| /* Process declarations and variables for C++ compiler. |
| Copyright (C) 1988-2019 Free Software Foundation, Inc. |
| Contributed by Michael Tiemann (tiemann@cygnus.com) |
| |
| This file is part of GCC. |
| |
| GCC is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 3, or (at your option) |
| any later version. |
| |
| GCC is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GCC; see the file COPYING3. If not see |
| <http://www.gnu.org/licenses/>. */ |
| |
| |
| /* Process declarations and symbol lookup for C++ front end. |
| Also constructs types; the standard scalar types at initialization, |
| and structure, union, array and enum types when they are declared. */ |
| |
| /* ??? not all decl nodes are given the most useful possible |
| line numbers. For example, the CONST_DECLs for enum values. */ |
| |
| #include "config.h" |
| #include "system.h" |
| #include "coretypes.h" |
| #include "target.h" |
| #include "c-family/c-target.h" |
| #include "cp-tree.h" |
| #include "timevar.h" |
| #include "stringpool.h" |
| #include "cgraph.h" |
| #include "stor-layout.h" |
| #include "varasm.h" |
| #include "attribs.h" |
| #include "flags.h" |
| #include "tree-iterator.h" |
| #include "decl.h" |
| #include "intl.h" |
| #include "toplev.h" |
| #include "c-family/c-objc.h" |
| #include "c-family/c-pragma.h" |
| #include "c-family/c-ubsan.h" |
| #include "debug.h" |
| #include "plugin.h" |
| #include "builtins.h" |
| #include "gimplify.h" |
| #include "asan.h" |
| #include "gcc-rich-location.h" |
| #include "langhooks.h" |
| |
| /* Possible cases of bad specifiers type used by bad_specifiers. */ |
| enum bad_spec_place { |
| BSP_VAR, /* variable */ |
| BSP_PARM, /* parameter */ |
| BSP_TYPE, /* type */ |
| BSP_FIELD /* field */ |
| }; |
| |
| static const char *redeclaration_error_message (tree, tree); |
| |
| static int decl_jump_unsafe (tree); |
| static void require_complete_types_for_parms (tree); |
| static tree grok_reference_init (tree, tree, tree, int); |
| static tree grokvardecl (tree, tree, tree, const cp_decl_specifier_seq *, |
| int, int, int, bool, int, tree, location_t); |
| static void check_static_variable_definition (tree, tree); |
| static void record_unknown_type (tree, const char *); |
| static tree builtin_function_1 (tree, tree, bool); |
| static int member_function_or_else (tree, tree, enum overload_flags); |
| static tree local_variable_p_walkfn (tree *, int *, void *); |
| static const char *tag_name (enum tag_types); |
| static tree lookup_and_check_tag (enum tag_types, tree, tag_scope, bool); |
| static void maybe_deduce_size_from_array_init (tree, tree); |
| static void layout_var_decl (tree); |
| static tree check_initializer (tree, tree, int, vec<tree, va_gc> **); |
| static void make_rtl_for_nonlocal_decl (tree, tree, const char *); |
| static void save_function_data (tree); |
| static void copy_type_enum (tree , tree); |
| static void check_function_type (tree, tree); |
| static void finish_constructor_body (void); |
| static void begin_destructor_body (void); |
| static void finish_destructor_body (void); |
| static void record_key_method_defined (tree); |
| static tree create_array_type_for_decl (tree, tree, tree, location_t); |
| static tree get_atexit_node (void); |
| static tree get_dso_handle_node (void); |
| static tree start_cleanup_fn (void); |
| static void end_cleanup_fn (void); |
| static tree cp_make_fname_decl (location_t, tree, int); |
| static void initialize_predefined_identifiers (void); |
| static tree check_special_function_return_type |
| (special_function_kind, tree, tree, int, const location_t*); |
| static tree push_cp_library_fn (enum tree_code, tree, int); |
| static tree build_cp_library_fn (tree, enum tree_code, tree, int); |
| static void store_parm_decls (tree); |
| static void initialize_local_var (tree, tree); |
| static void expand_static_init (tree, tree); |
| |
| /* The following symbols are subsumed in the cp_global_trees array, and |
| listed here individually for documentation purposes. |
| |
| C++ extensions |
| tree wchar_decl_node; |
| |
| tree vtable_entry_type; |
| tree delta_type_node; |
| tree __t_desc_type_node; |
| |
| tree class_type_node; |
| tree unknown_type_node; |
| |
| Array type `vtable_entry_type[]' |
| |
| tree vtbl_type_node; |
| tree vtbl_ptr_type_node; |
| |
| Namespaces, |
| |
| tree std_node; |
| tree abi_node; |
| |
| A FUNCTION_DECL which can call `abort'. Not necessarily the |
| one that the user will declare, but sufficient to be called |
| by routines that want to abort the program. |
| |
| tree abort_fndecl; |
| |
| Used by RTTI |
| tree type_info_type_node, tinfo_decl_id, tinfo_decl_type; |
| tree tinfo_var_id; */ |
| |
| tree cp_global_trees[CPTI_MAX]; |
| |
| /* A list of objects which have constructors or destructors |
| which reside in the global scope. The decl is stored in |
| the TREE_VALUE slot and the initializer is stored |
| in the TREE_PURPOSE slot. */ |
| tree static_aggregates; |
| |
| /* Like static_aggregates, but for thread_local variables. */ |
| tree tls_aggregates; |
| |
| /* -- end of C++ */ |
| |
| /* A node for the integer constant 2. */ |
| |
| tree integer_two_node; |
| |
| /* vector of static decls. */ |
| vec<tree, va_gc> *static_decls; |
| |
| /* vector of keyed classes. */ |
| vec<tree, va_gc> *keyed_classes; |
| |
| /* Used only for jumps to as-yet undefined labels, since jumps to |
| defined labels can have their validity checked immediately. */ |
| |
| struct GTY((chain_next ("%h.next"))) named_label_use_entry { |
| struct named_label_use_entry *next; |
| /* The binding level to which this entry is *currently* attached. |
| This is initially the binding level in which the goto appeared, |
| but is modified as scopes are closed. */ |
| cp_binding_level *binding_level; |
| /* The head of the names list that was current when the goto appeared, |
| or the inner scope popped. These are the decls that will *not* be |
| skipped when jumping to the label. */ |
| tree names_in_scope; |
| /* The location of the goto, for error reporting. */ |
| location_t o_goto_locus; |
| /* True if an OpenMP structured block scope has been closed since |
| the goto appeared. This means that the branch from the label will |
| illegally exit an OpenMP scope. */ |
| bool in_omp_scope; |
| }; |
| |
| /* A list of all LABEL_DECLs in the function that have names. Here so |
| we can clear out their names' definitions at the end of the |
| function, and so we can check the validity of jumps to these labels. */ |
| |
| struct GTY((for_user)) named_label_entry { |
| |
| tree name; /* Name of decl. */ |
| |
| tree label_decl; /* LABEL_DECL, unless deleted local label. */ |
| |
| named_label_entry *outer; /* Outer shadowed chain. */ |
| |
| /* The binding level to which the label is *currently* attached. |
| This is initially set to the binding level in which the label |
| is defined, but is modified as scopes are closed. */ |
| cp_binding_level *binding_level; |
| |
| /* The head of the names list that was current when the label was |
| defined, or the inner scope popped. These are the decls that will |
| be skipped when jumping to the label. */ |
| tree names_in_scope; |
| |
| /* A vector of all decls from all binding levels that would be |
| crossed by a backward branch to the label. */ |
| vec<tree, va_gc> *bad_decls; |
| |
| /* A list of uses of the label, before the label is defined. */ |
| named_label_use_entry *uses; |
| |
| /* The following bits are set after the label is defined, and are |
| updated as scopes are popped. They indicate that a jump to the |
| label will illegally enter a scope of the given flavor. */ |
| bool in_try_scope; |
| bool in_catch_scope; |
| bool in_omp_scope; |
| bool in_transaction_scope; |
| bool in_constexpr_if; |
| }; |
| |
| #define named_labels cp_function_chain->x_named_labels |
| |
| /* The number of function bodies which we are currently processing. |
| (Zero if we are at namespace scope, one inside the body of a |
| function, two inside the body of a function in a local class, etc.) */ |
| int function_depth; |
| |
| /* Whether the exception-specifier is part of a function type (i.e. C++17). */ |
| bool flag_noexcept_type; |
| |
| /* States indicating how grokdeclarator() should handle declspecs marked |
| with __attribute__((deprecated)). An object declared as |
| __attribute__((deprecated)) suppresses warnings of uses of other |
| deprecated items. */ |
| enum deprecated_states deprecated_state = DEPRECATED_NORMAL; |
| |
| |
| /* A list of VAR_DECLs whose type was incomplete at the time the |
| variable was declared. */ |
| |
| struct GTY(()) incomplete_var { |
| tree decl; |
| tree incomplete_type; |
| }; |
| |
| |
| static GTY(()) vec<incomplete_var, va_gc> *incomplete_vars; |
| |
| /* Returns the kind of template specialization we are currently |
| processing, given that it's declaration contained N_CLASS_SCOPES |
| explicit scope qualifications. */ |
| |
| tmpl_spec_kind |
| current_tmpl_spec_kind (int n_class_scopes) |
| { |
| int n_template_parm_scopes = 0; |
| int seen_specialization_p = 0; |
| int innermost_specialization_p = 0; |
| cp_binding_level *b; |
| |
| /* Scan through the template parameter scopes. */ |
| for (b = current_binding_level; |
| b->kind == sk_template_parms; |
| b = b->level_chain) |
| { |
| /* If we see a specialization scope inside a parameter scope, |
| then something is wrong. That corresponds to a declaration |
| like: |
| |
| template <class T> template <> ... |
| |
| which is always invalid since [temp.expl.spec] forbids the |
| specialization of a class member template if the enclosing |
| class templates are not explicitly specialized as well. */ |
| if (b->explicit_spec_p) |
| { |
| if (n_template_parm_scopes == 0) |
| innermost_specialization_p = 1; |
| else |
| seen_specialization_p = 1; |
| } |
| else if (seen_specialization_p == 1) |
| return tsk_invalid_member_spec; |
| |
| ++n_template_parm_scopes; |
| } |
| |
| /* Handle explicit instantiations. */ |
| if (processing_explicit_instantiation) |
| { |
| if (n_template_parm_scopes != 0) |
| /* We've seen a template parameter list during an explicit |
| instantiation. For example: |
| |
| template <class T> template void f(int); |
| |
| This is erroneous. */ |
| return tsk_invalid_expl_inst; |
| else |
| return tsk_expl_inst; |
| } |
| |
| if (n_template_parm_scopes < n_class_scopes) |
| /* We've not seen enough template headers to match all the |
| specialized classes present. For example: |
| |
| template <class T> void R<T>::S<T>::f(int); |
| |
| This is invalid; there needs to be one set of template |
| parameters for each class. */ |
| return tsk_insufficient_parms; |
| else if (n_template_parm_scopes == n_class_scopes) |
| /* We're processing a non-template declaration (even though it may |
| be a member of a template class.) For example: |
| |
| template <class T> void S<T>::f(int); |
| |
| The `class T' matches the `S<T>', leaving no template headers |
| corresponding to the `f'. */ |
| return tsk_none; |
| else if (n_template_parm_scopes > n_class_scopes + 1) |
| /* We've got too many template headers. For example: |
| |
| template <> template <class T> void f (T); |
| |
| There need to be more enclosing classes. */ |
| return tsk_excessive_parms; |
| else |
| /* This must be a template. It's of the form: |
| |
| template <class T> template <class U> void S<T>::f(U); |
| |
| This is a specialization if the innermost level was a |
| specialization; otherwise it's just a definition of the |
| template. */ |
| return innermost_specialization_p ? tsk_expl_spec : tsk_template; |
| } |
| |
| /* Exit the current scope. */ |
| |
| void |
| finish_scope (void) |
| { |
| poplevel (0, 0, 0); |
| } |
| |
| /* When a label goes out of scope, check to see if that label was used |
| in a valid manner, and issue any appropriate warnings or errors. */ |
| |
| static void |
| check_label_used (tree label) |
| { |
| if (!processing_template_decl) |
| { |
| if (DECL_INITIAL (label) == NULL_TREE) |
| { |
| location_t location; |
| |
| error ("label %q+D used but not defined", label); |
| location = input_location; |
| /* FIXME want (LOCATION_FILE (input_location), (line)0) */ |
| /* Avoid crashing later. */ |
| define_label (location, DECL_NAME (label)); |
| } |
| else |
| warn_for_unused_label (label); |
| } |
| } |
| |
| /* Helper function to sort named label entries in a vector by DECL_UID. */ |
| |
| static int |
| sort_labels (const void *a, const void *b) |
| { |
| tree label1 = *(tree const *) a; |
| tree label2 = *(tree const *) b; |
| |
| /* DECL_UIDs can never be equal. */ |
| return DECL_UID (label1) > DECL_UID (label2) ? -1 : +1; |
| } |
| |
| /* At the end of a function, all labels declared within the function |
| go out of scope. BLOCK is the top-level block for the |
| function. */ |
| |
| static void |
| pop_labels (tree block) |
| { |
| if (!named_labels) |
| return; |
| |
| /* We need to add the labels to the block chain, so debug |
| information is emitted. But, we want the order to be stable so |
| need to sort them first. Otherwise the debug output could be |
| randomly ordered. I guess it's mostly stable, unless the hash |
| table implementation changes. */ |
| auto_vec<tree, 32> labels (named_labels->elements ()); |
| hash_table<named_label_hash>::iterator end (named_labels->end ()); |
| for (hash_table<named_label_hash>::iterator iter |
| (named_labels->begin ()); iter != end; ++iter) |
| { |
| named_label_entry *ent = *iter; |
| |
| gcc_checking_assert (!ent->outer); |
| if (ent->label_decl) |
| labels.quick_push (ent->label_decl); |
| ggc_free (ent); |
| } |
| named_labels = NULL; |
| labels.qsort (sort_labels); |
| |
| while (labels.length ()) |
| { |
| tree label = labels.pop (); |
| |
| DECL_CHAIN (label) = BLOCK_VARS (block); |
| BLOCK_VARS (block) = label; |
| |
| check_label_used (label); |
| } |
| } |
| |
| /* At the end of a block with local labels, restore the outer definition. */ |
| |
| static void |
| pop_local_label (tree id, tree label) |
| { |
| check_label_used (label); |
| named_label_entry **slot = named_labels->find_slot_with_hash |
| (id, IDENTIFIER_HASH_VALUE (id), NO_INSERT); |
| named_label_entry *ent = *slot; |
| |
| if (ent->outer) |
| ent = ent->outer; |
| else |
| { |
| ent = ggc_cleared_alloc<named_label_entry> (); |
| ent->name = id; |
| } |
| *slot = ent; |
| } |
| |
| /* The following two routines are used to interface to Objective-C++. |
| The binding level is purposely treated as an opaque type. */ |
| |
| void * |
| objc_get_current_scope (void) |
| { |
| return current_binding_level; |
| } |
| |
| /* The following routine is used by the NeXT-style SJLJ exceptions; |
| variables get marked 'volatile' so as to not be clobbered by |
| _setjmp()/_longjmp() calls. All variables in the current scope, |
| as well as parent scopes up to (but not including) ENCLOSING_BLK |
| shall be thusly marked. */ |
| |
| void |
| objc_mark_locals_volatile (void *enclosing_blk) |
| { |
| cp_binding_level *scope; |
| |
| for (scope = current_binding_level; |
| scope && scope != enclosing_blk; |
| scope = scope->level_chain) |
| { |
| tree decl; |
| |
| for (decl = scope->names; decl; decl = TREE_CHAIN (decl)) |
| objc_volatilize_decl (decl); |
| |
| /* Do not climb up past the current function. */ |
| if (scope->kind == sk_function_parms) |
| break; |
| } |
| } |
| |
| /* True if B is the level for the condition of a constexpr if. */ |
| |
| static bool |
| level_for_constexpr_if (cp_binding_level *b) |
| { |
| return (b->kind == sk_cond && b->this_entity |
| && TREE_CODE (b->this_entity) == IF_STMT |
| && IF_STMT_CONSTEXPR_P (b->this_entity)); |
| } |
| |
| /* Update data for defined and undefined labels when leaving a scope. */ |
| |
| int |
| poplevel_named_label_1 (named_label_entry **slot, cp_binding_level *bl) |
| { |
| named_label_entry *ent = *slot; |
| cp_binding_level *obl = bl->level_chain; |
| |
| if (ent->binding_level == bl) |
| { |
| tree decl; |
| |
| /* ENT->NAMES_IN_SCOPE may contain a mixture of DECLs and |
| TREE_LISTs representing OVERLOADs, so be careful. */ |
| for (decl = ent->names_in_scope; decl; decl = (DECL_P (decl) |
| ? DECL_CHAIN (decl) |
| : TREE_CHAIN (decl))) |
| if (decl_jump_unsafe (decl)) |
| vec_safe_push (ent->bad_decls, decl); |
| |
| ent->binding_level = obl; |
| ent->names_in_scope = obl->names; |
| switch (bl->kind) |
| { |
| case sk_try: |
| ent->in_try_scope = true; |
| break; |
| case sk_catch: |
| ent->in_catch_scope = true; |
| break; |
| case sk_omp: |
| ent->in_omp_scope = true; |
| break; |
| case sk_transaction: |
| ent->in_transaction_scope = true; |
| break; |
| case sk_block: |
| if (level_for_constexpr_if (bl->level_chain)) |
| ent->in_constexpr_if = true; |
| break; |
| default: |
| break; |
| } |
| } |
| else if (ent->uses) |
| { |
| struct named_label_use_entry *use; |
| |
| for (use = ent->uses; use ; use = use->next) |
| if (use->binding_level == bl) |
| { |
| use->binding_level = obl; |
| use->names_in_scope = obl->names; |
| if (bl->kind == sk_omp) |
| use->in_omp_scope = true; |
| } |
| } |
| |
| return 1; |
| } |
| |
| /* Saved errorcount to avoid -Wunused-but-set-{parameter,variable} warnings |
| when errors were reported, except for -Werror-unused-but-set-*. */ |
| static int unused_but_set_errorcount; |
| |
| /* Exit a binding level. |
| Pop the level off, and restore the state of the identifier-decl mappings |
| that were in effect when this level was entered. |
| |
| If KEEP == 1, this level had explicit declarations, so |
| and create a "block" (a BLOCK node) for the level |
| to record its declarations and subblocks for symbol table output. |
| |
| If FUNCTIONBODY is nonzero, this level is the body of a function, |
| so create a block as if KEEP were set and also clear out all |
| label names. |
| |
| If REVERSE is nonzero, reverse the order of decls before putting |
| them into the BLOCK. */ |
| |
| tree |
| poplevel (int keep, int reverse, int functionbody) |
| { |
| tree link; |
| /* The chain of decls was accumulated in reverse order. |
| Put it into forward order, just for cleanliness. */ |
| tree decls; |
| tree subblocks; |
| tree block; |
| tree decl; |
| scope_kind kind; |
| |
| bool subtime = timevar_cond_start (TV_NAME_LOOKUP); |
| restart: |
| |
| block = NULL_TREE; |
| |
| gcc_assert (current_binding_level->kind != sk_class |
| && current_binding_level->kind != sk_namespace); |
| |
| if (current_binding_level->kind == sk_cleanup) |
| functionbody = 0; |
| subblocks = functionbody >= 0 ? current_binding_level->blocks : 0; |
| |
| gcc_assert (!vec_safe_length (current_binding_level->class_shadowed)); |
| |
| /* We used to use KEEP == 2 to indicate that the new block should go |
| at the beginning of the list of blocks at this binding level, |
| rather than the end. This hack is no longer used. */ |
| gcc_assert (keep == 0 || keep == 1); |
| |
| if (current_binding_level->keep) |
| keep = 1; |
| |
| /* Any uses of undefined labels, and any defined labels, now operate |
| under constraints of next binding contour. */ |
| if (cfun && !functionbody && named_labels) |
| named_labels->traverse<cp_binding_level *, poplevel_named_label_1> |
| (current_binding_level); |
| |
| /* Get the decls in the order they were written. |
| Usually current_binding_level->names is in reverse order. |
| But parameter decls were previously put in forward order. */ |
| |
| decls = current_binding_level->names; |
| if (reverse) |
| { |
| decls = nreverse (decls); |
| current_binding_level->names = decls; |
| } |
| |
| /* If there were any declarations or structure tags in that level, |
| or if this level is a function body, |
| create a BLOCK to record them for the life of this function. */ |
| block = NULL_TREE; |
| /* Avoid function body block if possible. */ |
| if (functionbody && subblocks && BLOCK_CHAIN (subblocks) == NULL_TREE) |
| keep = 0; |
| else if (keep == 1 || functionbody) |
| block = make_node (BLOCK); |
| if (block != NULL_TREE) |
| { |
| BLOCK_VARS (block) = decls; |
| BLOCK_SUBBLOCKS (block) = subblocks; |
| } |
| |
| /* In each subblock, record that this is its superior. */ |
| if (keep >= 0) |
| for (link = subblocks; link; link = BLOCK_CHAIN (link)) |
| BLOCK_SUPERCONTEXT (link) = block; |
| |
| /* Before we remove the declarations first check for unused variables. */ |
| if ((warn_unused_variable || warn_unused_but_set_variable) |
| && current_binding_level->kind != sk_template_parms |
| && !processing_template_decl) |
| for (tree d = get_local_decls (); d; d = TREE_CHAIN (d)) |
| { |
| /* There are cases where D itself is a TREE_LIST. See in |
| push_local_binding where the list of decls returned by |
| getdecls is built. */ |
| decl = TREE_CODE (d) == TREE_LIST ? TREE_VALUE (d) : d; |
| |
| tree type = TREE_TYPE (decl); |
| if (VAR_P (decl) |
| && (! TREE_USED (decl) || !DECL_READ_P (decl)) |
| && ! DECL_IN_SYSTEM_HEADER (decl) |
| /* For structured bindings, consider only real variables, not |
| subobjects. */ |
| && (DECL_DECOMPOSITION_P (decl) ? !DECL_DECOMP_BASE (decl) |
| : (DECL_NAME (decl) && !DECL_ARTIFICIAL (decl))) |
| && type != error_mark_node |
| && (!CLASS_TYPE_P (type) |
| || !TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type) |
| || lookup_attribute ("warn_unused", |
| TYPE_ATTRIBUTES (TREE_TYPE (decl))))) |
| { |
| if (! TREE_USED (decl)) |
| { |
| if (!DECL_NAME (decl) && DECL_DECOMPOSITION_P (decl)) |
| warning_at (DECL_SOURCE_LOCATION (decl), |
| OPT_Wunused_variable, |
| "unused structured binding declaration"); |
| else |
| warning_at (DECL_SOURCE_LOCATION (decl), |
| OPT_Wunused_variable, "unused variable %qD", decl); |
| } |
| else if (DECL_CONTEXT (decl) == current_function_decl |
| // For -Wunused-but-set-variable leave references alone. |
| && !TYPE_REF_P (TREE_TYPE (decl)) |
| && errorcount == unused_but_set_errorcount) |
| { |
| if (!DECL_NAME (decl) && DECL_DECOMPOSITION_P (decl)) |
| warning_at (DECL_SOURCE_LOCATION (decl), |
| OPT_Wunused_but_set_variable, "structured " |
| "binding declaration set but not used"); |
| else |
| warning_at (DECL_SOURCE_LOCATION (decl), |
| OPT_Wunused_but_set_variable, |
| "variable %qD set but not used", decl); |
| unused_but_set_errorcount = errorcount; |
| } |
| } |
| } |
| |
| /* Remove declarations for all the DECLs in this level. */ |
| for (link = decls; link; link = TREE_CHAIN (link)) |
| { |
| decl = TREE_CODE (link) == TREE_LIST ? TREE_VALUE (link) : link; |
| tree name = OVL_NAME (decl); |
| |
| /* Remove the binding. */ |
| if (TREE_CODE (decl) == LABEL_DECL) |
| pop_local_label (name, decl); |
| else |
| pop_local_binding (name, decl); |
| } |
| |
| /* Restore the IDENTIFIER_TYPE_VALUEs. */ |
| for (link = current_binding_level->type_shadowed; |
| link; link = TREE_CHAIN (link)) |
| SET_IDENTIFIER_TYPE_VALUE (TREE_PURPOSE (link), TREE_VALUE (link)); |
| |
| /* There may be OVERLOADs (wrapped in TREE_LISTs) on the BLOCK_VARs |
| list if a `using' declaration put them there. The debugging |
| back ends won't understand OVERLOAD, so we remove them here. |
| Because the BLOCK_VARS are (temporarily) shared with |
| CURRENT_BINDING_LEVEL->NAMES we must do this fixup after we have |
| popped all the bindings. Also remove undeduced 'auto' decls, |
| which LTO doesn't understand, and can't have been used by anything. */ |
| if (block) |
| { |
| tree* d; |
| |
| for (d = &BLOCK_VARS (block); *d; ) |
| { |
| if (TREE_CODE (*d) == TREE_LIST |
| || (!processing_template_decl |
| && undeduced_auto_decl (*d))) |
| *d = TREE_CHAIN (*d); |
| else |
| d = &DECL_CHAIN (*d); |
| } |
| } |
| |
| /* If the level being exited is the top level of a function, |
| check over all the labels. */ |
| if (functionbody) |
| { |
| if (block) |
| { |
| /* Since this is the top level block of a function, the vars are |
| the function's parameters. Don't leave them in the BLOCK |
| because they are found in the FUNCTION_DECL instead. */ |
| BLOCK_VARS (block) = 0; |
| pop_labels (block); |
| } |
| else |
| pop_labels (subblocks); |
| } |
| |
| kind = current_binding_level->kind; |
| if (kind == sk_cleanup) |
| { |
| tree stmt; |
| |
| /* If this is a temporary binding created for a cleanup, then we'll |
| have pushed a statement list level. Pop that, create a new |
| BIND_EXPR for the block, and insert it into the stream. */ |
| stmt = pop_stmt_list (current_binding_level->statement_list); |
| stmt = c_build_bind_expr (input_location, block, stmt); |
| add_stmt (stmt); |
| } |
| |
| leave_scope (); |
| if (functionbody) |
| { |
| /* The current function is being defined, so its DECL_INITIAL |
| should be error_mark_node. */ |
| gcc_assert (DECL_INITIAL (current_function_decl) == error_mark_node); |
| DECL_INITIAL (current_function_decl) = block ? block : subblocks; |
| if (subblocks) |
| { |
| if (FUNCTION_NEEDS_BODY_BLOCK (current_function_decl)) |
| { |
| if (BLOCK_SUBBLOCKS (subblocks)) |
| BLOCK_OUTER_CURLY_BRACE_P (BLOCK_SUBBLOCKS (subblocks)) = 1; |
| } |
| else |
| BLOCK_OUTER_CURLY_BRACE_P (subblocks) = 1; |
| } |
| } |
| else if (block) |
| current_binding_level->blocks |
| = block_chainon (current_binding_level->blocks, block); |
| |
| /* If we did not make a block for the level just exited, |
| any blocks made for inner levels |
| (since they cannot be recorded as subblocks in that level) |
| must be carried forward so they will later become subblocks |
| of something else. */ |
| else if (subblocks) |
| current_binding_level->blocks |
| = block_chainon (current_binding_level->blocks, subblocks); |
| |
| /* Each and every BLOCK node created here in `poplevel' is important |
| (e.g. for proper debugging information) so if we created one |
| earlier, mark it as "used". */ |
| if (block) |
| TREE_USED (block) = 1; |
| |
| /* All temporary bindings created for cleanups are popped silently. */ |
| if (kind == sk_cleanup) |
| goto restart; |
| |
| timevar_cond_stop (TV_NAME_LOOKUP, subtime); |
| return block; |
| } |
| |
| /* Call wrapup_globals_declarations for the globals in NAMESPACE. */ |
| /* Diagnose odr-used extern inline variables without definitions |
| in the current TU. */ |
| |
| int |
| wrapup_namespace_globals () |
| { |
| if (vec<tree, va_gc> *statics = static_decls) |
| { |
| tree decl; |
| unsigned int i; |
| FOR_EACH_VEC_ELT (*statics, i, decl) |
| { |
| if (warn_unused_function |
| && TREE_CODE (decl) == FUNCTION_DECL |
| && DECL_INITIAL (decl) == 0 |
| && DECL_EXTERNAL (decl) |
| && !TREE_PUBLIC (decl) |
| && !DECL_ARTIFICIAL (decl) |
| && !DECL_FRIEND_PSEUDO_TEMPLATE_INSTANTIATION (decl) |
| && !TREE_NO_WARNING (decl)) |
| warning_at (DECL_SOURCE_LOCATION (decl), |
| OPT_Wunused_function, |
| "%qF declared %<static%> but never defined", decl); |
| |
| if (VAR_P (decl) |
| && DECL_EXTERNAL (decl) |
| && DECL_INLINE_VAR_P (decl) |
| && DECL_ODR_USED (decl)) |
| error_at (DECL_SOURCE_LOCATION (decl), |
| "odr-used inline variable %qD is not defined", decl); |
| } |
| |
| /* Clear out the list, so we don't rescan next time. */ |
| static_decls = NULL; |
| |
| /* Write out any globals that need to be output. */ |
| return wrapup_global_declarations (statics->address (), |
| statics->length ()); |
| } |
| return 0; |
| } |
| |
| /* In C++, you don't have to write `struct S' to refer to `S'; you |
| can just use `S'. We accomplish this by creating a TYPE_DECL as |
| if the user had written `typedef struct S S'. Create and return |
| the TYPE_DECL for TYPE. */ |
| |
| tree |
| create_implicit_typedef (tree name, tree type) |
| { |
| tree decl; |
| |
| decl = build_decl (input_location, TYPE_DECL, name, type); |
| DECL_ARTIFICIAL (decl) = 1; |
| /* There are other implicit type declarations, like the one *within* |
| a class that allows you to write `S::S'. We must distinguish |
| amongst these. */ |
| SET_DECL_IMPLICIT_TYPEDEF_P (decl); |
| TYPE_NAME (type) = decl; |
| TYPE_STUB_DECL (type) = decl; |
| |
| return decl; |
| } |
| |
| /* Function-scope local entities that need discriminators. Each entry |
| is a {decl,name} pair. VAR_DECLs for anon unions get their name |
| smashed, so we cannot rely on DECL_NAME. */ |
| |
| static GTY((deletable)) vec<tree, va_gc> *local_entities; |
| |
| /* Determine the mangling discriminator of local DECL. There are |
| generally very few of these in any particular function. */ |
| |
| void |
| determine_local_discriminator (tree decl) |
| { |
| bool subtime = timevar_cond_start (TV_NAME_LOOKUP); |
| retrofit_lang_decl (decl); |
| tree ctx = DECL_CONTEXT (decl); |
| tree name = (TREE_CODE (decl) == TYPE_DECL |
| && TYPE_UNNAMED_P (TREE_TYPE (decl)) |
| ? NULL_TREE : DECL_NAME (decl)); |
| size_t nelts = vec_safe_length (local_entities); |
| for (size_t i = 0; i < nelts; i += 2) |
| { |
| tree *pair = &(*local_entities)[i]; |
| tree d = pair[0]; |
| tree n = pair[1]; |
| gcc_checking_assert (d != decl); |
| if (name == n |
| && TREE_CODE (decl) == TREE_CODE (d) |
| && ctx == DECL_CONTEXT (d)) |
| { |
| tree disc = integer_one_node; |
| if (DECL_DISCRIMINATOR (d)) |
| disc = build_int_cst (TREE_TYPE (disc), |
| TREE_INT_CST_LOW (DECL_DISCRIMINATOR (d)) + 1); |
| DECL_DISCRIMINATOR (decl) = disc; |
| /* Replace the saved decl. */ |
| pair[0] = decl; |
| decl = NULL_TREE; |
| break; |
| } |
| } |
| |
| if (decl) |
| { |
| vec_safe_reserve (local_entities, 2); |
| local_entities->quick_push (decl); |
| local_entities->quick_push (name); |
| } |
| |
| timevar_cond_stop (TV_NAME_LOOKUP, subtime); |
| } |
| |
| |
| /* Subroutine of duplicate_decls: return truthvalue of whether |
| or not types of these decls match. |
| |
| For C++, we must compare the parameter list so that `int' can match |
| `int&' in a parameter position, but `int&' is not confused with |
| `const int&'. */ |
| |
| int |
| decls_match (tree newdecl, tree olddecl, bool record_versions /* = true */) |
| { |
| int types_match; |
| |
| if (newdecl == olddecl) |
| return 1; |
| |
| if (TREE_CODE (newdecl) != TREE_CODE (olddecl)) |
| /* If the two DECLs are not even the same kind of thing, we're not |
| interested in their types. */ |
| return 0; |
| |
| gcc_assert (DECL_P (newdecl)); |
| |
| if (TREE_CODE (newdecl) == FUNCTION_DECL) |
| { |
| tree f1 = TREE_TYPE (newdecl); |
| tree f2 = TREE_TYPE (olddecl); |
| tree p1 = TYPE_ARG_TYPES (f1); |
| tree p2 = TYPE_ARG_TYPES (f2); |
| tree r2; |
| |
| /* Specializations of different templates are different functions |
| even if they have the same type. */ |
| tree t1 = (DECL_USE_TEMPLATE (newdecl) |
| ? DECL_TI_TEMPLATE (newdecl) |
| : NULL_TREE); |
| tree t2 = (DECL_USE_TEMPLATE (olddecl) |
| ? DECL_TI_TEMPLATE (olddecl) |
| : NULL_TREE); |
| if (t1 != t2) |
| return 0; |
| |
| if (CP_DECL_CONTEXT (newdecl) != CP_DECL_CONTEXT (olddecl) |
| && ! (DECL_EXTERN_C_P (newdecl) |
| && DECL_EXTERN_C_P (olddecl))) |
| return 0; |
| |
| /* A new declaration doesn't match a built-in one unless it |
| is also extern "C". */ |
| if (DECL_IS_BUILTIN (olddecl) |
| && DECL_EXTERN_C_P (olddecl) && !DECL_EXTERN_C_P (newdecl)) |
| return 0; |
| |
| if (TREE_CODE (f1) != TREE_CODE (f2)) |
| return 0; |
| |
| /* A declaration with deduced return type should use its pre-deduction |
| type for declaration matching. */ |
| r2 = fndecl_declared_return_type (olddecl); |
| |
| if (same_type_p (TREE_TYPE (f1), r2)) |
| { |
| if (!prototype_p (f2) && DECL_EXTERN_C_P (olddecl) |
| && fndecl_built_in_p (olddecl)) |
| { |
| types_match = self_promoting_args_p (p1); |
| if (p1 == void_list_node) |
| TREE_TYPE (newdecl) = TREE_TYPE (olddecl); |
| } |
| else |
| types_match = |
| compparms (p1, p2) |
| && type_memfn_rqual (f1) == type_memfn_rqual (f2) |
| && (TYPE_ATTRIBUTES (TREE_TYPE (newdecl)) == NULL_TREE |
| || comp_type_attributes (TREE_TYPE (newdecl), |
| TREE_TYPE (olddecl)) != 0); |
| } |
| else |
| types_match = 0; |
| |
| /* The decls dont match if they correspond to two different versions |
| of the same function. Disallow extern "C" functions to be |
| versions for now. */ |
| if (types_match |
| && !DECL_EXTERN_C_P (newdecl) |
| && !DECL_EXTERN_C_P (olddecl) |
| && record_versions |
| && maybe_version_functions (newdecl, olddecl, |
| (!DECL_FUNCTION_VERSIONED (newdecl) |
| || !DECL_FUNCTION_VERSIONED (olddecl)))) |
| return 0; |
| } |
| else if (TREE_CODE (newdecl) == TEMPLATE_DECL) |
| { |
| tree oldres = DECL_TEMPLATE_RESULT (olddecl); |
| tree newres = DECL_TEMPLATE_RESULT (newdecl); |
| |
| if (TREE_CODE (newres) != TREE_CODE (oldres)) |
| return 0; |
| |
| if (!comp_template_parms (DECL_TEMPLATE_PARMS (newdecl), |
| DECL_TEMPLATE_PARMS (olddecl))) |
| return 0; |
| |
| if (TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) == TYPE_DECL) |
| types_match = (same_type_p (TREE_TYPE (oldres), TREE_TYPE (newres)) |
| && equivalently_constrained (olddecl, newdecl)); |
| else |
| // We don't need to check equivalently_constrained for variable and |
| // function templates because we check it on the results. |
| types_match = decls_match (oldres, newres); |
| } |
| else |
| { |
| /* Need to check scope for variable declaration (VAR_DECL). |
| For typedef (TYPE_DECL), scope is ignored. */ |
| if (VAR_P (newdecl) |
| && CP_DECL_CONTEXT (newdecl) != CP_DECL_CONTEXT (olddecl) |
| /* [dcl.link] |
| Two declarations for an object with C language linkage |
| with the same name (ignoring the namespace that qualify |
| it) that appear in different namespace scopes refer to |
| the same object. */ |
| && !(DECL_EXTERN_C_P (olddecl) && DECL_EXTERN_C_P (newdecl))) |
| return 0; |
| |
| if (TREE_TYPE (newdecl) == error_mark_node) |
| types_match = TREE_TYPE (olddecl) == error_mark_node; |
| else if (TREE_TYPE (olddecl) == NULL_TREE) |
| types_match = TREE_TYPE (newdecl) == NULL_TREE; |
| else if (TREE_TYPE (newdecl) == NULL_TREE) |
| types_match = 0; |
| else |
| types_match = comptypes (TREE_TYPE (newdecl), |
| TREE_TYPE (olddecl), |
| COMPARE_REDECLARATION); |
| } |
| |
| // Normal functions can be constrained, as can variable partial |
| // specializations. |
| if (types_match && VAR_OR_FUNCTION_DECL_P (newdecl)) |
| types_match = equivalently_constrained (newdecl, olddecl); |
| |
| return types_match; |
| } |
| |
| /* NEWDECL and OLDDECL have identical signatures. If they are |
| different versions adjust them and return true. |
| If RECORD is set to true, record function versions. */ |
| |
| bool |
| maybe_version_functions (tree newdecl, tree olddecl, bool record) |
| { |
| if (!targetm.target_option.function_versions (newdecl, olddecl)) |
| return false; |
| |
| if (!DECL_FUNCTION_VERSIONED (olddecl)) |
| { |
| DECL_FUNCTION_VERSIONED (olddecl) = 1; |
| if (DECL_ASSEMBLER_NAME_SET_P (olddecl)) |
| mangle_decl (olddecl); |
| } |
| |
| if (!DECL_FUNCTION_VERSIONED (newdecl)) |
| { |
| DECL_FUNCTION_VERSIONED (newdecl) = 1; |
| if (DECL_ASSEMBLER_NAME_SET_P (newdecl)) |
| mangle_decl (newdecl); |
| } |
| |
| if (record) |
| cgraph_node::record_function_versions (olddecl, newdecl); |
| |
| return true; |
| } |
| |
| /* If NEWDECL is `static' and an `extern' was seen previously, |
| warn about it. OLDDECL is the previous declaration. |
| |
| Note that this does not apply to the C++ case of declaring |
| a variable `extern const' and then later `const'. |
| |
| Don't complain about built-in functions, since they are beyond |
| the user's control. */ |
| |
| void |
| warn_extern_redeclared_static (tree newdecl, tree olddecl) |
| { |
| if (TREE_CODE (newdecl) == TYPE_DECL |
| || TREE_CODE (newdecl) == TEMPLATE_DECL |
| || TREE_CODE (newdecl) == CONST_DECL |
| || TREE_CODE (newdecl) == NAMESPACE_DECL) |
| return; |
| |
| /* Don't get confused by static member functions; that's a different |
| use of `static'. */ |
| if (TREE_CODE (newdecl) == FUNCTION_DECL |
| && DECL_STATIC_FUNCTION_P (newdecl)) |
| return; |
| |
| /* If the old declaration was `static', or the new one isn't, then |
| everything is OK. */ |
| if (DECL_THIS_STATIC (olddecl) || !DECL_THIS_STATIC (newdecl)) |
| return; |
| |
| /* It's OK to declare a builtin function as `static'. */ |
| if (TREE_CODE (olddecl) == FUNCTION_DECL |
| && DECL_ARTIFICIAL (olddecl)) |
| return; |
| |
| auto_diagnostic_group d; |
| if (permerror (DECL_SOURCE_LOCATION (newdecl), |
| "%qD was declared %<extern%> and later %<static%>", newdecl)) |
| inform (DECL_SOURCE_LOCATION (olddecl), |
| "previous declaration of %qD", olddecl); |
| } |
| |
| /* NEW_DECL is a redeclaration of OLD_DECL; both are functions or |
| function templates. If their exception specifications do not |
| match, issue a diagnostic. */ |
| |
| static void |
| check_redeclaration_exception_specification (tree new_decl, |
| tree old_decl) |
| { |
| tree new_exceptions = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (new_decl)); |
| tree old_exceptions = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (old_decl)); |
| |
| /* Two default specs are equivalent, don't force evaluation. */ |
| if (UNEVALUATED_NOEXCEPT_SPEC_P (new_exceptions) |
| && UNEVALUATED_NOEXCEPT_SPEC_P (old_exceptions)) |
| return; |
| |
| if (!type_dependent_expression_p (old_decl)) |
| { |
| maybe_instantiate_noexcept (new_decl); |
| maybe_instantiate_noexcept (old_decl); |
| } |
| new_exceptions = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (new_decl)); |
| old_exceptions = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (old_decl)); |
| |
| /* [except.spec] |
| |
| If any declaration of a function has an exception-specification, |
| all declarations, including the definition and an explicit |
| specialization, of that function shall have an |
| exception-specification with the same set of type-ids. */ |
| if (! DECL_IS_BUILTIN (old_decl) |
| && !comp_except_specs (new_exceptions, old_exceptions, ce_normal)) |
| { |
| const char *const msg |
| = G_("declaration of %qF has a different exception specifier"); |
| bool complained = true; |
| location_t new_loc = DECL_SOURCE_LOCATION (new_decl); |
| auto_diagnostic_group d; |
| if (DECL_IN_SYSTEM_HEADER (old_decl)) |
| complained = pedwarn (new_loc, OPT_Wsystem_headers, msg, new_decl); |
| else if (!flag_exceptions) |
| /* We used to silently permit mismatched eh specs with |
| -fno-exceptions, so make them a pedwarn now. */ |
| complained = pedwarn (new_loc, OPT_Wpedantic, msg, new_decl); |
| else |
| error_at (new_loc, msg, new_decl); |
| if (complained) |
| inform (DECL_SOURCE_LOCATION (old_decl), |
| "from previous declaration %qF", old_decl); |
| } |
| } |
| |
| /* Return true if OLD_DECL and NEW_DECL agree on constexprness. |
| Otherwise issue diagnostics. */ |
| |
| static bool |
| validate_constexpr_redeclaration (tree old_decl, tree new_decl) |
| { |
| old_decl = STRIP_TEMPLATE (old_decl); |
| new_decl = STRIP_TEMPLATE (new_decl); |
| if (!VAR_OR_FUNCTION_DECL_P (old_decl) |
| || !VAR_OR_FUNCTION_DECL_P (new_decl)) |
| return true; |
| if (DECL_DECLARED_CONSTEXPR_P (old_decl) |
| == DECL_DECLARED_CONSTEXPR_P (new_decl)) |
| return true; |
| if (TREE_CODE (old_decl) == FUNCTION_DECL) |
| { |
| if (fndecl_built_in_p (old_decl)) |
| { |
| /* Hide a built-in declaration. */ |
| DECL_DECLARED_CONSTEXPR_P (old_decl) |
| = DECL_DECLARED_CONSTEXPR_P (new_decl); |
| return true; |
| } |
| /* 7.1.5 [dcl.constexpr] |
| Note: An explicit specialization can differ from the template |
| declaration with respect to the constexpr specifier. */ |
| if (! DECL_TEMPLATE_SPECIALIZATION (old_decl) |
| && DECL_TEMPLATE_SPECIALIZATION (new_decl)) |
| return true; |
| |
| error_at (DECL_SOURCE_LOCATION (new_decl), |
| "redeclaration %qD differs in %<constexpr%> " |
| "from previous declaration", new_decl); |
| inform (DECL_SOURCE_LOCATION (old_decl), |
| "previous declaration %qD", old_decl); |
| return false; |
| } |
| return true; |
| } |
| |
| // If OLDDECL and NEWDECL are concept declarations with the same type |
| // (i.e., and template parameters), but different requirements, |
| // emit diagnostics and return true. Otherwise, return false. |
| static inline bool |
| check_concept_refinement (tree olddecl, tree newdecl) |
| { |
| if (!DECL_DECLARED_CONCEPT_P (olddecl) || !DECL_DECLARED_CONCEPT_P (newdecl)) |
| return false; |
| |
| tree d1 = DECL_TEMPLATE_RESULT (olddecl); |
| tree d2 = DECL_TEMPLATE_RESULT (newdecl); |
| if (TREE_CODE (d1) != TREE_CODE (d2)) |
| return false; |
| |
| tree t1 = TREE_TYPE (d1); |
| tree t2 = TREE_TYPE (d2); |
| if (TREE_CODE (d1) == FUNCTION_DECL) |
| { |
| if (compparms (TYPE_ARG_TYPES (t1), TYPE_ARG_TYPES (t2)) |
| && comp_template_parms (DECL_TEMPLATE_PARMS (olddecl), |
| DECL_TEMPLATE_PARMS (newdecl)) |
| && !equivalently_constrained (olddecl, newdecl)) |
| { |
| error ("cannot specialize concept %q#D", olddecl); |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /* DECL is a redeclaration of a function or function template. If |
| it does have default arguments issue a diagnostic. Note: this |
| function is used to enforce the requirements in C++11 8.3.6 about |
| no default arguments in redeclarations. */ |
| |
| static void |
| check_redeclaration_no_default_args (tree decl) |
| { |
| gcc_assert (DECL_DECLARES_FUNCTION_P (decl)); |
| |
| for (tree t = FUNCTION_FIRST_USER_PARMTYPE (decl); |
| t && t != void_list_node; t = TREE_CHAIN (t)) |
| if (TREE_PURPOSE (t)) |
| { |
| permerror (DECL_SOURCE_LOCATION (decl), |
| "redeclaration of %q#D may not have default " |
| "arguments", decl); |
| return; |
| } |
| } |
| |
| /* NEWDECL is a redeclaration of a function or function template OLDDECL, |
| in any case represented as FUNCTION_DECLs (the DECL_TEMPLATE_RESULTs of |
| the TEMPLATE_DECLs in case of function templates). This function is used |
| to enforce the final part of C++17 11.3.6/4, about a single declaration: |
| "If a friend declaration specifies a default argument expression, that |
| declaration shall be a definition and shall be the only declaration of |
| the function or function template in the translation unit." */ |
| |
| static void |
| check_no_redeclaration_friend_default_args (tree olddecl, tree newdecl, |
| bool olddecl_hidden_friend_p) |
| { |
| if (!olddecl_hidden_friend_p && !DECL_FRIEND_P (newdecl)) |
| return; |
| |
| tree t1 = FUNCTION_FIRST_USER_PARMTYPE (olddecl); |
| tree t2 = FUNCTION_FIRST_USER_PARMTYPE (newdecl); |
| |
| for (; t1 && t1 != void_list_node; |
| t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2)) |
| if ((olddecl_hidden_friend_p && TREE_PURPOSE (t1)) |
| || (DECL_FRIEND_P (newdecl) && TREE_PURPOSE (t2))) |
| { |
| auto_diagnostic_group d; |
| if (permerror (DECL_SOURCE_LOCATION (newdecl), |
| "friend declaration of %q#D specifies default " |
| "arguments and isn%'t the only declaration", newdecl)) |
| inform (DECL_SOURCE_LOCATION (olddecl), |
| "previous declaration of %q#D", olddecl); |
| return; |
| } |
| } |
| |
| /* Merge tree bits that correspond to attributes noreturn, nothrow, |
| const, malloc, and pure from NEWDECL with those of OLDDECL. */ |
| |
| static void |
| merge_attribute_bits (tree newdecl, tree olddecl) |
| { |
| TREE_THIS_VOLATILE (newdecl) |= TREE_THIS_VOLATILE (olddecl); |
| TREE_THIS_VOLATILE (olddecl) |= TREE_THIS_VOLATILE (newdecl); |
| TREE_NOTHROW (newdecl) |= TREE_NOTHROW (olddecl); |
| TREE_NOTHROW (olddecl) |= TREE_NOTHROW (newdecl); |
| TREE_READONLY (newdecl) |= TREE_READONLY (olddecl); |
| TREE_READONLY (olddecl) |= TREE_READONLY (newdecl); |
| DECL_IS_MALLOC (newdecl) |= DECL_IS_MALLOC (olddecl); |
| DECL_IS_MALLOC (olddecl) |= DECL_IS_MALLOC (newdecl); |
| DECL_PURE_P (newdecl) |= DECL_PURE_P (olddecl); |
| DECL_PURE_P (olddecl) |= DECL_PURE_P (newdecl); |
| DECL_UNINLINABLE (newdecl) |= DECL_UNINLINABLE (olddecl); |
| DECL_UNINLINABLE (olddecl) |= DECL_UNINLINABLE (newdecl); |
| } |
| |
| #define GNU_INLINE_P(fn) (DECL_DECLARED_INLINE_P (fn) \ |
| && lookup_attribute ("gnu_inline", \ |
| DECL_ATTRIBUTES (fn))) |
| |
| /* If NEWDECL is a redeclaration of OLDDECL, merge the declarations. |
| If the redeclaration is invalid, a diagnostic is issued, and the |
| error_mark_node is returned. Otherwise, OLDDECL is returned. |
| |
| If NEWDECL is not a redeclaration of OLDDECL, NULL_TREE is |
| returned. |
| |
| NEWDECL_IS_FRIEND is true if NEWDECL was declared as a friend. */ |
| |
| tree |
| duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) |
| { |
| unsigned olddecl_uid = DECL_UID (olddecl); |
| int olddecl_friend = 0, types_match = 0, hidden_friend = 0; |
| int olddecl_hidden_friend = 0; |
| int new_defines_function = 0; |
| tree new_template_info; |
| location_t olddecl_loc = DECL_SOURCE_LOCATION (olddecl); |
| location_t newdecl_loc = DECL_SOURCE_LOCATION (newdecl); |
| |
| if (newdecl == olddecl) |
| return olddecl; |
| |
| types_match = decls_match (newdecl, olddecl); |
| |
| /* If either the type of the new decl or the type of the old decl is an |
| error_mark_node, then that implies that we have already issued an |
| error (earlier) for some bogus type specification, and in that case, |
| it is rather pointless to harass the user with yet more error message |
| about the same declaration, so just pretend the types match here. */ |
| if (TREE_TYPE (newdecl) == error_mark_node |
| || TREE_TYPE (olddecl) == error_mark_node) |
| return error_mark_node; |
| |
| /* Check for redeclaration and other discrepancies. */ |
| if (TREE_CODE (olddecl) == FUNCTION_DECL |
| && DECL_ARTIFICIAL (olddecl)) |
| { |
| gcc_assert (!DECL_HIDDEN_FRIEND_P (olddecl)); |
| if (TREE_CODE (newdecl) != FUNCTION_DECL) |
| { |
| /* Avoid warnings redeclaring built-ins which have not been |
| explicitly declared. */ |
| if (DECL_ANTICIPATED (olddecl)) |
| { |
| if (TREE_PUBLIC (newdecl) |
| && CP_DECL_CONTEXT (newdecl) == global_namespace) |
| warning_at (newdecl_loc, |
| OPT_Wbuiltin_declaration_mismatch, |
| "built-in function %qD declared as non-function", |
| newdecl); |
| return NULL_TREE; |
| } |
| |
| /* If you declare a built-in or predefined function name as static, |
| the old definition is overridden, but optionally warn this was a |
| bad choice of name. */ |
| if (! TREE_PUBLIC (newdecl)) |
| { |
| warning_at (newdecl_loc, |
| OPT_Wshadow, |
| fndecl_built_in_p (olddecl) |
| ? G_("shadowing built-in function %q#D") |
| : G_("shadowing library function %q#D"), olddecl); |
| /* Discard the old built-in function. */ |
| return NULL_TREE; |
| } |
| /* If the built-in is not ansi, then programs can override |
| it even globally without an error. */ |
| else if (! fndecl_built_in_p (olddecl)) |
| warning_at (newdecl_loc, 0, |
| "library function %q#D redeclared as non-function %q#D", |
| olddecl, newdecl); |
| else |
| error_at (newdecl_loc, |
| "declaration of %q#D conflicts with built-in " |
| "declaration %q#D", newdecl, olddecl); |
| return NULL_TREE; |
| } |
| else if (DECL_OMP_DECLARE_REDUCTION_P (olddecl)) |
| { |
| gcc_assert (DECL_OMP_DECLARE_REDUCTION_P (newdecl)); |
| error_at (newdecl_loc, |
| "redeclaration of %<pragma omp declare reduction%>"); |
| inform (olddecl_loc, |
| "previous %<pragma omp declare reduction%> declaration"); |
| return error_mark_node; |
| } |
| else if (!types_match) |
| { |
| /* Avoid warnings redeclaring built-ins which have not been |
| explicitly declared. */ |
| if (DECL_ANTICIPATED (olddecl)) |
| { |
| tree t1, t2; |
| |
| /* A new declaration doesn't match a built-in one unless it |
| is also extern "C". */ |
| gcc_assert (DECL_IS_BUILTIN (olddecl)); |
| gcc_assert (DECL_EXTERN_C_P (olddecl)); |
| if (!DECL_EXTERN_C_P (newdecl)) |
| return NULL_TREE; |
| |
| for (t1 = TYPE_ARG_TYPES (TREE_TYPE (newdecl)), |
| t2 = TYPE_ARG_TYPES (TREE_TYPE (olddecl)); |
| t1 || t2; |
| t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2)) |
| { |
| if (!t1 || !t2) |
| break; |
| /* FILE, tm types are not known at the time |
| we create the builtins. */ |
| for (unsigned i = 0; |
| i < sizeof (builtin_structptr_types) |
| / sizeof (builtin_structptr_type); |
| ++i) |
| if (TREE_VALUE (t2) == builtin_structptr_types[i].node) |
| { |
| tree t = TREE_VALUE (t1); |
| |
| if (TYPE_PTR_P (t) |
| && TYPE_IDENTIFIER (TREE_TYPE (t)) |
| == get_identifier (builtin_structptr_types[i].str) |
| && compparms (TREE_CHAIN (t1), TREE_CHAIN (t2))) |
| { |
| tree oldargs = TYPE_ARG_TYPES (TREE_TYPE (olddecl)); |
| |
| TYPE_ARG_TYPES (TREE_TYPE (olddecl)) |
| = TYPE_ARG_TYPES (TREE_TYPE (newdecl)); |
| types_match = decls_match (newdecl, olddecl); |
| if (types_match) |
| return duplicate_decls (newdecl, olddecl, |
| newdecl_is_friend); |
| TYPE_ARG_TYPES (TREE_TYPE (olddecl)) = oldargs; |
| } |
| goto next_arg; |
| } |
| |
| if (! same_type_p (TREE_VALUE (t1), TREE_VALUE (t2))) |
| break; |
| next_arg:; |
| } |
| |
| warning_at (newdecl_loc, |
| OPT_Wbuiltin_declaration_mismatch, |
| "declaration of %q#D conflicts with built-in " |
| "declaration %q#D", newdecl, olddecl); |
| } |
| else if ((DECL_EXTERN_C_P (newdecl) |
| && DECL_EXTERN_C_P (olddecl)) |
| || compparms (TYPE_ARG_TYPES (TREE_TYPE (newdecl)), |
| TYPE_ARG_TYPES (TREE_TYPE (olddecl)))) |
| { |
| /* Don't really override olddecl for __* prefixed builtins |
| except for __[^b]*_chk, the compiler might be using those |
| explicitly. */ |
| if (fndecl_built_in_p (olddecl)) |
| { |
| tree id = DECL_NAME (olddecl); |
| const char *name = IDENTIFIER_POINTER (id); |
| size_t len; |
| |
| if (name[0] == '_' |
| && name[1] == '_' |
| && (strncmp (name + 2, "builtin_", |
| strlen ("builtin_")) == 0 |
| || (len = strlen (name)) <= strlen ("___chk") |
| || memcmp (name + len - strlen ("_chk"), |
| "_chk", strlen ("_chk") + 1) != 0)) |
| { |
| if (DECL_INITIAL (newdecl)) |
| { |
| error_at (newdecl_loc, |
| "definition of %q#D ambiguates built-in " |
| "declaration %q#D", newdecl, olddecl); |
| return error_mark_node; |
| } |
| auto_diagnostic_group d; |
| if (permerror (newdecl_loc, |
| "new declaration %q#D ambiguates built-in" |
| " declaration %q#D", newdecl, olddecl) |
| && flag_permissive) |
| inform (newdecl_loc, |
| "ignoring the %q#D declaration", newdecl); |
| return flag_permissive ? olddecl : error_mark_node; |
| } |
| } |
| |
| /* A near match; override the builtin. */ |
| |
| if (TREE_PUBLIC (newdecl)) |
| warning_at (newdecl_loc, |
| OPT_Wbuiltin_declaration_mismatch, |
| "new declaration %q#D ambiguates built-in " |
| "declaration %q#D", newdecl, olddecl); |
| else |
| warning (OPT_Wshadow, |
| fndecl_built_in_p (olddecl) |
| ? G_("shadowing built-in function %q#D") |
| : G_("shadowing library function %q#D"), olddecl); |
| } |
| else |
| /* Discard the old built-in function. */ |
| return NULL_TREE; |
| |
| /* Replace the old RTL to avoid problems with inlining. */ |
| COPY_DECL_RTL (newdecl, olddecl); |
| } |
| /* Even if the types match, prefer the new declarations type for |
| built-ins which have not been explicitly declared, for |
| exception lists, etc... */ |
| else if (DECL_IS_BUILTIN (olddecl)) |
| { |
| tree type = TREE_TYPE (newdecl); |
| tree attribs = (*targetm.merge_type_attributes) |
| (TREE_TYPE (olddecl), type); |
| |
| type = cp_build_type_attribute_variant (type, attribs); |
| TREE_TYPE (newdecl) = TREE_TYPE (olddecl) = type; |
| } |
| |
| /* If a function is explicitly declared "throw ()", propagate that to |
| the corresponding builtin. */ |
| if (DECL_BUILT_IN_CLASS (olddecl) == BUILT_IN_NORMAL |
| && DECL_ANTICIPATED (olddecl) |
| && TREE_NOTHROW (newdecl) |
| && !TREE_NOTHROW (olddecl)) |
| { |
| enum built_in_function fncode = DECL_FUNCTION_CODE (olddecl); |
| tree tmpdecl = builtin_decl_explicit (fncode); |
| if (tmpdecl && tmpdecl != olddecl && types_match) |
| TREE_NOTHROW (tmpdecl) = 1; |
| } |
| |
| /* Whether or not the builtin can throw exceptions has no |
| bearing on this declarator. */ |
| TREE_NOTHROW (olddecl) = 0; |
| |
| if (DECL_THIS_STATIC (newdecl) && !DECL_THIS_STATIC (olddecl)) |
| { |
| /* If a builtin function is redeclared as `static', merge |
| the declarations, but make the original one static. */ |
| DECL_THIS_STATIC (olddecl) = 1; |
| TREE_PUBLIC (olddecl) = 0; |
| |
| /* Make the old declaration consistent with the new one so |
| that all remnants of the builtin-ness of this function |
| will be banished. */ |
| SET_DECL_LANGUAGE (olddecl, DECL_LANGUAGE (newdecl)); |
| COPY_DECL_RTL (newdecl, olddecl); |
| } |
| } |
| else if (TREE_CODE (olddecl) != TREE_CODE (newdecl)) |
| { |
| /* C++ Standard, 3.3, clause 4: |
| "[Note: a namespace name or a class template name must be unique |
| in its declarative region (7.3.2, clause 14). ]" */ |
| if (TREE_CODE (olddecl) == NAMESPACE_DECL |
| || TREE_CODE (newdecl) == NAMESPACE_DECL) |
| /* Namespace conflicts with not namespace. */; |
| else if (DECL_TYPE_TEMPLATE_P (olddecl) |
| || DECL_TYPE_TEMPLATE_P (newdecl)) |
| /* Class template conflicts. */; |
| else if ((TREE_CODE (newdecl) == FUNCTION_DECL |
| && DECL_FUNCTION_TEMPLATE_P (olddecl)) |
| || (TREE_CODE (olddecl) == FUNCTION_DECL |
| && DECL_FUNCTION_TEMPLATE_P (newdecl))) |
| { |
| /* One is a function and the other is a template |
| function. */ |
| if (!UDLIT_OPER_P (DECL_NAME (newdecl))) |
| return NULL_TREE; |
| |
| /* There can only be one! */ |
| if (TREE_CODE (newdecl) == TEMPLATE_DECL |
| && check_raw_literal_operator (olddecl)) |
| error_at (newdecl_loc, |
| "literal operator %q#D conflicts with" |
| " raw literal operator", newdecl); |
| else if (check_raw_literal_operator (newdecl)) |
| error_at (newdecl_loc, |
| "raw literal operator %q#D conflicts with" |
| " literal operator template", newdecl); |
| else |
| return NULL_TREE; |
| |
| inform (olddecl_loc, "previous declaration %q#D", olddecl); |
| return error_mark_node; |
| } |
| else if (DECL_IMPLICIT_TYPEDEF_P (olddecl) |
| || DECL_IMPLICIT_TYPEDEF_P (newdecl)) |
| /* One is an implicit typedef, that's ok. */ |
| return NULL_TREE; |
| |
| error ("%q#D redeclared as different kind of entity", newdecl); |
| inform (olddecl_loc, "previous declaration %q#D", olddecl); |
| |
| return error_mark_node; |
| } |
| else if (!types_match) |
| { |
| if (CP_DECL_CONTEXT (newdecl) != CP_DECL_CONTEXT (olddecl)) |
| /* These are certainly not duplicate declarations; they're |
| from different scopes. */ |
| return NULL_TREE; |
| |
| if (TREE_CODE (newdecl) == TEMPLATE_DECL) |
| { |
| /* The name of a class template may not be declared to refer to |
| any other template, class, function, object, namespace, value, |
| or type in the same scope. */ |
| if (TREE_CODE (DECL_TEMPLATE_RESULT (olddecl)) == TYPE_DECL |
| || TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) == TYPE_DECL) |
| { |
| error_at (newdecl_loc, |
| "conflicting declaration of template %q#D", newdecl); |
| inform (olddecl_loc, |
| "previous declaration %q#D", olddecl); |
| return error_mark_node; |
| } |
| else if (TREE_CODE (DECL_TEMPLATE_RESULT (olddecl)) == FUNCTION_DECL |
| && TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) == FUNCTION_DECL |
| && compparms (TYPE_ARG_TYPES (TREE_TYPE (DECL_TEMPLATE_RESULT (olddecl))), |
| TYPE_ARG_TYPES (TREE_TYPE (DECL_TEMPLATE_RESULT (newdecl)))) |
| && comp_template_parms (DECL_TEMPLATE_PARMS (newdecl), |
| DECL_TEMPLATE_PARMS (olddecl)) |
| /* Template functions can be disambiguated by |
| return type. */ |
| && same_type_p (TREE_TYPE (TREE_TYPE (newdecl)), |
| TREE_TYPE (TREE_TYPE (olddecl))) |
| /* Template functions can also be disambiguated by |
| constraints. */ |
| && equivalently_constrained (olddecl, newdecl)) |
| { |
| error_at (newdecl_loc, "ambiguating new declaration %q#D", |
| newdecl); |
| inform (olddecl_loc, |
| "old declaration %q#D", olddecl); |
| } |
| else if (check_concept_refinement (olddecl, newdecl)) |
| return error_mark_node; |
| return NULL_TREE; |
| } |
| if (TREE_CODE (newdecl) == FUNCTION_DECL) |
| { |
| if (DECL_EXTERN_C_P (newdecl) && DECL_EXTERN_C_P (olddecl)) |
| { |
| error_at (newdecl_loc, |
| "conflicting declaration of C function %q#D", |
| newdecl); |
| inform (olddecl_loc, |
| "previous declaration %q#D", olddecl); |
| return NULL_TREE; |
| } |
| /* For function versions, params and types match, but they |
| are not ambiguous. */ |
| else if ((!DECL_FUNCTION_VERSIONED (newdecl) |
| && !DECL_FUNCTION_VERSIONED (olddecl)) |
| // The functions have the same parameter types. |
| && compparms (TYPE_ARG_TYPES (TREE_TYPE (newdecl)), |
| TYPE_ARG_TYPES (TREE_TYPE (olddecl))) |
| // And the same constraints. |
| && equivalently_constrained (newdecl, olddecl)) |
| { |
| error_at (newdecl_loc, |
| "ambiguating new declaration of %q#D", newdecl); |
| inform (olddecl_loc, |
| "old declaration %q#D", olddecl); |
| return error_mark_node; |
| } |
| else |
| return NULL_TREE; |
| } |
| else |
| { |
| error_at (newdecl_loc, "conflicting declaration %q#D", newdecl); |
| inform (olddecl_loc, |
| "previous declaration as %q#D", olddecl); |
| return error_mark_node; |
| } |
| } |
| else if (TREE_CODE (newdecl) == FUNCTION_DECL |
| && ((DECL_TEMPLATE_SPECIALIZATION (olddecl) |
| && (!DECL_TEMPLATE_INFO (newdecl) |
| || (DECL_TI_TEMPLATE (newdecl) |
| != DECL_TI_TEMPLATE (olddecl)))) |
| || (DECL_TEMPLATE_SPECIALIZATION (newdecl) |
| && (!DECL_TEMPLATE_INFO (olddecl) |
| || (DECL_TI_TEMPLATE (olddecl) |
| != DECL_TI_TEMPLATE (newdecl)))))) |
| /* It's OK to have a template specialization and a non-template |
| with the same type, or to have specializations of two |
| different templates with the same type. Note that if one is a |
| specialization, and the other is an instantiation of the same |
| template, that we do not exit at this point. That situation |
| can occur if we instantiate a template class, and then |
| specialize one of its methods. This situation is valid, but |
| the declarations must be merged in the usual way. */ |
| return NULL_TREE; |
| else if (TREE_CODE (newdecl) == FUNCTION_DECL |
| && ((DECL_TEMPLATE_INSTANTIATION (olddecl) |
| && !DECL_USE_TEMPLATE (newdecl)) |
| || (DECL_TEMPLATE_INSTANTIATION (newdecl) |
| && !DECL_USE_TEMPLATE (olddecl)))) |
| /* One of the declarations is a template instantiation, and the |
| other is not a template at all. That's OK. */ |
| return NULL_TREE; |
| else if (TREE_CODE (newdecl) == NAMESPACE_DECL) |
| { |
| /* In [namespace.alias] we have: |
| |
| In a declarative region, a namespace-alias-definition can be |
| used to redefine a namespace-alias declared in that declarative |
| region to refer only to the namespace to which it already |
| refers. |
| |
| Therefore, if we encounter a second alias directive for the same |
| alias, we can just ignore the second directive. */ |
| if (DECL_NAMESPACE_ALIAS (newdecl) |
| && (DECL_NAMESPACE_ALIAS (newdecl) |
| == DECL_NAMESPACE_ALIAS (olddecl))) |
| return olddecl; |
| |
| /* Leave it to update_binding to merge or report error. */ |
| return NULL_TREE; |
| } |
| else |
| { |
| const char *errmsg = redeclaration_error_message (newdecl, olddecl); |
| if (errmsg) |
| { |
| auto_diagnostic_group d; |
| error_at (newdecl_loc, errmsg, newdecl); |
| if (DECL_NAME (olddecl) != NULL_TREE) |
| inform (olddecl_loc, |
| (DECL_INITIAL (olddecl) && namespace_bindings_p ()) |
| ? G_("%q#D previously defined here") |
| : G_("%q#D previously declared here"), olddecl); |
| return error_mark_node; |
| } |
| else if (TREE_CODE (olddecl) == FUNCTION_DECL |
| && DECL_INITIAL (olddecl) != NULL_TREE |
| && !prototype_p (TREE_TYPE (olddecl)) |
| && prototype_p (TREE_TYPE (newdecl))) |
| { |
| /* Prototype decl follows defn w/o prototype. */ |
| auto_diagnostic_group d; |
| if (warning_at (newdecl_loc, 0, |
| "prototype specified for %q#D", newdecl)) |
| inform (olddecl_loc, |
| "previous non-prototype definition here"); |
| } |
| else if (VAR_OR_FUNCTION_DECL_P (olddecl) |
| && DECL_LANGUAGE (newdecl) != DECL_LANGUAGE (olddecl)) |
| { |
| /* [dcl.link] |
| If two declarations of the same function or object |
| specify different linkage-specifications ..., the program |
| is ill-formed.... Except for functions with C++ linkage, |
| a function declaration without a linkage specification |
| shall not precede the first linkage specification for |
| that function. A function can be declared without a |
| linkage specification after an explicit linkage |
| specification has been seen; the linkage explicitly |
| specified in the earlier declaration is not affected by |
| such a function declaration. |
| |
| DR 563 raises the question why the restrictions on |
| functions should not also apply to objects. Older |
| versions of G++ silently ignore the linkage-specification |
| for this example: |
| |
| namespace N { |
| extern int i; |
| extern "C" int i; |
| } |
| |
| which is clearly wrong. Therefore, we now treat objects |
| like functions. */ |
| if (current_lang_depth () == 0) |
| { |
| /* There is no explicit linkage-specification, so we use |
| the linkage from the previous declaration. */ |
| retrofit_lang_decl (newdecl); |
| SET_DECL_LANGUAGE (newdecl, DECL_LANGUAGE (olddecl)); |
| } |
| else |
| { |
| auto_diagnostic_group d; |
| error_at (newdecl_loc, |
| "conflicting declaration of %q#D with %qL linkage", |
| newdecl, DECL_LANGUAGE (newdecl)); |
| inform (olddecl_loc, |
| "previous declaration with %qL linkage", |
| DECL_LANGUAGE (olddecl)); |
| } |
| } |
| |
| if (DECL_LANG_SPECIFIC (olddecl) && DECL_USE_TEMPLATE (olddecl)) |
| ; |
| else if (TREE_CODE (olddecl) == FUNCTION_DECL) |
| { |
| /* Note: free functions, as TEMPLATE_DECLs, are handled below. */ |
| if (DECL_FUNCTION_MEMBER_P (olddecl) |
| && (/* grokfndecl passes member function templates too |
| as FUNCTION_DECLs. */ |
| DECL_TEMPLATE_INFO (olddecl) |
| /* C++11 8.3.6/6. |
| Default arguments for a member function of a class |
| template shall be specified on the initial declaration |
| of the member function within the class template. */ |
| || CLASSTYPE_TEMPLATE_INFO (CP_DECL_CONTEXT (olddecl)))) |
| check_redeclaration_no_default_args (newdecl); |
| else |
| { |
| tree t1 = FUNCTION_FIRST_USER_PARMTYPE (olddecl); |
| tree t2 = FUNCTION_FIRST_USER_PARMTYPE (newdecl); |
| int i = 1; |
| |
| for (; t1 && t1 != void_list_node; |
| t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2), i++) |
| if (TREE_PURPOSE (t1) && TREE_PURPOSE (t2)) |
| { |
| if (simple_cst_equal (TREE_PURPOSE (t1), |
| TREE_PURPOSE (t2)) == 1) |
| { |
| auto_diagnostic_group d; |
| if (permerror (newdecl_loc, |
| "default argument given for parameter " |
| "%d of %q#D", i, newdecl)) |
| inform (olddecl_loc, |
| "previous specification in %q#D here", |
| olddecl); |
| } |
| else |
| { |
| auto_diagnostic_group d; |
| error_at (newdecl_loc, |
| "default argument given for parameter %d " |
| "of %q#D", i, newdecl); |
| inform (olddecl_loc, |
| "previous specification in %q#D here", |
| olddecl); |
| } |
| } |
| |
| /* C++17 11.3.6/4: "If a friend declaration specifies a default |
| argument expression, that declaration... shall be the only |
| declaration of the function or function template in the |
| translation unit." */ |
| check_no_redeclaration_friend_default_args |
| (olddecl, newdecl, DECL_HIDDEN_FRIEND_P (olddecl)); |
| } |
| } |
| } |
| |
| /* Do not merge an implicit typedef with an explicit one. In: |
| |
| class A; |
| ... |
| typedef class A A __attribute__ ((foo)); |
| |
| the attribute should apply only to the typedef. */ |
| if (TREE_CODE (olddecl) == TYPE_DECL |
| && (DECL_IMPLICIT_TYPEDEF_P (olddecl) |
| || DECL_IMPLICIT_TYPEDEF_P (newdecl))) |
| return NULL_TREE; |
| |
| if (!validate_constexpr_redeclaration (olddecl, newdecl)) |
| return error_mark_node; |
| |
| /* We have committed to returning OLDDECL at this point. */ |
| |
| /* If new decl is `static' and an `extern' was seen previously, |
| warn about it. */ |
| warn_extern_redeclared_static (newdecl, olddecl); |
| |
| /* True to merge attributes between the declarations, false to |
| set OLDDECL's attributes to those of NEWDECL (for template |
| explicit specializations that specify their own attributes |
| independent of those specified for the primary template). */ |
| const bool merge_attr = (TREE_CODE (newdecl) != FUNCTION_DECL |
| || !DECL_TEMPLATE_SPECIALIZATION (newdecl) |
| || DECL_TEMPLATE_SPECIALIZATION (olddecl)); |
| |
| if (TREE_CODE (newdecl) == FUNCTION_DECL) |
| { |
| if (merge_attr && diagnose_mismatched_attributes (olddecl, newdecl)) |
| inform (olddecl_loc, DECL_INITIAL (olddecl) |
| ? G_("previous definition of %qD here") |
| : G_("previous declaration of %qD here"), olddecl); |
| |
| /* Now that functions must hold information normally held |
| by field decls, there is extra work to do so that |
| declaration information does not get destroyed during |
| definition. */ |
| if (DECL_VINDEX (olddecl)) |
| DECL_VINDEX (newdecl) = DECL_VINDEX (olddecl); |
| if (DECL_CONTEXT (olddecl)) |
| DECL_CONTEXT (newdecl) = DECL_CONTEXT (olddecl); |
| DECL_STATIC_CONSTRUCTOR (newdecl) |= DECL_STATIC_CONSTRUCTOR (olddecl); |
| DECL_STATIC_DESTRUCTOR (newdecl) |= DECL_STATIC_DESTRUCTOR (olddecl); |
| DECL_PURE_VIRTUAL_P (newdecl) |= DECL_PURE_VIRTUAL_P (olddecl); |
| DECL_VIRTUAL_P (newdecl) |= DECL_VIRTUAL_P (olddecl); |
| DECL_INVALID_OVERRIDER_P (newdecl) |= DECL_INVALID_OVERRIDER_P (olddecl); |
| DECL_FINAL_P (newdecl) |= DECL_FINAL_P (olddecl); |
| DECL_OVERRIDE_P (newdecl) |= DECL_OVERRIDE_P (olddecl); |
| DECL_THIS_STATIC (newdecl) |= DECL_THIS_STATIC (olddecl); |
| if (DECL_OVERLOADED_OPERATOR_P (olddecl)) |
| DECL_OVERLOADED_OPERATOR_CODE_RAW (newdecl) |
| = DECL_OVERLOADED_OPERATOR_CODE_RAW (olddecl); |
| new_defines_function = DECL_INITIAL (newdecl) != NULL_TREE; |
| |
| /* Optionally warn about more than one declaration for the same |
| name, but don't warn about a function declaration followed by a |
| definition. */ |
| if (warn_redundant_decls && ! DECL_ARTIFICIAL (olddecl) |
| && !(new_defines_function && DECL_INITIAL (olddecl) == NULL_TREE) |
| /* Don't warn about extern decl followed by definition. */ |
| && !(DECL_EXTERNAL (olddecl) && ! DECL_EXTERNAL (newdecl)) |
| /* Don't warn about friends, let add_friend take care of it. */ |
| && ! (newdecl_is_friend || DECL_FRIEND_P (olddecl)) |
| /* Don't warn about declaration followed by specialization. */ |
| && (! DECL_TEMPLATE_SPECIALIZATION (newdecl) |
| || DECL_TEMPLATE_SPECIALIZATION (olddecl))) |
| { |
| auto_diagnostic_group d; |
| if (warning_at (newdecl_loc, |
| OPT_Wredundant_decls, |
| "redundant redeclaration of %qD in same scope", |
| newdecl)) |
| inform (olddecl_loc, |
| "previous declaration of %qD", olddecl); |
| } |
| |
| if (!(DECL_TEMPLATE_INSTANTIATION (olddecl) |
| && DECL_TEMPLATE_SPECIALIZATION (newdecl))) |
| { |
| if (DECL_DELETED_FN (newdecl)) |
| { |
| auto_diagnostic_group d; |
| error_at (newdecl_loc, "deleted definition of %qD", newdecl); |
| inform (olddecl_loc, |
| "previous declaration of %qD", olddecl); |
| } |
| DECL_DELETED_FN (newdecl) |= DECL_DELETED_FN (olddecl); |
| } |
| } |
| |
| /* Deal with C++: must preserve virtual function table size. */ |
| if (TREE_CODE (olddecl) == TYPE_DECL) |
| { |
| tree newtype = TREE_TYPE (newdecl); |
| tree oldtype = TREE_TYPE (olddecl); |
| |
| if (newtype != error_mark_node && oldtype != error_mark_node |
| && TYPE_LANG_SPECIFIC (newtype) && TYPE_LANG_SPECIFIC (oldtype)) |
| CLASSTYPE_FRIEND_CLASSES (newtype) |
| = CLASSTYPE_FRIEND_CLASSES (oldtype); |
| |
| DECL_ORIGINAL_TYPE (newdecl) = DECL_ORIGINAL_TYPE (olddecl); |
| } |
| |
| /* Copy all the DECL_... slots specified in the new decl except for |
| any that we copy here from the old type. */ |
| if (merge_attr) |
| DECL_ATTRIBUTES (newdecl) |
| = (*targetm.merge_decl_attributes) (olddecl, newdecl); |
| else |
| DECL_ATTRIBUTES (olddecl) = DECL_ATTRIBUTES (newdecl); |
| |
| if (DECL_DECLARES_FUNCTION_P (olddecl)) |
| { |
| olddecl_friend = DECL_FRIEND_P (olddecl); |
| olddecl_hidden_friend = DECL_HIDDEN_FRIEND_P (olddecl); |
| hidden_friend = (DECL_ANTICIPATED (olddecl) |
| && DECL_HIDDEN_FRIEND_P (olddecl) |
| && newdecl_is_friend); |
| if (!hidden_friend) |
| { |
| DECL_ANTICIPATED (olddecl) = 0; |
| DECL_HIDDEN_FRIEND_P (olddecl) = 0; |
| } |
| } |
| |
| if (TREE_CODE (newdecl) == TEMPLATE_DECL) |
| { |
| tree old_result = DECL_TEMPLATE_RESULT (olddecl); |
| tree new_result = DECL_TEMPLATE_RESULT (newdecl); |
| TREE_TYPE (olddecl) = TREE_TYPE (old_result); |
| DECL_TEMPLATE_SPECIALIZATIONS (olddecl) |
| = chainon (DECL_TEMPLATE_SPECIALIZATIONS (olddecl), |
| DECL_TEMPLATE_SPECIALIZATIONS (newdecl)); |
| |
| DECL_ATTRIBUTES (old_result) |
| = (*targetm.merge_decl_attributes) (old_result, new_result); |
| |
| if (DECL_FUNCTION_TEMPLATE_P (newdecl)) |
| { |
| if (DECL_SOURCE_LOCATION (newdecl) |
| != DECL_SOURCE_LOCATION (olddecl)) |
| { |
| /* Per C++11 8.3.6/4, default arguments cannot be added in |
| later declarations of a function template. */ |
| check_redeclaration_no_default_args (newdecl); |
| /* C++17 11.3.6/4: "If a friend declaration specifies a default |
| argument expression, that declaration... shall be the only |
| declaration of the function or function template in the |
| translation unit." */ |
| check_no_redeclaration_friend_default_args |
| (old_result, new_result, olddecl_hidden_friend); |
| } |
| |
| check_default_args (newdecl); |
| |
| if (GNU_INLINE_P (old_result) != GNU_INLINE_P (new_result) |
| && DECL_INITIAL (new_result)) |
| { |
| if (DECL_INITIAL (old_result)) |
| DECL_UNINLINABLE (old_result) = 1; |
| else |
| DECL_UNINLINABLE (old_result) = DECL_UNINLINABLE (new_result); |
| DECL_EXTERNAL (old_result) = DECL_EXTERNAL (new_result); |
| DECL_NOT_REALLY_EXTERN (old_result) |
| = DECL_NOT_REALLY_EXTERN (new_result); |
| DECL_INTERFACE_KNOWN (old_result) |
| = DECL_INTERFACE_KNOWN (new_result); |
| DECL_DECLARED_INLINE_P (old_result) |
| = DECL_DECLARED_INLINE_P (new_result); |
| DECL_DISREGARD_INLINE_LIMITS (old_result) |
| |= DECL_DISREGARD_INLINE_LIMITS (new_result); |
| |
| } |
| else |
| { |
| DECL_DECLARED_INLINE_P (old_result) |
| |= DECL_DECLARED_INLINE_P (new_result); |
| DECL_DISREGARD_INLINE_LIMITS (old_result) |
| |= DECL_DISREGARD_INLINE_LIMITS (new_result); |
| check_redeclaration_exception_specification (newdecl, olddecl); |
| |
| merge_attribute_bits (new_result, old_result); |
| } |
| } |
| |
| /* If the new declaration is a definition, update the file and |
| line information on the declaration, and also make |
| the old declaration the same definition. */ |
| if (DECL_INITIAL (new_result) != NULL_TREE) |
| { |
| DECL_SOURCE_LOCATION (olddecl) |
| = DECL_SOURCE_LOCATION (old_result) |
| = DECL_SOURCE_LOCATION (newdecl); |
| DECL_INITIAL (old_result) = DECL_INITIAL (new_result); |
| if (DECL_FUNCTION_TEMPLATE_P (newdecl)) |
| { |
| tree parm; |
| DECL_ARGUMENTS (old_result) |
| = DECL_ARGUMENTS (new_result); |
| for (parm = DECL_ARGUMENTS (old_result); parm; |
| parm = DECL_CHAIN (parm)) |
| DECL_CONTEXT (parm) = old_result; |
| } |
| } |
| |
| return olddecl; |
| } |
| |
| if (types_match) |
| { |
| if (TREE_CODE (newdecl) == FUNCTION_DECL) |
| check_redeclaration_exception_specification (newdecl, olddecl); |
| |
| /* Automatically handles default parameters. */ |
| tree oldtype = TREE_TYPE (olddecl); |
| tree newtype; |
| |
| /* For typedefs use the old type, as the new type's DECL_NAME points |
| at newdecl, which will be ggc_freed. */ |
| if (TREE_CODE (newdecl) == TYPE_DECL) |
| { |
| /* But NEWTYPE might have an attribute, honor that. */ |
| tree tem = TREE_TYPE (newdecl); |
| newtype = oldtype; |
| |
| if (TYPE_USER_ALIGN (tem)) |
| { |
| if (TYPE_ALIGN (tem) > TYPE_ALIGN (newtype)) |
| SET_TYPE_ALIGN (newtype, TYPE_ALIGN (tem)); |
| TYPE_USER_ALIGN (newtype) = true; |
| } |
| |
| /* And remove the new type from the variants list. */ |
| if (TYPE_NAME (TREE_TYPE (newdecl)) == newdecl) |
| { |
| tree remove = TREE_TYPE (newdecl); |
| if (TYPE_MAIN_VARIANT (remove) == remove) |
| { |
| gcc_assert (TYPE_NEXT_VARIANT (remove) == NULL_TREE); |
| /* If remove is the main variant, no need to remove that |
| from the list. One of the DECL_ORIGINAL_TYPE |
| variants, e.g. created for aligned attribute, might still |
| refer to the newdecl TYPE_DECL though, so remove that one |
| in that case. */ |
| if (tree orig = DECL_ORIGINAL_TYPE (newdecl)) |
| if (orig != remove) |
| for (tree t = TYPE_MAIN_VARIANT (orig); t; |
| t = TYPE_MAIN_VARIANT (t)) |
| if (TYPE_NAME (TYPE_NEXT_VARIANT (t)) == newdecl) |
| { |
| TYPE_NEXT_VARIANT (t) |
| = TYPE_NEXT_VARIANT (TYPE_NEXT_VARIANT (t)); |
| break; |
| } |
| } |
| else |
| for (tree t = TYPE_MAIN_VARIANT (remove); ; |
| t = TYPE_NEXT_VARIANT (t)) |
| if (TYPE_NEXT_VARIANT (t) == remove) |
| { |
| TYPE_NEXT_VARIANT (t) = TYPE_NEXT_VARIANT (remove); |
| break; |
| } |
| } |
| } |
| else if (merge_attr) |
| newtype = merge_types (TREE_TYPE (newdecl), TREE_TYPE (olddecl)); |
| else |
| newtype = TREE_TYPE (newdecl); |
| |
| if (VAR_P (newdecl)) |
| { |
| DECL_THIS_EXTERN (newdecl) |= DECL_THIS_EXTERN (olddecl); |
| /* For already initialized vars, TREE_READONLY could have been |
| cleared in cp_finish_decl, because the var needs runtime |
| initialization or destruction. Make sure not to set |
| TREE_READONLY on it again. */ |
| if (DECL_INITIALIZED_P (olddecl) |
| && !DECL_EXTERNAL (olddecl) |
| && !TREE_READONLY (olddecl)) |
| TREE_READONLY (newdecl) = 0; |
| DECL_INITIALIZED_P (newdecl) |= DECL_INITIALIZED_P (olddecl); |
| DECL_NONTRIVIALLY_INITIALIZED_P (newdecl) |
| |= DECL_NONTRIVIALLY_INITIALIZED_P (olddecl); |
| if (DECL_DEPENDENT_INIT_P (olddecl)) |
| SET_DECL_DEPENDENT_INIT_P (newdecl, true); |
| DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (newdecl) |
| |= DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (olddecl); |
| if (DECL_CLASS_SCOPE_P (olddecl)) |
| DECL_DECLARED_CONSTEXPR_P (newdecl) |
| |= DECL_DECLARED_CONSTEXPR_P (olddecl); |
| |
| /* Merge the threadprivate attribute from OLDDECL into NEWDECL. */ |
| if (DECL_LANG_SPECIFIC (olddecl) |
| && CP_DECL_THREADPRIVATE_P (olddecl)) |
| { |
| /* Allocate a LANG_SPECIFIC structure for NEWDECL, if needed. */ |
| retrofit_lang_decl (newdecl); |
| CP_DECL_THREADPRIVATE_P (newdecl) = 1; |
| } |
| } |
| |
| /* An explicit specialization of a function template or of a member |
| function of a class template can be declared transaction_safe |
| independently of whether the corresponding template entity is declared |
| transaction_safe. */ |
| if (flag_tm && TREE_CODE (newdecl) == FUNCTION_DECL |
| && DECL_TEMPLATE_INSTANTIATION (olddecl) |
| && DECL_TEMPLATE_SPECIALIZATION (newdecl) |
| && tx_safe_fn_type_p (newtype) |
| && !tx_safe_fn_type_p (TREE_TYPE (newdecl))) |
| newtype = tx_unsafe_fn_variant (newtype); |
| |
| TREE_TYPE (newdecl) = TREE_TYPE (olddecl) = newtype; |
| |
| if (TREE_CODE (newdecl) == FUNCTION_DECL) |
| check_default_args (newdecl); |
| |
| /* Lay the type out, unless already done. */ |
| if (! same_type_p (newtype, oldtype) |
| && TREE_TYPE (newdecl) != error_mark_node |
| && !(processing_template_decl && uses_template_parms (newdecl))) |
| layout_type (TREE_TYPE (newdecl)); |
| |
| if ((VAR_P (newdecl) |
| || TREE_CODE (newdecl) == PARM_DECL |
| || TREE_CODE (newdecl) == RESULT_DECL |
| || TREE_CODE (newdecl) == FIELD_DECL |
| || TREE_CODE (newdecl) == TYPE_DECL) |
| && !(processing_template_decl && uses_template_parms (newdecl))) |
| layout_decl (newdecl, 0); |
| |
| /* Merge deprecatedness. */ |
| if (TREE_DEPRECATED (newdecl)) |
| TREE_DEPRECATED (olddecl) = 1; |
| |
| /* Preserve function specific target and optimization options */ |
| if (TREE_CODE (newdecl) == FUNCTION_DECL) |
| { |
| if (DECL_FUNCTION_SPECIFIC_TARGET (olddecl) |
| && !DECL_FUNCTION_SPECIFIC_TARGET (newdecl)) |
| DECL_FUNCTION_SPECIFIC_TARGET (newdecl) |
| = DECL_FUNCTION_SPECIFIC_TARGET (olddecl); |
| |
| if (DECL_FUNCTION_SPECIFIC_OPTIMIZATION (olddecl) |
| && !DECL_FUNCTION_SPECIFIC_OPTIMIZATION (newdecl)) |
| DECL_FUNCTION_SPECIFIC_OPTIMIZATION (newdecl) |
| = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (olddecl); |
| } |
| else |
| { |
| /* Merge the const type qualifier. */ |
| if (TREE_READONLY (newdecl)) |
| TREE_READONLY (olddecl) = 1; |
| /* Merge the volatile type qualifier. */ |
| if (TREE_THIS_VOLATILE (newdecl)) |
| TREE_THIS_VOLATILE (olddecl) = 1; |
| } |
| |
| /* Merge the initialization information. */ |
| if (DECL_INITIAL (newdecl) == NULL_TREE |
| && DECL_INITIAL (olddecl) != NULL_TREE) |
| { |
| DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl); |
| DECL_SOURCE_LOCATION (newdecl) = DECL_SOURCE_LOCATION (olddecl); |
| if (TREE_CODE (newdecl) == FUNCTION_DECL) |
| { |
| DECL_SAVED_TREE (newdecl) = DECL_SAVED_TREE (olddecl); |
| DECL_STRUCT_FUNCTION (newdecl) = DECL_STRUCT_FUNCTION (olddecl); |
| } |
| } |
| |
| if (TREE_CODE (newdecl) == FUNCTION_DECL) |
| { |
| DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (newdecl) |
| |= DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (olddecl); |
| DECL_NO_LIMIT_STACK (newdecl) |= DECL_NO_LIMIT_STACK (olddecl); |
| DECL_IS_OPERATOR_NEW (newdecl) |= DECL_IS_OPERATOR_NEW (olddecl); |
| DECL_LOOPING_CONST_OR_PURE_P (newdecl) |
| |= DECL_LOOPING_CONST_OR_PURE_P (olddecl); |
| |
| if (merge_attr) |
| merge_attribute_bits (newdecl, olddecl); |
| else |
| { |
| /* Merge the noreturn bit. */ |
| TREE_THIS_VOLATILE (olddecl) = TREE_THIS_VOLATILE (newdecl); |
| TREE_READONLY (olddecl) = TREE_READONLY (newdecl); |
| TREE_NOTHROW (olddecl) = TREE_NOTHROW (newdecl); |
| DECL_IS_MALLOC (olddecl) = DECL_IS_MALLOC (newdecl); |
| DECL_PURE_P (olddecl) = DECL_PURE_P (newdecl); |
| } |
| /* Keep the old RTL. */ |
| COPY_DECL_RTL (olddecl, newdecl); |
| } |
| else if (VAR_P (newdecl) |
| && (DECL_SIZE (olddecl) || !DECL_SIZE (newdecl))) |
| { |
| /* Keep the old RTL. We cannot keep the old RTL if the old |
| declaration was for an incomplete object and the new |
| declaration is not since many attributes of the RTL will |
| change. */ |
| COPY_DECL_RTL (olddecl, newdecl); |
| } |
| } |
| /* If cannot merge, then use the new type and qualifiers, |
| and don't preserve the old rtl. */ |
| else |
| { |
| /* Clean out any memory we had of the old declaration. */ |
| tree oldstatic = value_member (olddecl, static_aggregates); |
| if (oldstatic) |
| TREE_VALUE (oldstatic) = error_mark_node; |
| |
| TREE_TYPE (olddecl) = TREE_TYPE (newdecl); |
| TREE_READONLY (olddecl) = TREE_READONLY (newdecl); |
| TREE_THIS_VOLATILE (olddecl) = TREE_THIS_VOLATILE (newdecl); |
| TREE_NOTHROW (olddecl) = TREE_NOTHROW (newdecl); |
| TREE_SIDE_EFFECTS (olddecl) = TREE_SIDE_EFFECTS (newdecl); |
| } |
| |
| /* Merge the storage class information. */ |
| merge_weak (newdecl, olddecl); |
| |
| DECL_DEFER_OUTPUT (newdecl) |= DECL_DEFER_OUTPUT (olddecl); |
| TREE_PUBLIC (newdecl) = TREE_PUBLIC (olddecl); |
| TREE_STATIC (olddecl) = TREE_STATIC (newdecl) |= TREE_STATIC (olddecl); |
| if (! DECL_EXTERNAL (olddecl)) |
| DECL_EXTERNAL (newdecl) = 0; |
| if (! DECL_COMDAT (olddecl)) |
| DECL_COMDAT (newdecl) = 0; |
| |
| new_template_info = NULL_TREE; |
| if (DECL_LANG_SPECIFIC (newdecl) && DECL_LANG_SPECIFIC (olddecl)) |
| { |
| bool new_redefines_gnu_inline = false; |
| |
| if (new_defines_function |
| && ((DECL_INTERFACE_KNOWN (olddecl) |
| && TREE_CODE (olddecl) == FUNCTION_DECL) |
| || (TREE_CODE (olddecl) == TEMPLATE_DECL |
| && (TREE_CODE (DECL_TEMPLATE_RESULT (olddecl)) |
| == FUNCTION_DECL)))) |
| { |
| tree fn = olddecl; |
| |
| if (TREE_CODE (fn) == TEMPLATE_DECL) |
| fn = DECL_TEMPLATE_RESULT (olddecl); |
| |
| new_redefines_gnu_inline = GNU_INLINE_P (fn) && DECL_INITIAL (fn); |
| } |
| |
| if (!new_redefines_gnu_inline) |
| { |
| DECL_INTERFACE_KNOWN (newdecl) |= DECL_INTERFACE_KNOWN (olddecl); |
| DECL_NOT_REALLY_EXTERN (newdecl) |= DECL_NOT_REALLY_EXTERN (olddecl); |
| DECL_COMDAT (newdecl) |= DECL_COMDAT (olddecl); |
| } |
| DECL_TEMPLATE_INSTANTIATED (newdecl) |
| |= DECL_TEMPLATE_INSTANTIATED (olddecl); |
| DECL_ODR_USED (newdecl) |= DECL_ODR_USED (olddecl); |
| |
| /* If the OLDDECL is an instantiation and/or specialization, |
| then the NEWDECL must be too. But, it may not yet be marked |
| as such if the caller has created NEWDECL, but has not yet |
| figured out that it is a redeclaration. */ |
| if (!DECL_USE_TEMPLATE (newdecl)) |
| DECL_USE_TEMPLATE (newdecl) = DECL_USE_TEMPLATE (olddecl); |
| |
| /* Don't really know how much of the language-specific |
| values we should copy from old to new. */ |
| DECL_IN_AGGR_P (newdecl) = DECL_IN_AGGR_P (olddecl); |
| DECL_REPO_AVAILABLE_P (newdecl) = DECL_REPO_AVAILABLE_P (olddecl); |
| DECL_INITIALIZED_IN_CLASS_P (newdecl) |
| |= DECL_INITIALIZED_IN_CLASS_P (olddecl); |
| |
| if (LANG_DECL_HAS_MIN (newdecl)) |
| { |
| DECL_ACCESS (newdecl) = DECL_ACCESS (olddecl); |
| if (DECL_TEMPLATE_INFO (newdecl)) |
| { |
| new_template_info = DECL_TEMPLATE_INFO (newdecl); |
| if (DECL_TEMPLATE_INSTANTIATION (olddecl) |
| && DECL_TEMPLATE_SPECIALIZATION (newdecl)) |
| /* Remember the presence of explicit specialization args. */ |
| TINFO_USED_TEMPLATE_ID (DECL_TEMPLATE_INFO (olddecl)) |
| = TINFO_USED_TEMPLATE_ID (new_template_info); |
| } |
| DECL_TEMPLATE_INFO (newdecl) = DECL_TEMPLATE_INFO (olddecl); |
| } |
| /* Only functions have these fields. */ |
| if (DECL_DECLARES_FUNCTION_P (newdecl)) |
| { |
| DECL_NONCONVERTING_P (newdecl) = DECL_NONCONVERTING_P (olddecl); |
| DECL_BEFRIENDING_CLASSES (newdecl) |
| = chainon (DECL_BEFRIENDING_CLASSES (newdecl), |
| DECL_BEFRIENDING_CLASSES (olddecl)); |
| /* DECL_THUNKS is only valid for virtual functions, |
| otherwise it is a DECL_FRIEND_CONTEXT. */ |
| if (DECL_VIRTUAL_P (newdecl)) |
| SET_DECL_THUNKS (newdecl, DECL_THUNKS (olddecl)); |
| } |
| /* Only variables have this field. */ |
| else if (VAR_P (newdecl) |
| && VAR_HAD_UNKNOWN_BOUND (olddecl)) |
| SET_VAR_HAD_UNKNOWN_BOUND (newdecl); |
| } |
| |
| if (TREE_CODE (newdecl) == FUNCTION_DECL) |
| { |
| tree parm; |
| |
| /* Merge parameter attributes. */ |
| tree oldarg, newarg; |
| for (oldarg = DECL_ARGUMENTS(olddecl), newarg = DECL_ARGUMENTS(newdecl); |
| oldarg && newarg; |
| oldarg = DECL_CHAIN(oldarg), newarg = DECL_CHAIN(newarg)) |
| { |
| DECL_ATTRIBUTES (newarg) |
| = (*targetm.merge_decl_attributes) (oldarg, newarg); |
| DECL_ATTRIBUTES (oldarg) = DECL_ATTRIBUTES (newarg); |
| } |
| |
| if (DECL_TEMPLATE_INSTANTIATION (olddecl) |
| && !DECL_TEMPLATE_INSTANTIATION (newdecl)) |
| { |
| /* If newdecl is not a specialization, then it is not a |
| template-related function at all. And that means that we |
| should have exited above, returning 0. */ |
| gcc_assert (DECL_TEMPLATE_SPECIALIZATION (newdecl)); |
| |
| if (DECL_ODR_USED (olddecl)) |
| /* From [temp.expl.spec]: |
| |
| If a template, a member template or the member of a class |
| template is explicitly specialized then that |
| specialization shall be declared before the first use of |
| that specialization that would cause an implicit |
| instantiation to take place, in every translation unit in |
| which such a use occurs. */ |
| error ("explicit specialization of %qD after first use", |
| olddecl); |
| |
| SET_DECL_TEMPLATE_SPECIALIZATION (olddecl); |
| DECL_COMDAT (newdecl) = (TREE_PUBLIC (newdecl) |
| && DECL_DECLARED_INLINE_P (newdecl)); |
| |
| /* Don't propagate visibility from the template to the |
| specialization here. We'll do that in determine_visibility if |
| appropriate. */ |
| DECL_VISIBILITY_SPECIFIED (olddecl) = 0; |
| |
| /* [temp.expl.spec/14] We don't inline explicit specialization |
| just because the primary template says so. */ |
| gcc_assert (!merge_attr); |
| |
| DECL_DECLARED_INLINE_P (olddecl) |
| = DECL_DECLARED_INLINE_P (newdecl); |
| |
| DECL_DISREGARD_INLINE_LIMITS (olddecl) |
| = DECL_DISREGARD_INLINE_LIMITS (newdecl); |
| |
| DECL_UNINLINABLE (olddecl) = DECL_UNINLINABLE (newdecl); |
| } |
| else if (new_defines_function && DECL_INITIAL (olddecl)) |
| { |
| /* Never inline re-defined extern inline functions. |
| FIXME: this could be better handled by keeping both |
| function as separate declarations. */ |
| DECL_UNINLINABLE (newdecl) = 1; |
| } |
| else |
| { |
| if (DECL_PENDING_INLINE_P (olddecl)) |
| { |
| DECL_PENDING_INLINE_P (newdecl) = 1; |
| DECL_PENDING_INLINE_INFO (newdecl) |
| = DECL_PENDING_INLINE_INFO (olddecl); |
| } |
| else if (DECL_PENDING_INLINE_P (newdecl)) |
| ; |
| else if (DECL_SAVED_FUNCTION_DATA (newdecl) == NULL) |
| DECL_SAVED_FUNCTION_DATA (newdecl) |
| = DECL_SAVED_FUNCTION_DATA (olddecl); |
| |
| DECL_DECLARED_INLINE_P (newdecl) |= DECL_DECLARED_INLINE_P (olddecl); |
| |
| DECL_UNINLINABLE (newdecl) = DECL_UNINLINABLE (olddecl) |
| = (DECL_UNINLINABLE (newdecl) || DECL_UNINLINABLE (olddecl)); |
| |
| DECL_DISREGARD_INLINE_LIMITS (newdecl) |
| = DECL_DISREGARD_INLINE_LIMITS (olddecl) |
| = (DECL_DISREGARD_INLINE_LIMITS (newdecl) |
| || DECL_DISREGARD_INLINE_LIMITS (olddecl)); |
| } |
| |
| /* Preserve abstractness on cloned [cd]tors. */ |
| DECL_ABSTRACT_P (newdecl) = DECL_ABSTRACT_P (olddecl); |
| |
| /* Update newdecl's parms to point at olddecl. */ |
| for (parm = DECL_ARGUMENTS (newdecl); parm; |
| parm = DECL_CHAIN (parm)) |
| DECL_CONTEXT (parm) = olddecl; |
| |
| if (! types_match) |
| { |
| SET_DECL_LANGUAGE (olddecl, DECL_LANGUAGE (newdecl)); |
| COPY_DECL_ASSEMBLER_NAME (newdecl, olddecl); |
| COPY_DECL_RTL (newdecl, olddecl); |
| } |
| if (! types_match || new_defines_function) |
| { |
| /* These need to be copied so that the names are available. |
| Note that if the types do match, we'll preserve inline |
| info and other bits, but if not, we won't. */ |
| DECL_ARGUMENTS (olddecl) = DECL_ARGUMENTS (newdecl); |
| DECL_RESULT (olddecl) = DECL_RESULT (newdecl); |
| } |
| /* If redeclaring a builtin function, it stays built in |
| if newdecl is a gnu_inline definition, or if newdecl is just |
| a declaration. */ |
| if (fndecl_built_in_p (olddecl) |
| && (new_defines_function ? GNU_INLINE_P (newdecl) : types_match)) |
| { |
| DECL_BUILT_IN_CLASS (newdecl) = DECL_BUILT_IN_CLASS (olddecl); |
| DECL_FUNCTION_CODE (newdecl) = DECL_FUNCTION_CODE (olddecl); |
| /* If we're keeping the built-in definition, keep the rtl, |
| regardless of declaration matches. */ |
| COPY_DECL_RTL (olddecl, newdecl); |
| if (DECL_BUILT_IN_CLASS (newdecl) == BUILT_IN_NORMAL) |
| { |
| enum built_in_function fncode = DECL_FUNCTION_CODE (newdecl); |
| switch (fncode) |
| { |
| /* If a compatible prototype of these builtin functions |
| is seen, assume the runtime implements it with the |
| expected semantics. */ |
| case BUILT_IN_STPCPY: |
| if (builtin_decl_explicit_p (fncode)) |
| set_builtin_decl_implicit_p (fncode, true); |
| break; |
| default: |
| if (builtin_decl_explicit_p (fncode)) |
| set_builtin_decl_declared_p (fncode, true); |
| break; |
| } |
| } |
| |
| copy_attributes_to_builtin (newdecl); |
| } |
| if (new_defines_function) |
| /* If defining a function declared with other language |
| linkage, use the previously declared language linkage. */ |
| SET_DECL_LANGUAGE (newdecl, DECL_LANGUAGE (olddecl)); |
| else if (types_match) |
| { |
| DECL_RESULT (newdecl) = DECL_RESULT (olddecl); |
| /* Don't clear out the arguments if we're just redeclaring a |
| function. */ |
| if (DECL_ARGUMENTS (olddecl)) |
| DECL_ARGUMENTS (newdecl) = DECL_ARGUMENTS (olddecl); |
| } |
| } |
| else if (TREE_CODE (newdecl) == NAMESPACE_DECL) |
| NAMESPACE_LEVEL (newdecl) = NAMESPACE_LEVEL (olddecl); |
| |
| /* Now preserve various other info from the definition. */ |
| TREE_ADDRESSABLE (newdecl) = TREE_ADDRESSABLE (olddecl); |
| TREE_ASM_WRITTEN (newdecl) = TREE_ASM_WRITTEN (olddecl); |
| DECL_COMMON (newdecl) = DECL_COMMON (olddecl); |
| COPY_DECL_ASSEMBLER_NAME (olddecl, newdecl); |
| |
| /* Warn about conflicting visibility specifications. */ |
| if (DECL_VISIBILITY_SPECIFIED (olddecl) |
| && DECL_VISIBILITY_SPECIFIED (newdecl) |
| && DECL_VISIBILITY (newdecl) != DECL_VISIBILITY (olddecl)) |
| { |
| auto_diagnostic_group d; |
| if (warning_at (newdecl_loc, OPT_Wattributes, |
| "%qD: visibility attribute ignored because it " |
| "conflicts with previous declaration", newdecl)) |
| inform (olddecl_loc, |
| "previous declaration of %qD", olddecl); |
| } |
| /* Choose the declaration which specified visibility. */ |
| if (DECL_VISIBILITY_SPECIFIED (olddecl)) |
| { |
| DECL_VISIBILITY (newdecl) = DECL_VISIBILITY (olddecl); |
| DECL_VISIBILITY_SPECIFIED (newdecl) = 1; |
| } |
| /* Init priority used to be merged from newdecl to olddecl by the memcpy, |
| so keep this behavior. */ |
| if (VAR_P (newdecl) && DECL_HAS_INIT_PRIORITY_P (newdecl)) |
| { |
| SET_DECL_INIT_PRIORITY (olddecl, DECL_INIT_PRIORITY (newdecl)); |
| DECL_HAS_INIT_PRIORITY_P (olddecl) = 1; |
| } |
| /* Likewise for DECL_ALIGN, DECL_USER_ALIGN and DECL_PACKED. */ |
| if (DECL_ALIGN (olddecl) > DECL_ALIGN (newdecl)) |
| { |
| SET_DECL_ALIGN (newdecl, DECL_ALIGN (olddecl)); |
| DECL_USER_ALIGN (newdecl) |= DECL_USER_ALIGN (olddecl); |
| } |
| DECL_USER_ALIGN (olddecl) = DECL_USER_ALIGN (newdecl); |
| if (DECL_WARN_IF_NOT_ALIGN (olddecl) |
| > DECL_WARN_IF_NOT_ALIGN (newdecl)) |
| SET_DECL_WARN_IF_NOT_ALIGN (newdecl, |
| DECL_WARN_IF_NOT_ALIGN (olddecl)); |
| if (TREE_CODE (newdecl) == FIELD_DECL) |
| DECL_PACKED (olddecl) = DECL_PACKED (newdecl); |
| |
| /* The DECL_LANG_SPECIFIC information in OLDDECL will be replaced |
| with that from NEWDECL below. */ |
| if (DECL_LANG_SPECIFIC (olddecl)) |
| { |
| gcc_assert (DECL_LANG_SPECIFIC (olddecl) |
| != DECL_LANG_SPECIFIC (newdecl)); |
| ggc_free (DECL_LANG_SPECIFIC (olddecl)); |
| } |
| |
| /* Merge the USED information. */ |
| if (TREE_USED (olddecl)) |
| TREE_USED (newdecl) = 1; |
| else if (TREE_USED (newdecl)) |
| TREE_USED (olddecl) = 1; |
| if (VAR_P (newdecl)) |
| { |
| if (DECL_READ_P (olddecl)) |
| DECL_READ_P (newdecl) = 1; |
| else if (DECL_READ_P (newdecl)) |
| DECL_READ_P (olddecl) = 1; |
| } |
| if (DECL_PRESERVE_P (olddecl)) |
| DECL_PRESERVE_P (newdecl) = 1; |
| else if (DECL_PRESERVE_P (newdecl)) |
| DECL_PRESERVE_P (olddecl) = 1; |
| |
| /* Merge the DECL_FUNCTION_VERSIONED information. newdecl will be copied |
| to olddecl and deleted. */ |
| if (TREE_CODE (newdecl) == FUNCTION_DECL |
| && DECL_FUNCTION_VERSIONED (olddecl)) |
| { |
| /* Set the flag for newdecl so that it gets copied to olddecl. */ |
| DECL_FUNCTION_VERSIONED (newdecl) = 1; |
| /* newdecl will be purged after copying to olddecl and is no longer |
| a version. */ |
| cgraph_node::delete_function_version_by_decl (newdecl); |
| } |
| |
| if (TREE_CODE (newdecl) == FUNCTION_DECL) |
| { |
| int function_size; |
| struct symtab_node *snode = symtab_node::get (olddecl); |
| |
| function_size = sizeof (struct tree_decl_common); |
| |
| memcpy ((char *) olddecl + sizeof (struct tree_common), |
| (char *) newdecl + sizeof (struct tree_common), |
| function_size - sizeof (struct tree_common)); |
| |
| memcpy ((char *) olddecl + sizeof (struct tree_decl_common), |
| (char *) newdecl + sizeof (struct tree_decl_common), |
| sizeof (struct tree_function_decl) - sizeof (struct tree_decl_common)); |
| |
| /* Preserve symtab node mapping. */ |
| olddecl->decl_with_vis.symtab_node = snode; |
| |
| if (new_template_info) |
| /* If newdecl is a template instantiation, it is possible that |
| the following sequence of events has occurred: |
| |
| o A friend function was declared in a class template. The |
| class template was instantiated. |
| |
| o The instantiation of the friend declaration was |
| recorded on the instantiation list, and is newdecl. |
| |
| o Later, however, instantiate_class_template called pushdecl |
| on the newdecl to perform name injection. But, pushdecl in |
| turn called duplicate_decls when it discovered that another |
| declaration of a global function with the same name already |
| existed. |
| |
| o Here, in duplicate_decls, we decided to clobber newdecl. |
| |
| If we're going to do that, we'd better make sure that |
| olddecl, and not newdecl, is on the list of |
| instantiations so that if we try to do the instantiation |
| again we won't get the clobbered declaration. */ |
| reregister_specialization (newdecl, |
| new_template_info, |
| olddecl); |
| } |
| else |
| { |
| size_t size = tree_code_size (TREE_CODE (newdecl)); |
| |
| memcpy ((char *) olddecl + sizeof (struct tree_common), |
| (char *) newdecl + sizeof (struct tree_common), |
| sizeof (struct tree_decl_common) - sizeof (struct tree_common)); |
| switch (TREE_CODE (newdecl)) |
| { |
| case LABEL_DECL: |
| case VAR_DECL: |
| case RESULT_DECL: |
| case PARM_DECL: |
| case FIELD_DECL: |
| case TYPE_DECL: |
| case CONST_DECL: |
| { |
| struct symtab_node *snode = NULL; |
| |
| if (VAR_P (newdecl) |
| && (TREE_STATIC (olddecl) || TREE_PUBLIC (olddecl) |
| || DECL_EXTERNAL (olddecl))) |
| snode = symtab_node::get (olddecl); |
| memcpy ((char *) olddecl + sizeof (struct tree_decl_common), |
| (char *) newdecl + sizeof (struct tree_decl_common), |
| size - sizeof (struct tree_decl_common) |
| + TREE_CODE_LENGTH (TREE_CODE (newdecl)) * sizeof (char *)); |
| if (VAR_P (newdecl)) |
| olddecl->decl_with_vis.symtab_node = snode; |
| } |
| break; |
| default: |
| memcpy ((char *) olddecl + sizeof (struct tree_decl_common), |
| (char *) newdecl + sizeof (struct tree_decl_common), |
| sizeof (struct tree_decl_non_common) - sizeof (struct tree_decl_common) |
| + TREE_CODE_LENGTH (TREE_CODE (newdecl)) * sizeof (char *)); |
| break; |
| } |
| } |
| |
| if (VAR_OR_FUNCTION_DECL_P (newdecl)) |
| { |
| if (DECL_EXTERNAL (olddecl) |
| || TREE_PUBLIC (olddecl) |
| || TREE_STATIC (olddecl)) |
| { |
| /* Merge the section attribute. |
| We want to issue an error if the sections conflict but that must be |
| done later in decl_attributes since we are called before attributes |
| are assigned. */ |
| if (DECL_SECTION_NAME (newdecl) != NULL) |
| set_decl_section_name (olddecl, DECL_SECTION_NAME (newdecl)); |
| |
| if (DECL_ONE_ONLY (newdecl)) |
| { |
| struct symtab_node *oldsym, *newsym; |
| if (TREE_CODE (olddecl) == FUNCTION_DECL) |
| oldsym = cgraph_node::get_create (olddecl); |
| else |
| oldsym = varpool_node::get_create (olddecl); |
| newsym = symtab_node::get (newdecl); |
| oldsym->set_comdat_group (newsym->get_comdat_group ()); |
| } |
| } |
| |
| if (VAR_P (newdecl) |
| && CP_DECL_THREAD_LOCAL_P (newdecl)) |
| { |
| CP_DECL_THREAD_LOCAL_P (olddecl) = true; |
| if (!processing_template_decl) |
| set_decl_tls_model (olddecl, DECL_TLS_MODEL (newdecl)); |
| } |
| } |
| |
| DECL_UID (olddecl) = olddecl_uid; |
| if (olddecl_friend) |
| DECL_FRIEND_P (olddecl) = 1; |
| if (hidden_friend) |
| { |
| DECL_ANTICIPATED (olddecl) = 1; |
| DECL_HIDDEN_FRIEND_P (olddecl) = 1; |
| } |
| |
| /* NEWDECL contains the merged attribute lists. |
| Update OLDDECL to be the same. */ |
| DECL_ATTRIBUTES (olddecl) = DECL_ATTRIBUTES (newdecl); |
| |
| /* If OLDDECL had its DECL_RTL instantiated, re-invoke make_decl_rtl |
| so that encode_section_info has a chance to look at the new decl |
| flags and attributes. */ |
| if (DECL_RTL_SET_P (olddecl) |
| && (TREE_CODE (olddecl) == FUNCTION_DECL |
| || (VAR_P (olddecl) |
| && TREE_STATIC (olddecl)))) |
| make_decl_rtl (olddecl); |
| |
| /* The NEWDECL will no longer be needed. Because every out-of-class |
| declaration of a member results in a call to duplicate_decls, |
| freeing these nodes represents in a significant savings. |
| |
| Before releasing the node, be sore to remove function from symbol |
| table that might have been inserted there to record comdat group. |
| Be sure to however do not free DECL_STRUCT_FUNCTION because this |
| structure is shared in between newdecl and oldecl. */ |
| if (TREE_CODE (newdecl) == FUNCTION_DECL) |
| DECL_STRUCT_FUNCTION (newdecl) = NULL; |
| if (VAR_OR_FUNCTION_DECL_P (newdecl)) |
| { |
| struct symtab_node *snode = symtab_node::get (newdecl); |
| if (snode) |
| snode->remove (); |
| } |
| |
| /* Remove the associated constraints for newdecl, if any, before |
| reclaiming memory. */ |
| if (flag_concepts) |
| remove_constraints (newdecl); |
| |
| ggc_free (newdecl); |
| |
| return olddecl; |
| } |
| |
| /* Return zero if the declaration NEWDECL is valid |
| when the declaration OLDDECL (assumed to be for the same name) |
| has already been seen. |
| Otherwise return an error message format string with a %s |
| where the identifier should go. */ |
| |
| static const char * |
| redeclaration_error_message (tree newdecl, tree olddecl) |
| { |
| if (TREE_CODE (newdecl) == TYPE_DECL) |
| { |
| /* Because C++ can put things into name space for free, |
| constructs like "typedef struct foo { ... } foo" |
| would look like an erroneous redeclaration. */ |
| if (same_type_p (TREE_TYPE (newdecl), TREE_TYPE (olddecl))) |
| return NULL; |
| else |
| return G_("redefinition of %q#D"); |
| } |
| else if (TREE_CODE (newdecl) == FUNCTION_DECL) |
| { |
| /* If this is a pure function, its olddecl will actually be |
| the original initialization to `0' (which we force to call |
| abort()). Don't complain about redefinition in this case. */ |
| if (DECL_LANG_SPECIFIC (olddecl) && DECL_PURE_VIRTUAL_P (olddecl) |
| && DECL_INITIAL (olddecl) == NULL_TREE) |
| return NULL; |
| |
| /* If both functions come from different namespaces, this is not |
| a redeclaration - this is a conflict with a used function. */ |
| if (DECL_NAMESPACE_SCOPE_P (olddecl) |
| && DECL_CONTEXT (olddecl) != DECL_CONTEXT (newdecl) |
| && ! decls_match (olddecl, newdecl)) |
| return G_("%qD conflicts with used function"); |
| |
| /* We'll complain about linkage mismatches in |
| warn_extern_redeclared_static. */ |
| |
| /* Defining the same name twice is no good. */ |
| if (decl_defined_p (olddecl) |
| && decl_defined_p (newdecl)) |
| { |
| if (DECL_NAME (olddecl) == NULL_TREE) |
| return G_("%q#D not declared in class"); |
| else if (!GNU_INLINE_P (olddecl) |
| || GNU_INLINE_P (newdecl)) |
| return G_("redefinition of %q#D"); |
| } |
| |
| if (DECL_DECLARED_INLINE_P (olddecl) && DECL_DECLARED_INLINE_P (newdecl)) |
| { |
| bool olda = GNU_INLINE_P (olddecl); |
| bool newa = GNU_INLINE_P (newdecl); |
| |
| if (olda != newa) |
| { |
| if (newa) |
| return G_("%q+D redeclared inline with " |
| "%<gnu_inline%> attribute"); |
| else |
| return G_("%q+D redeclared inline without " |
| "%<gnu_inline%> attribute"); |
| } |
| } |
| |
| check_abi_tag_redeclaration |
| (olddecl, lookup_attribute ("abi_tag", DECL_ATTRIBUTES (olddecl)), |
| lookup_attribute ("abi_tag", DECL_ATTRIBUTES (newdecl))); |
| |
| return NULL; |
| } |
| else if (TREE_CODE (newdecl) == TEMPLATE_DECL) |
| { |
| tree nt, ot; |
| |
| if (TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) == TYPE_DECL) |
| { |
| if (COMPLETE_TYPE_P (TREE_TYPE (newdecl)) |
| && COMPLETE_TYPE_P (TREE_TYPE (olddecl))) |
| return G_("redefinition of %q#D"); |
| return NULL; |
| } |
| |
| if (TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) != FUNCTION_DECL |
| || (DECL_TEMPLATE_RESULT (newdecl) |
| == DECL_TEMPLATE_RESULT (olddecl))) |
| return NULL; |
| |
| nt = DECL_TEMPLATE_RESULT (newdecl); |
| if (DECL_TEMPLATE_INFO (nt)) |
| nt = DECL_TEMPLATE_RESULT (template_for_substitution (nt)); |
| ot = DECL_TEMPLATE_RESULT (olddecl); |
| if (DECL_TEMPLATE_INFO (ot)) |
| ot = DECL_TEMPLATE_RESULT (template_for_substitution (ot)); |
| if (DECL_INITIAL (nt) && DECL_INITIAL (ot) |
| && (!GNU_INLINE_P (ot) || GNU_INLINE_P (nt))) |
| return G_("redefinition of %q#D"); |
| |
| if (DECL_DECLARED_INLINE_P (ot) && DECL_DECLARED_INLINE_P (nt)) |
| { |
| bool olda = GNU_INLINE_P (ot); |
| bool newa = GNU_INLINE_P (nt); |
| |
| if (olda != newa) |
| { |
| if (newa) |
| return G_("%q+D redeclared inline with " |
| "%<gnu_inline%> attribute"); |
| else |
| return G_("%q+D redeclared inline without " |
| "%<gnu_inline%> attribute"); |
| } |
| } |
| |
| /* Core issue #226 (C++0x): |
| |
| If a friend function template declaration specifies a |
| default template-argument, that declaration shall be a |
| definition and shall be the only declaration of the |
| function template in the translation unit. */ |
| if ((cxx_dialect != cxx98) |
| && TREE_CODE (ot) == FUNCTION_DECL && DECL_FRIEND_P (ot) |
| && !check_default_tmpl_args (nt, DECL_TEMPLATE_PARMS (newdecl), |
| /*is_primary=*/true, |
| /*is_partial=*/false, |
| /*is_friend_decl=*/2)) |
| return G_("redeclaration of friend %q#D " |
| "may not have default template arguments"); |
| |
| return NULL; |
| } |
| else if (VAR_P (newdecl) |
| && CP_DECL_THREAD_LOCAL_P (newdecl) != CP_DECL_THREAD_LOCAL_P (olddecl) |
| && (! DECL_LANG_SPECIFIC (olddecl) |
| || ! CP_DECL_THREADPRIVATE_P (olddecl) |
| || CP_DECL_THREAD_LOCAL_P (newdecl))) |
| { |
| /* Only variables can be thread-local, and all declarations must |
| agree on this property. */ |
| if (CP_DECL_THREAD_LOCAL_P (newdecl)) |
| return G_("thread-local declaration of %q#D follows " |
| "non-thread-local declaration"); |
| else |
| return G_("non-thread-local declaration of %q#D follows " |
| "thread-local declaration"); |
| } |
| else if (toplevel_bindings_p () || DECL_NAMESPACE_SCOPE_P (newdecl)) |
| { |
| /* The objects have been declared at namespace scope. If either |
| is a member of an anonymous union, then this is an invalid |
| redeclaration. For example: |
| |
| int i; |
| union { int i; }; |
| |
| is invalid. */ |
| if ((VAR_P (newdecl) && DECL_ANON_UNION_VAR_P (newdecl)) |
| || (VAR_P (olddecl) && DECL_ANON_UNION_VAR_P (olddecl))) |
| return G_("redeclaration of %q#D"); |
| /* If at least one declaration is a reference, there is no |
| conflict. For example: |
| |
| int i = 3; |
| extern int i; |
| |
| is valid. */ |
| if (DECL_EXTERNAL (newdecl) || DECL_EXTERNAL (olddecl)) |
| return NULL; |
| |
| /* Static data member declared outside a class definition |
| if the variable is defined within the class with constexpr |
| specifier is declaration rather than definition (and |
| deprecated). */ |
| if (cxx_dialect >= cxx17 |
| && VAR_P (olddecl) |
| && DECL_CLASS_SCOPE_P (olddecl) |
| && DECL_DECLARED_CONSTEXPR_P (olddecl) |
| && !DECL_INITIAL (newdecl)) |
| { |
| DECL_EXTERNAL (newdecl) = 1; |
| /* For now, only warn with explicit -Wdeprecated. */ |
| if (global_options_set.x_warn_deprecated) |
| { |
| auto_diagnostic_group d; |
| if (warning_at (DECL_SOURCE_LOCATION (newdecl), OPT_Wdeprecated, |
| "redundant redeclaration of %<constexpr%> " |
| "static data member %qD", newdecl)) |
| inform (DECL_SOURCE_LOCATION (olddecl), |
| "previous declaration of %qD", olddecl); |
| } |
| return NULL; |
| } |
| |
| /* Reject two definitions. */ |
| return G_("redefinition of %q#D"); |
| } |
| else |
| { |
| /* Objects declared with block scope: */ |
| /* Reject two definitions, and reject a definition |
| together with an external reference. */ |
| if (!(DECL_EXTERNAL (newdecl) && DECL_EXTERNAL (olddecl))) |
| return G_("redeclaration of %q#D"); |
| return NULL; |
| } |
| } |
| |
| |
| /* Hash and equality functions for the named_label table. */ |
| |
| hashval_t |
| named_label_hash::hash (const value_type entry) |
| { |
| return IDENTIFIER_HASH_VALUE (entry->name); |
| } |
| |
| bool |
| named_label_hash::equal (const value_type entry, compare_type name) |
| { |
| return name == entry->name; |
| } |
| |
| /* Look for a label named ID in the current function. If one cannot |
| be found, create one. Return the named_label_entry, or NULL on |
| failure. */ |
| |
| static named_label_entry * |
| lookup_label_1 (tree id, bool making_local_p) |
| { |
| /* You can't use labels at global scope. */ |
| if (current_function_decl == NULL_TREE) |
| { |
| error ("label %qE referenced outside of any function", id); |
| return NULL; |
| } |
| |
| if (!named_labels) |
| named_labels = hash_table<named_label_hash>::create_ggc (13); |
| |
| hashval_t hash = IDENTIFIER_HASH_VALUE (id); |
| named_label_entry **slot |
| = named_labels->find_slot_with_hash (id, hash, INSERT); |
| named_label_entry *old = *slot; |
| |
| if (old && old->label_decl) |
| { |
| if (!making_local_p) |
| return old; |
| |
| if (old->binding_level == current_binding_level) |
| { |
| error ("local label %qE conflicts with existing label", id); |
| inform (DECL_SOURCE_LOCATION (old->label_decl), "previous label"); |
| return NULL; |
| } |
| } |
| |
| /* We are making a new decl, create or reuse the named_label_entry */ |
| named_label_entry *ent = NULL; |
| if (old && !old->label_decl) |
| ent = old; |
| else |
| { |
| ent = ggc_cleared_alloc<named_label_entry> (); |
| ent->name = id; |
| ent->outer = old; |
| *slot = ent; |
| } |
| |
| /* Now create the LABEL_DECL. */ |
| tree decl = build_decl (input_location, LABEL_DECL, id, void_type_node); |
| |
| DECL_CONTEXT (decl) = current_function_decl; |
| SET_DECL_MODE (decl, VOIDmode); |
| if (making_local_p) |
| { |
| C_DECLARED_LABEL_FLAG (decl) = true; |
| DECL_CHAIN (decl) = current_binding_level->names; |
| current_binding_level->names = decl; |
| } |
| |
| ent->label_decl = decl; |
| |
| return ent; |
| } |
| |
| /* Wrapper for lookup_label_1. */ |
| |
| tree |
| lookup_label (tree id) |
| { |
| bool subtime = timevar_cond_start (TV_NAME_LOOKUP); |
| named_label_entry *ent = lookup_label_1 (id, false); |
| timevar_cond_stop (TV_NAME_LOOKUP, subtime); |
| return ent ? ent->label_decl : NULL_TREE; |
| } |
| |
| tree |
| declare_local_label (tree id) |
| { |
| bool subtime = timevar_cond_start (TV_NAME_LOOKUP); |
| named_label_entry *ent = lookup_label_1 (id, true); |
| timevar_cond_stop (TV_NAME_LOOKUP, subtime); |
| return ent ? ent->label_decl : NULL_TREE; |
| } |
| |
| /* Returns nonzero if it is ill-formed to jump past the declaration of |
| DECL. Returns 2 if it's also a real problem. */ |
| |
| static int |
| decl_jump_unsafe (tree decl) |
| { |
| /* [stmt.dcl]/3: A program that jumps from a point where a local variable |
| with automatic storage duration is not in scope to a point where it is |
| in scope is ill-formed unless the variable has scalar type, class type |
| with a trivial default constructor and a trivial destructor, a |
| cv-qualified version of one of these types, or an array of one of the |
| preceding types and is declared without an initializer (8.5). */ |
| tree type = TREE_TYPE (decl); |
| |
| if (!VAR_P (decl) || TREE_STATIC (decl) |
| || type == error_mark_node) |
| return 0; |
| |
| if (DECL_NONTRIVIALLY_INITIALIZED_P (decl) |
| || variably_modified_type_p (type, NULL_TREE)) |
| return 2; |
| |
| if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type)) |
| return 1; |
| |
| return 0; |
| } |
| |
| /* A subroutine of check_previous_goto_1 and check_goto to identify a branch |
| to the user. */ |
| |
| static bool |
| identify_goto (tree decl, location_t loc, const location_t *locus, |
| diagnostic_t diag_kind) |
| { |
| bool complained |
| = emit_diagnostic (diag_kind, loc, 0, |
| decl ? N_("jump to label %qD") |
| : N_("jump to case label"), decl); |
| if (complained && locus) |
| inform (*locus, " from here"); |
| return complained; |
| } |
| |
| /* Check that a single previously seen jump to a newly defined label |
| is OK. DECL is the LABEL_DECL or 0; LEVEL is the binding_level for |
| the jump context; NAMES are the names in scope in LEVEL at the jump |
| context; LOCUS is the source position of the jump or 0. Returns |
| true if all is well. */ |
| |
| static bool |
| check_previous_goto_1 (tree decl, cp_binding_level* level, tree names, |
| bool exited_omp, const location_t *locus) |
| { |
| cp_binding_level *b; |
| bool complained = false; |
| int identified = 0; |
| bool saw_eh = false, saw_omp = false, saw_tm = false, saw_cxif = false; |
| |
| if (exited_omp) |
| { |
| complained = identify_goto (decl, input_location, locus, DK_ERROR); |
| if (complained) |
| inform (input_location, " exits OpenMP structured block"); |
| saw_omp = true; |
| identified = 2; |
| } |
| |
| for (b = current_binding_level; b ; b = b->level_chain) |
| { |
| tree new_decls, old_decls = (b == level ? names : NULL_TREE); |
| |
| for (new_decls = b->names; new_decls != old_decls; |
| new_decls = (DECL_P (new_decls) ? DECL_CHAIN (new_decls) |
| : TREE_CHAIN (new_decls))) |
| { |
| int problem = decl_jump_unsafe (new_decls); |
| if (! problem) |
| continue; |
| |
| if (!identified) |
| { |
| complained = identify_goto (decl, input_location, locus, |
| problem > 1 |
| ? DK_ERROR : DK_PERMERROR); |
| identified = 1; |
| } |
| if (complained) |
| { |
| if (problem > 1) |
| inform (DECL_SOURCE_LOCATION (new_decls), |
| " crosses initialization of %q#D", new_decls); |
| else |
| inform (DECL_SOURCE_LOCATION (new_decls), |
| " enters scope of %q#D, which has " |
| "non-trivial destructor", new_decls); |
| } |
| } |
| |
| if (b == level) |
| break; |
| |
| const char *inf = NULL; |
| location_t loc = input_location; |
| switch (b->kind) |
| { |
| case sk_try: |
| if (!saw_eh) |
| inf = N_("enters try block"); |
| saw_eh = true; |
| break; |
| |
| case sk_catch: |
| if (!saw_eh) |
| inf = N_("enters catch block"); |
| saw_eh = true; |
| break; |
| |
| case sk_omp: |
| if (!saw_omp) |
| inf = N_("enters OpenMP structured block"); |
| saw_omp = true; |
| break; |
| |
| case sk_transaction: |
| if (!saw_tm) |
| inf = N_("enters synchronized or atomic statement"); |
| saw_tm = true; |
| break; |
| |
| case sk_block: |
| if (!saw_cxif && level_for_constexpr_if (b->level_chain)) |
| { |
| inf = N_("enters constexpr if statement"); |
| loc = EXPR_LOCATION (b->level_chain->this_entity); |
| saw_cxif = true; |
| } |
| break; |
| |
| default: |
| break; |
| } |
| |
| if (inf) |
| { |
| if (identified < 2) |
| complained = identify_goto (decl, input_location, locus, DK_ERROR); |
| identified = 2; |
| if (complained) |
| inform (loc, " %s", inf); |
| } |
| } |
| |
| return !identified; |
| } |
| |
| static void |
| check_previous_goto (tree decl, struct named_label_use_entry *use) |
| { |
| check_previous_goto_1 (decl, use->binding_level, |
| use->names_in_scope, use->in_omp_scope, |
| &use->o_goto_locus); |
| } |
| |
| static bool |
| check_switch_goto (cp_binding_level* level) |
| { |
| return check_previous_goto_1 (NULL_TREE, level, level->names, false, NULL); |
| } |
| |
| /* Check that a new jump to a label DECL is OK. Called by |
| finish_goto_stmt. */ |
| |
| void |
| check_goto (tree decl) |
| { |
| /* We can't know where a computed goto is jumping. |
| So we assume that it's OK. */ |
| if (TREE_CODE (decl) != LABEL_DECL) |
| return; |
| |
| /* We didn't record any information about this label when we created it, |
| and there's not much point since it's trivial to analyze as a return. */ |
| if (decl == cdtor_label) |
| return; |
| |
| hashval_t hash = IDENTIFIER_HASH_VALUE (DECL_NAME (decl)); |
| named_label_entry **slot |
| = named_labels->find_slot_with_hash (DECL_NAME (decl), hash, NO_INSERT); |
| named_label_entry *ent = *slot; |
| |
| /* If the label hasn't been defined yet, defer checking. */ |
| if (! DECL_INITIAL (decl)) |
| { |
| /* Don't bother creating another use if the last goto had the |
| same data, and will therefore create the same set of errors. */ |
| if (ent->uses |
| && ent->uses->names_in_scope == current_binding_level->names) |
| return; |
| |
| named_label_use_entry *new_use |
| = ggc_alloc<named_label_use_entry> (); |
| new_use->binding_level = current_binding_level; |
| new_use->names_in_scope = current_binding_level->names; |
| new_use->o_goto_locus = input_location; |
| new_use->in_omp_scope = false; |
| |
| new_use->next = ent->uses; |
| ent->uses = new_use; |
| return; |
| } |
| |
| bool saw_catch = false, complained = false; |
| int identified = 0; |
| tree bad; |
| unsigned ix; |
| |
| if (ent->in_try_scope || ent->in_catch_scope || ent->in_transaction_scope |
| || ent->in_constexpr_if |
| || ent->in_omp_scope || !vec_safe_is_empty (ent->bad_decls)) |
| { |
| diagnostic_t diag_kind = DK_PERMERROR; |
| if (ent->in_try_scope || ent->in_catch_scope || ent->in_constexpr_if |
| || ent->in_transaction_scope || ent->in_omp_scope) |
| diag_kind = DK_ERROR; |
| complained = identify_goto (decl, DECL_SOURCE_LOCATION (decl), |
| &input_location, diag_kind); |
| identified = 1 + (diag_kind == DK_ERROR); |
| } |
| |
| FOR_EACH_VEC_SAFE_ELT (ent->bad_decls, ix, bad) |
| { |
| int u = decl_jump_unsafe (bad); |
| |
| if (u > 1 && DECL_ARTIFICIAL (bad)) |
| { |
| /* Can't skip init of __exception_info. */ |
| if (identified == 1) |
| { |
| complained = identify_goto (decl, DECL_SOURCE_LOCATION (decl), |
| &input_location, DK_ERROR); |
| identified = 2; |
| } |
| if (complained) |
| inform (DECL_SOURCE_LOCATION (bad), " enters catch block"); |
| saw_catch = true; |
| } |
| else if (complained) |
| { |
| if (u > 1) |
| inform (DECL_SOURCE_LOCATION (bad), |
| " skips initialization of %q#D", bad); |
| else |
| inform (DECL_SOURCE_LOCATION (bad), |
| " enters scope of %q#D which has " |
| "non-trivial destructor", bad); |
| } |
| } |
| |
| if (complained) |
| { |
| if (ent->in_try_scope) |
| inform (input_location, " enters try block"); |
| else if (ent->in_catch_scope && !saw_catch) |
| inform (input_location, " enters catch block"); |
| else if (ent->in_transaction_scope) |
| inform (input_location, " enters synchronized or atomic statement"); |
| else if (ent->in_constexpr_if) |
| inform (input_location, " enters %<constexpr%> if statement"); |
| } |
| |
| if (ent->in_omp_scope) |
| { |
| if (complained) |
| inform (input_location, " enters OpenMP structured block"); |
| } |
| else if (flag_openmp) |
| for (cp_binding_level *b = current_binding_level; b ; b = b->level_chain) |
| { |
| if (b == ent->binding_level) |
| break; |
| if (b->kind == sk_omp) |
| { |
| if (identified < 2) |
| { |
| complained = identify_goto (decl, |
| DECL_SOURCE_LOCATION (decl), |
| &input_location, DK_ERROR); |
| identified = 2; |
| } |
| if (complained) |
| inform (input_location, " exits OpenMP structured block"); |
| break; |
| } |
| } |
| } |
| |
| /* Check that a return is ok wrt OpenMP structured blocks. |
| Called by finish_return_stmt. Returns true if all is well. */ |
| |
| bool |
| check_omp_return (void) |
| { |
| for (cp_binding_level *b = current_binding_level; b ; b = b->level_chain) |
| if (b->kind == sk_omp) |
| { |
| error ("invalid exit from OpenMP structured block"); |
| return false; |
| } |
| else if (b->kind == sk_function_parms) |
| break; |
| return true; |
| } |
| |
| /* Define a label, specifying the location in the source file. |
| Return the LABEL_DECL node for the label. */ |
| |
| static tree |
| define_label_1 (location_t location, tree name) |
| { |
| /* After labels, make any new cleanups in the function go into their |
| own new (temporary) binding contour. */ |
| for (cp_binding_level *p = current_binding_level; |
| p->kind != sk_function_parms; |
| p = p->level_chain) |
| p->more_cleanups_ok = 0; |
| |
| named_label_entry *ent = lookup_label_1 (name, false); |
| tree decl = ent->label_decl; |
| |
| if (DECL_INITIAL (decl) != NULL_TREE) |
| { |
| error ("duplicate label %qD", decl); |
| return error_mark_node; |
| } |
| else |
| { |
| /* Mark label as having been defined. */ |
| DECL_INITIAL (decl) = error_mark_node; |
| /* Say where in the source. */ |
| DECL_SOURCE_LOCATION (decl) = location; |
| |
| ent->binding_level = current_binding_level; |
| ent->names_in_scope = current_binding_level->names; |
| |
| for (named_label_use_entry *use = ent->uses; use; use = use->next) |
| check_previous_goto (decl, use); |
| ent->uses = NULL; |
| } |
| |
| return decl; |
| } |
| |
| /* Wrapper for define_label_1. */ |
| |
| tree |
| define_label (location_t location, tree name) |
| { |
| bool running = timevar_cond_start (TV_NAME_LOOKUP); |
| tree ret = define_label_1 (location, name); |
| timevar_cond_stop (TV_NAME_LOOKUP, running); |
| return ret; |
| } |
| |
| |
| struct cp_switch |
| { |
| cp_binding_level *level; |
| struct cp_switch *next; |
| /* The SWITCH_STMT being built. */ |
| tree switch_stmt; |
| /* A splay-tree mapping the low element of a case range to the high |
| element, or NULL_TREE if there is no high element. Used to |
| determine whether or not a new case label duplicates an old case |
| label. We need a tree, rather than simply a hash table, because |
| of the GNU case range extension. */ |
| splay_tree cases; |
| /* Remember whether a default: case label has been seen. */ |
| bool has_default_p; |
| /* Remember whether a BREAK_STMT has been seen in this SWITCH_STMT. */ |
| bool break_stmt_seen_p; |
| /* Set if inside of {FOR,DO,WHILE}_BODY nested inside of a switch, |
| where BREAK_STMT doesn't belong to the SWITCH_STMT. */ |
| bool in_loop_body_p; |
| }; |
| |
| /* A stack of the currently active switch statements. The innermost |
| switch statement is on the top of the stack. There is no need to |
| mark the stack for garbage collection because it is only active |
| during the processing of the body of a function, and we never |
| collect at that point. */ |
| |
| static struct cp_switch *switch_stack; |
| |
| /* Called right after a switch-statement condition is parsed. |
| SWITCH_STMT is the switch statement being parsed. */ |
| |
| void |
| push_switch (tree switch_stmt) |
| { |
| struct cp_switch *p = XNEW (struct cp_switch); |
| p->level = current_binding_level; |
| p->next = switch_stack; |
| p->switch_stmt = switch_stmt; |
| p->cases = splay_tree_new (case_compare, NULL, NULL); |
| p->has_default_p = false; |
| p->break_stmt_seen_p = false; |
| p->in_loop_body_p = false; |
| switch_stack = p; |
| } |
| |
| void |
| pop_switch (void) |
| { |
| struct cp_switch *cs = switch_stack; |
| location_t switch_location; |
| |
| /* Emit warnings as needed. */ |
| switch_location = cp_expr_loc_or_loc (cs->switch_stmt, input_location); |
| const bool bool_cond_p |
| = (SWITCH_STMT_TYPE (cs->switch_stmt) |
| && TREE_CODE (SWITCH_STMT_TYPE (cs->switch_stmt)) == BOOLEAN_TYPE); |
| if (!processing_template_decl) |
| c_do_switch_warnings (cs->cases, switch_location, |
| SWITCH_STMT_TYPE (cs->switch_stmt), |
| SWITCH_STMT_COND (cs->switch_stmt), bool_cond_p); |
| |
| /* For the benefit of block_may_fallthru remember if the switch body |
| case labels cover all possible values and if there are break; stmts. */ |
| if (cs->has_default_p |
| || (!processing_template_decl |
| && c_switch_covers_all_cases_p (cs->cases, |
| SWITCH_STMT_TYPE (cs->switch_stmt)))) |
| SWITCH_STMT_ALL_CASES_P (cs->switch_stmt) = 1; |
| if (!cs->break_stmt_seen_p) |
| SWITCH_STMT_NO_BREAK_P (cs->switch_stmt) = 1; |
| gcc_assert (!cs->in_loop_body_p); |
| splay_tree_delete (cs->cases); |
| switch_stack = switch_stack->next; |
| free (cs); |
| } |
| |
| /* Note that a BREAK_STMT is about to be added. If it is inside of |
| a SWITCH_STMT and not inside of a loop body inside of it, note |
| in switch_stack we've seen a BREAK_STMT. */ |
| |
| void |
| note_break_stmt (void) |
| { |
| if (switch_stack && !switch_stack->in_loop_body_p) |
| switch_stack->break_stmt_seen_p = true; |
| } |
| |
| /* Note the start of processing of an iteration statement's body. |
| The note_break_stmt function will do nothing while processing it. |
| Return a flag that should be passed to note_iteration_stmt_body_end. */ |
| |
| bool |
| note_iteration_stmt_body_start (void) |
| { |
| if (!switch_stack) |
| return false; |
| bool ret = switch_stack->in_loop_body_p; |
| switch_stack->in_loop_body_p = true; |
| return ret; |
| } |
| |
| /* Note the end of processing of an iteration statement's body. */ |
| |
| void |
| note_iteration_stmt_body_end (bool prev) |
| { |
| if (switch_stack) |
| switch_stack->in_loop_body_p = prev; |
| } |
| |
| /* Convert a case constant VALUE in a switch to the type TYPE of the switch |
| condition. Note that if TYPE and VALUE are already integral we don't |
| really do the conversion because the language-independent |
| warning/optimization code will work better that way. */ |
| |
| static tree |
| case_conversion (tree type, tree value) |
| { |
| if (value == NULL_TREE) |
| return value; |
| |
| value = mark_rvalue_use (value); |
| |
| if (cxx_dialect >= cxx11 |
| && (SCOPED_ENUM_P (type) |
| || !INTEGRAL_OR_UNSCOPED_ENUMERATION_TYPE_P (TREE_TYPE (value)))) |
| { |
| if (INTEGRAL_OR_UNSCOPED_ENUMERATION_TYPE_P (type)) |
| type = type_promotes_to (type); |
| value = (perform_implicit_conversion_flags |
| (type, value, tf_warning_or_error, |
| LOOKUP_IMPLICIT | LOOKUP_NO_NON_INTEGRAL)); |
| } |
| return cxx_constant_value (value); |
| } |
| |
| /* Note that we've seen a definition of a case label, and complain if this |
| is a bad place for one. */ |
| |
| tree |
| finish_case_label (location_t loc, tree low_value, tree high_value) |
| { |
| tree cond, r; |
| cp_binding_level *p; |
| tree type; |
| |
| if (low_value == NULL_TREE && high_value == NULL_TREE) |
| switch_stack->has_default_p = true; |
| |
| if (processing_template_decl) |
| { |
| tree label; |
| |
| /* For templates, just add the case label; we'll do semantic |
| analysis at instantiation-time. */ |
| label = build_decl (loc, LABEL_DECL, NULL_TREE, void_type_node); |
| return add_stmt (build_case_label (low_value, high_value, label)); |
| } |
| |
| /* Find the condition on which this switch statement depends. */ |
| cond = SWITCH_STMT_COND (switch_stack->switch_stmt); |
| if (cond && TREE_CODE (cond) == TREE_LIST) |
| cond = TREE_VALUE (cond); |
| |
| if (!check_switch_goto (switch_stack->level)) |
| return error_mark_node; |
| |
| type = SWITCH_STMT_TYPE (switch_stack->switch_stmt); |
| if (type == error_mark_node) |
| return error_mark_node; |
| |
| low_value = case_conversion (type, low_value); |
| high_value = case_conversion (type, high_value); |
| |
| r = c_add_case_label (loc, switch_stack->cases, cond, low_value, high_value); |
| |
| /* After labels, make any new cleanups in the function go into their |
| own new (temporary) binding contour. */ |
| for (p = current_binding_level; |
| p->kind != sk_function_parms; |
| p = p->level_chain) |
| p->more_cleanups_ok = 0; |
| |
| return r; |
| } |
| |
| struct typename_info { |
| tree scope; |
| tree name; |
| tree template_id; |
| bool enum_p; |
| bool class_p; |
| }; |
| |
| struct typename_hasher : ggc_ptr_hash<tree_node> |
| { |
| typedef typename_info *compare_type; |
| |
| /* Hash a TYPENAME_TYPE. */ |
| |
| static hashval_t |
| hash (tree t) |
| { |
| hashval_t hash; |
| |
| hash = (htab_hash_pointer (TYPE_CONTEXT (t)) |
| ^ htab_hash_pointer (TYPE_IDENTIFIER (t))); |
| |
| return hash; |
| } |
| |
| /* Compare two TYPENAME_TYPEs. */ |
| |
| static bool |
| equal (tree t1, const typename_info *t2) |
| { |
| return (TYPE_IDENTIFIER (t1) == t2->name |
| && TYPE_CONTEXT (t1) == t2->scope |
| && TYPENAME_TYPE_FULLNAME (t1) == t2->template_id |
| && TYPENAME_IS_ENUM_P (t1) == t2->enum_p |
| && TYPENAME_IS_CLASS_P (t1) == t2->class_p); |
| } |
| }; |
| |
| /* Build a TYPENAME_TYPE. If the type is `typename T::t', CONTEXT is |
| the type of `T', NAME is the IDENTIFIER_NODE for `t'. |
| |
| Returns the new TYPENAME_TYPE. */ |
| |
| static GTY (()) hash_table<typename_hasher> *typename_htab; |
| |
| tree |
| build_typename_type (tree context, tree name, tree fullname, |
| enum tag_types tag_type) |
| { |
| tree t; |
| tree d; |
| typename_info ti; |
| tree *e; |
| hashval_t hash; |
| |
| if (typename_htab == NULL) |
| typename_htab = hash_table<typename_hasher>::create_ggc (61); |
| |
| ti.scope = FROB_CONTEXT (context); |
| ti.name = name; |
| ti.template_id = fullname; |
| ti.enum_p = tag_type == enum_type; |
| ti.class_p = (tag_type == class_type |
| || tag_type == record_type |
| || tag_type == union_type); |
| hash = (htab_hash_pointer (ti.scope) |
| ^ htab_hash_pointer (ti.name)); |
| |
| /* See if we already have this type. */ |
| e = typename_htab->find_slot_with_hash (&ti, hash, INSERT); |
| if (*e) |
| t = *e; |
| else |
| { |
| /* Build the TYPENAME_TYPE. */ |
| t = cxx_make_type (TYPENAME_TYPE); |
| TYPE_CONTEXT (t) = ti.scope; |
| TYPENAME_TYPE_FULLNAME (t) = ti.template_id; |
| TYPENAME_IS_ENUM_P (t) = ti.enum_p; |
| TYPENAME_IS_CLASS_P (t) = ti.class_p; |
| |
| /* Build the corresponding TYPE_DECL. */ |
| d = build_decl (input_location, TYPE_DECL, name, t); |
| TYPE_NAME (TREE_TYPE (d)) = d; |
| TYPE_STUB_DECL (TREE_TYPE (d)) = d; |
| DECL_CONTEXT (d) = FROB_CONTEXT (context); |
| DECL_ARTIFICIAL (d) = 1; |
| |
| /* Store it in the hash table. */ |
| *e = t; |
| |
| /* TYPENAME_TYPEs must always be compared structurally, because |
| they may or may not resolve down to another type depending on |
| the currently open classes. */ |
| SET_TYPE_STRUCTURAL_EQUALITY (t); |
| } |
| |
| return t; |
| } |
| |
| /* Resolve `typename CONTEXT::NAME'. TAG_TYPE indicates the tag |
| provided to name the type. Returns an appropriate type, unless an |
| error occurs, in which case error_mark_node is returned. If we |
| locate a non-artificial TYPE_DECL and TF_KEEP_TYPE_DECL is set, we |
| return that, rather than the _TYPE it corresponds to, in other |
| cases we look through the type decl. If TF_ERROR is set, complain |
| about errors, otherwise be quiet. */ |
| |
| tree |
| make_typename_type (tree context, tree name, enum tag_types tag_type, |
| tsubst_flags_t complain) |
| { |
| tree fullname; |
| tree t; |
| bool want_template; |
| |
| if (name == error_mark_node |
| || context == NULL_TREE |
| || context == error_mark_node) |
| return error_mark_node; |
| |
| if (TYPE_P (name)) |
| { |
| if (!(TYPE_LANG_SPECIFIC (name) |
| && (CLASSTYPE_IS_TEMPLATE (name) |
| || CLASSTYPE_USE_TEMPLATE (name)))) |
| name = TYPE_IDENTIFIER (name); |
| else |
| /* Create a TEMPLATE_ID_EXPR for the type. */ |
| name = build_nt (TEMPLATE_ID_EXPR, |
| CLASSTYPE_TI_TEMPLATE (name), |
| CLASSTYPE_TI_ARGS (name)); |
| } |
| else if (TREE_CODE (name) == TYPE_DECL) |
| name = DECL_NAME (name); |
| |
| fullname = name; |
| |
| if (TREE_CODE (name) == TEMPLATE_ID_EXPR) |
| { |
| name = TREE_OPERAND (name, 0); |
| if (DECL_TYPE_TEMPLATE_P (name)) |
| name = TREE_OPERAND (fullname, 0) = DECL_NAME (name); |
| if (TREE_CODE (name) != IDENTIFIER_NODE) |
| { |
| if (complain & tf_error) |
| error ("%qD is not a type", name); |
| return error_mark_node; |
| } |
| } |
| if (TREE_CODE (name) == TEMPLATE_DECL) |
| { |
| if (complain & tf_error) |
| error ("%qD used without template arguments", name); |
| return error_mark_node; |
| } |
| gcc_assert (identifier_p (name)); |
| gcc_assert (TYPE_P (context)); |
| |
| if (TREE_CODE (context) == TYPE_PACK_EXPANSION) |
| /* This can happen for C++17 variadic using (c++/88986). */; |
| else if (!MAYBE_CLASS_TYPE_P (context)) |
| { |
| if (complain & tf_error) |
| error ("%q#T is not a class", context); |
| return error_mark_node; |
| } |
| |
| /* When the CONTEXT is a dependent type, NAME could refer to a |
| dependent base class of CONTEXT. But look inside it anyway |
| if CONTEXT is a currently open scope, in case it refers to a |
| member of the current instantiation or a non-dependent base; |
| lookup will stop when we hit a dependent base. */ |
| if (!dependent_scope_p (context)) |
| /* We should only set WANT_TYPE when we're a nested typename type. |
| Then we can give better diagnostics if we find a non-type. */ |
| t = lookup_field (context, name, 2, /*want_type=*/true); |
| else |
| t = NULL_TREE; |
| |
| if ((!t || TREE_CODE (t) == TREE_LIST) && dependent_type_p (context)) |
| return build_typename_type (context, name, fullname, tag_type); |
| |
| want_template = TREE_CODE (fullname) == TEMPLATE_ID_EXPR; |
| |
| if (!t) |
| { |
| if (complain & tf_error) |
| { |
| if (!COMPLETE_TYPE_P (context)) |
| cxx_incomplete_type_error (NULL_TREE, context); |
| else |
| error (want_template ? G_("no class template named %q#T in %q#T") |
| : G_("no type named %q#T in %q#T"), name, context); |
| } |
| return error_mark_node; |
| } |
| |
| /* Pull out the template from an injected-class-name (or multiple). */ |
| if (want_template) |
| t = maybe_get_template_decl_from_type_decl (t); |
| |
| if (TREE_CODE (t) == TREE_LIST) |
| { |
| if (complain & tf_error) |
| { |
| error ("lookup of %qT in %qT is ambiguous", name, context); |
| print_candidates (t); |
| } |
| return error_mark_node; |
| } |
| |
| if (want_template && !DECL_TYPE_TEMPLATE_P (t)) |
| { |
| if (complain & tf_error) |
| error ("%<typename %T::%D%> names %q#T, which is not a class template", |
| context, name, t); |
| return error_mark_node; |
| } |
| if (!want_template && TREE_CODE (t) != TYPE_DECL) |
| { |
| if (complain & tf_error) |
| error ("%<typename %T::%D%> names %q#T, which is not a type", |
| context, name, t); |
| return error_mark_node; |
| } |
| |
| if (!perform_or_defer_access_check (TYPE_BINFO (context), t, t, complain)) |
| return error_mark_node; |
| |
| /* If we are currently parsing a template and if T is a typedef accessed |
| through CONTEXT then we need to remember and check access of T at |
| template instantiation time. */ |
| add_typedef_to_current_template_for_access_check (t, context, input_location); |
| |
| if (want_template) |
| return lookup_template_class (t, TREE_OPERAND (fullname, 1), |
| NULL_TREE, context, |
| /*entering_scope=*/0, |
| complain | tf_user); |
| |
| if (DECL_ARTIFICIAL (t) || !(complain & tf_keep_type_decl)) |
| t = TREE_TYPE (t); |
| |
| maybe_record_typedef_use (t); |
| |
| return t; |
| } |
| |
| /* Resolve `CONTEXT::template NAME'. Returns a TEMPLATE_DECL if the name |
| can be resolved or an UNBOUND_CLASS_TEMPLATE, unless an error occurs, |
| in which case error_mark_node is returned. |
| |
| If PARM_LIST is non-NULL, also make sure that the template parameter |
| list of TEMPLATE_DECL matches. |
| |
| If COMPLAIN zero, don't complain about any errors that occur. */ |
| |
| tree |
| make_unbound_class_template (tree context, tree name, tree parm_list, |
| tsubst_flags_t complain) |
| { |
| tree t; |
| tree d; |
| |
| if (TYPE_P (name)) |
| name = TYPE_IDENTIFIER (name); |
| else if (DECL_P (name)) |
| name = DECL_NAME (name); |
| gcc_assert (identifier_p (name)); |
| |
| if (!dependent_type_p (context) |
| || currently_open_class (context)) |
| { |
| tree tmpl = NULL_TREE; |
| |
| if (MAYBE_CLASS_TYPE_P (context)) |
| tmpl = lookup_field (context, name, 0, false); |
| |
| if (tmpl && TREE_CODE (tmpl) == TYPE_DECL) |
| tmpl = maybe_get_template_decl_from_type_decl (tmpl); |
| |
| if (!tmpl || !DECL_TYPE_TEMPLATE_P (tmpl)) |
| { |
| if (complain & tf_error) |
| error ("no class template named %q#T in %q#T", name, context); |
| return error_mark_node; |
| } |
| |
| if (parm_list |
| && !comp_template_parms (DECL_TEMPLATE_PARMS (tmpl), parm_list)) |
| { |
| if (complain & tf_error) |
| { |
| error ("template parameters do not match template %qD", tmpl); |
| inform (DECL_SOURCE_LOCATION (tmpl), |
| "%qD declared here", tmpl); |
| } |
| return error_mark_node; |
| } |
| |
| if (!perform_or_defer_access_check (TYPE_BINFO (context), tmpl, tmpl, |
| complain)) |
| return error_mark_node; |
| |
| return tmpl; |
| } |
| |
| /* Build the UNBOUND_CLASS_TEMPLATE. */ |
| t = cxx_make_type (UNBOUND_CLASS_TEMPLATE); |
| TYPE_CONTEXT (t) = FROB_CONTEXT (context); |
| TREE_TYPE (t) = NULL_TREE; |
| SET_TYPE_STRUCTURAL_EQUALITY (t); |
| |
| /* Build the corresponding TEMPLATE_DECL. */ |
| d = build_decl (input_location, TEMPLATE_DECL, name, t); |
| TYPE_NAME (TREE_TYPE (d)) = d; |
| TYPE_STUB_DECL (TREE_TYPE (d)) = d; |
| DECL_CONTEXT (d) = FROB_CONTEXT (context); |
| DECL_ARTIFICIAL (d) = 1; |
| DECL_TEMPLATE_PARMS (d) = parm_list; |
| |
| return t; |
| } |
| |
| |
| |
| /* Push the declarations of builtin types into the global namespace. |
| RID_INDEX is the index of the builtin type in the array |
| RID_POINTERS. NAME is the name used when looking up the builtin |
| type. TYPE is the _TYPE node for the builtin type. |
| |
| The calls to set_global_binding below should be |
| eliminated. Built-in types should not be looked up name; their |
| names are keywords that the parser can recognize. However, there |
| is code in c-common.c that uses identifier_global_value to look up |
| built-in types by name. */ |
| |
| void |
| record_builtin_type (enum rid rid_index, |
| const char* name, |
| tree type) |
| { |
| tree decl = NULL_TREE; |
| |
| if (name) |
| { |
| tree tname = get_identifier (name); |
| tree tdecl = build_decl (BUILTINS_LOCATION, TYPE_DECL, tname, type); |
| DECL_ARTIFICIAL (tdecl) = 1; |
| set_global_binding (tdecl); |
| decl = tdecl; |
| } |
| |
| if ((int) rid_index < (int) RID_MAX) |
| if (tree rname = ridpointers[(int) rid_index]) |
| if (!decl || DECL_NAME (decl) != rname) |
| { |
| tree rdecl = build_decl (BUILTINS_LOCATION, TYPE_DECL, rname, type); |
| DECL_ARTIFICIAL (rdecl) = 1; |
| set_global_binding (rdecl); |
| if (!decl) |
| decl = rdecl; |
| } |
| |
| if (decl) |
| { |
| if (!TYPE_NAME (type)) |
| TYPE_NAME (type) = decl; |
| debug_hooks->type_decl (decl, 0); |
| } |
| } |
| |
| /* Push a type into the namespace so that the back ends ignore it. */ |
| |
| static void |
| record_unknown_type (tree type, const char* name) |
| { |
| tree decl = pushdecl (build_decl (UNKNOWN_LOCATION, |
| TYPE_DECL, get_identifier (name), type)); |
| /* Make sure the "unknown type" typedecl gets ignored for debug info. */ |
| DECL_IGNORED_P (decl) = 1; |
| TYPE_DECL_SUPPRESS_DEBUG (decl) = 1; |
| TYPE_SIZE (type) = TYPE_SIZE (void_type_node); |
| SET_TYPE_ALIGN (type, 1); |
| TYPE_USER_ALIGN (type) = 0; |
| SET_TYPE_MODE (type, TYPE_MODE (void_type_node)); |
| } |
| |
| /* Create all the predefined identifiers. */ |
| |
| static void |
| initialize_predefined_identifiers (void) |
| { |
| struct predefined_identifier |
| { |
| const char *name; /* Name. */ |
| tree *node; /* Node to store it in. */ |
| cp_identifier_kind kind; /* Kind of identifier. */ |
| }; |
| |
| /* A table of identifiers to create at startup. */ |
| static const predefined_identifier predefined_identifiers[] = { |
| {"C++", &lang_name_cplusplus, cik_normal}, |
| {"C", &lang_name_c, cik_normal}, |
| /* Some of these names have a trailing space so that it is |
| impossible for them to conflict with names written by users. */ |
| {"__ct ", &ctor_identifier, cik_ctor}, |
| {"__ct_base ", &base_ctor_identifier, cik_ctor}, |
| {"__ct_comp ", &complete_ctor_identifier, cik_ctor}, |
| {"__dt ", &dtor_identifier, cik_dtor}, |
| {"__dt_base ", &base_dtor_identifier, cik_dtor}, |
| {"__dt_comp ", &complete_dtor_identifier, cik_dtor}, |
| {"__dt_del ", &deleting_dtor_identifier, cik_dtor}, |
| {"__conv_op ", &conv_op_identifier, cik_conv_op}, |
| {"__in_chrg", &in_charge_identifier, cik_normal}, |
| {"this", &this_identifier, cik_normal}, |
| {"__delta", &delta_identifier, cik_normal}, |
| {"__pfn", &pfn_identifier, cik_normal}, |
| {"_vptr", &vptr_identifier, cik_normal}, |
| {"__vtt_parm", &vtt_parm_identifier, cik_normal}, |
| {"::", &global_identifier, cik_normal}, |
| {"std", &std_identifier, cik_normal}, |
| /* The demangler expects anonymous namespaces to be called |
| something starting with '_GLOBAL__N_'. It no longer needs |
| to be unique to the TU. */ |
| {"_GLOBAL__N_1", &anon_identifier, cik_normal}, |
| {"auto", &auto_identifier, cik_normal}, |
| {"decltype(auto)", &decltype_auto_identifier, cik_normal}, |
| {"initializer_list", &init_list_identifier, cik_normal}, |
| {"__for_range ", &for_range__identifier, cik_normal}, |
| {"__for_begin ", &for_begin__identifier, cik_normal}, |
| {"__for_end ", &for_end__identifier, cik_normal}, |
| {"__for_range", &for_range_identifier, cik_normal}, |
| {"__for_begin", &for_begin_identifier, cik_normal}, |
| {"__for_end", &for_end_identifier, cik_normal}, |
| {"abi_tag", &abi_tag_identifier, cik_normal}, |
| {"aligned", &aligned_identifier, cik_normal}, |
| {"begin", &begin_identifier, cik_normal}, |
| {"end", &end_identifier, cik_normal}, |
| {"get", &get__identifier, cik_normal}, |
| {"gnu", &gnu_identifier, cik_normal}, |
| {"tuple_element", &tuple_element_identifier, cik_normal}, |
| {"tuple_size", &tuple_size_identifier, cik_normal}, |
| {"type", &type_identifier, cik_normal}, |
| {"value", &value_identifier, cik_normal}, |
| {"_FUN", &fun_identifier, cik_normal}, |
| {"__closure", &closure_identifier, cik_normal}, |
| {NULL, NULL, cik_normal} |
| }; |
| |
| for (const predefined_identifier *pid = predefined_identifiers; |
| pid->name; ++pid) |
| { |
| *pid->node = get_identifier (pid->name); |
| /* Some of these identifiers already have a special kind. */ |
| if (pid->kind != cik_normal) |
| set_identifier_kind (*pid->node, pid->kind); |
| } |
| } |
| |
| /* Create the predefined scalar types of C, |
| and some nodes representing standard constants (0, 1, (void *)0). |
| Initialize the global binding level. |
| Make definitions for built-in primitive functions. */ |
| |
| void |
| cxx_init_decl_processing (void) |
| { |
| tree void_ftype; |
| tree void_ftype_ptr; |
| |
| /* Create all the identifiers we need. */ |
| initialize_predefined_identifiers (); |
| |
| /* Create the global variables. */ |
| push_to_top_level (); |
| |
| current_function_decl = NULL_TREE; |
| current_binding_level = NULL; |
| /* Enter the global namespace. */ |
| gcc_assert (global_namespace == NULL_TREE); |
| global_namespace = build_lang_decl (NAMESPACE_DECL, global_identifier, |
| void_type_node); |
| TREE_PUBLIC (global_namespace) = 1; |
| DECL_CONTEXT (global_namespace) |
| = build_translation_unit_decl (get_identifier (main_input_filename)); |
| /* Remember whether we want the empty class passing ABI change warning |
| in this TU. */ |
| TRANSLATION_UNIT_WARN_EMPTY_P (DECL_CONTEXT (global_namespace)) |
| = warn_abi && abi_version_crosses (12); |
| debug_hooks->register_main_translation_unit |
| (DECL_CONTEXT (global_namespace)); |
| begin_scope (sk_namespace, global_namespace); |
| current_namespace = global_namespace; |
| |
| if (flag_visibility_ms_compat) |
| default_visibility = VISIBILITY_HIDDEN; |
| |
| /* Initially, C. */ |
| current_lang_name = lang_name_c; |
| |
| /* Create the `std' namespace. */ |
| push_namespace (std_identifier); |
| std_node = current_namespace; |
| pop_namespace (); |
| |
| flag_noexcept_type = (cxx_dialect >= cxx17); |
| |
| c_common_nodes_and_builtins (); |
| |
| tree bool_ftype = build_function_type_list (boolean_type_node, NULL_TREE); |
| tree decl |
| = add_builtin_function ("__builtin_is_constant_evaluated", |
| bool_ftype, CP_BUILT_IN_IS_CONSTANT_EVALUATED, |
| BUILT_IN_FRONTEND, NULL, NULL_TREE); |
| set_call_expr_flags (decl, ECF_CONST | ECF_NOTHROW | ECF_LEAF); |
| |
| integer_two_node = build_int_cst (NULL_TREE, 2); |
| |
| /* Guess at the initial static decls size. */ |
| vec_alloc (static_decls, 500); |
| |
| /* ... and keyed classes. */ |
| vec_alloc (keyed_classes, 100); |
| |
| record_builtin_type (RID_BOOL, "bool", boolean_type_node); |
| truthvalue_type_node = boolean_type_node; |
| truthvalue_false_node = boolean_false_node; |
| truthvalue_true_node = boolean_true_node; |
| |
| empty_except_spec = build_tree_list (NULL_TREE, NULL_TREE); |
| noexcept_true_spec = build_tree_list (boolean_true_node, NULL_TREE); |
| noexcept_false_spec = build_tree_list (boolean_false_node, NULL_TREE); |
| noexcept_deferred_spec = build_tree_list (make_node (DEFERRED_NOEXCEPT), |
| NULL_TREE); |
| |
| #if 0 |
| record_builtin_type (RID_MAX, NULL, string_type_node); |
| #endif |
| |
| delta_type_node = ptrdiff_type_node; |
| vtable_index_type = ptrdiff_type_node; |
| |
| vtt_parm_type = build_pointer_type (const_ptr_type_node); |
| void_ftype = build_function_type_list (void_type_node, NULL_TREE); |
| void_ftype_ptr = build_function_type_list (void_type_node, |
| ptr_type_node, NULL_TREE); |
| void_ftype_ptr |
| = build_exception_variant (void_ftype_ptr, empty_except_spec); |
| |
| /* Create the conversion operator marker. This operator's DECL_NAME |
| is in the identifier table, so we can use identifier equality to |
| find it. */ |
| conv_op_marker = build_lang_decl (FUNCTION_DECL, conv_op_identifier, |
| void_ftype); |
| |
| /* C++ extensions */ |
| |
| unknown_type_node = make_node (LANG_TYPE); |
| record_unknown_type (unknown_type_node, "unknown type"); |
| |
| /* Indirecting an UNKNOWN_TYPE node yields an UNKNOWN_TYPE node. */ |
| TREE_TYPE (unknown_type_node) = unknown_type_node; |
| |
| /* Looking up TYPE_POINTER_TO and TYPE_REFERENCE_TO yield the same |
| result. */ |
| TYPE_POINTER_TO (unknown_type_node) = unknown_type_node; |
| TYPE_REFERENCE_TO (unknown_type_node) = unknown_type_node; |
| |
| init_list_type_node = make_node (LANG_TYPE); |
| record_unknown_type (init_list_type_node, "init list"); |
| |
| { |
| /* Make sure we get a unique function type, so we can give |
| its pointer type a name. (This wins for gdb.) */ |
| tree vfunc_type = make_node (FUNCTION_TYPE); |
| TREE_TYPE (vfunc_type) = integer_type_node; |
| TYPE_ARG_TYPES (vfunc_type) = NULL_TREE; |
| layout_type (vfunc_type); |
| |
| vtable_entry_type = build_pointer_type (vfunc_type); |
| } |
| record_builtin_type (RID_MAX, "__vtbl_ptr_type", vtable_entry_type); |
| |
| vtbl_type_node |
| = build_cplus_array_type (vtable_entry_type, NULL_TREE); |
| layout_type (vtbl_type_node); |
| vtbl_type_node = cp_build_qualified_type (vtbl_type_node, TYPE_QUAL_CONST); |
| record_builtin_type (RID_MAX, NULL, vtbl_type_node); |
| vtbl_ptr_type_node = build_pointer_type (vtable_entry_type); |
| layout_type (vtbl_ptr_type_node); |
| record_builtin_type (RID_MAX, NULL, vtbl_ptr_type_node); |
| |
| push_namespace (get_identifier ("__cxxabiv1")); |
| abi_node = current_namespace; |
| pop_namespace (); |
| |
| global_type_node = make_node (LANG_TYPE); |
| record_unknown_type (global_type_node, "global type"); |
| |
| any_targ_node = make_node (LANG_TYPE); |
| record_unknown_type (any_targ_node, "any type"); |
| |
| /* Now, C++. */ |
| current_lang_name = lang_name_cplusplus; |
| |
| if (aligned_new_threshold > 1 |
| && !pow2p_hwi (aligned_new_threshold)) |
| { |
| error ("%<-faligned-new=%d%> is not a power of two", |
| aligned_new_threshold); |
| aligned_new_threshold = 1; |
| } |
| if (aligned_new_threshold == -1) |
| aligned_new_threshold = (cxx_dialect >= cxx17) ? 1 : 0; |
| if (aligned_new_threshold == 1) |
| aligned_new_threshold = malloc_alignment () / BITS_PER_UNIT; |
| |
| { |
| tree newattrs, extvisattr; |
| tree newtype, deltype; |
| tree ptr_ftype_sizetype; |
| tree new_eh_spec; |
| |
| ptr_ftype_sizetype |
| = build_function_type_list (ptr_type_node, size_type_node, NULL_TREE); |
| if (cxx_dialect == cxx98) |
| { |
| tree bad_alloc_id; |
| tree bad_alloc_type_node; |
| tree bad_alloc_decl; |
| |
| push_namespace (std_identifier); |
| bad_alloc_id = get_identifier ("bad_alloc"); |
| bad_alloc_type_node = make_class_type (RECORD_TYPE); |
| TYPE_CONTEXT (bad_alloc_type_node) = current_namespace; |
| bad_alloc_decl |
| = create_implicit_typedef (bad_alloc_id, bad_alloc_type_node); |
| DECL_CONTEXT (bad_alloc_decl) = current_namespace; |
| pop_namespace (); |
| |
| new_eh_spec |
| = add_exception_specifier (NULL_TREE, bad_alloc_type_node, -1); |
| } |
| else |
| new_eh_spec = noexcept_false_spec; |
| |
| /* Ensure attribs.c is initialized. */ |
| init_attributes (); |
| |
| /* Ensure constraint.cc is initialized. */ |
| init_constraint_processing (); |
| |
| extvisattr = build_tree_list (get_identifier ("externally_visible"), |
| NULL_TREE); |
| newattrs = tree_cons (get_identifier ("alloc_size"), |
| build_tree_list (NULL_TREE, integer_one_node), |
| extvisattr); |
| newtype = cp_build_type_attribute_variant (ptr_ftype_sizetype, newattrs); |
| newtype = build_exception_variant (newtype, new_eh_spec); |
| deltype = cp_build_type_attribute_variant (void_ftype_ptr, extvisattr); |
| deltype = build_exception_variant (deltype, empty_except_spec); |
| tree opnew = push_cp_library_fn (NEW_EXPR, newtype, 0); |
| DECL_IS_MALLOC (opnew) = 1; |
| DECL_IS_OPERATOR_NEW (opnew) = 1; |
| opnew = push_cp_library_fn (VEC_NEW_EXPR, newtype, 0); |
| DECL_IS_MALLOC (opnew) = 1; |
| DECL_IS_OPERATOR_NEW (opnew) = 1; |
| push_cp_library_fn (DELETE_EXPR, deltype, ECF_NOTHROW); |
| push_cp_library_fn (VEC_DELETE_EXPR, deltype, ECF_NOTHROW); |
| if (flag_sized_deallocation) |
| { |
| /* Also push the sized deallocation variants: |
| void operator delete(void*, std::size_t) throw(); |
| void operator delete[](void*, std::size_t) throw(); */ |
| tree void_ftype_ptr_size |
| = build_function_type_list (void_type_node, ptr_type_node, |
| size_type_node, NULL_TREE); |
| deltype = cp_build_type_attribute_variant (void_ftype_ptr_size, |
| extvisattr); |
| deltype = build_exception_variant (deltype, empty_except_spec); |
| push_cp_library_fn (DELETE_EXPR, deltype, ECF_NOTHROW); |
| push_cp_library_fn (VEC_DELETE_EXPR, deltype, ECF_NOTHROW); |
| } |
| |
| if (aligned_new_threshold) |
| { |
| push_namespace (std_identifier); |
| tree align_id = get_identifier ("align_val_t"); |
| align_type_node = start_enum (align_id, NULL_TREE, size_type_node, |
| NULL_TREE, /*scoped*/true, NULL); |
| pop_namespace (); |
| |
| /* operator new (size_t, align_val_t); */ |
| newtype = build_function_type_list (ptr_type_node, size_type_node, |
| align_type_node, NULL_TREE); |
| newtype = cp_build_type_attribute_variant (newtype, newattrs); |
| newtype = build_exception_variant (newtype, new_eh_spec); |
| opnew = push_cp_library_fn (NEW_EXPR, newtype, 0); |
| DECL_IS_MALLOC (opnew) = 1; |
| DECL_IS_OPERATOR_NEW (opnew) = 1; |
| opnew = push_cp_library_fn (VEC_NEW_EXPR, newtype, 0); |
| DECL_IS_MALLOC (opnew) = 1; |
| DECL_IS_OPERATOR_NEW (opnew) = 1; |
| |
| /* operator delete (void *, align_val_t); */ |
| deltype = build_function_type_list (void_type_node, ptr_type_node, |
| align_type_node, NULL_TREE); |
| deltype = cp_build_type_attribute_variant (deltype, extvisattr); |
| deltype = build_exception_variant (deltype, empty_except_spec); |
| push_cp_library_fn (DELETE_EXPR, deltype, ECF_NOTHROW); |
| push_cp_library_fn (VEC_DELETE_EXPR, deltype, ECF_NOTHROW); |
| |
| if (flag_sized_deallocation) |
| { |
| /* operator delete (void *, size_t, align_val_t); */ |
| deltype = build_function_type_list (void_type_node, ptr_type_node, |
| size_type_node, align_type_node, |
| NULL_TREE); |
| deltype = cp_build_type_attribute_variant (deltype, extvisattr); |
| deltype = build_exception_variant (deltype, empty_except_spec); |
| push_cp_library_fn (DELETE_EXPR, deltype, ECF_NOTHROW); |
| push_cp_library_fn (VEC_DELETE_EXPR, deltype, ECF_NOTHROW); |
| } |
| } |
| |
| nullptr_type_node = make_node (NULLPTR_TYPE); |
| TYPE_SIZE (nullptr_type_node) = bitsize_int (GET_MODE_BITSIZE (ptr_mode)); |
| TYPE_SIZE_UNIT (nullptr_type_node) = size_int (GET_MODE_SIZE (ptr_mode)); |
| TYPE_UNSIGNED (nullptr_type_node) = 1; |
| TYPE_PRECISION (nullptr_type_node) = GET_MODE_BITSIZE (ptr_mode); |
| if (abi_version_at_least (9)) |
| SET_TYPE_ALIGN (nullptr_type_node, GET_MODE_ALIGNMENT (ptr_mode)); |
| SET_TYPE_MODE (nullptr_type_node, ptr_mode); |
| record_builtin_type (RID_MAX, "decltype(nullptr)", nullptr_type_node); |
| nullptr_node = build_int_cst (nullptr_type_node, 0); |
| } |
| |
| abort_fndecl |
| = build_library_fn_ptr ("__cxa_pure_virtual", void_ftype, |
| ECF_NORETURN | ECF_NOTHROW | ECF_COLD); |
| |
| /* Perform other language dependent initializations. */ |
| init_class_processing (); |
| init_rtti_processing (); |
| init_template_processing (); |
| |
| if (flag_exceptions) |
| init_exception_processing (); |
| |
| if (! supports_one_only ()) |
| flag_weak = 0; |
| |
| make_fname_decl = cp_make_fname_decl; |
| start_fname_decls (); |
| |
| /* Show we use EH for cleanups. */ |
| if (flag_exceptions) |
| using_eh_for_cleanups (); |
| } |
| |
| /* Generate an initializer for a function naming variable from |
| NAME. NAME may be NULL, to indicate a dependent name. TYPE_P is |
| filled in with the type of the init. */ |
| |
| tree |
| cp_fname_init (const char* name, tree *type_p) |
| { |
| tree domain = NULL_TREE; |
| tree type; |
| tree init = NULL_TREE; |
| size_t length = 0; |
| |
| if (name) |
| { |
| length = strlen (name); |
| domain = build_index_type (size_int (length)); |
| init = build_string (length + 1, name); |
| } |
| |
| type = cp_build_qualified_type (char_type_node, TYPE_QUAL_CONST); |
| type = build_cplus_array_type (type, domain); |
| |
| *type_p = type; |
| |
| if (init) |
| TREE_TYPE (init) = type; |
| else |
| init = error_mark_node; |
| |
| return init; |
| } |
| |
| /* Create the VAR_DECL for __FUNCTION__ etc. ID is the name to give |
| the decl, LOC is the location to give the decl, NAME is the |
| initialization string and TYPE_DEP indicates whether NAME depended |
| on the type of the function. We make use of that to detect |
| __PRETTY_FUNCTION__ inside a template fn. This is being done lazily |
| at the point of first use, so we mustn't push the decl now. */ |
| |
| static tree |
| cp_make_fname_decl (location_t loc, tree id, int type_dep) |
| { |
| const char * name = NULL; |
| bool release_name = false; |
| if (!(type_dep && in_template_function ())) |
| { |
| if (current_function_decl == NULL_TREE) |
| name = "top level"; |
| else if (type_dep == 1) /* __PRETTY_FUNCTION__ */ |
| name = cxx_printable_name (current_function_decl, 2); |
| else if (type_dep == 0) /* __FUNCTION__ */ |
| { |
| name = fname_as_string (type_dep); |
| release_name = true; |
| } |
| else |
| gcc_unreachable (); |
| } |
| tree type; |
| tree init = cp_fname_init (name, &type); |
| tree decl = build_decl (loc, VAR_DECL, id, type); |
| |
| if (release_name) |
| free (CONST_CAST (char *, name)); |
| |
| /* As we're using pushdecl_with_scope, we must set the context. */ |
| DECL_CONTEXT (decl) = current_function_decl; |
| |
| TREE_READONLY (decl) = 1; |
| DECL_ARTIFICIAL (decl) = 1; |
| DECL_DECLARED_CONSTEXPR_P (decl) = 1; |
| TREE_STATIC (decl) = 1; |
| |
| TREE_USED (decl) = 1; |
| |
| if (init) |
| { |
| SET_DECL_VALUE_EXPR (decl, init); |
| DECL_HAS_VALUE_EXPR_P (decl) = 1; |
| /* For decl_constant_var_p. */ |
| DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = 1; |
| } |
| |
| if (current_function_decl) |
| { |
| DECL_CONTEXT (decl) = current_function_decl; |
| decl = pushdecl_outermost_localscope (decl); |
| if (decl != error_mark_node) |
| add_decl_expr (decl); |
| } |
| else |
| { |
| DECL_THIS_STATIC (decl) = true; |
| pushdecl_top_level_and_finish (decl, NULL_TREE); |
| } |
| |
| return decl; |
| } |
| |
| static tree |
| builtin_function_1 (tree decl, tree context, bool is_global) |
| { |
| tree id = DECL_NAME (decl); |
| const char *name = IDENTIFIER_POINTER (id); |
| |
| retrofit_lang_decl (decl); |
| |
| DECL_ARTIFICIAL (decl) = 1; |
| SET_DECL_LANGUAGE (decl, lang_c); |
| /* Runtime library routines are, by definition, available in an |
| external shared object. */ |
| DECL_VISIBILITY (decl) = VISIBILITY_DEFAULT; |
| DECL_VISIBILITY_SPECIFIED (decl) = 1; |
| |
| DECL_CONTEXT (decl) = context; |
| |
| /* A function in the user's namespace should have an explicit |
| declaration before it is used. Mark the built-in function as |
| anticipated but not actually declared. */ |
| if (name[0] != '_' || name[1] != '_') |
| DECL_ANTICIPATED (decl) = 1; |
| else if (strncmp (name + 2, "builtin_", strlen ("builtin_")) != 0) |
| { |
| size_t len = strlen (name); |
| |
| /* Treat __*_chk fortification functions as anticipated as well, |
| unless they are __builtin_*. */ |
| if (len > strlen ("___chk") |
| && memcmp (name + len - strlen ("_chk"), |
| "_chk", strlen ("_chk") + 1) == 0) |
| DECL_ANTICIPATED (decl) = 1; |
| } |
| |
| if (is_global) |
| return pushdecl_top_level (decl); |
| else |
| return pushdecl (decl); |
| } |
| |
| tree |
| cxx_builtin_function (tree decl) |
| { |
| tree id = DECL_NAME (decl); |
| const char *name = IDENTIFIER_POINTER (id); |
| /* All builtins that don't begin with an '_' should additionally |
| go in the 'std' namespace. */ |
| if (name[0] != '_') |
| { |
| tree decl2 = copy_node(decl); |
| push_namespace (std_identifier); |
| builtin_function_1 (decl2, std_node, false); |
| pop_namespace (); |
| } |
| |
| return builtin_function_1 (decl, NULL_TREE, false); |
| } |
| |
| /* Like cxx_builtin_function, but guarantee the function is added to the global |
| scope. This is to allow function specific options to add new machine |
| dependent builtins when the target ISA changes via attribute((target(...))) |
| which saves space on program startup if the program does not use non-generic |
| ISAs. */ |
| |
| tree |
| cxx_builtin_function_ext_scope (tree decl) |
| { |
| |
| tree id = DECL_NAME (decl); |
| const char *name = IDENTIFIER_POINTER (id); |
| /* All builtins that don't begin with an '_' should additionally |
| go in the 'std' namespace. */ |
| if (name[0] != '_') |
| { |
| tree decl2 = copy_node(decl); |
| push_namespace (std_identifier); |
| builtin_function_1 (decl2, std_node, true); |
| pop_namespace (); |
| } |
| |
| return builtin_function_1 (decl, NULL_TREE, true); |
| } |
| |
| /* Generate a FUNCTION_DECL with the typical flags for a runtime library |
| function. Not called directly. */ |
| |
| static tree |
| build_library_fn (tree name, enum tree_code operator_code, tree type, |
| int ecf_flags) |
| { |
| tree fn = build_lang_decl (FUNCTION_DECL, name, type); |
| DECL_EXTERNAL (fn) = 1; |
| TREE_PUBLIC (fn) = 1; |
| DECL_ARTIFICIAL (fn) = 1; |
| DECL_OVERLOADED_OPERATOR_CODE_RAW (fn) |
| = OVL_OP_INFO (false, operator_code)->ovl_op_code; |
| SET_DECL_LANGUAGE (fn, lang_c); |
| /* Runtime library routines are, by definition, available in an |
| external shared object. */ |
| DECL_VISIBILITY (fn) = VISIBILITY_DEFAULT; |
| DECL_VISIBILITY_SPECIFIED (fn) = 1; |
| set_call_expr_flags (fn, ecf_flags); |
| return fn; |
| } |
| |
| /* Returns the _DECL for a library function with C++ linkage. */ |
| |
| static tree |
| build_cp_library_fn (tree name, enum tree_code operator_code, tree type, |
| int ecf_flags) |
| { |
| tree fn = build_library_fn (name, operator_code, type, ecf_flags); |
| DECL_CONTEXT (fn) = FROB_CONTEXT (current_namespace); |
| SET_DECL_LANGUAGE (fn, lang_cplusplus); |
| return fn; |
| } |
| |
| /* Like build_library_fn, but takes a C string instead of an |
| IDENTIFIER_NODE. */ |
| |
| tree |
| build_library_fn_ptr (const char* name, tree type, int ecf_flags) |
| { |
| return build_library_fn (get_identifier (name), ERROR_MARK, type, ecf_flags); |
| } |
| |
| /* Like build_cp_library_fn, but takes a C string instead of an |
| IDENTIFIER_NODE. */ |
| |
| tree |
| build_cp_library_fn_ptr (const char* name, tree type, int ecf_flags) |
| { |
| return build_cp_library_fn (get_identifier (name), ERROR_MARK, type, |
| ecf_flags); |
| } |
| |
| /* Like build_library_fn, but also pushes the function so that we will |
| be able to find it via get_global_binding. Also, the function |
| may throw exceptions listed in RAISES. */ |
| |
| tree |
| push_library_fn (tree name, tree type, tree raises, int ecf_flags) |
| { |
| tree fn; |
| |
| if (raises) |
| type = build_exception_variant (type, raises); |
| |
| fn = build_library_fn (name, ERROR_MARK, type, ecf_flags); |
| pushdecl_top_level (fn); |
| return fn; |
| } |
| |
| /* Like build_cp_library_fn, but also pushes the function so that it |
| will be found by normal lookup. */ |
| |
| static tree |
| push_cp_library_fn (enum tree_code operator_code, tree type, |
| int ecf_flags) |
| { |
| tree fn = build_cp_library_fn (ovl_op_identifier (false, operator_code), |
| operator_code, type, ecf_flags); |
| pushdecl (fn); |
| if (flag_tm) |
| apply_tm_attr (fn, get_identifier ("transaction_safe")); |
| return fn; |
| } |
| |
| /* Like push_library_fn, but takes a TREE_LIST of parm types rather than |
| a FUNCTION_TYPE. */ |
| |
| tree |
| push_void_library_fn (tree name, tree parmtypes, int ecf_flags) |
| { |
| tree type = build_function_type (void_type_node, parmtypes); |
| return push_library_fn (name, type, NULL_TREE, ecf_flags); |
| } |
| |
| /* Like push_library_fn, but also note that this function throws |
| and does not return. Used for __throw_foo and the like. */ |
| |
| tree |
| push_throw_library_fn (tree name, tree type) |
| { |
| tree fn = push_library_fn (name, type, NULL_TREE, ECF_NORETURN | ECF_COLD); |
| return fn; |
| } |
| |
| /* When we call finish_struct for an anonymous union, we create |
| default copy constructors and such. But, an anonymous union |
| shouldn't have such things; this function undoes the damage to the |
| anonymous union type T. |
| |
| (The reason that we create the synthesized methods is that we don't |
| distinguish `union { int i; }' from `typedef union { int i; } U'. |
| The first is an anonymous union; the second is just an ordinary |
| union type.) */ |
| |
| void |
| fixup_anonymous_aggr (tree t) |
| { |
| /* Wipe out memory of synthesized methods. */ |
| TYPE_HAS_USER_CONSTRUCTOR (t) = 0; |
| TYPE_HAS_DEFAULT_CONSTRUCTOR (t) = 0; |
| TYPE_HAS_COPY_CTOR (t) = 0; |
| TYPE_HAS_CONST_COPY_CTOR (t) = 0; |
| TYPE_HAS_COPY_ASSIGN (t) = 0; |
| TYPE_HAS_CONST_COPY_ASSIGN (t) = 0; |
| |
| /* Splice the implicitly generated functions out of TYPE_FIELDS. */ |
| for (tree probe, *prev_p = &TYPE_FIELDS (t); (probe = *prev_p);) |
| if (TREE_CODE (probe) == FUNCTION_DECL && DECL_ARTIFICIAL (probe)) |
| *prev_p = DECL_CHAIN (probe); |
| else |
| prev_p = &DECL_CHAIN (probe); |
| |
| /* Anonymous aggregates cannot have fields with ctors, dtors or complex |
| assignment operators (because they cannot have these methods themselves). |
| For anonymous unions this is already checked because they are not allowed |
| in any union, otherwise we have to check it. */ |
| if (TREE_CODE (t) != UNION_TYPE) |
| { |
| tree field, type; |
| |
| for (field = TYPE_FIELDS (t); field; field = DECL_CHAIN (field)) |
| if (TREE_CODE (field) == FIELD_DECL) |
| { |
| type = TREE_TYPE (field); |
| if (CLASS_TYPE_P (type)) |
| { |
| if (TYPE_NEEDS_CONSTRUCTING (type)) |
| error ("member %q+#D with constructor not allowed " |
| "in anonymous aggregate", field); |
| if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type)) |
| error ("member %q+#D with destructor not allowed " |
| "in anonymous aggregate", field); |
| if (TYPE_HAS_COMPLEX_COPY_ASSIGN (type)) |
| error ("member %q+#D with copy assignment operator " |
| "not allowed in anonymous aggregate", field); |
| } |
| } |
| } |
| } |
| |
| /* Warn for an attribute located at LOCATION that appertains to the |
| class type CLASS_TYPE that has not been properly placed after its |
| class-key, in it class-specifier. */ |
| |
| void |
| warn_misplaced_attr_for_class_type (location_t location, |
| tree class_type) |
| { |
| gcc_assert (OVERLOAD_TYPE_P (class_type)); |
| |
| auto_diagnostic_group d; |
| if (warning_at (location, OPT_Wattributes, |
| "attribute ignored in declaration " |
| "of %q#T", class_type)) |
| inform (location, |
| "attribute for %q#T must follow the %qs keyword", |
| class_type, class_key_or_enum_as_string (class_type)); |
| } |
| |
| /* Make sure that a declaration with no declarator is well-formed, i.e. |
| just declares a tagged type or anonymous union. |
| |
| Returns the type declared; or NULL_TREE if none. */ |
| |
| tree |
| check_tag_decl (cp_decl_specifier_seq *declspecs, |
| bool explicit_type_instantiation_p) |
| { |
| int saw_friend = decl_spec_seq_has_spec_p (declspecs, ds_friend); |
| int saw_typedef = decl_spec_seq_has_spec_p (declspecs, ds_typedef); |
| /* If a class, struct, or enum type is declared by the DECLSPECS |
| (i.e, if a class-specifier, enum-specifier, or non-typename |
| elaborated-type-specifier appears in the DECLSPECS), |
| DECLARED_TYPE is set to the corresponding type. */ |
| tree declared_type = NULL_TREE; |
| bool error_p = false; |
| |
| if (declspecs->multiple_types_p) |
| error ("multiple types in one declaration"); |
| else if (declspecs->redefined_builtin_type) |
| { |
| if (!in_system_header_at (input_location)) |
| permerror (declspecs->locations[ds_redefined_builtin_type_spec], |
| "redeclaration of C++ built-in type %qT", |
| declspecs->redefined_builtin_type); |
| return NULL_TREE; |
| } |
| |
| if (declspecs->type |
| && TYPE_P (declspecs->type) |
| && ((TREE_CODE (declspecs->type) != TYPENAME_TYPE |
| && MAYBE_CLASS_TYPE_P (declspecs->type)) |
| || TREE_CODE (declspecs->type) == ENUMERAL_TYPE)) |
| declared_type = declspecs->type; |
| else if (declspecs->type == error_mark_node) |
| error_p = true; |
| |
| if (type_uses_auto (declared_type)) |
| { |
| error_at (declspecs->locations[ds_type_spec], |
| "%<auto%> can only be specified for variables " |
| "or function declarations"); |
| return error_mark_node; |
| } |
| |
| if (declared_type && !OVERLOAD_TYPE_P (declared_type)) |
| declared_type = NULL_TREE; |
| |
| if (!declared_type && !saw_friend && !error_p) |
| permerror (input_location, "declaration does not declare anything"); |
| /* Check for an anonymous union. */ |
| else if (declared_type && RECORD_OR_UNION_CODE_P (TREE_CODE (declared_type)) |
| && TYPE_UNNAMED_P (declared_type)) |
| { |
| /* 7/3 In a simple-declaration, the optional init-declarator-list |
| can be omitted only when declaring a class (clause 9) or |
| enumeration (7.2), that is, when the decl-specifier-seq contains |
| either a class-specifier, an elaborated-type-specifier with |
| a class-key (9.1), or an enum-specifier. In these cases and |
| whenever a class-specifier or enum-specifier is present in the |
| decl-specifier-seq, the identifiers in these specifiers are among |
| the names being declared by the declaration (as class-name, |
| enum-names, or enumerators, depending on the syntax). In such |
| cases, and except for the declaration of an unnamed bit-field (9.6), |
| the decl-specifier-seq shall introduce one or more names into the |
| program, or shall redeclare a name introduced by a previous |
| declaration. [Example: |
| enum { }; // ill-formed |
| typedef class { }; // ill-formed |
| --end example] */ |
| if (saw_typedef) |
| { |
| error ("missing type-name in typedef-declaration"); |
| return NULL_TREE; |
| } |
| /* Anonymous unions are objects, so they can have specifiers. */; |
| SET_ANON_AGGR_TYPE_P (declared_type); |
| |
| if (TREE_CODE (declared_type) != UNION_TYPE |
| && !in_system_header_at (input_location)) |
| pedwarn (input_location, OPT_Wpedantic, "ISO C++ prohibits anonymous structs"); |
| } |
| |
| else |
| { |
| if (decl_spec_seq_has_spec_p (declspecs, ds_inline)) |
| error_at (declspecs->locations[ds_inline], |
| "%<inline%> can only be specified for functions"); |
| else if (decl_spec_seq_has_spec_p (declspecs, ds_virtual)) |
| error_at (declspecs->locations[ds_virtual], |
| "%<virtual%> can only be specified for functions"); |
| else if (saw_friend |
| && (!current_class_type |
| || current_scope () != current_class_type)) |
| error_at (declspecs->locations[ds_friend], |
| "%<friend%> can only be specified inside a class"); |
| else if (decl_spec_seq_has_spec_p (declspecs, ds_explicit)) |
| error_at (declspecs->locations[ds_explicit], |
| "%<explicit%> can only be specified for constructors"); |
| else if (declspecs->storage_class) |
| error_at (declspecs->locations[ds_storage_class], |
| "a storage class can only be specified for objects " |
| "and functions"); |
| else if (decl_spec_seq_has_spec_p (declspecs, ds_const)) |
| error_at (declspecs->locations[ds_const], |
| "%<const%> can only be specified for objects and " |
| "functions"); |
| else if (decl_spec_seq_has_spec_p (declspecs, ds_volatile)) |
| error_at (declspecs->locations[ds_volatile], |
| "%<volatile%> can only be specified for objects and " |
| "functions"); |
| else if (decl_spec_seq_has_spec_p (declspecs, ds_restrict)) |
| error_at (declspecs->locations[ds_restrict], |
| "%<__restrict%> can only be specified for objects and " |
| "functions"); |
| else if (decl_spec_seq_has_spec_p (declspecs, ds_thread)) |
| error_at (declspecs->locations[ds_thread], |
| "%<__thread%> can only be specified for objects " |
| "and functions"); |
| else if (saw_typedef) |
| warning_at (declspecs->locations[ds_typedef], 0, |
| "%<typedef%> was ignored in this declaration"); |
| else if (decl_spec_seq_has_spec_p (declspecs, ds_constexpr)) |
| error_at (declspecs->locations[ds_constexpr], |
| "%<constexpr%> cannot be used for type declarations"); |
| } |
| |
| if (declspecs->attributes && warn_attributes && declared_type) |
| { |
| location_t loc; |
| if (!CLASS_TYPE_P (declared_type) |
| || !CLASSTYPE_TEMPLATE_INSTANTIATION (declared_type)) |
| /* For a non-template class, use the name location. */ |
| loc = location_of (declared_type); |
| else |
| /* For a template class (an explicit instantiation), use the |
| current location. */ |
| loc = input_location; |
| |
| if (explicit_type_instantiation_p) |
| /* [dcl.attr.grammar]/4: |
| |
| No attribute-specifier-seq shall appertain to an explicit |
| instantiation. */ |
| { |
| if (warning_at (loc, OPT_Wattributes, |
| "attribute ignored in explicit instantiation %q#T", |
| declared_type)) |
| inform (loc, |
| "no attribute can be applied to " |
| "an explicit instantiation"); |
| } |
| else |
| warn_misplaced_attr_for_class_type (loc, declared_type); |
| } |
| |
| return declared_type; |
| } |
| |
| /* Called when a declaration is seen that contains no names to declare. |
| If its type is a reference to a structure, union or enum inherited |
| from a containing scope, shadow that tag name for the current scope |
| with a forward reference. |
| If its type defines a new named structure or union |
| or defines an enum, it is valid but we need not do anything here. |
| Otherwise, it is an error. |
| |
| C++: may have to grok the declspecs to learn about static, |
| complain for anonymous unions. |
| |
| Returns the TYPE declared -- or NULL_TREE if none. */ |
| |
| tree |
| shadow_tag (cp_decl_specifier_seq *declspecs) |
| { |
| tree t = check_tag_decl (declspecs, |
| /*explicit_type_instantiation_p=*/false); |
| |
| if (!t) |
| return NULL_TREE; |
| |
| if (maybe_process_partial_specialization (t) == error_mark_node) |
| return NULL_TREE; |
| |
| /* This is where the variables in an anonymous union are |
| declared. An anonymous union declaration looks like: |
| union { ... } ; |
| because there is no declarator after the union, the parser |
| sends that declaration here. */ |
| if (ANON_AGGR_TYPE_P (t)) |
| { |
| fixup_anonymous_aggr (t); |
| |
| if (TYPE_FIELDS (t)) |
| { |
| tree decl = grokdeclarator (/*declarator=*/NULL, |
| declspecs, NORMAL, 0, NULL); |
| finish_anon_union (decl); |
| } |
| } |
| |
| return t; |
| } |
| |
| /* Decode a "typename", such as "int **", returning a ..._TYPE node. */ |
| |
| tree |
| groktypename (cp_decl_specifier_seq *type_specifiers, |
| const cp_declarator *declarator, |
| bool is_template_arg) |
| { |
| tree attrs; |
| tree type; |
| enum decl_context context |
| = is_template_arg ? TEMPLATE_TYPE_ARG : TYPENAME; |
| attrs = type_specifiers->attributes; |
| type_specifiers->attributes = NULL_TREE; |
| type = grokdeclarator (declarator, type_specifiers, context, 0, &attrs); |
| if (attrs && type != error_mark_node) |
| { |
| if (CLASS_TYPE_P (type)) |
| warning (OPT_Wattributes, "ignoring attributes applied to class type %qT " |
| "outside of definition", type); |
| else if (MAYBE_CLASS_TYPE_P (type)) |
| /* A template type parameter or other dependent type. */ |
| warning (OPT_Wattributes, "ignoring attributes applied to dependent " |
| "type %qT without an associated declaration", type); |
| else |
| cplus_decl_attributes (&type, attrs, 0); |
| } |
| return type; |
| } |
| |
| /* Process a DECLARATOR for a function-scope variable declaration, |
| namespace-scope variable declaration, or function declaration. |
| (Function definitions go through start_function; class member |
| declarations appearing in the body of the class go through |
| grokfield.) The DECL corresponding to the DECLARATOR is returned. |
| If an error occurs, the error_mark_node is returned instead. |
| |
| DECLSPECS are the decl-specifiers for the declaration. INITIALIZED is |
| SD_INITIALIZED if an explicit initializer is present, or SD_DEFAULTED |
| for an explicitly defaulted function, or SD_DELETED for an explicitly |
| deleted function, but 0 (SD_UNINITIALIZED) if this is a variable |
| implicitly initialized via a default constructor. ATTRIBUTES and |
| PREFIX_ATTRIBUTES are GNU attributes associated with this declaration. |
| |
| The scope represented by the context of the returned DECL is pushed |
| (if it is not the global namespace) and is assigned to |
| *PUSHED_SCOPE_P. The caller is then responsible for calling |
| pop_scope on *PUSHED_SCOPE_P if it is set. */ |
| |
| tree |
| start_decl (const cp_declarator *declarator, |
| cp_decl_specifier_seq *declspecs, |
| int initialized, |
| tree attributes, |
| tree prefix_attributes, |
| tree *pushed_scope_p) |
| { |
| tree decl; |
| tree context; |
| bool was_public; |
| int flags; |
| bool alias; |
| |
| *pushed_scope_p = NULL_TREE; |
| |
| /* An object declared as __attribute__((deprecated)) suppresses |
| warnings of uses of other deprecated items. */ |
| if (lookup_attribute ("deprecated", attributes)) |
| deprecated_state = DEPRECATED_SUPPRESS; |
| |
| attributes = chainon (attributes, prefix_attributes); |
| |
| decl = grokdeclarator (declarator, declspecs, NORMAL, initialized, |
| &attributes); |
| |
| deprecated_state = DEPRECATED_NORMAL; |
| |
| if (decl == NULL_TREE || VOID_TYPE_P (decl) |
| || decl == error_mark_node) |
| return error_mark_node; |
| |
| context = CP_DECL_CONTEXT (decl); |
| if (context != global_namespace) |
| *pushed_scope_p = push_scope (context); |
| |
| /* Is it valid for this decl to have an initializer at all? |
| If not, set INITIALIZED to zero, which will indirectly |
| tell `cp_finish_decl' to ignore the initializer once it is parsed. */ |
| if (initialized |
| && TREE_CODE (decl) == TYPE_DECL) |
| { |
| error_at (DECL_SOURCE_LOCATION (decl), |
| "typedef %qD is initialized (use decltype instead)", decl); |
| return error_mark_node; |
| } |
| |
| if (initialized) |
| { |
| if (! toplevel_bindings_p () |
| && DECL_EXTERNAL (decl)) |
| warning (0, "declaration of %q#D has %<extern%> and is initialized", |
| decl); |
| DECL_EXTERNAL (decl) = 0; |
| if (toplevel_bindings_p ()) |
| TREE_STATIC (decl) = 1; |
| } |
| alias = lookup_attribute ("alias", DECL_ATTRIBUTES (decl)) != 0; |
| |
| if (alias && TREE_CODE (decl) == FUNCTION_DECL) |
| record_key_method_defined (decl); |
| |
| /* If this is a typedef that names the class for linkage purposes |
| (7.1.3p8), apply any attributes directly to the type. */ |
| if (TREE_CODE (decl) == TYPE_DECL |
| && OVERLOAD_TYPE_P (TREE_TYPE (decl)) |
| && decl == TYPE_NAME (TYPE_MAIN_VARIANT (TREE_TYPE (decl)))) |
| flags = ATTR_FLAG_TYPE_IN_PLACE; |
| else |
| flags = 0; |
| |
| /* Set attributes here so if duplicate decl, will have proper attributes. */ |
| cplus_decl_attributes (&decl, attributes, flags); |
| |
| /* Dllimported symbols cannot be defined. Static data members (which |
| can be initialized in-class and dllimported) go through grokfield, |
| not here, so we don't need to exclude those decls when checking for |
| a definition. */ |
| if (initialized && DECL_DLLIMPORT_P (decl)) |
| { |
| error_at (DECL_SOURCE_LOCATION (decl), |
| "definition of %q#D is marked %<dllimport%>", decl); |
| DECL_DLLIMPORT_P (decl) = 0; |
| } |
| |
| /* If #pragma weak was used, mark the decl weak now. */ |
| if (!processing_template_decl && !DECL_DECOMPOSITION_P (decl)) |
| maybe_apply_pragma_weak (decl); |
| |
| if (TREE_CODE (decl) == FUNCTION_DECL |
| && DECL_DECLARED_INLINE_P (decl) |
| && DECL_UNINLINABLE (decl) |
| && lookup_attribute ("noinline", DECL_ATTRIBUTES (decl))) |
| warning_at (DECL_SOURCE_LOCATION (decl), 0, |
| "inline function %qD given attribute noinline", decl); |
| |
| if (TYPE_P (context) && COMPLETE_TYPE_P (complete_type (context))) |
| { |
| bool this_tmpl = (processing_template_decl |
| > template_class_depth (context)); |
| if (VAR_P (decl)) |
| { |
| tree field = lookup_field (context, DECL_NAME (decl), 0, false); |
| if (field == NULL_TREE |
| || !(VAR_P (field) || variable_template_p (field))) |
| error ("%q+#D is not a static data member of %q#T", decl, context); |
| else if (variable_template_p (field) |
| && (DECL_LANG_SPECIFIC (decl) |
| && DECL_TEMPLATE_SPECIALIZATION (decl))) |
| /* OK, specialization was already checked. */; |
| else if (variable_template_p (field) && !this_tmpl) |
| { |
| error_at (DECL_SOURCE_LOCATION (decl), |
| "non-member-template declaration of %qD", decl); |
| inform (DECL_SOURCE_LOCATION (field), "does not match " |
| "member template declaration here"); |
| return error_mark_node; |
| } |
| else |
| { |
| if (variable_template_p (field)) |
| field = DECL_TEMPLATE_RESULT (field); |
| |
| if (DECL_CONTEXT (field) != context) |
| { |
| if (!same_type_p (DECL_CONTEXT (field), context)) |
| permerror (input_location, "ISO C++ does not permit %<%T::%D%> " |
| "to be defined as %<%T::%D%>", |
| DECL_CONTEXT (field), DECL_NAME (decl), |
| context, DECL_NAME (decl)); |
| DECL_CONTEXT (decl) = DECL_CONTEXT (field); |
| } |
| /* Static data member are tricky; an in-class initialization |
| still doesn't provide a definition, so the in-class |
| declaration will have DECL_EXTERNAL set, but will have an |
| initialization. Thus, duplicate_decls won't warn |
| about this situation, and so we check here. */ |
| if (initialized && DECL_INITIALIZED_IN_CLASS_P (field)) |
| error ("duplicate initialization of %qD", decl); |
| field = duplicate_decls (decl, field, |
| /*newdecl_is_friend=*/false); |
| if (field == error_mark_node) |
| return error_mark_node; |
| else if (field) |
| decl = field; |
| } |
| } |
| else |
| { |
| tree field = check_classfn (context, decl, |
| this_tmpl |
| ? current_template_parms |
| : NULL_TREE); |
| if (field && field != error_mark_node |
| && duplicate_decls (decl, field, |
| /*newdecl_is_friend=*/false)) |
| decl = field; |
| } |
| |
| /* cp_finish_decl sets DECL_EXTERNAL if DECL_IN_AGGR_P is set. */ |
| DECL_IN_AGGR_P (decl) = 0; |
| /* Do not mark DECL as an explicit specialization if it was not |
| already marked as an instantiation; a declaration should |
| never be marked as a specialization unless we know what |
| template is being specialized. */ |
| if (DECL_LANG_SPECIFIC (decl) && DECL_USE_TEMPLATE (decl)) |
| { |
| SET_DECL_TEMPLATE_SPECIALIZATION (decl); |
| if (TREE_CODE (decl) == FUNCTION_DECL) |
| DECL_COMDAT (decl) = (TREE_PUBLIC (decl) |
| && DECL_DECLARED_INLINE_P (decl)); |
| else |
| DECL_COMDAT (decl) = false; |
| |
| /* [temp.expl.spec] An explicit specialization of a static data |
| member of a template is a definition if the declaration |
| includes an initializer; otherwise, it is a declaration. |
| |
| We check for processing_specialization so this only applies |
| to the new specialization syntax. */ |
| if (!initialized && processing_specialization) |
| DECL_EXTERNAL (decl) = 1; |
| } |
| |
| if (DECL_EXTERNAL (decl) && ! DECL_TEMPLATE_SPECIALIZATION (decl) |
| /* Aliases are definitions. */ |
| && !alias) |
| permerror (declarator->id_loc, |
| "declaration of %q#D outside of class is not definition", |
| decl); |
| } |
| |
| was_public = TREE_PUBLIC (decl); |
| |
| /* Enter this declaration into the symbol table. Don't push the plain |
| VAR_DECL for a variable template. */ |
| if (!template_parm_scope_p () |
| || !VAR_P (decl)) |
| decl = maybe_push_decl (decl); |
| |
| if (processing_template_decl) |
| decl = push_template_decl (decl); |
| if (decl == error_mark_node) |
| return error_mark_node; |
| |
| if (VAR_P (decl) |
| && DECL_NAMESPACE_SCOPE_P (decl) && !TREE_PUBLIC (decl) && !was_public |
| && !DECL_THIS_STATIC (decl) && !DECL_ARTIFICIAL (decl)) |
| { |
| /* This is a const variable with implicit 'static'. Set |
| DECL_THIS_STATIC so we can tell it from variables that are |
| !TREE_PUBLIC because of the anonymous namespace. */ |
| gcc_assert (CP_TYPE_CONST_P (TREE_TYPE (decl)) || errorcount); |
| DECL_THIS_STATIC (decl) = 1; |
| } |
| |
| if (current_function_decl && VAR_P (decl) |
| && DECL_DECLARED_CONSTEXPR_P (current_function_decl)) |
| { |
| bool ok = false; |
| if (CP_DECL_THREAD_LOCAL_P (decl) && !DECL_REALLY_EXTERN (decl)) |
| error_at (DECL_SOURCE_LOCATION (decl), |
| "%qD declared %<thread_local%> in %<constexpr%> function", |
| decl); |
| else if (TREE_STATIC (decl)) |
| error_at (DECL_SOURCE_LOCATION (decl), |
| "%qD declared %<static%> in %<constexpr%> function", decl); |
| else |
| ok = true; |
| if (!ok) |
| cp_function_chain->invalid_constexpr = true; |
| } |
| |
| if (!processing_template_decl && VAR_P (decl)) |
| start_decl_1 (decl, initialized); |
| |
| return decl; |
| } |
| |
| /* Process the declaration of a variable DECL. INITIALIZED is true |
| iff DECL is explicitly initialized. (INITIALIZED is false if the |
| variable is initialized via an implicitly-called constructor.) |
| This function must be called for ordinary variables (including, for |
| example, implicit instantiations of templates), but must not be |
| called for template declarations. */ |
| |
| void |
| start_decl_1 (tree decl, bool initialized) |
| { |
| tree type; |
| bool complete_p; |
| bool aggregate_definition_p; |
| |
| gcc_assert (!processing_template_decl); |
| |
| if (error_operand_p (decl)) |
| return; |
| |
| gcc_assert (VAR_P (decl)); |
| |
| type = TREE_TYPE (decl); |
| complete_p = COMPLETE_TYPE_P (type); |
| aggregate_definition_p = MAYBE_CLASS_TYPE_P (type) && !DECL_EXTERNAL (decl); |
| |
| /* If an explicit initializer is present, or if this is a definition |
| of an aggregate, then we need a complete type at this point. |
| (Scalars are always complete types, so there is nothing to |
| check.) This code just sets COMPLETE_P; errors (if necessary) |
| are issued below. */ |
| if ((initialized || aggregate_definition_p) |
| && !complete_p |
| && COMPLETE_TYPE_P (complete_type (type))) |
| { |
| complete_p = true; |
| /* We will not yet have set TREE_READONLY on DECL if the type |
| was "const", but incomplete, before this point. But, now, we |
| have a complete type, so we can try again. */ |
| cp_apply_type_quals_to_decl (cp_type_quals (type), decl); |
| } |
| |
| if (initialized) |
| /* Is it valid for this decl to have an initializer at all? */ |
| { |
| /* Don't allow initializations for incomplete types except for |
| arrays which might be completed by the initialization. */ |
| if (complete_p) |
| ; /* A complete type is ok. */ |
| else if (type_uses_auto (type)) |
| ; /* An auto type is ok. */ |
| else if (TREE_CODE (type) != ARRAY_TYPE) |
| { |
| error ("variable %q#D has initializer but incomplete type", decl); |
| type = TREE_TYPE (decl) = error_mark_node; |
| } |
| else if (!COMPLETE_TYPE_P (complete_type (TREE_TYPE (type)))) |
| { |
| if (DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (decl)) |
| error ("elements of array %q#D have incomplete type", decl); |
| /* else we already gave an error in start_decl. */ |
| } |
| } |
| else if (aggregate_definition_p && !complete_p) |
| { |
| if (type_uses_auto (type)) |
| gcc_assert (CLASS_PLACEHOLDER_TEMPLATE (type)); |
| else |
| { |
| error ("aggregate %q#D has incomplete type and cannot be defined", |
| decl); |
| /* Change the type so that assemble_variable will give |
| DECL an rtl we can live with: (mem (const_int 0)). */ |
| type = TREE_TYPE (decl) = error_mark_node; |
| } |
| } |
| |
| /* Create a new scope to hold this declaration if necessary. |
| Whether or not a new scope is necessary cannot be determined |
| until after the type has been completed; if the type is a |
| specialization of a class template it is not until after |
| instantiation has occurred that TYPE_HAS_NONTRIVIAL_DESTRUCTOR |
| will be set correctly. */ |
| maybe_push_cleanup_level (type); |
| } |
| |
| /* Handle initialization of references. DECL, TYPE, and INIT have the |
| same meaning as in cp_finish_decl. *CLEANUP must be NULL on entry, |
| but will be set to a new CLEANUP_STMT if a temporary is created |
| that must be destroyed subsequently. |
| |
| Returns an initializer expression to use to initialize DECL, or |
| NULL if the initialization can be performed statically. |
| |
| Quotes on semantics can be found in ARM 8.4.3. */ |
| |
| static tree |
| grok_reference_init (tree decl, tree type, tree init, int flags) |
| { |
| if (init == NULL_TREE) |
| { |
| if ((DECL_LANG_SPECIFIC (decl) == 0 |
| || DECL_IN_AGGR_P (decl) == 0) |
| && ! DECL_THIS_EXTERN (decl)) |
| error_at (DECL_SOURCE_LOCATION (decl), |
| "%qD declared as reference but not initialized", decl); |
| return NULL_TREE; |
| } |
| |
| if (TREE_CODE (init) == TREE_LIST) |
| init = build_x_compound_expr_from_list (init, ELK_INIT, |
| tf_warning_or_error); |
| |
| tree ttype = TREE_TYPE (type); |
| if (TREE_CODE (ttype) != ARRAY_TYPE |
| && TREE_CODE (TREE_TYPE (init)) == ARRAY_TYPE) |
| /* Note: default conversion is only called in very special cases. */ |
| init = decay_conversion (init, tf_warning_or_error); |
| |
| /* check_initializer handles this for non-reference variables, but for |
| references we need to do it here or the initializer will get the |
| incomplete array type and confuse later calls to |
| cp_complete_array_type. */ |
| if (TREE_CODE (ttype) == ARRAY_TYPE |
| && TYPE_DOMAIN (ttype) == NULL_TREE |
| && (BRACE_ENCLOSED_INITIALIZER_P (init) |
| || TREE_CODE (init) == STRING_CST)) |
| { |
| cp_complete_array_type (&ttype, init, false); |
| if (ttype != TREE_TYPE (type)) |
| type = cp_build_reference_type (ttype, TYPE_REF_IS_RVALUE (type)); |
| } |
| |
| /* Convert INIT to the reference type TYPE. This may involve the |
| creation of a temporary, whose lifetime must be the same as that |
| of the reference. If so, a DECL_EXPR for the temporary will be |
| added just after the DECL_EXPR for DECL. That's why we don't set |
| DECL_INITIAL for local references (instead assigning to them |
| explicitly); we need to allow the temporary to be initialized |
| first. */ |
| return initialize_reference (type, init, flags, |
| tf_warning_or_error); |
| } |
| |
| /* Designated initializers in arrays are not supported in GNU C++. |
| The parser cannot detect this error since it does not know whether |
| a given brace-enclosed initializer is for a class type or for an |
| array. This function checks that CE does not use a designated |
| initializer. If it does, an error is issued. Returns true if CE |
| is valid, i.e., does not have a designated initializer. */ |
| |
| bool |
| check_array_designated_initializer (constructor_elt *ce, |
| unsigned HOST_WIDE_INT index) |
| { |
| /* Designated initializers for array elements are not supported. */ |
| if (ce->index) |
| { |
| /* The parser only allows identifiers as designated |
| initializers. */ |
| if (ce->index == error_mark_node) |
| { |
| error ("name used in a GNU-style designated " |
| "initializer for an array"); |
| return false; |
| } |
| else if (identifier_p (ce->index)) |
| { |
| error ("name %qD used in a GNU-style designated " |
| "initializer for an array", ce->index); |
| return false; |
| } |
| |
| tree ce_index = build_expr_type_conversion (WANT_INT | WANT_ENUM, |
| ce->index, true); |
| if (ce_index |
| && INTEGRAL_OR_UNSCOPED_ENUMERATION_TYPE_P (TREE_TYPE (ce_index)) |
| && (TREE_CODE (ce_index = fold_non_dependent_expr (ce_index)) |
| == INTEGER_CST)) |
| { |
| /* A C99 designator is OK if it matches the current index. */ |
| if (wi::to_wide (ce_index) == index) |
| { |
| ce->index = ce_index; |
| return true; |
| } |
| else |
| sorry ("non-trivial designated initializers not supported"); |
| } |
| else |
| error ("C99 designator %qE is not an integral constant-expression", |
| ce->index); |
| |
| return false; |
| } |
| |
| return true; |
| } |
| |
| /* When parsing `int a[] = {1, 2};' we don't know the size of the |
| array until we finish parsing the initializer. If that's the |
| situation we're in, update DECL accordingly. */ |
| |
| static void |
| maybe_deduce_size_from_array_init (tree decl, tree init) |
| { |
| tree type = TREE_TYPE (decl); |
| |
| if (TREE_CODE (type) == ARRAY_TYPE |
| && TYPE_DOMAIN (type) == NULL_TREE |
| && TREE_CODE (decl) != TYPE_DECL) |
| { |
| /* do_default is really a C-ism to deal with tentative definitions. |
| But let's leave it here to ease the eventual merge. */ |
| int do_default = !DECL_EXTERNAL (decl); |
| tree initializer = init ? init : DECL_INITIAL (decl); |
| int failure = 0; |
| |
| /* Check that there are no designated initializers in INIT, as |
| those are not supported in GNU C++, and as the middle-end |
| will crash if presented with a non-numeric designated |
| initializer. */ |
| if (initializer && BRACE_ENCLOSED_INITIALIZER_P (initializer)) |
| { |
| vec<constructor_elt, va_gc> *v = CONSTRUCTOR_ELTS (initializer); |
| constructor_elt *ce; |
| HOST_WIDE_INT i; |
| FOR_EACH_VEC_SAFE_ELT (v, i, ce) |
| { |
| if (instantiation_dependent_expression_p (ce->index)) |
| return; |
| if (!check_array_designated_initializer (ce, i)) |
| failure = 1; |
| } |
| } |
| |
| if (failure) |
| TREE_TYPE (decl) = error_mark_node; |
| else |
| { |
| failure = cp_complete_array_type (&TREE_TYPE (decl), initializer, |
| do_default); |
| if (failure == 1) |
| { |
| error_at (cp_expr_loc_or_loc (initializer, |
| DECL_SOURCE_LOCATION (decl)), |
| "initializer fails to determine size of %qD", decl); |
| } |
| else if (failure == 2) |
| { |
| if (do_default) |
| { |
| error_at (DECL_SOURCE_LOCATION (decl), |
| "array size missing in %qD", decl); |
| } |
| /* If a `static' var's size isn't known, make it extern as |
| well as static, so it does not get allocated. If it's not |
| `static', then don't mark it extern; finish_incomplete_decl |
| will give it a default size and it will get allocated. */ |
| else if (!pedantic && TREE_STATIC (decl) && !TREE_PUBLIC (decl)) |
| DECL_EXTERNAL (decl) = 1; |
| } |
| else if (failure == 3) |
| { |
| error_at (DECL_SOURCE_LOCATION (decl), |
| "zero-size array %qD", decl); |
| } |
| } |
| |
| cp_apply_type_quals_to_decl (cp_type_quals (TREE_TYPE (decl)), decl); |
| |
| relayout_decl (decl); |
| } |
| } |
| |
| /* Set DECL_SIZE, DECL_ALIGN, etc. for DECL (a VAR_DECL), and issue |
| any appropriate error messages regarding the layout. */ |
| |
| static void |
| layout_var_decl (tree decl) |
| { |
| tree type; |
| |
| type = TREE_TYPE (decl); |
| if (type == error_mark_node) |
| return; |
| |
| /* If we haven't already laid out this declaration, do so now. |
| Note that we must not call complete type for an external object |
| because it's type might involve templates that we are not |
| supposed to instantiate yet. (And it's perfectly valid to say |
| `extern X x' for some incomplete type `X'.) */ |
| if (!DECL_EXTERNAL (decl)) |
| complete_type (type); |
| if (!DECL_SIZE (decl) |
| && TREE_TYPE (decl) != error_mark_node |
| && complete_or_array_type_p (type)) |
| layout_decl (decl, 0); |
| |
| if (!DECL_EXTERNAL (decl) && DECL_SIZE (decl) == NULL_TREE) |
| { |
| /* An automatic variable with an incomplete type: that is an error. |
| Don't talk about array types here, since we took care of that |
| message in grokdeclarator. */ |
| error_at (DECL_SOURCE_LOCATION (decl), |
| "storage size of %qD isn%'t known", decl); |
| TREE_TYPE (decl) = error_mark_node; |
| } |
| #if 0 |
| /* Keep this code around in case we later want to control debug info |
| based on whether a type is "used". (jason 1999-11-11) */ |
| |
| else if (!DECL_EXTERNAL (decl) && MAYBE_CLASS_TYPE_P (ttype)) |
| /* Let debugger know it should output info for this type. */ |
| note_debug_info_needed (ttype); |
| |
| if (TREE_STATIC (decl) && DECL_CLASS_SCOPE_P (decl)) |
| note_debug_info_needed (DECL_CONTEXT (decl)); |
| #endif |
| |
| if ((DECL_EXTERNAL (decl) || TREE_STATIC (decl)) |
| && DECL_SIZE (decl) != NULL_TREE |
| && ! TREE_CONSTANT (DECL_SIZE (decl))) |
| { |
| if (TREE_CODE (DECL_SIZE (decl)) == INTEGER_CST) |
| constant_expression_warning (DECL_SIZE (decl)); |
| else |
| { |
| error_at (DECL_SOURCE_LOCATION (decl), |
| "storage size of %qD isn%'t constant", decl); |
| TREE_TYPE (decl) = error_mark_node; |
| type = error_mark_node; |
| } |
| } |
| |
| /* If the final element initializes a flexible array field, add the size of |
| that initializer to DECL's size. */ |
| if (type != error_mark_node |
| && DECL_INITIAL (decl) |
| && TREE_CODE (DECL_INITIAL (decl)) == CONSTRUCTOR |
| && !vec_safe_is_empty (CONSTRUCTOR_ELTS (DECL_INITIAL (decl))) |
| && DECL_SIZE (decl) != NULL_TREE |
| && TREE_CODE (DECL_SIZE (decl)) == INTEGER_CST |
| && TYPE_SIZE (type) != NULL_TREE |
| && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST |
| && tree_int_cst_equal (DECL_SIZE (decl), TYPE_SIZE (type))) |
| { |
| constructor_elt &elt = CONSTRUCTOR_ELTS (DECL_INITIAL (decl))->last (); |
| if (elt.index) |
| { |
| tree itype = TREE_TYPE (elt.index); |
| tree vtype = TREE_TYPE (elt.value); |
| if (TREE_CODE (itype) == ARRAY_TYPE |
| && TYPE_DOMAIN (itype) == NULL |
| && TREE_CODE (vtype) == ARRAY_TYPE |
| && COMPLETE_TYPE_P (vtype)) |
| { |
| DECL_SIZE (decl) |
| = size_binop (PLUS_EXPR, DECL_SIZE (decl), TYPE_SIZE (vtype)); |
| DECL_SIZE_UNIT (decl) |
| = size_binop (PLUS_EXPR, DECL_SIZE_UNIT (decl), |
| TYPE_SIZE_UNIT (vtype)); |
| } |
| } |
| } |
| } |
| |
| /* If a local static variable is declared in an inline function, or if |
| we have a weak definition, we must endeavor to create only one |
| instance of the variable at link-time. */ |
| |
| void |
| maybe_commonize_var (tree decl) |
| { |
| /* Don't mess with __FUNCTION__ and similar. */ |
| if (DECL_ARTIFICIAL (decl)) |
| return; |
| |
| /* Static data in a function with comdat linkage also has comdat |
| linkage. */ |
| if ((TREE_STATIC (decl) |
| && DECL_FUNCTION_SCOPE_P (decl) |
| && vague_linkage_p (DECL_CONTEXT (decl))) |
| || (TREE_PUBLIC (decl) && DECL_INLINE_VAR_P (decl))) |
| { |
| if (flag_weak) |
| { |
| /* With weak symbols, we simply make the variable COMDAT; |
| that will cause copies in multiple translations units to |
| be merged. */ |
| comdat_linkage (decl); |
| } |
| else |
| { |
| if (DECL_INITIAL (decl) == NULL_TREE |
| || DECL_INITIAL (decl) == error_mark_node) |
| { |
| /* Without weak symbols, we can use COMMON to merge |
| uninitialized variables. */ |
| TREE_PUBLIC (decl) = 1; |
| DECL_COMMON (decl) = 1; |
| } |
| else |
| { |
| /* While for initialized variables, we must use internal |
| linkage -- which means that multiple copies will not |
| be merged. */ |
| TREE_PUBLIC (decl) = 0; |
| DECL_COMMON (decl) = 0; |
| DECL_INTERFACE_KNOWN (decl) = 1; |
| const char *msg; |
| if (DECL_INLINE_VAR_P (decl)) |
| msg = G_("sorry: semantics of inline variable " |
| "%q#D are wrong (you%'ll wind up with " |
| "multiple copies)"); |
| else |
| msg = G_("sorry: semantics of inline function " |
| "static data %q#D are wrong (you%'ll wind " |
| "up with multiple copies)"); |
| if (warning_at (DECL_SOURCE_LOCATION (decl), 0, |
| msg, decl)) |
| inform (DECL_SOURCE_LOCATION (decl), |
| "you can work around this by removing the initializer"); |
| } |
| } |
| } |
| } |
| |
| /* Issue an error message if DECL is an uninitialized const variable. |
| CONSTEXPR_CONTEXT_P is true when the function is called in a constexpr |
| context from potential_constant_expression. Returns true if all is well, |
| false otherwise. */ |
| |
| bool |
| check_for_uninitialized_const_var (tree decl, bool constexpr_context_p, |
| tsubst_flags_t complain) |
| { |
| tree type = strip_array_types (TREE_TYPE (decl)); |
| |
| /* ``Unless explicitly declared extern, a const object does not have |
| external linkage and must be initialized. ($8.4; $12.1)'' ARM |
| 7.1.6 */ |
| if (VAR_P (decl) |
| && !TYPE_REF_P (type) |
| && (constexpr_context_p |
| || CP_TYPE_CONST_P (type) || var_in_constexpr_fn (decl)) |
| && !DECL_NONTRIVIALLY_INITIALIZED_P (decl)) |
| { |
| tree field = default_init_uninitialized_part (type); |
| if (!field) |
| return true; |
| |
| if (!constexpr_context_p) |
| { |
| if (CP_TYPE_CONST_P (type)) |
| { |
| if (complain & tf_error) |
| permerror (DECL_SOURCE_LOCATION (decl), |
| "uninitialized const %qD", decl); |
| } |
| else |
| { |
| if (!is_instantiation_of_constexpr (current_function_decl) |
| && (complain & tf_error)) |
| error_at (DECL_SOURCE_LOCATION (decl), |
| "uninitialized variable %qD in %<constexpr%> " |
| "function", decl); |
| cp_function_chain->invalid_constexpr = true; |
| } |
| } |
| else if (complain & tf_error) |
| error_at (DECL_SOURCE_LOCATION (decl), |
| "uninitialized variable %qD in %<constexpr%> context", |
| decl); |
| |
| if (CLASS_TYPE_P (type) && (complain & tf_error)) |
| { |
| tree defaulted_ctor; |
| |
| inform (DECL_SOURCE_LOCATION (TYPE_MAIN_DECL (type)), |
| "%q#T has no user-provided default constructor", type); |
| defaulted_ctor = in_class_defaulted_default_constructor (type); |
| if (defaulted_ctor) |
| inform (DECL_SOURCE_LOCATION (defaulted_ctor), |
| "constructor is not user-provided because it is " |
| "explicitly defaulted in the class body"); |
| inform (DECL_SOURCE_LOCATION (field), |
| "and the implicitly-defined constructor does not " |
| "initialize %q#D", field); |
| } |
| |
| return false; |
| } |
| |
| return true; |
| } |
| |
| /* Structure holding the current initializer being processed by reshape_init. |
| CUR is a pointer to the current element being processed, END is a pointer |
| after the last element present in the initializer. */ |
| struct reshape_iter |
| { |
| constructor_elt *cur; |
| constructor_elt *end; |
| }; |
| |
| static tree reshape_init_r (tree, reshape_iter *, bool, tsubst_flags_t); |
| |
| /* FIELD is a FIELD_DECL or NULL. In the former case, the value |
| returned is the next FIELD_DECL (possibly FIELD itself) that can be |
| initialized. If there are no more such fields, the return value |
| will be NULL. */ |
| |
| tree |
| next_initializable_field (tree field) |
| { |
| while (field |
| && (TREE_CODE (field) != FIELD_DECL |
| || DECL_UNNAMED_BIT_FIELD (field) |
| || (DECL_ARTIFICIAL (field) |
| && !(cxx_dialect >= cxx17 && DECL_FIELD_IS_BASE (field))))) |
| field = DECL_CHAIN (field); |
| |
| return field; |
| } |
| |
| /* Return true for [dcl.init.list] direct-list-initialization from |
| single element of enumeration with a fixed underlying type. */ |
| |
| bool |
| is_direct_enum_init (tree type, tree init) |
| { |
| if (cxx_dialect >= cxx17 |
| && TREE_CODE (type) == ENUMERAL_TYPE |
| && ENUM_FIXED_UNDERLYING_TYPE_P (type) |
| && TREE_CODE (init) == CONSTRUCTOR |
| && CONSTRUCTOR_IS_DIRECT_INIT (init) |
| && CONSTRUCTOR_NELTS (init) == 1) |
| return true; |
| return false; |
| } |
| |
| /* Subroutine of reshape_init_array and reshape_init_vector, which does |
| the actual work. ELT_TYPE is the element type of the array. MAX_INDEX is an |
| INTEGER_CST representing the size of the array minus one (the maximum index), |
| or NULL_TREE if the array was declared without specifying the size. D is |
| the iterator within the constructor. */ |
| |
| static tree |
| reshape_init_array_1 (tree elt_type, tree max_index, reshape_iter *d, |
| tsubst_flags_t complain) |
| { |
| tree new_init; |
| bool sized_array_p = (max_index && TREE_CONSTANT (max_index)); |
| unsigned HOST_WIDE_INT max_index_cst = 0; |
| unsigned HOST_WIDE_INT index; |
| |
| /* The initializer for an array is always a CONSTRUCTOR. */ |
| new_init = build_constructor (init_list_type_node, NULL); |
| |
| if (sized_array_p) |
| { |
| /* Minus 1 is used for zero sized arrays. */ |
| if (integer_all_onesp (max_index)) |
| return new_init; |
| |
| if (tree_fits_uhwi_p (max_index)) |
| max_index_cst = tree_to_uhwi (max_index); |
| /* sizetype is sign extended, not zero extended. */ |
| else |
| max_index_cst = tree_to_uhwi (fold_convert (size_type_node, max_index)); |
| } |
| |
| /* Loop until there are no more initializers. */ |
| for (index = 0; |
| d->cur != d->end && (!sized_array_p || index <= max_index_cst); |
| ++index) |
| { |
| tree elt_init; |
| constructor_elt *old_cur = d->cur; |
| |
| check_array_designated_initializer (d->cur, index); |
| elt_init = reshape_init_r (elt_type, d, /*first_initializer_p=*/false, |
| complain); |
| if (elt_init == error_mark_node) |
| return error_mark_node; |
| CONSTRUCTOR_APPEND_ELT (CONSTRUCTOR_ELTS (new_init), |
| size_int (index), elt_init); |
| if (!TREE_CONSTANT (elt_init)) |
| TREE_CONSTANT (new_init) = false; |
| |
| /* This can happen with an invalid initializer (c++/54501). */ |
| if (d->cur == old_cur && !sized_array_p) |
| break; |
| } |
| |
| return new_init; |
| } |
| |
| /* Subroutine of reshape_init_r, processes the initializers for arrays. |
| Parameters are the same of reshape_init_r. */ |
| |
| static tree |
| reshape_init_array (tree type, reshape_iter *d, tsubst_flags_t complain) |
| { |
| tree max_index = NULL_TREE; |
| |
| gcc_assert (TREE_CODE (type) == ARRAY_TYPE); |
| |
| if (TYPE_DOMAIN (type)) |
| max_index = array_type_nelts (type); |
| |
| return reshape_init_array_1 (TREE_TYPE (type), max_index, d, complain); |
| } |
| |
| /* Subroutine of reshape_init_r, processes the initializers for vectors. |
| Parameters are the same of reshape_init_r. */ |
| |
| static tree |
| reshape_init_vector (tree type, reshape_iter *d, tsubst_flags_t complain) |
| { |
| tree max_index = NULL_TREE; |
| |
| gcc_assert (VECTOR_TYPE_P (type)); |
| |
| if (COMPOUND_LITERAL_P (d->cur->value)) |
| { |
| tree value = d->cur->value; |
| if (!same_type_p (TREE_TYPE (value), type)) |
| { |
| if (complain & tf_error) |
| error ("invalid type %qT as initializer for a vector of type %qT", |
| TREE_TYPE (d->cur->value), type); |
| value = error_mark_node; |
| } |
| ++d->cur; |
| return value; |
| } |
| |
| /* For a vector, we initialize it as an array of the appropriate size. */ |
| if (VECTOR_TYPE_P (type)) |
| max_index = size_int (TYPE_VECTOR_SUBPARTS (type) - 1); |
| |
| return reshape_init_array_1 (TREE_TYPE (type), max_index, d, complain); |
| } |
| |
| /* Subroutine of reshape_init_r, processes the initializers for classes |
| or union. Parameters are the same of reshape_init_r. */ |
| |
| static tree |
| reshape_init_class (tree type, reshape_iter *d, bool first_initializer_p, |
| tsubst_flags_t complain) |
| { |
| tree field; |
| tree new_init; |
| |
| gcc_assert (CLASS_TYPE_P (type)); |
| |
| /* The initializer for a class is always a CONSTRUCTOR. */ |
| new_init = build_constructor (init_list_type_node, NULL); |
| field = next_initializable_field (TYPE_FIELDS (type)); |
| |
| if (!field) |
| { |
| /* [dcl.init.aggr] |
| |
| An initializer for an aggregate member that is an |
| empty class shall have the form of an empty |
| initializer-list {}. */ |
| if (!first_initializer_p) |
| { |
| if (complain & tf_error) |
| error ("initializer for %qT must be brace-enclosed", type); |
| return error_mark_node; |
| } |
| return new_init; |
| } |
| |
| /* Loop through the initializable fields, gathering initializers. */ |
| while (d->cur != d->end) |
| { |
| tree field_init; |
| constructor_elt *old_cur = d->cur; |
| |
| /* Handle designated initializers, as an extension. */ |
| if (d->cur->index) |
| { |
| if (d->cur->index == error_mark_node) |
| return error_mark_node; |
| |
| if (TREE_CODE (d->cur->index) == FIELD_DECL) |
| { |
| /* We already reshaped this. */ |
| if (field != d->cur->index) |
| { |
| tree id = DECL_NAME (d->cur->index); |
| gcc_assert (id); |
| gcc_checking_assert (d->cur->index |
| == get_class_binding (type, id, false)); |
| field = d->cur->index; |
| } |
| } |
| else if (TREE_CODE (d->cur->index) == IDENTIFIER_NODE) |
| field = get_class_binding (type, d->cur->index, false); |
| else |
| { |
| if (complain & tf_error) |
| error ("%<[%E] =%> used in a GNU-style designated initializer" |
| " for class %qT", d->cur->index, type); |
| return error_mark_node; |
| } |
| |
| if (!field || TREE_CODE (field) != FIELD_DECL) |
| { |
| if (complain & tf_error) |
| error ("%qT has no non-static data member named %qD", type, |
| d->cur->index); |
| return error_mark_node; |
| } |
| } |
| |
| /* If we processed all the member of the class, we are done. */ |
| if (!field) |
| break; |
| |
| field_init = reshape_init_r (TREE_TYPE (field), d, |
| /*first_initializer_p=*/false, complain); |
| if (field_init == error_mark_node) |
| return error_mark_node; |
| |
| if (d->cur == old_cur && d->cur->index) |
| { |
| /* This can happen with an invalid initializer for a flexible |
| array member (c++/54441). */ |
| if (complain & tf_error) |
| error ("invalid initializer for %q#D", field); |
| return error_mark_node; |
| } |
| |
| CONSTRUCTOR_APPEND_ELT (CONSTRUCTOR_ELTS (new_init), field, field_init); |
| |
| /* [dcl.init.aggr] |
| |
| When a union is initialized with a brace-enclosed |
| initializer, the braces shall only contain an |
| initializer for the first member of the union. */ |
| if (TREE_CODE (type) == UNION_TYPE) |
| break; |
| |
| field = next_initializable_field (DECL_CHAIN (field)); |
| } |
| |
| return new_init; |
| } |
| |
| /* Subroutine of reshape_init_r. We're in a context where C99 initializer |
| designators are not valid; either complain or return true to indicate |
| that reshape_init_r should return error_mark_node. */ |
| |
| static bool |
| has_designator_problem (reshape_iter *d, tsubst_flags_t complain) |
| { |
| if (d->cur->index) |
| { |
| if (complain & tf_error) |
| error ("C99 designator %qE outside aggregate initializer", |
| d->cur->index); |
| else |
| return true; |
| } |
| return false; |
| } |
| |
| /* Subroutine of reshape_init, which processes a single initializer (part of |
| a CONSTRUCTOR). TYPE is the type of the variable being initialized, D is the |
| iterator within the CONSTRUCTOR which points to the initializer to process. |
| FIRST_INITIALIZER_P is true if this is the first initializer of the |
| outermost CONSTRUCTOR node. */ |
| |
| static tree |
| reshape_init_r (tree type, reshape_iter *d, bool first_initializer_p, |
| tsubst_flags_t complain) |
| { |
| tree init = d->cur->value; |
| |
| if (error_operand_p (init)) |
| return error_mark_node; |
| |
| if (first_initializer_p && !CP_AGGREGATE_TYPE_P (type) |
| && has_designator_problem (d, complain)) |
| return error_mark_node; |
| |
| tree stripped_init = tree_strip_any_location_wrapper (init); |
| |
| if (TREE_CODE (type) == COMPLEX_TYPE) |
| { |
| /* A complex type can be initialized from one or two initializers, |
| but braces are not elided. */ |
| d->cur++; |
| if (BRACE_ENCLOSED_INITIALIZER_P (stripped_init)) |
| { |
| if (CONSTRUCTOR_NELTS (stripped_init) > 2) |
| { |
| if (complain & tf_error) |
| error ("too many initializers for %qT", type); |
| else |
| return error_mark_node; |
| } |
| } |
| else if (first_initializer_p && d->cur != d->end) |
| { |
| vec<constructor_elt, va_gc> *v = 0; |
| CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, init); |
| CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, d->cur->value); |
| if (has_designator_problem (d, complain)) |
| return error_mark_node; |
| d->cur++; |
| init = build_constructor (init_list_type_node, v); |
| } |
| return init; |
| } |
| |
| /* A non-aggregate type is always initialized with a single |
| initializer. */ |
| if (!CP_AGGREGATE_TYPE_P (type)) |
| { |
| /* It is invalid to initialize a non-aggregate type with a |
| brace-enclosed initializer before C++0x. |
| We need to check for BRACE_ENCLOSED_INITIALIZER_P here because |
| of g++.old-deja/g++.mike/p7626.C: a pointer-to-member constant is |
| a CONSTRUCTOR (with a record type). */ |
| if (TREE_CODE (stripped_init) == CONSTRUCTOR |
| /* Don't complain about a capture-init. */ |
| && !CONSTRUCTOR_IS_DIRECT_INIT (stripped_init) |
| && BRACE_ENCLOSED_INITIALIZER_P (stripped_init)) /* p7626.C */ |
| { |
| if (SCALAR_TYPE_P (type)) |
| { |
| if (cxx_dialect < cxx11) |
| { |
| if (complain & tf_error) |
| error ("braces around scalar initializer for type %qT", |
| type); |
| init = error_mark_node; |
| } |
| else if (first_initializer_p |
| || (CONSTRUCTOR_NELTS (stripped_init) > 0 |
| && (BRACE_ENCLOSED_INITIALIZER_P |
| (CONSTRUCTOR_ELT (stripped_init,0)->value)))) |
| { |
| if (complain & tf_error) |
| error ("too many braces around scalar initializer " |
| "for type %qT", type); |
| init = error_mark_node; |
| } |
| } |
| else |
| maybe_warn_cpp0x (CPP0X_INITIALIZER_LISTS); |
| } |
| |
| d->cur++; |
| return init; |
| } |
| |
| /* "If T is a class type and the initializer list has a single element of |
| type cv U, where U is T or a class derived from T, the object is |
| initialized from that element." Even if T is an aggregate. */ |
| if (cxx_dialect >= cxx11 && (CLASS_TYPE_P (type) || VECTOR_TYPE_P (type)) |
| && first_initializer_p |
| && d->end - d->cur == 1 |
| && reference_related_p (type, TREE_TYPE (init))) |
| { |
| d->cur++; |
| return init; |
| } |
| |
| /* [dcl.init.aggr] |
| |
| All implicit type conversions (clause _conv_) are considered when |
| initializing the aggregate member with an initializer from an |
| initializer-list. If the initializer can initialize a member, |
| the member is initialized. Otherwise, if the member is itself a |
| non-empty subaggregate, brace elision is assumed and the |
| initializer is considered for the initialization of the first |
| member of the subaggregate. */ |
| if (TREE_CODE (init) != CONSTRUCTOR |
| /* But don't try this for the first initializer, since that would be |
| looking through the outermost braces; A a2 = { a1 }; is not a |
| valid aggregate initialization. */ |
| && !first_initializer_p |
| && (same_type_ignoring_top_level_qualifiers_p (type, TREE_TYPE (init)) |
| || can_convert_arg (type, TREE_TYPE (init), init, LOOKUP_NORMAL, |
| complain))) |
| { |
| d->cur++; |
| return init; |
| } |
| |
| /* [dcl.init.string] |
| |
| A char array (whether plain char, signed char, or unsigned char) |
| can be initialized by a string-literal (optionally enclosed in |
| braces); a wchar_t array can be initialized by a wide |
| string-literal (optionally enclosed in braces). */ |
| if (TREE_CODE (type) == ARRAY_TYPE |
| && char_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (type)))) |
| { |
| tree str_init = init; |
| tree stripped_str_init = stripped_init; |
| |
| /* Strip one level of braces if and only if they enclose a single |
| element (as allowed by [dcl.init.string]). */ |
| if (!first_initializer_p |
| && TREE_CODE (stripped_str_init) == CONSTRUCTOR |
| && CONSTRUCTOR_NELTS (stripped_str_init) == 1) |
| { |
| str_init = (*CONSTRUCTOR_ELTS (stripped_str_init))[0].value; |
| stripped_str_init = tree_strip_any_location_wrapper (str_init); |
| } |
| |
| /* If it's a string literal, then it's the initializer for the array |
| as a whole. Otherwise, continue with normal initialization for |
| array types (one value per array element). */ |
| if (TREE_CODE (stripped_str_init) == STRING_CST) |
| { |
| if (has_designator_problem (d, complain)) |
| return error_mark_node; |
| d->cur++; |
| return str_init; |
| } |
| } |
| |
| /* The following cases are about aggregates. If we are not within a full |
| initializer already, and there is not a CONSTRUCTOR, it means that there |
| is a missing set of braces (that is, we are processing the case for |
| which reshape_init exists). */ |
| if (!first_initializer_p) |
| { |
| if (TREE_CODE (stripped_init) == CONSTRUCTOR) |
| { |
| tree init_type = TREE_TYPE (init); |
| if (init_type && TYPE_PTRMEMFUNC_P (init_type)) |
| /* There is no need to call reshape_init for pointer-to-member |
| function initializers, as they are always constructed correctly |
| by the front end. Here we have e.g. {.__pfn=0B, .__delta=0}, |
| which is missing outermost braces. We should warn below, and |
| one of the routines below will wrap it in additional { }. */; |
| /* For a nested compound literal, proceed to specialized routines, |
| to handle initialization of arrays and similar. */ |
| else if (COMPOUND_LITERAL_P (stripped_init)) |
| gcc_assert (!BRACE_ENCLOSED_INITIALIZER_P (stripped_init)); |
| /* A CONSTRUCTOR of the target's type is a previously |
| digested initializer. */ |
| else if (same_type_ignoring_top_level_qualifiers_p (type, init_type)) |
| { |
| ++d->cur; |
| gcc_assert (!BRACE_ENCLOSED_INITIALIZER_P (stripped_init)); |
| return init; |
| } |
| else |
| { |
| /* Something that hasn't been reshaped yet. */ |
| ++d->cur; |
| gcc_assert (BRACE_ENCLOSED_INITIALIZER_P (stripped_init)); |
| return reshape_init (type, init, complain); |
| } |
| } |
| |
| if (complain & tf_warning) |
| warning (OPT_Wmissing_braces, |
| "missing braces around initializer for %qT", |
| type); |
| } |
| |
| /* Dispatch to specialized routines. */ |
| if (CLASS_TYPE_P (type)) |
| return reshape_init_class (type, d, first_initializer_p, complain); |
| else if (TREE_CODE (type) == ARRAY_TYPE) |
| return reshape_init_array (type, d, complain); |
| else if (VECTOR_TYPE_P (type)) |
| return reshape_init_vector (type, d, complain); |
| else |
| gcc_unreachable(); |
| } |
| |
| /* Undo the brace-elision allowed by [dcl.init.aggr] in a |
| brace-enclosed aggregate initializer. |
| |
| INIT is the CONSTRUCTOR containing the list of initializers describing |
| a brace-enclosed initializer for an entity of the indicated aggregate TYPE. |
| It may not presently match the shape of the TYPE; for example: |
| |
| struct S { int a; int b; }; |
| struct S a[] = { 1, 2, 3, 4 }; |
| |
| Here INIT will hold a vector of four elements, rather than a |
| vector of two elements, each itself a vector of two elements. This |
| routine transforms INIT from the former form into the latter. The |
| revised CONSTRUCTOR node is returned. */ |
| |
| tree |
| reshape_init (tree type, tree init, tsubst_flags_t complain) |
| { |
| vec<constructor_elt, va_gc> *v; |
| reshape_iter d; |
| tree new_init; |
| |
| gcc_assert (BRACE_ENCLOSED_INITIALIZER_P (init)); |
| |
| v = CONSTRUCTOR_ELTS (init); |
| |
| /* An empty constructor does not need reshaping, and it is always a valid |
| initializer. */ |
| if (vec_safe_is_empty (v)) |
| return init; |
| |
| /* Handle [dcl.init.list] direct-list-initialization from |
| single element of enumeration with a fixed underlying type. */ |
| if (is_direct_enum_init (type, init)) |
| { |
| tree elt = CONSTRUCTOR_ELT (init, 0)->value; |
| type = cv_unqualified (type); |
| if (check_narrowing (ENUM_UNDERLYING_TYPE (type), elt, complain)) |
| { |
| warning_sentinel w (warn_useless_cast); |
| warning_sentinel w2 (warn_ignored_qualifiers); |
| return cp_build_c_cast (type, elt, tf_warning_or_error); |
| } |
| else |
| return error_mark_node; |
| } |
| |
| /* Recurse on this CONSTRUCTOR. */ |
| d.cur = &(*v)[0]; |
| d.end = d.cur + v->length (); |
| |
| new_init = reshape_init_r (type, &d, true, complain); |
| if (new_init == error_mark_node) |
| return error_mark_node; |
| |
| /* Make sure all the element of the constructor were used. Otherwise, |
| issue an error about exceeding initializers. */ |
| if (d.cur != d.end) |
| { |
| if (complain & tf_error) |
| error ("too many initializers for %qT", type); |
| return error_mark_node; |
| } |
| |
| if (CONSTRUCTOR_IS_DIRECT_INIT (init) |
| && BRACE_ENCLOSED_INITIALIZER_P (new_init)) |
| CONSTRUCTOR_IS_DIRECT_INIT (new_init) = true; |
| if (CONSTRUCTOR_IS_DESIGNATED_INIT (init) |
| && BRACE_ENCLOSED_INITIALIZER_P (new_init)) |
| CONSTRUCTOR_IS_DESIGNATED_INIT (new_init) = true; |
| |
| return new_init; |
| } |
| |
| /* Verify array initializer. Returns true if errors have been reported. */ |
| |
| bool |
| check_array_initializer (tree decl, tree type, tree init) |
| { |
| tree element_type = TREE_TYPE (type); |
| |
| /* Structured binding when initialized with an array type needs |
| to have complete type. */ |
| if (decl |
| && DECL_DECOMPOSITION_P (decl) |
| && !DECL_DECOMP_BASE (decl) |
| && !COMPLETE_TYPE_P (type)) |
| { |
| error_at (DECL_SOURCE_LOCATION (decl), |
| "structured binding has incomplete type %qT", type); |
| TREE_TYPE (decl) = error_mark_node; |
| return true; |
| } |
| |
| /* The array type itself need not be complete, because the |
| initializer may tell us how many elements are in the array. |
| But, the elements of the array must be complete. */ |
| if (!COMPLETE_TYPE_P (complete_type (element_type))) |
| { |
| if (decl) |
| error_at (DECL_SOURCE_LOCATION (decl), |
| "elements of array %q#D have incomplete type", decl); |
| else |
| error ("elements of array %q#T have incomplete type", type); |
| return true; |
| } |
| /* A compound literal can't have variable size. */ |
| if (init && !decl |
| && ((COMPLETE_TYPE_P (type) && !TREE_CONSTANT (TYPE_SIZE (type))) |
| || !TREE_CONSTANT (TYPE_SIZE (element_type)))) |
| { |
| error ("variable-sized compound literal"); |
| return true; |
| } |
| return false; |
| } |
| |
| /* Subroutine of check_initializer; args are passed down from that function. |
| Set stmts_are_full_exprs_p to 1 across a call to build_aggr_init. */ |
| |
| static tree |
| build_aggr_init_full_exprs (tree decl, tree init, int flags) |
| |
| { |
| gcc_assert (stmts_are_full_exprs_p ()); |
| return build_aggr_init (decl, init, flags, tf_warning_or_error); |
| } |
| |
| /* Verify INIT (the initializer for DECL), and record the |
| initialization in DECL_INITIAL, if appropriate. CLEANUP is as for |
| grok_reference_init. |
| |
| If the return value is non-NULL, it is an expression that must be |
| evaluated dynamically to initialize DECL. */ |
| |
| static tree |
| check_initializer (tree decl, tree init, int flags, vec<tree, va_gc> **cleanups) |
| { |
| tree type = TREE_TYPE (decl); |
| tree init_code = NULL; |
| tree core_type; |
| |
| /* Things that are going to be initialized need to have complete |
| type. */ |
| TREE_TYPE (decl) = type = complete_type (TREE_TYPE (decl)); |
| |
| if (DECL_HAS_VALUE_EXPR_P (decl)) |
| { |
| /* A variable with DECL_HAS_VALUE_EXPR_P set is just a placeholder, |
| it doesn't have storage to be initialized. */ |
| gcc_assert (init == NULL_TREE); |
| return NULL_TREE; |
| } |
| |
| if (type == error_mark_node) |
| /* We will have already complained. */ |
| return NULL_TREE; |
| |
| if (TREE_CODE (type) == ARRAY_TYPE) |
| { |
| if (check_array_initializer (decl, type, init)) |
| return NULL_TREE; |
| } |
| else if (!COMPLETE_TYPE_P (type)) |
| { |
| error_at (DECL_SOURCE_LOCATION (decl), |
| "%q#D has incomplete type", decl); |
| TREE_TYPE (decl) = error_mark_node; |
| return NULL_TREE; |
| } |
| else |
| /* There is no way to make a variable-sized class type in GNU C++. */ |
| gcc_assert (TREE_CONSTANT (TYPE_SIZE (type))); |
| |
| if (init && BRACE_ENCLOSED_INITIALIZER_P (init)) |
| { |
| int init_len = CONSTRUCTOR_NELTS (init); |
| if (SCALAR_TYPE_P (type)) |
| { |
| if (init_len == 0) |
| { |
| maybe_warn_cpp0x (CPP0X_INITIALIZER_LISTS); |
| init = build_zero_init (type, NULL_TREE, false); |
| } |
| else if (init_len != 1 && TREE_CODE (type) != COMPLEX_TYPE) |
| { |
| error_at (cp_expr_loc_or_loc (init, DECL_SOURCE_LOCATION (decl)), |
| "scalar object %qD requires one element in " |
| "initializer", decl); |
| TREE_TYPE (decl) = error_mark_node; |
| return NULL_TREE; |
| } |
| } |
| } |
| |
| if (TREE_CODE (decl) == CONST_DECL) |
| { |
| gcc_assert (!TYPE_REF_P (type)); |
| |
| DECL_INITIAL (decl) = init; |
| |
| gcc_assert (init != NULL_TREE); |
| init = NULL_TREE; |
| } |
| else if (!init && DECL_REALLY_EXTERN (decl)) |
| ; |
| else if (init || type_build_ctor_call (type) |
| || TYPE_REF_P (type)) |
| { |
| if (TYPE_REF_P (type)) |
| { |
| init = grok_reference_init (decl, type, init, flags); |
| flags |= LOOKUP_ALREADY_DIGESTED; |
| } |
| else if (!init) |
| check_for_uninitialized_const_var (decl, /*constexpr_context_p=*/false, |
| tf_warning_or_error); |
| /* Do not reshape constructors of vectors (they don't need to be |
| reshaped. */ |
| else if (BRACE_ENCLOSED_INITIALIZER_P (init)) |
| { |
| if (is_std_init_list (type)) |
| { |
| init = perform_implicit_conversion (type, init, |
| tf_warning_or_error); |
| flags |= LOOKUP_ALREADY_DIGESTED; |
| } |
| else if (TYPE_NON_AGGREGATE_CLASS (type)) |
| { |
| /* Don't reshape if the class has constructors. */ |
| if (cxx_dialect == cxx98) |
| error_at (cp_expr_loc_or_loc (init, DECL_SOURCE_LOCATION (decl)), |
| "in C++98 %qD must be initialized by " |
| "constructor, not by %<{...}%>", |
| decl); |
| } |
| else if (VECTOR_TYPE_P (type) && TYPE_VECTOR_OPAQUE (type)) |
| { |
| error ("opaque vector types cannot be initialized"); |
| init = error_mark_node; |
| } |
| else |
| { |
| init = reshape_init (type, init, tf_warning_or_error); |
| flags |= LOOKUP_NO_NARROWING; |
| } |
| } |
| else if (TREE_CODE (init) == TREE_LIST |
| && TREE_TYPE (init) != unknown_type_node |
| && !MAYBE_CLASS_TYPE_P (type)) |
| { |
| gcc_assert (TREE_CODE (decl) != RESULT_DECL); |
| |
| /* We get here with code like `int a (2);' */ |
| init = build_x_compound_expr_from_list (init, ELK_INIT, |
| tf_warning_or_error); |
| } |
| |
| /* If DECL has an array type without a specific bound, deduce the |
| array size from the initializer. */ |
| maybe_deduce_size_from_array_init (decl, init); |
| type = TREE_TYPE (decl); |
| if (type == error_mark_node) |
| return NULL_TREE; |
| |
| if (((type_build_ctor_call (type) || CLASS_TYPE_P (type)) |
| && !(flags & LOOKUP_ALREADY_DIGESTED) |
| && !(init && BRACE_ENCLOSED_INITIALIZER_P (init) |
| && CP_AGGREGATE_TYPE_P (type) |
| && (CLASS_TYPE_P (type) |
| || !TYPE_NEEDS_CONSTRUCTING (type) |
| || type_has_extended_temps (type)))) |
| || (DECL_DECOMPOSITION_P (decl) && TREE_CODE (type) == ARRAY_TYPE)) |
| { |
| init_code = build_aggr_init_full_exprs (decl, init, flags); |
| |
| /* A constructor call is a non-trivial initializer even if |
| it isn't explicitly written. */ |
| if (TREE_SIDE_EFFECTS (init_code)) |
| DECL_NONTRIVIALLY_INITIALIZED_P (decl) = true; |
| |
| /* If this is a constexpr initializer, expand_default_init will |
| have returned an INIT_EXPR rather than a CALL_EXPR. In that |
| case, pull the initializer back out and pass it down into |
| store_init_value. */ |
| while (TREE_CODE (init_code) == EXPR_STMT |
| || TREE_CODE (init_code) == CONVERT_EXPR) |
| init_code = TREE_OPERAND (init_code, 0); |
| if (TREE_CODE (init_code) == INIT_EXPR) |
| { |
| init = TREE_OPERAND (init_code, 1); |
| init_code = NULL_TREE; |
| /* Don't call digest_init; it's unnecessary and will complain |
| about aggregate initialization of non-aggregate classes. */ |
| flags |= LOOKUP_ALREADY_DIGESTED; |
| } |
| else if (DECL_DECLARED_CONSTEXPR_P (decl)) |
| { |
| /* Declared constexpr, but no suitable initializer; massage |
| init appropriately so we can pass it into store_init_value |
| for the error. */ |
| if (CLASS_TYPE_P (type) |
| && (!init || TREE_CODE (init) == TREE_LIST)) |
| { |
| init = build_functional_cast (type, init, tf_none); |
| if (TREE_CODE (init) == TARGET_EXPR) |
| TARGET_EXPR_DIRECT_INIT_P (init) = true; |
| } |
| init_code = NULL_TREE; |
| } |
| else |
| init = NULL_TREE; |
| } |
| |
| if (init && TREE_CODE (init) != TREE_VEC) |
| { |
| /* In aggregate initialization of a variable, each element |
| initialization is a full-expression because there is no |
| enclosing expression. */ |
| gcc_assert (stmts_are_full_exprs_p ()); |
| |
| init_code = store_init_value (decl, init, cleanups, flags); |
| |
| if (DECL_INITIAL (decl) |
| && TREE_CODE (DECL_INITIAL (decl)) == CONSTRUCTOR |
| && !vec_safe_is_empty (CONSTRUCTOR_ELTS (DECL_INITIAL (decl)))) |
| { |
| tree elt = CONSTRUCTOR_ELTS (DECL_INITIAL (decl))->last ().value; |
| if (TREE_CODE (TREE_TYPE (elt)) == ARRAY_TYPE |
| && TYPE_SIZE (TREE_TYPE (elt)) == NULL_TREE) |
| cp_complete_array_type (&TREE_TYPE (elt), elt, false); |
| } |
| |
| if (pedantic && TREE_CODE (type) == ARRAY_TYPE |
| && DECL_INITIAL (decl) |
| && TREE_CODE (DECL_INITIAL (decl)) == STRING_CST |
| && PAREN_STRING_LITERAL_P (DECL_INITIAL (decl))) |
| warning_at (cp_expr_loc_or_loc (DECL_INITIAL (decl), |
| DECL_SOURCE_LOCATION (decl)), |
| 0, "array %qD initialized by parenthesized " |
| "string literal %qE", |
| decl, DECL_INITIAL (decl)); |
| init = NULL; |
| } |
| } |
| else |
| { |
| if (CLASS_TYPE_P (core_type = strip_array_types (type)) |
| && (CLASSTYPE_READONLY_FIELDS_NEED_INIT (core_type) |
| || CLASSTYPE_REF_FIELDS_NEED_INIT (core_type))) |
| diagnose_uninitialized_cst_or_ref_member (core_type, /*using_new=*/false, |
| /*complain=*/true); |
| |
| check_for_uninitialized_const_var (decl, /*constexpr_context_p=*/false, |
| tf_warning_or_error); |
| } |
| |
| if (init && init != error_mark_node) |
| init_code = build2 (INIT_EXPR, type, decl, init); |
| |
| if (init_code) |
| { |
| /* We might have set these in cp_finish_decl. */ |
| DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = false; |
| TREE_CONSTANT (decl) = false; |
| } |
| |
| if (init_code |
| && DECL_IN_AGGR_P (decl) |
| && DECL_INITIALIZED_IN_CLASS_P (decl)) |
| { |
| static int explained = 0; |
| |
| if (cxx_dialect < cxx11) |
| error ("initializer invalid for static member with constructor"); |
| else if (cxx_dialect < cxx17) |
| error ("non-constant in-class initialization invalid for static " |
| "member %qD", decl); |
| else |
| error ("non-constant in-class initialization invalid for non-inline " |
| "static member %qD", decl); |
| if (!explained) |
| { |
| inform (input_location, |
| "(an out of class initialization is required)"); |
| explained = 1; |
| } |
| return NULL_TREE; |
| } |
| |
| return init_code; |
| } |
| |
| /* If DECL is not a local variable, give it RTL. */ |
| |
| static void |
| make_rtl_for_nonlocal_decl (tree decl, tree init, const char* asmspec) |
| { |
| int toplev = toplevel_bindings_p (); |
| int defer_p; |
| |
| /* Set the DECL_ASSEMBLER_NAME for the object. */ |
| if (asmspec) |
| { |
| /* The `register' keyword, when used together with an |
| asm-specification, indicates that the variable should be |
| placed in a particular register. */ |
| if (VAR_P (decl) && DECL_REGISTER (decl)) |
| { |
| set_user_assembler_name (decl, asmspec); |
| DECL_HARD_REGISTER (decl) = 1; |
| } |
| else |
| { |
| if (TREE_CODE (decl) == FUNCTION_DECL |
| && fndecl_built_in_p (decl, BUILT_IN_NORMAL)) |
| set_builtin_user_assembler_name (decl, asmspec); |
| set_user_assembler_name (decl, asmspec); |
| } |
| } |
| |
| /* Handle non-variables up front. */ |
| if (!VAR_P (decl)) |
| { |
| rest_of_decl_compilation (decl, toplev, at_eof); |
| return; |
| } |
| |
| /* If we see a class member here, it should be a static data |
| member. */ |
| if (DECL_LANG_SPECIFIC (decl) && DECL_IN_AGGR_P (decl)) |
| { |
| gcc_assert (TREE_STATIC (decl)); |
| /* An in-class declaration of a static data member should be |
| external; it is only a declaration, and not a definition. */ |
| if (init == NULL_TREE) |
| gcc_assert (DECL_EXTERNAL (decl) |
| || !TREE_PUBLIC (decl)); |
| } |
| |
| /* We don't create any RTL for local variables. */ |
| if (DECL_FUNCTION_SCOPE_P (decl) && !TREE_STATIC (decl)) |
| return; |
| |
| /* We defer emission of local statics until the corresponding |
| DECL_EXPR is expanded. But with constexpr its function might never |
| be expanded, so go ahead and tell cgraph about the variable now. */ |
| defer_p = ((DECL_FUNCTION_SCOPE_P (decl) |
| && !var_in_maybe_constexpr_fn (decl)) |
| || DECL_VIRTUAL_P (decl)); |
| |
| /* Defer template instantiations. */ |
| if (DECL_LANG_SPECIFIC (decl) |
| && DECL_IMPLICIT_INSTANTIATION (decl)) |
| defer_p = 1; |
| |
| /* If we're not deferring, go ahead and assemble the variable. */ |
| if (!defer_p) |
| rest_of_decl_compilation (decl, toplev, at_eof); |
| } |
| |
| /* walk_tree helper for wrap_temporary_cleanups, below. */ |
| |
| static tree |
| wrap_cleanups_r (tree *stmt_p, int *walk_subtrees, void *data) |
| { |
| /* Stop at types or full-expression boundaries. */ |
| if (TYPE_P (*stmt_p) |
| || TREE_CODE (*stmt_p) == CLEANUP_POINT_EXPR) |
| { |
| *walk_subtrees = 0; |
| return NULL_TREE; |
| } |
| |
| if (TREE_CODE (*stmt_p) == TARGET_EXPR) |
| { |
| tree guard = (tree)data; |
| tree tcleanup = TARGET_EXPR_CLEANUP (*stmt_p); |
| |
| tcleanup = build2 (TRY_CATCH_EXPR, void_type_node, tcleanup, guard); |
| /* Tell honor_protect_cleanup_actions to handle this as a separate |
| cleanup. */ |
| TRY_CATCH_IS_CLEANUP (tcleanup) = 1; |
| |
| TARGET_EXPR_CLEANUP (*stmt_p) = tcleanup; |
| } |
| |
| return NULL_TREE; |
| } |
| |
| /* We're initializing a local variable which has a cleanup GUARD. If there |
| are any temporaries used in the initializer INIT of this variable, we |
| need to wrap their cleanups with TRY_CATCH_EXPR (, GUARD) so that the |
| variable will be cleaned up properly if one of them throws. |
| |
| Unfortunately, there's no way to express this properly in terms of |
| nesting, as the regions for the temporaries overlap the region for the |
| variable itself; if there are two temporaries, the variable needs to be |
| the first thing destroyed if either of them throws. However, we only |
| want to run the variable's cleanup if it actually got constructed. So |
| we need to guard the temporary cleanups with the variable's cleanup if |
| they are run on the normal path, but not if they are run on the |
| exceptional path. We implement this by telling |
| honor_protect_cleanup_actions to strip the variable cleanup from the |
| exceptional path. */ |
| |
| static void |
| wrap_temporary_cleanups (tree init, tree guard) |
| { |
| cp_walk_tree_without_duplicates (&init, wrap_cleanups_r, (void *)guard); |
| } |
| |
| /* Generate code to initialize DECL (a local variable). */ |
| |
| static void |
| initialize_local_var (tree decl, tree init) |
| { |
| tree type = TREE_TYPE (decl); |
| tree cleanup; |
| int already_used; |
| |
| gcc_assert (VAR_P (decl) |
| || TREE_CODE (decl) == RESULT_DECL); |
| gcc_assert (!TREE_STATIC (decl)); |
| |
| if (DECL_SIZE (decl) == NULL_TREE) |
| { |
| /* If we used it already as memory, it must stay in memory. */ |
| DECL_INITIAL (decl) = NULL_TREE; |
| TREE_ADDRESSABLE (decl) = TREE_USED (decl); |
| return; |
| } |
| |
| if (type == error_mark_node) |
| return; |
| |
| /* Compute and store the initial value. */ |
| already_used = TREE_USED (decl) || TREE_USED (type); |
| if (TREE_USED (type)) |
| DECL_READ_P (decl) = 1; |
| |
| /* Generate a cleanup, if necessary. */ |
| cleanup = cxx_maybe_build_cleanup (decl, tf_warning_or_error); |
| |
| /* Perform the initialization. */ |
| if (init) |
| { |
| tree rinit = (TREE_CODE (init) == INIT_EXPR |
| ? TREE_OPERAND (init, 1) : NULL_TREE); |
| if (rinit && !TREE_SIDE_EFFECTS (rinit)) |
| { |
| /* Stick simple initializers in DECL_INITIAL so that |
| -Wno-init-self works (c++/34772). */ |
| gcc_assert (TREE_OPERAND (init, 0) == decl); |
| DECL_INITIAL (decl) = rinit; |
| |
| if (warn_init_self && TYPE_REF_P (type)) |
| { |
| STRIP_NOPS (rinit); |
| if (rinit == decl) |
| warning_at (DECL_SOURCE_LOCATION (decl), |
| OPT_Winit_self, |
| "reference %qD is initialized with itself", decl); |
| } |
| } |
| else |
| { |
| int saved_stmts_are_full_exprs_p; |
| |
| /* If we're only initializing a single object, guard the |
| destructors of any temporaries used in its initializer with |
| its destructor. This isn't right for arrays because each |
| element initialization is a full-expression. */ |
| if (cleanup && TREE_CODE (type) != ARRAY_TYPE) |
| wrap_temporary_cleanups (init, cleanup); |
| |
| gcc_assert (building_stmt_list_p ()); |
| saved_stmts_are_full_exprs_p = stmts_are_full_exprs_p (); |
| current_stmt_tree ()->stmts_are_full_exprs_p = 1; |
| finish_expr_stmt (init); |
| current_stmt_tree ()->stmts_are_full_exprs_p = |
| saved_stmts_are_full_exprs_p; |
| } |
| } |
| |
| /* Set this to 0 so we can tell whether an aggregate which was |
| initialized was ever used. Don't do this if it has a |
| destructor, so we don't complain about the 'resource |
| allocation is initialization' idiom. Now set |
| attribute((unused)) on types so decls of that type will be |
| marked used. (see TREE_USED, above.) */ |
| if (TYPE_NEEDS_CONSTRUCTING (type) |
| && ! already_used |
| && TYPE_HAS_TRIVIAL_DESTRUCTOR (type) |
| && DECL_NAME (decl)) |
| TREE_USED (decl) = 0; |
| else if (already_used) |
| TREE_USED (decl) = 1; |
| |
| if (cleanup) |
| finish_decl_cleanup (decl, cleanup); |
| } |
| |
| /* DECL is a VAR_DECL for a compiler-generated variable with static |
| storage duration (like a virtual table) whose initializer is a |
| compile-time constant. Initialize the variable and provide it to the |
| back end. */ |
| |
| void |
| initialize_artificial_var (tree decl, vec<constructor_elt, va_gc> *v) |
| { |
| tree init; |
| gcc_assert (DECL_ARTIFICIAL (decl)); |
| init = build_constructor (TREE_TYPE (decl), v); |
| gcc_assert (TREE_CODE (init) == CONSTRUCTOR); |
| DECL_INITIAL (decl) = init; |
| DECL_INITIALIZED_P (decl) = 1; |
| /* Mark the decl as constexpr so that we can access its content |
| at compile time. */ |
| DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = true; |
| DECL_DECLARED_CONSTEXPR_P (decl) = true; |
| determine_visibility (decl); |
| layout_var_decl (decl); |
| maybe_commonize_var (decl); |
| make_rtl_for_nonlocal_decl (decl, init, /*asmspec=*/NULL); |
| } |
| |
| /* INIT is the initializer for a variable, as represented by the |
| parser. Returns true iff INIT is value-dependent. */ |
| |
| static bool |
| value_dependent_init_p (tree init) |
| { |
| if (TREE_CODE (init) == TREE_LIST) |
| /* A parenthesized initializer, e.g.: int i (3, 2); ? */ |
| return any_value_dependent_elements_p (init); |
| else if (TREE_CODE (init) == CONSTRUCTOR) |
| /* A brace-enclosed initializer, e.g.: int i = { 3 }; ? */ |
| { |
| if (dependent_type_p (TREE_TYPE (init))) |
| return true; |
| |
| vec<constructor_elt, va_gc> *elts; |
| size_t nelts; |
| size_t i; |
| |
| elts = CONSTRUCTOR_ELTS (init); |
| nelts = vec_safe_length (elts); |
| for (i = 0; i < nelts; ++i) |
| if (value_dependent_init_p ((*elts)[i].value)) |
| return true; |
| } |
| else |
| /* It must be a simple expression, e.g., int i = 3; */ |
| return value_dependent_expression_p (init); |
| |
| return false; |
| } |
| |
| // Returns true if a DECL is VAR_DECL with the concept specifier. |
| static inline bool |
| is_concept_var (tree decl) |
| { |
| return (VAR_P (decl) |
| // Not all variables have DECL_LANG_SPECIFIC. |
| && DECL_LANG_SPECIFIC (decl) |
| && DECL_DECLARED_CONCEPT_P (decl)); |
| } |
| |
| /* A helper function to be called via walk_tree. If any label exists |
| under *TP, it is (going to be) forced. Set has_forced_label_in_static. */ |
| |
| static tree |
| notice_forced_label_r (tree *tp, int *walk_subtrees, void *) |
| { |
| if (TYPE_P (*tp)) |
| *walk_subtrees = 0; |
| if (TREE_CODE (*tp) == LABEL_DECL) |
| cfun->has_forced_label_in_static = 1; |
| return NULL_TREE; |
| } |
| |
| /* Finish processing of a declaration; |
| install its line number and initial value. |
| If the length of an array type is not known before, |
| it must be determined now, from the initial value, or it is an error. |
| |
| INIT is the initializer (if any) for DECL. If INIT_CONST_EXPR_P is |
| true, then INIT is an integral constant expression. |
| |
| FLAGS is LOOKUP_ONLYCONVERTING if the = init syntax was used, else 0 |
| if the (init) syntax was used. */ |
| |
| void |
| cp_finish_decl (tree decl, tree init, bool init_const_expr_p, |
| tree asmspec_tree, int flags) |
| { |
| tree type; |
| vec<tree, va_gc> *cleanups = NULL; |
| const char *asmspec = NULL; |
| int was_readonly = 0; |
| bool var_definition_p = false; |
| tree auto_node; |
| |
| if (decl == error_mark_node) |
| return; |
| else if (! decl) |
| { |
| if (init) |
| error ("assignment (not initialization) in declaration"); |
| return; |
| } |
| |
| gcc_assert (TREE_CODE (decl) != RESULT_DECL); |
| /* Parameters are handled by store_parm_decls, not cp_finish_decl. */ |
| gcc_assert (TREE_CODE (decl) != PARM_DECL); |
| |
| type = TREE_TYPE (decl); |
| if (type == error_mark_node) |
| return; |
| |
| /* Warn about register storage specifiers except when in GNU global |
| or local register variable extension. */ |
| if (VAR_P (decl) && DECL_REGISTER (decl) && asmspec_tree == NULL_TREE) |
| { |
| if (cxx_dialect >= cxx17) |
| pedwarn (DECL_SOURCE_LOCATION (decl), OPT_Wregister, |
| "ISO C++17 does not allow %<register%> storage " |
| "class specifier"); |
| else |
| warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wregister, |
| "%<register%> storage class specifier used"); |
| } |
| |
| /* If a name was specified, get the string. */ |
| if (at_namespace_scope_p ()) |
| asmspec_tree = maybe_apply_renaming_pragma (decl, asmspec_tree); |
| if (asmspec_tree && asmspec_tree != error_mark_node) |
| asmspec = TREE_STRING_POINTER (asmspec_tree); |
| |
| bool in_class_decl |
| = (current_class_type |
| && CP_DECL_CONTEXT (decl) == current_class_type |
| && TYPE_BEING_DEFINED (current_class_type) |
| && !CLASSTYPE_TEMPLATE_INSTANTIATION (current_class_type)); |
| |
| if (in_class_decl |
| && (DECL_INITIAL (decl) || init)) |
| DECL_INITIALIZED_IN_CLASS_P (decl) = 1; |
| |
| /* Do auto deduction unless decl is a function or an uninstantiated |
| template specialization. */ |
| if (TREE_CODE (decl) != FUNCTION_DECL |
| && !(init == NULL_TREE |
| && DECL_LANG_SPECIFIC (decl) |
| && DECL_TEMPLATE_INSTANTIATION (decl) |
| && !DECL_TEMPLATE_INSTANTIATED (decl)) |
| && (auto_node = type_uses_auto (type))) |
| { |
| tree d_init; |
| if (init == NULL_TREE) |
| gcc_assert (CLASS_PLACEHOLDER_TEMPLATE (auto_node)); |
| d_init = init; |
| if (d_init) |
| { |
| if (TREE_CODE (d_init) == TREE_LIST |
| && !CLASS_PLACEHOLDER_TEMPLATE (auto_node)) |
| d_init = build_x_compound_expr_from_list (d_init, ELK_INIT, |
| tf_warning_or_error); |
| d_init = resolve_nondeduced_context (d_init, tf_warning_or_error); |
| } |
| enum auto_deduction_context adc = adc_variable_type; |
| if (VAR_P (decl) && DECL_DECOMPOSITION_P (decl)) |
| adc = adc_decomp_type; |
| type = TREE_TYPE (decl) = do_auto_deduction (type, d_init, auto_node, |
| tf_warning_or_error, adc, |
| NULL_TREE, flags); |
| if (type == error_mark_node) |
| return; |
| if (TREE_CODE (type) == FUNCTION_TYPE) |
| { |
| error ("initializer for %<decltype(auto) %D%> has function type " |
| "(did you forget the %<()%> ?)", decl); |
| TREE_TYPE (decl) = error_mark_node; |
| return; |
| } |
| cp_apply_type_quals_to_decl (cp_type_quals (type), decl); |
| } |
| |
| if (ensure_literal_type_for_constexpr_object (decl) == error_mark_node) |
| { |
| DECL_DECLARED_CONSTEXPR_P (decl) = 0; |
| if (VAR_P (decl) && DECL_CLASS_SCOPE_P (decl)) |
| { |
| init = NULL_TREE; |
| DECL_EXTERNAL (decl) = 1; |
| } |
| } |
| |
| if (VAR_P (decl) |
| && DECL_CLASS_SCOPE_P (decl) |
| && DECL_INITIALIZED_IN_CLASS_P (decl)) |
| check_static_variable_definition (decl, type); |
| |
| if (init && TREE_CODE (decl) == FUNCTION_DECL) |
| { |
| tree clone; |
| if (init == ridpointers[(int)RID_DELETE]) |
| { |
| /* FIXME check this is 1st decl. */ |
| DECL_DELETED_FN (decl) = 1; |
| DECL_DECLARED_INLINE_P (decl) = 1; |
| DECL_INITIAL (decl) = error_mark_node; |
| FOR_EACH_CLONE (clone, decl) |
| { |
| DECL_DELETED_FN (clone) = 1; |
| DECL_DECLARED_INLINE_P (clone) = 1; |
| DECL_INITIAL (clone) = error_mark_node; |
| } |
| init = NULL_TREE; |
| } |
| else if (init == ridpointers[(int)RID_DEFAULT]) |
| { |
| if (defaultable_fn_check (decl)) |
| DECL_DEFAULTED_FN (decl) = 1; |
| else |
| DECL_INITIAL (decl) = NULL_TREE; |
| } |
| } |
| |
| if (init && VAR_P (decl)) |
| { |
| DECL_NONTRIVIALLY_INITIALIZED_P (decl) = 1; |
| /* If DECL is a reference, then we want to know whether init is a |
| reference constant; init_const_expr_p as passed tells us whether |
| it's an rvalue constant. */ |
| if (TYPE_REF_P (type)) |
| init_const_expr_p = potential_constant_expression (init); |
| if (init_const_expr_p) |
| { |
| /* Set these flags now for templates. We'll update the flags in |
| store_init_value for instantiations. */ |
| DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = 1; |
| if (decl_maybe_constant_var_p (decl) |
| /* FIXME setting TREE_CONSTANT on refs breaks the back end. */ |
| && !TYPE_REF_P (type)) |
| TREE_CONSTANT (decl) = 1; |
| } |
| } |
| |
| if (processing_template_decl) |
| { |
| bool type_dependent_p; |
| |
| /* Add this declaration to the statement-tree. */ |
| if (at_function_scope_p ()) |
| add_decl_expr (decl); |
| |
| type_dependent_p = dependent_type_p (type); |
| |
| if (check_for_bare_parameter_packs (init)) |
| { |
| init = NULL_TREE; |
| DECL_INITIAL (decl) = NULL_TREE; |
| } |
| |
| /* Generally, initializers in templates are expanded when the |
| template is instantiated. But, if DECL is a variable constant |
| then it can be used in future constant expressions, so its value |
| must be available. */ |
| |
| bool dep_init = false; |
| |
| if (!VAR_P (decl) || type_dependent_p) |
| /* We can't do anything if the decl has dependent type. */; |
| else if (!init && is_concept_var (decl)) |
| { |
| error ("variable concept has no initializer"); |
| init = boolean_true_node; |
| } |
| else if (init |
| && init_const_expr_p |
| && !TYPE_REF_P (type) |
| && decl_maybe_constant_var_p (decl) |
| && !(dep_init = value_dependent_init_p (init))) |
| { |
| /* This variable seems to be a non-dependent constant, so process |
| its initializer. If check_initializer returns non-null the |
| initialization wasn't constant after all. */ |
| tree init_code; |
| cleanups = make_tree_vector (); |
| init_code = check_initializer (decl, init, flags, &cleanups); |
| if (init_code == NULL_TREE) |
| init = NULL_TREE; |
| release_tree_vector (cleanups); |
| } |
| else |
| { |
| gcc_assert (!DECL_PRETTY_FUNCTION_P (decl)); |
| /* Deduce array size even if the initializer is dependent. */ |
| maybe_deduce_size_from_array_init (decl, init); |
| /* And complain about multiple initializers. */ |
| if (init && TREE_CODE (init) == TREE_LIST && TREE_CHAIN (init) |
| && !MAYBE_CLASS_TYPE_P (type)) |
| init = build_x_compound_expr_from_list (init, ELK_INIT, |
| tf_warning_or_error); |
| } |
| |
| if (init) |
| DECL_INITIAL (decl) = init; |
| |
| if (dep_init) |
| { |
| retrofit_lang_decl (decl); |
| SET_DECL_DEPENDENT_INIT_P (decl, true); |
| } |
| |
| if (VAR_P (decl) && DECL_REGISTER (decl) && asmspec) |
| { |
| set_user_assembler_name (decl, asmspec); |
| DECL_HARD_REGISTER (decl) = 1; |
| } |
| return; |
| } |
| |
| /* Just store non-static data member initializers for later. */ |
| if (init && TREE_CODE (decl) == FIELD_DECL) |
| DECL_INITIAL (decl) = init; |
| |
| /* Take care of TYPE_DECLs up front. */ |
| if (TREE_CODE (decl) == TYPE_DECL) |
| { |
| if (type != error_mark_node |
| && MAYBE_CLASS_TYPE_P (type) && DECL_NAME (decl)) |
| { |
| if (TREE_TYPE (DECL_NAME (decl)) && TREE_TYPE (decl) != type) |
| warning (0, "shadowing previous type declaration of %q#D", decl); |
| set_identifier_type_value (DECL_NAME (decl), decl); |
| } |
| |
| /* If we have installed this as the canonical typedef for this |
| type, and that type has not been defined yet, delay emitting |
| the debug information for it, as we will emit it later. */ |
| if (TYPE_MAIN_DECL (TREE_TYPE (decl)) == decl |
| && !COMPLETE_TYPE_P (TREE_TYPE (decl))) |
| TYPE_DECL_SUPPRESS_DEBUG (decl) = 1; |
| |
| rest_of_decl_compilation (decl, DECL_FILE_SCOPE_P (decl), |
| at_eof); |
| return; |
| } |
| |
| /* A reference will be modified here, as it is initialized. */ |
| if (! DECL_EXTERNAL (decl) |
| && TREE_READONLY (decl) |
| && TYPE_REF_P (type)) |
| { |
| was_readonly = 1; |
| TREE_READONLY (decl) = 0; |
| } |
| |
| if (VAR_P (decl)) |
| { |
| /* If this is a local variable that will need a mangled name, |
| register it now. We must do this before processing the |
| initializer for the variable, since the initialization might |
| require a guard variable, and since the mangled name of the |
| guard variable will depend on the mangled name of this |
| variable. */ |
| if (DECL_FUNCTION_SCOPE_P (decl) |
| && TREE_STATIC (decl) |
| && !DECL_ARTIFICIAL (decl)) |
| { |
| /* The variable holding an anonymous union will have had its |
| discriminator set in finish_anon_union, after which it's |
| NAME will have been cleared. */ |
| if (DECL_NAME (decl)) |
| determine_local_discriminator (decl); |
| /* Normally has_forced_label_in_static is set during GIMPLE |
| lowering, but [cd]tors are never actually compiled directly. |
| We need to set this early so we can deal with the label |
| address extension. */ |
| if ((DECL_CONSTRUCTOR_P (current_function_decl) |
| || DECL_DESTRUCTOR_P (current_function_decl)) |
| && init) |
| { |
| walk_tree (&init, notice_forced_label_r, NULL, NULL); |
| add_local_decl (cfun, decl); |
| } |
| /* And make sure it's in the symbol table for |
| c_parse_final_cleanups to find. */ |
| varpool_node::get_create (decl); |
| } |
| |
| /* Convert the initializer to the type of DECL, if we have not |
| already initialized DECL. */ |
| if (!DECL_INITIALIZED_P (decl) |
| /* If !DECL_EXTERNAL then DECL is being defined. In the |
| case of a static data member initialized inside the |
| class-specifier, there can be an initializer even if DECL |
| is *not* defined. */ |
| && (!DECL_EXTERNAL (decl) || init)) |
| { |
| cleanups = make_tree_vector (); |
| init = check_initializer (decl, init, flags, &cleanups); |
| |
| /* Handle: |
| |
| [dcl.init] |
| |
| The memory occupied by any object of static storage |
| duration is zero-initialized at program startup before |
| any other initialization takes place. |
| |
| We cannot create an appropriate initializer until after |
| the type of DECL is finalized. If DECL_INITIAL is set, |
| then the DECL is statically initialized, and any |
| necessary zero-initialization has already been performed. */ |
| if (TREE_STATIC (decl) && !DECL_INITIAL (decl)) |
| DECL_INITIAL (decl) = build_zero_init (TREE_TYPE (decl), |
| /*nelts=*/NULL_TREE, |
| /*static_storage_p=*/true); |
| /* Remember that the initialization for this variable has |
| taken place. */ |
| DECL_INITIALIZED_P (decl) = 1; |
| /* This declaration is the definition of this variable, |
| unless we are initializing a static data member within |
| the class specifier. */ |
| if (!DECL_EXTERNAL (decl)) |
| var_definition_p = true; |
| } |
| /* If the variable has an array type, lay out the type, even if |
| there is no initializer. It is valid to index through the |
| array, and we must get TYPE_ALIGN set correctly on the array |
| type. */ |
| else if (TREE_CODE (type) == ARRAY_TYPE) |
| layout_type (type); |
| |
| if (TREE_STATIC (decl) |
| && !at_function_scope_p () |
| && current_function_decl == NULL) |
| /* So decl is a global variable or a static member of a |
| non local class. Record the types it uses |
| so that we can decide later to emit debug info for them. */ |
| record_types_used_by_current_var_decl (decl); |
| } |
| |
| /* Add this declaration to the statement-tree. This needs to happen |
| after the call to check_initializer so that the DECL_EXPR for a |
| reference temp is added before the DECL_EXPR for the reference itself. */ |
| if (DECL_FUNCTION_SCOPE_P (decl)) |
| { |
| /* If we're building a variable sized type, and we might be |
| reachable other than via the top of the current binding |
| level, then create a new BIND_EXPR so that we deallocate |
| the object at the right time. */ |
| if (VAR_P (decl) |
| && DECL_SIZE (decl) |
| && !TREE_CONSTANT (DECL_SIZE (decl)) |
| && STATEMENT_LIST_HAS_LABEL (cur_stmt_list)) |
| { |
| tree bind; |
| bind = build3 (BIND_EXPR, void_type_node, NULL, NULL, NULL); |
| TREE_SIDE_EFFECTS (bind) = 1; |
| add_stmt (bind); |
| BIND_EXPR_BODY (bind) = push_stmt_list (); |
| } |
| add_decl_expr (decl); |
| } |
| |
| /* Let the middle end know about variables and functions -- but not |
| static data members in uninstantiated class templates. */ |
| if (VAR_OR_FUNCTION_DECL_P (decl)) |
| { |
| if (VAR_P (decl)) |
| { |
| layout_var_decl (decl); |
| maybe_commonize_var (decl); |
| /* A class-scope constexpr variable with an out-of-class declaration. |
| C++17 makes them implicitly inline, but still force it out. */ |
| if (DECL_INLINE_VAR_P (decl) |
| && !DECL_VAR_DECLARED_INLINE_P (decl) |
| && !DECL_TEMPLATE_INSTANTIATION (decl) |
| && !in_class_decl) |
| mark_needed (decl); |
| } |
| |
| /* This needs to happen after the linkage is set. */ |
| determine_visibility (decl); |
| |
| if (var_definition_p |
| /* With -fmerge-all-constants, gimplify_init_constructor |
| might add TREE_STATIC to the variable. */ |
| && (TREE_STATIC (decl) || flag_merge_constants >= 2)) |
| { |
| /* If a TREE_READONLY variable needs initialization |
| at runtime, it is no longer readonly and we need to |
| avoid MEM_READONLY_P being set on RTL created for it. */ |
| if (init) |
| { |
| if (TREE_READONLY (decl)) |
| TREE_READONLY (decl) = 0; |
| was_readonly = 0; |
| } |
| else if (was_readonly) |
| TREE_READONLY (decl) = 1; |
| |
| /* Likewise if it needs destruction. */ |
| if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type)) |
| TREE_READONLY (decl) = 0; |
| } |
| |
| make_rtl_for_nonlocal_decl (decl, init, asmspec); |
| |
| /* Check for abstractness of the type. Notice that there is no |
| need to strip array types here since the check for those types |
| is already done within create_array_type_for_decl. */ |
| abstract_virtuals_error (decl, type); |
| |
| if (TREE_TYPE (decl) == error_mark_node) |
| /* No initialization required. */ |
| ; |
| else if (TREE_CODE (decl) == FUNCTION_DECL) |
| { |
| if (init) |
| { |
| if (init == ridpointers[(int)RID_DEFAULT]) |
| { |
| /* An out-of-class default definition is defined at |
| the point where it is explicitly defaulted. */ |
| if (DECL_DELETED_FN (decl)) |
| maybe_explain_implicit_delete (decl); |
| else if (DECL_INITIAL (decl) == error_mark_node) |
| synthesize_method (decl); |
| } |
| else |
| error_at (cp_expr_loc_or_loc (init, |
| DECL_SOURCE_LOCATION (decl)), |
| "function %q#D is initialized like a variable", |
| decl); |
| } |
| /* else no initialization required. */ |
| } |
| else if (DECL_EXTERNAL (decl) |
| && ! (DECL_LANG_SPECIFIC (decl) |
| && DECL_NOT_REALLY_EXTERN (decl))) |
| { |
| /* check_initializer will have done any constant initialization. */ |
| } |
| /* A variable definition. */ |
| else if (DECL_FUNCTION_SCOPE_P (decl) && !TREE_STATIC (decl)) |
| /* Initialize the local variable. */ |
| initialize_local_var (decl, init); |
| |
| /* If a variable is defined, and then a subsequent |
| definition with external linkage is encountered, we will |
| get here twice for the same variable. We want to avoid |
| calling expand_static_init more than once. For variables |
| that are not static data members, we can call |
| expand_static_init only when we actually process the |
| initializer. It is not legal to redeclare a static data |
| member, so this issue does not arise in that case. */ |
| else if (var_definition_p && TREE_STATIC (decl)) |
| expand_static_init (decl, init); |
| } |
| |
| /* If a CLEANUP_STMT was created to destroy a temporary bound to a |
| reference, insert it in the statement-tree now. */ |
| if (cleanups) |
| { |
| unsigned i; tree t; |
| FOR_EACH_VEC_ELT (*cleanups, i, t) |
| push_cleanup (NULL_TREE, t, false); |
| release_tree_vector (cleanups); |
| } |
| |
| if (was_readonly) |
| TREE_READONLY (decl) = 1; |
| |
| if (flag_openmp |
| && VAR_P (decl) |
| && lookup_attribute ("omp declare target implicit", |
| DECL_ATTRIBUTES (decl))) |
| { |
| DECL_ATTRIBUTES (decl) |
| = remove_attribute ("omp declare target implicit", |
| DECL_ATTRIBUTES (decl)); |
| complete_type (TREE_TYPE (decl)); |
| if (!cp_omp_mappable_type (TREE_TYPE (decl))) |
| error ("%q+D in declare target directive does not have mappable type", |
| decl); |
| else if (!lookup_attribute ("omp declare target", |
| DECL_ATTRIBUTES (decl)) |
| && !lookup_attribute ("omp declare target link", |
| DECL_ATTRIBUTES (decl))) |
| DECL_ATTRIBUTES (decl) |
| = tree_cons (get_identifier ("omp declare target"), |
| NULL_TREE, DECL_ATTRIBUTES (decl)); |
| } |
| |
| invoke_plugin_callbacks (PLUGIN_FINISH_DECL, decl); |
| } |
| |
| /* For class TYPE return itself or some its bases that contain |
| any direct non-static data members. Return error_mark_node if an |
| error has been diagnosed. */ |
| |
| static tree |
| find_decomp_class_base (location_t loc, tree type, tree ret) |
| { |
| bool member_seen = false; |
| for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) |
| if (TREE_CODE (field) != FIELD_DECL |
| || DECL_ARTIFICIAL (field) |
| || DECL_UNNAMED_BIT_FIELD (field)) |
| continue; |
| else if (ret) |
| return type; |
| else if (ANON_AGGR_TYPE_P (TREE_TYPE (field))) |
| { |
| if (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE) |
| error_at (loc, "cannot decompose class type %qT because it has an " |
| "anonymous struct member", type); |
| else |
| error_at (loc, "cannot decompose class type %qT because it has an " |
| "anonymous union member", type); |
| inform (DECL_SOURCE_LOCATION (field), "declared here"); |
| return error_mark_node; |
| } |
| else if (!accessible_p (type, field, true)) |
| { |
| error_at (loc, "cannot decompose inaccessible member %qD of %qT", |
| field, type); |
| inform (DECL_SOURCE_LOCATION (field), |
| TREE_PRIVATE (field) |
| ? G_("declared private here") |
| : G_("declared protected here")); |
| return error_mark_node; |
| } |
| else |
| member_seen = true; |
| |
| tree base_binfo, binfo; |
| tree orig_ret = ret; |
| int i; |
| if (member_seen) |
| ret = type; |
| for (binfo = TYPE_BINFO (type), i = 0; |
| BINFO_BASE_ITERATE (binfo, i, base_binfo); i++) |
| { |
| tree t = find_decomp_class_base (loc, TREE_TYPE (base_binfo), ret); |
| if (t == error_mark_node) |
| return error_mark_node; |
| if (t != NULL_TREE && t != ret) |
| { |
| if (ret == type) |
| { |
| error_at (loc, "cannot decompose class type %qT: both it and " |
| "its base class %qT have non-static data members", |
| type, t); |
| return error_mark_node; |
| } |
| else if (orig_ret != NULL_TREE) |
| return t; |
| else if (ret != NULL_TREE) |
| { |
| error_at (loc, "cannot decompose class type %qT: its base " |
| "classes %qT and %qT have non-static data " |
| "members", type, ret, t); |
| return error_mark_node; |
| } |
| else |
| ret = t; |
| } |
| } |
| return ret; |
| } |
| |
| /* Return std::tuple_size<TYPE>::value. */ |
| |
| static tree |
| get_tuple_size (tree type) |
| { |
| tree args = make_tree_vec (1); |
| TREE_VEC_ELT (args, 0) = type; |
| tree inst = lookup_template_class (tuple_size_identifier, args, |
| /*in_decl*/NULL_TREE, |
| /*context*/std_node, |
| /*entering_scope*/false, tf_none); |
| inst = complete_type (inst); |
| if (inst == error_mark_node || !COMPLETE_TYPE_P (inst)) |
| return NULL_TREE; |
| tree val = lookup_qualified_name (inst, value_identifier, |
| /*type*/false, /*complain*/false); |
| if (TREE_CODE (val) == VAR_DECL || TREE_CODE (val) == CONST_DECL) |
| val = maybe_constant_value (val); |
| if (TREE_CODE (val) == INTEGER_CST) |
| return val; |
| else |
| return error_mark_node; |
| } |
| |
| /* Return std::tuple_element<I,TYPE>::type. */ |
| |
| static tree |
| get_tuple_element_type (tree type, unsigned i) |
| { |
| tree args = make_tree_vec (2); |
| TREE_VEC_ELT (args, 0) = build_int_cst (integer_type_node, i); |
| TREE_VEC_ELT (args, 1) = type; |
| tree inst = lookup_template_class (tuple_element_identifier, args, |
| /*in_decl*/NULL_TREE, |
| /*context*/std_node, |
| /*entering_scope*/false, |
| tf_warning_or_error); |
| return make_typename_type (inst, type_identifier, |
| none_type, tf_warning_or_error); |
| } |
| |
| /* Return e.get<i>() or get<i>(e). */ |
| |
| static tree |
| get_tuple_decomp_init (tree decl, unsigned i) |
| { |
| tree targs = make_tree_vec (1); |
| TREE_VEC_ELT (targs, 0) = build_int_cst (integer_type_node, i); |
| |
| tree etype = TREE_TYPE (decl); |
| tree e = convert_from_reference (decl); |
| |
| /* [The id-expression] e is an lvalue if the type of the entity e is an |
| lvalue reference and an xvalue otherwise. */ |
| if (!TYPE_REF_P (etype) |
| || TYPE_REF_IS_RVALUE (etype)) |
| e = move (e); |
| |
| tree fns = lookup_qualified_name (TREE_TYPE (e), get__identifier, |
| /*type*/false, /*complain*/false); |
| bool use_member_get = false; |
| |
| /* To use a member get, member lookup must find at least one |
| declaration that is a function template |
| whose first template parameter is a non-type parameter. */ |
| for (lkp_iterator iter (MAYBE_BASELINK_FUNCTIONS (fns)); iter; ++iter) |
| { |
| tree fn = *iter; |
| if (TREE_CODE (fn) == TEMPLATE_DECL) |
| { |
| tree tparms = DECL_TEMPLATE_PARMS (fn); |
| tree parm = TREE_VEC_ELT (INNERMOST_TEMPLATE_PARMS (tparms), 0); |
| if (TREE_CODE (TREE_VALUE (parm)) == PARM_DECL) |
| { |
| use_member_get = true; |
| break; |
| } |
| } |
| } |
| |
| if (use_member_get) |
| { |
| fns = lookup_template_function (fns, targs); |
| return build_new_method_call (e, fns, /*args*/NULL, |
| /*path*/NULL_TREE, LOOKUP_NORMAL, |
| /*fn_p*/NULL, tf_warning_or_error); |
| } |
| else |
| { |
| vec<tree,va_gc> *args = make_tree_vector_single (e); |
| fns = lookup_template_function (get__identifier, targs); |
| fns = perform_koenig_lookup (fns, args, tf_warning_or_error); |
| return finish_call_expr (fns, &args, /*novirt*/false, |
| /*koenig*/true, tf_warning_or_error); |
| } |
| } |
| |
| /* It's impossible to recover the decltype of a tuple decomposition variable |
| based on the actual type of the variable, so store it in a hash table. */ |
| |
| static GTY((cache)) tree_cache_map *decomp_type_table; |
| static void |
| store_decomp_type (tree v, tree t) |
| { |
| if (!decomp_type_table) |
| decomp_type_table = tree_cache_map::create_ggc (13); |
| decomp_type_table->put (v, t); |
| } |
| |
| tree |
| lookup_decomp_type (tree v) |
| { |
| return *decomp_type_table->get (v); |
| } |
| |
| /* Mangle a decomposition declaration if needed. Arguments like |
| in cp_finish_decomp. */ |
| |
| void |
| cp_maybe_mangle_decomp (tree decl, tree first, unsigned int count) |
| { |
| if (!processing_template_decl |
| && !error_operand_p (decl) |
| && DECL_NAMESPACE_SCOPE_P (decl)) |
| { |
| auto_vec<tree, 16> v; |
| v.safe_grow (count); |
| tree d = first; |
| for (unsigned int i = 0; i < count; i++, d = DECL_CHAIN (d)) |
| v[count - i - 1] = d; |
| SET_DECL_ASSEMBLER_NAME (decl, mangle_decomp (decl, v)); |
| maybe_apply_pragma_weak (decl); |
| } |
| } |
| |
| /* Finish a decomposition declaration. DECL is the underlying declaration |
| "e", FIRST is the head of a chain of decls for the individual identifiers |
| chained through DECL_CHAIN in reverse order and COUNT is the number of |
| those decls. */ |
| |
| void |
| cp_finish_decomp (tree decl, tree first, unsigned int count) |
| { |
| if (error_operand_p (decl)) |
| { |
| error_out: |
| while (count--) |
| { |
| TREE_TYPE (first) = error_mark_node; |
| if (DECL_HAS_VALUE_EXPR_P (first)) |
| { |
| SET_DECL_VALUE_EXPR (first, NULL_TREE); |
| DECL_HAS_VALUE_EXPR_P (first) = 0; |
| } |
| first = DECL_CHAIN (first); |
| } |
| if (DECL_P (decl) && DECL_NAMESPACE_SCOPE_P (decl)) |
| SET_DECL_ASSEMBLER_NAME (decl, get_identifier ("<decomp>")); |
| return; |
| } |
| |
| location_t loc = DECL_SOURCE_LOCATION (decl); |
| if (type_dependent_expression_p (decl) |
| /* This happens for range for when not in templates. |
| Still add the DECL_VALUE_EXPRs for later processing. */ |
| || (!processing_template_decl |
| && type_uses_auto (TREE_TYPE (decl)))) |
| { |
| for (unsigned int i = 0; i < count; i++) |
| { |
| if (!DECL_HAS_VALUE_EXPR_P (first)) |
| { |
| tree v = build_nt (ARRAY_REF, decl, |
| size_int (count - i - 1), |
| NULL_TREE, NULL_TREE); |
| SET_DECL_VALUE_EXPR (first, v); |
| DECL_HAS_VALUE_EXPR_P (first) = 1; |
| } |
| if (processing_template_decl) |
| fit_decomposition_lang_decl (first, decl); |
| first = DECL_CHAIN (first); |
| } |
| return; |
| } |
| |
| auto_vec<tree, 16> v; |
| v.safe_grow (count); |
| tree d = first; |
| for (unsigned int i = 0; i < count; i++, d = DECL_CHAIN (d)) |
| { |
| v[count - i - 1] = d; |
| fit_decomposition_lang_decl (d, decl); |
| } |
| |
| tree type = TREE_TYPE (decl); |
| tree dexp = decl; |
| |
| if (TYPE_REF_P (type)) |
| { |
| dexp = convert_from_reference (dexp); |
| type = complete_type (TREE_TYPE (type)); |
| if (type == error_mark_node) |
| goto error_out; |
| if (!COMPLETE_TYPE_P (type)) |
| { |
| error_at (loc, "structured binding refers to incomplete type %qT", |
| type); |
| goto error_out; |
| } |
| } |
| |
| tree eltype = NULL_TREE; |
| unsigned HOST_WIDE_INT eltscnt = 0; |
| if (TREE_CODE (type) == ARRAY_TYPE) |
| { |
| tree nelts; |
| nelts = array_type_nelts_top (type); |
| if (nelts == error_mark_node) |
| goto error_out; |
| if (!tree_fits_uhwi_p (nelts)) |
| { |
| error_at (loc, "cannot decompose variable length array %qT", type); |
| goto error_out; |
| } |
| eltscnt = tree_to_uhwi (nelts); |
| if (count != eltscnt) |
| { |
| cnt_mismatch: |
| if (count > eltscnt) |
| error_n (loc, count, |
| "%u name provided for structured binding", |
| "%u names provided for structured binding", count); |
| else |
| error_n (loc, count, |
| "only %u name provided for structured binding", |
| "only %u names provided for structured binding", count); |
| inform_n (loc, eltscnt, |
| "while %qT decomposes into %wu element", |
| "while %qT decomposes into %wu elements", |
| type, eltscnt); |
| goto error_out; |
| } |
| eltype = TREE_TYPE (type); |
| for (unsigned int i = 0; i < count; i++) |
| { |
| TREE_TYPE (v[i]) = eltype; |
| layout_decl (v[i], 0); |
| if (processing_template_decl) |
| continue; |
| tree t = unshare_expr (dexp); |
| t = build4_loc (DECL_SOURCE_LOCATION (v[i]), ARRAY_REF, |
| eltype, t, size_int (i), NULL_TREE, |
| NULL_TREE); |
| SET_DECL_VALUE_EXPR (v[i], t); |
| DECL_HAS_VALUE_EXPR_P (v[i]) = 1; |
| } |
| } |
| /* 2 GNU extensions. */ |
| else if (TREE_CODE (type) == COMPLEX_TYPE) |
| { |
| eltscnt = 2; |
| if (count != eltscnt) |
| goto cnt_mismatch; |
| eltype = cp_build_qualified_type (TREE_TYPE (type), TYPE_QUALS (type)); |
| for (unsigned int i = 0; i < count; i++) |
| { |
| TREE_TYPE (v[i]) = eltype; |
| layout_decl (v[i], 0); |
| if (processing_template_decl) |
| continue; |
| tree t = unshare_expr (dexp); |
| t = build1_loc (DECL_SOURCE_LOCATION (v[i]), |
| i ? IMAGPART_EXPR : REALPART_EXPR, eltype, |
| t); |
| SET_DECL_VALUE_EXPR (v[i], t); |
| DECL_HAS_VALUE_EXPR_P (v[i]) = 1; |
| } |
| } |
| else if (TREE_CODE (type) == VECTOR_TYPE) |
| { |
| if (!TYPE_VECTOR_SUBPARTS (type).is_constant (&eltscnt)) |
| { |
| error_at (loc, "cannot decompose variable length vector %qT", type); |
| goto error_out; |
| } |
| if (count != eltscnt) |
| goto cnt_mismatch; |
| eltype = cp_build_qualified_type (TREE_TYPE (type), TYPE_QUALS (type)); |
| for (unsigned int i = 0; i < count; i++) |
| { |
| TREE_TYPE (v[i]) = eltype; |
| layout_decl (v[i], 0); |
| if (processing_template_decl) |
| continue; |
| tree t = unshare_expr (dexp); |
| convert_vector_to_array_for_subscript (DECL_SOURCE_LOCATION (v[i]), |
| &t, size_int (i)); |
| t = build4_loc (DECL_SOURCE_LOCATION (v[i]), ARRAY_REF, |
| eltype, t, size_int (i), NULL_TREE, |
| NULL_TREE); |
| SET_DECL_VALUE_EXPR (v[i], t); |
| DECL_HAS_VALUE_EXPR_P (v[i]) = 1; |
| } |
| } |
| else if (tree tsize = get_tuple_size (type)) |
| { |
| if (tsize == error_mark_node) |
| { |
| error_at (loc, "%<std::tuple_size<%T>::value%> is not an integral " |
| "constant expression", type); |
| goto error_out; |
| } |
| if (!tree_fits_uhwi_p (tsize)) |
| { |
| error_n (loc, count, |
| "%u name provided for structured binding", |
| "%u names provided for structured binding", count); |
| inform (loc, "while %qT decomposes into %E elements", |
| type, tsize); |
| goto error_out; |
| } |
| eltscnt = tree_to_uhwi (tsize); |
| if (count != eltscnt) |
| goto cnt_mismatch; |
| int save_read = DECL_READ_P (decl); |
| for (unsigned i = 0; i < count; ++i) |
| { |
| location_t sloc = input_location; |
| location_t dloc = DECL_SOURCE_LOCATION (v[i]); |
| |
| input_location = dloc; |
| tree init = get_tuple_decomp_init (decl, i); |
| tree eltype = (init == error_mark_node ? error_mark_node |
| : get_tuple_element_type (type, i)); |
| input_location = sloc; |
| |
| if (VOID_TYPE_P (eltype)) |
| { |
| error ("%<std::tuple_element<%u, %T>::type%> is %<void%>", |
| i, type); |
| eltype = error_mark_node; |
| } |
| if (init == error_mark_node || eltype == error_mark_node) |
| { |
| inform (dloc, "in initialization of structured binding " |
| "variable %qD", v[i]); |
| goto error_out; |
| } |
| /* Save the decltype away before reference collapse. */ |
| store_decomp_type (v[i], eltype); |
| eltype = cp_build_reference_type (eltype, !lvalue_p (init)); |
| TREE_TYPE (v[i]) = eltype; |
| layout_decl (v[i], 0); |
| if (DECL_HAS_VALUE_EXPR_P (v[i])) |
| { |
| /* In this case the names are variables, not just proxies. */ |
| SET_DECL_VALUE_EXPR (v[i], NULL_TREE); |
| DECL_HAS_VALUE_EXPR_P (v[i]) = 0; |
| } |
| if (!processing_template_decl) |
| cp_finish_decl (v[i], init, /*constexpr*/false, |
| /*asm*/NULL_TREE, LOOKUP_NORMAL); |
| } |
| /* Ignore reads from the underlying decl performed during initialization |
| of the individual variables. If those will be read, we'll mark |
| the underlying decl as read at that point. */ |
| DECL_READ_P (decl) = save_read; |
| } |
| else if (TREE_CODE (type) == UNION_TYPE) |
| { |
| error_at (loc, "cannot decompose union type %qT", type); |
| goto error_out; |
| } |
| else if (!CLASS_TYPE_P (type)) |
| { |
| error_at (loc, "cannot decompose non-array non-class type %qT", type); |
| goto error_out; |
| } |
| else if (LAMBDA_TYPE_P (type)) |
| { |
| error_at (loc, "cannot decompose lambda closure type %qT", type); |
| goto error_out; |
| } |
| else if (processing_template_decl && complete_type (type) == error_mark_node) |
| goto error_out; |
| else if (processing_template_decl && !COMPLETE_TYPE_P (type)) |
| pedwarn (loc, 0, "structured binding refers to incomplete class type %qT", |
| type); |
| else |
| { |
| tree btype = find_decomp_class_base (loc, type, NULL_TREE); |
| if (btype == error_mark_node) |
| goto error_out; |
| else if (btype == NULL_TREE) |
| { |
| error_at (loc, "cannot decompose class type %qT without non-static " |
| "data members", type); |
| goto error_out; |
| } |
| for (tree field = TYPE_FIELDS (btype); field; field = TREE_CHAIN (field)) |
| if (TREE_CODE (field) != FIELD_DECL |
| || DECL_ARTIFICIAL (field) |
| || DECL_UNNAMED_BIT_FIELD (field)) |
| continue; |
| else |
| eltscnt++; |
| if (count != eltscnt) |
| goto cnt_mismatch; |
| tree t = dexp; |
| if (type != btype) |
| { |
| t = convert_to_base (t, btype, /*check_access*/true, |
| /*nonnull*/false, tf_warning_or_error); |
| type = btype; |
| } |
| unsigned int i = 0; |
| for (tree field = TYPE_FIELDS (btype); field; field = TREE_CHAIN (field)) |
| if (TREE_CODE (field) != FIELD_DECL |
| || DECL_ARTIFICIAL (field) |
| || DECL_UNNAMED_BIT_FIELD (field)) |
| continue; |
| else |
| { |
| tree tt = finish_non_static_data_member (field, unshare_expr (t), |
| NULL_TREE); |
| if (REFERENCE_REF_P (tt)) |
| tt = TREE_OPERAND (tt, 0); |
| TREE_TYPE (v[i]) = TREE_TYPE (tt); |
| layout_decl (v[i], 0); |
| if (!processing_template_decl) |
| { |
| SET_DECL_VALUE_EXPR (v[i], tt); |
| DECL_HAS_VALUE_EXPR_P (v[i]) = 1; |
| } |
| i++; |
| } |
| } |
| if (processing_template_decl) |
| { |
| for (unsigned int i = 0; i < count; i++) |
| if (!DECL_HAS_VALUE_EXPR_P (v[i])) |
| { |
| tree a = build_nt (ARRAY_REF, decl, size_int (i), |
| NULL_TREE, NULL_TREE); |
| SET_DECL_VALUE_EXPR (v[i], a); |
| DECL_HAS_VALUE_EXPR_P (v[i]) = 1; |
| } |
| } |
| } |
| |
| /* Returns a declaration for a VAR_DECL as if: |
| |
| extern "C" TYPE NAME; |
| |
| had been seen. Used to create compiler-generated global |
| variables. */ |
| |
| static tree |
| declare_global_var (tree name, tree type) |
| { |
| tree decl; |
| |
| push_to_top_level (); |
| decl = build_decl (input_location, VAR_DECL, name, type); |
| TREE_PUBLIC (decl) = 1; |
| DECL_EXTERNAL (decl) = 1; |
| DECL_ARTIFICIAL (decl) = 1; |
| DECL_CONTEXT (decl) = FROB_CONTEXT (global_namespace); |
| /* If the user has explicitly declared this variable (perhaps |
| because the code we are compiling is part of a low-level runtime |
| library), then it is possible that our declaration will be merged |
| with theirs by pushdecl. */ |
| decl = pushdecl (decl); |
| cp_finish_decl (decl, NULL_TREE, false, NULL_TREE, 0); |
| pop_from_top_level (); |
| |
| return decl; |
| } |
| |
| /* Returns the type for the argument to "__cxa_atexit" (or "atexit", |
| if "__cxa_atexit" is not being used) corresponding to the function |
| to be called when the program exits. */ |
| |
| static tree |
| get_atexit_fn_ptr_type (void) |
| { |
| tree fn_type; |
| |
| if (!atexit_fn_ptr_type_node) |
| { |
| tree arg_type; |
| if (flag_use_cxa_atexit |
| && !targetm.cxx.use_atexit_for_cxa_atexit ()) |
| /* The parameter to "__cxa_atexit" is "void (*)(void *)". */ |
| arg_type = ptr_type_node; |
| else |
| /* The parameter to "atexit" is "void (*)(void)". */ |
| arg_type = NULL_TREE; |
| |
| fn_type = build_function_type_list (void_type_node, |
| arg_type, NULL_TREE); |
| atexit_fn_ptr_type_node = build_pointer_type (fn_type); |
| } |
| |
| return atexit_fn_ptr_type_node; |
| } |
| |
| /* Returns a pointer to the `atexit' function. Note that if |
| FLAG_USE_CXA_ATEXIT is nonzero, then this will actually be the new |
| `__cxa_atexit' function specified in the IA64 C++ ABI. */ |
| |
| static tree |
| get_atexit_node (void) |
| { |
| tree atexit_fndecl; |
| tree fn_type; |
| tree fn_ptr_type; |
| const char *name; |
| bool use_aeabi_atexit; |
| |
| if (atexit_node) |
| return atexit_node; |
| |
| if (flag_use_cxa_atexit && !targetm.cxx.use_atexit_for_cxa_atexit ()) |
| { |
| /* The declaration for `__cxa_atexit' is: |
| |
| int __cxa_atexit (void (*)(void *), void *, void *) |
| |
| We build up the argument types and then the function type |
| itself. */ |
| tree argtype0, argtype1, argtype2; |
| |
| use_aeabi_atexit = targetm.cxx.use_aeabi_atexit (); |
| /* First, build the pointer-to-function type for the first |
| argument. */ |
| fn_ptr_type = get_atexit_fn_ptr_type (); |
| /* Then, build the rest of the argument types. */ |
| argtype2 = ptr_type_node; |
| if (use_aeabi_atexit) |
| { |
| argtype1 = fn_ptr_type; |
| argtype0 = ptr_type_node; |
| } |
| else |
| { |
| argtype1 = ptr_type_node; |
| argtype0 = fn_ptr_type; |
| } |
| /* And the final __cxa_atexit type. */ |
| fn_type = build_function_type_list (integer_type_node, |
| argtype0, argtype1, argtype2, |
| NULL_TREE); |
| if (use_aeabi_atexit) |
| name = "__aeabi_atexit"; |
| else |
| name = "__cxa_atexit"; |
| } |
| else |
| { |
| /* The declaration for `atexit' is: |
| |
| int atexit (void (*)()); |
| |
| We build up the argument types and then the function type |
| itself. */ |
| fn_ptr_type = get_atexit_fn_ptr_type (); |
| /* Build the final atexit type. */ |
| fn_type = build_function_type_list (integer_type_node, |
| fn_ptr_type, NULL_TREE); |
| name = "atexit"; |
| } |
| |
| /* Now, build the function declaration. */ |
| push_lang_context (lang_name_c); |
| atexit_fndecl = build_library_fn_ptr (name, fn_type, ECF_LEAF | ECF_NOTHROW); |
| mark_used (atexit_fndecl); |
| pop_lang_context (); |
| atexit_node = decay_conversion (atexit_fndecl, tf_warning_or_error); |
| |
| return atexit_node; |
| } |
| |
| /* Like get_atexit_node, but for thread-local cleanups. */ |
| |
| static tree |
| get_thread_atexit_node (void) |
| { |
| /* The declaration for `__cxa_thread_atexit' is: |
| |
| int __cxa_thread_atexit (void (*)(void *), void *, void *) */ |
| tree fn_type = build_function_type_list (integer_type_node, |
| get_atexit_fn_ptr_type (), |
| ptr_type_node, ptr_type_node, |
| NULL_TREE); |
| |
| /* Now, build the function declaration. */ |
| tree atexit_fndecl = build_library_fn_ptr ("__cxa_thread_atexit", fn_type, |
| ECF_LEAF | ECF_NOTHROW); |
| return decay_conversion (atexit_fndecl, tf_warning_or_error); |
| } |
| |
| /* Returns the __dso_handle VAR_DECL. */ |
| |
| static tree |
| get_dso_handle_node (void) |
| { |
| if (dso_handle_node) |
| return dso_handle_node; |
| |
| /* Declare the variable. */ |
| dso_handle_node = declare_global_var (get_identifier ("__dso_handle"), |
| ptr_type_node); |
| |
| #ifdef HAVE_GAS_HIDDEN |
| if (dso_handle_node != error_mark_node) |
| { |
| DECL_VISIBILITY (dso_handle_node) = VISIBILITY_HIDDEN; |
| DECL_VISIBILITY_SPECIFIED (dso_handle_node) = 1; |
| } |
| #endif |
| |
| return dso_handle_node; |
| } |
| |
| /* Begin a new function with internal linkage whose job will be simply |
| to destroy some particular variable. */ |
| |
| static GTY(()) int start_cleanup_cnt; |
| |
| static tree |
| start_cleanup_fn (void) |
| { |
| char name[32]; |
| tree fntype; |
| tree fndecl; |
| bool use_cxa_atexit = flag_use_cxa_atexit |
| && !targetm.cxx.use_atexit_for_cxa_atexit (); |
| |
| push_to_top_level (); |
| |
| /* No need to mangle this. */ |
| push_lang_context (lang_name_c); |
| |
| /* Build the name of the function. */ |
| sprintf (name, "__tcf_%d", start_cleanup_cnt++); |
| /* Build the function declaration. */ |
| fntype = TREE_TYPE (get_atexit_fn_ptr_type ()); |
| fndecl = build_lang_decl (FUNCTION_DECL, get_identifier (name), fntype); |
| /* It's a function with internal linkage, generated by the |
| compiler. */ |
| TREE_PUBLIC (fndecl) = 0; |
| DECL_ARTIFICIAL (fndecl) = 1; |
| /* Make the function `inline' so that it is only emitted if it is |
| actually needed. It is unlikely that it will be inlined, since |
| it is only called via a function pointer, but we avoid unnecessary |
| emissions this way. */ |
| DECL_DECLARED_INLINE_P (fndecl) = 1; |
| DECL_INTERFACE_KNOWN (fndecl) = 1; |
| /* Build the parameter. */ |
| if (use_cxa_atexit) |
| { |
| tree parmdecl = cp_build_parm_decl (fndecl, NULL_TREE, ptr_type_node); |
| TREE_USED (parmdecl) = 1; |
| DECL_READ_P (parmdecl) = 1; |
| DECL_ARGUMENTS (fndecl) = parmdecl; |
| } |
| |
| pushdecl (fndecl); |
| start_preparsed_function (fndecl, NULL_TREE, SF_PRE_PARSED); |
| |
| pop_lang_context (); |
| |
| return current_function_decl; |
| } |
| |
| /* Finish the cleanup function begun by start_cleanup_fn. */ |
| |
| static void |
| end_cleanup_fn (void) |
| { |
| expand_or_defer_fn (finish_function (/*inline_p=*/false)); |
| |
| pop_from_top_level (); |
| } |
| |
| /* Generate code to handle the destruction of DECL, an object with |
| static storage duration. */ |
| |
| tree |
| register_dtor_fn (tree decl) |
| { |
| tree cleanup; |
| tree addr; |
| tree compound_stmt; |
| tree fcall; |
| tree type; |
| bool ob_parm, dso_parm, use_dtor; |
| tree arg0, arg1, arg2; |
| tree atex_node; |
| |
| type = TREE_TYPE (decl); |
| if (TYPE_HAS_TRIVIAL_DESTRUCTOR (type)) |
| return void_node; |
| |
| /* If we're using "__cxa_atexit" (or "__cxa_thread_atexit" or |
| "__aeabi_atexit"), and DECL is a class object, we can just pass the |
| destructor to "__cxa_atexit"; we don't have to build a temporary |
| function to do the cleanup. */ |
| dso_parm = (flag_use_cxa_atexit |
| && !targetm.cxx.use_atexit_for_cxa_atexit ()); |
| ob_parm = (CP_DECL_THREAD_LOCAL_P (decl) || dso_parm); |
| use_dtor = ob_parm && CLASS_TYPE_P (type); |
| if (use_dtor) |
| { |
| cleanup = get_class_binding (type, complete_dtor_identifier); |
| |
| /* Make sure it is accessible. */ |
| perform_or_defer_access_check (TYPE_BINFO (type), cleanup, cleanup, |
| tf_warning_or_error); |
| } |
| else |
| { |
| /* Call build_cleanup before we enter the anonymous function so |
| that any access checks will be done relative to the current |
| scope, rather than the scope of the anonymous function. */ |
| build_cleanup (decl); |
| |
| /* Now start the function. */ |
| cleanup = start_cleanup_fn (); |
| |
| /* Now, recompute the cleanup. It may contain SAVE_EXPRs that refer |
| to the original function, rather than the anonymous one. That |
| will make the back end think that nested functions are in use, |
| which causes confusion. */ |
| push_deferring_access_checks (dk_no_check); |
| fcall = build_cleanup (decl); |
| pop_deferring_access_checks (); |
| |
| /* Create the body of the anonymous function. */ |
| compound_stmt = begin_compound_stmt (BCS_FN_BODY); |
| finish_expr_stmt (fcall); |
| finish_compound_stmt (compound_stmt); |
| end_cleanup_fn (); |
| } |
| |
| /* Call atexit with the cleanup function. */ |
| mark_used (cleanup); |
| cleanup = build_address (cleanup); |
| |
| if (CP_DECL_THREAD_LOCAL_P (decl)) |
| atex_node = get_thread_atexit_node (); |
| else |
| atex_node = get_atexit_node (); |
| |
| if (use_dtor) |
| { |
| /* We must convert CLEANUP to the type that "__cxa_atexit" |
| expects. */ |
| cleanup = build_nop (get_atexit_fn_ptr_type (), cleanup); |
| /* "__cxa_atexit" will pass the address of DECL to the |
| cleanup function. */ |
| mark_used (decl); |
| addr = build_address (decl); |
| /* The declared type of the parameter to "__cxa_atexit" is |
| "void *". For plain "T*", we could just let the |
| machinery in cp_build_function_call convert it -- but if the |
| type is "cv-qualified T *", then we need to convert it |
| before passing it in, to avoid spurious errors. */ |
| addr = build_nop (ptr_type_node, addr); |
| } |
| else |
| /* Since the cleanup functions we build ignore the address |
| they're given, there's no reason to pass the actual address |
| in, and, in general, it's cheaper to pass NULL than any |
| other value. */ |
| addr = null_pointer_node; |
| |
| if (dso_parm) |
| arg2 = cp_build_addr_expr (get_dso_handle_node (), |
| tf_warning_or_error); |
| else if (ob_parm) |
| /* Just pass NULL to the dso handle parm if we don't actually |
| have a DSO handle on this target. */ |
| arg2 = null_pointer_node; |
| else |
| arg2 = NULL_TREE; |
| |
| if (ob_parm) |
| { |
| if (!CP_DECL_THREAD_LOCAL_P (decl) |
| && targetm.cxx.use_aeabi_atexit ()) |
| { |
| arg1 = cleanup; |
| arg0 = addr; |
| } |
| else |
| { |
| arg1 = addr; |
| arg0 = cleanup; |
| } |
| } |
| else |
| { |
| arg0 = cleanup; |
| arg1 = NULL_TREE; |
| } |
| return cp_build_function_call_nary (atex_node, tf_warning_or_error, |
| arg0, arg1, arg2, NULL_TREE); |
| } |
| |
| /* DECL is a VAR_DECL with static storage duration. INIT, if present, |
| is its initializer. Generate code to handle the construction |
| and destruction of DECL. */ |
| |
| static void |
| expand_static_init (tree decl, tree init) |
| { |
| gcc_assert (VAR_P (decl)); |
| gcc_assert (TREE_STATIC (decl)); |
| |
| /* Some variables require no dynamic initialization. */ |
| if (TYPE_HAS_TRIVIAL_DESTRUCTOR (TREE_TYPE (decl))) |
| { |
| /* Make sure the destructor is callable. */ |
| cxx_maybe_build_cleanup (decl, tf_warning_or_error); |
| if (!init) |
| return; |
| } |
| |
| if (CP_DECL_THREAD_LOCAL_P (decl) && DECL_GNU_TLS_P (decl) |
| && !DECL_FUNCTION_SCOPE_P (decl)) |
| { |
| location_t dloc = DECL_SOURCE_LOCATION (decl); |
| if (init) |
| error_at (dloc, "non-local variable %qD declared %<__thread%> " |
| "needs dynamic initialization", decl); |
| else |
| error_at (dloc, "non-local variable %qD declared %<__thread%> " |
| "has a non-trivial destructor", decl); |
| static bool informed; |
| if (!informed) |
| { |
| inform (dloc, "C++11 %<thread_local%> allows dynamic " |
| "initialization and destruction"); |
| informed = true; |
| } |
| return; |
| } |
| |
| if (DECL_FUNCTION_SCOPE_P (decl)) |
| { |
| /* Emit code to perform this initialization but once. */ |
| tree if_stmt = NULL_TREE, inner_if_stmt = NULL_TREE; |
| tree then_clause = NULL_TREE, inner_then_clause = NULL_TREE; |
| tree guard, guard_addr; |
| tree flag, begin; |
| /* We don't need thread-safety code for thread-local vars. */ |
| bool thread_guard = (flag_threadsafe_statics |
| && !CP_DECL_THREAD_LOCAL_P (decl)); |
| |
| /* Emit code to perform this initialization but once. This code |
| looks like: |
| |
| static <type> guard; |
| if (!__atomic_load (guard.first_byte)) { |
| if (__cxa_guard_acquire (&guard)) { |
| bool flag = false; |
| try { |
| // Do initialization. |
| flag = true; __cxa_guard_release (&guard); |
| // Register variable for destruction at end of program. |
| } catch { |
| if (!flag) __cxa_guard_abort (&guard); |
| } |
| } |
| } |
| |
| Note that the `flag' variable is only set to 1 *after* the |
| initialization is complete. This ensures that an exception, |
| thrown during the construction, will cause the variable to |
| reinitialized when we pass through this code again, as per: |
| |
| [stmt.dcl] |
| |
| If the initialization exits by throwing an exception, the |
| initialization is not complete, so it will be tried again |
| the next time control enters the declaration. |
| |
| This process should be thread-safe, too; multiple threads |
| should not be able to initialize the variable more than |
| once. */ |
| |
| /* Create the guard variable. */ |
| guard = get_guard (decl); |
| |
| /* Begin the conditional initialization. */ |
| if_stmt = begin_if_stmt (); |
| |
| finish_if_stmt_cond (get_guard_cond (guard, thread_guard), if_stmt); |
| then_clause = begin_compound_stmt (BCS_NO_SCOPE); |
| |
| if (thread_guard) |
| { |
| tree vfntype = NULL_TREE; |
| tree acquire_name, release_name, abort_name; |
| tree acquire_fn, release_fn, abort_fn; |
| guard_addr = build_address (guard); |
| |
| acquire_name = get_identifier ("__cxa_guard_acquire"); |
| release_name = get_identifier ("__cxa_guard_release"); |
| abort_name = get_identifier ("__cxa_guard_abort"); |
| acquire_fn = get_global_binding (acquire_name); |
| release_fn = get_global_binding (release_name); |
| abort_fn = get_global_binding (abort_name); |
| if (!acquire_fn) |
| acquire_fn = push_library_fn |
| (acquire_name, build_function_type_list (integer_type_node, |
| TREE_TYPE (guard_addr), |
| NULL_TREE), |
| NULL_TREE, ECF_NOTHROW); |
| if (!release_fn || !abort_fn) |
| vfntype = build_function_type_list (void_type_node, |
| TREE_TYPE (guard_addr), |
| NULL_TREE); |
| if (!release_fn) |
| release_fn = push_library_fn (release_name, vfntype, NULL_TREE, |
| ECF_NOTHROW); |
| if (!abort_fn) |
| abort_fn = push_library_fn (abort_name, vfntype, NULL_TREE, |
| ECF_NOTHROW | ECF_LEAF); |
| |
| inner_if_stmt = begin_if_stmt (); |
| finish_if_stmt_cond (build_call_n (acquire_fn, 1, guard_addr), |
| inner_if_stmt); |
| |
| inner_then_clause = begin_compound_stmt (BCS_NO_SCOPE); |
| begin = get_target_expr (boolean_false_node); |
| flag = TARGET_EXPR_SLOT (begin); |
| |
| TARGET_EXPR_CLEANUP (begin) |
| = build3 (COND_EXPR, void_type_node, flag, |
| void_node, |
| build_call_n (abort_fn, 1, guard_addr)); |
| CLEANUP_EH_ONLY (begin) = 1; |
| |
| /* Do the initialization itself. */ |
| init = add_stmt_to_compound (begin, init); |
| init = add_stmt_to_compound (init, |
| build2 (MODIFY_EXPR, void_type_node, |
| flag, boolean_true_node)); |
| |
| /* Use atexit to register a function for destroying this static |
| variable. Do this before calling __cxa_guard_release. */ |
| init = add_stmt_to_compound (init, register_dtor_fn (decl)); |
| |
| init = add_stmt_to_compound (init, build_call_n (release_fn, 1, |
| guard_addr)); |
| } |
| else |
| { |
| init = add_stmt_to_compound (init, set_guard (guard)); |
| |
| /* Use atexit to register a function for destroying this static |
| variable. */ |
| init = add_stmt_to_compound (init, register_dtor_fn (decl)); |
| } |
| |
| finish_expr_stmt (init); |
| |
| if (thread_guard) |
| { |
| finish_compound_stmt (inner_then_clause); |
| finish_then_clause (inner_if_stmt); |
| finish_if_stmt (inner_if_stmt); |
| } |
| |
| finish_compound_stmt (then_clause); |
| finish_then_clause (if_stmt); |
| finish_if_stmt (if_stmt); |
| } |
| else if (CP_DECL_THREAD_LOCAL_P (decl)) |
| tls_aggregates = tree_cons (init, decl, tls_aggregates); |
| else |
| static_aggregates = tree_cons (init, decl, static_aggregates); |
| } |
| |
| |
| /* Make TYPE a complete type based on INITIAL_VALUE. |
| Return 0 if successful, 1 if INITIAL_VALUE can't be deciphered, |
| 2 if there was no information (in which case assume 0 if DO_DEFAULT), |
| 3 if the initializer list is empty (in pedantic mode). */ |
| |
| int |
| cp_complete_array_type (tree *ptype, tree initial_value, bool do_default) |
| { |
| int failure; |
| tree type, elt_type; |
| |
| /* Don't get confused by a CONSTRUCTOR for some other type. */ |
| if (initial_value && TREE_CODE (initial_value) == CONSTRUCTOR |
| && !BRACE_ENCLOSED_INITIALIZER_P (initial_value) |
| && TREE_CODE (TREE_TYPE (initial_value)) != ARRAY_TYPE) |
| return 1; |
| |
| if (initial_value) |
| { |
| unsigned HOST_WIDE_INT i; |
| tree value; |
| |
| /* An array of character type can be initialized from a |
| brace-enclosed string constant. |
| |
| FIXME: this code is duplicated from reshape_init. Probably |
| we should just call reshape_init here? */ |
| if (char_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (*ptype))) |
| && TREE_CODE (initial_value) == CONSTRUCTOR |
| && !vec_safe_is_empty (CONSTRUCTOR_ELTS (initial_value))) |
| { |
| vec<constructor_elt, va_gc> *v = CONSTRUCTOR_ELTS (initial_value); |
| tree value = (*v)[0].value; |
| STRIP_ANY_LOCATION_WRAPPER (value); |
| |
| if (TREE_CODE (value) == STRING_CST |
| && v->length () == 1) |
| initial_value = value; |
| } |
| |
| /* If any of the elements are parameter packs, we can't actually |
| complete this type now because the array size is dependent. */ |
| if (TREE_CODE (initial_value) == CONSTRUCTOR) |
| { |
| FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (initial_value), |
| i, value) |
| { |
| if (PACK_EXPANSION_P (value)) |
| return 0; |
| } |
| } |
| } |
| |
| failure = complete_array_type (ptype, initial_value, do_default); |
| |
| /* We can create the array before the element type is complete, which |
| means that we didn't have these two bits set in the original type |
| either. In completing the type, we are expected to propagate these |
| bits. See also complete_type which does the same thing for arrays |
| of fixed size. */ |
| type = *ptype; |
| if (type != error_mark_node && TYPE_DOMAIN (type)) |
| { |
| elt_type = TREE_TYPE (type); |
| TYPE_NEEDS_CONSTRUCTING (type) = TYPE_NEEDS_CONSTRUCTING (elt_type); |
| TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type) |
| = TYPE_HAS_NONTRIVIAL_DESTRUCTOR (elt_type); |
| } |
| |
| return failure; |
| } |
| |
| /* As above, but either give an error or reject zero-size arrays, depending |
| on COMPLAIN. */ |
| |
| int |
| cp_complete_array_type_or_error (tree *ptype, tree initial_value, |
| bool do_default, tsubst_flags_t complain) |
| { |
| int failure; |
| bool sfinae = !(complain & tf_error); |
| /* In SFINAE context we can't be lenient about zero-size arrays. */ |
| if (sfinae) |
| ++pedantic; |
| failure = cp_complete_array_type (ptype, initial_value, do_default); |
| if (sfinae) |
| --pedantic; |
| if (failure) |
| { |
| if (sfinae) |
| /* Not an error. */; |
| else if (failure == 1) |
| error ("initializer fails to determine size of %qT", *ptype); |
| else if (failure == 2) |
| { |
| if (do_default) |
| error ("array size missing in %qT", *ptype); |
| } |
| else if (failure == 3) |
| error ("zero-size array %qT", *ptype); |
| *ptype = error_mark_node; |
| } |
| return failure; |
| } |
| |
| /* Return zero if something is declared to be a member of type |
| CTYPE when in the context of CUR_TYPE. STRING is the error |
| message to print in that case. Otherwise, quietly return 1. */ |
| |
| static int |
| member_function_or_else (tree ctype, tree cur_type, enum overload_flags flags) |
| { |
| if (ctype && ctype != cur_type) |
| { |
| if (flags == DTOR_FLAG) |
| error ("destructor for alien class %qT cannot be a member", ctype); |
| else |
| error ("constructor for alien class %qT cannot be a member", ctype); |
| return 0; |
| } |
| return 1; |
| } |
| |
| /* Subroutine of `grokdeclarator'. */ |
| |
| /* Generate errors possibly applicable for a given set of specifiers. |
| This is for ARM $7.1.2. */ |
| |
| static void |
| bad_specifiers (tree object, |
| enum bad_spec_place type, |
| int virtualp, |
| int quals, |
| int inlinep, |
| int friendp, |
| int raises, |
| const location_t* locations) |
| { |
| switch (type) |
| { |
| case BSP_VAR: |
| if (virtualp) |
| error_at (locations[ds_virtual], |
| "%qD declared as a %<virtual%> variable", object); |
| if (quals) |
| error ("%<const%> and %<volatile%> function specifiers on " |
| "%qD invalid in variable declaration", object); |
| break; |
| case BSP_PARM: |
| if (virtualp) |
| error_at (locations[ds_virtual], |
| "%qD declared as a %<virtual%> parameter", object); |
| if (inlinep) |
| error_at (locations[ds_inline], |
| "%qD declared as an %<inline%> parameter", object); |
| if (quals) |
| error ("%<const%> and %<volatile%> function specifiers on " |
| "%qD invalid in parameter declaration", object); |
| break; |
| case BSP_TYPE: |
| if (virtualp) |
| error_at (locations[ds_virtual], |
| "%qD declared as a %<virtual%> type", object); |
| if (inlinep) |
| error_at (locations[ds_inline], |
| "%qD declared as an %<inline%> type", object); |
| if (quals) |
| error ("%<const%> and %<volatile%> function specifiers on " |
| "%qD invalid in type declaration", object); |
| break; |
| case BSP_FIELD: |
| if (virtualp) |
| error_at (locations[ds_virtual], |
| "%qD declared as a %<virtual%> field", object); |
| if (inlinep) |
| error_at (locations[ds_inline], |
| "%qD declared as an %<inline%> field", object); |
| if (quals) |
| error ("%<const%> and %<volatile%> function specifiers on " |
| "%qD invalid in field declaration", object); |
| break; |
| default: |
| gcc_unreachable(); |
| } |
| if (friendp) |
| error ("%q+D declared as a friend", object); |
| if (raises |
| && !flag_noexcept_type |
| && (TREE_CODE (object) == TYPE_DECL |
| || (!TYPE_PTRFN_P (TREE_TYPE (object)) |
| && !TYPE_REFFN_P (TREE_TYPE (object)) |
| && !TYPE_PTRMEMFUNC_P (TREE_TYPE (object))))) |
| error ("%q+D declared with an exception specification", object); |
| } |
| |
| /* DECL is a member function or static data member and is presently |
| being defined. Check that the definition is taking place in a |
| valid namespace. */ |
| |
| static void |
| check_class_member_definition_namespace (tree decl) |
| { |
| /* These checks only apply to member functions and static data |
| members. */ |
| gcc_assert (VAR_OR_FUNCTION_DECL_P (decl)); |
| /* We check for problems with specializations in pt.c in |
| check_specialization_namespace, where we can issue better |
| diagnostics. */ |
| if (processing_specialization) |
| return; |
| /* We check this in check_explicit_instantiation_namespace. */ |
| if (processing_explicit_instantiation) |
| return; |
| /* [class.mfct] |
| |
| A member function definition that appears outside of the |
| class definition shall appear in a namespace scope enclosing |
| the class definition. |
| |
| [class.static.data] |
| |
| The definition for a static data member shall appear in a |
| namespace scope enclosing the member's class definition. */ |
| if (!is_ancestor (current_namespace, DECL_CONTEXT (decl))) |
| permerror (input_location, "definition of %qD is not in namespace enclosing %qT", |
| decl, DECL_CONTEXT (decl)); |
| } |
| |
| /* Build a PARM_DECL for the "this" parameter of FN. TYPE is the |
| METHOD_TYPE for a non-static member function; QUALS are the |
| cv-qualifiers that apply to the function. */ |
| |
| tree |
| build_this_parm (tree fn, tree type, cp_cv_quals quals) |
| { |
| tree this_type; |
| tree qual_type; |
| tree parm; |
| cp_cv_quals this_quals; |
| |
| if (CLASS_TYPE_P (type)) |
| { |
| this_type |
| = cp_build_qualified_type (type, quals & ~TYPE_QUAL_RESTRICT); |
| this_type = build_pointer_type (this_type); |
| } |
| else |
| this_type = type_of_this_parm (type); |
| /* The `this' parameter is implicitly `const'; it cannot be |
| assigned to. */ |
| this_quals = (quals & TYPE_QUAL_RESTRICT) | TYPE_QUAL_CONST; |
| qual_type = cp_build_qualified_type (this_type, this_quals); |
| parm = build_artificial_parm (fn, this_identifier, qual_type); |
| cp_apply_type_quals_to_decl (this_quals, parm); |
| return parm; |
| } |
| |
| /* DECL is a static member function. Complain if it was declared |
| with function-cv-quals. */ |
| |
| static void |
| check_static_quals (tree decl, cp_cv_quals quals) |
| { |
| if (quals != TYPE_UNQUALIFIED) |
| error ("static member function %q#D declared with type qualifiers", |
| decl); |
| } |
| |
| // Check that FN takes no arguments and returns bool. |
| static void |
| check_concept_fn (tree fn) |
| { |
| // A constraint is nullary. |
| if (DECL_ARGUMENTS (fn)) |
| error_at (DECL_SOURCE_LOCATION (fn), |
| "concept %q#D declared with function parameters", fn); |
| |
| // The declared return type of the concept shall be bool, and |
| // it shall not be deduced from it definition. |
| tree type = TREE_TYPE (TREE_TYPE (fn)); |
| if (is_auto (type)) |
| error_at (DECL_SOURCE_LOCATION (fn), |
| "concept %q#D declared with a deduced return type", fn); |
| else if (type != boolean_type_node) |
| error_at (DECL_SOURCE_LOCATION (fn), |
| "concept %q#D with non-%<bool%> return type %qT", fn, type); |
| } |
| |
| /* Helper function. Replace the temporary this parameter injected |
| during cp_finish_omp_declare_simd with the real this parameter. */ |
| |
| static tree |
| declare_simd_adjust_this (tree *tp, int *walk_subtrees, void *data) |
| { |
| tree this_parm = (tree) data; |
| if (TREE_CODE (*tp) == PARM_DECL |
| && DECL_NAME (*tp) == this_identifier |
| && *tp != this_parm) |
| *tp = this_parm; |
| else if (TYPE_P (*tp)) |
| *walk_subtrees = 0; |
| return NULL_TREE; |
| } |
| |
| /* CTYPE is class type, or null if non-class. |
| TYPE is type this FUNCTION_DECL should have, either FUNCTION_TYPE |
| or METHOD_TYPE. |
| DECLARATOR is the function's name. |
| PARMS is a chain of PARM_DECLs for the function. |
| VIRTUALP is truthvalue of whether the function is virtual or not. |
| FLAGS are to be passed through to `grokclassfn'. |
| QUALS are qualifiers indicating whether the function is `const' |
| or `volatile'. |
| RAISES is a list of exceptions that this function can raise. |
| CHECK is 1 if we must find this method in CTYPE, 0 if we should |
| not look, and -1 if we should not call `grokclassfn' at all. |
| |
| SFK is the kind of special function (if any) for the new function. |
| |
| Returns `NULL_TREE' if something goes wrong, after issuing |
| applicable error messages. */ |
| |
| static tree |
| grokfndecl (tree ctype, |
| tree type, |
| tree declarator, |
| tree parms, |
| tree orig_declarator, |
| const cp_decl_specifier_seq *declspecs, |
| tree decl_reqs, |
| int virtualp, |
| enum overload_flags flags, |
| cp_cv_quals quals, |
| cp_ref_qualifier rqual, |
| tree raises, |
| int check, |
| int friendp, |
| int publicp, |
| int inlinep, |
| bool deletedp, |
| special_function_kind sfk, |
| bool funcdef_flag, |
| bool late_return_type_p, |
| int template_count, |
| tree in_namespace, |
| tree* attrlist, |
| location_t location) |
| { |
| tree decl; |
| int staticp = ctype && TREE_CODE (type) == FUNCTION_TYPE; |
| tree t; |
| |
| if (location == UNKNOWN_LOCATION) |
| location = input_location; |
| |
| // Was the concept specifier present? |
| bool concept_p = inlinep & 4; |
| |
| // Concept declarations must have a corresponding definition. |
| if (concept_p && !funcdef_flag) |
| { |
| error_at (location, "concept %qD has no definition", declarator); |
| return NULL_TREE; |
| } |
| |
| type = build_cp_fntype_variant (type, rqual, raises, late_return_type_p); |
| |
| decl = build_lang_decl_loc (location, FUNCTION_DECL, declarator, type); |
| |
| /* Set the constraints on the declaration. */ |
| if (flag_concepts) |
| { |
| tree tmpl_reqs = NULL_TREE; |
| if (processing_template_decl > template_class_depth (ctype)) |
| tmpl_reqs = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms); |
| |
| /* Adjust the required expression into a constraint. */ |
| if (decl_reqs) |
| decl_reqs = normalize_expression (decl_reqs); |
| |
| tree ci = build_constraints (tmpl_reqs, decl_reqs); |
| set_constraints (decl, ci); |
| } |
| |
| if (TREE_CODE (type) == METHOD_TYPE) |
| { |
| tree parm = build_this_parm (decl, type, quals); |
| DECL_CHAIN (parm) = parms; |
| parms = parm; |
| |
| /* Allocate space to hold the vptr bit if needed. */ |
| SET_DECL_ALIGN (decl, MINIMUM_METHOD_BOUNDARY); |
| } |
| |
| DECL_ARGUMENTS (decl) = parms; |
| for (t = parms; t; t = DECL_CHAIN (t)) |
| DECL_CONTEXT (t) = decl; |
| |
| /* Propagate volatile out from type to decl. */ |
| if (TYPE_VOLATILE (type)) |
| TREE_THIS_VOLATILE (decl) = 1; |
| |
| /* Setup decl according to sfk. */ |
| switch (sfk) |
| { |
| case sfk_constructor: |
| case sfk_copy_constructor: |
| case sfk_move_constructor: |
| DECL_CXX_CONSTRUCTOR_P (decl) = 1; |
| DECL_NAME (decl) = ctor_identifier; |
| break; |
| case sfk_destructor: |
| DECL_CXX_DESTRUCTOR_P (decl) = 1; |
| DECL_NAME (decl) = dtor_identifier; |
| break; |
| default: |
| break; |
| } |
| |
| if (friendp && TREE_CODE (orig_declarator) == TEMPLATE_ID_EXPR) |
| { |
| if (funcdef_flag) |
| error_at (location, |
| "defining explicit specialization %qD in friend declaration", |
| orig_declarator); |
| else |
| { |
| tree fns = TREE_OPERAND (orig_declarator, 0); |
| tree args = TREE_OPERAND (orig_declarator, 1); |
| |
| if (PROCESSING_REAL_TEMPLATE_DECL_P ()) |
| { |
| /* Something like `template <class T> friend void f<T>()'. */ |
| error_at (location, |
| "invalid use of template-id %qD in declaration " |
| "of primary template", |
| orig_declarator); |
| return NULL_TREE; |
| } |
| |
| |
| /* A friend declaration of the form friend void f<>(). Record |
| the information in the TEMPLATE_ID_EXPR. */ |
| SET_DECL_IMPLICIT_INSTANTIATION (decl); |
| |
| gcc_assert (identifier_p (fns) |
| || TREE_CODE (fns) == OVERLOAD |
| || TREE_CODE (fns) == FUNCTION_DECL); |
| DECL_TEMPLATE_INFO (decl) = build_template_info (fns, args); |
| |
| for (t = TYPE_ARG_TYPES (TREE_TYPE (decl)); t; t = TREE_CHAIN (t)) |
| if (TREE_PURPOSE (t) |
| && TREE_CODE (TREE_PURPOSE (t)) == DEFAULT_ARG) |
| { |
| error_at (defarg_location (TREE_PURPOSE (t)), |
| "default arguments are not allowed in declaration " |
| "of friend template specialization %qD", |
| decl); |
| return NULL_TREE; |
| } |
| |
| if (inlinep & 1) |
| { |
| error_at (declspecs->locations[ds_inline], |
| "%<inline%> is not allowed in declaration of friend " |
| "template specialization %qD", |
| decl); |
| return NULL_TREE; |
| } |
| } |
| } |
| |
| /* C++17 11.3.6/4: "If a friend declaration specifies a default argument |
| expression, that declaration shall be a definition..." */ |
| if (friendp && !funcdef_flag) |
| { |
| for (tree t = FUNCTION_FIRST_USER_PARMTYPE (decl); |
| t && t != void_list_node; t = TREE_CHAIN (t)) |
| if (TREE_PURPOSE (t)) |
| { |
| permerror (DECL_SOURCE_LOCATION (decl), |
| "friend declaration of %qD specifies default " |
| "arguments and isn%'t a definition", decl); |
| break; |
| } |
| } |
| |
| /* If this decl has namespace scope, set that up. */ |
| if (in_namespace) |
| set_decl_namespace (decl, in_namespace, friendp); |
| else if (!ctype) |
| DECL_CONTEXT (decl) = FROB_CONTEXT (current_decl_namespace ()); |
| |
| /* `main' and builtins have implicit 'C' linkage. */ |
| if (ctype == NULL_TREE |
| && DECL_FILE_SCOPE_P (decl) |
| && current_lang_name == lang_name_cplusplus |
| && (MAIN_NAME_P (declarator) |
| || (IDENTIFIER_LENGTH (declarator) > 10 |
| && IDENTIFIER_POINTER (declarator)[0] == '_' |
| && IDENTIFIER_POINTER (declarator)[1] == '_' |
| && strncmp (IDENTIFIER_POINTER (declarator)+2, |
| "builtin_", 8) == 0) |
| || (targetcm.cxx_implicit_extern_c |
| && (targetcm.cxx_implicit_extern_c |
| (IDENTIFIER_POINTER (declarator)))))) |
| SET_DECL_LANGUAGE (decl, lang_c); |
| |
| /* Should probably propagate const out from type to decl I bet (mrs). */ |
| if (staticp) |
| { |
| DECL_STATIC_FUNCTION_P (decl) = 1; |
| DECL_CONTEXT (decl) = ctype; |
| } |
| |
| if (deletedp) |
| DECL_DELETED_FN (decl) = 1; |
| |
| if (ctype) |
| { |
| DECL_CONTEXT (decl) = ctype; |
| if (funcdef_flag) |
| check_class_member_definition_namespace (decl); |
| } |
| |
| if (ctype == NULL_TREE && DECL_MAIN_P (decl)) |
| { |
| if (PROCESSING_REAL_TEMPLATE_DECL_P()) |
| error_at (location, "cannot declare %<::main%> to be a template"); |
| if (inlinep & 1) |
| error_at (declspecs->locations[ds_inline], |
| "cannot declare %<::main%> to be inline"); |
| if (inlinep & 2) |
| error_at (declspecs->locations[ds_constexpr], |
| "cannot declare %<::main%> to be %<constexpr%>"); |
| if (!publicp) |
| error_at (location, "cannot declare %<::main%> to be static"); |
| inlinep = 0; |
| publicp = 1; |
| } |
| |
| /* Members of anonymous types and local classes have no linkage; make |
| them internal. If a typedef is made later, this will be changed. */ |
| if (ctype && (!TREE_PUBLIC (TYPE_MAIN_DECL (ctype)) |
| || decl_function_context (TYPE_MAIN_DECL (ctype)))) |
| publicp = 0; |
| |
| if (publicp && cxx_dialect == cxx98) |
| { |
| /* [basic.link]: A name with no linkage (notably, the name of a class |
| or enumeration declared in a local scope) shall not be used to |
| declare an entity with linkage. |
| |
| DR 757 relaxes this restriction for C++0x. */ |
| no_linkage_error (decl); |
| } |
| |
| TREE_PUBLIC (decl) = publicp; |
| if (! publicp) |
| { |
| DECL_INTERFACE_KNOWN (decl) = 1; |
| DECL_NOT_REALLY_EXTERN (decl) = 1; |
| } |
| |
| /* If the declaration was declared inline, mark it as such. */ |
| if (inlinep) |
| { |
| DECL_DECLARED_INLINE_P (decl) = 1; |
| if (publicp) |
| DECL_COMDAT (decl) = 1; |
| } |
| if (inlinep & 2) |
| DECL_DECLARED_CONSTEXPR_P (decl) = true; |
| |
| // If the concept declaration specifier was found, check |
| // that the declaration satisfies the necessary requirements. |
| if (concept_p) |
| { |
| DECL_DECLARED_CONCEPT_P (decl) = true; |
| check_concept_fn (decl); |
| } |
| |
| DECL_EXTERNAL (decl) = 1; |
| if (TREE_CODE (type) == FUNCTION_TYPE) |
| { |
| if (quals || rqual) |
| TREE_TYPE (decl) = apply_memfn_quals (TREE_TYPE (decl), |
| TYPE_UNQUALIFIED, |
| REF_QUAL_NONE); |
| |
| if (quals) |
| { |
| error (ctype |
| ? G_("static member function %qD cannot have cv-qualifier") |
| : G_("non-member function %qD cannot have cv-qualifier"), |
| decl); |
| quals = TYPE_UNQUALIFIED; |
| } |
| |
| if (rqual) |
| { |
| error (ctype |
| ? G_("static member function %qD cannot have ref-qualifier") |
| : G_("non-member function %qD cannot have ref-qualifier"), |
| decl); |
| rqual = REF_QUAL_NONE; |
| } |
| } |
| |
| if (deduction_guide_p (decl)) |
| { |
| if (!DECL_NAMESPACE_SCOPE_P (decl)) |
| { |
| error_at (location, "deduction guide %qD must be declared at " |
| "namespace scope", decl); |
| return NULL_TREE; |
| } |
| if (funcdef_flag) |
| error_at (location, |
| "deduction guide %qD must not have a function body", decl); |
| } |
| else if (IDENTIFIER_ANY_OP_P (DECL_NAME (decl)) |
| && !grok_op_properties (decl, /*complain=*/true)) |
| return NULL_TREE; |
| else if (UDLIT_OPER_P (DECL_NAME (decl))) |
| { |
| bool long_long_unsigned_p; |
| bool long_double_p; |
| const char *suffix = NULL; |
| /* [over.literal]/6: Literal operators shall not have C linkage. */ |
| if (DECL_LANGUAGE (decl) == lang_c) |
| { |
| error_at (location, "literal operator with C linkage"); |
| maybe_show_extern_c_location (); |
| return NULL_TREE; |
| } |
| |
| if (DECL_NAMESPACE_SCOPE_P (decl)) |
| { |
| if (!check_literal_operator_args (decl, &long_long_unsigned_p, |
| &long_double_p)) |
| { |
| error_at (location, "%qD has invalid argument list", decl); |
| return NULL_TREE; |
| } |
| |
| suffix = UDLIT_OP_SUFFIX (DECL_NAME (decl)); |
| if (long_long_unsigned_p) |
| { |
| if (cpp_interpret_int_suffix (parse_in, suffix, strlen (suffix))) |
| warning_at (location, 0, "integer suffix %qs" |
| " shadowed by implementation", suffix); |
| } |
| else if (long_double_p) |
| { |
| if (cpp_interpret_float_suffix (parse_in, suffix, strlen (suffix))) |
| warning_at (location, 0, "floating point suffix %qs" |
| " shadowed by implementation", suffix); |
| } |
| /* 17.6.3.3.5 */ |
| if (suffix[0] != '_' |
| && !in_system_header_at (location) |
| && !current_function_decl && !(friendp && !funcdef_flag)) |
| warning_at (location, OPT_Wliteral_suffix, |
| "literal operator suffixes not preceded by %<_%>" |
| " are reserved for future standardization"); |
| } |
| else |
| { |
| error_at (location, "%qD must be a non-member function", decl); |
| return NULL_TREE; |
| } |
| } |
| |
| if (funcdef_flag) |
| /* Make the init_value nonzero so pushdecl knows this is not |
| tentative. error_mark_node is replaced later with the BLOCK. */ |
| DECL_INITIAL (decl) = error_mark_node; |
| |
| if (TYPE_NOTHROW_P (type) || nothrow_libfn_p (decl)) |
| TREE_NOTHROW (decl) = 1; |
| |
| if (flag_openmp || flag_openmp_simd) |
| { |
| /* Adjust "omp declare simd" attributes. */ |
| tree ods = lookup_attribute ("omp declare simd", *attrlist); |
| if (ods) |
| { |
| tree attr; |
| for (attr = ods; attr; |
| attr = lookup_attribute ("omp declare simd", TREE_CHAIN (attr))) |
| { |
| if (TREE_CODE (type) == METHOD_TYPE) |
| walk_tree (&TREE_VALUE (attr), declare_simd_adjust_this, |
| DECL_ARGUMENTS (decl), NULL); |
| if (TREE_VALUE (attr) != NULL_TREE) |
| { |
| tree cl = TREE_VALUE (TREE_VALUE (attr)); |
| cl = c_omp_declare_simd_clauses_to_numbers |
| (DECL_ARGUMENTS (decl), cl); |
| if (cl) |
| TREE_VALUE (TREE_VALUE (attr)) = cl; |
| else |
| TREE_VALUE (attr) = NULL_TREE; |
| } |
| } |
| } |
| } |
| |
| /* Caller will do the rest of this. */ |
| if (check < 0) |
| return decl; |
| |
| if (ctype != NULL_TREE) |
| grokclassfn (ctype, decl, flags); |
| |
| /* 12.4/3 */ |
| if (cxx_dialect >= cxx11 |
| && DECL_DESTRUCTOR_P (decl) |
| && !TYPE_BEING_DEFINED (DECL_CONTEXT (decl)) |
| && !processing_template_decl) |
| deduce_noexcept_on_destructor (decl); |
| |
| decl = check_explicit_specialization (orig_declarator, decl, |
| template_count, |
| 2 * funcdef_flag + |
| 4 * (friendp != 0) + |
| 8 * concept_p, |
| *attrlist); |
| if (decl == error_mark_node) |
| return NULL_TREE; |
| |
| if (DECL_STATIC_FUNCTION_P (decl)) |
| check_static_quals (decl, quals); |
| |
| if (attrlist) |
| { |
| cplus_decl_attributes (&decl, *attrlist, 0); |
| *attrlist = NULL_TREE; |
| } |
| |
| /* Check main's type after attributes have been applied. */ |
| if (ctype == NULL_TREE && DECL_MAIN_P (decl)) |
| { |
| if (!same_type_p (TREE_TYPE (TREE_TYPE (decl)), |
| integer_type_node)) |
| { |
| tree oldtypeargs = TYPE_ARG_TYPES (TREE_TYPE (decl)); |
| tree newtype; |
| error_at (declspecs->locations[ds_type_spec], |
| "%<::main%> must return %<int%>"); |
| newtype = build_function_type (integer_type_node, oldtypeargs); |
| TREE_TYPE (decl) = newtype; |
| } |
| if (warn_main) |
| check_main_parameter_types (decl); |
| } |
| |
| if (ctype != NULL_TREE && check) |
| { |
| tree old_decl = check_classfn (ctype, decl, |
| (processing_template_decl |
| > template_class_depth (ctype)) |
| ? current_template_parms |
| : NULL_TREE); |
| |
| if (old_decl == error_mark_node) |
| return NULL_TREE; |
| |
| if (old_decl) |
| { |
| tree ok; |
| tree pushed_scope; |
| |
| if (TREE_CODE (old_decl) == TEMPLATE_DECL) |
| /* Because grokfndecl is always supposed to return a |
| FUNCTION_DECL, we pull out the DECL_TEMPLATE_RESULT |
| here. We depend on our callers to figure out that its |
| really a template that's being returned. */ |
| old_decl = DECL_TEMPLATE_RESULT (old_decl); |
| |
| if (DECL_STATIC_FUNCTION_P (old_decl) |
| && TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE) |
| { |
| /* Remove the `this' parm added by grokclassfn. */ |
| revert_static_member_fn (decl); |
| check_static_quals (decl, quals); |
| } |
| if (DECL_ARTIFICIAL (old_decl)) |
| { |
| error ("definition of implicitly-declared %qD", old_decl); |
| return NULL_TREE; |
| } |
| else if (DECL_DEFAULTED_FN (old_decl)) |
| { |
| error ("definition of explicitly-defaulted %q+D", decl); |
| inform (DECL_SOURCE_LOCATION (old_decl), |
| "%q#D explicitly defaulted here", old_decl); |
| return NULL_TREE; |
| } |
| |
| /* Since we've smashed OLD_DECL to its |
| DECL_TEMPLATE_RESULT, we must do the same to DECL. */ |
| if (TREE_CODE (decl) == TEMPLATE_DECL) |
| decl = DECL_TEMPLATE_RESULT (decl); |
| |
| /* Attempt to merge the declarations. This can fail, in |
| the case of some invalid specialization declarations. */ |
| pushed_scope = push_scope (ctype); |
| ok = duplicate_decls (decl, old_decl, friendp); |
| if (pushed_scope) |
| pop_scope (pushed_scope); |
| if (!ok) |
| { |
| error ("no %q#D member function declared in class %qT", |
| decl, ctype); |
| return NULL_TREE; |
| } |
| if (ok == error_mark_node) |
| return NULL_TREE; |
| return old_decl; |
| } |
| } |
| |
| if (DECL_CONSTRUCTOR_P (decl) && !grok_ctor_properties (ctype, decl)) |
| return NULL_TREE; |
| |
| if (ctype == NULL_TREE || check) |
| return decl; |
| |
| if (virtualp) |
| DECL_VIRTUAL_P (decl) = 1; |
| |
| return decl; |
| } |
| |
| /* decl is a FUNCTION_DECL. |
| specifiers are the parsed virt-specifiers. |
| |
| Set flags to reflect the virt-specifiers. |
| |
| Returns decl. */ |
| |
| static tree |
| set_virt_specifiers (tree decl, cp_virt_specifiers specifiers) |
| { |
| if (decl == NULL_TREE) |
| return decl; |
| if (specifiers & VIRT_SPEC_OVERRIDE) |
| DECL_OVERRIDE_P (decl) = 1; |
| if (specifiers & VIRT_SPEC_FINAL) |
| DECL_FINAL_P (decl) = 1; |
| return decl; |
| } |
| |
| /* DECL is a VAR_DECL for a static data member. Set flags to reflect |
| the linkage that DECL will receive in the object file. */ |
| |
| static void |
| set_linkage_for_static_data_member (tree decl) |
| { |
| /* A static data member always has static storage duration and |
| external linkage. Note that static data members are forbidden in |
| local classes -- the only situation in which a class has |
| non-external linkage. */ |
| TREE_PUBLIC (decl) = 1; |
| TREE_STATIC (decl) = 1; |
| /* For non-template classes, static data members are always put |
| out in exactly those files where they are defined, just as |
| with ordinary namespace-scope variables. */ |
| if (!processing_template_decl) |
| DECL_INTERFACE_KNOWN (decl) = 1; |
| } |
| |
| /* Create a VAR_DECL named NAME with the indicated TYPE. |
| |
| If SCOPE is non-NULL, it is the class type or namespace containing |
| the variable. If SCOPE is NULL, the variable should is created in |
| the innermost enclosing scope. */ |
| |
| static tree |
| grokvardecl (tree type, |
| tree name, |
| tree orig_declarator, |
| const cp_decl_specifier_seq *declspecs, |
| int initialized, |
| int type_quals, |
| int inlinep, |
| bool conceptp, |
| int template_count, |
| tree scope, |
| location_t location) |
| { |
| tree decl; |
| tree explicit_scope; |
| |
| gcc_assert (!name || identifier_p (name)); |
| |
| bool constp = (type_quals & TYPE_QUAL_CONST) != 0; |
| bool volatilep = (type_quals & TYPE_QUAL_VOLATILE) != 0; |
| |
| /* Compute the scope in which to place the variable, but remember |
| whether or not that scope was explicitly specified by the user. */ |
| explicit_scope = scope; |
| if (!scope) |
| { |
| /* An explicit "extern" specifier indicates a namespace-scope |
| variable. */ |
| if (declspecs->storage_class == sc_extern) |
| scope = current_decl_namespace (); |
| else if (!at_function_scope_p ()) |
| scope = current_scope (); |
| } |
| |
| if (scope |
| && (/* If the variable is a namespace-scope variable declared in a |
| template, we need DECL_LANG_SPECIFIC. */ |
| (TREE_CODE (scope) == NAMESPACE_DECL && processing_template_decl) |
| /* Similarly for namespace-scope variables with language linkage |
| other than C++. */ |
| || (TREE_CODE (scope) == NAMESPACE_DECL |
| && current_lang_name != lang_name_cplusplus) |
| /* Similarly for static data members. */ |
| || TYPE_P (scope) |
| /* Similarly for explicit specializations. */ |
| || (orig_declarator |
| && TREE_CODE (orig_declarator) == TEMPLATE_ID_EXPR))) |
| decl = build_lang_decl_loc (location, VAR_DECL, name, type); |
| else |
| decl = build_decl (location, VAR_DECL, name, type); |
| |
| if (explicit_scope && TREE_CODE (explicit_scope) == NAMESPACE_DECL) |
| set_decl_namespace (decl, explicit_scope, 0); |
| else |
| DECL_CONTEXT (decl) = FROB_CONTEXT (scope); |
| |
| if (declspecs->storage_class == sc_extern) |
| { |
| DECL_THIS_EXTERN (decl) = 1; |
| DECL_EXTERNAL (decl) = !initialized; |
| } |
| |
| if (DECL_CLASS_SCOPE_P (decl)) |
| { |
| set_linkage_for_static_data_member (decl); |
| /* This function is only called with out-of-class definitions. */ |
| DECL_EXTERNAL (decl) = 0; |
| check_class_member_definition_namespace (decl); |
| } |
| /* At top level, either `static' or no s.c. makes a definition |
| (perhaps tentative), and absence of `static' makes it public. */ |
| else if (toplevel_bindings_p ()) |
| { |
| TREE_PUBLIC (decl) = (declspecs->storage_class != sc_static |
| && (DECL_THIS_EXTERN (decl) |
| || ! constp |
| || volatilep |
| || inlinep)); |
| TREE_STATIC (decl) = ! DECL_EXTERNAL (decl); |
| } |
| /* Not at top level, only `static' makes a static definition. */ |
| else |
| { |
| TREE_STATIC (decl) = declspecs->storage_class == sc_static; |
| TREE_PUBLIC (decl) = DECL_EXTERNAL (decl); |
| } |
| |
| if (decl_spec_seq_has_spec_p (declspecs, ds_thread)) |
| { |
| if (DECL_EXTERNAL (decl) || TREE_STATIC (decl)) |
| { |
| CP_DECL_THREAD_LOCAL_P (decl) = true; |
| if (!processing_template_decl) |
| set_decl_tls_model (decl, decl_default_tls_model (decl)); |
| } |
| if (declspecs->gnu_thread_keyword_p) |
| SET_DECL_GNU_TLS_P (decl); |
| } |
| |
| /* If the type of the decl has no linkage, make sure that we'll |
| notice that in mark_used. */ |
| if (cxx_dialect > cxx98 |
| && decl_linkage (decl) != lk_none |
| && DECL_LANG_SPECIFIC (decl) == NULL |
| && !DECL_EXTERN_C_P (decl) |
| && no_linkage_check (TREE_TYPE (decl), /*relaxed_p=*/false)) |
| retrofit_lang_decl (decl); |
| |
| if (TREE_PUBLIC (decl)) |
| { |
| /* [basic.link]: A name with no linkage (notably, the name of a class |
| or enumeration declared in a local scope) shall not be used to |
| declare an entity with linkage. |
| |
| DR 757 relaxes this restriction for C++0x. */ |
| if (cxx_dialect < cxx11) |
| no_linkage_error (decl); |
| } |
| else |
| DECL_INTERFACE_KNOWN (decl) = 1; |
| |
| if (DECL_NAME (decl) |
| && MAIN_NAME_P (DECL_NAME (decl)) |
| && scope == global_namespace) |
| error ("cannot declare %<::main%> to be a global variable"); |
| |
| /* Check that the variable can be safely declared as a concept. |
| Note that this also forbids explicit specializations. */ |
| if (conceptp) |
| { |
| if (!processing_template_decl) |
| { |
| error_at (declspecs->locations[ds_concept], |
| "a non-template variable cannot be %<concept%>"); |
| return NULL_TREE; |
| } |
| else |
| DECL_DECLARED_CONCEPT_P (decl) = true; |
| if (!same_type_ignoring_top_level_qualifiers_p (type, boolean_type_node)) |
| error_at (declspecs->locations[ds_type_spec], |
| "concept must have type %<bool%>"); |
| } |
| else if (flag_concepts |
| && processing_template_decl > template_class_depth (scope)) |
| { |
| tree reqs = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms); |
| tree ci = build_constraints (reqs, NULL_TREE); |
| set_constraints (decl, ci); |
| } |
| |
| // Handle explicit specializations and instantiations of variable templates. |
| if (orig_declarator) |
| decl = check_explicit_specialization (orig_declarator, decl, |
| template_count, conceptp * 8); |
| |
| return decl != error_mark_node ? decl : NULL_TREE; |
| } |
| |
| /* Create and return a canonical pointer to member function type, for |
| TYPE, which is a POINTER_TYPE to a METHOD_TYPE. */ |
| |
| tree |
| build_ptrmemfunc_type (tree type) |
| { |
| tree field, fields; |
| tree t; |
| |
| if (type == error_mark_node) |
| return type; |
| |
| /* Make sure that we always have the unqualified pointer-to-member |
| type first. */ |
| if (cp_cv_quals quals = cp_type_quals (type)) |
| { |
| tree unqual = build_ptrmemfunc_type (TYPE_MAIN_VARIANT (type)); |
| return cp_build_qualified_type (unqual, quals); |
| } |
| |
| /* If a canonical type already exists for this type, use it. We use |
| this method instead of type_hash_canon, because it only does a |
| simple equality check on the list of field members. */ |
| |
| t = TYPE_PTRMEMFUNC_TYPE (type); |
| if (t) |
| return t; |
| |
| t = make_node (RECORD_TYPE); |
| |
| /* Let the front end know this is a pointer to member function. */ |
| TYPE_PTRMEMFUNC_FLAG (t) = 1; |
| |
| field = build_decl (input_location, FIELD_DECL, pfn_identifier, type); |
| DECL_NONADDRESSABLE_P (field) = 1; |
| fields = field; |
| |
| field = build_decl (input_location, FIELD_DECL, delta_identifier, |
| delta_type_node); |
| DECL_NONADDRESSABLE_P (field) = 1; |
| DECL_CHAIN (field) = fields; |
| fields = field; |
| |
| finish_builtin_struct (t, "__ptrmemfunc_type", fields, ptr_type_node); |
| |
| /* Zap out the name so that the back end will give us the debugging |
| information for this anonymous RECORD_TYPE. */ |
| TYPE_NAME (t) = NULL_TREE; |
| |
| /* Cache this pointer-to-member type so that we can find it again |
| later. */ |
| TYPE_PTRMEMFUNC_TYPE (type) = t; |
| |
| if (TYPE_STRUCTURAL_EQUALITY_P (type)) |
| SET_TYPE_STRUCTURAL_EQUALITY (t); |
| else if (TYPE_CANONICAL (type) != type) |
| TYPE_CANONICAL (t) = build_ptrmemfunc_type (TYPE_CANONICAL (type)); |
| |
| return t; |
| } |
| |
| /* Create and return a pointer to data member type. */ |
| |
| tree |
| build_ptrmem_type (tree class_type, tree member_type) |
| { |
| if (TREE_CODE (member_type) == METHOD_TYPE) |
| { |
| cp_cv_quals quals = type_memfn_quals (member_type); |
| cp_ref_qualifier rqual = type_memfn_rqual (member_type); |
| member_type = build_memfn_type (member_type, class_type, quals, rqual); |
| return build_ptrmemfunc_type (build_pointer_type (member_type)); |
| } |
| else |
| { |
| gcc_assert (TREE_CODE (member_type) != FUNCTION_TYPE); |
| return build_offset_type (class_type, member_type); |
| } |
| } |
| |
| /* DECL is a VAR_DECL defined in-class, whose TYPE is also given. |
| Check to see that the definition is valid. Issue appropriate error |
| messages. */ |
| |
| static void |
| check_static_variable_definition (tree decl, tree type) |
| { |
| /* Avoid redundant diagnostics on out-of-class definitions. */ |
| if (!current_class_type || !TYPE_BEING_DEFINED (current_class_type)) |
| ; |
| /* Can't check yet if we don't know the type. */ |
| else if (dependent_type_p (type)) |
| ; |
| /* If DECL is declared constexpr, we'll do the appropriate checks |
| in check_initializer. Similarly for inline static data members. */ |
| else if (DECL_P (decl) |
| && (DECL_DECLARED_CONSTEXPR_P (decl) |
| || undeduced_auto_decl (decl) |
| || DECL_VAR_DECLARED_INLINE_P (decl))) |
| ; |
| else if (cxx_dialect >= cxx11 && !INTEGRAL_OR_ENUMERATION_TYPE_P (type)) |
| { |
| if (!COMPLETE_TYPE_P (type)) |
| error_at (DECL_SOURCE_LOCATION (decl), |
| "in-class initialization of static data member %q#D of " |
| "incomplete type", decl); |
| else if (literal_type_p (type)) |
| permerror (DECL_SOURCE_LOCATION (decl), |
| "%<constexpr%> needed for in-class initialization of " |
| "static data member %q#D of non-integral type", decl); |
| else |
| error_at (DECL_SOURCE_LOCATION (decl), |
| "in-class initialization of static data member %q#D of " |
| "non-literal type", decl); |
| } |
| /* Motion 10 at San Diego: If a static const integral data member is |
| initialized with an integral constant expression, the initializer |
| may appear either in the declaration (within the class), or in |
| the definition, but not both. If it appears in the class, the |
| member is a member constant. The file-scope definition is always |
| required. */ |
| else if (!ARITHMETIC_TYPE_P (type) && TREE_CODE (type) != ENUMERAL_TYPE) |
| error_at (DECL_SOURCE_LOCATION (decl), |
| "invalid in-class initialization of static data member " |
| "of non-integral type %qT", |
| type); |
| else if (!CP_TYPE_CONST_P (type)) |
| error_at (DECL_SOURCE_LOCATION (decl), |
| "ISO C++ forbids in-class initialization of non-const " |
| "static member %qD", |
| decl); |
| else if (!INTEGRAL_OR_ENUMERATION_TYPE_P (type)) |
| pedwarn (DECL_SOURCE_LOCATION (decl), OPT_Wpedantic, |
| "ISO C++ forbids initialization of member constant " |
| "%qD of non-integral type %qT", decl, type); |
| } |
| |
| /* *expr_p is part of the TYPE_SIZE of a variably-sized array. If any |
| SAVE_EXPRs in *expr_p wrap expressions with side-effects, break those |
| expressions out into temporary variables so that walk_tree doesn't |
| step into them (c++/15764). */ |
| |
| static tree |
| stabilize_save_expr_r (tree *expr_p, int *walk_subtrees, void *data) |
| { |
| hash_set<tree> *pset = (hash_set<tree> *)data; |
| tree expr = *expr_p; |
| if (TREE_CODE (expr) == SAVE_EXPR) |
| { |
| tree op = TREE_OPERAND (expr, 0); |
| cp_walk_tree (&op, stabilize_save_expr_r, data, pset); |
| if (TREE_SIDE_EFFECTS (op)) |
| TREE_OPERAND (expr, 0) = get_temp_regvar (TREE_TYPE (op), op); |
| *walk_subtrees = 0; |
| } |
| else if (!EXPR_P (expr) || !TREE_SIDE_EFFECTS (expr)) |
| *walk_subtrees = 0; |
| return NULL; |
| } |
| |
| /* Entry point for the above. */ |
| |
| static void |
| stabilize_vla_size (tree size) |
| { |
| hash_set<tree> pset; |
| /* Break out any function calls into temporary variables. */ |
| cp_walk_tree (&size, stabilize_save_expr_r, &pset, &pset); |
| } |
| |
| /* Reduce a SIZEOF_EXPR to its value. */ |
| |
| tree |
| fold_sizeof_expr (tree t) |
| { |
| tree r; |
| if (SIZEOF_EXPR_TYPE_P (t)) |
| r = cxx_sizeof_or_alignof_type (TREE_TYPE (TREE_OPERAND (t, 0)), |
| SIZEOF_EXPR, false, false); |
| else if (TYPE_P (TREE_OPERAND (t, 0))) |
| r = cxx_sizeof_or_alignof_type (TREE_OPERAND (t, 0), SIZEOF_EXPR, |
| false, false); |
| else |
| r = cxx_sizeof_or_alignof_expr (TREE_OPERAND (t, 0), SIZEOF_EXPR, |
| false); |
| if (r == error_mark_node) |
| r = size_one_node; |
| return r; |
| } |
| |
| /* Given the SIZE (i.e., number of elements) in an array, compute |
| an appropriate index type for the array. If non-NULL, NAME is |
| the name of the entity being declared. */ |
| |
| static tree |
| compute_array_index_type_loc (location_t name_loc, tree name, tree size, |
| tsubst_flags_t complain) |
| { |
| if (error_operand_p (size)) |
| return error_mark_node; |
| |
| /* The type of the index being computed. */ |
| tree itype; |
| |
| /* The original numeric size as seen in the source code before |
| conversion to size_t. */ |
| tree origsize = size; |
| |
| location_t loc = cp_expr_loc_or_loc (size, name ? name_loc : input_location); |
| |
| if (!type_dependent_expression_p (size)) |
| { |
| origsize = size = mark_rvalue_use (size); |
| |
| if (cxx_dialect < cxx11 && TREE_CODE (size) == NOP_EXPR |
| && TREE_SIDE_EFFECTS (size)) |
| /* In C++98, we mark a non-constant array bound with a magic |
| NOP_EXPR with TREE_SIDE_EFFECTS; don't fold in that case. */; |
| else |
| { |
| size = instantiate_non_dependent_expr_sfinae (size, complain); |
| size = build_converted_constant_expr (size_type_node, size, complain); |
| /* Pedantically a constant expression is required here and so |
| __builtin_is_constant_evaluated () should fold to true if it |
| is successfully folded into a constant. */ |
| size = maybe_constant_value (size, NULL_TREE, |
| /*manifestly_const_eval=*/true); |
| |
| if (!TREE_CONSTANT (size)) |
| size = origsize; |
| } |
| |
| if (error_operand_p (size)) |
| return error_mark_node; |
| |
| /* The array bound must be an integer type. */ |
| tree type = TREE_TYPE (size); |
| if (!INTEGRAL_OR_UNSCOPED_ENUMERATION_TYPE_P (type)) |
| { |
| if (!(complain & tf_error)) |
| return error_mark_node; |
| if (name) |
| error_at (loc, "size of array %qD has non-integral type %qT", |
| name, type); |
| else |
| error_at (loc, "size of array has non-integral type %qT", type); |
| size = integer_one_node; |
| } |
| } |
| |
| /* A type is dependent if it is...an array type constructed from any |
| dependent type or whose size is specified by a constant expression |
| that is value-dependent. */ |
| /* We can only call value_dependent_expression_p on integral constant |
| expressions; treat non-constant expressions as dependent, too. */ |
| if (processing_template_decl |
| && (type_dependent_expression_p (size) |
| || !TREE_CONSTANT (size) || value_dependent_expression_p (size))) |
| { |
| /* We cannot do any checking for a SIZE that isn't known to be |
| constant. Just build the index type and mark that it requires |
| structural equality checks. */ |
| itype = build_index_type (build_min (MINUS_EXPR, sizetype, |
| size, size_one_node)); |
| TYPE_DEPENDENT_P (itype) = 1; |
| TYPE_DEPENDENT_P_VALID (itype) = 1; |
| SET_TYPE_STRUCTURAL_EQUALITY (itype); |
| return itype; |
| } |
| |
| if (TREE_CODE (size) != INTEGER_CST) |
| { |
| tree folded = cp_fully_fold (size); |
| if (TREE_CODE (folded) == INTEGER_CST) |
| { |
| if (name) |
| pedwarn (loc, OPT_Wpedantic, "size of array %qD is not an " |
| "integral constant-expression", name); |
| else |
| pedwarn (loc, OPT_Wpedantic, |
| "size of array is not an integral constant-expression"); |
| } |
| /* Use the folded result for VLAs, too; it will have resolved |
| SIZEOF_EXPR. */ |
| size = folded; |
| } |
| |
| /* Normally, the array-bound will be a constant. */ |
| if (TREE_CODE (size) == INTEGER_CST) |
| { |
| /* The size to use in diagnostics that reflects the constant |
| size used in the source, rather than SIZE massaged above. */ |
| tree diagsize = size; |
| |
| /* If the original size before conversion to size_t was signed |
| and negative, convert it to ssizetype to restore the sign. */ |
| if (!TYPE_UNSIGNED (TREE_TYPE (origsize)) |
| && TREE_CODE (size) == INTEGER_CST |
| && tree_int_cst_sign_bit (size)) |
| { |
| diagsize = fold_convert (ssizetype, size); |
| |
| /* Clear the overflow bit that may have been set as a result |
| of the conversion from the sizetype of the new size to |
| ssizetype. */ |
| TREE_OVERFLOW (diagsize) = false; |
| } |
| |
| /* Verify that the array has a positive number of elements |
| and issue the appropriate diagnostic if it doesn't. */ |
| if (!valid_array_size_p (loc, diagsize, name, (complain & tf_error))) |
| { |
| if (!(complain & tf_error)) |
| return error_mark_node; |
| size = integer_one_node; |
| } |
| /* As an extension we allow zero-sized arrays. */ |
| else if (integer_zerop (size)) |
| { |
| if (!(complain & tf_error)) |
| /* We must fail if performing argument deduction (as |
| indicated by the state of complain), so that |
| another substitution can be found. */ |
| return error_mark_node; |
| else if (in_system_header_at (input_location)) |
| /* Allow them in system headers because glibc uses them. */; |
| else if (name) |
| pedwarn (loc, OPT_Wpedantic, |
| "ISO C++ forbids zero-size array %qD", name); |
| else |
| pedwarn (loc, OPT_Wpedantic, |
| "ISO C++ forbids zero-size array"); |
| } |
| } |
| else if (TREE_CONSTANT (size) |
| /* We don't allow VLAs at non-function scopes, or during |
| tentative template substitution. */ |
| || !at_function_scope_p () |
| || !(complain & tf_error)) |
| { |
| if (!(complain & tf_error)) |
| return error_mark_node; |
| /* `(int) &fn' is not a valid array bound. */ |
| if (name) |
| error_at (loc, |
| "size of array %qD is not an integral constant-expression", |
| name); |
| else |
| error_at (loc, "size of array is not an integral constant-expression"); |
| size = integer_one_node; |
| } |
| else if (pedantic && warn_vla != 0) |
| { |
| if (name) |
| pedwarn (name_loc, OPT_Wvla, |
| "ISO C++ forbids variable length array %qD", name); |
| else |
| pedwarn (input_location, OPT_Wvla, |
| "ISO C++ forbids variable length array"); |
| } |
| else if (warn_vla > 0) |
| { |
| if (name) |
| warning_at (name_loc, OPT_Wvla, |
| "variable length array %qD is used", name); |
| else |
| warning (OPT_Wvla, |
| "variable length array is used"); |
| } |
| |
| if (processing_template_decl && !TREE_CONSTANT (size)) |
| /* A variable sized array. */ |
| itype = build_min (MINUS_EXPR, sizetype, size, integer_one_node); |
| else |
| { |
| /* Compute the index of the largest element in the array. It is |
| one less than the number of elements in the array. We save |
| and restore PROCESSING_TEMPLATE_DECL so that computations in |
| cp_build_binary_op will be appropriately folded. */ |
| { |
| processing_template_decl_sentinel s; |
| itype = cp_build_binary_op (input_location, |
| MINUS_EXPR, |
| cp_convert (ssizetype, size, complain), |
| cp_convert (ssizetype, integer_one_node, |
| complain), |
| complain); |
| itype = maybe_constant_value (itype); |
| } |
| |
| if (!TREE_CONSTANT (itype)) |
| { |
| /* A variable sized array. */ |
| itype = variable_size (itype); |
| |
| stabilize_vla_size (itype); |
| |
| if (sanitize_flags_p (SANITIZE_VLA) |
| && current_function_decl != NULL_TREE) |
| { |
| /* We have to add 1 -- in the ubsan routine we generate |
| LE_EXPR rather than LT_EXPR. */ |
| tree t = fold_build2 (PLUS_EXPR, TREE_TYPE (itype), itype, |
| build_one_cst (TREE_TYPE (itype))); |
| t = ubsan_instrument_vla (input_location, t); |
| finish_expr_stmt (t); |
| } |
| } |
| /* Make sure that there was no overflow when creating to a signed |
| index type. (For example, on a 32-bit machine, an array with |
| size 2^32 - 1 is too big.) */ |
| else if (TREE_CODE (itype) == INTEGER_CST |
| && TREE_OVERFLOW (itype)) |
| { |
| if (!(complain & tf_error)) |
| return error_mark_node; |
| error ("overflow in array dimension"); |
| TREE_OVERFLOW (itype) = 0; |
| } |
| } |
| |
| /* Create and return the appropriate index type. */ |
| itype = build_index_type (itype); |
| |
| /* If the index type were dependent, we would have returned early, so |
| remember that it isn't. */ |
| TYPE_DEPENDENT_P (itype) = 0; |
| TYPE_DEPENDENT_P_VALID (itype) = 1; |
| return itype; |
| } |
| |
| tree |
| compute_array_index_type (tree name, tree size, tsubst_flags_t complain) |
| { |
| return compute_array_index_type_loc (input_location, name, size, complain); |
| } |
| |
| /* Returns the scope (if any) in which the entity declared by |
| DECLARATOR will be located. If the entity was declared with an |
| unqualified name, NULL_TREE is returned. */ |
| |
| tree |
| get_scope_of_declarator (const cp_declarator *declarator) |
| { |
| while (declarator && declarator->kind != cdk_id) |
| declarator = declarator->declarator; |
| |
| /* If the declarator-id is a SCOPE_REF, the scope in which the |
| declaration occurs is the first operand. */ |
| if (declarator |
| && declarator->u.id.qualifying_scope) |
| return declarator->u.id.qualifying_scope; |
| |
| /* Otherwise, the declarator is not a qualified name; the entity will |
| be declared in the current scope. */ |
| return NULL_TREE; |
| } |
| |
| /* Returns an ARRAY_TYPE for an array with SIZE elements of the |
| indicated TYPE. If non-NULL, NAME is the NAME of the declaration |
| with this type. */ |
| |
| static tree |
| create_array_type_for_decl (tree name, tree type, tree size, location_t loc) |
| { |
| tree itype = NULL_TREE; |
| |
| /* If things have already gone awry, bail now. */ |
| if (type == error_mark_node || size == error_mark_node) |
| return error_mark_node; |
| |
| /* 8.3.4/1: If the type of the identifier of D contains the auto |
| type-specifier, the program is ill-formed. */ |
| if (type_uses_auto (type)) |
| { |
| if (name) |
| error_at (loc, "%qD declared as array of %qT", name, type); |
| else |
| error ("creating array of %qT", type); |
| return error_mark_node; |
| } |
| |
| /* If there are some types which cannot be array elements, |
| issue an error-message and return. */ |
| switch (TREE_CODE (type)) |
| { |
| case VOID_TYPE: |
| if (name) |
| error_at (loc, "declaration of %qD as array of void", name); |
| else |
| error ("creating array of void"); |
| return error_mark_node; |
| |
| case FUNCTION_TYPE: |
| if (name) |
| error_at (loc, "declaration of %qD as array of functions", name); |
| else |
| error ("creating array of functions"); |
| return error_mark_node; |
| |
| case REFERENCE_TYPE: |
| if (name) |
| error_at (loc, "declaration of %qD as array of references", name); |
| else |
| error ("creating array of references"); |
| return error_mark_node; |
| |
| case METHOD_TYPE: |
| if (name) |
| error_at (loc, "declaration of %qD as array of function members", |
| name); |
| else |
| error ("creating array of function members"); |
| return error_mark_node; |
| |
| default: |
| break; |
| } |
| |
| /* [dcl.array] |
| |
| The constant expressions that specify the bounds of the arrays |
| can be omitted only for the first member of the sequence. */ |
| if (TREE_CODE (type) == ARRAY_TYPE && !TYPE_DOMAIN (type)) |
| { |
| if (name) |
| error_at (loc, "declaration of %qD as multidimensional array must " |
| "have bounds for all dimensions except the first", |
| name); |
| else |
| error ("multidimensional array must have bounds for all " |
| "dimensions except the first"); |
| |
| return error_mark_node; |
| } |
| |
| /* Figure out the index type for the array. */ |
| if (size) |
| itype = compute_array_index_type_loc (loc, name, size, |
| tf_warning_or_error); |
| |
| /* [dcl.array] |
| T is called the array element type; this type shall not be [...] an |
| abstract class type. */ |
| abstract_virtuals_error (name, type); |
| |
| return build_cplus_array_type (type, itype); |
| } |
| |
| /* Returns the smallest location that is not UNKNOWN_LOCATION. */ |
| |
| static location_t |
| min_location (location_t loca, location_t locb) |
| { |
| if (loca == UNKNOWN_LOCATION |
| || (locb != UNKNOWN_LOCATION |
| && linemap_location_before_p (line_table, locb, loca))) |
| return locb; |
| return loca; |
| } |
| |
| /* Returns the smallest location != UNKNOWN_LOCATION among the |
| three stored in LOCATIONS[ds_const], LOCATIONS[ds_volatile], |
| and LOCATIONS[ds_restrict]. */ |
| |
| static location_t |
| smallest_type_quals_location (int type_quals, const location_t* locations) |
| { |
| location_t loc = UNKNOWN_LOCATION; |
| |
| if (type_quals & TYPE_QUAL_CONST) |
| loc = locations[ds_const]; |
| |
| if (type_quals & TYPE_QUAL_VOLATILE) |
| loc = min_location (loc, locations[ds_volatile]); |
| |
| if (type_quals & TYPE_QUAL_RESTRICT) |
| loc = min_location (loc, locations[ds_restrict]); |
| |
| return loc; |
| } |
| |
| /* Check that it's OK to declare a function with the indicated TYPE |
| and TYPE_QUALS. SFK indicates the kind of special function (if any) |
| that this function is. OPTYPE is the type given in a conversion |
| operator declaration, or the class type for a constructor/destructor. |
| Returns the actual return type of the function; that may be different |
| than TYPE if an error occurs, or for certain special functions. */ |
| |
| static tree |
| check_special_function_return_type (special_function_kind sfk, |
| tree type, |
| tree optype, |
| int type_quals, |
| const location_t* locations) |
| { |
| switch (sfk) |
| { |
| case sfk_constructor: |
| if (type) |
| error ("return type specification for constructor invalid"); |
| else if (type_quals != TYPE_UNQUALIFIED) |
| error_at (smallest_type_quals_location (type_quals, locations), |
| "qualifiers are not allowed on constructor declaration"); |
| |
| if (targetm.cxx.cdtor_returns_this ()) |
| type = build_pointer_type (optype); |
| else |
| type = void_type_node; |
| break; |
| |
| case sfk_destructor: |
| if (type) |
| error ("return type specification for destructor invalid"); |
| else if (type_quals != TYPE_UNQUALIFIED) |
| error_at (smallest_type_quals_location (type_quals, locations), |
| "qualifiers are not allowed on destructor declaration"); |
| |
| /* We can't use the proper return type here because we run into |
| problems with ambiguous bases and covariant returns. */ |
| if (targetm.cxx.cdtor_returns_this ()) |
| type = build_pointer_type (void_type_node); |
| else |
| type = void_type_node; |
| break; |
| |
| case sfk_conversion: |
| if (type) |
| error ("return type specified for %<operator %T%>", optype); |
| else if (type_quals != TYPE_UNQUALIFIED) |
| error_at (smallest_type_quals_location (type_quals, locations), |
| "qualifiers are not allowed on declaration of " |
| "%<operator %T%>", optype); |
| |
| type = optype; |
| break; |
| |
| case sfk_deduction_guide: |
| if (type) |
| error ("return type specified for deduction guide"); |
| else if (type_quals != TYPE_UNQUALIFIED) |
| error_at (smallest_type_quals_location (type_quals, locations), |
| "qualifiers are not allowed on declaration of " |
| "deduction guide"); |
| if (TREE_CODE (optype) == TEMPLATE_TEMPLATE_PARM) |
| { |
| error ("template template parameter %qT in declaration of " |
| "deduction guide", optype); |
| type = error_mark_node; |
| } |
| else |
| type = make_template_placeholder (CLASSTYPE_TI_TEMPLATE (optype)); |
| for (int i = 0; i < ds_last; ++i) |
| if (i != ds_explicit && locations[i]) |
| error_at (locations[i], |
| "decl-specifier in declaration of deduction guide"); |
| break; |
| |
| default: |
| gcc_unreachable (); |
| } |
| |
| return type; |
| } |
| |
| /* A variable or data member (whose unqualified name is IDENTIFIER) |
| has been declared with the indicated TYPE. If the TYPE is not |
| acceptable, issue an error message and return a type to use for |
| error-recovery purposes. */ |
| |
| tree |
| check_var_type (tree identifier, tree type) |
| { |
| if (VOID_TYPE_P (type)) |
| { |
| if (!identifier) |
| error ("unnamed variable or field declared void"); |
| else if (identifier_p (identifier)) |
| { |
| gcc_assert (!IDENTIFIER_ANY_OP_P (identifier)); |
| error ("variable or field %qE declared void", identifier); |
| } |
| else |
| error ("variable or field declared void"); |
| type = error_mark_node; |
| } |
| |
| return type; |
| } |
| |
| /* Handle declaring DECL as an inline variable. */ |
| |
| static void |
| mark_inline_variable (tree decl, location_t loc) |
| { |
| bool inlinep = true; |
| if (! toplevel_bindings_p ()) |
| { |
| error_at (loc, "%<inline%> specifier invalid for variable " |
| "%qD declared at block scope", decl); |
| inlinep = false; |
| } |
| else if (cxx_dialect < cxx17) |
| pedwarn (loc, 0, "inline variables are only available " |
| "with %<-std=c++17%> or %<-std=gnu++17%>"); |
| if (inlinep) |
| { |
| retrofit_lang_decl (decl); |
| SET_DECL_VAR_DECLARED_INLINE_P (decl); |
| } |
| } |
| |
| |
| /* Assign a typedef-given name to a class or enumeration type declared |
| as anonymous at first. This was split out of grokdeclarator |
| because it is also used in libcc1. */ |
| |
| void |
| name_unnamed_type (tree type, tree decl) |
| { |
| gcc_assert (TYPE_UNNAMED_P (type)); |
| |
| /* Replace the anonymous name with the real name everywhere. */ |
| for (tree t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t)) |
| { |
| if (anon_aggrname_p (TYPE_IDENTIFIER (t))) |
| /* We do not rename the debug info representing the |
| unnamed tagged type because the standard says in |
| [dcl.typedef] that the naming applies only for |
| linkage purposes. */ |
| /*debug_hooks->set_name (t, decl);*/ |
| TYPE_NAME (t) = decl; |
| } |
| |
| if (TYPE_LANG_SPECIFIC (type)) |
| TYPE_WAS_UNNAMED (type) = 1; |
| |
| /* If this is a typedef within a template class, the nested |
| type is a (non-primary) template. The name for the |
| template needs updating as well. */ |
| if (TYPE_LANG_SPECIFIC (type) && CLASSTYPE_TEMPLATE_INFO (type)) |
| DECL_NAME (CLASSTYPE_TI_TEMPLATE (type)) |
| = TYPE_IDENTIFIER (type); |
| |
| /* Adjust linkage now that we aren't unnamed anymore. */ |
| reset_type_linkage (type); |
| |
| /* FIXME remangle member functions; member functions of a |
| type with external linkage have external linkage. */ |
| |
| /* Check that our job is done, and that it would fail if we |
| attempted to do it again. */ |
| gcc_assert (!TYPE_UNNAMED_P (type)); |
| } |
| |
| /* Given declspecs and a declarator (abstract or otherwise), determine |
| the name and type of the object declared and construct a DECL node |
| for it. |
| |
| DECLSPECS points to the representation of declaration-specifier |
| sequence that precedes declarator. |
| |
| DECL_CONTEXT says which syntactic context this declaration is in: |
| NORMAL for most contexts. Make a VAR_DECL or FUNCTION_DECL or TYPE_DECL. |
| FUNCDEF for a function definition. Like NORMAL but a few different |
| error messages in each case. Return value may be zero meaning |
| this definition is too screwy to try to parse. |
| MEMFUNCDEF for a function definition. Like FUNCDEF but prepares to |
| handle member functions (which have FIELD context). |
| Return value may be zero meaning this definition is too screwy to |
| try to parse. |
| PARM for a parameter declaration (either within a function prototype |
| or before a function body). Make a PARM_DECL, or return void_type_node. |
| TPARM for a template parameter declaration. |
| CATCHPARM for a parameter declaration before a catch clause. |
| TYPENAME if for a typename (in a cast or sizeof). |
| Don't make a DECL node; just return the ..._TYPE node. |
| FIELD for a struct or union field; make a FIELD_DECL. |
| BITFIELD for a field with specified width. |
| |
| INITIALIZED is as for start_decl. |
| |
| ATTRLIST is a pointer to the list of attributes, which may be NULL |
| if there are none; *ATTRLIST may be modified if attributes from inside |
| the declarator should be applied to the declaration. |
| |
| When this function is called, scoping variables (such as |
| CURRENT_CLASS_TYPE) should reflect the scope in which the |
| declaration occurs, not the scope in which the new declaration will |
| be placed. For example, on: |
| |
| void S::f() { ... } |
| |
| when grokdeclarator is called for `S::f', the CURRENT_CLASS_TYPE |
| should not be `S'. |
| |
| Returns a DECL (if a declarator is present), a TYPE (if there is no |
| declarator, in cases like "struct S;"), or the ERROR_MARK_NODE if an |
| error occurs. */ |
| |
| tree |
| grokdeclarator (const cp_declarator *declarator, |
| cp_decl_specifier_seq *declspecs, |
| enum decl_context decl_context, |
| int initialized, |
| tree* attrlist) |
| { |
| tree type = NULL_TREE; |
| int longlong = 0; |
| int explicit_intN = 0; |
| int virtualp, explicitp, friendp, inlinep, staticp; |
| int explicit_int = 0; |
| int explicit_char = 0; |
| int defaulted_int = 0; |
| |
| tree typedef_decl = NULL_TREE; |
| const char *name = NULL; |
| tree typedef_type = NULL_TREE; |
| /* True if this declarator is a function definition. */ |
| bool funcdef_flag = false; |
| cp_declarator_kind innermost_code = cdk_error; |
| int bitfield = 0; |
| #if 0 |
| /* See the code below that used this. */ |
| tree decl_attr = NULL_TREE; |
| #endif |
| |
| /* Keep track of what sort of function is being processed |
| so that we can warn about default return values, or explicit |
| return values which do not match prescribed defaults. */ |
| special_function_kind sfk = sfk_none; |
| |
| tree dname = NULL_TREE; |
| tree ctor_return_type = NULL_TREE; |
| enum overload_flags flags = NO_SPECIAL; |
| /* cv-qualifiers that apply to the declarator, for a declaration of |
| a member function. */ |
| cp_cv_quals memfn_quals = TYPE_UNQUALIFIED; |
| /* virt-specifiers that apply to the declarator, for a declaration of |
| a member function. */ |
| cp_virt_specifiers virt_specifiers = VIRT_SPEC_UNSPECIFIED; |
| /* ref-qualifier that applies to the declarator, for a declaration of |
| a member function. */ |
| cp_ref_qualifier rqual = REF_QUAL_NONE; |
| /* cv-qualifiers that apply to the type specified by the DECLSPECS. */ |
| int type_quals = TYPE_UNQUALIFIED; |
| tree raises = NULL_TREE; |
| int template_count = 0; |
| tree returned_attrs = NULL_TREE; |
| tree parms = NULL_TREE; |
| const cp_declarator *id_declarator; |
| /* The unqualified name of the declarator; either an |
| IDENTIFIER_NODE, BIT_NOT_EXPR, or TEMPLATE_ID_EXPR. */ |
| tree unqualified_id; |
| /* The class type, if any, in which this entity is located, |
| or NULL_TREE if none. Note that this value may be different from |
| the current class type; for example if an attempt is made to declare |
| "A::f" inside "B", this value will be "A". */ |
| tree ctype = current_class_type; |
| /* The NAMESPACE_DECL for the namespace in which this entity is |
| located. If an unqualified name is used to declare the entity, |
| this value will be NULL_TREE, even if the entity is located at |
| namespace scope. */ |
| tree in_namespace = NULL_TREE; |
| cp_storage_class storage_class; |
| bool unsigned_p, signed_p, short_p, long_p, thread_p; |
| bool type_was_error_mark_node = false; |
| bool parameter_pack_p = declarator ? declarator->parameter_pack_p : false; |
| bool template_type_arg = false; |
| bool template_parm_flag = false; |
| bool typedef_p = decl_spec_seq_has_spec_p (declspecs, ds_typedef); |
| bool constexpr_p = decl_spec_seq_has_spec_p (declspecs, ds_constexpr); |
| bool late_return_type_p = false; |
| bool array_parameter_p = false; |
| location_t saved_loc = input_location; |
| tree reqs = NULL_TREE; |
| |
| signed_p = decl_spec_seq_has_spec_p (declspecs, ds_signed); |
| unsigned_p = decl_spec_seq_has_spec_p (declspecs, ds_unsigned); |
| short_p = decl_spec_seq_has_spec_p (declspecs, ds_short); |
| long_p = decl_spec_seq_has_spec_p (declspecs, ds_long); |
| longlong = decl_spec_seq_has_spec_p (declspecs, ds_long_long); |
| explicit_intN = declspecs->explicit_intN_p; |
| thread_p = decl_spec_seq_has_spec_p (declspecs, ds_thread); |
| |
| // Was concept_p specified? Note that ds_concept |
| // implies ds_constexpr! |
| bool concept_p = decl_spec_seq_has_spec_p (declspecs, ds_concept); |
| if (concept_p) |
| constexpr_p = true; |
| |
| if (decl_spec_seq_has_spec_p (declspecs, ds_const)) |
| type_quals |= TYPE_QUAL_CONST; |
| if (decl_spec_seq_has_spec_p (declspecs, ds_volatile)) |
| type_quals |= TYPE_QUAL_VOLATILE; |
| if (decl_spec_seq_has_spec_p (declspecs, ds_restrict)) |
| type_quals |= TYPE_QUAL_RESTRICT; |
| |
| if (decl_context == FUNCDEF) |
| funcdef_flag = true, decl_context = NORMAL; |
| else if (decl_context == MEMFUNCDEF) |
| funcdef_flag = true, decl_context = FIELD; |
| else if (decl_context == BITFIELD) |
| bitfield = 1, decl_context = FIELD; |
| else if (decl_context == TEMPLATE_TYPE_ARG) |
| template_type_arg = true, decl_context = TYPENAME; |
| else if (decl_context == TPARM) |
| template_parm_flag = true, decl_context = PARM; |
| |
| if (initialized > 1) |
| funcdef_flag = true; |
| |
| location_t typespec_loc = smallest_type_quals_location (type_quals, |
| declspecs->locations); |
| if (typespec_loc == UNKNOWN_LOCATION) |
| typespec_loc = declspecs->locations[ds_type_spec]; |
| if (typespec_loc == UNKNOWN_LOCATION) |
| typespec_loc = input_location; |
| |
| /* Look inside a declarator for the name being declared |
| and get it as a string, for an error message. */ |
| for (id_declarator = declarator; |
| id_declarator; |
| id_declarator = id_declarator->declarator) |
| { |
| if (id_declarator->kind != cdk_id) |
| innermost_code = id_declarator->kind; |
| |
| switch (id_declarator->kind) |
| { |
| case cdk_function: |
| if (id_declarator->declarator |
| && id_declarator->declarator->kind == cdk_id) |
| { |
| sfk = id_declarator->declarator->u.id.sfk; |
| if (sfk == sfk_destructor) |
| flags = DTOR_FLAG; |
| } |
| break; |
| |
| case cdk_id: |
| { |
| tree qualifying_scope = id_declarator->u.id.qualifying_scope; |
| tree decl = id_declarator->u.id.unqualified_name; |
| if (!decl) |
| break; |
| if (qualifying_scope) |
| { |
| if (check_for_bare_parameter_packs (qualifying_scope, |
| id_declarator->id_loc)) |
| return error_mark_node; |
| if (at_function_scope_p ()) |
| { |
| /* [dcl.meaning] |
| |
| A declarator-id shall not be qualified except |
| for ... |
| |
| None of the cases are permitted in block |
| scope. */ |
| if (qualifying_scope == global_namespace) |
| error ("invalid use of qualified-name %<::%D%>", |
| decl); |
| else if (TYPE_P (qualifying_scope)) |
| error ("invalid use of qualified-name %<%T::%D%>", |
| qualifying_scope, decl); |
| else |
| error ("invalid use of qualified-name %<%D::%D%>", |
| qualifying_scope, decl); |
| return error_mark_node; |
| } |
| else if (TYPE_P (qualifying_scope)) |
| { |
| ctype = qualifying_scope; |
| if (!MAYBE_CLASS_TYPE_P (ctype)) |
| { |
| error ("%q#T is not a class or a namespace", ctype); |
| ctype = NULL_TREE; |
| } |
| else if (innermost_code != cdk_function |
| && current_class_type |
| && !uniquely_derived_from_p (ctype, |
| current_class_type)) |
| { |
| error ("invalid use of qualified-name %<%T::%D%>", |
| qualifying_scope, decl); |
| return error_mark_node; |
| } |
| } |
| else if (TREE_CODE (qualifying_scope) == NAMESPACE_DECL) |
| in_namespace = qualifying_scope; |
| } |
| switch (TREE_CODE (decl)) |
| { |
| case BIT_NOT_EXPR: |
| { |
| if (innermost_code != cdk_function) |
| { |
| error ("declaration of %qD as non-function", decl); |
| return error_mark_node; |
| } |
| else if (!qualifying_scope |
| && !(current_class_type && at_class_scope_p ())) |
| { |
| error ("declaration of %qD as non-member", decl); |
| return error_mark_node; |
| } |
| |
| tree type = TREE_OPERAND (decl, 0); |
| if (TYPE_P (type)) |
| type = constructor_name (type); |
| name = identifier_to_locale (IDENTIFIER_POINTER (type)); |
| dname = decl; |
| } |
| break; |
| |
| case TEMPLATE_ID_EXPR: |
| { |
| tree fns = TREE_OPERAND (decl, 0); |
| |
| dname = fns; |
| if (!identifier_p (dname)) |
| dname = OVL_NAME (dname); |
| } |
| /* Fall through. */ |
| |
| case IDENTIFIER_NODE: |
| if (identifier_p (decl)) |
| dname = decl; |
| |
| if (IDENTIFIER_KEYWORD_P (dname)) |
| { |
| error ("declarator-id missing; using reserved word %qD", |
| dname); |
| name = identifier_to_locale (IDENTIFIER_POINTER (dname)); |
| } |
| else if (!IDENTIFIER_CONV_OP_P (dname)) |
| name = identifier_to_locale (IDENTIFIER_POINTER (dname)); |
| else |
| { |
| gcc_assert (flags == NO_SPECIAL); |
| flags = TYPENAME_FLAG; |
| sfk = sfk_conversion; |
| tree glob = get_global_binding (dname); |
| if (glob && TREE_CODE (glob) == TYPE_DECL) |
| name = identifier_to_locale (IDENTIFIER_POINTER (dname)); |
| else |
| name = "<invalid operator>"; |
| } |
| break; |
| |
| default: |
| gcc_unreachable (); |
| } |
| break; |
| } |
| |
| case cdk_array: |
| case cdk_pointer: |
| case cdk_reference: |
| case cdk_ptrmem: |
| break; |
| |
| case cdk_decomp: |
| name = "structured binding"; |
| break; |
| |
| case cdk_error: |
| return error_mark_node; |
| |
| default: |
| gcc_unreachable (); |
| } |
| if (id_declarator->kind == cdk_id) |
| break; |
| } |
| |
| /* [dcl.fct.edf] |
| |
| The declarator in a function-definition shall have the form |
| D1 ( parameter-declaration-clause) ... */ |
| if (funcdef_flag && innermost_code != cdk_function) |
| { |
| error ("function definition does not declare parameters"); |
| return error_mark_node; |
| } |
| |
| if (flags == TYPENAME_FLAG |
| && innermost_code != cdk_function |
| && ! (ctype && !declspecs->any_specifiers_p)) |
| { |
| error ("declaration of %qD as non-function", dname); |
| return error_mark_node; |
| } |
| |
| if (dname && identifier_p (dname)) |
| { |
| if (UDLIT_OPER_P (dname) |
| && innermost_code != cdk_function) |
| { |
| error ("declaration of %qD as non-function", dname); |
| return error_mark_node; |
| } |
| |
| if (IDENTIFIER_ANY_OP_P (dname)) |
| { |
| if (typedef_p) |
| { |
| error ("declaration of %qD as %<typedef%>", dname); |
| return error_mark_node; |
| } |
| else if (decl_context == PARM || decl_context == CATCHPARM) |
| { |
| error ("declaration of %qD as parameter", dname); |
| return error_mark_node; |
| } |
| } |
| } |
| |
| /* Anything declared one level down from the top level |
| must be one of the parameters of a function |
| (because the body is at least two levels down). */ |
| |
| /* This heuristic cannot be applied to C++ nodes! Fixed, however, |
| by not allowing C++ class definitions to specify their parameters |
| with xdecls (must be spec.d in the parmlist). |
| |
| Since we now wait to push a class scope until we are sure that |
| we are in a legitimate method context, we must set oldcname |
| explicitly (since current_class_name is not yet alive). |
| |
| We also want to avoid calling this a PARM if it is in a namespace. */ |
| |
| if (decl_context == NORMAL && !toplevel_bindings_p ()) |
| { |
| cp_binding_level *b = current_binding_level; |
| current_binding_level = b->level_chain; |
| if (current_binding_level != 0 && toplevel_bindings_p ()) |
| decl_context = PARM; |
| current_binding_level = b; |
| } |
| |
| if (name == NULL) |
| name = decl_context == PARM ? "parameter" : "type name"; |
| |
| if (concept_p && typedef_p) |
| { |
| error_at (declspecs->locations[ds_concept], |
| "%<concept%> cannot appear in a typedef declaration"); |
| return error_mark_node; |
| } |
| |
| if (constexpr_p && typedef_p) |
| { |
| error_at (declspecs->locations[ds_constexpr], |
| "%<constexpr%> cannot appear in a typedef declaration"); |
| return error_mark_node; |
| } |
| |
| /* If there were multiple types specified in the decl-specifier-seq, |
| issue an error message. */ |
| if (declspecs->multiple_types_p) |
| { |
| error ("two or more data types in declaration of %qs", name); |
| return error_mark_node; |
| } |
| |
| if (declspecs->conflicting_specifiers_p) |
| { |
| error ("conflicting specifiers in declaration of %qs", name); |
| return error_mark_node; |
| } |
| |
| /* Extract the basic type from the decl-specifier-seq. */ |
| type = declspecs->type; |
| if (type == error_mark_node) |
| { |
| type = NULL_TREE; |
| type_was_error_mark_node = true; |
| } |
| cp_warn_deprecated_use (type); |
| if (type && TREE_CODE (type) == TYPE_DECL) |
| { |
| typedef_decl = type; |
| type = TREE_TYPE (typedef_decl); |
| if (DECL_ARTIFICIAL (typedef_decl)) |
| cp_warn_deprecated_use (type); |
| } |
| /* No type at all: default to `int', and set DEFAULTED_INT |
| because it was not a user-defined typedef. */ |
| if (type == NULL_TREE) |
| { |
| if (signed_p || unsigned_p || long_p || short_p) |
| { |
| /* These imply 'int'. */ |
| type = integer_type_node; |
| defaulted_int = 1; |
| } |
| /* If we just have "complex", it is equivalent to "complex double". */ |
| else if (!longlong && !explicit_intN |
| && decl_spec_seq_has_spec_p (declspecs, ds_complex)) |
| { |
| type = double_type_node; |
| pedwarn (declspecs->locations[ds_complex], OPT_Wpedantic, |
| "ISO C++ does not support plain %<complex%> meaning " |
| "%<double complex%>"); |
| } |
| } |
| /* Gather flags. */ |
| explicit_int = declspecs->explicit_int_p; |
| explicit_char = declspecs->explicit_char_p; |
| |
| #if 0 |
| /* See the code below that used this. */ |
| if (typedef_decl) |
| decl_attr = DECL_ATTRIBUTES (typedef_decl); |
| #endif |
| typedef_type = type; |
| |
| if (sfk == sfk_conversion || sfk == sfk_deduction_guide) |
| ctor_return_type = TREE_TYPE (dname); |
| else |
| ctor_return_type = ctype; |
| |
| if (sfk != sfk_none) |
| { |
| type = check_special_function_return_type (sfk, type, |
| ctor_return_type, |
| type_quals, |
| declspecs->locations); |
| type_quals = TYPE_UNQUALIFIED; |
| } |
| else if (type == NULL_TREE) |
| { |
| int is_main; |
| |
| explicit_int = -1; |
| |
| /* We handle `main' specially here, because 'main () { }' is so |
| common. With no options, it is allowed. With -Wreturn-type, |
| it is a warning. It is only an error with -pedantic-errors. */ |
| is_main = (funcdef_flag |
| && dname && identifier_p (dname) |
| && MAIN_NAME_P (dname) |
| && ctype == NULL_TREE |
| && in_namespace == NULL_TREE |
| && current_namespace == global_namespace); |
| |
| if (type_was_error_mark_node) |
| /* We've already issued an error, don't complain more. */; |
| else if (in_system_header_at (input_location) || flag_ms_extensions) |
| /* Allow it, sigh. */; |
| else if (! is_main) |
| permerror (input_location, "ISO C++ forbids declaration of %qs with no type", name); |
| else if (pedantic) |
| pedwarn (input_location, OPT_Wpedantic, |
| "ISO C++ forbids declaration of %qs with no type", name); |
| else |
| warning (OPT_Wreturn_type, |
| "ISO C++ forbids declaration of %qs with no type", name); |
| |
| if (type_was_error_mark_node && template_parm_flag) |
| /* FIXME we should be able to propagate the error_mark_node as is |
| for other contexts too. */ |
| type = error_mark_node; |
| else |
| type = integer_type_node; |
| } |
| |
| ctype = NULL_TREE; |
| |
| if (explicit_intN) |
| { |
| if (! int_n_enabled_p[declspecs->int_n_idx]) |
| { |
| error ("%<__int%d%> is not supported by this target", |
| int_n_data[declspecs->int_n_idx].bitsize); |
| explicit_intN = false; |
| } |
| else if (pedantic && ! in_system_header_at (input_location)) |
| pedwarn (input_location, OPT_Wpedantic, |
| "ISO C++ does not support %<__int%d%> for %qs", |
| int_n_data[declspecs->int_n_idx].bitsize, name); |
| } |
| |
| /* Now process the modifiers that were specified |
| and check for invalid combinations. */ |
| |
| /* Long double is a special combination. */ |
| if (long_p && !longlong && TYPE_MAIN_VARIANT (type) == double_type_node) |
| { |
| long_p = false; |
| type = cp_build_qualified_type (long_double_type_node, |
| cp_type_quals (type)); |
| } |
| |
| /* Check all other uses of type modifiers. */ |
| |
| if (unsigned_p || signed_p || long_p || short_p) |
| { |
| location_t loc; |
| const char *key; |
| if (unsigned_p) |
| { |
| key = "unsigned"; |
| loc = declspecs->locations[ds_unsigned]; |
| } |
| else if (signed_p) |
| { |
| key = "signed"; |
| loc = declspecs->locations[ds_signed]; |
| } |
| else if (longlong) |
| { |
| key = "long long"; |
| loc = declspecs->locations[ds_long_long]; |
| } |
| else if (long_p) |
| { |
| key = "long"; |
| loc = declspecs->locations[ds_long]; |
| } |
| else /* if (short_p) */ |
| { |
| key = "short"; |
| loc = declspecs->locations[ds_short]; |
| } |
| |
| int ok = 0; |
| |
| if (signed_p && unsigned_p) |
| { |
| gcc_rich_location richloc (declspecs->locations[ds_signed]); |
| richloc.add_range (declspecs->locations[ds_unsigned]); |
| error_at (&richloc, |
| "%<signed%> and %<unsigned%> specified together"); |
| } |
| else if (long_p && short_p) |
| { |
| gcc_rich_location richloc (declspecs->locations[ds_long]); |
| richloc.add_range (declspecs->locations[ds_short]); |
| error_at (&richloc, "%<long%> and %<short%> specified together"); |
| } |
| else if (TREE_CODE (type) != INTEGER_TYPE |
| || type == char8_type_node |
| || type == char16_type_node |
| || type == char32_type_node |
| || ((long_p || short_p) |
| && (explicit_char || explicit_intN))) |
| error_at (loc, "%qs specified with %qT", key, type); |
| else if (!explicit_int && !defaulted_int |
| && !explicit_char && !explicit_intN) |
| { |
| if (typedef_decl) |
| { |
| pedwarn (loc, OPT_Wpedantic, "%qs specified with %qT", |
| key, type); |
| ok = !flag_pedantic_errors; |
| } |
| else if (declspecs->decltype_p) |
| error_at (loc, "%qs specified with %<decltype%>", key); |
| else |
| error_at (loc, "%qs specified with %<typeof%>", key); |
| } |
| else |
| ok = 1; |
| |
| /* Discard the type modifiers if they are invalid. */ |
| if (! ok) |
| { |
| unsigned_p = false; |
| signed_p = false; |
| long_p = false; |
| short_p = false; |
| longlong = 0; |
| } |
| } |
| |
| /* Decide whether an integer type is signed or not. |
| Optionally treat bitfields as signed by default. */ |
| if (unsigned_p |
| /* [class.bit] |
| |
| It is implementation-defined whether a plain (neither |
| explicitly signed or unsigned) char, short, int, or long |
| bit-field is signed or unsigned. |
| |
| Naturally, we extend this to long long as well. Note that |
| this does not include wchar_t. */ |
| || (bitfield && !flag_signed_bitfields |
| && !signed_p |
| /* A typedef for plain `int' without `signed' can be |
| controlled just like plain `int', but a typedef for |
| `signed int' cannot be so controlled. */ |
| && !(typedef_decl |
| && C_TYPEDEF_EXPLICITLY_SIGNED (typedef_decl)) |
| && TREE_CODE (type) == INTEGER_TYPE |
| && !same_type_p (TYPE_MAIN_VARIANT (type), wchar_type_node))) |
| { |
| if (explicit_intN) |
| type = int_n_trees[declspecs->int_n_idx].unsigned_type; |
| else if (longlong) |
| type = long_long_unsigned_type_node; |
| else if (long_p) |
| type = long_unsigned_type_node; |
| else if (short_p) |
| type = short_unsigned_type_node; |
| else if (type == char_type_node) |
| type = unsigned_char_type_node; |
| else if (typedef_decl) |
| type = unsigned_type_for (type); |
| else |
| type = unsigned_type_node; |
| } |
| else if (signed_p && type == char_type_node) |
| type = signed_char_type_node; |
| else if (explicit_intN) |
| type = int_n_trees[declspecs->int_n_idx].signed_type; |
| else if (longlong) |
| type = long_long_integer_type_node; |
| else if (long_p) |
| type = long_integer_type_node; |
| else if (short_p) |
| type = short_integer_type_node; |
| |
| if (decl_spec_seq_has_spec_p (declspecs, ds_complex)) |
| { |
| if (TREE_CODE (type) != INTEGER_TYPE && TREE_CODE (type) != REAL_TYPE) |
| error ("complex invalid for %qs", name); |
| /* If a modifier is specified, the resulting complex is the complex |
| form of TYPE. E.g, "complex short" is "complex short int". */ |
| else if (type == integer_type_node) |
| type = complex_integer_type_node; |
| else if (type == float_type_node) |
| type = complex_float_type_node; |
| else if (type == double_type_node) |
| type = complex_double_type_node; |
| else if (type == long_double_type_node) |
| type = complex_long_double_type_node; |
| else |
| type = build_complex_type (type); |
| } |
| |
| /* If we're using the injected-class-name to form a compound type or a |
| declaration, replace it with the underlying class so we don't get |
| redundant typedefs in the debug output. But if we are returning the |
| type unchanged, leave it alone so that it's available to |
| maybe_get_template_decl_from_type_decl. */ |
| if (CLASS_TYPE_P (type) |
| && DECL_SELF_REFERENCE_P (TYPE_NAME (type)) |
| && type == TREE_TYPE (TYPE_NAME (type)) |
| && (declarator || type_quals)) |
| type = DECL_ORIGINAL_TYPE (TYPE_NAME (type)); |
| |
| type_quals |= cp_type_quals (type); |
| type = cp_build_qualified_type_real |
| (type, type_quals, ((((typedef_decl && !DECL_ARTIFICIAL (typedef_decl)) |
| || declspecs->decltype_p) |
| ? tf_ignore_bad_quals : 0) | tf_warning_or_error)); |
| /* We might have ignored or rejected some of the qualifiers. */ |
| type_quals = cp_type_quals (type); |
| |
| if (cxx_dialect >= cxx17 && type && is_auto (type) |
| && innermost_code != cdk_function |
| && id_declarator && declarator != id_declarator) |
| if (tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (type)) |
| { |
| error_at (typespec_loc, "template placeholder type %qT must be followed " |
| "by a simple declarator-id", type); |
| inform (DECL_SOURCE_LOCATION (tmpl), "%qD declared here", tmpl); |
| type = error_mark_node; |
| } |
| |
| staticp = 0; |
| inlinep = decl_spec_seq_has_spec_p (declspecs, ds_inline); |
| virtualp = decl_spec_seq_has_spec_p (declspecs, ds_virtual); |
| explicitp = decl_spec_seq_has_spec_p (declspecs, ds_explicit); |
| |
| storage_class = declspecs->storage_class; |
| if (storage_class == sc_static) |
| staticp = 1 + (decl_context == FIELD); |
| |
| if (virtualp) |
| { |
| if (staticp == 2) |
| { |
| gcc_rich_location richloc (declspecs->locations[ds_virtual]); |
| richloc.add_range (declspecs->locations[ds_storage_class]); |
| error_at (&richloc, "member %qD cannot be declared both %<virtual%> " |
| "and %<static%>", dname); |
| storage_class = sc_none; |
| staticp = 0; |
| } |
| if (constexpr_p && cxx_dialect < cxx2a) |
| { |
| gcc_rich_location richloc (declspecs->locations[ds_virtual]); |
| richloc.add_range (declspecs->locations[ds_constexpr]); |
| pedwarn (&richloc, OPT_Wpedantic, "member %qD can be declared both " |
| "%<virtual%> and %<constexpr%> only in %<-std=c++2a%> or " |
| "%<-std=gnu++2a%>", dname); |
| } |
| } |
| friendp = decl_spec_seq_has_spec_p (declspecs, ds_friend); |
| |
| /* Issue errors about use of storage classes for parameters. */ |
| if (decl_context == PARM) |
| { |
| if (typedef_p) |
| { |
| error_at (declspecs->locations[ds_typedef], |
| "typedef declaration invalid in parameter declaration"); |
| return error_mark_node; |
| } |
| else if (template_parm_flag && storage_class != sc_none) |
| { |
| error_at (min_location (declspecs->locations[ds_thread], |
| declspecs->locations[ds_storage_class]), |
| "storage class specified for template parameter %qs", |
| name); |
| return error_mark_node; |
| } |
| else if (storage_class == sc_static |
| || storage_class == sc_extern |
| || thread_p) |
| { |
| error_at (min_location (declspecs->locations[ds_thread], |
| declspecs->locations[ds_storage_class]), |
| "storage class specified for parameter %qs", name); |
| return error_mark_node; |
| } |
| |
| /* Function parameters cannot be concept. */ |
| if (concept_p) |
| error_at (declspecs->locations[ds_concept], |
| "a parameter cannot be declared %<concept%>"); |
| /* Function parameters cannot be constexpr. If we saw one, moan |
| and pretend it wasn't there. */ |
| else if (constexpr_p) |
| { |
| error_at (declspecs->locations[ds_constexpr], |
| "a parameter cannot be declared %<constexpr%>"); |
| constexpr_p = 0; |
| } |
| } |
| |
| /* Give error if `virtual' is used outside of class declaration. */ |
| if (virtualp |
| && (current_class_name == NULL_TREE || decl_context != FIELD)) |
| { |
| error_at (declspecs->locations[ds_virtual], |
| "%<virtual%> outside class declaration"); |
| virtualp = 0; |
| } |
| |
| if (innermost_code == cdk_decomp) |
| { |
| location_t loc = (declarator->kind == cdk_reference |
| ? declarator->declarator->id_loc : declarator->id_loc); |
| if (inlinep) |
| error_at (declspecs->locations[ds_inline], |
| "structured binding declaration cannot be %<inline%>"); |
| if (typedef_p) |
| error_at (declspecs->locations[ds_typedef], |
| "structured binding declaration cannot be %<typedef%>"); |
| if (constexpr_p) |
| error_at (declspecs->locations[ds_constexpr], "structured " |
| "binding declaration cannot be %<constexpr%>"); |
| if (thread_p) |
| error_at (declspecs->locations[ds_thread], |
| "structured binding declaration cannot be %qs", |
| declspecs->gnu_thread_keyword_p |
| ? "__thread" : "thread_local"); |
| if (concept_p) |
| error_at (declspecs->locations[ds_concept], |
| "structured binding declaration cannot be %<concept%>"); |
| switch (storage_class) |
| { |
| case sc_none: |
| break; |
| case sc_register: |
| error_at (loc, "structured binding declaration cannot be " |
| "%<register%>"); |
| break; |
| case sc_static: |
| error_at (loc, "structured binding declaration cannot be " |
| "%<static%>"); |
| break; |
| case sc_extern: |
| error_at (loc, "structured binding declaration cannot be " |
| "%<extern%>"); |
| break; |
| case sc_mutable: |
| error_at (loc, "structured binding declaration cannot be " |
| "%<mutable%>"); |
| break; |
| case sc_auto: |
| error_at (loc, "structured binding declaration cannot be " |
| "C++98 %<auto%>"); |
| break; |
| default: |
| gcc_unreachable (); |
| } |
| if (TREE_CODE (type) != TEMPLATE_TYPE_PARM |
| || TYPE_IDENTIFIER (type) != auto_identifier) |
| { |
| if (type != error_mark_node) |
| { |
| error_at (loc, "structured binding declaration cannot have " |
| "type %qT", type); |
| inform (loc, |
| "type must be cv-qualified %<auto%> or reference to " |
| "cv-qualified %<auto%>"); |
| } |
| type = build_qualified_type (make_auto (), type_quals); |
| declspecs->type = type; |
| } |
| inlinep = 0; |
| typedef_p = 0; |
| constexpr_p = 0; |
| thread_p = 0; |
| concept_p = 0; |
| storage_class = sc_none; |
| staticp = 0; |
| declspecs->storage_class = sc_none; |
| declspecs->locations[ds_thread] = UNKNOWN_LOCATION; |
| } |
| |
| /* Static anonymous unions are dealt with here. */ |
| if (staticp && decl_context == TYPENAME |
| && declspecs->type |
| && ANON_AGGR_TYPE_P (declspecs->type)) |
| decl_context = FIELD; |
| |
| /* Warn about storage classes that are invalid for certain |
| kinds of declarations (parameters, typenames, etc.). */ |
| if (thread_p |
| && ((storage_class |
| && storage_class != sc_extern |
| && storage_class != sc_static) |
| || typedef_p)) |
| { |
| error ("multiple storage classes in declaration of %qs", name); |
| thread_p = false; |
| } |
| if (decl_context != NORMAL |
| && ((storage_class != sc_none |
| && storage_class != sc_mutable) |
| || thread_p)) |
| { |
| if ((decl_context == PARM || decl_context == CATCHPARM) |
| && (storage_class == sc_register |
| || storage_class == sc_auto)) |
| ; |
| else if (typedef_p) |
| ; |
| else if (decl_context == FIELD |
| /* C++ allows static class elements. */ |
| && storage_class == sc_static) |
| /* C++ also allows inlines and signed and unsigned elements, |
| but in those cases we don't come in here. */ |
| ; |
| else |
| { |
| location_t loc |
| = min_location (declspecs->locations[ds_thread], |
| declspecs->locations[ds_storage_class]); |
| if (decl_context == FIELD) |
| error_at (loc, "storage class specified for %qs", name); |
| else if (decl_context == PARM || decl_context == CATCHPARM) |
| error_at (loc, "storage class specified for parameter %qs", name); |
| else |
| error_at (loc, "storage class specified for typename"); |
| if (storage_class == sc_register |
| || storage_class == sc_auto |
| || storage_class == sc_extern |
| || thread_p) |
| storage_class = sc_none; |
| } |
| } |
| else if (storage_class == sc_extern && funcdef_flag |
| && ! toplevel_bindings_p ()) |
| error ("nested function %qs declared %<extern%>", name); |
| else if (toplevel_bindings_p ()) |
| { |
| if (storage_class == sc_auto) |
| error ("top-level declaration of %qs specifies %<auto%>", name); |
| } |
| else if (thread_p |
| && storage_class != sc_extern |
| && storage_class != sc_static) |
| { |
| if (declspecs->gnu_thread_keyword_p) |
| pedwarn (declspecs->locations[ds_thread], |
| 0, "function-scope %qs implicitly auto and " |
| "declared %<__thread%>", name); |
| |
| /* When thread_local is applied to a variable of block scope the |
| storage-class-specifier static is implied if it does not appear |
| explicitly. */ |
| storage_class = declspecs->storage_class = sc_static; |
| staticp = 1; |
| } |
| |
| if (storage_class && friendp) |
| { |
| error_at (min_location (declspecs->locations[ds_thread], |
| declspecs->locations[ds_storage_class]), |
| "storage class specifiers invalid in friend function " |
| "declarations"); |
| storage_class = sc_none; |
| staticp = 0; |
| } |
| |
| if (!id_declarator) |
| unqualified_id = NULL_TREE; |
| else |
| { |
| unqualified_id = id_declarator->u.id.unqualified_name; |
| switch (TREE_CODE (unqualified_id)) |
| { |
| case BIT_NOT_EXPR: |
| unqualified_id = TREE_OPERAND (unqualified_id, 0); |
| if (TYPE_P (unqualified_id)) |
| unqualified_id = constructor_name (unqualified_id); |
| break; |
| |
| case IDENTIFIER_NODE: |
| case TEMPLATE_ID_EXPR: |
| break; |
| |
| default: |
| gcc_unreachable (); |
| } |
| } |
| |
| if (declspecs->std_attributes) |
| { |
| location_t attr_loc = declspecs->locations[ds_std_attribute]; |
| if (warning_at (attr_loc, OPT_Wattributes, "attribute ignored")) |
| inform (attr_loc, "an attribute that appertains to a type-specifier " |
| "is ignored"); |
| } |
| |
| /* Determine the type of the entity declared by recurring on the |
| declarator. */ |
| for (; declarator; declarator = declarator->declarator) |
| { |
| const cp_declarator *inner_declarator; |
| tree attrs; |
| |
| if (type == error_mark_node) |
| return error_mark_node; |
| |
| attrs = declarator->attributes; |
| if (attrs) |
| { |
| int attr_flags; |
| |
| attr_flags = 0; |
| if (declarator == NULL || declarator->kind == cdk_id) |
| attr_flags |= (int) ATTR_FLAG_DECL_NEXT; |
| if (declarator->kind == cdk_function) |
| attr_flags |= (int) ATTR_FLAG_FUNCTION_NEXT; |
| if (declarator->kind == cdk_array) |
| attr_flags |= (int) ATTR_FLAG_ARRAY_NEXT; |
| tree late_attrs = NULL_TREE; |
| if (decl_context != PARM) |
| /* Assume that any attributes that get applied late to |
| templates will DTRT when applied to the declaration |
| as a whole. */ |
| late_attrs = splice_template_attributes (&attrs, type); |
| returned_attrs = decl_attributes (&type, |
| chainon (returned_attrs, attrs), |
| attr_flags); |
| returned_attrs = chainon (late_attrs, returned_attrs); |
| } |
| |
| inner_declarator = declarator->declarator; |
| |
| /* We don't want to warn in parameter context because we don't |
| yet know if the parse will succeed, and this might turn out |
| to be a constructor call. */ |
| if (decl_context != PARM |
| && decl_context != TYPENAME |
| && !typedef_p |
| && declarator->parenthesized != UNKNOWN_LOCATION |
| /* If the type is class-like and the inner name used a |
| global namespace qualifier, we need the parens. |
| Unfortunately all we can tell is whether a qualified name |
| was used or not. */ |
| && !(inner_declarator |
| && inner_declarator->kind == cdk_id |
| && inner_declarator->u.id.qualifying_scope |
| && (MAYBE_CLASS_TYPE_P (type) |
| || TREE_CODE (type) == ENUMERAL_TYPE))) |
| warning_at (declarator->parenthesized, OPT_Wparentheses, |
| "unnecessary parentheses in declaration of %qs", name); |
| if (declarator->kind == cdk_id || declarator->kind == cdk_decomp) |
| break; |
| |
| switch (declarator->kind) |
| { |
| case cdk_array: |
| type = create_array_type_for_decl (dname, type, |
| declarator->u.array.bounds, |
| declarator->id_loc); |
| if (!valid_array_size_p (input_location, type, dname)) |
| type = error_mark_node; |
| |
| if (declarator->std_attributes) |
| /* [dcl.array]/1: |
| |
| The optional attribute-specifier-seq appertains to the |
| array. */ |
| returned_attrs = chainon (returned_attrs, |
| declarator->std_attributes); |
| break; |
| |
| case cdk_function: |
| { |
| tree arg_types; |
| int funcdecl_p; |
| |
| /* Declaring a function type. */ |
| |
| input_location = declspecs->locations[ds_type_spec]; |
| abstract_virtuals_error (ACU_RETURN, type); |
| input_location = saved_loc; |
| |
| /* Pick up type qualifiers which should be applied to `this'. */ |
| memfn_quals = declarator->u.function.qualifiers; |
| /* Pick up virt-specifiers. */ |
| virt_specifiers = declarator->u.function.virt_specifiers; |
| /* And ref-qualifier, too */ |
| rqual = declarator->u.function.ref_qualifier; |
| /* And tx-qualifier. */ |
| tree tx_qual = declarator->u.function.tx_qualifier; |
| /* Pick up the exception specifications. */ |
| raises = declarator->u.function.exception_specification; |
| /* If the exception-specification is ill-formed, let's pretend |
| there wasn't one. */ |
| if (raises == error_mark_node) |
| raises = NULL_TREE; |
| |
| if (reqs) |
| error_at (location_of (reqs), "requires-clause on return type"); |
| reqs = declarator->u.function.requires_clause; |
| |
| /* Say it's a definition only for the CALL_EXPR |
| closest to the identifier. */ |
| funcdecl_p = inner_declarator && inner_declarator->kind == cdk_id; |
| |
| /* Handle a late-specified return type. */ |
| tree late_return_type = declarator->u.function.late_return_type; |
| if (funcdecl_p |
| /* This is the case e.g. for |
| using T = auto () -> int. */ |
| || inner_declarator == NULL) |
| { |
| if (tree auto_node = type_uses_auto (type)) |
| { |
| if (!late_return_type) |
| { |
| if (current_class_type |
| && LAMBDA_TYPE_P (current_class_type)) |
| /* OK for C++11 lambdas. */; |
| else if (cxx_dialect < cxx14) |
| { |
| error_at (typespec_loc, "%qs function uses " |
| "%<auto%> type specifier without " |
| "trailing return type", name); |
| inform (typespec_loc, |
| "deduced return type only available " |
| "with %<-std=c++14%> or %<-std=gnu++14%>"); |
| } |
| else if (virtualp) |
| { |
| error_at (typespec_loc, "virtual function " |
| "cannot have deduced return type"); |
| virtualp = false; |
| } |
| } |
| else if (!is_auto (type) && sfk != sfk_conversion) |
| { |
| error_at (typespec_loc, "%qs function with trailing " |
| "return type has %qT as its type rather " |
| "than plain %<auto%>", name, type); |
| return error_mark_node; |
| } |
| else if (is_auto (type) && AUTO_IS_DECLTYPE (type)) |
| { |
| if (funcdecl_p) |
| error_at (typespec_loc, |
| "%qs function with trailing return type " |
| "has %<decltype(auto)%> as its type " |
| "rather than plain %<auto%>", name); |
| else |
| error_at (typespec_loc, |
| "invalid use of %<decltype(auto)%>"); |
| return error_mark_node; |
| } |
| tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (auto_node); |
| if (!tmpl) |
| if (tree late_auto = type_uses_auto (late_return_type)) |
| tmpl = CLASS_PLACEHOLDER_TEMPLATE (late_auto); |
| if (tmpl && funcdecl_p) |
| { |
| if (!dguide_name_p (unqualified_id)) |
| { |
| error_at (declarator->id_loc, "deduced class " |
| "type %qD in function return type", |
| DECL_NAME (tmpl)); |
| inform (DECL_SOURCE_LOCATION (tmpl), |
| "%qD declared here", tmpl); |
| return error_mark_node; |
| } |
| else if (!late_return_type) |
| { |
| error_at (declarator->id_loc, "deduction guide " |
| "for %qT must have trailing return " |
| "type", TREE_TYPE (tmpl)); |
| inform (DECL_SOURCE_LOCATION (tmpl), |
| "%qD declared here", tmpl); |
| return error_mark_node; |
| } |
| else if (CLASS_TYPE_P (late_return_type) |
| && CLASSTYPE_TEMPLATE_INFO (late_return_type) |
| && (CLASSTYPE_TI_TEMPLATE (late_return_type) |
| == tmpl)) |
| /* OK */; |
| else |
| error ("trailing return type %qT of deduction guide " |
| "is not a specialization of %qT", |
| late_return_type, TREE_TYPE (tmpl)); |
| } |
| } |
| else if (late_return_type |
| && sfk != sfk_conversion) |
| { |
| if (late_return_type == error_mark_node) |
| return error_mark_node; |
| if (cxx_dialect < cxx11) |
| /* Not using maybe_warn_cpp0x because this should |
| always be an error. */ |
| error_at (typespec_loc, |
| "trailing return type only available " |
| "with %<-std=c++11%> or %<-std=gnu++11%>"); |
| else |
| error_at (typespec_loc, "%qs function with trailing " |
| "return type not declared with %<auto%> " |
| "type specifier", name); |
| return error_mark_node; |
| } |
| } |
| type = splice_late_return_type (type, late_return_type); |
| if (type == error_mark_node) |
| return error_mark_node; |
| |
| if (late_return_type) |
| { |
| late_return_type_p = true; |
| type_quals = cp_type_quals (type); |
| } |
| |
| if (type_quals != TYPE_UNQUALIFIED) |
| { |
| if (SCALAR_TYPE_P (type) || VOID_TYPE_P (type)) |
| warning_at (typespec_loc, OPT_Wignored_qualifiers, "type " |
| "qualifiers ignored on function return type"); |
| /* We now know that the TYPE_QUALS don't apply to the |
| decl, but to its return type. */ |
| type_quals = TYPE_UNQUALIFIED; |
| } |
| |
| /* Error about some types functions can't return. */ |
| |
| if (TREE_CODE (type) == FUNCTION_TYPE) |
| { |
| error_at (typespec_loc, "%qs declared as function returning " |
| "a function", name); |
| return error_mark_node; |
| } |
| if (TREE_CODE (type) == ARRAY_TYPE) |
| { |
| error_at (typespec_loc, "%qs declared as function returning " |
| "an array", name); |
| return error_mark_node; |
| } |
| |
| if (ctype == NULL_TREE |
| && decl_context == FIELD |
| && funcdecl_p |
| && friendp == 0) |
| ctype = current_class_type; |
| |
| if (ctype && (sfk == sfk_constructor |
| || sfk == sfk_destructor)) |
| { |
| /* We are within a class's scope. If our declarator name |
| is the same as the class name, and we are defining |
| a function, then it is a constructor/destructor, and |
| therefore returns a void type. */ |
| |
| /* ISO C++ 12.4/2. A destructor may not be declared |
| const or volatile. A destructor may not be static. |
| A destructor may not be declared with ref-qualifier. |
| |
| ISO C++ 12.1. A constructor may not be declared |
| const or volatile. A constructor may not be |
| virtual. A constructor may not be static. |
| A constructor may not be declared with ref-qualifier. */ |
| if (staticp == 2) |
| error ((flags == DTOR_FLAG) |
| ? G_("destructor cannot be static member function") |
| : G_("constructor cannot be static member function")); |
| if (memfn_quals) |
| { |
| error ((flags == DTOR_FLAG) |
| ? G_("destructors may not be cv-qualified") |
| : G_("constructors may not be cv-qualified")); |
| memfn_quals = TYPE_UNQUALIFIED; |
| } |
| |
| if (rqual) |
| { |
| maybe_warn_cpp0x (CPP0X_REF_QUALIFIER); |
| error ((flags == DTOR_FLAG) |
| ? G_("destructors may not be ref-qualified") |
| : G_("constructors may not be ref-qualified")); |
| rqual = REF_QUAL_NONE; |
| } |
| |
| if (decl_context == FIELD |
| && !member_function_or_else (ctype, |
| current_class_type, |
| flags)) |
| return error_mark_node; |
| |
| if (flags != DTOR_FLAG) |
| { |
| /* It's a constructor. */ |
| if (explicitp == 1) |
| explicitp = 2; |
| if (virtualp) |
| { |
| permerror (declspecs->locations[ds_virtual], |
| "constructors cannot be declared %<virtual%>"); |
| virtualp = 0; |
| } |
| if (decl_context == FIELD |
| && sfk != sfk_constructor) |
| return error_mark_node; |
| } |
| if (decl_context == FIELD) |
| staticp = 0; |
| } |
| else if (friendp) |
| { |
| if (virtualp) |
| { |
| /* Cannot be both friend and virtual. */ |
| gcc_rich_location richloc (declspecs->locations[ds_virtual]); |
| richloc.add_range (declspecs->locations[ds_friend]); |
| error_at (&richloc, "virtual functions cannot be friends"); |
| friendp = 0; |
| } |
| if (decl_context == NORMAL) |
| error ("friend declaration not in class definition"); |
| if (current_function_decl && funcdef_flag) |
| { |
| error ("can%'t define friend function %qs in a local " |
| "class definition", name); |
| friendp = 0; |
| } |
| } |
| else if (ctype && sfk == sfk_conversion) |
| { |
| if (explicitp == 1) |
| { |
| maybe_warn_cpp0x (CPP0X_EXPLICIT_CONVERSION); |
| explicitp = 2; |
| } |
| if (late_return_type_p) |
| error ("a conversion function cannot have a trailing return type"); |
| } |
| else if (sfk == sfk_deduction_guide) |
| { |
| if (explicitp == 1) |
| explicitp = 2; |
| } |
| |
| tree pushed_scope = NULL_TREE; |
| if (funcdecl_p |
| && decl_context != FIELD |
| && inner_declarator->u.id.qualifying_scope |
| && CLASS_TYPE_P (inner_declarator->u.id.qualifying_scope)) |
| pushed_scope |
| = push_scope (inner_declarator->u.id.qualifying_scope); |
| |
| arg_types = grokparms (declarator->u.function.parameters, &parms); |
| |
| if (pushed_scope) |
| pop_scope (pushed_scope); |
| |
| if (inner_declarator |
| && inner_declarator->kind == cdk_id |
| && inner_declarator->u.id.sfk == sfk_destructor |
| && arg_types != void_list_node) |
| { |
| error ("destructors may not have parameters"); |
| arg_types = void_list_node; |
| parms = NULL_TREE; |
| } |
| |
| type = build_function_type (type, arg_types); |
| |
| tree attrs = declarator->std_attributes; |
| if (tx_qual) |
| { |
| tree att = build_tree_list (tx_qual, NULL_TREE); |
| /* transaction_safe applies to the type, but |
| transaction_safe_dynamic applies to the function. */ |
| if (is_attribute_p ("transaction_safe", tx_qual)) |
| attrs = chainon (attrs, att); |
| else |
| returned_attrs = chainon (returned_attrs, att); |
| } |
| if (attrs) |
| /* [dcl.fct]/2: |
| |
| The optional attribute-specifier-seq appertains to |
| the function type. */ |
| decl_attributes (&type, attrs, 0); |
| |
| if (raises) |
| type = build_exception_variant (type, raises); |
| } |
| break; |
| |
| case cdk_pointer: |
| case cdk_reference: |
| case cdk_ptrmem: |
| /* Filter out pointers-to-references and references-to-references. |
| We can get these if a TYPE_DECL is used. */ |
| |
| if (TYPE_REF_P (type)) |
| { |
| if (declarator->kind != cdk_reference) |
| { |
| error ("cannot declare pointer to %q#T", type); |
| type = TREE_TYPE (type); |
| } |
| |
| /* In C++0x, we allow reference to reference declarations |
| that occur indirectly through typedefs [7.1.3/8 dcl.typedef] |
| and template type arguments [14.3.1/4 temp.arg.type]. The |
| check for direct reference to reference declarations, which |
| are still forbidden, occurs below. Reasoning behind the change |
| can be found in DR106, DR540, and the rvalue reference |
| proposals. */ |
| else if (cxx_dialect == cxx98) |
| { |
| error ("cannot declare reference to %q#T", type); |
| type = TREE_TYPE (type); |
| } |
| } |
| else if (VOID_TYPE_P (type)) |
| { |
| if (declarator->kind == cdk_reference) |
| error ("cannot declare reference to %q#T", type); |
| else if (declarator->kind == cdk_ptrmem) |
| error ("cannot declare pointer to %q#T member", type); |
| } |
| |
| /* We now know that the TYPE_QUALS don't apply to the decl, |
| but to the target of the pointer. */ |
| type_quals = TYPE_UNQUALIFIED; |
| |
| /* This code used to handle METHOD_TYPE, but I don't think it's |
| possible to get it here anymore. */ |
| gcc_assert (TREE_CODE (type) != METHOD_TYPE); |
| if (declarator->kind == cdk_ptrmem |
| && TREE_CODE (type) == FUNCTION_TYPE) |
| { |
| memfn_quals |= type_memfn_quals (type); |
| type = build_memfn_type (type, |
| declarator->u.pointer.class_type, |
| memfn_quals, |
| rqual); |
| if (type == error_mark_node) |
| return error_mark_node; |
| |
| rqual = REF_QUAL_NONE; |
| memfn_quals = TYPE_UNQUALIFIED; |
| } |
| |
| if (TREE_CODE (type) == FUNCTION_TYPE |
| && (type_memfn_quals (type) != TYPE_UNQUALIFIED |
| || type_memfn_rqual (type) != REF_QUAL_NONE)) |
| error (declarator->kind == cdk_reference |
| ? G_("cannot declare reference to qualified function type %qT") |
| : G_("cannot declare pointer to qualified function type %qT"), |
| type); |
| |
| /* When the pointed-to type involves components of variable size, |
| care must be taken to ensure that the size evaluation code is |
| emitted early enough to dominate all the possible later uses |
| and late enough for the variables on which it depends to have |
| been assigned. |
| |
| This is expected to happen automatically when the pointed-to |
| type has a name/declaration of it's own, but special attention |
| is required if the type is anonymous. |
| |
| We handle the NORMAL and FIELD contexts here by inserting a |
| dummy statement that just evaluates the size at a safe point |
| and ensures it is not deferred until e.g. within a deeper |
| conditional context (c++/43555). |
| |
| We expect nothing to be needed here for PARM or TYPENAME. |
| Evaluating the size at this point for TYPENAME would |
| actually be incorrect, as we might be in the middle of an |
| expression with side effects on the pointed-to type size |
| "arguments" prior to the pointer declaration point and the |
| size evaluation could end up prior to the side effects. */ |
| |
| if (!TYPE_NAME (type) |
| && (decl_context == NORMAL || decl_context == FIELD) |
| && at_function_scope_p () |
| && variably_modified_type_p (type, NULL_TREE)) |
| { |
| TYPE_NAME (type) = build_decl (UNKNOWN_LOCATION, TYPE_DECL, |
| NULL_TREE, type); |
| add_decl_expr (TYPE_NAME (type)); |
| } |
| |
| if (declarator->kind == cdk_reference) |
| { |
| /* In C++0x, the type we are creating a reference to might be |
| a typedef which is itself a reference type. In that case, |
| we follow the reference collapsing rules in |
| [7.1.3/8 dcl.typedef] to create the final reference type: |
| |
| "If a typedef TD names a type that is a reference to a type |
| T, an attempt to create the type 'lvalue reference to cv TD' |
| creates the type 'lvalue reference to T,' while an attempt |
| to create the type "rvalue reference to cv TD' creates the |
| type TD." |
| */ |
| if (VOID_TYPE_P (type)) |
| /* We already gave an error. */; |
| else if (TYPE_REF_P (type)) |
| { |
| if (declarator->u.reference.rvalue_ref) |
| /* Leave type alone. */; |
| else |
| type = cp_build_reference_type (TREE_TYPE (type), false); |
| } |
| else |
| type = cp_build_reference_type |
| (type, declarator->u.reference.rvalue_ref); |
| |
| /* In C++0x, we need this check for direct reference to |
| reference declarations, which are forbidden by |
| [8.3.2/5 dcl.ref]. Reference to reference declarations |
| are only allowed indirectly through typedefs and template |
| type arguments. Example: |
| |
| void foo(int & &); // invalid ref-to-ref decl |
| |
| typedef int & int_ref; |
| void foo(int_ref &); // valid ref-to-ref decl |
| */ |
| if (inner_declarator && inner_declarator->kind == cdk_reference) |
| error ("cannot declare reference to %q#T, which is not " |
| "a typedef or a template type argument", type); |
| } |
| else if (TREE_CODE (type) == METHOD_TYPE) |
| type = build_ptrmemfunc_type (build_pointer_type (type)); |
| else if (declarator->kind == cdk_ptrmem) |
| { |
| gcc_assert (TREE_CODE (declarator->u.pointer.class_type) |
| != NAMESPACE_DECL); |
| if (declarator->u.pointer.class_type == error_mark_node) |
| /* We will already have complained. */ |
| type = error_mark_node; |
| else |
| type = build_ptrmem_type (declarator->u.pointer.class_type, |
| type); |
| } |
| else |
| type = build_pointer_type (type); |
| |
| /* Process a list of type modifier keywords (such as |
| const or volatile) that were given inside the `*' or `&'. */ |
| |
| if (declarator->u.pointer.qualifiers) |
| { |
| type |
| = cp_build_qualified_type (type, |
| declarator->u.pointer.qualifiers); |
| type_quals = cp_type_quals (type); |
| } |
| |
| /* Apply C++11 attributes to the pointer, and not to the |
| type pointed to. This is unlike what is done for GNU |
| attributes above. It is to comply with [dcl.ptr]/1: |
| |
| [the optional attribute-specifier-seq (7.6.1) appertains |
| to the pointer and not to the object pointed to]. */ |
| if (declarator->std_attributes) |
| decl_attributes (&type, declarator->std_attributes, |
| 0); |
| |
| ctype = NULL_TREE; |
| break; |
| |
| case cdk_error: |
| break; |
| |
| default: |
| gcc_unreachable (); |
| } |
| } |
| |
| /* A `constexpr' specifier used in an object declaration declares |
| the object as `const'. */ |
| if (constexpr_p && innermost_code != cdk_function) |
| { |
| /* DR1688 says that a `constexpr' specifier in combination with |
| `volatile' is valid. */ |
| |
| if (!TYPE_REF_P (type)) |
| { |
| type_quals |= TYPE_QUAL_CONST; |
| type = cp_build_qualified_type (type, type_quals); |
| } |
| } |
| |
| if (unqualified_id && TREE_CODE (unqualified_id) == TEMPLATE_ID_EXPR |
| && TREE_CODE (type) != FUNCTION_TYPE |
| && TREE_CODE (type) != METHOD_TYPE |
| && !variable_template_p (TREE_OPERAND (unqualified_id, 0))) |
| { |
| error ("template-id %qD used as a declarator", |
| unqualified_id); |
| unqualified_id = dname; |
| } |
| |
| /* If TYPE is a FUNCTION_TYPE, but the function name was explicitly |
| qualified with a class-name, turn it into a METHOD_TYPE, unless |
| we know that the function is static. We take advantage of this |
| opportunity to do other processing that pertains to entities |
| explicitly declared to be class members. Note that if DECLARATOR |
| is non-NULL, we know it is a cdk_id declarator; otherwise, we |
| would not have exited the loop above. */ |
| if (declarator |
| && declarator->kind == cdk_id |
| && declarator->u.id.qualifying_scope |
| && MAYBE_CLASS_TYPE_P (declarator->u.id.qualifying_scope)) |
| { |
| ctype = declarator->u.id.qualifying_scope; |
| ctype = TYPE_MAIN_VARIANT (ctype); |
| template_count = num_template_headers_for_class (ctype); |
| |
| if (ctype == current_class_type) |
| { |
| if (friendp) |
| { |
| permerror (input_location, "member functions are implicitly " |
| "friends of their class"); |
| friendp = 0; |
| } |
| else |
| permerror (declarator->id_loc, |
| "extra qualification %<%T::%> on member %qs", |
| ctype, name); |
| } |
| else if (/* If the qualifying type is already complete, then we |
| can skip the following checks. */ |
| !COMPLETE_TYPE_P (ctype) |
| && (/* If the function is being defined, then |
| qualifying type must certainly be complete. */ |
| funcdef_flag |
| /* A friend declaration of "T::f" is OK, even if |
| "T" is a template parameter. But, if this |
| function is not a friend, the qualifying type |
| must be a class. */ |
| || (!friendp && !CLASS_TYPE_P (ctype)) |
| /* For a declaration, the type need not be |
| complete, if either it is dependent (since there |
| is no meaningful definition of complete in that |
| case) or the qualifying class is currently being |
| defined. */ |
| || !(dependent_type_p (ctype) |
| || currently_open_class (ctype))) |
| /* Check that the qualifying type is complete. */ |
| && !complete_type_or_else (ctype, NULL_TREE)) |
| return error_mark_node; |
| else if (TREE_CODE (type) == FUNCTION_TYPE) |
| { |
| if (current_class_type |
| && (!friendp || funcdef_flag || initialized)) |
| { |
| error (funcdef_flag || initialized |
| ? G_("cannot define member function %<%T::%s%> " |
| "within %qT") |
| : G_("cannot declare member function %<%T::%s%> " |
| "within %qT"), |
| ctype, name, current_class_type); |
| return error_mark_node; |
| } |
| } |
| else if (typedef_p && current_class_type) |
| { |
| error ("cannot declare member %<%T::%s%> within %qT", |
| ctype, name, current_class_type); |
| return error_mark_node; |
| } |
| } |
| |
| if (ctype == NULL_TREE && decl_context == FIELD && friendp == 0) |
| ctype = current_class_type; |
| |
| /* Now TYPE has the actual type. */ |
| |
| if (returned_attrs) |
| { |
| if (attrlist) |
| *attrlist = chainon (returned_attrs, *attrlist); |
| else |
| attrlist = &returned_attrs; |
| } |
| |
| if (declarator |
| && declarator->kind == cdk_id |
| && declarator->std_attributes |
| && attrlist != NULL) |
| { |
| /* [dcl.meaning]/1: The optional attribute-specifier-seq following |
| a declarator-id appertains to the entity that is declared. */ |
| if (declarator->std_attributes != error_mark_node) |
| *attrlist = chainon (*attrlist, declarator->std_attributes); |
| else |
| /* We should have already diagnosed the issue (c++/78344). */ |
| gcc_assert (seen_error ()); |
| } |
| |
| /* Handle parameter packs. */ |
| if (parameter_pack_p) |
| { |
| if (decl_context == PARM) |
| /* Turn the type into a pack expansion.*/ |
| type = make_pack_expansion (type); |
| else |
| error ("non-parameter %qs cannot be a parameter pack", name); |
| } |
| |
| if ((decl_context == FIELD || decl_context == PARM) |
| && !processing_template_decl |
| && variably_modified_type_p (type, NULL_TREE)) |
| { |
| if (decl_context == FIELD) |
| error ("data member may not have variably modified type %qT", type); |
| else |
| error ("parameter may not have variably modified type %qT", type); |
| type = error_mark_node; |
| } |
| |
| if (explicitp == 1 || (explicitp && friendp)) |
| { |
| /* [dcl.fct.spec] (C++11) The explicit specifier shall be used only |
| in the declaration of a constructor or conversion function within |
| a class definition. */ |
| if (!current_class_type) |
| error_at (declspecs->locations[ds_explicit], |
| "%<explicit%> outside class declaration"); |
| else if (friendp) |
| error_at (declspecs->locations[ds_explicit], |
| "%<explicit%> in friend declaration"); |
| else |
| error_at (declspecs->locations[ds_explicit], |
| "only declarations of constructors and conversion operators " |
| "can be %<explicit%>"); |
| explicitp = 0; |
| } |
| |
| if (storage_class == sc_mutable) |
| { |
| location_t sloc = declspecs->locations[ds_storage_class]; |
| if (decl_context != FIELD || friendp) |
| { |
| error_at (sloc, "non-member %qs cannot be declared %<mutable%>", |
| name); |
| storage_class = sc_none; |
| } |
| else if (decl_context == TYPENAME || typedef_p) |
| { |
| error_at (sloc, |
| "non-object member %qs cannot be declared %<mutable%>", |
| name); |
| storage_class = sc_none; |
| } |
| else if (TREE_CODE (type) == FUNCTION_TYPE |
| || TREE_CODE (type) == METHOD_TYPE) |
| { |
| error_at (sloc, "function %qs cannot be declared %<mutable%>", |
| name); |
| storage_class = sc_none; |
| } |
| else if (staticp) |
| { |
| error_at (sloc, "%<static%> %qs cannot be declared %<mutable%>", |
| name); |
| storage_class = sc_none; |
| } |
| else if (type_quals & TYPE_QUAL_CONST) |
| { |
| error_at (sloc, "%<const%> %qs cannot be declared %<mutable%>", |
| name); |
| storage_class = sc_none; |
| } |
| else if (TYPE_REF_P (type)) |
| { |
| permerror (sloc, "reference %qs cannot be declared %<mutable%>", |
| name); |
| storage_class = sc_none; |
| } |
| } |
| |
| location_t loc = declarator ? declarator->id_loc : input_location; |
| |
| /* If this is declaring a typedef name, return a TYPE_DECL. */ |
| if (typedef_p && decl_context != TYPENAME) |
| { |
| bool alias_p = decl_spec_seq_has_spec_p (declspecs, ds_alias); |
| tree decl; |
| |
| /* This declaration: |
| |
| typedef void f(int) const; |
| |
| declares a function type which is not a member of any |
| particular class, but which is cv-qualified; for |
| example "f S::*" declares a pointer to a const-qualified |
| member function of S. We record the cv-qualification in the |
| function type. */ |
| if ((rqual || memfn_quals) && TREE_CODE (type) == FUNCTION_TYPE) |
| { |
| type = apply_memfn_quals (type, memfn_quals, rqual); |
| |
| /* We have now dealt with these qualifiers. */ |
| memfn_quals = TYPE_UNQUALIFIED; |
| rqual = REF_QUAL_NONE; |
| } |
| |
| if (type_uses_auto (type)) |
| { |
| if (alias_p) |
| error_at (declspecs->locations[ds_type_spec], |
| "%<auto%> not allowed in alias declaration"); |
| else |
| error_at (declspecs->locations[ds_type_spec], |
| "typedef declared %<auto%>"); |
| type = error_mark_node; |
| } |
| |
| if (reqs) |
| error_at (location_of (reqs), "requires-clause on typedef"); |
| |
| if (id_declarator && declarator->u.id.qualifying_scope) |
| { |
| error ("typedef name may not be a nested-name-specifier"); |
| type = error_mark_node; |
| } |
| |
| if (decl_context == FIELD) |
| decl = build_lang_decl_loc (loc, TYPE_DECL, unqualified_id, type); |
| else |
| decl = build_decl (loc, TYPE_DECL, unqualified_id, type); |
| |
| if (decl_context != FIELD) |
| { |
| if (!current_function_decl) |
| DECL_CONTEXT (decl) = FROB_CONTEXT (current_namespace); |
| else if (DECL_MAYBE_IN_CHARGE_CDTOR_P (current_function_decl)) |
| /* The TYPE_DECL is "abstract" because there will be |
| clones of this constructor/destructor, and there will |
| be copies of this TYPE_DECL generated in those |
| clones. The decloning optimization (for space) may |
| revert this subsequently if it determines that |
| the clones should share a common implementation. */ |
| DECL_ABSTRACT_P (decl) = true; |
| } |
| else if (current_class_type |
| && constructor_name_p (unqualified_id, current_class_type)) |
| permerror (input_location, "ISO C++ forbids nested type %qD with same name " |
| "as enclosing class", |
| unqualified_id); |
| |
| /* If the user declares "typedef struct {...} foo" then the |
| struct will have an anonymous name. Fill that name in now. |
| Nothing can refer to it, so nothing needs know about the name |
| change. */ |
| if (type != error_mark_node |
| && unqualified_id |
| && TYPE_NAME (type) |
| && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL |
| && TYPE_UNNAMED_P (type) |
| && declspecs->type_definition_p |
| && attributes_naming_typedef_ok (*attrlist) |
| && cp_type_quals (type) == TYPE_UNQUALIFIED) |
| name_unnamed_type (type, decl); |
| |
| if (signed_p |
| || (typedef_decl && C_TYPEDEF_EXPLICITLY_SIGNED (typedef_decl))) |
| C_TYPEDEF_EXPLICITLY_SIGNED (decl) = 1; |
| |
| bad_specifiers (decl, BSP_TYPE, virtualp, |
| memfn_quals != TYPE_UNQUALIFIED, |
| inlinep, friendp, raises != NULL_TREE, |
| declspecs->locations); |
| |
| if (alias_p) |
| /* Acknowledge that this was written: |
| `using analias = atype;'. */ |
| TYPE_DECL_ALIAS_P (decl) = 1; |
| |
| return decl; |
| } |
| |
| /* Detect the case of an array type of unspecified size |
| which came, as such, direct from a typedef name. |
| We must copy the type, so that the array's domain can be |
| individually set by the object's initializer. */ |
| |
| if (type && typedef_type |
| && TREE_CODE (type) == ARRAY_TYPE && !TYPE_DOMAIN (type) |
| && TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (typedef_type)) |
| type = build_cplus_array_type (TREE_TYPE (type), NULL_TREE); |
| |
| /* Detect where we're using a typedef of function type to declare a |
| function. PARMS will not be set, so we must create it now. */ |
| |
| if (type == typedef_type && TREE_CODE (type) == FUNCTION_TYPE) |
| { |
| tree decls = NULL_TREE; |
| tree args; |
| |
| for (args = TYPE_ARG_TYPES (type); |
| args && args != void_list_node; |
| args = TREE_CHAIN (args)) |
| { |
| tree decl = cp_build_parm_decl (NULL_TREE, NULL_TREE, |
| TREE_VALUE (args)); |
| |
| DECL_CHAIN (decl) = decls; |
| decls = decl; |
| } |
| |
| parms = nreverse (decls); |
| |
| if (decl_context != TYPENAME) |
| { |
| /* The qualifiers on the function type become the qualifiers on |
| the non-static member function. */ |
| memfn_quals |= type_memfn_quals (type); |
| rqual = type_memfn_rqual (type); |
| type_quals = TYPE_UNQUALIFIED; |
| raises = TYPE_RAISES_EXCEPTIONS (type); |
| } |
| } |
| |
| /* If this is a type name (such as, in a cast or sizeof), |
| compute the type and return it now. */ |
| |
| if (decl_context == TYPENAME) |
| { |
| /* Note that here we don't care about type_quals. */ |
| |
| /* Special case: "friend class foo" looks like a TYPENAME context. */ |
| if (friendp) |
| { |
| if (inlinep) |
| { |
| error ("%<inline%> specified for friend class declaration"); |
| inlinep = 0; |
| } |
| |
| if (!current_aggr) |
| { |
| /* Don't allow friend declaration without a class-key. */ |
| if (TREE_CODE (type) == TEMPLATE_TYPE_PARM) |
| permerror (input_location, "template parameters cannot be friends"); |
| else if (TREE_CODE (type) == TYPENAME_TYPE) |
| permerror (input_location, "friend declaration requires class-key, " |
| "i.e. %<friend class %T::%D%>", |
| TYPE_CONTEXT (type), TYPENAME_TYPE_FULLNAME (type)); |
| else |
| permerror (input_location, "friend declaration requires class-key, " |
| "i.e. %<friend %#T%>", |
| type); |
| } |
| |
| /* Only try to do this stuff if we didn't already give up. */ |
| if (type != integer_type_node) |
| { |
| /* A friendly class? */ |
| if (current_class_type) |
| make_friend_class (current_class_type, TYPE_MAIN_VARIANT (type), |
| /*complain=*/true); |
| else |
| error ("trying to make class %qT a friend of global scope", |
| type); |
| |
| type = void_type_node; |
| } |
| } |
| else if (memfn_quals || rqual) |
| { |
| if (ctype == NULL_TREE |
| && TREE_CODE (type) == METHOD_TYPE) |
| ctype = TYPE_METHOD_BASETYPE (type); |
| |
| if (ctype) |
| type = build_memfn_type (type, ctype, memfn_quals, rqual); |
| /* Core issue #547: need to allow this in template type args. |
| Allow it in general in C++11 for alias-declarations. */ |
| else if ((template_type_arg || cxx_dialect >= cxx11) |
| && TREE_CODE (type) == FUNCTION_TYPE) |
| type = apply_memfn_quals (type, memfn_quals, rqual); |
| else |
| error ("invalid qualifiers on non-member function type"); |
| } |
| |
| if (reqs) |
| error_at (location_of (reqs), "requires-clause on type-id"); |
| |
| return type; |
| } |
| else if (unqualified_id == NULL_TREE && decl_context != PARM |
| && decl_context != CATCHPARM |
| && TREE_CODE (type) != UNION_TYPE |
| && ! bitfield |
| && innermost_code != cdk_decomp) |
| { |
| error ("abstract declarator %qT used as declaration", type); |
| return error_mark_node; |
| } |
| |
| if (!FUNC_OR_METHOD_TYPE_P (type)) |
| { |
| /* Only functions may be declared using an operator-function-id. */ |
| if (dname && IDENTIFIER_ANY_OP_P (dname)) |
| { |
| error ("declaration of %qD as non-function", dname); |
| return error_mark_node; |
| } |
| |
| if (reqs) |
| error_at (location_of (reqs), |
| "requires-clause on declaration of non-function type %qT", |
| type); |
| } |
| |
| /* We don't check parameter types here because we can emit a better |
| error message later. */ |
| if (decl_context != PARM) |
| { |
| type = check_var_type (unqualified_id, type); |
| if (type == error_mark_node) |
| return error_mark_node; |
| } |
| |
| /* Now create the decl, which may be a VAR_DECL, a PARM_DECL |
| or a FUNCTION_DECL, depending on DECL_CONTEXT and TYPE. */ |
| |
| if (decl_context == PARM || decl_context == CATCHPARM) |
| { |
| if (ctype || in_namespace) |
| error ("cannot use %<::%> in parameter declaration"); |
| |
| if (type_uses_auto (type) |
| && !(cxx_dialect >= cxx17 && template_parm_flag)) |
| { |
| if (cxx_dialect >= cxx14) |
| error ("%<auto%> parameter not permitted in this context"); |
| else |
| error ("parameter declared %<auto%>"); |
| type = error_mark_node; |
| } |
| |
| /* A parameter declared as an array of T is really a pointer to T. |
| One declared as a function is really a pointer to a function. |
| One declared as a member is really a pointer to member. */ |
| |
| if (TREE_CODE (type) == ARRAY_TYPE) |
| { |
| /* Transfer const-ness of array into that of type pointed to. */ |
| type = build_pointer_type (TREE_TYPE (type)); |
| type_quals = TYPE_UNQUALIFIED; |
| array_parameter_p = true; |
| } |
| else if (TREE_CODE (type) == FUNCTION_TYPE) |
| type = build_pointer_type (type); |
| } |
| |
| if (ctype && TREE_CODE (type) == FUNCTION_TYPE && staticp < 2 |
| && !(unqualified_id |
| && identifier_p (unqualified_id) |
| && IDENTIFIER_NEWDEL_OP_P (unqualified_id))) |
| { |
| cp_cv_quals real_quals = memfn_quals; |
| if (cxx_dialect < cxx14 && constexpr_p |
| && sfk != sfk_constructor && sfk != sfk_destructor) |
| real_quals |= TYPE_QUAL_CONST; |
| type = build_memfn_type (type, ctype, real_quals, rqual); |
| } |
| |
| { |
| tree decl = NULL_TREE; |
| |
| if (decl_context == PARM) |
| { |
| decl = cp_build_parm_decl (NULL_TREE, unqualified_id, type); |
| DECL_ARRAY_PARAMETER_P (decl) = array_parameter_p; |
| |
| bad_specifiers (decl, BSP_PARM, virtualp, |
| memfn_quals != TYPE_UNQUALIFIED, |
| inlinep, friendp, raises != NULL_TREE, |
| declspecs->locations); |
| } |
| else if (decl_context == FIELD) |
| { |
| if (!staticp && !friendp && TREE_CODE (type) != METHOD_TYPE) |
| if (tree auto_node = type_uses_auto (type)) |
| { |
| location_t tloc = declspecs->locations[ds_type_spec]; |
| if (CLASS_PLACEHOLDER_TEMPLATE (auto_node)) |
| error_at (tloc, "invalid use of template-name %qE without an " |
| "argument list", |
| CLASS_PLACEHOLDER_TEMPLATE (auto_node)); |
| else |
| error_at (tloc, "non-static data member declared with " |
| "placeholder %qT", auto_node); |
| type = error_mark_node; |
| } |
| |
| /* The C99 flexible array extension. */ |
| if (!staticp && TREE_CODE (type) == ARRAY_TYPE |
| && TYPE_DOMAIN (type) == NULL_TREE) |
| { |
| if (ctype |
| && (TREE_CODE (ctype) == UNION_TYPE |
| || TREE_CODE (ctype) == QUAL_UNION_TYPE)) |
| { |
| error ("flexible array member in union"); |
| type = error_mark_node; |
| } |
| else |
| { |
| /* Array is a flexible member. */ |
| if (in_system_header_at (input_location)) |
| /* Do not warn on flexible array members in system |
| headers because glibc uses them. */; |
| else if (name && declarator) |
| pedwarn (declarator->id_loc, OPT_Wpedantic, |
| "ISO C++ forbids flexible array member %qs", name); |
| else |
| pedwarn (input_location, OPT_Wpedantic, |
| "ISO C++ forbids flexible array members"); |
| |
| /* Flexible array member has a null domain. */ |
| type = build_cplus_array_type (TREE_TYPE (type), NULL_TREE); |
| } |
| } |
| |
| if (type == error_mark_node) |
| { |
| /* Happens when declaring arrays of sizes which |
| are error_mark_node, for example. */ |
| decl = NULL_TREE; |
| } |
| else if (in_namespace && !friendp) |
| { |
| /* Something like struct S { int N::j; }; */ |
| error ("invalid use of %<::%>"); |
| return error_mark_node; |
| } |
| else if (FUNC_OR_METHOD_TYPE_P (type) && unqualified_id) |
| { |
| int publicp = 0; |
| tree function_context; |
| |
| if (friendp == 0) |
| { |
| /* This should never happen in pure C++ (the check |
| could be an assert). It could happen in |
| Objective-C++ if someone writes invalid code that |
| uses a function declaration for an instance |
| variable or property (instance variables and |
| properties are parsed as FIELD_DECLs, but they are |
| part of an Objective-C class, not a C++ class). |
| That code is invalid and is caught by this |
| check. */ |
| if (!ctype) |
| { |
| error ("declaration of function %qD in invalid context", |
| unqualified_id); |
| return error_mark_node; |
| } |
| |
| /* ``A union may [ ... ] not [ have ] virtual functions.'' |
| ARM 9.5 */ |
| if (virtualp && TREE_CODE (ctype) == UNION_TYPE) |
| { |
| error_at (declspecs->locations[ds_virtual], |
| "function %qD declared %<virtual%> inside a union", |
| unqualified_id); |
| return error_mark_node; |
| } |
| |
| if (virtualp |
| && identifier_p (unqualified_id) |
| && IDENTIFIER_NEWDEL_OP_P (unqualified_id)) |
| { |
| error_at (declspecs->locations[ds_virtual], |
| "%qD cannot be declared %<virtual%>, since it " |
| "is always static", unqualified_id); |
| virtualp = 0; |
| } |
| } |
| |
| /* Check that the name used for a destructor makes sense. */ |
| if (sfk == sfk_destructor) |
| { |
| tree uqname = id_declarator->u.id.unqualified_name; |
| |
| if (!ctype) |
| { |
| gcc_assert (friendp); |
| error ("expected qualified name in friend declaration " |
| "for destructor %qD", uqname); |
| return error_mark_node; |
| } |
| |
| if (!check_dtor_name (ctype, TREE_OPERAND (uqname, 0))) |
| { |
| error ("declaration of %qD as member of %qT", |
| uqname, ctype); |
| return error_mark_node; |
| } |
| if (concept_p) |
| { |
| error_at (declspecs->locations[ds_concept], |
| "a destructor cannot be %<concept%>"); |
| return error_mark_node; |
| } |
| if (constexpr_p) |
| { |
| error_at (declspecs->locations[ds_constexpr], |
| "a destructor cannot be %<constexpr%>"); |
| return error_mark_node; |
| } |
| } |
| else if (sfk == sfk_constructor && friendp && !ctype) |
| { |
| error ("expected qualified name in friend declaration " |
| "for constructor %qD", |
| id_declarator->u.id.unqualified_name); |
| return error_mark_node; |
| } |
| if (sfk == sfk_constructor) |
| if (concept_p) |
| { |
| error_at (declspecs->locations[ds_concept], |
| "a constructor cannot be %<concept%>"); |
| return error_mark_node; |
| } |
| if (concept_p) |
| { |
| error_at (declspecs->locations[ds_concept], |
| "a concept cannot be a member function"); |
| concept_p = false; |
| } |
| |
| if (TREE_CODE (unqualified_id) == TEMPLATE_ID_EXPR) |
| { |
| tree tmpl = TREE_OPERAND (unqualified_id, 0); |
| if (variable_template_p (tmpl)) |
| { |
| error ("specialization of variable template %qD " |
| "declared as function", tmpl); |
| inform (DECL_SOURCE_LOCATION (tmpl), |
| "variable template declared here"); |
| return error_mark_node; |
| } |
| } |
| |
| /* Tell grokfndecl if it needs to set TREE_PUBLIC on the node. */ |
| function_context = (ctype != NULL_TREE) ? |
| decl_function_context (TYPE_MAIN_DECL (ctype)) : NULL_TREE; |
| publicp = (! friendp || ! staticp) |
| && function_context == NULL_TREE; |
| |
| decl = grokfndecl (ctype, type, |
| TREE_CODE (unqualified_id) != TEMPLATE_ID_EXPR |
| ? unqualified_id : dname, |
| parms, |
| unqualified_id, |
| declspecs, |
| reqs, |
| virtualp, flags, memfn_quals, rqual, raises, |
| friendp ? -1 : 0, friendp, publicp, |
| inlinep | (2 * constexpr_p) | (4 * concept_p), |
| initialized == SD_DELETED, sfk, |
| funcdef_flag, late_return_type_p, |
| template_count, in_namespace, |
| attrlist, declarator->id_loc); |
| decl = set_virt_specifiers (decl, virt_specifiers); |
| if (decl == NULL_TREE) |
| return error_mark_node; |
| #if 0 |
| /* This clobbers the attrs stored in `decl' from `attrlist'. */ |
| /* The decl and setting of decl_attr is also turned off. */ |
| decl = build_decl_attribute_variant (decl, decl_attr); |
| #endif |
| |
| /* [class.conv.ctor] |
| |
| A constructor declared without the function-specifier |
| explicit that can be called with a single parameter |
| specifies a conversion from the type of its first |
| parameter to the type of its class. Such a constructor |
| is called a converting constructor. */ |
| if (explicitp == 2) |
| DECL_NONCONVERTING_P (decl) = 1; |
| |
| if (declspecs->explicit_specifier) |
| store_explicit_specifier (decl, declspecs->explicit_specifier); |
| } |
| else if (!staticp && !dependent_type_p (type) |
| && !COMPLETE_TYPE_P (complete_type (type)) |
| && (!complete_or_array_type_p (type) |
| || initialized == 0)) |
| { |
| if (TREE_CODE (type) != ARRAY_TYPE |
| || !COMPLETE_TYPE_P (TREE_TYPE (type))) |
| { |
| if (unqualified_id) |
| { |
| error_at (declarator->id_loc, |
| "field %qD has incomplete type %qT", |
| unqualified_id, type); |
| cxx_incomplete_type_inform (strip_array_types (type)); |
| } |
| else |
| error ("name %qT has incomplete type", type); |
| |
| type = error_mark_node; |
| decl = NULL_TREE; |
| } |
| } |
| else |
| { |
| if (friendp) |
| { |
| if (unqualified_id && declarator) |
| error_at (declarator->id_loc, |
| "%qE is neither function nor member function; " |
| "cannot be declared friend", unqualified_id); |
| else |
| error ("unnamed field is neither function nor member " |
| "function; cannot be declared friend"); |
| return error_mark_node; |
| } |
| decl = NULL_TREE; |
| } |
| |
| if (friendp) |
| { |
| /* Friends are treated specially. */ |
| if (ctype == current_class_type) |
| ; /* We already issued a permerror. */ |
| else if (decl && DECL_NAME (decl)) |
| { |
| if (template_class_depth (current_class_type) == 0) |
| { |
| decl = check_explicit_specialization |
| (unqualified_id, decl, template_count, |
| 2 * funcdef_flag + 4); |
| if (decl == error_mark_node) |
| return error_mark_node; |
| } |
| |
| decl = do_friend (ctype, unqualified_id, decl, |
| *attrlist, flags, |
| funcdef_flag); |
| return decl; |
| } |
| else |
| return error_mark_node; |
| } |
| |
| /* Structure field. It may not be a function, except for C++. */ |
| |
| if (decl == NULL_TREE) |
| { |
| if (staticp) |
| { |
| /* C++ allows static class members. All other work |
| for this is done by grokfield. */ |
| decl = build_lang_decl_loc (loc, VAR_DECL, |
| unqualified_id, type); |
| set_linkage_for_static_data_member (decl); |
| if (concept_p) |
| error_at (declspecs->locations[ds_concept], |
| "static data member %qE declared %<concept%>", |
| unqualified_id); |
| else if (constexpr_p && !initialized) |
| { |
| error_at (DECL_SOURCE_LOCATION (decl), |
| "%<constexpr%> static data member %qD must " |
| "have an initializer", decl); |
| constexpr_p = false; |
| } |
| |
| if (inlinep) |
| mark_inline_variable (decl, declspecs->locations[ds_inline]); |
| |
| if (!DECL_VAR_DECLARED_INLINE_P (decl) |
| && !(cxx_dialect >= cxx17 && constexpr_p)) |
| /* Even if there is an in-class initialization, DECL |
| is considered undefined until an out-of-class |
| definition is provided, unless this is an inline |
| variable. */ |
| DECL_EXTERNAL (decl) = 1; |
| |
| if (thread_p) |
| { |
| CP_DECL_THREAD_LOCAL_P (decl) = true; |
| if (!processing_template_decl) |
| set_decl_tls_model (decl, decl_default_tls_model (decl)); |
| if (declspecs->gnu_thread_keyword_p) |
| SET_DECL_GNU_TLS_P (decl); |
| } |
| } |
| else |
| { |
| if (concept_p) |
| error_at (declspecs->locations[ds_concept], |
| "non-static data member %qE declared %<concept%>", |
| unqualified_id); |
| else if (constexpr_p) |
| { |
| error_at (declspecs->locations[ds_constexpr], |
| "non-static data member %qE declared %<constexpr%>", |
| unqualified_id); |
| constexpr_p = false; |
| } |
| decl = build_decl (loc, FIELD_DECL, unqualified_id, type); |
| DECL_NONADDRESSABLE_P (decl) = bitfield; |
| if (bitfield && !unqualified_id) |
| { |
| TREE_NO_WARNING (decl) = 1; |
| DECL_PADDING_P (decl) = 1; |
| } |
| |
| if (storage_class == sc_mutable) |
| { |
| DECL_MUTABLE_P (decl) = 1; |
| storage_class = sc_none; |
| } |
| |
| if (initialized) |
| { |
| /* An attempt is being made to initialize a non-static |
| member. This is new in C++11. */ |
| maybe_warn_cpp0x (CPP0X_NSDMI); |
| |
| /* If this has been parsed with static storage class, but |
| errors forced staticp to be cleared, ensure NSDMI is |
| not present. */ |
| if (declspecs->storage_class == sc_static) |
| DECL_INITIAL (decl) = error_mark_node; |
| } |
| } |
| |
| bad_specifiers (decl, BSP_FIELD, virtualp, |
| memfn_quals != TYPE_UNQUALIFIED, |
| staticp ? false : inlinep, friendp, |
| raises != NULL_TREE, |
| declspecs->locations); |
| } |
| } |
| else if (TREE_CODE (type) == FUNCTION_TYPE |
| || TREE_CODE (type) == METHOD_TYPE) |
| { |
| tree original_name; |
| int publicp = 0; |
| |
| if (!unqualified_id) |
| return error_mark_node; |
| |
| if (TREE_CODE (unqualified_id) == TEMPLATE_ID_EXPR) |
| original_name = dname; |
| else |
| original_name = unqualified_id; |
| // FIXME:gcc_assert (original_name == dname); |
| |
| if (storage_class == sc_auto) |
| error ("storage class %<auto%> invalid for function %qs", name); |
| else if (storage_class == sc_register) |
| error ("storage class %<register%> invalid for function %qs", name); |
| else if (thread_p) |
| { |
| if (declspecs->gnu_thread_keyword_p) |
| error_at (declspecs->locations[ds_thread], |
| "storage class %<__thread%> invalid for function %qs", |
| name); |
| else |
| error_at (declspecs->locations[ds_thread], |
| "storage class %<thread_local%> invalid for " |
| "function %qs", name); |
| } |
| |
| if (virt_specifiers) |
| error ("virt-specifiers in %qs not allowed outside a class " |
| "definition", name); |
| /* Function declaration not at top level. |
| Storage classes other than `extern' are not allowed |
| and `extern' makes no difference. */ |
| if (! toplevel_bindings_p () |
| && (storage_class == sc_static |
| || decl_spec_seq_has_spec_p (declspecs, ds_inline)) |
| && pedantic) |
| { |
| if (storage_class == sc_static) |
| pedwarn (declspecs->locations[ds_storage_class], OPT_Wpedantic, |
| "%<static%> specifier invalid for function %qs " |
| "declared out of global scope", name); |
| else |
| pedwarn (declspecs->locations[ds_inline], OPT_Wpedantic, |
| "%<inline%> specifier invalid for function %qs " |
| "declared out of global scope", name); |
| } |
| |
| if (ctype == NULL_TREE) |
| { |
| if (virtualp) |
| { |
| error ("virtual non-class function %qs", name); |
| virtualp = 0; |
| } |
| else if (sfk == sfk_constructor |
| || sfk == sfk_destructor) |
| { |
| error (funcdef_flag |
| ? G_("%qs defined in a non-class scope") |
| : G_("%qs declared in a non-class scope"), name); |
| sfk = sfk_none; |
| } |
| } |
| |
| /* Record whether the function is public. */ |
| publicp = (ctype != NULL_TREE |
| || storage_class != sc_static); |
| |
| decl = grokfndecl (ctype, type, original_name, parms, unqualified_id, |
| declspecs, |
| reqs, virtualp, flags, memfn_quals, rqual, raises, |
| 1, friendp, |
| publicp, |
| inlinep | (2 * constexpr_p) | (4 * concept_p), |
| initialized == SD_DELETED, |
| sfk, |
| funcdef_flag, |
| late_return_type_p, |
| template_count, in_namespace, attrlist, |
| declarator->id_loc); |
| if (decl == NULL_TREE) |
| return error_mark_node; |
| |
| if (explicitp == 2) |
| DECL_NONCONVERTING_P (decl) = 1; |
| if (staticp == 1) |
| { |
| int invalid_static = 0; |
| |
| /* Don't allow a static member function in a class, and forbid |
| declaring main to be static. */ |
| if (TREE_CODE (type) == METHOD_TYPE) |
| { |
| permerror (input_location, "cannot declare member function %qD to have " |
| "static linkage", decl); |
| invalid_static = 1; |
| } |
| else if (current_function_decl) |
| { |
| /* 7.1.1: There can be no static function declarations within a |
| block. */ |
| error_at (declspecs->locations[ds_storage_class], |
| "cannot declare static function inside another function"); |
| invalid_static = 1; |
| } |
| |
| if (invalid_static) |
| { |
| staticp = 0; |
| storage_class = sc_none; |
| } |
| } |
| } |
| else |
| { |
| /* It's a variable. */ |
| |
| /* An uninitialized decl with `extern' is a reference. */ |
| decl = grokvardecl (type, dname, unqualified_id, |
| declspecs, |
| initialized, |
| type_quals, |
| inlinep, |
| concept_p, |
| template_count, |
| ctype ? ctype : in_namespace, |
| loc); |
| if (decl == NULL_TREE) |
| return error_mark_node; |
| |
| bad_specifiers (decl, BSP_VAR, virtualp, |
| memfn_quals != TYPE_UNQUALIFIED, |
| inlinep, friendp, raises != NULL_TREE, |
| declspecs->locations); |
| |
| if (ctype) |
| { |
| DECL_CONTEXT (decl) = ctype; |
| if (staticp == 1) |
| { |
| permerror (declspecs->locations[ds_storage_class], |
| "%<static%> may not be used when defining " |
| "(as opposed to declaring) a static data member"); |
| staticp = 0; |
| storage_class = sc_none; |
| } |
| if (storage_class == sc_register && TREE_STATIC (decl)) |
| { |
| error ("static member %qD declared %<register%>", decl); |
| storage_class = sc_none; |
| } |
| if (storage_class == sc_extern && pedantic) |
| { |
| pedwarn (input_location, OPT_Wpedantic, |
| "cannot explicitly declare member %q#D to have " |
| "extern linkage", decl); |
| storage_class = sc_none; |
| } |
| } |
| else if (constexpr_p && DECL_EXTERNAL (decl)) |
| { |
| error_at (DECL_SOURCE_LOCATION (decl), |
| "declaration of %<constexpr%> variable %qD " |
| "is not a definition", decl); |
| constexpr_p = false; |
| } |
| |
| if (inlinep) |
| mark_inline_variable (decl, declspecs->locations[ds_inline]); |
| if (innermost_code == cdk_decomp) |
| { |
| gcc_assert (declarator && declarator->kind == cdk_decomp); |
| DECL_SOURCE_LOCATION (decl) = declarator->id_loc; |
| DECL_ARTIFICIAL (decl) = 1; |
| fit_decomposition_lang_decl (decl, NULL_TREE); |
| } |
| } |
| |
| if (VAR_P (decl) && !initialized) |
| if (tree auto_node = type_uses_auto (type)) |
| if (!CLASS_PLACEHOLDER_TEMPLATE (auto_node)) |
| { |
| location_t loc = declspecs->locations[ds_type_spec]; |
| error_at (loc, "declaration of %q#D has no initializer", decl); |
| TREE_TYPE (decl) = error_mark_node; |
| } |
| |
| if (storage_class == sc_extern && initialized && !funcdef_flag) |
| { |
| if (toplevel_bindings_p ()) |
| { |
| /* It's common practice (and completely valid) to have a const |
| be initialized and declared extern. */ |
| if (!(type_quals & TYPE_QUAL_CONST)) |
| warning_at (DECL_SOURCE_LOCATION (decl), 0, |
| "%qs initialized and declared %<extern%>", name); |
| } |
| else |
| { |
| error_at (DECL_SOURCE_LOCATION (decl), |
| "%qs has both %<extern%> and initializer", name); |
| return error_mark_node; |
| } |
| } |
| |
| /* Record `register' declaration for warnings on & |
| and in case doing stupid register allocation. */ |
| |
| if (storage_class == sc_register) |
| { |
| DECL_REGISTER (decl) = 1; |
| /* Warn about register storage specifiers on PARM_DECLs. */ |
| if (TREE_CODE (decl) == PARM_DECL) |
| { |
| if (cxx_dialect >= cxx17) |
| pedwarn (DECL_SOURCE_LOCATION (decl), OPT_Wregister, |
| "ISO C++17 does not allow %<register%> storage " |
| "class specifier"); |
| else |
| warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wregister, |
| "%<register%> storage class specifier used"); |
| } |
| } |
| else if (storage_class == sc_extern) |
| DECL_THIS_EXTERN (decl) = 1; |
| else if (storage_class == sc_static) |
| DECL_THIS_STATIC (decl) = 1; |
| |
| /* Set constexpr flag on vars (functions got it in grokfndecl). */ |
| if (constexpr_p && VAR_P (decl)) |
| DECL_DECLARED_CONSTEXPR_P (decl) = true; |
| |
| /* Record constancy and volatility on the DECL itself . There's |
| no need to do this when processing a template; we'll do this |
| for the instantiated declaration based on the type of DECL. */ |
| if (!processing_template_decl) |
| cp_apply_type_quals_to_decl (type_quals, decl); |
| |
| return decl; |
| } |
| } |
| |
| /* Subroutine of start_function. Ensure that each of the parameter |
| types (as listed in PARMS) is complete, as is required for a |
| function definition. */ |
| |
| static void |
| require_complete_types_for_parms (tree parms) |
| { |
| for (; parms; parms = DECL_CHAIN (parms)) |
| { |
| if (dependent_type_p (TREE_TYPE (parms))) |
| continue; |
| if (!VOID_TYPE_P (TREE_TYPE (parms)) |
| && complete_type_or_else (TREE_TYPE (parms), parms)) |
| { |
| relayout_decl (parms); |
| DECL_ARG_TYPE (parms) = type_passed_as (TREE_TYPE (parms)); |
| |
| maybe_warn_parm_abi (TREE_TYPE (parms), |
| DECL_SOURCE_LOCATION (parms)); |
| } |
| else |
| /* grokparms or complete_type_or_else will have already issued |
| an error. */ |
| TREE_TYPE (parms) = error_mark_node; |
| } |
| } |
| |
| /* Returns nonzero if T is a local variable. */ |
| |
| int |
| local_variable_p (const_tree t) |
| { |
| if ((VAR_P (t) |
| /* A VAR_DECL with a context that is a _TYPE is a static data |
| member. */ |
| && !TYPE_P (CP_DECL_CONTEXT (t)) |
| /* Any other non-local variable must be at namespace scope. */ |
| && !DECL_NAMESPACE_SCOPE_P (t)) |
| || (TREE_CODE (t) == PARM_DECL)) |
| return 1; |
| |
| return 0; |
| } |
| |
| /* Like local_variable_p, but suitable for use as a tree-walking |
| function. */ |
| |
| static tree |
| local_variable_p_walkfn (tree *tp, int *walk_subtrees, |
| void * /*data*/) |
| { |
| if (local_variable_p (*tp) |
| && (!DECL_ARTIFICIAL (*tp) || DECL_NAME (*tp) == this_identifier)) |
| return *tp; |
| else if (TYPE_P (*tp)) |
| *walk_subtrees = 0; |
| |
| return NULL_TREE; |
| } |
| |
| /* Check that ARG, which is a default-argument expression for a |
| parameter DECL, is valid. Returns ARG, or ERROR_MARK_NODE, if |
| something goes wrong. DECL may also be a _TYPE node, rather than a |
| DECL, if there is no DECL available. */ |
| |
| tree |
| check_default_argument (tree decl, tree arg, tsubst_flags_t complain) |
| { |
| tree var; |
| tree decl_type; |
| |
| if (TREE_CODE (arg) == DEFAULT_ARG) |
| /* We get a DEFAULT_ARG when looking at an in-class declaration |
| with a default argument. Ignore the argument for now; we'll |
| deal with it after the class is complete. */ |
| return arg; |
| |
| if (TYPE_P (decl)) |
| { |
| decl_type = decl; |
| decl = NULL_TREE; |
| } |
| else |
| decl_type = TREE_TYPE (decl); |
| |
| if (arg == error_mark_node |
| || decl == error_mark_node |
| || TREE_TYPE (arg) == error_mark_node |
| || decl_type == error_mark_node) |
| /* Something already went wrong. There's no need to check |
| further. */ |
| return error_mark_node; |
| |
| /* [dcl.fct.default] |
| |
| A default argument expression is implicitly converted to the |
| parameter type. */ |
| ++cp_unevaluated_operand; |
| /* Avoid digest_init clobbering the initializer. */ |
| tree carg = BRACE_ENCLOSED_INITIALIZER_P (arg) ? unshare_expr (arg): arg; |
| perform_implicit_conversion_flags (decl_type, carg, complain, |
| LOOKUP_IMPLICIT); |
| --cp_unevaluated_operand; |
| |
| /* Avoid redundant -Wzero-as-null-pointer-constant warnings at |
| the call sites. */ |
| if (TYPE_PTR_OR_PTRMEM_P (decl_type) |
| && null_ptr_cst_p (arg) |
| /* Don't lose side-effects as in PR90473. */ |
| && !TREE_SIDE_EFFECTS (arg)) |
| return nullptr_node; |
| |
| /* [dcl.fct.default] |
| |
| Local variables shall not be used in default argument |
| expressions. |
| |
| The keyword `this' shall not be used in a default argument of a |
| member function. */ |
| var = cp_walk_tree_without_duplicates (&arg, local_variable_p_walkfn, NULL); |
| if (var) |
| { |
| if (complain & tf_warning_or_error) |
| { |
| if (DECL_NAME (var) == this_identifier) |
| permerror (input_location, "default argument %qE uses %qD", |
| arg, var); |
| else |
| error ("default argument %qE uses local variable %qD", arg, var); |
| } |
| return error_mark_node; |
| } |
| |
| /* All is well. */ |
| return arg; |
| } |
| |
| /* Returns a deprecated type used within TYPE, or NULL_TREE if none. */ |
| |
| static tree |
| type_is_deprecated (tree type) |
| { |
| enum tree_code code; |
| if (TREE_DEPRECATED (type)) |
| return type; |
| if (TYPE_NAME (type)) |
| { |
| if (TREE_DEPRECATED (TYPE_NAME (type))) |
| return type; |
| else |
| return NULL_TREE; |
| } |
| |
| /* Do warn about using typedefs to a deprecated class. */ |
| if (OVERLOAD_TYPE_P (type) && type != TYPE_MAIN_VARIANT (type)) |
| return type_is_deprecated (TYPE_MAIN_VARIANT (type)); |
| |
| code = TREE_CODE (type); |
| |
| if (code == POINTER_TYPE || code == REFERENCE_TYPE |
| || code == OFFSET_TYPE || code == FUNCTION_TYPE |
| || code == METHOD_TYPE || code == ARRAY_TYPE) |
| return type_is_deprecated (TREE_TYPE (type)); |
| |
| if (TYPE_PTRMEMFUNC_P (type)) |
| return type_is_deprecated |
| (TREE_TYPE (TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (type)))); |
| |
| return NULL_TREE; |
| } |
| |
| /* Decode the list of parameter types for a function type. |
| Given the list of things declared inside the parens, |
| return a list of types. |
| |
| If this parameter does not end with an ellipsis, we append |
| void_list_node. |
| |
| *PARMS is set to the chain of PARM_DECLs created. */ |
| |
| tree |
| grokparms (tree parmlist, tree *parms) |
| { |
| tree result = NULL_TREE; |
| tree decls = NULL_TREE; |
| tree parm; |
| int any_error = 0; |
| |
| for (parm = parmlist; parm != NULL_TREE; parm = TREE_CHAIN (parm)) |
| { |
| tree type = NULL_TREE; |
| tree init = TREE_PURPOSE (parm); |
| tree decl = TREE_VALUE (parm); |
| |
| if (parm == void_list_node) |
| break; |
| |
| if (! decl || TREE_TYPE (decl) == error_mark_node) |
| continue; |
| |
| type = TREE_TYPE (decl); |
| if (VOID_TYPE_P (type)) |
| { |
| if (same_type_p (type, void_type_node) |
| && !init |
| && !DECL_NAME (decl) && !result |
| && TREE_CHAIN (parm) == void_list_node) |
| /* DR 577: A parameter list consisting of a single |
| unnamed parameter of non-dependent type 'void'. */ |
| break; |
| else if (cv_qualified_p (type)) |
| error_at (DECL_SOURCE_LOCATION (decl), |
| "invalid use of cv-qualified type %qT in " |
| "parameter declaration", type); |
| else |
| error_at (DECL_SOURCE_LOCATION (decl), |
| "invalid use of type %<void%> in parameter " |
| "declaration"); |
| /* It's not a good idea to actually create parameters of |
| type `void'; other parts of the compiler assume that a |
| void type terminates the parameter list. */ |
| type = error_mark_node; |
| TREE_TYPE (decl) = error_mark_node; |
| } |
| |
| if (type != error_mark_node) |
| { |
| if (deprecated_state != DEPRECATED_SUPPRESS) |
| { |
| tree deptype = type_is_deprecated (type); |
| if (deptype) |
| cp_warn_deprecated_use (deptype); |
| } |
| |
| /* Top-level qualifiers on the parameters are |
| ignored for function types. */ |
| type = cp_build_qualified_type (type, 0); |
| if (TREE_CODE (type) == METHOD_TYPE) |
| { |
| error ("parameter %qD invalidly declared method type", decl); |
| type = build_pointer_type (type); |
| TREE_TYPE (decl) = type; |
| } |
| else if (abstract_virtuals_error (decl, type)) |
| any_error = 1; /* Seems like a good idea. */ |
| else if (cxx_dialect < cxx17 && INDIRECT_TYPE_P (type)) |
| { |
| /* Before C++17 DR 393: |
| [dcl.fct]/6, parameter types cannot contain pointers |
| (references) to arrays of unknown bound. */ |
| tree t = TREE_TYPE (type); |
| int ptr = TYPE_PTR_P (type); |
| |
| while (1) |
| { |
| if (TYPE_PTR_P (t)) |
| ptr = 1; |
| else if (TREE_CODE (t) != ARRAY_TYPE) |
| break; |
| else if (!TYPE_DOMAIN (t)) |
| break; |
| t = TREE_TYPE (t); |
| } |
| if (TREE_CODE (t) == ARRAY_TYPE) |
| pedwarn (DECL_SOURCE_LOCATION (decl), OPT_Wpedantic, |
| ptr |
| ? G_("parameter %qD includes pointer to array of " |
| "unknown bound %qT") |
| : G_("parameter %qD includes reference to array of " |
| "unknown bound %qT"), |
| decl, t); |
| } |
| |
| if (any_error) |
| init = NULL_TREE; |
| else if (init && !processing_template_decl) |
| init = check_default_argument (decl, init, tf_warning_or_error); |
| } |
| |
| DECL_CHAIN (decl) = decls; |
| decls = decl; |
| result = tree_cons (init, type, result); |
| } |
| decls = nreverse (decls); |
| result = nreverse (result); |
| if (parm) |
| result = chainon (result, void_list_node); |
| *parms = decls; |
| |
| return result; |
| } |
| |
| |
| /* D is a constructor or overloaded `operator='. |
| |
| Let T be the class in which D is declared. Then, this function |
| returns: |
| |
| -1 if D's is an ill-formed constructor or copy assignment operator |
| whose first parameter is of type `T'. |
| 0 if D is not a copy constructor or copy assignment |
| operator. |
| 1 if D is a copy constructor or copy assignment operator whose |
| first parameter is a reference to non-const qualified T. |
| 2 if D is a copy constructor or copy assignment operator whose |
| first parameter is a reference to const qualified T. |
| |
| This function can be used as a predicate. Positive values indicate |
| a copy constructor and nonzero values indicate a copy assignment |
| operator. */ |
| |
| int |
| copy_fn_p (const_tree d) |
| { |
| tree args; |
| tree arg_type; |
| int result = 1; |
| |
| gcc_assert (DECL_FUNCTION_MEMBER_P (d)); |
| |
| if (TREE_CODE (d) == TEMPLATE_DECL |
| || (DECL_TEMPLATE_INFO (d) |
| && DECL_MEMBER_TEMPLATE_P (DECL_TI_TEMPLATE (d)))) |
| /* Instantiations of template member functions are never copy |
| functions. Note that member functions of templated classes are |
| represented as template functions internally, and we must |
| accept those as copy functions. */ |
| return 0; |
| |
| args = FUNCTION_FIRST_USER_PARMTYPE (d); |
| if (!args) |
| return 0; |
| |
| arg_type = TREE_VALUE (args); |
| if (arg_type == error_mark_node) |
| return 0; |
| |
| if (TYPE_MAIN_VARIANT (arg_type) == DECL_CONTEXT (d)) |
| { |
| /* Pass by value copy assignment operator. */ |
| result = -1; |
| } |
| else if (TYPE_REF_P (arg_type) |
| && !TYPE_REF_IS_RVALUE (arg_type) |
| && TYPE_MAIN_VARIANT (TREE_TYPE (arg_type)) == DECL_CONTEXT (d)) |
| { |
| if (CP_TYPE_CONST_P (TREE_TYPE (arg_type))) |
| result = 2; |
| } |
| else |
| return 0; |
| |
| args = TREE_CHAIN (args); |
| |
| if (args && args != void_list_node && !TREE_PURPOSE (args)) |
| /* There are more non-optional args. */ |
| return 0; |
| |
| return result; |
| } |
| |
| /* D is a constructor or overloaded `operator='. |
| |
| Let T be the class in which D is declared. Then, this function |
| returns true when D is a move constructor or move assignment |
| operator, false otherwise. */ |
| |
| bool |
| move_fn_p (const_tree d) |
| { |
| gcc_assert (DECL_FUNCTION_MEMBER_P (d)); |
| |
| if (cxx_dialect == cxx98) |
| /* There are no move constructors if we are in C++98 mode. */ |
| return false; |
| |
| if (TREE_CODE (d) == TEMPLATE_DECL |
| || (DECL_TEMPLATE_INFO (d) |
| && DECL_MEMBER_TEMPLATE_P (DECL_TI_TEMPLATE (d)))) |
| /* Instantiations of template member functions are never move |
| functions. Note that member functions of templated classes are |
| represented as template functions internally, and we must |
| accept those as move functions. */ |
| return 0; |
| |
| return move_signature_fn_p (d); |
| } |
| |
| /* D is a constructor or overloaded `operator='. |
| |
| Then, this function returns true when D has the same signature as a move |
| constructor or move assignment operator (because either it is such a |
| ctor/op= or it is a template specialization with the same signature), |
| false otherwise. */ |
| |
| bool |
| move_signature_fn_p (const_tree d) |
| { |
| tree args; |
| tree arg_type; |
| bool result = false; |
| |
| args = FUNCTION_FIRST_USER_PARMTYPE (d); |
| if (!args) |
| return 0; |
| |
| arg_type = TREE_VALUE (args); |
| if (arg_type == error_mark_node) |
| return 0; |
| |
| if (TYPE_REF_P (arg_type) |
| && TYPE_REF_IS_RVALUE (arg_type) |
| && same_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (arg_type)), |
| DECL_CONTEXT (d))) |
| result = true; |
| |
| args = TREE_CHAIN (args); |
| |
| if (args && args != void_list_node && !TREE_PURPOSE (args)) |
| /* There are more non-optional args. */ |
| return false; |
| |
| return result; |
| } |
| |
| /* Remember any special properties of member function DECL. */ |
| |
| void |
| grok_special_member_properties (tree decl) |
| { |
| tree class_type; |
| |
| if (TREE_CODE (decl) == USING_DECL |
| || !DECL_NONSTATIC_MEMBER_FUNCTION_P (decl)) |
| return; |
| |
| class_type = DECL_CONTEXT (decl); |
| if (IDENTIFIER_CTOR_P (DECL_NAME (decl))) |
| { |
| int ctor = copy_fn_p (decl); |
| |
| if (!DECL_ARTIFICIAL (decl)) |
| TYPE_HAS_USER_CONSTRUCTOR (class_type) = 1; |
| |
| if (ctor > 0) |
| { |
| /* [class.copy] |
| |
| A non-template constructor for class X is a copy |
| constructor if its first parameter is of type X&, const |
| X&, volatile X& or const volatile X&, and either there |
| are no other parameters or else all other parameters have |
| default arguments. */ |
| TYPE_HAS_COPY_CTOR (class_type) = 1; |
| if (user_provided_p (decl)) |
| TYPE_HAS_COMPLEX_COPY_CTOR (class_type) = 1; |
| if (ctor > 1) |
| TYPE_HAS_CONST_COPY_CTOR (class_type) = 1; |
| } |
| else if (sufficient_parms_p (FUNCTION_FIRST_USER_PARMTYPE (decl))) |
| TYPE_HAS_DEFAULT_CONSTRUCTOR (class_type) = 1; |
| else if (move_fn_p (decl) && user_provided_p (decl)) |
| TYPE_HAS_COMPLEX_MOVE_CTOR (class_type) = 1; |
| else if (is_list_ctor (decl)) |
| TYPE_HAS_LIST_CTOR (class_type) = 1; |
| |
| if (DECL_DECLARED_CONSTEXPR_P (decl) |
| && !ctor && !move_fn_p (decl)) |
| TYPE_HAS_CONSTEXPR_CTOR (class_type) = 1; |
| } |
| else if (DECL_NAME (decl) == assign_op_identifier) |
| { |
| /* [class.copy] |
| |
| A non-template assignment operator for class X is a copy |
| assignment operator if its parameter is of type X, X&, const |
| X&, volatile X& or const volatile X&. */ |
| |
| int assop = copy_fn_p (decl); |
| |
| if (assop) |
| { |
| TYPE_HAS_COPY_ASSIGN (class_type) = 1; |
| if (user_provided_p (decl)) |
| TYPE_HAS_COMPLEX_COPY_ASSIGN (class_type) = 1; |
| if (assop != 1) |
| TYPE_HAS_CONST_COPY_ASSIGN (class_type) = 1; |
| } |
| else if (move_fn_p (decl) && user_provided_p (decl)) |
| TYPE_HAS_COMPLEX_MOVE_ASSIGN (class_type) = 1; |
| } |
| else if (IDENTIFIER_CONV_OP_P (DECL_NAME (decl))) |
| TYPE_HAS_CONVERSION (class_type) = true; |
| |
| /* Destructors are handled in check_methods. */ |
| } |
| |
| /* Check a constructor DECL has the correct form. Complains |
| if the class has a constructor of the form X(X). */ |
| |
| bool |
| grok_ctor_properties (const_tree ctype, const_tree decl) |
| { |
| int ctor_parm = copy_fn_p (decl); |
| |
| if (ctor_parm < 0) |
| { |
| /* [class.copy] |
| |
| A declaration of a constructor for a class X is ill-formed if |
| its first parameter is of type (optionally cv-qualified) X |
| and either there are no other parameters or else all other |
| parameters have default arguments. |
| |
| We *don't* complain about member template instantiations that |
| have this form, though; they can occur as we try to decide |
| what constructor to use during overload resolution. Since |
| overload resolution will never prefer such a constructor to |
| the non-template copy constructor (which is either explicitly |
| or implicitly defined), there's no need to worry about their |
| existence. Theoretically, they should never even be |
| instantiated, but that's hard to forestall. */ |
| error ("invalid constructor; you probably meant %<%T (const %T&)%>", |
| ctype, ctype); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| /* DECL is a declaration for an overloaded or conversion operator. If |
| COMPLAIN is true, errors are issued for invalid declarations. */ |
| |
| bool |
| grok_op_properties (tree decl, bool complain) |
| { |
| tree argtypes = TYPE_ARG_TYPES (TREE_TYPE (decl)); |
| bool methodp = TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE; |
| tree name = DECL_NAME (decl); |
| location_t loc = DECL_SOURCE_LOCATION (decl); |
| |
| tree class_type = DECL_CONTEXT (decl); |
| if (class_type && !CLASS_TYPE_P (class_type)) |
| class_type = NULL_TREE; |
| |
| tree_code operator_code; |
| unsigned op_flags; |
| if (IDENTIFIER_CONV_OP_P (name)) |
| { |
| /* Conversion operators are TYPE_EXPR for the purposes of this |
| function. */ |
| operator_code = TYPE_EXPR; |
| op_flags = OVL_OP_FLAG_UNARY; |
| } |
| else |
| { |
| const ovl_op_info_t *ovl_op = IDENTIFIER_OVL_OP_INFO (name); |
| |
| operator_code = ovl_op->tree_code; |
| op_flags = ovl_op->flags; |
| gcc_checking_assert (operator_code != ERROR_MARK); |
| DECL_OVERLOADED_OPERATOR_CODE_RAW (decl) = ovl_op->ovl_op_code; |
| } |
| |
| if (op_flags & OVL_OP_FLAG_ALLOC) |
| { |
| /* operator new and operator delete are quite special. */ |
| if (class_type) |
| switch (op_flags) |
| { |
| case OVL_OP_FLAG_ALLOC: |
| TYPE_HAS_NEW_OPERATOR (class_type) = 1; |
| break; |
| |
| case OVL_OP_FLAG_ALLOC | OVL_OP_FLAG_DELETE: |
| TYPE_GETS_DELETE (class_type) |= 1; |
| break; |
| |
| case OVL_OP_FLAG_ALLOC | OVL_OP_FLAG_VEC: |
| TYPE_HAS_ARRAY_NEW_OPERATOR (class_type) = 1; |
| break; |
| |
| case OVL_OP_FLAG_ALLOC | OVL_OP_FLAG_DELETE | OVL_OP_FLAG_VEC: |
| TYPE_GETS_DELETE (class_type) |= 2; |
| break; |
| |
| default: |
| gcc_unreachable (); |
| } |
| |
| /* [basic.std.dynamic.allocation]/1: |
| |
| A program is ill-formed if an allocation function is declared |
| in a namespace scope other than global scope or declared |
| static in global scope. |
| |
| The same also holds true for deallocation functions. */ |
| if (DECL_NAMESPACE_SCOPE_P (decl)) |
| { |
| if (CP_DECL_CONTEXT (decl) != global_namespace) |
| { |
| error_at (loc, "%qD may not be declared within a namespace", |
| decl); |
| return false; |
| } |
| |
| if (!TREE_PUBLIC (decl)) |
| { |
| error_at (loc, "%qD may not be declared as static", decl); |
| return false; |
| } |
| } |
| |
| if (op_flags & OVL_OP_FLAG_DELETE) |
| coerce_delete_type (decl, loc); |
| else |
| { |
| DECL_IS_OPERATOR_NEW (decl) = 1; |
| TREE_TYPE (decl) = coerce_new_type (TREE_TYPE (decl), loc); |
| } |
| |
| return true; |
| } |
| |
| /* An operator function must either be a non-static member function |
| or have at least one parameter of a class, a reference to a class, |
| an enumeration, or a reference to an enumeration. 13.4.0.6 */ |
| if (! methodp || DECL_STATIC_FUNCTION_P (decl)) |
| { |
| if (operator_code == TYPE_EXPR |
| || operator_code == CALL_EXPR |
| || operator_code == COMPONENT_REF |
| || operator_code == ARRAY_REF |
| || operator_code == NOP_EXPR) |
| { |
| error_at (loc, "%qD must be a nonstatic member function", decl); |
| return false; |
| } |
| |
| if (DECL_STATIC_FUNCTION_P (decl)) |
| { |
| error_at (loc, "%qD must be either a non-static member " |
| "function or a non-member function", decl); |
| return false; |
| } |
| |
| for (tree arg = argtypes; ; arg = TREE_CHAIN (arg)) |
| { |
| if (!arg || arg == void_list_node) |
| { |
| if (complain) |
| error_at(loc, "%qD must have an argument of class or " |
| "enumerated type", decl); |
| return false; |
| } |
| |
| tree type = non_reference (TREE_VALUE (arg)); |
| if (type == error_mark_node) |
| return false; |
| |
| /* MAYBE_CLASS_TYPE_P, rather than CLASS_TYPE_P, is used |
| because these checks are performed even on template |
| functions. */ |
| if (MAYBE_CLASS_TYPE_P (type) |
| || TREE_CODE (type) == ENUMERAL_TYPE) |
| break; |
| } |
| } |
| |
| if (operator_code == CALL_EXPR) |
| /* There are no further restrictions on the arguments to an overloaded |
| "operator ()". */ |
| return true; |
| |
| if (operator_code == COND_EXPR) |
| { |
| /* 13.4.0.3 */ |
| error_at (loc, "ISO C++ prohibits overloading operator ?:"); |
| return false; |
| } |
| |
| /* Count the number of arguments and check for ellipsis. */ |
| int arity = 0; |
| for (tree arg = argtypes; arg != void_list_node; arg = TREE_CHAIN (arg)) |
| { |
| if (!arg) |
| { |
| /* Variadic. */ |
| error_at (loc, "%qD must not have variable number of arguments", |
| decl); |
| return false; |
| } |
| ++arity; |
| } |
| |
| /* Verify correct number of arguments. */ |
| switch (op_flags) |
| { |
| case OVL_OP_FLAG_AMBIARY: |
| if (arity == 1) |
| { |
| /* We have a unary instance of an ambi-ary op. Remap to the |
| unary one. */ |
| unsigned alt = ovl_op_alternate[ovl_op_mapping [operator_code]]; |
| const ovl_op_info_t *ovl_op = &ovl_op_info[false][alt]; |
| gcc_checking_assert (ovl_op->flags == OVL_OP_FLAG_UNARY); |
| operator_code = ovl_op->tree_code; |
| DECL_OVERLOADED_OPERATOR_CODE_RAW (decl) = ovl_op->ovl_op_code; |
| } |
| else if (arity != 2) |
| { |
| /* This was an ambiguous operator but is invalid. */ |
| error_at (loc, |
| methodp |
| ? G_("%qD must have either zero or one argument") |
| : G_("%qD must have either one or two arguments"), decl); |
| return false; |
| } |
| else if ((operator_code == POSTINCREMENT_EXPR |
| || operator_code == POSTDECREMENT_EXPR) |
| && ! processing_template_decl |
| /* x++ and x--'s second argument must be an int. */ |
| && ! same_type_p (TREE_VALUE (TREE_CHAIN (argtypes)), |
| integer_type_node)) |
| { |
| error_at (loc, |
| methodp |
| ? G_("postfix %qD must have %<int%> as its argument") |
| : G_("postfix %qD must have %<int%> as its second argument"), |
| decl); |
| return false; |
| } |
| break; |
| |
| case OVL_OP_FLAG_UNARY: |
| if (arity != 1) |
| { |
| error_at (loc, |
| methodp |
| ? G_("%qD must have no arguments") |
| : G_("%qD must have exactly one argument"), decl); |
| return false; |
| } |
| break; |
| |
| case OVL_OP_FLAG_BINARY: |
| if (arity != 2) |
| { |
| error_at (loc, |
| methodp |
| ? G_("%qD must have exactly one argument") |
| : G_("%qD must have exactly two arguments"), decl); |
| return false; |
| } |
| break; |
| |
| default: |
| gcc_unreachable (); |
| } |
| |
| /* There can be no default arguments. */ |
| for (tree arg = argtypes; arg != void_list_node; arg = TREE_CHAIN (arg)) |
| if (TREE_PURPOSE (arg)) |
| { |
| TREE_PURPOSE (arg) = NULL_TREE; |
| error_at (loc, "%qD cannot have default arguments", decl); |
| return false; |
| } |
| |
| /* At this point the declaration is well-formed. It may not be |
| sensible though. */ |
| |
| /* Check member function warnings only on the in-class declaration. |
| There's no point warning on an out-of-class definition. */ |
| if (class_type && class_type != current_class_type) |
| return true; |
| |
| /* Warn about conversion operators that will never be used. */ |
| if (IDENTIFIER_CONV_OP_P (name) |
| && ! DECL_TEMPLATE_INFO (decl) |
| && warn_class_conversion) |
| { |
| tree t = TREE_TYPE (name); |
| int ref = TYPE_REF_P (t); |
| |
| if (ref) |
| t = TYPE_MAIN_VARIANT (TREE_TYPE (t)); |
| |
| if (VOID_TYPE_P (t)) |
| warning_at (loc, OPT_Wclass_conversion, "converting %qT to %<void%> " |
| "will never use a type conversion operator", class_type); |
| else if (class_type) |
| { |
| if (same_type_ignoring_top_level_qualifiers_p (t, class_type)) |
| warning_at (loc, OPT_Wclass_conversion, |
| ref |
| ? G_("converting %qT to a reference to the same type " |
| "will never use a type conversion operator") |
| : G_("converting %qT to the same type " |
| "will never use a type conversion operator"), |
| class_type); |
| /* Don't force t to be complete here. */ |
| else if (MAYBE_CLASS_TYPE_P (t) |
| && COMPLETE_TYPE_P (t) |
| && DERIVED_FROM_P (t, class_type)) |
| warning_at (loc, OPT_Wclass_conversion, |
| ref |
| ? G_("converting %qT to a reference to a base class " |
| "%qT will never use a type conversion operator") |
| : G_("converting %qT to a base class %qT " |
| "will never use a type conversion operator"), |
| class_type, t); |
| } |
| } |
| |
| if (!warn_ecpp) |
| return true; |
| |
| /* Effective C++ rules below. */ |
| |
| /* More Effective C++ rule 7. */ |
| if (operator_code == TRUTH_ANDIF_EXPR |
| || operator_code == TRUTH_ORIF_EXPR |
| || operator_code == COMPOUND_EXPR) |
| warning_at (loc, OPT_Weffc__, |
| "user-defined %qD always evaluates both arguments", decl); |
| |
| /* More Effective C++ rule 6. */ |
| if (operator_code == POSTINCREMENT_EXPR |
| || operator_code == POSTDECREMENT_EXPR |
| || operator_code == PREINCREMENT_EXPR |
| || operator_code == PREDECREMENT_EXPR) |
| { |
| tree arg = TREE_VALUE (argtypes); |
| tree ret = TREE_TYPE (TREE_TYPE (decl)); |
| if (methodp || TYPE_REF_P (arg)) |
| arg = TREE_TYPE (arg); |
| arg = TYPE_MAIN_VARIANT (arg); |
| |
| if (operator_code == PREINCREMENT_EXPR |
| || operator_code == PREDECREMENT_EXPR) |
| { |
| if (!TYPE_REF_P (ret) |
| || !same_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (ret)), arg)) |
| warning_at (loc, OPT_Weffc__, "prefix %qD should return %qT", decl, |
| build_reference_type (arg)); |
| } |
| else |
| { |
| if (!same_type_p (TYPE_MAIN_VARIANT (ret), arg)) |
| warning_at (loc, OPT_Weffc__, |
| "postfix %qD should return %qT", decl, arg); |
| } |
| } |
| |
| /* Effective C++ rule 23. */ |
| if (!DECL_ASSIGNMENT_OPERATOR_P (decl) |
| && (operator_code == PLUS_EXPR |
| || operator_code == MINUS_EXPR |
| || operator_code == TRUNC_DIV_EXPR |
| || operator_code == MULT_EXPR |
| || operator_code == TRUNC_MOD_EXPR) |
| && TYPE_REF_P (TREE_TYPE (TREE_TYPE (decl)))) |
| warning_at (loc, OPT_Weffc__, "%qD should return by value", decl); |
| |
| return true; |
| } |
| |
| /* Return a string giving the keyword associate with CODE. */ |
| |
| static const char * |
| tag_name (enum tag_types code) |
| { |
| switch (code) |
| { |
| case record_type: |
| return "struct"; |
| case class_type: |
| return "class"; |
| case union_type: |
| return "union"; |
| case enum_type: |
| return "enum"; |
| case typename_type: |
| return "typename"; |
| default: |
| gcc_unreachable (); |
| } |
| } |
| |
| /* Name lookup in an elaborated-type-specifier (after the keyword |
| indicated by TAG_CODE) has found the TYPE_DECL DECL. If the |
| elaborated-type-specifier is invalid, issue a diagnostic and return |
| error_mark_node; otherwise, return the *_TYPE to which it referred. |
| If ALLOW_TEMPLATE_P is true, TYPE may be a class template. */ |
| |
| tree |
| check_elaborated_type_specifier (enum tag_types tag_code, |
| tree decl, |
| bool allow_template_p) |
| { |
| tree type; |
| |
| /* In the case of: |
| |
| struct S { struct S *p; }; |
| |
| name lookup will find the TYPE_DECL for the implicit "S::S" |
| typedef. Adjust for that here. */ |
| if (DECL_SELF_REFERENCE_P (decl)) |
| decl = TYPE_NAME (TREE_TYPE (decl)); |
| |
| type = TREE_TYPE (decl); |
| |
| /* Check TEMPLATE_TYPE_PARM first because DECL_IMPLICIT_TYPEDEF_P |
| is false for this case as well. */ |
| if (TREE_CODE (type) == TEMPLATE_TYPE_PARM) |
| { |
| error ("using template type parameter %qT after %qs", |
| type, tag_name (tag_code)); |
| return error_mark_node; |
| } |
| /* Accept template template parameters. */ |
| else if (allow_template_p |
| && (TREE_CODE (type) == BOUND_TEMPLATE_TEMPLATE_PARM |
| || TREE_CODE (type) == TEMPLATE_TEMPLATE_PARM)) |
| ; |
| /* [dcl.type.elab] |
| |
| If the identifier resolves to a typedef-name or the |
| simple-template-id resolves to an alias template |
| specialization, the elaborated-type-specifier is ill-formed. |
| |
| In other words, the only legitimate declaration to use in the |
| elaborated type specifier is the implicit typedef created when |
| the type is declared. */ |
| else if (!DECL_IMPLICIT_TYPEDEF_P (decl) |
| && !DECL_SELF_REFERENCE_P (decl) |
| && tag_code != typename_type) |
| { |
| if (alias_template_specialization_p (type)) |
| error ("using alias template specialization %qT after %qs", |
| type, tag_name (tag_code)); |
| else |
| error ("using typedef-name %qD after %qs", decl, tag_name (tag_code)); |
| inform (DECL_SOURCE_LOCATION (decl), |
| "%qD has a previous declaration here", decl); |
| return error_mark_node; |
| } |
| else if (TREE_CODE (type) != RECORD_TYPE |
| && TREE_CODE (type) != UNION_TYPE |
| && tag_code != enum_type |
| && tag_code != typename_type) |
| { |
| error ("%qT referred to as %qs", type, tag_name (tag_code)); |
| inform (location_of (type), "%qT has a previous declaration here", type); |
| return error_mark_node; |
| } |
| else if (TREE_CODE (type) != ENUMERAL_TYPE |
| && tag_code == enum_type) |
| { |
| error ("%qT referred to as enum", type); |
| inform (location_of (type), "%qT has a previous declaration here", type); |
| return error_mark_node; |
| } |
| else if (!allow_template_p |
| && TREE_CODE (type) == RECORD_TYPE |
| && CLASSTYPE_IS_TEMPLATE (type)) |
| { |
| /* If a class template appears as elaborated type specifier |
| without a template header such as: |
| |
| template <class T> class C {}; |
| void f(class C); // No template header here |
| |
| then the required template argument is missing. */ |
| error ("template argument required for %<%s %T%>", |
| tag_name (tag_code), |
| DECL_NAME (CLASSTYPE_TI_TEMPLATE (type))); |
| return error_mark_node; |
| } |
| |
| return type; |
| } |
| |
| /* Lookup NAME in elaborate type specifier in scope according to |
| SCOPE and issue diagnostics if necessary. |
| Return *_TYPE node upon success, NULL_TREE when the NAME is not |
| found, and ERROR_MARK_NODE for type error. */ |
| |
| static tree |
| lookup_and_check_tag (enum tag_types tag_code, tree name, |
| tag_scope scope, bool template_header_p) |
| { |
| tree t; |
| tree decl; |
| if (scope == ts_global) |
| { |
| /* First try ordinary name lookup, ignoring hidden class name |
| injected via friend declaration. */ |
| decl = lookup_name_prefer_type (name, 2); |
| decl = strip_using_decl (decl); |
| /* If that fails, the name will be placed in the smallest |
| non-class, non-function-prototype scope according to 3.3.1/5. |
| We may already have a hidden name declared as friend in this |
| scope. So lookup again but not ignoring hidden names. |
| If we find one, that name will be made visible rather than |
| creating a new tag. */ |
| if (!decl) |
| decl = lookup_type_scope (name, ts_within_enclosing_non_class); |
| } |
| else |
| decl = lookup_type_scope (name, scope); |
| |
| if (decl |
| && (DECL_CLASS_TEMPLATE_P (decl) |
| /* If scope is ts_current we're defining a class, so ignore a |
| template template parameter. */ |
| || (scope != ts_current |
| && DECL_TEMPLATE_TEMPLATE_PARM_P (decl)))) |
| decl = DECL_TEMPLATE_RESULT (decl); |
| |
| if (decl && TREE_CODE (decl) == TYPE_DECL) |
| { |
| /* Look for invalid nested type: |
| class C { |
| class C {}; |
| }; */ |
| if (scope == ts_current && DECL_SELF_REFERENCE_P (decl)) |
| { |
| error ("%qD has the same name as the class in which it is " |
| "declared", |
| decl); |
| return error_mark_node; |
| } |
| |
| /* Two cases we need to consider when deciding if a class |
| template is allowed as an elaborated type specifier: |
| 1. It is a self reference to its own class. |
| 2. It comes with a template header. |
| |
| For example: |
| |
| template <class T> class C { |
| class C *c1; // DECL_SELF_REFERENCE_P is true |
| class D; |
| }; |
| template <class U> class C; // template_header_p is true |
| template <class T> class C<T>::D { |
| class C *c2; // DECL_SELF_REFERENCE_P is true |
| }; */ |
| |
| t = check_elaborated_type_specifier (tag_code, |
| decl, |
| template_header_p |
| | DECL_SELF_REFERENCE_P (decl)); |
| if (template_header_p && t && CLASS_TYPE_P (t) |
| && (!CLASSTYPE_TEMPLATE_INFO (t) |
| || (!PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (t))))) |
| { |
| error ("%qT is not a template", t); |
| inform (location_of (t), "previous declaration here"); |
| if (TYPE_CLASS_SCOPE_P (t) |
| && CLASSTYPE_TEMPLATE_INFO (TYPE_CONTEXT (t))) |
| inform (input_location, |
| "perhaps you want to explicitly add %<%T::%>", |
| TYPE_CONTEXT (t)); |
| t = error_mark_node; |
| } |
| |
| return t; |
| } |
| else if (decl && TREE_CODE (decl) == TREE_LIST) |
| { |
| error ("reference to %qD is ambiguous", name); |
| print_candidates (decl); |
| return error_mark_node; |
| } |
| else |
| return NULL_TREE; |
| } |
| |
| /* Get the struct, enum or union (TAG_CODE says which) with tag NAME. |
| Define the tag as a forward-reference if it is not defined. |
| |
| If a declaration is given, process it here, and report an error if |
| multiple declarations are not identical. |
| |
| SCOPE is TS_CURRENT when this is also a definition. Only look in |
| the current frame for the name (since C++ allows new names in any |
| scope.) It is TS_WITHIN_ENCLOSING_NON_CLASS if this is a friend |
| declaration. Only look beginning from the current scope outward up |
| till the nearest non-class scope. Otherwise it is TS_GLOBAL. |
| |
| TEMPLATE_HEADER_P is true when this declaration is preceded by |
| a set of template parameters. */ |
| |
| static tree |
| xref_tag_1 (enum tag_types tag_code, tree name, |
| tag_scope scope, bool template_header_p) |
| { |
| enum tree_code code; |
| tree context = NULL_TREE; |
| |
| gcc_assert (identifier_p (name)); |
| |
| switch (tag_code) |
| { |
| case record_type: |
| case class_type: |
| code = RECORD_TYPE; |
| break; |
| case union_type: |
| code = UNION_TYPE; |
| break; |
| case enum_type: |
| code = ENUMERAL_TYPE; |
| break; |
| default: |
| gcc_unreachable (); |
| } |
| |
| /* In case of anonymous name, xref_tag is only called to |
| make type node and push name. Name lookup is not required. */ |
| tree t = NULL_TREE; |
| if (scope != ts_lambda && !anon_aggrname_p (name)) |
| t = lookup_and_check_tag (tag_code, name, scope, template_header_p); |
| |
| if (t == error_mark_node) |
| return error_mark_node; |
| |
| if (scope != ts_current && t && current_class_type |
| && template_class_depth (current_class_type) |
| && template_header_p) |
| { |
| if (TREE_CODE (t) == TEMPLATE_TEMPLATE_PARM) |
| return t; |
| |
| /* Since SCOPE is not TS_CURRENT, we are not looking at a |
| definition of this tag. Since, in addition, we are currently |
| processing a (member) template declaration of a template |
| class, we must be very careful; consider: |
| |
| template <class X> struct S1 |
| |
| template <class U> struct S2 |
| { |
| template <class V> friend struct S1; |
| }; |
| |
| Here, the S2::S1 declaration should not be confused with the |
| outer declaration. In particular, the inner version should |
| have a template parameter of level 2, not level 1. |
| |
| On the other hand, when presented with: |
| |
| template <class T> struct S1 |
| { |
| template <class U> struct S2 {}; |
| template <class U> friend struct S2; |
| }; |
| |
| the friend must find S1::S2 eventually. We accomplish this |
| by making sure that the new type we create to represent this |
| declaration has the right TYPE_CONTEXT. */ |
| context = TYPE_CONTEXT (t); |
| t = NULL_TREE; |
| } |
| |
| if (! t) |
| { |
| /* If no such tag is yet defined, create a forward-reference node |
| and record it as the "definition". |
| When a real declaration of this type is found, |
| the forward-reference will be altered into a real type. */ |
| if (code == ENUMERAL_TYPE) |
| { |
| error ("use of enum %q#D without previous declaration", name); |
| return error_mark_node; |
| } |
| else |
| { |
| t = make_class_type (code); |
| TYPE_CONTEXT (t) = context; |
| if (scope == ts_lambda) |
| { |
| /* Mark it as a lambda type. */ |
| CLASSTYPE_LAMBDA_EXPR (t) = error_mark_node; |
| /* And push it into current scope. */ |
| scope = ts_current; |
| } |
| t = pushtag (name, t, scope); |
| } |
| } |
| else |
| { |
| if (template_header_p && MAYBE_CLASS_TYPE_P (t)) |
| { |
| /* Check that we aren't trying to overload a class with different |
| constraints. */ |
| tree constr = NULL_TREE; |
| if (current_template_parms) |
| { |
| tree reqs = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms); |
| constr = build_constraints (reqs, NULL_TREE); |
| } |
| if (!redeclare_class_template (t, current_template_parms, constr)) |
| return error_mark_node; |
| } |
| else if (!processing_template_decl |
| && CLASS_TYPE_P (t) |
| && CLASSTYPE_IS_TEMPLATE (t)) |
| { |
| error ("redeclaration of %qT as a non-template", t); |
| inform (location_of (t), "previous declaration %qD", t); |
| return error_mark_node; |
| } |
| |
| if (scope != ts_within_enclosing_non_class && TYPE_HIDDEN_P (t)) |
| { |
| /* This is no longer an invisible friend. Make it |
| visible. */ |
| tree decl = TYPE_NAME (t); |
| |
| DECL_ANTICIPATED (decl) = false; |
| DECL_FRIEND_P (decl) = false; |
| |
| if (TYPE_TEMPLATE_INFO (t)) |
| { |
| tree tmpl = TYPE_TI_TEMPLATE (t); |
| DECL_ANTICIPATED (tmpl) = false; |
| DECL_FRIEND_P (tmpl) = false; |
| } |
| } |
| } |
| |
| return t; |
| } |
| |
| /* Wrapper for xref_tag_1. */ |
| |
| tree |
| xref_tag (enum tag_types tag_code, tree name, |
| tag_scope scope, bool template_header_p) |
| { |
| tree ret; |
| bool subtime; |
| subtime = timevar_cond_start (TV_NAME_LOOKUP); |
| ret = xref_tag_1 (tag_code, name, scope, template_header_p); |
| timevar_cond_stop (TV_NAME_LOOKUP, subtime); |
| return ret; |
| } |
| |
| |
| tree |
| xref_tag_from_type (tree old, tree id, tag_scope scope) |
| { |
| enum tag_types tag_kind; |
| |
| if (TREE_CODE (old) == RECORD_TYPE) |
| tag_kind = (CLASSTYPE_DECLARED_CLASS (old) ? class_type : record_type); |
| else |
| tag_kind = union_type; |
| |
| if (id == NULL_TREE) |
| id = TYPE_IDENTIFIER (old); |
| |
| return xref_tag (tag_kind, id, scope, false); |
| } |
| |
| /* Create the binfo hierarchy for REF with (possibly NULL) base list |
| BASE_LIST. For each element on BASE_LIST the TREE_PURPOSE is an |
| access_* node, and the TREE_VALUE is the type of the base-class. |
| Non-NULL TREE_TYPE indicates virtual inheritance. */ |
| |
| void |
| xref_basetypes (tree ref, tree base_list) |
| { |
| tree *basep; |
| tree binfo, base_binfo; |
| unsigned max_vbases = 0; /* Maximum direct & indirect virtual bases. */ |
| unsigned max_bases = 0; /* Maximum direct bases. */ |
| unsigned max_dvbases = 0; /* Maximum direct virtual bases. */ |
| int i; |
| tree default_access; |
| tree igo_prev; /* Track Inheritance Graph Order. */ |
| |
| if (ref == error_mark_node) |
| return; |
| |
| /* The base of a derived class is private by default, all others are |
| public. */ |
| default_access = (TREE_CODE (ref) == RECORD_TYPE |
| && CLASSTYPE_DECLARED_CLASS (ref) |
| ? access_private_node : access_public_node); |
| |
| /* First, make sure that any templates in base-classes are |
| instantiated. This ensures that if we call ourselves recursively |
| we do not get confused about which classes are marked and which |
| are not. */ |
| basep = &base_list; |
| while (*basep) |
| { |
| tree basetype = TREE_VALUE (*basep); |
| |
| /* The dependent_type_p call below should really be dependent_scope_p |
| so that we give a hard error about using an incomplete type as a |
| base, but we allow it with a pedwarn for backward |
| compatibility. */ |
| if (processing_template_decl |
| && CLASS_TYPE_P (basetype) && TYPE_BEING_DEFINED (basetype)) |
| cxx_incomplete_type_diagnostic (NULL_TREE, basetype, DK_PEDWARN); |
| if (!dependent_type_p (basetype) |
| && !complete_type_or_else (basetype, NULL)) |
| /* An incomplete type. Remove it from the list. */ |
| *basep = TREE_CHAIN (*basep); |
| else |
| { |
| max_bases++; |
| if (TREE_TYPE (*basep)) |
| max_dvbases++; |
| if (CLASS_TYPE_P (basetype)) |
| max_vbases += vec_safe_length (CLASSTYPE_VBASECLASSES (basetype)); |
| basep = &TREE_CHAIN (*basep); |
| } |
| } |
| max_vbases += max_dvbases; |
| |
| TYPE_MARKED_P (ref) = 1; |
| |
| /* The binfo slot should be empty, unless this is an (ill-formed) |
| redefinition. */ |
| gcc_assert (!TYPE_BINFO (ref) || TYPE_SIZE (ref)); |
| |
| gcc_assert (TYPE_MAIN_VARIANT (ref) == ref); |
| |
| binfo = make_tree_binfo (max_bases); |
| |
| TYPE_BINFO (ref) = binfo; |
| BINFO_OFFSET (binfo) = size_zero_node; |
| BINFO_TYPE (binfo) = ref; |
| |
| /* Apply base-class info set up to the variants of this type. */ |
| fixup_type_variants (ref); |
| |
| if (max_bases) |
| { |
| vec_alloc (BINFO_BASE_ACCESSES (binfo), max_bases); |
| /* A C++98 POD cannot have base classes. */ |
| CLASSTYPE_NON_LAYOUT_POD_P (ref) = true; |
| |
| if (TREE_CODE (ref) == UNION_TYPE) |
| { |
| error ("derived union %qT invalid", ref); |
| return; |
| } |
| } |
| |
| if (max_bases > 1) |
| warning (OPT_Wmultiple_inheritance, |
| "%qT defined with multiple direct bases", ref); |
| |
| if (max_vbases) |
| { |
| /* An aggregate can't have virtual base classes. */ |
| CLASSTYPE_NON_AGGREGATE (ref) = true; |
| |
| vec_alloc (CLASSTYPE_VBASECLASSES (ref), max_vbases); |
| |
| if (max_dvbases) |
| warning (OPT_Wvirtual_inheritance, |
| "%qT defined with direct virtual base", ref); |
| } |
| |
| for (igo_prev = binfo; base_list; base_list = TREE_CHAIN (base_list)) |
| { |
| tree access = TREE_PURPOSE (base_list); |
| int via_virtual = TREE_TYPE (base_list) != NULL_TREE; |
| tree basetype = TREE_VALUE (base_list); |
| |
| if (access == access_default_node) |
| access = default_access; |
| |
| /* Before C++17, an aggregate cannot have base classes. In C++17, an |
| aggregate can't have virtual, private, or protected base classes. */ |
| if (cxx_dialect < cxx17 |
| || access != access_public_node |
| || via_virtual) |
| CLASSTYPE_NON_AGGREGATE (ref) = true; |
| |
| if (PACK_EXPANSION_P (basetype)) |
| basetype = PACK_EXPANSION_PATTERN (basetype); |
| if (TREE_CODE (basetype) == TYPE_DECL) |
| basetype = TREE_TYPE (basetype); |
| if (!MAYBE_CLASS_TYPE_P (basetype) || TREE_CODE (basetype) == UNION_TYPE) |
| { |
| error ("base type %qT fails to be a struct or class type", |
| basetype); |
| goto dropped_base; |
| } |
| |
| base_binfo = NULL_TREE; |
| if (CLASS_TYPE_P (basetype) && !dependent_scope_p (basetype)) |
| { |
| base_binfo = TYPE_BINFO (basetype); |
| /* The original basetype could have been a typedef'd type. */ |
| basetype = BINFO_TYPE (base_binfo); |
| |
| /* Inherit flags from the base. */ |
| TYPE_HAS_NEW_OPERATOR (ref) |
| |= TYPE_HAS_NEW_OPERATOR (basetype); |
| TYPE_HAS_ARRAY_NEW_OPERATOR (ref) |
| |= TYPE_HAS_ARRAY_NEW_OPERATOR (basetype); |
| TYPE_GETS_DELETE (ref) |= TYPE_GETS_DELETE (basetype); |
| TYPE_HAS_CONVERSION (ref) |= TYPE_HAS_CONVERSION (basetype); |
| CLASSTYPE_DIAMOND_SHAPED_P (ref) |
| |= CLASSTYPE_DIAMOND_SHAPED_P (basetype); |
| CLASSTYPE_REPEATED_BASE_P (ref) |
| |= CLASSTYPE_REPEATED_BASE_P (basetype); |
| } |
| |
| /* We must do this test after we've seen through a typedef |
| type. */ |
| if (TYPE_MARKED_P (basetype)) |
| { |
| if (basetype == ref) |
| error ("recursive type %qT undefined", basetype); |
| else |
| error ("duplicate base type %qT invalid", basetype); |
| goto dropped_base; |
| } |
| |
| if (PACK_EXPANSION_P (TREE_VALUE (base_list))) |
| /* Regenerate the pack expansion for the bases. */ |
| basetype = make_pack_expansion (basetype); |
| |
| TYPE_MARKED_P (basetype) = 1; |
| |
| base_binfo = copy_binfo (base_binfo, basetype, ref, |
| &igo_prev, via_virtual); |
| if (!BINFO_INHERITANCE_CHAIN (base_binfo)) |
| BINFO_INHERITANCE_CHAIN (base_binfo) = binfo; |
| |
| BINFO_BASE_APPEND (binfo, base_binfo); |
| BINFO_BASE_ACCESS_APPEND (binfo, access); |
| continue; |
| |
| dropped_base: |
| /* Update max_vbases to reflect the reality that we are dropping |
| this base: if it reaches zero we want to undo the vec_alloc |
| above to avoid inconsistencies during error-recovery: eg, in |
| build_special_member_call, CLASSTYPE_VBASECLASSES non null |
| and vtt null (c++/27952). */ |
| if (via_virtual) |
| max_vbases--; |
| if (CLASS_TYPE_P (basetype)) |
| max_vbases |
| -= vec_safe_length (CLASSTYPE_VBASECLASSES (basetype)); |
| } |
| |
| if (CLASSTYPE_VBASECLASSES (ref) |
| && max_vbases == 0) |
| vec_free (CLASSTYPE_VBASECLASSES (ref)); |
| |
| if (vec_safe_length (CLASSTYPE_VBASECLASSES (ref)) < max_vbases) |
| /* If we didn't get max_vbases vbases, we must have shared at |
| least one of them, and are therefore diamond shaped. */ |
| CLASSTYPE_DIAMOND_SHAPED_P (ref) = 1; |
| |
| /* Unmark all the types. */ |
| for (i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++) |
| TYPE_MARKED_P (BINFO_TYPE (base_binfo)) = 0; |
| TYPE_MARKED_P (ref) = 0; |
| |
| /* Now see if we have a repeated base type. */ |
| if (!CLASSTYPE_REPEATED_BASE_P (ref)) |
| { |
| for (base_binfo = binfo; base_binfo; |
| base_binfo = TREE_CHAIN (base_binfo)) |
| { |
| if (TYPE_MARKED_P (BINFO_TYPE (base_binfo))) |
| { |
| CLASSTYPE_REPEATED_BASE_P (ref) = 1; |
| break; |
| } |
| TYPE_MARKED_P (BINFO_TYPE (base_binfo)) = 1; |
| } |
| for (base_binfo = binfo; base_binfo; |
| base_binfo = TREE_CHAIN (base_binfo)) |
| if (TYPE_MARKED_P (BINFO_TYPE (base_binfo))) |
| TYPE_MARKED_P (BINFO_TYPE (base_binfo)) = 0; |
| else |
| break; |
| } |
| } |
| |
| |
| /* Copies the enum-related properties from type SRC to type DST. |
| Used with the underlying type of an enum and the enum itself. */ |
| static void |
| copy_type_enum (tree dst, tree src) |
| { |
| tree t; |
| for (t = dst; t; t = TYPE_NEXT_VARIANT (t)) |
| { |
| TYPE_MIN_VALUE (t) = TYPE_MIN_VALUE (src); |
| TYPE_MAX_VALUE (t) = TYPE_MAX_VALUE (src); |
| TYPE_SIZE (t) = TYPE_SIZE (src); |
| TYPE_SIZE_UNIT (t) = TYPE_SIZE_UNIT (src); |
| SET_TYPE_MODE (dst, TYPE_MODE (src)); |
| TYPE_PRECISION (t) = TYPE_PRECISION (src); |
| unsigned valign = TYPE_ALIGN (src); |
| if (TYPE_USER_ALIGN (t)) |
| valign = MAX (valign, TYPE_ALIGN (t)); |
| else |
| TYPE_USER_ALIGN (t) = TYPE_USER_ALIGN (src); |
| SET_TYPE_ALIGN (t, valign); |
| TYPE_UNSIGNED (t) = TYPE_UNSIGNED (src); |
| } |
| } |
| |
| /* Begin compiling the definition of an enumeration type. |
| NAME is its name, |
| |
| if ENUMTYPE is not NULL_TREE then the type has alredy been found. |
| |
| UNDERLYING_TYPE is the type that will be used as the storage for |
| the enumeration type. This should be NULL_TREE if no storage type |
| was specified. |
| |
| ATTRIBUTES are any attributes specified after the enum-key. |
| |
| SCOPED_ENUM_P is true if this is a scoped enumeration type. |
| |
| if IS_NEW is not NULL, gets TRUE iff a new type is created. |
| |
| Returns the type object, as yet incomplete. |
| Also records info about it so that build_enumerator |
| may be used to declare the individual values as they are read. */ |
| |
| tree |
| start_enum (tree name, tree enumtype, tree underlying_type, |
| tree attributes, bool scoped_enum_p, bool *is_new) |
| { |
| tree prevtype = NULL_TREE; |
| gcc_assert (identifier_p (name)); |
| |
| if (is_new) |
| *is_new = false; |
| /* [C++0x dcl.enum]p5: |
| |
| If not explicitly specified, the underlying type of a scoped |
| enumeration type is int. */ |
| if (!underlying_type && scoped_enum_p) |
| underlying_type = integer_type_node; |
| |
| if (underlying_type) |
| underlying_type = cv_unqualified (underlying_type); |
| |
| /* If this is the real definition for a previous forward reference, |
| fill in the contents in the same object that used to be the |
| forward reference. */ |
| if (!enumtype) |
| enumtype = lookup_and_check_tag (enum_type, name, |
| /*tag_scope=*/ts_current, |
| /*template_header_p=*/false); |
| |
| /* In case of a template_decl, the only check that should be deferred |
| to instantiation time is the comparison of underlying types. */ |
| if (enumtype && TREE_CODE (enumtype) == ENUMERAL_TYPE) |
| { |
| if (scoped_enum_p != SCOPED_ENUM_P (enumtype)) |
| { |
| error_at (input_location, "scoped/unscoped mismatch " |
| "in enum %q#T", enumtype); |
| inform (DECL_SOURCE_LOCATION (TYPE_MAIN_DECL (enumtype)), |
| "previous definition here"); |
| enumtype = error_mark_node; |
| } |
| else if (ENUM_FIXED_UNDERLYING_TYPE_P (enumtype) != !! underlying_type) |
| { |
| error_at (input_location, "underlying type mismatch " |
| "in enum %q#T", enumtype); |
| inform (DECL_SOURCE_LOCATION (TYPE_MAIN_DECL (enumtype)), |
| "previous definition here"); |
| enumtype = error_mark_node; |
| } |
| else if (underlying_type && ENUM_UNDERLYING_TYPE (enumtype) |
| && !same_type_p (underlying_type, |
| ENUM_UNDERLYING_TYPE (enumtype))) |
| { |
| error_at (input_location, "different underlying type " |
| "in enum %q#T", enumtype); |
| inform (DECL_SOURCE_LOCATION (TYPE_MAIN_DECL (enumtype)), |
| "previous definition here"); |
| underlying_type = NULL_TREE; |
| } |
| } |
| |
| if (!enumtype || TREE_CODE (enumtype) != ENUMERAL_TYPE |
| || processing_template_decl) |
| { |
| /* In case of error, make a dummy enum to allow parsing to |
| continue. */ |
| if (enumtype == error_mark_node) |
| { |
| name = make_anon_name (); |
| enumtype = NULL_TREE; |
| } |
| |
| /* enumtype may be an ENUMERAL_TYPE if this is a redefinition |
| of an opaque enum, or an opaque enum of an already defined |
| enumeration (C++11). |
| In any other case, it'll be NULL_TREE. */ |
| if (!enumtype) |
| { |
| if (is_new) |
| *is_new = true; |
| } |
| prevtype = enumtype; |
| |
| /* Do not push the decl more than once. */ |
| if (!enumtype |
| || TREE_CODE (enumtype) != ENUMERAL_TYPE) |
| { |
| enumtype = cxx_make_type (ENUMERAL_TYPE); |
| enumtype = pushtag (name, enumtype, /*tag_scope=*/ts_current); |
| |
| /* std::byte aliases anything. */ |
| if (enumtype != error_mark_node |
| && TYPE_CONTEXT (enumtype) == std_node |
| && !strcmp ("byte", TYPE_NAME_STRING (enumtype))) |
| TYPE_ALIAS_SET (enumtype) = 0; |
| } |
| else |
| enumtype = xref_tag (enum_type, name, /*tag_scope=*/ts_current, |
| false); |
| |
| if (enumtype == error_mark_node) |
| return error_mark_node; |
| |
| /* The enum is considered opaque until the opening '{' of the |
| enumerator list. */ |
| SET_OPAQUE_ENUM_P (enumtype, true); |
| ENUM_FIXED_UNDERLYING_TYPE_P (enumtype) = !! underlying_type; |
| } |
| |
| SET_SCOPED_ENUM_P (enumtype, scoped_enum_p); |
| |
| cplus_decl_attributes (&enumtype, attributes, (int)ATTR_FLAG_TYPE_IN_PLACE); |
| |
| if (underlying_type) |
| { |
| if (ENUM_UNDERLYING_TYPE (enumtype)) |
| /* We already checked that it matches, don't change it to a different |
| typedef variant. */; |
| else if (CP_INTEGRAL_TYPE_P (underlying_type)) |
| { |
| copy_type_enum (enumtype, underlying_type); |
| ENUM_UNDERLYING_TYPE (enumtype) = underlying_type; |
| } |
| else if (dependent_type_p (underlying_type)) |
| ENUM_UNDERLYING_TYPE (enumtype) = underlying_type; |
| else |
| error ("underlying type %qT of %qT must be an integral type", |
| underlying_type, enumtype); |
| } |
| |
| /* If into a template class, the returned enum is always the first |
| declaration (opaque or not) seen. This way all the references to |
| this type will be to the same declaration. The following ones are used |
| only to check for definition errors. */ |
| if (prevtype && processing_template_decl) |
| return prevtype; |
| else |
| return enumtype; |
| } |
| |
| /* After processing and defining all the values of an enumeration type, |
| install their decls in the enumeration type. |
| ENUMTYPE is the type object. */ |
| |
| void |
| finish_enum_value_list (tree enumtype) |
| { |
| tree values; |
| tree underlying_type; |
| tree decl; |
| tree value; |
| tree minnode, maxnode; |
| tree t; |
| |
| bool fixed_underlying_type_p |
| = ENUM_UNDERLYING_TYPE (enumtype) != NULL_TREE; |
| |
| /* We built up the VALUES in reverse order. */ |
| TYPE_VALUES (enumtype) = nreverse (TYPE_VALUES (enumtype)); |
| |
| /* For an enum defined in a template, just set the type of the values; |
| all further processing is postponed until the template is |
| instantiated. We need to set the type so that tsubst of a CONST_DECL |
| works. */ |
| if (processing_template_decl) |
| { |
| for (values = TYPE_VALUES (enumtype); |
| values; |
| values = TREE_CHAIN (values)) |
| TREE_TYPE (TREE_VALUE (values)) = enumtype; |
| return; |
| } |
| |
| /* Determine the minimum and maximum values of the enumerators. */ |
| if (TYPE_VALUES (enumtype)) |
| { |
| minnode = maxnode = NULL_TREE; |
| |
| for (values = TYPE_VALUES (enumtype); |
| values; |
| values = TREE_CHAIN (values)) |
| { |
| decl = TREE_VALUE (values); |
| |
| /* [dcl.enum]: Following the closing brace of an enum-specifier, |
| each enumerator has the type of its enumeration. Prior to the |
| closing brace, the type of each enumerator is the type of its |
| initializing value. */ |
| TREE_TYPE (decl) = enumtype; |
| |
| /* Update the minimum and maximum values, if appropriate. */ |
| value = DECL_INITIAL (decl); |
| if (value == error_mark_node) |
| value = integer_zero_node; |
| /* Figure out what the minimum and maximum values of the |
| enumerators are. */ |
| if (!minnode) |
| minnode = maxnode = value; |
| else if (tree_int_cst_lt (maxnode, value)) |
| maxnode = value; |
| else if (tree_int_cst_lt (value, minnode)) |
| minnode = value; |
| } |
| } |
| else |
| /* [dcl.enum] |
| |
| If the enumerator-list is empty, the underlying type is as if |
| the enumeration had a single enumerator with value 0. */ |
| minnode = maxnode = integer_zero_node; |
| |
| if (!fixed_underlying_type_p) |
| { |
| /* Compute the number of bits require to represent all values of the |
| enumeration. We must do this before the type of MINNODE and |
| MAXNODE are transformed, since tree_int_cst_min_precision relies |
| on the TREE_TYPE of the value it is passed. */ |
| signop sgn = tree_int_cst_sgn (minnode) >= 0 ? UNSIGNED : SIGNED; |
| int lowprec = tree_int_cst_min_precision (minnode, sgn); |
| int highprec = tree_int_cst_min_precision (maxnode, sgn); |
| int precision = MAX (lowprec, highprec); |
| unsigned int itk; |
| bool use_short_enum; |
| |
| /* Determine the underlying type of the enumeration. |
| |
| [dcl.enum] |
| |
| The underlying type of an enumeration is an integral type that |
| can represent all the enumerator values defined in the |
| enumeration. It is implementation-defined which integral type is |
| used as the underlying type for an enumeration except that the |
| underlying type shall not be larger than int unless the value of |
| an enumerator cannot fit in an int or unsigned int. |
| |
| We use "int" or an "unsigned int" as the underlying type, even if |
| a smaller integral type would work, unless the user has |
| explicitly requested that we use the smallest possible type. The |
| user can request that for all enumerations with a command line |
| flag, or for just one enumeration with an attribute. */ |
| |
| use_short_enum = flag_short_enums |
| || lookup_attribute ("packed", TYPE_ATTRIBUTES (enumtype)); |
| |
| /* If the precision of the type was specified with an attribute and it |
| was too small, give an error. Otherwise, use it. */ |
| if (TYPE_PRECISION (enumtype)) |
| { |
| if (precision > TYPE_PRECISION (enumtype)) |
| error ("specified mode too small for enumeral values"); |
| else |
| { |
| use_short_enum = true; |
| precision = TYPE_PRECISION (enumtype); |
| } |
| } |
| |
| for (itk = (use_short_enum ? itk_char : itk_int); |
| itk != itk_none; |
| itk++) |
| { |
| underlying_type = integer_types[itk]; |
| if (underlying_type != NULL_TREE |
| && TYPE_PRECISION (underlying_type) >= precision |
| && TYPE_SIGN (underlying_type) == sgn) |
| break; |
| } |
| if (itk == itk_none) |
| { |
| /* DR 377 |
| |
| IF no integral type can represent all the enumerator values, the |
| enumeration is ill-formed. */ |
| error ("no integral type can represent all of the enumerator values " |
| "for %qT", enumtype); |
| precision = TYPE_PRECISION (long_long_integer_type_node); |
| underlying_type = integer_types[itk_unsigned_long_long]; |
| } |
| |
| /* [dcl.enum] |
| |
| The value of sizeof() applied to an enumeration type, an object |
| of an enumeration type, or an enumerator, is the value of sizeof() |
| applied to the underlying type. */ |
| copy_type_enum (enumtype, underlying_type); |
| |
| /* Compute the minimum and maximum values for the type. |
| |
| [dcl.enum] |
| |
| For an enumeration where emin is the smallest enumerator and emax |
| is the largest, the values of the enumeration are the values of the |
| underlying type in the range bmin to bmax, where bmin and bmax are, |
| respectively, the smallest and largest values of the smallest bit- |
| field that can store emin and emax. */ |
| |
| /* The middle-end currently assumes that types with TYPE_PRECISION |
| narrower than their underlying type are suitably zero or sign |
| extended to fill their mode. Similarly, it assumes that the front |
| end assures that a value of a particular type must be within |
| TYPE_MIN_VALUE and TYPE_MAX_VALUE. |
| |
| We used to set these fields based on bmin and bmax, but that led |
| to invalid assumptions like optimizing away bounds checking. So |
| now we just set the TYPE_PRECISION, TYPE_MIN_VALUE, and |
| TYPE_MAX_VALUE to the values for the mode above and only restrict |
| the ENUM_UNDERLYING_TYPE for the benefit of diagnostics. */ |
| ENUM_UNDERLYING_TYPE (enumtype) |
| = build_distinct_type_copy (underlying_type); |
| TYPE_PRECISION (ENUM_UNDERLYING_TYPE (enumtype)) = precision; |
| set_min_and_max_values_for_integral_type |
| (ENUM_UNDERLYING_TYPE (enumtype), precision, sgn); |
| |
| /* If -fstrict-enums, still constrain TYPE_MIN/MAX_VALUE. */ |
| if (flag_strict_enums) |
| set_min_and_max_values_for_integral_type (enumtype, precision, sgn); |
| } |
| else |
| underlying_type = ENUM_UNDERLYING_TYPE (enumtype); |
| |
| /* Convert each of the enumerators to the type of the underlying |
| type of the enumeration. */ |
| for (values = TYPE_VALUES (enumtype); values; values = TREE_CHAIN (values)) |
| { |
| location_t saved_location; |
| |
| decl = TREE_VALUE (values); |
| saved_location = input_location; |
| input_location = DECL_SOURCE_LOCATION (decl); |
| if (fixed_underlying_type_p) |
| /* If the enumeration type has a fixed underlying type, we |
| already checked all of the enumerator values. */ |
| value = DECL_INITIAL (decl); |
| else |
| value = perform_implicit_conversion (underlying_type, |
| DECL_INITIAL (decl), |
| tf_warning_or_error); |
| input_location = saved_location; |
| |
| /* Do not clobber shared ints. */ |
| if (value != error_mark_node) |
| { |
| value = copy_node (value); |
| |
| TREE_TYPE (value) = enumtype; |
| } |
| DECL_INITIAL (decl) = value; |
| } |
| |
| /* Fix up all variant types of this enum type. */ |
| for (t = TYPE_MAIN_VARIANT (enumtype); t; t = TYPE_NEXT_VARIANT (t)) |
| TYPE_VALUES (t) = TYPE_VALUES (enumtype); |
| |
| if (at_class_scope_p () |
| && COMPLETE_TYPE_P (current_class_type) |
| && UNSCOPED_ENUM_P (enumtype)) |
| { |
| insert_late_enum_def_bindings (current_class_type, enumtype); |
| /* TYPE_FIELDS needs fixup. */ |
| fixup_type_variants (current_class_type); |
| } |
| |
| /* Finish debugging output for this type. */ |
| rest_of_type_compilation (enumtype, namespace_bindings_p ()); |
| |
| /* Each enumerator now has the type of its enumeration. Clear the cache |
| so that this change in types doesn't confuse us later on. */ |
| clear_cv_and_fold_caches (); |
| } |
| |
| /* Finishes the enum type. This is called only the first time an |
| enumeration is seen, be it opaque or odinary. |
| ENUMTYPE is the type object. */ |
| |
| void |
| finish_enum (tree enumtype) |
| { |
| if (processing_template_decl) |
| { |
| if (at_function_scope_p ()) |
| add_stmt (build_min (TAG_DEFN, enumtype)); |
| return; |
| } |
| |
| /* If this is a forward declaration, there should not be any variants, |
| though we can get a variant in the middle of an enum-specifier with |
| wacky code like 'enum E { e = sizeof(const E*) };' */ |
| gcc_assert (enumtype == TYPE_MAIN_VARIANT (enumtype) |
| && (TYPE_VALUES (enumtype) |
| || !TYPE_NEXT_VARIANT (enumtype))); |
| } |
| |
| /* Build and install a CONST_DECL for an enumeration constant of the |
| enumeration type ENUMTYPE whose NAME and VALUE (if any) are provided. |
| Apply ATTRIBUTES if available. LOC is the location of NAME. |
| Assignment of sequential values by default is handled here. */ |
| |
| void |
| build_enumerator (tree name, tree value, tree enumtype, tree attributes, |
| location_t loc) |
| { |
| tree decl; |
| tree context; |
| tree type; |
| |
| /* scalar_constant_value will pull out this expression, so make sure |
| it's folded as appropriate. */ |
| if (processing_template_decl) |
| value = fold_non_dependent_expr (value); |
| |
| /* If the VALUE was erroneous, pretend it wasn't there; that will |
| result in the enum being assigned the next value in sequence. */ |
| if (value == error_mark_node) |
| value = NULL_TREE; |
| |
| /* Remove no-op casts from the value. */ |
| if (value) |
| STRIP_TYPE_NOPS (value); |
| |
| if (! processing_template_decl) |
| { |
| /* Validate and default VALUE. */ |
| if (value != NULL_TREE) |
| { |
| if (!ENUM_UNDERLYING_TYPE (enumtype)) |
| { |
| tree tmp_value = build_expr_type_conversion (WANT_INT | WANT_ENUM, |
| value, true); |
| if (tmp_value) |
| value = tmp_value; |
| } |
| else if (! INTEGRAL_OR_UNSCOPED_ENUMERATION_TYPE_P |
| (TREE_TYPE (value))) |
| value = perform_implicit_conversion_flags |
| (ENUM_UNDERLYING_TYPE (enumtype), value, tf_warning_or_error, |
| LOOKUP_IMPLICIT | LOOKUP_NO_NARROWING); |
| |
| if (value == error_mark_node) |
| value = NULL_TREE; |
| |
| if (value != NULL_TREE) |
| { |
| if (! INTEGRAL_OR_UNSCOPED_ENUMERATION_TYPE_P |
| (TREE_TYPE (value))) |
| { |
| error ("enumerator value for %qD must have integral or " |
| "unscoped enumeration type", name); |
| value = NULL_TREE; |
| } |
| else |
| { |
| value = cxx_constant_value (value); |
| |
| if (TREE_CODE (value) != INTEGER_CST) |
| { |
| error ("enumerator value for %qD is not an integer " |
| "constant", name); |
| value = NULL_TREE; |
| } |
| } |
| } |
| } |
| |
| /* Default based on previous value. */ |
| if (value == NULL_TREE) |
| { |
| if (TYPE_VALUES (enumtype)) |
| { |
| tree prev_value; |
| |
| /* C++03 7.2/4: If no initializer is specified for the first |
| enumerator, the type is an unspecified integral |
| type. Otherwise the type is the same as the type of the |
| initializing value of the preceding enumerator unless the |
| incremented value is not representable in that type, in |
| which case the type is an unspecified integral type |
| sufficient to contain the incremented value. */ |
| prev_value = DECL_INITIAL (TREE_VALUE (TYPE_VALUES (enumtype))); |
| if (error_operand_p (prev_value)) |
| value = error_mark_node; |
| else |
| { |
| wi::overflow_type overflowed; |
| tree type = TREE_TYPE (prev_value); |
| signop sgn = TYPE_SIGN (type); |
| widest_int wi = wi::add (wi::to_widest (prev_value), 1, sgn, |
| &overflowed); |
| if (!overflowed) |
| { |
| bool pos = !wi::neg_p (wi, sgn); |
| if (!wi::fits_to_tree_p (wi, type)) |
| { |
| unsigned int itk; |
| for (itk = itk_int; itk != itk_none; itk++) |
| { |
| type = integer_types[itk]; |
| if (type != NULL_TREE |
| && (pos || !TYPE_UNSIGNED (type)) |
| && wi::fits_to_tree_p (wi, type)) |
| break; |
| } |
| if (type && cxx_dialect < cxx11 |
| && itk > itk_unsigned_long) |
| pedwarn (input_location, OPT_Wlong_long, |
| pos ? G_("\ |
| incremented enumerator value is too large for %<unsigned long%>") : G_("\ |
| incremented enumerator value is too large for %<long%>")); |
| } |
| if (type == NULL_TREE) |
| overflowed = wi::OVF_UNKNOWN; |
| else |
| value = wide_int_to_tree (type, wi); |
| } |
| |
| if (overflowed) |
| { |
| error ("overflow in enumeration values at %qD", name); |
| value = error_mark_node; |
| } |
| } |
| } |
| else |
| value = integer_zero_node; |
| } |
| |
| /* Remove no-op casts from the value. */ |
| STRIP_TYPE_NOPS (value); |
| |
| /* If the underlying type of the enum is fixed, check whether |
| the enumerator values fits in the underlying type. If it |
| does not fit, the program is ill-formed [C++0x dcl.enum]. */ |
| if (ENUM_UNDERLYING_TYPE (enumtype) |
| && value |
| && TREE_CODE (value) == INTEGER_CST) |
| { |
| if (!int_fits_type_p (value, ENUM_UNDERLYING_TYPE (enumtype))) |
| error ("enumerator value %qE is outside the range of underlying " |
| "type %qT", value, ENUM_UNDERLYING_TYPE (enumtype)); |
| |
| /* Convert the value to the appropriate type. */ |
| value = fold_convert (ENUM_UNDERLYING_TYPE (enumtype), value); |
| } |
| } |
| |
| /* C++ associates enums with global, function, or class declarations. */ |
| context = current_scope (); |
| |
| /* Build the actual enumeration constant. Note that the enumeration |
| constants have the underlying type of the enum (if it is fixed) |
| or the type of their initializer (if the underlying type of the |
| enum is not fixed): |
| |
| [ C++0x dcl.enum ] |
| |
| If the underlying type is fixed, the type of each enumerator |
| prior to the closing brace is the underlying type; if the |
| initializing value of an enumerator cannot be represented by |
| the underlying type, the program is ill-formed. If the |
| underlying type is not fixed, the type of each enumerator is |
| the type of its initializing value. |
| |
| If the underlying type is not fixed, it will be computed by |
| finish_enum and we will reset the type of this enumerator. Of |
| course, if we're processing a template, there may be no value. */ |
| type = value ? TREE_TYPE (value) : NULL_TREE; |
| |
| decl = build_decl (loc, CONST_DECL, name, type); |
| |
| DECL_CONTEXT (decl) = enumtype; |
| TREE_CONSTANT (decl) = 1; |
| TREE_READONLY (decl) = 1; |
| DECL_INITIAL (decl) = value; |
| |
| if (attributes) |
| cplus_decl_attributes (&decl, attributes, 0); |
| |
| if (context && context == current_class_type && !SCOPED_ENUM_P (enumtype)) |
| { |
| /* In something like `struct S { enum E { i = 7 }; };' we put `i' |
| on the TYPE_FIELDS list for `S'. (That's so that you can say |
| things like `S::i' later.) */ |
| |
| /* The enumerator may be getting declared outside of its enclosing |
| class, like so: |
| |
| class S { public: enum E : int; }; enum S::E : int { i = 7; }; |
| |
| For which case we need to make sure that the access of `S::i' |
| matches the access of `S::E'. */ |
| tree saved_cas = current_access_specifier; |
| if (TREE_PRIVATE (TYPE_NAME (enumtype))) |
| current_access_specifier = access_private_node; |
| else if (TREE_PROTECTED (TYPE_NAME (enumtype))) |
| current_access_specifier = access_protected_node; |
| else |
| current_access_specifier = access_public_node; |
| |
| finish_member_declaration (decl); |
| |
| current_access_specifier = saved_cas; |
| } |
| else |
| pushdecl (decl); |
| |
| /* Add this enumeration constant to the list for this type. */ |
| TYPE_VALUES (enumtype) = tree_cons (name, decl, TYPE_VALUES (enumtype)); |
| } |
| |
| /* Look for an enumerator with the given NAME within the enumeration |
| type ENUMTYPE. This routine is used primarily for qualified name |
| lookup into an enumerator in C++0x, e.g., |
| |
| enum class Color { Red, Green, Blue }; |
| |
| Color color = Color::Red; |
| |
| Returns the value corresponding to the enumerator, or |
| NULL_TREE if no such enumerator was found. */ |
| tree |
| lookup_enumerator (tree enumtype, tree name) |
| { |
| tree e; |
| gcc_assert (enumtype && TREE_CODE (enumtype) == ENUMERAL_TYPE); |
| |
| e = purpose_member (name, TYPE_VALUES (enumtype)); |
| return e? TREE_VALUE (e) : NULL_TREE; |
| } |
| |
| |
| /* We're defining DECL. Make sure that its type is OK. */ |
| |
| static void |
| check_function_type (tree decl, tree current_function_parms) |
| { |
| tree fntype = TREE_TYPE (decl); |
| tree return_type = complete_type (TREE_TYPE (fntype)); |
| |
| /* In a function definition, arg types must be complete. */ |
| require_complete_types_for_parms (current_function_parms); |
| |
| if (dependent_type_p (return_type) |
| || type_uses_auto (return_type)) |
| return; |
| if (!COMPLETE_OR_VOID_TYPE_P (return_type)) |
| { |
| tree args = TYPE_ARG_TYPES (fntype); |
| |
| error ("return type %q#T is incomplete", return_type); |
| |
| /* Make it return void instead. */ |
| if (TREE_CODE (fntype) == METHOD_TYPE) |
| fntype = build_method_type_directly (TREE_TYPE (TREE_VALUE (args)), |
| void_type_node, |
| TREE_CHAIN (args)); |
| else |
| fntype = build_function_type (void_type_node, args); |
| fntype = (cp_build_type_attribute_variant |
| (fntype, TYPE_ATTRIBUTES (TREE_TYPE (decl)))); |
| fntype = cxx_copy_lang_qualifiers (fntype, TREE_TYPE (decl)); |
| TREE_TYPE (decl) = fntype; |
| } |
| else |
| { |
| abstract_virtuals_error (decl, TREE_TYPE (fntype)); |
| maybe_warn_parm_abi (TREE_TYPE (fntype), |
| DECL_SOURCE_LOCATION (decl)); |
| } |
| } |
| |
| /* True iff FN is an implicitly-defined default constructor. */ |
| |
| static bool |
| implicit_default_ctor_p (tree fn) |
| { |
| return (DECL_CONSTRUCTOR_P (fn) |
| && !user_provided_p (fn) |
| && sufficient_parms_p (FUNCTION_FIRST_USER_PARMTYPE (fn))); |
| } |
| |
| /* Clobber the contents of *this to let the back end know that the object |
| storage is dead when we enter the constructor or leave the destructor. */ |
| |
| static tree |
| build_clobber_this () |
| { |
| /* Clobbering an empty base is pointless, and harmful if its one byte |
| TYPE_SIZE overlays real data. */ |
| if (is_empty_class (current_class_type)) |
| return void_node; |
| |
| /* If we have virtual bases, clobber the whole object, but only if we're in |
| charge. If we don't have virtual bases, clobber the as-base type so we |
| don't mess with tail padding. */ |
| bool vbases = CLASSTYPE_VBASECLASSES (current_class_type); |
| |
| tree ctype = current_class_type; |
| if (!vbases) |
| ctype = CLASSTYPE_AS_BASE (ctype); |
| |
| tree clobber = build_clobber (ctype); |
| |
| tree thisref = current_class_ref; |
| if (ctype != current_class_type) |
| { |
| thisref = build_nop (build_reference_type (ctype), current_class_ptr); |
| thisref = convert_from_reference (thisref); |
| } |
| |
| tree exprstmt = build2 (MODIFY_EXPR, void_type_node, thisref, clobber); |
| if (vbases) |
| exprstmt = build_if_in_charge (exprstmt); |
| |
| return exprstmt; |
| } |
| |
| /* Create the FUNCTION_DECL for a function definition. |
| DECLSPECS and DECLARATOR are the parts of the declaration; |
| they describe the function's name and the type it returns, |
| but twisted together in a fashion that parallels the syntax of C. |
| |
| FLAGS is a bitwise or of SF_PRE_PARSED (indicating that the |
| DECLARATOR is really the DECL for the function we are about to |
| process and that DECLSPECS should be ignored), SF_INCLASS_INLINE |
| indicating that the function is an inline defined in-class. |
| |
| This function creates a binding context for the function body |
| as well as setting up the FUNCTION_DECL in current_function_decl. |
| |
| For C++, we must first check whether that datum makes any sense. |
| For example, "class A local_a(1,2);" means that variable local_a |
| is an aggregate of type A, which should have a constructor |
| applied to it with the argument list [1, 2]. |
| |
| On entry, DECL_INITIAL (decl1) should be NULL_TREE or error_mark_node, |
| or may be a BLOCK if the function has been defined previously |
| in this translation unit. On exit, DECL_INITIAL (decl1) will be |
| error_mark_node if the function has never been defined, or |
| a BLOCK if the function has been defined somewhere. */ |
| |
| bool |
| start_preparsed_function (tree decl1, tree attrs, int flags) |
| { |
| tree ctype = NULL_TREE; |
| tree fntype; |
| tree restype; |
| int doing_friend = 0; |
| cp_binding_level *bl; |
| tree current_function_parms; |
| struct c_fileinfo *finfo |
| = get_fileinfo (LOCATION_FILE (DECL_SOURCE_LOCATION (decl1))); |
| bool honor_interface; |
| |
| /* Sanity check. */ |
| gcc_assert (VOID_TYPE_P (TREE_VALUE (void_list_node))); |
| gcc_assert (TREE_CHAIN (void_list_node) == NULL_TREE); |
| |
| fntype = TREE_TYPE (decl1); |
| if (TREE_CODE (fntype) == METHOD_TYPE) |
| ctype = TYPE_METHOD_BASETYPE (fntype); |
| |
| /* ISO C++ 11.4/5. A friend function defined in a class is in |
| the (lexical) scope of the class in which it is defined. */ |
| if (!ctype && DECL_FRIEND_P (decl1)) |
| { |
| ctype = DECL_FRIEND_CONTEXT (decl1); |
| |
| /* CTYPE could be null here if we're dealing with a template; |
| for example, `inline friend float foo()' inside a template |
| will have no CTYPE set. */ |
| if (ctype && TREE_CODE (ctype) != RECORD_TYPE) |
| ctype = NULL_TREE; |
| else |
| doing_friend = 1; |
| } |
| |
| if (DECL_DECLARED_INLINE_P (decl1) |
| && lookup_attribute ("noinline", attrs)) |
| warning_at (DECL_SOURCE_LOCATION (decl1), 0, |
| "inline function %qD given attribute noinline", decl1); |
| |
| /* Handle gnu_inline attribute. */ |
| if (GNU_INLINE_P (decl1)) |
| { |
| DECL_EXTERNAL (decl1) = 1; |
| DECL_NOT_REALLY_EXTERN (decl1) = 0; |
| DECL_INTERFACE_KNOWN (decl1) = 1; |
| DECL_DISREGARD_INLINE_LIMITS (decl1) = 1; |
| } |
| |
| if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (decl1)) |
| /* This is a constructor, we must ensure that any default args |
| introduced by this definition are propagated to the clones |
| now. The clones are used directly in overload resolution. */ |
| adjust_clone_args (decl1); |
| |
| /* Sometimes we don't notice that a function is a static member, and |
| build a METHOD_TYPE for it. Fix that up now. */ |
| gcc_assert (!(ctype != NULL_TREE && DECL_STATIC_FUNCTION_P (decl1) |
| && TREE_CODE (TREE_TYPE (decl1)) == METHOD_TYPE)); |
| |
| /* Set up current_class_type, and enter the scope of the class, if |
| appropriate. */ |
| if (ctype) |
| push_nested_class (ctype); |
| else if (DECL_STATIC_FUNCTION_P (decl1)) |
| push_nested_class (DECL_CONTEXT (decl1)); |
| |
| /* Now that we have entered the scope of the class, we must restore |
| the bindings for any template parameters surrounding DECL1, if it |
| is an inline member template. (Order is important; consider the |
| case where a template parameter has the same name as a field of |
| the class.) It is not until after this point that |
| PROCESSING_TEMPLATE_DECL is guaranteed to be set up correctly. */ |
| if (flags & SF_INCLASS_INLINE) |
| maybe_begin_member_template_processing (decl1); |
| |
| /* Effective C++ rule 15. */ |
| if (warn_ecpp |
| && DECL_ASSIGNMENT_OPERATOR_P (decl1) |
| && DECL_OVERLOADED_OPERATOR_IS (decl1, NOP_EXPR) |
| && VOID_TYPE_P (TREE_TYPE (fntype))) |
| warning (OPT_Weffc__, |
| "%<operator=%> should return a reference to %<*this%>"); |
| |
| /* Make the init_value nonzero so pushdecl knows this is not tentative. |
| error_mark_node is replaced below (in poplevel) with the BLOCK. */ |
| if (!DECL_INITIAL (decl1)) |
| DECL_INITIAL (decl1) = error_mark_node; |
| |
| /* This function exists in static storage. |
| (This does not mean `static' in the C sense!) */ |
| TREE_STATIC (decl1) = 1; |
| |
| /* We must call push_template_decl after current_class_type is set |
| up. (If we are processing inline definitions after exiting a |
| class scope, current_class_type will be NULL_TREE until set above |
| by push_nested_class.) */ |
| if (processing_template_decl) |
| { |
| tree newdecl1 = push_template_decl (decl1); |
| if (newdecl1 == error_mark_node) |
| { |
| if (ctype || DECL_STATIC_FUNCTION_P (decl1)) |
| pop_nested_class (); |
| return false; |
| } |
| decl1 = newdecl1; |
| } |
| |
| /* Make sure the parameter and return types are reasonable. When |
| you declare a function, these types can be incomplete, but they |
| must be complete when you define the function. */ |
| check_function_type (decl1, DECL_ARGUMENTS (decl1)); |
| |
| /* Build the return declaration for the function. */ |
| restype = TREE_TYPE (fntype); |
| |
| if (DECL_RESULT (decl1) == NULL_TREE) |
| { |
| tree resdecl; |
| |
| resdecl = build_decl (input_location, RESULT_DECL, 0, restype); |
| DECL_ARTIFICIAL (resdecl) = 1; |
| DECL_IGNORED_P (resdecl) = 1; |
| DECL_RESULT (decl1) = resdecl; |
| |
| cp_apply_type_quals_to_decl (cp_type_quals (restype), resdecl); |
| } |
| |
| /* Record the decl so that the function name is defined. |
| If we already have a decl for this name, and it is a FUNCTION_DECL, |
| use the old decl. */ |
| if (!processing_template_decl && !(flags & SF_PRE_PARSED)) |
| { |
| /* A specialization is not used to guide overload resolution. */ |
| if (!DECL_FUNCTION_MEMBER_P (decl1) |
| && !(DECL_USE_TEMPLATE (decl1) && |
| PRIMARY_TEMPLATE_P (DECL_TI_TEMPLATE (decl1)))) |
| { |
| tree olddecl = pushdecl (decl1); |
| |
| if (olddecl == error_mark_node) |
| /* If something went wrong when registering the declaration, |
| use DECL1; we have to have a FUNCTION_DECL to use when |
| parsing the body of the function. */ |
| ; |
| else |
| { |
| /* Otherwise, OLDDECL is either a previous declaration |
| of the same function or DECL1 itself. */ |
| |
| if (warn_missing_declarations |
| && olddecl == decl1 |
| && !DECL_MAIN_P (decl1) |
| && TREE_PUBLIC (decl1) |
| && !DECL_DECLARED_INLINE_P (decl1)) |
| { |
| tree context; |
| |
| /* Check whether DECL1 is in an anonymous |
| namespace. */ |
| for (context = DECL_CONTEXT (decl1); |
| context; |
| context = DECL_CONTEXT (context)) |
| { |
| if (TREE_CODE (context) == NAMESPACE_DECL |
| && DECL_NAME (context) == NULL_TREE) |
| break; |
| } |
| |
| if (context == NULL) |
| warning_at (DECL_SOURCE_LOCATION (decl1), |
| OPT_Wmissing_declarations, |
| "no previous declaration for %qD", decl1); |
| } |
| |
| decl1 = olddecl; |
| } |
| } |
| else |
| { |
| /* We need to set the DECL_CONTEXT. */ |
| if (!DECL_CONTEXT (decl1) && DECL_TEMPLATE_INFO (decl1)) |
| DECL_CONTEXT (decl1) = DECL_CONTEXT (DECL_TI_TEMPLATE (decl1)); |
| } |
| fntype = TREE_TYPE (decl1); |
| restype = TREE_TYPE (fntype); |
| |
| /* If #pragma weak applies, mark the decl appropriately now. |
| The pragma only applies to global functions. Because |
| determining whether or not the #pragma applies involves |
| computing the mangled name for the declaration, we cannot |
| apply the pragma until after we have merged this declaration |
| with any previous declarations; if the original declaration |
| has a linkage specification, that specification applies to |
| the definition as well, and may affect the mangled name. */ |
| if (DECL_FILE_SCOPE_P (decl1)) |
| maybe_apply_pragma_weak (decl1); |
| } |
| |
| /* We are now in the scope of the function being defined. */ |
| current_function_decl = decl1; |
| |
| /* Save the parm names or decls from this function's declarator |
| where store_parm_decls will find them. */ |
| current_function_parms = DECL_ARGUMENTS (decl1); |
| |
| /* Let the user know we're compiling this function. */ |
| announce_function (decl1); |
| |
| gcc_assert (DECL_INITIAL (decl1)); |
| |
| /* This function may already have been parsed, in which case just |
| return; our caller will skip over the body without parsing. */ |
| if (DECL_INITIAL (decl1) != error_mark_node) |
| return true; |
| |
| /* Initialize RTL machinery. We cannot do this until |
| CURRENT_FUNCTION_DECL and DECL_RESULT are set up. We do this |
| even when processing a template; this is how we get |
| CFUN set up, and our per-function variables initialized. |
| FIXME factor out the non-RTL stuff. */ |
| bl = current_binding_level; |
| allocate_struct_function (decl1, processing_template_decl); |
| |
| /* Initialize the language data structures. Whenever we start |
| a new function, we destroy temporaries in the usual way. */ |
| cfun->language = ggc_cleared_alloc<language_function> (); |
| current_stmt_tree ()->stmts_are_full_exprs_p = 1; |
| current_binding_level = bl; |
| |
| if (!processing_template_decl && type_uses_auto (restype)) |
| { |
| FNDECL_USED_AUTO (decl1) = true; |
| current_function_auto_return_pattern = restype; |
| } |
| |
| /* Start the statement-tree, start the tree now. */ |
| DECL_SAVED_TREE (decl1) = push_stmt_list (); |
| |
| /* If we are (erroneously) defining a function that we have already |
| defined before, wipe out what we knew before. */ |
| if (!DECL_PENDING_INLINE_P (decl1)) |
| DECL_SAVED_FUNCTION_DATA (decl1) = NULL; |
| |
| if (ctype && !doing_friend && !DECL_STATIC_FUNCTION_P (decl1)) |
| { |
| /* We know that this was set up by `grokclassfn'. We do not |
| wait until `store_parm_decls', since evil parse errors may |
| never get us to that point. Here we keep the consistency |
| between `current_class_type' and `current_class_ptr'. */ |
| tree t = DECL_ARGUMENTS (decl1); |
| |
| gcc_assert (t != NULL_TREE && TREE_CODE (t) == PARM_DECL); |
| gcc_assert (TYPE_PTR_P (TREE_TYPE (t))); |
| |
| cp_function_chain->x_current_class_ref |
| = cp_build_fold_indirect_ref (t); |
| /* Set this second to avoid shortcut in cp_build_indirect_ref. */ |
| cp_function_chain->x_current_class_ptr = t; |
| |
| /* Constructors and destructors need to know whether they're "in |
| charge" of initializing virtual base classes. */ |
| t = DECL_CHAIN (t); |
| if (DECL_HAS_IN_CHARGE_PARM_P (decl1)) |
| { |
| current_in_charge_parm = t; |
| t = DECL_CHAIN (t); |
| } |
| if (DECL_HAS_VTT_PARM_P (decl1)) |
| { |
| gcc_assert (DECL_NAME (t) == vtt_parm_identifier); |
| current_vtt_parm = t; |
| } |
| } |
| |
| honor_interface = (!DECL_TEMPLATE_INSTANTIATION (decl1) |
| /* Implicitly-defined methods (like the |
| destructor for a class in which no destructor |
| is explicitly declared) must not be defined |
| until their definition is needed. So, we |
| ignore interface specifications for |
| compiler-generated functions. */ |
| && !DECL_ARTIFICIAL (decl1)); |
| |
| if (processing_template_decl) |
| /* Don't mess with interface flags. */; |
| else if (DECL_INTERFACE_KNOWN (decl1)) |
| { |
| tree ctx = decl_function_context (decl1); |
| |
| if (DECL_NOT_REALLY_EXTERN (decl1)) |
| DECL_EXTERNAL (decl1) = 0; |
| |
| if (ctx != NULL_TREE && vague_linkage_p (ctx)) |
| /* This is a function in a local class in an extern inline |
| or template function. */ |
| comdat_linkage (decl1); |
| } |
| /* If this function belongs to an interface, it is public. |
| If it belongs to someone else's interface, it is also external. |
| This only affects inlines and template instantiations. */ |
| else if (!finfo->interface_unknown && honor_interface) |
| { |
| if (DECL_DECLARED_INLINE_P (decl1) |
| || DECL_TEMPLATE_INSTANTIATION (decl1)) |
| { |
| DECL_EXTERNAL (decl1) |
| = (finfo->interface_only |
| || (DECL_DECLARED_INLINE_P (decl1) |
| && ! flag_implement_inlines |
| && !DECL_VINDEX (decl1))); |
| |
| /* For WIN32 we also want to put these in linkonce sections. */ |
| maybe_make_one_only (decl1); |
| } |
| else |
| DECL_EXTERNAL (decl1) = 0; |
| DECL_INTERFACE_KNOWN (decl1) = 1; |
| /* If this function is in an interface implemented in this file, |
| make sure that the back end knows to emit this function |
| here. */ |
| if (!DECL_EXTERNAL (decl1)) |
| mark_needed (decl1); |
| } |
| else if (finfo->interface_unknown && finfo->interface_only |
| && honor_interface) |
| { |
| /* If MULTIPLE_SYMBOL_SPACES is defined and we saw a #pragma |
| interface, we will have both finfo->interface_unknown and |
| finfo->interface_only set. In that case, we don't want to |
| use the normal heuristics because someone will supply a |
| #pragma implementation elsewhere, and deducing it here would |
| produce a conflict. */ |
| comdat_linkage (decl1); |
| DECL_EXTERNAL (decl1) = 0; |
| DECL_INTERFACE_KNOWN (decl1) = 1; |
| DECL_DEFER_OUTPUT (decl1) = 1; |
| } |
| else |
| { |
| /* This is a definition, not a reference. |
| So clear DECL_EXTERNAL, unless this is a GNU extern inline. */ |
| if (!GNU_INLINE_P (decl1)) |
| DECL_EXTERNAL (decl1) = 0; |
| |
| if ((DECL_DECLARED_INLINE_P (decl1) |
| || DECL_TEMPLATE_INSTANTIATION (decl1)) |
| && ! DECL_INTERFACE_KNOWN (decl1)) |
| DECL_DEFER_OUTPUT (decl1) = 1; |
| else |
| DECL_INTERFACE_KNOWN (decl1) = 1; |
| } |
| |
| /* Determine the ELF visibility attribute for the function. We must not |
| do this before calling "pushdecl", as we must allow "duplicate_decls" |
| to merge any attributes appropriately. We also need to wait until |
| linkage is set. */ |
| if (!DECL_CLONED_FUNCTION_P (decl1)) |
| determine_visibility (decl1); |
| |
| if (!processing_template_decl) |
| maybe_instantiate_noexcept (decl1); |
| |
| begin_scope (sk_function_parms, decl1); |
| |
| ++function_depth; |
| |
| if (DECL_DESTRUCTOR_P (decl1) |
| || (DECL_CONSTRUCTOR_P (decl1) |
| && targetm.cxx.cdtor_returns_this ())) |
| { |
| cdtor_label = create_artificial_label (input_location); |
| LABEL_DECL_CDTOR (cdtor_label) = true; |
| } |
| |
| start_fname_decls (); |
| |
| store_parm_decls (current_function_parms); |
| |
| push_operator_bindings (); |
| |
| if (!processing_template_decl |
| && (flag_lifetime_dse > 1) |
| && DECL_CONSTRUCTOR_P (decl1) |
| && !DECL_CLONED_FUNCTION_P (decl1) |
| /* Clobbering an empty base is harmful if it overlays real data. */ |
| && !is_empty_class (current_class_type) |
| /* We can't clobber safely for an implicitly-defined default constructor |
| because part of the initialization might happen before we enter the |
| constructor, via AGGR_INIT_ZERO_FIRST (c++/68006). */ |
| && !implicit_default_ctor_p (decl1)) |
| finish_expr_stmt (build_clobber_this ()); |
| |
| if (!processing_template_decl |
| && DECL_CONSTRUCTOR_P (decl1) |
| && sanitize_flags_p (SANITIZE_VPTR) |
| && !DECL_CLONED_FUNCTION_P (decl1) |
| && !implicit_default_ctor_p (decl1)) |
| cp_ubsan_maybe_initialize_vtbl_ptrs (current_class_ptr); |
| |
| if (!DECL_OMP_DECLARE_REDUCTION_P (decl1)) |
| start_lambda_scope (decl1); |
| |
| return true; |
| } |
| |
| |
| /* Like start_preparsed_function, except that instead of a |
| FUNCTION_DECL, this function takes DECLSPECS and DECLARATOR. |
| |
| Returns true on success. If the DECLARATOR is not suitable |
| for a function, we return false, which tells the parser to |
| skip the entire function. */ |
| |
| bool |
| start_function (cp_decl_specifier_seq *declspecs, |
| const cp_declarator *declarator, |
| tree attrs) |
| { |
| tree decl1; |
| |
| decl1 = grokdeclarator (declarator, declspecs, FUNCDEF, 1, &attrs); |
| invoke_plugin_callbacks (PLUGIN_START_PARSE_FUNCTION, decl1); |
| if (decl1 == error_mark_node) |
| return false; |
| /* If the declarator is not suitable for a function definition, |
| cause a syntax error. */ |
| if (decl1 == NULL_TREE || TREE_CODE (decl1) != FUNCTION_DECL) |
| { |
| error ("invalid function declaration"); |
| return false; |
| } |
| |
| if (DECL_MAIN_P (decl1)) |
| /* main must return int. grokfndecl should have corrected it |
| (and issued a diagnostic) if the user got it wrong. */ |
| gcc_assert (same_type_p (TREE_TYPE (TREE_TYPE (decl1)), |
| integer_type_node)); |
| |
| return start_preparsed_function (decl1, attrs, /*flags=*/SF_DEFAULT); |
| } |
| |
| /* Returns true iff an EH_SPEC_BLOCK should be created in the body of |
| FN. */ |
| |
| static bool |
| use_eh_spec_block (tree fn) |
| { |
| return (flag_exceptions && flag_enforce_eh_specs |
| && !processing_template_decl |
| && !type_throw_all_p (TREE_TYPE (fn)) |
| /* We insert the EH_SPEC_BLOCK only in the original |
| function; then, it is copied automatically to the |
| clones. */ |
| && !DECL_CLONED_FUNCTION_P (fn) |
| /* Implicitly-generated constructors and destructors have |
| exception specifications. However, those specifications |
| are the union of the possible exceptions specified by the |
| constructors/destructors for bases and members, so no |
| unallowed exception will ever reach this function. By |
| not creating the EH_SPEC_BLOCK we save a little memory, |
| and we avoid spurious warnings about unreachable |
| code. */ |
| && !DECL_DEFAULTED_FN (fn)); |
| } |
| |
| /* Store the parameter declarations into the current function declaration. |
| This is called after parsing the parameter declarations, before |
| digesting the body of the function. |
| |
| Also install to binding contour return value identifier, if any. */ |
| |
| static void |
| store_parm_decls (tree current_function_parms) |
| { |
| tree fndecl = current_function_decl; |
| tree parm; |
| |
| /* This is a chain of any other decls that came in among the parm |
| declarations. If a parm is declared with enum {foo, bar} x; |
| then CONST_DECLs for foo and bar are put here. */ |
| tree nonparms = NULL_TREE; |
| |
| if (current_function_parms) |
| { |
| /* This case is when the function was defined with an ANSI prototype. |
| The parms already have decls, so we need not do anything here |
| except record them as in effect |
| and complain if any redundant old-style parm decls were written. */ |
| |
| tree specparms = current_function_parms; |
| tree next; |
| |
| /* Must clear this because it might contain TYPE_DECLs declared |
| at class level. */ |
| current_binding_level->names = NULL; |
| |
| /* If we're doing semantic analysis, then we'll call pushdecl |
| for each of these. We must do them in reverse order so that |
| they end in the correct forward order. */ |
| specparms = nreverse (specparms); |
| |
| for (parm = specparms; parm; parm = next) |
| { |
| next = DECL_CHAIN (parm); |
| if (TREE_CODE (parm) == PARM_DECL) |
| pushdecl (parm); |
| else |
| { |
| /* If we find an enum constant or a type tag, |
| put it aside for the moment. */ |
| TREE_CHAIN (parm) = NULL_TREE; |
| nonparms = chainon (nonparms, parm); |
| } |
| } |
| |
| /* Get the decls in their original chain order and record in the |
| function. This is all and only the PARM_DECLs that were |
| pushed into scope by the loop above. */ |
| DECL_ARGUMENTS (fndecl) = get_local_decls (); |
| } |
| else |
| DECL_ARGUMENTS (fndecl) = NULL_TREE; |
| |
| /* Now store the final chain of decls for the arguments |
| as the decl-chain of the current lexical scope. |
| Put the enumerators in as well, at the front so that |
| DECL_ARGUMENTS is not modified. */ |
| current_binding_level->names = chainon (nonparms, DECL_ARGUMENTS (fndecl)); |
| |
| if (use_eh_spec_block (current_function_decl)) |
| current_eh_spec_block = begin_eh_spec_block (); |
| } |
| |
| |
| /* We have finished doing semantic analysis on DECL, but have not yet |
| generated RTL for its body. Save away our current state, so that |
| when we want to generate RTL later we know what to do. */ |
| |
| static void |
| save_function_data (tree decl) |
| { |
| struct language_function *f; |
| |
| /* Save the language-specific per-function data so that we can |
| get it back when we really expand this function. */ |
| gcc_assert (!DECL_PENDING_INLINE_P (decl)); |
| |
| /* Make a copy. */ |
| f = ggc_alloc<language_function> (); |
| memcpy (f, cp_function_chain, sizeof (struct language_function)); |
| DECL_SAVED_FUNCTION_DATA (decl) = f; |
| |
| /* Clear out the bits we don't need. */ |
| f->base.x_stmt_tree.x_cur_stmt_list = NULL; |
| f->bindings = NULL; |
| f->base.local_typedefs = NULL; |
| } |
| |
| |
| /* Set the return value of the constructor (if present). */ |
| |
| static void |
| finish_constructor_body (void) |
| { |
| tree val; |
| tree exprstmt; |
| |
| if (targetm.cxx.cdtor_returns_this ()) |
| { |
| /* Any return from a constructor will end up here. */ |
| add_stmt (build_stmt (input_location, LABEL_EXPR, cdtor_label)); |
| |
| val = DECL_ARGUMENTS (current_function_decl); |
| val = build2 (MODIFY_EXPR, TREE_TYPE (val), |
| DECL_RESULT (current_function_decl), val); |
| /* Return the address of the object. */ |
| exprstmt = build_stmt (input_location, RETURN_EXPR, val); |
| add_stmt (exprstmt); |
| } |
| } |
| |
| /* Do all the processing for the beginning of a destructor; set up the |
| vtable pointers and cleanups for bases and members. */ |
| |
| static void |
| begin_destructor_body (void) |
| { |
| tree compound_stmt; |
| |
| /* If the CURRENT_CLASS_TYPE is incomplete, we will have already |
| issued an error message. We still want to try to process the |
| body of the function, but initialize_vtbl_ptrs will crash if |
| TYPE_BINFO is NULL. */ |
| if (COMPLETE_TYPE_P (current_class_type)) |
| { |
| compound_stmt = begin_compound_stmt (0); |
| /* Make all virtual function table pointers in non-virtual base |
| classes point to CURRENT_CLASS_TYPE's virtual function |
| tables. */ |
| initialize_vtbl_ptrs (current_class_ptr); |
| finish_compound_stmt (compound_stmt); |
| |
| if (flag_lifetime_dse |
| /* Clobbering an empty base is harmful if it overlays real data. */ |
| && !is_empty_class (current_class_type)) |
| { |
| if (sanitize_flags_p (SANITIZE_VPTR) |
| && (flag_sanitize_recover & SANITIZE_VPTR) == 0 |
| && TYPE_CONTAINS_VPTR_P (current_class_type)) |
| { |
| tree binfo = TYPE_BINFO (current_class_type); |
| tree ref |
| = cp_build_fold_indirect_ref (current_class_ptr); |
| |
| tree vtbl_ptr = build_vfield_ref (ref, TREE_TYPE (binfo)); |
| tree vtbl = build_zero_cst (TREE_TYPE (vtbl_ptr)); |
| tree stmt = cp_build_modify_expr (input_location, vtbl_ptr, |
| NOP_EXPR, vtbl, |
| tf_warning_or_error); |
| /* If the vptr is shared with some virtual nearly empty base, |
| don't clear it if not in charge, the dtor of the virtual |
| nearly empty base will do that later. */ |
| if (CLASSTYPE_VBASECLASSES (current_class_type)) |
| { |
| tree c = current_class_type; |
| while (CLASSTYPE_PRIMARY_BINFO (c)) |
| { |
| if (BINFO_VIRTUAL_P (CLASSTYPE_PRIMARY_BINFO (c))) |
| { |
| stmt = convert_to_void (stmt, ICV_STATEMENT, |
| tf_warning_or_error); |
| stmt = build_if_in_charge (stmt); |
| break; |
| } |
| c = BINFO_TYPE (CLASSTYPE_PRIMARY_BINFO (c)); |
| } |
| } |
| finish_decl_cleanup (NULL_TREE, stmt); |
| } |
| else |
| finish_decl_cleanup (NULL_TREE, build_clobber_this ()); |
| } |
| |
| /* And insert cleanups for our bases and members so that they |
| will be properly destroyed if we throw. */ |
| push_base_cleanups (); |
| } |
| } |
| |
| /* At the end of every destructor we generate code to delete the object if |
| necessary. Do that now. */ |
| |
| static void |
| finish_destructor_body (void) |
| { |
| tree exprstmt; |
| |
| /* Any return from a destructor will end up here; that way all base |
| and member cleanups will be run when the function returns. */ |
| add_stmt (build_stmt (input_location, LABEL_EXPR, cdtor_label)); |
| |
| if (targetm.cxx.cdtor_returns_this ()) |
| { |
| tree val; |
| |
| val = DECL_ARGUMENTS (current_function_decl); |
| val = build2 (MODIFY_EXPR, TREE_TYPE (val), |
| DECL_RESULT (current_function_decl), val); |
| /* Return the address of the object. */ |
| exprstmt = build_stmt (input_location, RETURN_EXPR, val); |
| add_stmt (exprstmt); |
| } |
| } |
| |
| /* Do the necessary processing for the beginning of a function body, which |
| in this case includes member-initializers, but not the catch clauses of |
| a function-try-block. Currently, this means opening a binding level |
| for the member-initializers (in a ctor), member cleanups (in a dtor), |
| and capture proxies (in a lambda operator()). */ |
| |
| tree |
| begin_function_body (void) |
| { |
| tree stmt; |
| |
| if (! FUNCTION_NEEDS_BODY_BLOCK (current_function_decl)) |
| return NULL_TREE; |
| |
| if (processing_template_decl) |
| /* Do nothing now. */; |
| else |
| /* Always keep the BLOCK node associated with the outermost pair of |
| curly braces of a function. These are needed for correct |
| operation of dwarfout.c. */ |
| keep_next_level (true); |
| |
| stmt = begin_compound_stmt (BCS_FN_BODY); |
| |
| if (processing_template_decl) |
| /* Do nothing now. */; |
| else if (DECL_DESTRUCTOR_P (current_function_decl)) |
| begin_destructor_body (); |
| |
| return stmt; |
| } |
| |
| /* Do the processing for the end of a function body. Currently, this means |
| closing out the cleanups for fully-constructed bases and members, and in |
| the case of the destructor, deleting the object if desired. Again, this |
| is only meaningful for [cd]tors, since they are the only functions where |
| there is a significant distinction between the main body and any |
| function catch clauses. Handling, say, main() return semantics here |
| would be wrong, as flowing off the end of a function catch clause for |
| main() would also need to return 0. */ |
| |
| void |
| finish_function_body (tree compstmt) |
| { |
| if (compstmt == NULL_TREE) |
| return; |
| |
| /* Close the block. */ |
| finish_compound_stmt (compstmt); |
| |
| if (processing_template_decl) |
| /* Do nothing now. */; |
| else if (DECL_CONSTRUCTOR_P (current_function_decl)) |
| finish_constructor_body (); |
|