Mercurial > hg > CbC > CbC_gcc
diff gcc/cp/name-lookup.c @ 131:84e7813d76e9
gcc-8.2
author | mir3636 |
---|---|
date | Thu, 25 Oct 2018 07:37:49 +0900 |
parents | 04ced10e8804 |
children | 1830386684a0 |
line wrap: on
line diff
--- a/gcc/cp/name-lookup.c Fri Oct 27 22:46:09 2017 +0900 +++ b/gcc/cp/name-lookup.c Thu Oct 25 07:37:49 2018 +0900 @@ -1,5 +1,5 @@ /* Definitions for C++ name lookup routines. - Copyright (C) 2003-2017 Free Software Foundation, Inc. + Copyright (C) 2003-2018 Free Software Foundation, Inc. Contributed by Gabriel Dos Reis <gdr@integrable-solutions.net> This file is part of GCC. @@ -19,6 +19,7 @@ <http://www.gnu.org/licenses/>. */ #include "config.h" +#define INCLUDE_UNIQUE_PTR #include "system.h" #include "coretypes.h" #include "cp-tree.h" @@ -32,11 +33,15 @@ #include "gcc-rich-location.h" #include "spellcheck-tree.h" #include "parser.h" +#include "c-family/name-hint.h" +#include "c-family/known-headers.h" +#include "c-family/c-spellcheck.h" static cxx_binding *cxx_binding_make (tree value, tree type); static cp_binding_level *innermost_nonclass_level (void); static void set_identifier_type_value_with_scope (tree id, tree decl, cp_binding_level *b); +static bool maybe_suggest_missing_std_header (location_t location, tree name); /* Create an overload suitable for recording an artificial TYPE_DECL and another decl. We use this machanism to implement the struct @@ -139,9 +144,7 @@ if (cxx_binding *binding = IDENTIFIER_BINDING (name)) for (;; b = b->level_chain) { - if (binding->scope == b - && !(VAR_P (binding->value) - && DECL_DEAD_FOR_LOCAL (binding->value))) + if (binding->scope == b) return binding; /* Cleanup contours are transparent to the language. */ @@ -555,11 +558,14 @@ /* Look in exactly namespace. */ bool found = search_namespace_only (scope); - - /* Recursively look in its inline children. */ - if (vec<tree, va_gc> *inlinees = DECL_NAMESPACE_INLINEES (scope)) - for (unsigned ix = inlinees->length (); ix--;) - found |= search_namespace ((*inlinees)[ix]); + + /* Don't look into inline children, if we're looking for an + anonymous name -- it must be in the current scope, if anywhere. */ + if (name) + /* Recursively look in its inline children. */ + if (vec<tree, va_gc> *inlinees = DECL_NAMESPACE_INLINEES (scope)) + for (unsigned ix = inlinees->length (); ix--;) + found |= search_namespace ((*inlinees)[ix]); if (found) mark_found (scope); @@ -707,6 +713,15 @@ done:; if (scope == global_namespace) break; + + /* If looking for hidden names, we only look in the innermost + namespace scope. [namespace.memdef]/3 If a friend + declaration in a non-local class first declares a class, + function, class template or function template the friend is a + member of the innermost enclosing namespace. See also + [basic.lookup.unqual]/7 */ + if (flags & LOOKUP_HIDDEN) + break; } vec_safe_truncate (queue, length); @@ -1133,17 +1148,9 @@ member_vec_linear_search (vec<tree, va_gc> *member_vec, tree name) { for (int ix = member_vec->length (); ix--;) - /* We can get a NULL binding during insertion of a new method - name, because the identifier_binding machinery performs a - lookup. If we find such a NULL slot, that's the thing we were - looking for, so we might as well bail out immediately. */ if (tree binding = (*member_vec)[ix]) - { - if (OVL_NAME (binding) == name) - return binding; - } - else - break; + if (OVL_NAME (binding) == name) + return binding; return NULL_TREE; } @@ -1157,25 +1164,11 @@ { tree decl = fields; - if (!want_type - && TREE_CODE (decl) == FIELD_DECL + if (TREE_CODE (decl) == FIELD_DECL && ANON_AGGR_TYPE_P (TREE_TYPE (decl))) { - tree anon = TREE_TYPE (decl); - gcc_assert (COMPLETE_TYPE_P (anon)); - tree temp; - - if (vec<tree, va_gc> *member_vec = CLASSTYPE_MEMBER_VEC (anon)) - temp = member_vec_linear_search (member_vec, name); - else - temp = fields_linear_search (anon, name, want_type); - - if (temp) - { - /* Anon members can only contain fields. */ - gcc_assert (!STAT_HACK_P (temp) && !DECL_DECLARES_TYPE_P (temp)); - return temp; - } + if (tree temp = search_anon_aggr (TREE_TYPE (decl), name, want_type)) + return temp; } if (DECL_NAME (decl) != name) @@ -1199,6 +1192,19 @@ return NULL_TREE; } +/* Look for NAME member inside of anonymous aggregate ANON. Although + such things should only contain FIELD_DECLs, we check that too + late, and would give very confusing errors if we weren't + permissive here. */ + +tree +search_anon_aggr (tree anon, tree name, bool want_type) +{ + gcc_assert (COMPLETE_TYPE_P (anon)); + tree ret = get_class_binding_direct (anon, name, want_type); + return ret; +} + /* Look for NAME as an immediate member of KLASS (including anon-members or unscoped enum member). TYPE_OR_FNS is zero for regular search. >0 to get a type binding (if there is one) and <0 @@ -1299,7 +1305,7 @@ if (CLASSTYPE_LAZY_DESTRUCTOR (klass)) lazily_declare_fn (sfk_destructor, klass); } - else if (name == cp_assignment_operator_id (NOP_EXPR)) + else if (name == assign_op_identifier) { if (CLASSTYPE_LAZY_COPY_ASSIGN (klass)) lazily_declare_fn (sfk_copy_assignment, klass); @@ -1312,15 +1318,15 @@ } /* Find the slot containing overloads called 'NAME'. If there is no - such slot, create an empty one. KLASS might be complete at this - point, in which case we need to preserve ordering. Deals with - conv_op marker handling. */ + such slot and the class is complete, create an empty one, at the + correct point in the sorted member vector. Otherwise return NULL. + Deals with conv_op marker handling. */ tree * -get_member_slot (tree klass, tree name) +find_member_slot (tree klass, tree name) { bool complete_p = COMPLETE_TYPE_P (klass); - + vec<tree, va_gc> *member_vec = CLASSTYPE_MEMBER_VEC (klass); if (!member_vec) { @@ -1367,24 +1373,34 @@ break; } - /* No slot found. Create one at IX. We know in this case that our - caller will succeed in adding the function. */ + /* No slot found, add one if the class is complete. */ if (complete_p) { - /* Do exact allocation when complete, as we don't expect to add - many. */ + /* Do exact allocation, as we don't expect to add many. */ + gcc_assert (name != conv_op_identifier); vec_safe_reserve_exact (member_vec, 1); + CLASSTYPE_MEMBER_VEC (klass) = member_vec; member_vec->quick_insert (ix, NULL_TREE); - } - else - { - gcc_checking_assert (ix == length); - vec_safe_push (member_vec, NULL_TREE); - } + return &(*member_vec)[ix]; + } + + return NULL; +} + +/* KLASS is an incomplete class to which we're adding a method NAME. + Add a slot and deal with conv_op marker handling. */ + +tree * +add_member_slot (tree klass, tree name) +{ + gcc_assert (!COMPLETE_TYPE_P (klass)); + + vec<tree, va_gc> *member_vec = CLASSTYPE_MEMBER_VEC (klass); + vec_safe_push (member_vec, NULL_TREE); CLASSTYPE_MEMBER_VEC (klass) = member_vec; - tree *slot = &(*member_vec)[ix]; - if (name == conv_op_identifier) + tree *slot = &member_vec->last (); + if (IDENTIFIER_CONV_OP_P (name)) { /* Install the marker prefix. */ *slot = ovl_make (conv_op_marker, NULL_TREE); @@ -1457,7 +1473,10 @@ how we order these. Use UID as a proxy for source ordering, so that identically-located decls still have a well-defined stable ordering. */ - return DECL_UID (a) < DECL_UID (b) ? -1 : +1; + if (DECL_UID (a) != DECL_UID (b)) + return DECL_UID (a) < DECL_UID (b) ? -1 : +1; + gcc_assert (a == b); + return 0; } static struct { @@ -1495,8 +1514,7 @@ { resort_data.new_value = new_value; resort_data.cookie = cookie; - qsort (member_vec->address (), member_vec->length (), - sizeof (tree), resort_member_name_cmp); + member_vec->qsort (resort_member_name_cmp); } } @@ -1572,68 +1590,61 @@ unsigned len = member_vec->length (); unsigned store = 0; - tree current = (*member_vec)[0], name = OVL_NAME (current); - tree next = NULL_TREE, next_name = NULL_TREE; - for (unsigned jx, ix = 0; ix < len; - ix = jx, current = next, name = next_name) - { + if (!len) + return; + + tree name = OVL_NAME ((*member_vec)[0]); + for (unsigned jx, ix = 0; ix < len; ix = jx) + { + tree current = NULL_TREE; tree to_type = NULL_TREE; tree to_using = NULL_TREE; tree marker = NULL_TREE; - if (IDENTIFIER_CONV_OP_P (name)) + + for (jx = ix; jx < len; jx++) { - marker = current; - current = OVL_CHAIN (current); - name = DECL_NAME (OVL_FUNCTION (marker)); - gcc_checking_assert (name == conv_op_identifier); - } - - if (TREE_CODE (current) == USING_DECL) - { - current = strip_using_decl (current); - if (is_overloaded_fn (current)) - current = NULL_TREE; - else if (TREE_CODE (current) == USING_DECL) + tree next = (*member_vec)[jx]; + if (jx != ix) { - to_using = current; - current = NULL_TREE; + tree next_name = OVL_NAME (next); + if (next_name != name) + { + name = next_name; + break; + } } - } - - if (current && DECL_DECLARES_TYPE_P (current)) - { - to_type = current; - current = NULL_TREE; - } - - for (jx = ix + 1; jx < len; jx++) - { - next = (*member_vec)[jx]; - next_name = OVL_NAME (next); - if (next_name != name) - break; - - if (marker) + + if (IDENTIFIER_CONV_OP_P (name)) { - gcc_checking_assert (OVL_FUNCTION (marker) - == OVL_FUNCTION (next)); + marker = next; next = OVL_CHAIN (next); } if (TREE_CODE (next) == USING_DECL) { + if (IDENTIFIER_CTOR_P (name)) + /* Dependent inherited ctor. */ + continue; + next = strip_using_decl (next); - if (is_overloaded_fn (next)) - next = NULL_TREE; - else if (TREE_CODE (next) == USING_DECL) + if (TREE_CODE (next) == USING_DECL) { to_using = next; - next = NULL_TREE; + continue; } + + if (is_overloaded_fn (next)) + continue; } - if (next && DECL_DECLARES_TYPE_P (next)) - to_type = next; + if (DECL_DECLARES_TYPE_P (next)) + { + to_type = next; + continue; + } + + if (!current) + current = next; } if (to_using) @@ -1652,13 +1663,15 @@ current = stat_hack (current, to_type); } - gcc_assert (current); - if (marker) + if (current) { - OVL_CHAIN (marker) = current; - current = marker; + if (marker) + { + OVL_CHAIN (marker) = current; + current = marker; + } + (*member_vec)[store++] = current; } - (*member_vec)[store++] = current; } while (store++ < len) @@ -1687,8 +1700,7 @@ if (member_vec) { CLASSTYPE_MEMBER_VEC (klass) = member_vec; - qsort (member_vec->address (), member_vec->length (), - sizeof (tree), member_name_cmp); + member_vec->qsort (member_name_cmp); member_vec_dedup (member_vec); } } @@ -1716,8 +1728,7 @@ else member_vec_append_class_fields (member_vec, klass); CLASSTYPE_MEMBER_VEC (klass) = member_vec; - qsort (member_vec->address (), member_vec->length (), - sizeof (tree), member_name_cmp); + member_vec->qsort (member_name_cmp); member_vec_dedup (member_vec); } } @@ -2472,21 +2483,12 @@ done: if (to_val) { - if (level->kind != sk_namespace - && !to_type && binding->value && OVL_P (to_val)) - update_local_overload (binding, to_val); + if (level->kind == sk_namespace || to_type == decl || to_val == decl) + add_decl_to_level (level, decl); else { - tree to_add = to_val; - - if (level->kind == sk_namespace) - to_add = decl; - else if (to_type == decl) - to_add = decl; - else if (TREE_CODE (to_add) == OVERLOAD) - to_add = build_tree_list (NULL_TREE, to_add); - - add_decl_to_level (level, to_add); + gcc_checking_assert (binding->value && OVL_P (binding->value)); + update_local_overload (binding, to_val); } if (slot) @@ -2526,6 +2528,10 @@ if (DECL_ARTIFICIAL (decl) || DECL_IN_SYSTEM_HEADER (decl)) return; + /* This only applies to decls at namespace scope. */ + if (!DECL_NAMESPACE_SCOPE_P (decl)) + return; + if (!extern_c_decls) extern_c_decls = hash_table<named_decl_hash>::create_ggc (127); @@ -2553,6 +2559,7 @@ if (mismatch) { + auto_diagnostic_group d; pedwarn (input_location, 0, "conflicting C language linkage declaration %q#D", decl); inform (DECL_SOURCE_LOCATION (old), @@ -2601,6 +2608,15 @@ return NULL_TREE; } +/* Subroutine of check_local_shadow. */ + +static void +inform_shadowed (tree shadowed) +{ + inform (DECL_SOURCE_LOCATION (shadowed), + "shadowed declaration is here"); +} + /* DECL is being declared at a local scope. Emit suitable shadow warnings. */ @@ -2612,10 +2628,6 @@ if (TREE_CODE (decl) == PARM_DECL && !DECL_CONTEXT (decl)) return; - /* Inline decls shadow nothing. */ - if (DECL_FROM_INLINE (decl)) - return; - /* External decls are something else. */ if (DECL_EXTERNAL (decl)) return; @@ -2627,24 +2639,38 @@ old = binding->value; old_scope = binding->scope; } - while (old && VAR_P (old) && DECL_DEAD_FOR_LOCAL (old)) - old = DECL_SHADOWED_FOR_VAR (old); - - tree shadowed = NULL_TREE; + if (old && (TREE_CODE (old) == PARM_DECL || VAR_P (old) || (TREE_CODE (old) == TYPE_DECL && (!DECL_ARTIFICIAL (old) || TREE_CODE (decl) == TYPE_DECL))) + && DECL_FUNCTION_SCOPE_P (old) && (!DECL_ARTIFICIAL (decl) + || is_capture_proxy (decl) || DECL_IMPLICIT_TYPEDEF_P (decl) || (VAR_P (decl) && DECL_ANON_UNION_VAR_P (decl)))) { /* DECL shadows a local thing possibly of interest. */ + /* DR 2211: check that captures and parameters + do not have the same name. */ + if (is_capture_proxy (decl)) + { + if (current_lambda_expr () + && DECL_CONTEXT (old) == lambda_function (current_lambda_expr ()) + && TREE_CODE (old) == PARM_DECL + && DECL_NAME (decl) != this_identifier) + { + error_at (DECL_SOURCE_LOCATION (old), + "lambda parameter %qD " + "previously declared as a capture", old); + } + return; + } /* Don't complain if it's from an enclosing function. */ - if (DECL_CONTEXT (old) == current_function_decl + else if (DECL_CONTEXT (old) == current_function_decl && TREE_CODE (decl) != PARM_DECL && TREE_CODE (old) == PARM_DECL) { @@ -2684,6 +2710,7 @@ && old_scope == current_binding_level->level_chain && (old_scope->kind == sk_cond || old_scope->kind == sk_for)) { + auto_diagnostic_group d; error ("redeclaration of %q#D", decl); inform (DECL_SOURCE_LOCATION (old), "%q#D previously declared here", old); @@ -2706,6 +2733,7 @@ || current_binding_level->level_chain->kind == sk_catch) && in_function_try_handler)) { + auto_diagnostic_group d; if (permerror (input_location, "redeclaration of %q#D", decl)) inform (DECL_SOURCE_LOCATION (old), "%q#D previously declared here", old); @@ -2732,6 +2760,13 @@ && (same_type_p (TREE_TYPE (old), TREE_TYPE (decl)) || (!dependent_type_p (TREE_TYPE (decl)) && !dependent_type_p (TREE_TYPE (old)) + /* If the new decl uses auto, we don't yet know + its type (the old type cannot be using auto + at this point, without also being + dependent). This is an indication we're + (now) doing the shadow checking too + early. */ + && !type_uses_auto (TREE_TYPE (decl)) && can_convert (TREE_TYPE (old), TREE_TYPE (decl), tf_none)))) warning_code = OPT_Wshadow_compatible_local; @@ -2746,11 +2781,9 @@ else msg = "declaration of %qD shadows a previous local"; + auto_diagnostic_group d; if (warning_at (input_location, warning_code, msg, decl)) - { - shadowed = old; - goto inform_shadowed; - } + inform_shadowed (old); return; } @@ -2775,14 +2808,12 @@ || TYPE_PTRFN_P (TREE_TYPE (decl)) || TYPE_PTRMEMFUNC_P (TREE_TYPE (decl))) { + auto_diagnostic_group d; if (warning_at (input_location, OPT_Wshadow, "declaration of %qD shadows a member of %qT", decl, current_nonlambda_class_type ()) && DECL_P (member)) - { - shadowed = member; - goto inform_shadowed; - } + inform_shadowed (member); } return; } @@ -2797,20 +2828,15 @@ && !instantiating_current_function_p ()) /* XXX shadow warnings in outer-more namespaces */ { + auto_diagnostic_group d; if (warning_at (input_location, OPT_Wshadow, "declaration of %qD shadows a global declaration", decl)) - { - shadowed = old; - goto inform_shadowed; - } + inform_shadowed (old); return; } return; - - inform_shadowed: - inform (DECL_SOURCE_LOCATION (shadowed), "shadowed declaration is here"); } /* DECL is being pushed inside function CTX. Set its context, if @@ -2869,7 +2895,9 @@ = find_namespace_value (current_namespace, DECL_NAME (decl)); loc_value = ns_value; } - if (loc_value == error_mark_node) + if (loc_value == error_mark_node + /* An ambiguous lookup. */ + || (loc_value && TREE_CODE (loc_value) == TREE_LIST)) loc_value = NULL_TREE; for (ovl_iterator iter (loc_value); iter; ++iter) @@ -2917,7 +2945,8 @@ if (ns_value == decl) ns_value = find_namespace_value (current_namespace, DECL_NAME (decl)); - if (ns_value == error_mark_node) + if (ns_value == error_mark_node + || (ns_value && TREE_CODE (ns_value) == TREE_LIST)) ns_value = NULL_TREE; for (ovl_iterator iter (ns_value); iter; ++iter) @@ -2933,6 +2962,7 @@ && !comptypes (TREE_TYPE (decl), TREE_TYPE (other), COMPARE_REDECLARATION))) { + auto_diagnostic_group d; if (permerror (DECL_SOURCE_LOCATION (decl), "local external declaration %q#D", decl)) inform (DECL_SOURCE_LOCATION (other), @@ -3054,14 +3084,17 @@ if (is_friend) { if (level->kind != sk_namespace) - /* In a local class, a friend function declaration must - find a matching decl in the innermost non-class scope. - [class.friend/11] */ - error ("friend declaration %qD in local class without " - "prior local declaration", decl); - else if (!flag_friend_injection) - /* Hide it from ordinary lookup. */ - DECL_ANTICIPATED (decl) = DECL_HIDDEN_FRIEND_P (decl) = true; + { + /* In a local class, a friend function declaration must + find a matching decl in the innermost non-class scope. + [class.friend/11] */ + error ("friend declaration %qD in local class without " + "prior local declaration", decl); + /* Don't attempt to push it. */ + return error_mark_node; + } + /* Hide it from ordinary lookup. */ + DECL_ANTICIPATED (decl) = DECL_HIDDEN_FRIEND_P (decl) = true; } } @@ -3201,83 +3234,6 @@ add_decl_to_level (b, decl); } -/* Check to see whether or not DECL is a variable that would have been - in scope under the ARM, but is not in scope under the ANSI/ISO - standard. If so, issue an error message. If name lookup would - work in both cases, but return a different result, this function - returns the result of ANSI/ISO lookup. Otherwise, it returns - DECL. */ - -tree -check_for_out_of_scope_variable (tree decl) -{ - tree shadowed; - - /* We only care about out of scope variables. */ - if (!(VAR_P (decl) && DECL_DEAD_FOR_LOCAL (decl))) - return decl; - - shadowed = DECL_HAS_SHADOWED_FOR_VAR_P (decl) - ? DECL_SHADOWED_FOR_VAR (decl) : NULL_TREE ; - while (shadowed != NULL_TREE && VAR_P (shadowed) - && DECL_DEAD_FOR_LOCAL (shadowed)) - shadowed = DECL_HAS_SHADOWED_FOR_VAR_P (shadowed) - ? DECL_SHADOWED_FOR_VAR (shadowed) : NULL_TREE; - if (!shadowed) - shadowed = find_namespace_value (current_namespace, DECL_NAME (decl)); - if (shadowed) - { - if (!DECL_ERROR_REPORTED (decl)) - { - warning (0, "name lookup of %qD changed", DECL_NAME (decl)); - warning_at (DECL_SOURCE_LOCATION (shadowed), 0, - " matches this %qD under ISO standard rules", - shadowed); - warning_at (DECL_SOURCE_LOCATION (decl), 0, - " matches this %qD under old rules", decl); - DECL_ERROR_REPORTED (decl) = 1; - } - return shadowed; - } - - /* If we have already complained about this declaration, there's no - need to do it again. */ - if (DECL_ERROR_REPORTED (decl)) - return decl; - - DECL_ERROR_REPORTED (decl) = 1; - - if (TREE_TYPE (decl) == error_mark_node) - return decl; - - if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (decl))) - { - error ("name lookup of %qD changed for ISO %<for%> scoping", - DECL_NAME (decl)); - error (" cannot use obsolete binding at %q+D because " - "it has a destructor", decl); - return error_mark_node; - } - else - { - permerror (input_location, "name lookup of %qD changed for ISO %<for%> scoping", - DECL_NAME (decl)); - if (flag_permissive) - permerror (DECL_SOURCE_LOCATION (decl), - " using obsolete binding at %qD", decl); - else - { - static bool hint; - if (!hint) - { - inform (input_location, "(if you use %<-fpermissive%> G++ will accept your code)"); - hint = true; - } - } - } - - return decl; -} /* true means unconditionally make a BLOCK for the next level pushed. */ @@ -3331,21 +3287,6 @@ verbatim ("%s %s %p %d\n", action, desc, (void *) scope, line); } -/* Return the estimated initial size of the hashtable of a NAMESPACE - scope. */ - -static inline size_t -namespace_scope_ht_size (tree ns) -{ - tree name = DECL_NAME (ns); - - return name == std_identifier - ? NAMESPACE_STD_HT_SIZE - : (name == global_identifier - ? GLOBAL_SCOPE_HT_SIZE - : NAMESPACE_ORDINARY_HT_SIZE); -} - /* A chain of binding_level structures awaiting reuse. */ static GTY((deletable)) cp_binding_level *free_binding_level; @@ -3727,7 +3668,7 @@ } -void +static void print_other_binding_stack (cp_binding_level *stack) { cp_binding_level *level; @@ -3945,9 +3886,7 @@ do_pushdecl_with_scope (tree x, cp_binding_level *level, bool is_friend) { cp_binding_level *b; - tree function_decl = current_function_decl; - - current_function_decl = NULL_TREE; + if (level->kind == sk_class) { b = class_binding_level; @@ -3957,12 +3896,15 @@ } else { + tree function_decl = current_function_decl; + if (level->kind == sk_namespace) + current_function_decl = NULL_TREE; b = current_binding_level; current_binding_level = level; x = pushdecl (x, is_friend); current_binding_level = b; - } - current_function_decl = function_decl; + current_function_decl = function_decl; + } return x; } @@ -4466,16 +4408,30 @@ /* If X is an anonymous aggregate, all of its members are treated as if they were members of the class containing the aggregate, for naming purposes. */ - tree f; - - for (f = TYPE_FIELDS (TREE_TYPE (x)); f; f = DECL_CHAIN (f)) - { - location_t save_location = input_location; - input_location = DECL_SOURCE_LOCATION (f); - if (!pushdecl_class_level (f)) - is_valid = false; - input_location = save_location; + location_t save_location = input_location; + tree anon = TREE_TYPE (x); + if (vec<tree, va_gc> *member_vec = CLASSTYPE_MEMBER_VEC (anon)) + for (unsigned ix = member_vec->length (); ix--;) + { + tree binding = (*member_vec)[ix]; + if (STAT_HACK_P (binding)) + { + if (!pushdecl_class_level (STAT_TYPE (binding))) + is_valid = false; + binding = STAT_DECL (binding); + } + if (!pushdecl_class_level (binding)) + is_valid = false; } + else + for (tree f = TYPE_FIELDS (anon); f; f = DECL_CHAIN (f)) + if (TREE_CODE (f) == FIELD_DECL) + { + input_location = DECL_SOURCE_LOCATION (f); + if (!pushdecl_class_level (f)) + is_valid = false; + } + input_location = save_location; } timevar_cond_stop (TV_NAME_LOOKUP, subtime); return is_valid; @@ -5015,6 +4971,9 @@ tree d; bool saw_vis = false; + if (attributes == error_mark_node) + return false; + for (d = attributes; d; d = TREE_CHAIN (d)) { tree name = get_attribute_name (d); @@ -5298,6 +5257,48 @@ return true; } +/* Is there a "using namespace std;" directive within USINGS? */ + +static bool +using_directives_contain_std_p (vec<tree, va_gc> *usings) +{ + if (!usings) + return false; + + for (unsigned ix = usings->length (); ix--;) + if ((*usings)[ix] == std_node) + return true; + + return false; +} + +/* Is there a "using namespace std;" directive within the current + namespace (or its ancestors)? + Compare with name_lookup::search_unqualified. */ + +static bool +has_using_namespace_std_directive_p () +{ + /* Look at local using-directives. */ + for (cp_binding_level *level = current_binding_level; + level->kind != sk_namespace; + level = level->level_chain) + if (using_directives_contain_std_p (level->using_directives)) + return true; + + /* Look at this namespace and its ancestors. */ + for (tree scope = current_namespace; scope; scope = CP_DECL_CONTEXT (scope)) + { + if (using_directives_contain_std_p (DECL_NAMESPACE_USING (scope))) + return true; + + if (scope == global_namespace) + break; + } + + return false; +} + /* Suggest alternatives for NAME, an IDENTIFIER_NODE for which name lookup failed. Search through all available namespaces and print out possible candidates. If no exact matches are found, and @@ -5368,100 +5369,273 @@ inform (location_of (val), " %qE", val); } candidates.release (); - } - else if (!suggest_misspellings) - ; - else if (const char *fuzzy = lookup_name_fuzzy (name, FUZZY_LOOKUP_NAME)) + return; + } + + /* No candidates were found in the available namespaces. */ + + /* If there's a "using namespace std;" active, and this + is one of the most common "std::" names, then it's probably a + missing #include. */ + if (has_using_namespace_std_directive_p ()) + if (maybe_suggest_missing_std_header (location, name)) + return; + + /* Otherwise, consider misspellings. */ + if (!suggest_misspellings) + return; + if (name_hint hint = lookup_name_fuzzy (name, FUZZY_LOOKUP_NAME, + location)) { /* Show a spelling correction. */ gcc_rich_location richloc (location); - richloc.add_fixit_replace (fuzzy); - inform_at_rich_loc (&richloc, "suggested alternative: %qs", fuzzy); - } -} + richloc.add_fixit_replace (hint.suggestion ()); + inform (&richloc, "suggested alternative: %qs", hint.suggestion ()); + } +} + +/* A well-known name within the C++ standard library, returned by + get_std_name_hint. */ + +struct std_name_hint +{ + /* A name within "std::". */ + const char *name; + + /* The header name defining it within the C++ Standard Library + (with '<' and '>'). */ + const char *header; + + /* The dialect of C++ in which this was added. */ + enum cxx_dialect min_dialect; +}; /* Subroutine of maybe_suggest_missing_header for handling unrecognized names for some of the most common names within "std::". - Given non-NULL NAME, a name for lookup within "std::", return the header - name defining it within the C++ Standard Library (with '<' and '>'), - or NULL. */ - -static const char * + Given non-NULL NAME, return the std_name_hint for it, or NULL. */ + +static const std_name_hint * get_std_name_hint (const char *name) { - struct std_name_hint - { - const char *name; - const char *header; - }; static const std_name_hint hints[] = { + /* <any>. */ + {"any", "<any>", cxx17}, + {"any_cast", "<any>", cxx17}, + {"make_any", "<any>", cxx17}, /* <array>. */ - {"array", "<array>"}, // C++11 + {"array", "<array>", cxx11}, + /* <atomic>. */ + {"atomic", "<atomic>", cxx11}, + {"atomic_flag", "<atomic>", cxx11}, + /* <bitset>. */ + {"bitset", "<bitset>", cxx11}, + /* <complex>. */ + {"complex", "<complex>", cxx98}, + {"complex_literals", "<complex>", cxx98}, + /* <condition_variable>. */ + {"condition_variable", "<condition_variable>", cxx11}, + {"condition_variable_any", "<condition_variable>", cxx11}, /* <deque>. */ - {"deque", "<deque>"}, + {"deque", "<deque>", cxx98}, /* <forward_list>. */ - {"forward_list", "<forward_list>"}, // C++11 + {"forward_list", "<forward_list>", cxx11}, /* <fstream>. */ - {"basic_filebuf", "<fstream>"}, - {"basic_ifstream", "<fstream>"}, - {"basic_ofstream", "<fstream>"}, - {"basic_fstream", "<fstream>"}, + {"basic_filebuf", "<fstream>", cxx98}, + {"basic_ifstream", "<fstream>", cxx98}, + {"basic_ofstream", "<fstream>", cxx98}, + {"basic_fstream", "<fstream>", cxx98}, + {"fstream", "<fstream>", cxx98}, + {"ifstream", "<fstream>", cxx98}, + {"ofstream", "<fstream>", cxx98}, + /* <functional>. */ + {"bind", "<functional>", cxx11}, + {"function", "<functional>", cxx11}, + {"hash", "<functional>", cxx11}, + {"mem_fn", "<functional>", cxx11}, + /* <future>. */ + {"async", "<future>", cxx11}, + {"future", "<future>", cxx11}, + {"packaged_task", "<future>", cxx11}, + {"promise", "<future>", cxx11}, /* <iostream>. */ - {"cin", "<iostream>"}, - {"cout", "<iostream>"}, - {"cerr", "<iostream>"}, - {"clog", "<iostream>"}, - {"wcin", "<iostream>"}, - {"wcout", "<iostream>"}, - {"wclog", "<iostream>"}, + {"cin", "<iostream>", cxx98}, + {"cout", "<iostream>", cxx98}, + {"cerr", "<iostream>", cxx98}, + {"clog", "<iostream>", cxx98}, + {"wcin", "<iostream>", cxx98}, + {"wcout", "<iostream>", cxx98}, + {"wclog", "<iostream>", cxx98}, + /* <istream>. */ + {"istream", "<istream>", cxx98}, + /* <iterator>. */ + {"advance", "<iterator>", cxx98}, + {"back_inserter", "<iterator>", cxx98}, + {"begin", "<iterator>", cxx11}, + {"distance", "<iterator>", cxx98}, + {"end", "<iterator>", cxx11}, + {"front_inserter", "<iterator>", cxx98}, + {"inserter", "<iterator>", cxx98}, + {"istream_iterator", "<iterator>", cxx98}, + {"istreambuf_iterator", "<iterator>", cxx98}, + {"iterator_traits", "<iterator>", cxx98}, + {"move_iterator", "<iterator>", cxx11}, + {"next", "<iterator>", cxx11}, + {"ostream_iterator", "<iterator>", cxx98}, + {"ostreambuf_iterator", "<iterator>", cxx98}, + {"prev", "<iterator>", cxx11}, + {"reverse_iterator", "<iterator>", cxx98}, + /* <ostream>. */ + {"ostream", "<ostream>", cxx98}, /* <list>. */ - {"list", "<list>"}, + {"list", "<list>", cxx98}, /* <map>. */ - {"map", "<map>"}, - {"multimap", "<map>"}, - /* <queue>. */ - {"queue", "<queue>"}, - {"priority_queue", "<queue>"}, + {"map", "<map>", cxx98}, + {"multimap", "<map>", cxx98}, + /* <memory>. */ + {"make_shared", "<memory>", cxx11}, + {"make_unique", "<memory>", cxx11}, + {"shared_ptr", "<memory>", cxx11}, + {"unique_ptr", "<memory>", cxx11}, + {"weak_ptr", "<memory>", cxx11}, + /* <mutex>. */ + {"mutex", "<mutex>", cxx11}, + {"timed_mutex", "<mutex>", cxx11}, + {"recursive_mutex", "<mutex>", cxx11}, + {"recursive_timed_mutex", "<mutex>", cxx11}, + {"once_flag", "<mutex>", cxx11}, + {"call_once,", "<mutex>", cxx11}, + {"lock", "<mutex>", cxx11}, + {"scoped_lock", "<mutex>", cxx17}, + {"try_lock", "<mutex>", cxx11}, + {"lock_guard", "<mutex>", cxx11}, + {"unique_lock", "<mutex>", cxx11}, + /* <optional>. */ + {"optional", "<optional>", cxx17}, + {"make_optional", "<optional>", cxx17}, /* <ostream>. */ - {"ostream", "<ostream>"}, - {"wostream", "<ostream>"}, - {"ends", "<ostream>"}, - {"flush", "<ostream>"}, - {"endl", "<ostream>"}, + {"ostream", "<ostream>", cxx98}, + {"wostream", "<ostream>", cxx98}, + {"ends", "<ostream>", cxx98}, + {"flush", "<ostream>", cxx98}, + {"endl", "<ostream>", cxx98}, + /* <queue>. */ + {"queue", "<queue>", cxx98}, + {"priority_queue", "<queue>", cxx98}, /* <set>. */ - {"set", "<set>"}, - {"multiset", "<set>"}, + {"set", "<set>", cxx98}, + {"multiset", "<set>", cxx98}, + /* <shared_mutex>. */ + {"shared_lock", "<shared_mutex>", cxx14}, + {"shared_mutex", "<shared_mutex>", cxx17}, + {"shared_timed_mutex", "<shared_mutex>", cxx14}, /* <sstream>. */ - {"basic_stringbuf", "<sstream>"}, - {"basic_istringstream", "<sstream>"}, - {"basic_ostringstream", "<sstream>"}, - {"basic_stringstream", "<sstream>"}, + {"basic_stringbuf", "<sstream>", cxx98}, + {"basic_istringstream", "<sstream>", cxx98}, + {"basic_ostringstream", "<sstream>", cxx98}, + {"basic_stringstream", "<sstream>", cxx98}, + {"istringstream", "<sstream>", cxx98}, + {"ostringstream", "<sstream>", cxx98}, + {"stringstream", "<sstream>", cxx98}, /* <stack>. */ - {"stack", "<stack>"}, + {"stack", "<stack>", cxx98}, /* <string>. */ - {"string", "<string>"}, - {"wstring", "<string>"}, - {"u16string", "<string>"}, - {"u32string", "<string>"}, + {"basic_string", "<string>", cxx98}, + {"string", "<string>", cxx98}, + {"wstring", "<string>", cxx98}, + {"u16string", "<string>", cxx11}, + {"u32string", "<string>", cxx11}, + /* <string_view>. */ + {"string_view", "<string_view>", cxx17}, + /* <thread>. */ + {"thread", "<thread>", cxx11}, + /* <tuple>. */ + {"make_tuple", "<tuple>", cxx11}, + {"tuple", "<tuple>", cxx11}, + {"tuple_element", "<tuple>", cxx11}, + {"tuple_size", "<tuple>", cxx11}, /* <unordered_map>. */ - {"unordered_map", "<unordered_map>"}, // C++11 - {"unordered_multimap", "<unordered_map>"}, // C++11 + {"unordered_map", "<unordered_map>", cxx11}, + {"unordered_multimap", "<unordered_map>", cxx11}, /* <unordered_set>. */ - {"unordered_set", "<unordered_set>"}, // C++11 - {"unordered_multiset", "<unordered_set>"}, // C++11 + {"unordered_set", "<unordered_set>", cxx11}, + {"unordered_multiset", "<unordered_set>", cxx11}, + /* <utility>. */ + {"declval", "<utility>", cxx11}, + {"forward", "<utility>", cxx11}, + {"make_pair", "<utility>", cxx98}, + {"move", "<utility>", cxx11}, + {"pair", "<utility>", cxx98}, + /* <variant>. */ + {"variant", "<variant>", cxx17}, + {"visit", "<variant>", cxx17}, /* <vector>. */ - {"vector", "<vector>"}, + {"vector", "<vector>", cxx98}, }; const size_t num_hints = sizeof (hints) / sizeof (hints[0]); for (size_t i = 0; i < num_hints; i++) { - if (0 == strcmp (name, hints[i].name)) - return hints[i].header; + if (strcmp (name, hints[i].name) == 0) + return &hints[i]; } return NULL; } +/* Describe DIALECT. */ + +static const char * +get_cxx_dialect_name (enum cxx_dialect dialect) +{ + switch (dialect) + { + default: + gcc_unreachable (); + case cxx98: + return "C++98"; + case cxx11: + return "C++11"; + case cxx14: + return "C++14"; + case cxx17: + return "C++17"; + case cxx2a: + return "C++2a"; + } +} + +/* Suggest pertinent header files for NAME at LOCATION, for common + names within the "std" namespace. + Return true iff a suggestion was offered. */ + +static bool +maybe_suggest_missing_std_header (location_t location, tree name) +{ + gcc_assert (TREE_CODE (name) == IDENTIFIER_NODE); + + const char *name_str = IDENTIFIER_POINTER (name); + const std_name_hint *header_hint = get_std_name_hint (name_str); + if (!header_hint) + return false; + + gcc_rich_location richloc (location); + if (cxx_dialect >= header_hint->min_dialect) + { + const char *header = header_hint->header; + maybe_add_include_fixit (&richloc, header, true); + inform (&richloc, + "%<std::%s%> is defined in header %qs;" + " did you forget to %<#include %s%>?", + name_str, header, header); + } + else + { + inform (&richloc, + "%<std::%s%> is only available from %s onwards", + name_str, get_cxx_dialect_name (header_hint->min_dialect)); + } + return true; +} + /* If SCOPE is the "std" namespace, then suggest pertinent header files for NAME at LOCATION. Return true iff a suggestion was offered. */ @@ -5476,20 +5650,7 @@ /* We only offer suggestions for the "std" namespace. */ if (scope != std_node) return false; - gcc_assert (TREE_CODE (name) == IDENTIFIER_NODE); - - const char *name_str = IDENTIFIER_POINTER (name); - const char *header_hint = get_std_name_hint (name_str); - if (!header_hint) - return false; - - gcc_rich_location richloc (location); - maybe_add_include_fixit (&richloc, header_hint); - inform_at_rich_loc (&richloc, - "%<std::%s%> is defined in header %qs;" - " did you forget to %<#include %s%>?", - name_str, header_hint, header_hint); - return true; + return maybe_suggest_missing_std_header (location, name); } /* Look for alternatives for NAME, an IDENTIFIER_NODE for which name @@ -5501,6 +5662,10 @@ suggest_alternative_in_explicit_scope (location_t location, tree name, tree scope) { + /* Something went very wrong; don't suggest anything. */ + if (name == error_mark_node) + return false; + /* Resolve any namespace aliases. */ scope = ORIGINAL_NAMESPACE (scope); @@ -5518,8 +5683,8 @@ { gcc_rich_location richloc (location); richloc.add_fixit_replace (fuzzy_name); - inform_at_rich_loc (&richloc, "suggested alternative: %qs", - fuzzy_name); + inform (&richloc, "suggested alternative: %qs", + fuzzy_name); return true; } @@ -5597,6 +5762,10 @@ bm.consider (IDENTIFIER_POINTER (best_matching_field)); } + /* Only suggest names reserved for the implementation if NAME begins + with an underscore. */ + bool consider_implementation_names = (IDENTIFIER_POINTER (name)[0] == '_'); + for (tree t = lvl->names; t; t = TREE_CHAIN (t)) { tree d = t; @@ -5613,26 +5782,141 @@ /* Skip anticipated decls of builtin functions. */ if (TREE_CODE (d) == FUNCTION_DECL - && DECL_BUILT_IN (d) + && fndecl_built_in_p (d) && DECL_ANTICIPATED (d)) continue; - if (tree name = DECL_NAME (d)) - /* Ignore internal names with spaces in them. */ - if (!strchr (IDENTIFIER_POINTER (name), ' ')) - bm.consider (IDENTIFIER_POINTER (name)); + /* Skip compiler-generated variables (e.g. __for_begin/__for_end + within range for). */ + if (TREE_CODE (d) == VAR_DECL + && DECL_ARTIFICIAL (d)) + continue; + + tree suggestion = DECL_NAME (d); + if (!suggestion) + continue; + + /* Don't suggest names that are for anonymous aggregate types, as + they are an implementation detail generated by the compiler. */ + if (anon_aggrname_p (suggestion)) + continue; + + const char *suggestion_str = IDENTIFIER_POINTER (suggestion); + + /* Ignore internal names with spaces in them. */ + if (strchr (suggestion_str, ' ')) + continue; + + /* Don't suggest names that are reserved for use by the + implementation, unless NAME began with an underscore. */ + if (name_reserved_for_implementation_p (suggestion_str) + && !consider_implementation_names) + continue; + + bm.consider (suggestion_str); + } +} + +/* Subclass of deferred_diagnostic. Notify the user that the + given macro was used before it was defined. + This can be done in the C++ frontend since tokenization happens + upfront. */ + +class macro_use_before_def : public deferred_diagnostic +{ + public: + /* Factory function. Return a new macro_use_before_def instance if + appropriate, or return NULL. */ + static macro_use_before_def * + maybe_make (location_t use_loc, cpp_hashnode *macro) + { + source_location def_loc = cpp_macro_definition_location (macro); + if (def_loc == UNKNOWN_LOCATION) + return NULL; + + /* We only want to issue a note if the macro was used *before* it was + defined. + We don't want to issue a note for cases where a macro was incorrectly + used, leaving it unexpanded (e.g. by using the wrong argument + count). */ + if (!linemap_location_before_p (line_table, use_loc, def_loc)) + return NULL; + + return new macro_use_before_def (use_loc, macro); + } + + private: + /* Ctor. LOC is the location of the usage. MACRO is the + macro that was used. */ + macro_use_before_def (location_t loc, cpp_hashnode *macro) + : deferred_diagnostic (loc), m_macro (macro) + { + gcc_assert (macro); + } + + ~macro_use_before_def () + { + if (is_suppressed_p ()) + return; + + inform (get_location (), "the macro %qs had not yet been defined", + (const char *)m_macro->ident.str); + inform (cpp_macro_definition_location (m_macro), + "it was later defined here"); + } + + private: + cpp_hashnode *m_macro; +}; + +/* Determine if it can ever make sense to offer RID as a suggestion for + a misspelling. + + Subroutine of lookup_name_fuzzy. */ + +static bool +suggest_rid_p (enum rid rid) +{ + switch (rid) + { + /* Support suggesting function-like keywords. */ + case RID_STATIC_ASSERT: + return true; + + default: + /* Support suggesting the various decl-specifier words, to handle + e.g. "singed" vs "signed" typos. */ + if (cp_keyword_starts_decl_specifier_p (rid)) + return true; + + /* Otherwise, don't offer it. This avoids suggesting e.g. "if" + and "do" for short misspellings, which are likely to lead to + nonsensical results. */ + return false; } } /* Search for near-matches for NAME within the current bindings, and within macro names, returning the best match as a const char *, or NULL if - no reasonable match is found. */ - -const char * -lookup_name_fuzzy (tree name, enum lookup_name_fuzzy_kind kind) + no reasonable match is found. + + Use LOC for any deferred diagnostics. */ + +name_hint +lookup_name_fuzzy (tree name, enum lookup_name_fuzzy_kind kind, location_t loc) { gcc_assert (TREE_CODE (name) == IDENTIFIER_NODE); + /* First, try some well-known names in the C++ standard library, in case + the user forgot a #include. */ + const char *header_hint + = get_cp_stdlib_header_for_name (IDENTIFIER_POINTER (name)); + if (header_hint) + return name_hint (NULL, + new suggest_missing_header (loc, + IDENTIFIER_POINTER (name), + header_hint)); + best_match <tree, const char *> bm (name); cp_binding_level *lvl; @@ -5659,6 +5943,16 @@ /* If a macro is the closest so far to NAME, consider it. */ if (best_macro) bm.consider ((const char *)best_macro->ident.str); + else if (bmm.get_best_distance () == 0) + { + /* If we have an exact match for a macro name, then either the + macro was used with the wrong argument count, or the macro + has been used before it was defined. */ + if (cpp_hashnode *macro = bmm.blithely_get_best_candidate ()) + if (cpp_user_macro_p (macro)) + return name_hint (NULL, + macro_use_before_def::maybe_make (loc, macro)); + } /* Try the "starts_decl_specifier_p" keywords to detect "singed" vs "signed" typos. */ @@ -5666,9 +5960,8 @@ { const c_common_resword *resword = &c_common_reswords[i]; - if (kind == FUZZY_LOOKUP_TYPENAME) - if (!cp_keyword_starts_decl_specifier_p (resword->rid)) - continue; + if (!suggest_rid_p (resword->rid)) + continue; tree resword_identifier = ridpointers [resword->rid]; if (!resword_identifier) @@ -5683,7 +5976,7 @@ bm.consider (IDENTIFIER_POINTER (resword_identifier)); } - return bm.get_best_meaningful_candidate (); + return name_hint (bm.get_best_meaningful_candidate (), NULL); } /* Subroutine of outer_binding. @@ -6231,27 +6524,30 @@ tree decl; cp_binding_level *b = current_binding_level; - while (/* Cleanup scopes are not scopes from the point of view of - the language. */ - b->kind == sk_cleanup - /* Neither are function parameter scopes. */ - || b->kind == sk_function_parms - /* Neither are the scopes used to hold template parameters - for an explicit specialization. For an ordinary template - declaration, these scopes are not scopes from the point of - view of the language. */ - || (b->kind == sk_template_parms - && (b->explicit_spec_p || scope == ts_global)) - /* Pushing into a class is ok for lambdas or when we want current */ - || (b->kind == sk_class - && scope != ts_lambda - && (scope != ts_current - /* We may be defining a new type in the initializer - of a static member variable. We allow this when - not pedantic, and it is particularly useful for - type punning via an anonymous union. */ - || COMPLETE_TYPE_P (b->this_entity)))) - b = b->level_chain; + while (true) + { + if (/* Cleanup scopes are not scopes from the point of view of + the language. */ + b->kind == sk_cleanup + /* Neither are function parameter scopes. */ + || b->kind == sk_function_parms + /* Neither are the scopes used to hold template parameters + for an explicit specialization. For an ordinary template + declaration, these scopes are not scopes from the point of + view of the language. */ + || (b->kind == sk_template_parms + && (b->explicit_spec_p || scope == ts_global))) + b = b->level_chain; + else if (b->kind == sk_class + && scope != ts_current) + { + b = b->level_chain; + if (b->kind == sk_template_parms) + b = b->level_chain; + } + else + break; + } gcc_assert (identifier_p (name)); @@ -6264,10 +6560,20 @@ if (! context) { - tree cs = current_scope (); + cp_binding_level *cb = b; + while (cb->kind != sk_namespace + && cb->kind != sk_class + && (cb->kind != sk_function_parms + || !cb->this_entity)) + cb = cb->level_chain; + tree cs = cb->this_entity; + + gcc_checking_assert (TREE_CODE (cs) == FUNCTION_DECL + ? cs == current_function_decl + : TYPE_P (cs) ? cs == current_class_type + : cs == current_namespace); if (scope == ts_current - || scope == ts_lambda || (cs && TREE_CODE (cs) == FUNCTION_DECL)) context = cs; else if (cs && TYPE_P (cs)) @@ -6304,11 +6610,11 @@ if (b->kind == sk_class) { - if (!TYPE_BEING_DEFINED (current_class_type) - && scope != ts_lambda) - return error_mark_node; - - if (!PROCESSING_REAL_TEMPLATE_DECL_P ()) + if (!TYPE_BEING_DEFINED (current_class_type)) + /* Don't push anywhere if the class is complete; a lambda in an + NSDMI is not a member of the class. */ + ; + else if (!PROCESSING_REAL_TEMPLATE_DECL_P ()) /* Put this TYPE_DECL on the TYPE_FIELDS list for the class. But if it's a member template class, we want the TEMPLATE_DECL, not the TYPE_DECL, so this is done @@ -6327,8 +6633,8 @@ && init_list_identifier == DECL_NAME (TYPE_NAME (type)) && !CLASSTYPE_TEMPLATE_INFO (type)) { - error ("declaration of std::initializer_list does not match " - "#include <initializer_list>, isn't a template"); + error ("declaration of %<std::initializer_list%> does not match " + "%<#include <initializer_list>%>, isn't a template"); return error_mark_node; } } @@ -6352,7 +6658,8 @@ template instantiation rather than in some nested context. */ add_decl_expr (decl); } - else + /* Lambdas use LAMBDA_EXPR_DISCRIMINATOR instead. */ + else if (!LAMBDA_TYPE_P (type)) vec_safe_push (local_classes, type); } } @@ -6570,7 +6877,7 @@ scope_chain = s; current_function_decl = NULL_TREE; - vec_alloc (current_lang_base, 10); + current_lang_base = NULL; current_lang_name = lang_name_cplusplus; current_namespace = global_namespace; push_class_stack (); @@ -6590,7 +6897,7 @@ invalidate_class_lookup_cache (); pop_class_stack (); - current_lang_base = 0; + release_tree_vector (current_lang_base); scope_chain = s->prev; FOR_EACH_VEC_SAFE_ELT (s->old_bindings, i, saved) @@ -6958,7 +7265,7 @@ of a builtin function. */ if (TREE_CODE (t) == FUNCTION_DECL && DECL_EXTERNAL (t) - && DECL_BUILT_IN (t)) + && fndecl_built_in_p (t)) return; /* Do not supply context to imported_module_or_decl, if