| /* Process declarations and variables for C++ compiler. |
| Copyright (C) 1988-2022 Free Software Foundation, Inc. |
| Hacked 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 "memmodel.h" |
| #include "target.h" |
| #include "cp-tree.h" |
| #include "c-family/c-common.h" |
| #include "timevar.h" |
| #include "stringpool.h" |
| #include "cgraph.h" |
| #include "varasm.h" |
| #include "attribs.h" |
| #include "stor-layout.h" |
| #include "calls.h" |
| #include "decl.h" |
| #include "toplev.h" |
| #include "c-family/c-objc.h" |
| #include "c-family/c-pragma.h" |
| #include "dumpfile.h" |
| #include "intl.h" |
| #include "c-family/c-ada-spec.h" |
| #include "asan.h" |
| #include "optabs-query.h" |
| |
| /* Id for dumping the raw trees. */ |
| int raw_dump_id; |
| |
| extern cpp_reader *parse_in; |
| |
| /* This structure contains information about the initializations |
| and/or destructions required for a particular priority level. */ |
| typedef struct priority_info_s { |
| /* Nonzero if there have been any initializations at this priority |
| throughout the translation unit. */ |
| int initializations_p; |
| /* Nonzero if there have been any destructions at this priority |
| throughout the translation unit. */ |
| int destructions_p; |
| } *priority_info; |
| |
| static tree start_objects (int, int); |
| static void finish_objects (int, int, tree); |
| static tree start_static_storage_duration_function (unsigned); |
| static void finish_static_storage_duration_function (tree); |
| static priority_info get_priority_info (int); |
| static void do_static_initialization_or_destruction (tree, bool); |
| static void one_static_initialization_or_destruction (tree, tree, bool); |
| static void generate_ctor_or_dtor_function (bool, int, location_t *); |
| static int generate_ctor_and_dtor_functions_for_priority (splay_tree_node, |
| void *); |
| static tree prune_vars_needing_no_initialization (tree *); |
| static void write_out_vars (tree); |
| static void import_export_class (tree); |
| static tree get_guard_bits (tree); |
| static void determine_visibility_from_class (tree, tree); |
| static bool determine_hidden_inline (tree); |
| |
| /* A list of static class variables. This is needed, because a |
| static class variable can be declared inside the class without |
| an initializer, and then initialized, statically, outside the class. */ |
| static GTY(()) vec<tree, va_gc> *pending_statics; |
| |
| /* A list of functions which were declared inline, but which we |
| may need to emit outline anyway. */ |
| static GTY(()) vec<tree, va_gc> *deferred_fns; |
| |
| /* A list of decls that use types with no linkage, which we need to make |
| sure are defined. */ |
| static GTY(()) vec<tree, va_gc> *no_linkage_decls; |
| |
| /* A vector of alternating decls and identifiers, where the latter |
| is to be an alias for the former if the former is defined. */ |
| static GTY(()) vec<tree, va_gc> *mangling_aliases; |
| |
| /* hash traits for declarations. Hashes single decls via |
| DECL_ASSEMBLER_NAME_RAW. */ |
| |
| struct mangled_decl_hash : ggc_remove <tree> |
| { |
| typedef tree value_type; /* A DECL. */ |
| typedef tree compare_type; /* An identifier. */ |
| |
| static hashval_t hash (const value_type decl) |
| { |
| return IDENTIFIER_HASH_VALUE (DECL_ASSEMBLER_NAME_RAW (decl)); |
| } |
| static bool equal (const value_type existing, compare_type candidate) |
| { |
| tree name = DECL_ASSEMBLER_NAME_RAW (existing); |
| return candidate == name; |
| } |
| |
| static const bool empty_zero_p = true; |
| static inline void mark_empty (value_type &p) {p = NULL_TREE;} |
| static inline bool is_empty (value_type p) {return !p;} |
| |
| static bool is_deleted (value_type e) |
| { |
| return e == reinterpret_cast <value_type> (1); |
| } |
| static void mark_deleted (value_type &e) |
| { |
| e = reinterpret_cast <value_type> (1); |
| } |
| }; |
| |
| /* A hash table of decls keyed by mangled name. Used to figure out if |
| we need compatibility aliases. */ |
| static GTY(()) hash_table<mangled_decl_hash> *mangled_decls; |
| |
| /* Nonzero if we're done parsing and into end-of-file activities. */ |
| |
| int at_eof; |
| |
| /* True if note_mangling_alias should enqueue mangling aliases for |
| later generation, rather than emitting them right away. */ |
| |
| bool defer_mangling_aliases = true; |
| |
| |
| /* Return a member function type (a METHOD_TYPE), given FNTYPE (a |
| FUNCTION_TYPE), CTYPE (class type), and QUALS (the cv-qualifiers |
| that apply to the function). */ |
| |
| tree |
| build_memfn_type (tree fntype, tree ctype, cp_cv_quals quals, |
| cp_ref_qualifier rqual) |
| { |
| if (fntype == error_mark_node || ctype == error_mark_node) |
| return error_mark_node; |
| |
| gcc_assert (FUNC_OR_METHOD_TYPE_P (fntype)); |
| |
| cp_cv_quals type_quals = quals & ~TYPE_QUAL_RESTRICT; |
| ctype = cp_build_qualified_type (ctype, type_quals); |
| |
| tree newtype |
| = build_method_type_directly (ctype, TREE_TYPE (fntype), |
| (TREE_CODE (fntype) == METHOD_TYPE |
| ? TREE_CHAIN (TYPE_ARG_TYPES (fntype)) |
| : TYPE_ARG_TYPES (fntype))); |
| if (tree attrs = TYPE_ATTRIBUTES (fntype)) |
| newtype = cp_build_type_attribute_variant (newtype, attrs); |
| newtype = build_cp_fntype_variant (newtype, rqual, |
| TYPE_RAISES_EXCEPTIONS (fntype), |
| TYPE_HAS_LATE_RETURN_TYPE (fntype)); |
| |
| return newtype; |
| } |
| |
| /* Return a variant of FNTYPE, a FUNCTION_TYPE or METHOD_TYPE, with its |
| return type changed to NEW_RET. */ |
| |
| tree |
| change_return_type (tree new_ret, tree fntype) |
| { |
| if (new_ret == error_mark_node) |
| return fntype; |
| |
| if (same_type_p (new_ret, TREE_TYPE (fntype))) |
| return fntype; |
| |
| tree newtype; |
| tree args = TYPE_ARG_TYPES (fntype); |
| |
| if (TREE_CODE (fntype) == FUNCTION_TYPE) |
| { |
| newtype = build_function_type (new_ret, args); |
| newtype = apply_memfn_quals (newtype, |
| type_memfn_quals (fntype)); |
| } |
| else |
| newtype = build_method_type_directly |
| (class_of_this_parm (fntype), new_ret, TREE_CHAIN (args)); |
| |
| if (tree attrs = TYPE_ATTRIBUTES (fntype)) |
| newtype = cp_build_type_attribute_variant (newtype, attrs); |
| newtype = cxx_copy_lang_qualifiers (newtype, fntype); |
| |
| return newtype; |
| } |
| |
| /* Build a PARM_DECL of FN with NAME and TYPE, and set DECL_ARG_TYPE |
| appropriately. */ |
| |
| tree |
| cp_build_parm_decl (tree fn, tree name, tree type) |
| { |
| tree parm = build_decl (input_location, |
| PARM_DECL, name, type); |
| DECL_CONTEXT (parm) = fn; |
| |
| /* DECL_ARG_TYPE is only used by the back end and the back end never |
| sees templates. */ |
| if (!processing_template_decl) |
| DECL_ARG_TYPE (parm) = type_passed_as (type); |
| |
| return parm; |
| } |
| |
| /* Returns a PARM_DECL of FN for a parameter of the indicated TYPE, with the |
| indicated NAME. */ |
| |
| tree |
| build_artificial_parm (tree fn, tree name, tree type) |
| { |
| tree parm = cp_build_parm_decl (fn, name, type); |
| DECL_ARTIFICIAL (parm) = 1; |
| /* All our artificial parms are implicitly `const'; they cannot be |
| assigned to. */ |
| TREE_READONLY (parm) = 1; |
| return parm; |
| } |
| |
| /* Constructors for types with virtual baseclasses need an "in-charge" flag |
| saying whether this constructor is responsible for initialization of |
| virtual baseclasses or not. All destructors also need this "in-charge" |
| flag, which additionally determines whether or not the destructor should |
| free the memory for the object. |
| |
| This function adds the "in-charge" flag to member function FN if |
| appropriate. It is called from grokclassfn and tsubst. |
| FN must be either a constructor or destructor. |
| |
| The in-charge flag follows the 'this' parameter, and is followed by the |
| VTT parm (if any), then the user-written parms. */ |
| |
| void |
| maybe_retrofit_in_chrg (tree fn) |
| { |
| tree basetype, arg_types, parms, parm, fntype; |
| |
| /* If we've already add the in-charge parameter don't do it again. */ |
| if (DECL_HAS_IN_CHARGE_PARM_P (fn)) |
| return; |
| |
| /* When processing templates we can't know, in general, whether or |
| not we're going to have virtual baseclasses. */ |
| if (processing_template_decl) |
| return; |
| |
| /* We don't need an in-charge parameter for constructors that don't |
| have virtual bases. */ |
| if (DECL_CONSTRUCTOR_P (fn) |
| && !CLASSTYPE_VBASECLASSES (DECL_CONTEXT (fn))) |
| return; |
| |
| arg_types = TYPE_ARG_TYPES (TREE_TYPE (fn)); |
| basetype = TREE_TYPE (TREE_VALUE (arg_types)); |
| arg_types = TREE_CHAIN (arg_types); |
| |
| parms = DECL_CHAIN (DECL_ARGUMENTS (fn)); |
| |
| /* If this is a subobject constructor or destructor, our caller will |
| pass us a pointer to our VTT. */ |
| if (CLASSTYPE_VBASECLASSES (DECL_CONTEXT (fn))) |
| { |
| parm = build_artificial_parm (fn, vtt_parm_identifier, vtt_parm_type); |
| |
| /* First add it to DECL_ARGUMENTS between 'this' and the real args... */ |
| DECL_CHAIN (parm) = parms; |
| parms = parm; |
| |
| /* ...and then to TYPE_ARG_TYPES. */ |
| arg_types = hash_tree_chain (vtt_parm_type, arg_types); |
| |
| DECL_HAS_VTT_PARM_P (fn) = 1; |
| } |
| |
| /* Then add the in-charge parm (before the VTT parm). */ |
| parm = build_artificial_parm (fn, in_charge_identifier, integer_type_node); |
| DECL_CHAIN (parm) = parms; |
| parms = parm; |
| arg_types = hash_tree_chain (integer_type_node, arg_types); |
| |
| /* Insert our new parameter(s) into the list. */ |
| DECL_CHAIN (DECL_ARGUMENTS (fn)) = parms; |
| |
| /* And rebuild the function type. */ |
| fntype = build_method_type_directly (basetype, TREE_TYPE (TREE_TYPE (fn)), |
| arg_types); |
| if (TYPE_ATTRIBUTES (TREE_TYPE (fn))) |
| fntype = (cp_build_type_attribute_variant |
| (fntype, TYPE_ATTRIBUTES (TREE_TYPE (fn)))); |
| fntype = cxx_copy_lang_qualifiers (fntype, TREE_TYPE (fn)); |
| TREE_TYPE (fn) = fntype; |
| |
| /* Now we've got the in-charge parameter. */ |
| DECL_HAS_IN_CHARGE_PARM_P (fn) = 1; |
| } |
| |
| /* Classes overload their constituent function names automatically. |
| When a function name is declared in a record structure, |
| its name is changed to it overloaded name. Since names for |
| constructors and destructors can conflict, we place a leading |
| '$' for destructors. |
| |
| CNAME is the name of the class we are grokking for. |
| |
| FUNCTION is a FUNCTION_DECL. It was created by `grokdeclarator'. |
| |
| FLAGS contains bits saying what's special about today's |
| arguments. DTOR_FLAG == DESTRUCTOR. |
| |
| If FUNCTION is a destructor, then we must add the `auto-delete' field |
| as a second parameter. There is some hair associated with the fact |
| that we must "declare" this variable in the manner consistent with the |
| way the rest of the arguments were declared. |
| |
| QUALS are the qualifiers for the this pointer. */ |
| |
| void |
| grokclassfn (tree ctype, tree function, enum overload_flags flags) |
| { |
| tree fn_name = DECL_NAME (function); |
| |
| /* Even within an `extern "C"' block, members get C++ linkage. See |
| [dcl.link] for details. */ |
| SET_DECL_LANGUAGE (function, lang_cplusplus); |
| |
| if (fn_name == NULL_TREE) |
| { |
| error ("name missing for member function"); |
| fn_name = get_identifier ("<anonymous>"); |
| DECL_NAME (function) = fn_name; |
| } |
| |
| DECL_CONTEXT (function) = ctype; |
| |
| if (flags == DTOR_FLAG) |
| DECL_CXX_DESTRUCTOR_P (function) = 1; |
| |
| if (flags == DTOR_FLAG || DECL_CONSTRUCTOR_P (function)) |
| maybe_retrofit_in_chrg (function); |
| } |
| |
| /* Create an ARRAY_REF, checking for the user doing things backwards |
| along the way. |
| If INDEX_EXP is non-NULL, then that is the index expression, |
| otherwise INDEX_EXP_LIST is the list of index expressions. */ |
| |
| tree |
| grok_array_decl (location_t loc, tree array_expr, tree index_exp, |
| vec<tree, va_gc> **index_exp_list, tsubst_flags_t complain) |
| { |
| tree type; |
| tree expr; |
| tree orig_array_expr = array_expr; |
| tree orig_index_exp = index_exp; |
| vec<tree, va_gc> *orig_index_exp_list |
| = index_exp_list ? *index_exp_list : NULL; |
| tree overload = NULL_TREE; |
| |
| if (error_operand_p (array_expr) || error_operand_p (index_exp)) |
| return error_mark_node; |
| |
| if (processing_template_decl) |
| { |
| if (type_dependent_expression_p (array_expr) |
| || (index_exp ? type_dependent_expression_p (index_exp) |
| : any_type_dependent_arguments_p (*index_exp_list))) |
| { |
| if (index_exp == NULL) |
| index_exp = build_min_nt_call_vec (ovl_op_identifier (ARRAY_REF), |
| *index_exp_list); |
| return build_min_nt_loc (loc, ARRAY_REF, array_expr, index_exp, |
| NULL_TREE, NULL_TREE); |
| } |
| array_expr = build_non_dependent_expr (array_expr); |
| if (index_exp) |
| index_exp = build_non_dependent_expr (index_exp); |
| else |
| { |
| orig_index_exp_list = make_tree_vector_copy (*index_exp_list); |
| make_args_non_dependent (*index_exp_list); |
| } |
| } |
| |
| type = TREE_TYPE (array_expr); |
| gcc_assert (type); |
| type = non_reference (type); |
| |
| /* If they have an `operator[]', use that. */ |
| if (MAYBE_CLASS_TYPE_P (type) |
| || (index_exp && MAYBE_CLASS_TYPE_P (TREE_TYPE (index_exp))) |
| || (index_exp == NULL_TREE |
| && !(*index_exp_list)->is_empty () |
| && MAYBE_CLASS_TYPE_P (TREE_TYPE ((*index_exp_list)->last ())))) |
| { |
| if (index_exp) |
| expr = build_new_op (loc, ARRAY_REF, LOOKUP_NORMAL, array_expr, |
| index_exp, NULL_TREE, NULL_TREE, |
| &overload, complain); |
| else if ((*index_exp_list)->is_empty ()) |
| expr = build_op_subscript (loc, array_expr, index_exp_list, &overload, |
| complain); |
| else |
| { |
| expr = build_op_subscript (loc, array_expr, index_exp_list, |
| &overload, complain & tf_decltype); |
| if (expr == error_mark_node) |
| { |
| tree idx = build_x_compound_expr_from_vec (*index_exp_list, NULL, |
| tf_none); |
| if (idx != error_mark_node) |
| expr = build_new_op (loc, ARRAY_REF, LOOKUP_NORMAL, array_expr, |
| idx, NULL_TREE, NULL_TREE, &overload, |
| complain & tf_decltype); |
| if (expr == error_mark_node) |
| { |
| overload = NULL_TREE; |
| expr = build_op_subscript (loc, array_expr, index_exp_list, |
| &overload, complain); |
| } |
| else |
| /* If it would be valid albeit deprecated expression in C++20, |
| just pedwarn on it and treat it as if wrapped in (). */ |
| pedwarn (loc, OPT_Wcomma_subscript, |
| "top-level comma expression in array subscript " |
| "changed meaning in C++23"); |
| } |
| } |
| } |
| else |
| { |
| tree p1, p2, i1, i2; |
| bool swapped = false; |
| |
| /* Otherwise, create an ARRAY_REF for a pointer or array type. |
| It is a little-known fact that, if `a' is an array and `i' is |
| an int, you can write `i[a]', which means the same thing as |
| `a[i]'. */ |
| if (TREE_CODE (type) == ARRAY_TYPE || VECTOR_TYPE_P (type)) |
| p1 = array_expr; |
| else |
| p1 = build_expr_type_conversion (WANT_POINTER, array_expr, false); |
| |
| if (index_exp == NULL_TREE) |
| { |
| if ((*index_exp_list)->is_empty ()) |
| { |
| error_at (loc, "built-in subscript operator without expression " |
| "list"); |
| return error_mark_node; |
| } |
| tree idx = build_x_compound_expr_from_vec (*index_exp_list, NULL, |
| tf_none); |
| if (idx != error_mark_node) |
| /* If it would be valid albeit deprecated expression in C++20, |
| just pedwarn on it and treat it as if wrapped in (). */ |
| pedwarn (loc, OPT_Wcomma_subscript, |
| "top-level comma expression in array subscript " |
| "changed meaning in C++23"); |
| else |
| { |
| error_at (loc, "built-in subscript operator with more than one " |
| "expression in expression list"); |
| return error_mark_node; |
| } |
| index_exp = idx; |
| } |
| |
| if (TREE_CODE (TREE_TYPE (index_exp)) == ARRAY_TYPE) |
| p2 = index_exp; |
| else |
| p2 = build_expr_type_conversion (WANT_POINTER, index_exp, false); |
| |
| i1 = build_expr_type_conversion (WANT_INT | WANT_ENUM, array_expr, |
| false); |
| i2 = build_expr_type_conversion (WANT_INT | WANT_ENUM, index_exp, |
| false); |
| |
| if ((p1 && i2) && (i1 && p2)) |
| error ("ambiguous conversion for array subscript"); |
| |
| if (p1 && i2) |
| array_expr = p1, index_exp = i2; |
| else if (i1 && p2) |
| swapped = true, array_expr = p2, index_exp = i1; |
| else |
| { |
| error_at (loc, "invalid types %<%T[%T]%> for array subscript", |
| type, TREE_TYPE (index_exp)); |
| return error_mark_node; |
| } |
| |
| if (array_expr == error_mark_node || index_exp == error_mark_node) |
| error ("ambiguous conversion for array subscript"); |
| |
| if (TYPE_PTR_P (TREE_TYPE (array_expr))) |
| array_expr = mark_rvalue_use (array_expr); |
| else |
| array_expr = mark_lvalue_use_nonread (array_expr); |
| index_exp = mark_rvalue_use (index_exp); |
| if (swapped |
| && flag_strong_eval_order == 2 |
| && (TREE_SIDE_EFFECTS (array_expr) || TREE_SIDE_EFFECTS (index_exp))) |
| expr = build_array_ref (input_location, index_exp, array_expr); |
| else |
| expr = build_array_ref (input_location, array_expr, index_exp); |
| } |
| if (processing_template_decl && expr != error_mark_node) |
| { |
| if (overload != NULL_TREE) |
| { |
| if (orig_index_exp == NULL_TREE) |
| { |
| expr = build_min_non_dep_op_overload (expr, overload, |
| orig_array_expr, |
| orig_index_exp_list); |
| release_tree_vector (orig_index_exp_list); |
| return expr; |
| } |
| return build_min_non_dep_op_overload (ARRAY_REF, expr, overload, |
| orig_array_expr, |
| orig_index_exp); |
| } |
| |
| if (orig_index_exp == NULL_TREE) |
| { |
| orig_index_exp |
| = build_min_nt_call_vec (ovl_op_identifier (ARRAY_REF), |
| orig_index_exp_list); |
| release_tree_vector (orig_index_exp_list); |
| } |
| |
| return build_min_non_dep (ARRAY_REF, expr, orig_array_expr, |
| orig_index_exp, NULL_TREE, NULL_TREE); |
| } |
| return expr; |
| } |
| |
| /* Given the cast expression EXP, checking out its validity. Either return |
| an error_mark_node if there was an unavoidable error, return a cast to |
| void for trying to delete a pointer w/ the value 0, or return the |
| call to delete. If DOING_VEC is true, we handle things differently |
| for doing an array delete. |
| Implements ARM $5.3.4. This is called from the parser. */ |
| |
| tree |
| delete_sanity (location_t loc, tree exp, tree size, bool doing_vec, |
| int use_global_delete, tsubst_flags_t complain) |
| { |
| tree t, type; |
| |
| if (exp == error_mark_node) |
| return exp; |
| |
| if (processing_template_decl) |
| { |
| t = build_min (DELETE_EXPR, void_type_node, exp, size); |
| DELETE_EXPR_USE_GLOBAL (t) = use_global_delete; |
| DELETE_EXPR_USE_VEC (t) = doing_vec; |
| TREE_SIDE_EFFECTS (t) = 1; |
| SET_EXPR_LOCATION (t, loc); |
| return t; |
| } |
| |
| location_t exp_loc = cp_expr_loc_or_loc (exp, loc); |
| |
| /* An array can't have been allocated by new, so complain. */ |
| if (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE |
| && (complain & tf_warning)) |
| warning_at (exp_loc, 0, "deleting array %q#E", exp); |
| |
| t = build_expr_type_conversion (WANT_POINTER, exp, true); |
| |
| if (t == NULL_TREE || t == error_mark_node) |
| { |
| if (complain & tf_error) |
| error_at (exp_loc, |
| "type %q#T argument given to %<delete%>, expected pointer", |
| TREE_TYPE (exp)); |
| return error_mark_node; |
| } |
| |
| type = TREE_TYPE (t); |
| |
| /* As of Valley Forge, you can delete a pointer to const. */ |
| |
| /* You can't delete functions. */ |
| if (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE) |
| { |
| if (complain & tf_error) |
| error_at (exp_loc, |
| "cannot delete a function. Only pointer-to-objects are " |
| "valid arguments to %<delete%>"); |
| return error_mark_node; |
| } |
| |
| /* Deleting ptr to void is undefined behavior [expr.delete/3]. */ |
| if (VOID_TYPE_P (TREE_TYPE (type))) |
| { |
| if (complain & tf_warning) |
| warning_at (exp_loc, OPT_Wdelete_incomplete, |
| "deleting %qT is undefined", type); |
| doing_vec = 0; |
| } |
| |
| /* Deleting a pointer with the value zero is valid and has no effect. */ |
| if (integer_zerop (t)) |
| return build1_loc (loc, NOP_EXPR, void_type_node, t); |
| |
| if (doing_vec) |
| return build_vec_delete (loc, t, /*maxindex=*/NULL_TREE, |
| sfk_deleting_destructor, |
| use_global_delete, complain); |
| else |
| return build_delete (loc, type, t, sfk_deleting_destructor, |
| LOOKUP_NORMAL, use_global_delete, |
| complain); |
| } |
| |
| /* Report an error if the indicated template declaration is not the |
| sort of thing that should be a member template. */ |
| |
| void |
| check_member_template (tree tmpl) |
| { |
| tree decl; |
| |
| gcc_assert (TREE_CODE (tmpl) == TEMPLATE_DECL); |
| decl = DECL_TEMPLATE_RESULT (tmpl); |
| |
| if (TREE_CODE (decl) == FUNCTION_DECL |
| || DECL_ALIAS_TEMPLATE_P (tmpl) |
| || (TREE_CODE (decl) == TYPE_DECL |
| && MAYBE_CLASS_TYPE_P (TREE_TYPE (decl)))) |
| { |
| /* The parser rejects template declarations in local classes |
| (with the exception of generic lambdas). */ |
| gcc_assert (!current_function_decl || LAMBDA_FUNCTION_P (decl)); |
| /* The parser rejects any use of virtual in a function template. */ |
| gcc_assert (!(TREE_CODE (decl) == FUNCTION_DECL |
| && DECL_VIRTUAL_P (decl))); |
| |
| /* The debug-information generating code doesn't know what to do |
| with member templates. */ |
| DECL_IGNORED_P (tmpl) = 1; |
| } |
| else if (variable_template_p (tmpl)) |
| /* OK */; |
| else |
| error ("template declaration of %q#D", decl); |
| } |
| |
| /* Sanity check: report error if this function FUNCTION is not |
| really a member of the class (CTYPE) it is supposed to belong to. |
| TEMPLATE_PARMS is used to specify the template parameters of a member |
| template passed as FUNCTION_DECL. If the member template is passed as a |
| TEMPLATE_DECL, it can be NULL since the parameters can be extracted |
| from the declaration. If the function is not a function template, it |
| must be NULL. |
| It returns the original declaration for the function, NULL_TREE if |
| no declaration was found, error_mark_node if an error was emitted. */ |
| |
| tree |
| check_classfn (tree ctype, tree function, tree template_parms) |
| { |
| if (DECL_USE_TEMPLATE (function) |
| && !(TREE_CODE (function) == TEMPLATE_DECL |
| && DECL_TEMPLATE_SPECIALIZATION (function)) |
| && DECL_MEMBER_TEMPLATE_P (DECL_TI_TEMPLATE (function))) |
| /* Since this is a specialization of a member template, |
| we're not going to find the declaration in the class. |
| For example, in: |
| |
| struct S { template <typename T> void f(T); }; |
| template <> void S::f(int); |
| |
| we're not going to find `S::f(int)', but there's no |
| reason we should, either. We let our callers know we didn't |
| find the method, but we don't complain. */ |
| return NULL_TREE; |
| |
| /* Basic sanity check: for a template function, the template parameters |
| either were not passed, or they are the same of DECL_TEMPLATE_PARMS. */ |
| if (TREE_CODE (function) == TEMPLATE_DECL) |
| { |
| if (template_parms |
| && !comp_template_parms (template_parms, |
| DECL_TEMPLATE_PARMS (function))) |
| { |
| error ("template parameter lists provided don%'t match the " |
| "template parameters of %qD", function); |
| return error_mark_node; |
| } |
| template_parms = DECL_TEMPLATE_PARMS (function); |
| } |
| |
| /* OK, is this a definition of a member template? */ |
| bool is_template = (template_parms != NULL_TREE); |
| |
| /* [temp.mem] |
| |
| A destructor shall not be a member template. */ |
| if (DECL_DESTRUCTOR_P (function) && is_template) |
| { |
| error ("destructor %qD declared as member template", function); |
| return error_mark_node; |
| } |
| |
| /* We must enter the scope here, because conversion operators are |
| named by target type, and type equivalence relies on typenames |
| resolving within the scope of CTYPE. */ |
| tree pushed_scope = push_scope (ctype); |
| tree matched = NULL_TREE; |
| tree fns = get_class_binding (ctype, DECL_NAME (function)); |
| bool saw_template = false; |
| |
| for (ovl_iterator iter (fns); !matched && iter; ++iter) |
| { |
| tree fndecl = *iter; |
| |
| if (TREE_CODE (fndecl) == TEMPLATE_DECL) |
| saw_template = true; |
| |
| /* A member template definition only matches a member template |
| declaration. */ |
| if (is_template != (TREE_CODE (fndecl) == TEMPLATE_DECL)) |
| continue; |
| |
| if (!DECL_DECLARES_FUNCTION_P (fndecl)) |
| continue; |
| |
| tree p1 = TYPE_ARG_TYPES (TREE_TYPE (function)); |
| tree p2 = TYPE_ARG_TYPES (TREE_TYPE (fndecl)); |
| |
| /* We cannot simply call decls_match because this doesn't work |
| for static member functions that are pretending to be |
| methods, and because the name may have been changed by |
| asm("new_name"). */ |
| |
| /* Get rid of the this parameter on functions that become |
| static. */ |
| if (DECL_STATIC_FUNCTION_P (fndecl) |
| && TREE_CODE (TREE_TYPE (function)) == METHOD_TYPE) |
| p1 = TREE_CHAIN (p1); |
| |
| /* ref-qualifier or absence of same must match. */ |
| if (type_memfn_rqual (TREE_TYPE (function)) |
| != type_memfn_rqual (TREE_TYPE (fndecl))) |
| continue; |
| |
| // Include constraints in the match. |
| tree c1 = get_constraints (function); |
| tree c2 = get_constraints (fndecl); |
| |
| /* While finding a match, same types and params are not enough |
| if the function is versioned. Also check version ("target") |
| attributes. */ |
| if (same_type_p (TREE_TYPE (TREE_TYPE (function)), |
| TREE_TYPE (TREE_TYPE (fndecl))) |
| && compparms (p1, p2) |
| && !targetm.target_option.function_versions (function, fndecl) |
| && (!is_template |
| || comp_template_parms (template_parms, |
| DECL_TEMPLATE_PARMS (fndecl))) |
| && equivalent_constraints (c1, c2) |
| && (DECL_TEMPLATE_SPECIALIZATION (function) |
| == DECL_TEMPLATE_SPECIALIZATION (fndecl)) |
| && (!DECL_TEMPLATE_SPECIALIZATION (function) |
| || (DECL_TI_TEMPLATE (function) == DECL_TI_TEMPLATE (fndecl)))) |
| matched = fndecl; |
| } |
| |
| if (!matched && !is_template && saw_template |
| && !processing_template_decl && DECL_UNIQUE_FRIEND_P (function)) |
| { |
| /* "[if no non-template match is found,] each remaining function template |
| is replaced with the specialization chosen by deduction from the |
| friend declaration or discarded if deduction fails." |
| |
| So ask check_explicit_specialization to find a matching template. */ |
| SET_DECL_IMPLICIT_INSTANTIATION (function); |
| tree spec = check_explicit_specialization (DECL_NAME (function), |
| function, /* tcount */0, |
| /* friend flag */4, |
| /* attrlist */NULL_TREE); |
| if (spec != error_mark_node) |
| matched = spec; |
| } |
| |
| if (!matched) |
| { |
| if (!COMPLETE_TYPE_P (ctype)) |
| cxx_incomplete_type_error (DECL_SOURCE_LOCATION (function), |
| function, ctype); |
| else |
| { |
| if (DECL_CONV_FN_P (function)) |
| fns = get_class_binding (ctype, conv_op_identifier); |
| |
| error_at (DECL_SOURCE_LOCATION (function), |
| "no declaration matches %q#D", function); |
| if (fns) |
| print_candidates (fns); |
| else if (DECL_CONV_FN_P (function)) |
| inform (DECL_SOURCE_LOCATION (function), |
| "no conversion operators declared"); |
| else |
| inform (DECL_SOURCE_LOCATION (function), |
| "no functions named %qD", function); |
| inform (DECL_SOURCE_LOCATION (TYPE_NAME (ctype)), |
| "%#qT defined here", ctype); |
| } |
| matched = error_mark_node; |
| } |
| |
| if (pushed_scope) |
| pop_scope (pushed_scope); |
| |
| return matched; |
| } |
| |
| /* DECL is a function with vague linkage. Remember it so that at the |
| end of the translation unit we can decide whether or not to emit |
| it. */ |
| |
| void |
| note_vague_linkage_fn (tree decl) |
| { |
| if (processing_template_decl) |
| return; |
| |
| DECL_DEFER_OUTPUT (decl) = 1; |
| vec_safe_push (deferred_fns, decl); |
| } |
| |
| /* As above, but for variable template instantiations. */ |
| |
| void |
| note_variable_template_instantiation (tree decl) |
| { |
| vec_safe_push (pending_statics, decl); |
| } |
| |
| /* We have just processed the DECL, which is a static data member. |
| The other parameters are as for cp_finish_decl. */ |
| |
| void |
| finish_static_data_member_decl (tree decl, |
| tree init, bool init_const_expr_p, |
| tree asmspec_tree, |
| int flags) |
| { |
| if (DECL_TEMPLATE_INSTANTIATED (decl)) |
| /* We already needed to instantiate this, so the processing in this |
| function is unnecessary/wrong. */ |
| return; |
| |
| DECL_CONTEXT (decl) = current_class_type; |
| |
| /* We cannot call pushdecl here, because that would fill in the |
| TREE_CHAIN of our decl. Instead, we modify cp_finish_decl to do |
| the right thing, namely, to put this decl out straight away. */ |
| |
| if (! processing_template_decl) |
| vec_safe_push (pending_statics, decl); |
| |
| if (LOCAL_CLASS_P (current_class_type) |
| /* We already complained about the template definition. */ |
| && !DECL_TEMPLATE_INSTANTIATION (decl)) |
| permerror (DECL_SOURCE_LOCATION (decl), |
| "local class %q#T shall not have static data member %q#D", |
| current_class_type, decl); |
| else |
| for (tree t = current_class_type; TYPE_P (t); |
| t = CP_TYPE_CONTEXT (t)) |
| if (TYPE_UNNAMED_P (t)) |
| { |
| auto_diagnostic_group d; |
| if (permerror (DECL_SOURCE_LOCATION (decl), |
| "static data member %qD in unnamed class", decl)) |
| inform (DECL_SOURCE_LOCATION (TYPE_NAME (t)), |
| "unnamed class defined here"); |
| break; |
| } |
| |
| if (DECL_INLINE_VAR_P (decl) && !DECL_TEMPLATE_INSTANTIATION (decl)) |
| /* An inline variable is immediately defined, so don't set DECL_IN_AGGR_P. |
| Except that if decl is a template instantiation, it isn't defined until |
| instantiate_decl. */; |
| else |
| DECL_IN_AGGR_P (decl) = 1; |
| |
| if (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE |
| && TYPE_DOMAIN (TREE_TYPE (decl)) == NULL_TREE) |
| SET_VAR_HAD_UNKNOWN_BOUND (decl); |
| |
| if (init) |
| { |
| /* Similarly to start_decl_1, we want to complete the type in order |
| to do the right thing in cp_apply_type_quals_to_decl, possibly |
| clear TYPE_QUAL_CONST (c++/65579). */ |
| tree type = TREE_TYPE (decl) = complete_type (TREE_TYPE (decl)); |
| cp_apply_type_quals_to_decl (cp_type_quals (type), decl); |
| } |
| |
| cp_finish_decl (decl, init, init_const_expr_p, asmspec_tree, flags); |
| } |
| |
| /* DECLARATOR and DECLSPECS correspond to a class member. The other |
| parameters are as for cp_finish_decl. Return the DECL for the |
| class member declared. */ |
| |
| tree |
| grokfield (const cp_declarator *declarator, |
| cp_decl_specifier_seq *declspecs, |
| tree init, bool init_const_expr_p, |
| tree asmspec_tree, |
| tree attrlist) |
| { |
| tree value; |
| const char *asmspec = 0; |
| int flags; |
| |
| if (init |
| && TREE_CODE (init) == TREE_LIST |
| && TREE_VALUE (init) == error_mark_node |
| && TREE_CHAIN (init) == NULL_TREE) |
| init = NULL_TREE; |
| |
| int initialized; |
| if (init == ridpointers[(int)RID_DELETE]) |
| initialized = SD_DELETED; |
| else if (init == ridpointers[(int)RID_DEFAULT]) |
| initialized = SD_DEFAULTED; |
| else if (init) |
| initialized = SD_INITIALIZED; |
| else |
| initialized = SD_UNINITIALIZED; |
| |
| value = grokdeclarator (declarator, declspecs, FIELD, initialized, &attrlist); |
| if (! value || value == error_mark_node) |
| /* friend or constructor went bad. */ |
| return error_mark_node; |
| if (TREE_TYPE (value) == error_mark_node) |
| return value; |
| |
| if (TREE_CODE (value) == TYPE_DECL && init) |
| { |
| error_at (cp_expr_loc_or_loc (init, DECL_SOURCE_LOCATION (value)), |
| "typedef %qD is initialized (use %qs instead)", |
| value, "decltype"); |
| init = NULL_TREE; |
| } |
| |
| /* Pass friendly classes back. */ |
| if (value == void_type_node) |
| return value; |
| |
| if (DECL_NAME (value) |
| && TREE_CODE (DECL_NAME (value)) == TEMPLATE_ID_EXPR) |
| { |
| error_at (declarator->id_loc, |
| "explicit template argument list not allowed"); |
| return error_mark_node; |
| } |
| |
| /* Stash away type declarations. */ |
| if (TREE_CODE (value) == TYPE_DECL) |
| { |
| DECL_NONLOCAL (value) = 1; |
| DECL_CONTEXT (value) = current_class_type; |
| |
| if (attrlist) |
| { |
| int attrflags = 0; |
| |
| /* If this is a typedef that names the class for linkage purposes |
| (7.1.3p8), apply any attributes directly to the type. */ |
| if (OVERLOAD_TYPE_P (TREE_TYPE (value)) |
| && value == TYPE_NAME (TYPE_MAIN_VARIANT (TREE_TYPE (value)))) |
| attrflags = ATTR_FLAG_TYPE_IN_PLACE; |
| |
| cplus_decl_attributes (&value, attrlist, attrflags); |
| } |
| |
| if (decl_spec_seq_has_spec_p (declspecs, ds_typedef) |
| && TREE_TYPE (value) != error_mark_node |
| && TYPE_NAME (TYPE_MAIN_VARIANT (TREE_TYPE (value))) != value) |
| set_underlying_type (value); |
| |
| /* It's important that push_template_decl below follows |
| set_underlying_type above so that the created template |
| carries the properly set type of VALUE. */ |
| if (processing_template_decl) |
| value = push_template_decl (value); |
| |
| record_locally_defined_typedef (value); |
| return value; |
| } |
| |
| int friendp = decl_spec_seq_has_spec_p (declspecs, ds_friend); |
| |
| if (!friendp && DECL_IN_AGGR_P (value)) |
| { |
| error ("%qD is already defined in %qT", value, DECL_CONTEXT (value)); |
| return void_type_node; |
| } |
| |
| if (asmspec_tree && asmspec_tree != error_mark_node) |
| asmspec = TREE_STRING_POINTER (asmspec_tree); |
| |
| if (init) |
| { |
| if (TREE_CODE (value) == FUNCTION_DECL) |
| { |
| if (init == ridpointers[(int)RID_DELETE]) |
| { |
| DECL_DELETED_FN (value) = 1; |
| DECL_DECLARED_INLINE_P (value) = 1; |
| } |
| else if (init == ridpointers[(int)RID_DEFAULT]) |
| { |
| if (defaultable_fn_check (value)) |
| { |
| DECL_DEFAULTED_FN (value) = 1; |
| DECL_INITIALIZED_IN_CLASS_P (value) = 1; |
| DECL_DECLARED_INLINE_P (value) = 1; |
| /* grokfndecl set this to error_mark_node, but we want to |
| leave it unset until synthesize_method. */ |
| DECL_INITIAL (value) = NULL_TREE; |
| } |
| } |
| else if (TREE_CODE (init) == DEFERRED_PARSE) |
| error ("invalid initializer for member function %qD", value); |
| else if (TREE_CODE (TREE_TYPE (value)) == METHOD_TYPE) |
| { |
| if (integer_zerop (init)) |
| DECL_PURE_VIRTUAL_P (value) = 1; |
| else if (error_operand_p (init)) |
| ; /* An error has already been reported. */ |
| else |
| error ("invalid initializer for member function %qD", |
| value); |
| } |
| else |
| { |
| gcc_assert (TREE_CODE (TREE_TYPE (value)) == FUNCTION_TYPE); |
| location_t iloc |
| = cp_expr_loc_or_loc (init, DECL_SOURCE_LOCATION (value)); |
| if (friendp) |
| error_at (iloc, "initializer specified for friend " |
| "function %qD", value); |
| else |
| error_at (iloc, "initializer specified for static " |
| "member function %qD", value); |
| } |
| } |
| else if (TREE_CODE (value) == FIELD_DECL) |
| /* C++11 NSDMI, keep going. */; |
| else if (!VAR_P (value)) |
| gcc_unreachable (); |
| } |
| |
| /* Pass friend decls back. */ |
| if ((TREE_CODE (value) == FUNCTION_DECL |
| || TREE_CODE (value) == TEMPLATE_DECL) |
| && DECL_CONTEXT (value) != current_class_type) |
| { |
| if (attrlist) |
| cplus_decl_attributes (&value, attrlist, 0); |
| return value; |
| } |
| |
| /* Need to set this before push_template_decl. */ |
| if (VAR_P (value)) |
| DECL_CONTEXT (value) = current_class_type; |
| |
| if (processing_template_decl && VAR_OR_FUNCTION_DECL_P (value)) |
| { |
| value = push_template_decl (value); |
| if (error_operand_p (value)) |
| return error_mark_node; |
| } |
| |
| if (attrlist) |
| cplus_decl_attributes (&value, attrlist, 0); |
| |
| if (init && DIRECT_LIST_INIT_P (init)) |
| flags = LOOKUP_NORMAL; |
| else |
| flags = LOOKUP_IMPLICIT; |
| |
| switch (TREE_CODE (value)) |
| { |
| case VAR_DECL: |
| finish_static_data_member_decl (value, init, init_const_expr_p, |
| asmspec_tree, flags); |
| return value; |
| |
| case FIELD_DECL: |
| if (asmspec) |
| error ("%<asm%> specifiers are not permitted on non-static data members"); |
| if (DECL_INITIAL (value) == error_mark_node) |
| init = error_mark_node; |
| cp_finish_decl (value, init, /*init_const_expr_p=*/false, |
| NULL_TREE, flags); |
| DECL_IN_AGGR_P (value) = 1; |
| return value; |
| |
| case FUNCTION_DECL: |
| if (asmspec) |
| set_user_assembler_name (value, asmspec); |
| |
| cp_finish_decl (value, |
| /*init=*/NULL_TREE, |
| /*init_const_expr_p=*/false, |
| asmspec_tree, flags); |
| |
| /* Pass friends back this way. */ |
| if (DECL_UNIQUE_FRIEND_P (value)) |
| return void_type_node; |
| |
| DECL_IN_AGGR_P (value) = 1; |
| return value; |
| |
| default: |
| gcc_unreachable (); |
| } |
| return NULL_TREE; |
| } |
| |
| /* Like `grokfield', but for bitfields. |
| WIDTH is the width of the bitfield, a constant expression. |
| The other parameters are as for grokfield. */ |
| |
| tree |
| grokbitfield (const cp_declarator *declarator, |
| cp_decl_specifier_seq *declspecs, tree width, tree init, |
| tree attrlist) |
| { |
| tree value = grokdeclarator (declarator, declspecs, BITFIELD, |
| init != NULL_TREE, &attrlist); |
| |
| if (value == error_mark_node) |
| return NULL_TREE; /* friends went bad. */ |
| |
| tree type = TREE_TYPE (value); |
| if (type == error_mark_node) |
| return value; |
| |
| /* Pass friendly classes back. */ |
| if (VOID_TYPE_P (value)) |
| return void_type_node; |
| |
| if (!INTEGRAL_OR_ENUMERATION_TYPE_P (type) |
| && (INDIRECT_TYPE_P (type) || !dependent_type_p (type))) |
| { |
| error_at (DECL_SOURCE_LOCATION (value), |
| "bit-field %qD with non-integral type %qT", |
| value, type); |
| return error_mark_node; |
| } |
| |
| if (TREE_CODE (value) == TYPE_DECL) |
| { |
| error_at (DECL_SOURCE_LOCATION (value), |
| "cannot declare %qD to be a bit-field type", value); |
| return NULL_TREE; |
| } |
| |
| /* Usually, finish_struct_1 catches bitfields with invalid types. |
| But, in the case of bitfields with function type, we confuse |
| ourselves into thinking they are member functions, so we must |
| check here. */ |
| if (TREE_CODE (value) == FUNCTION_DECL) |
| { |
| error_at (DECL_SOURCE_LOCATION (value), |
| "cannot declare bit-field %qD with function type", value); |
| return NULL_TREE; |
| } |
| |
| if (TYPE_WARN_IF_NOT_ALIGN (type)) |
| { |
| error_at (DECL_SOURCE_LOCATION (value), "cannot declare bit-field " |
| "%qD with %<warn_if_not_aligned%> type", value); |
| return NULL_TREE; |
| } |
| |
| if (DECL_IN_AGGR_P (value)) |
| { |
| error ("%qD is already defined in the class %qT", value, |
| DECL_CONTEXT (value)); |
| return void_type_node; |
| } |
| |
| if (TREE_STATIC (value)) |
| { |
| error_at (DECL_SOURCE_LOCATION (value), |
| "static member %qD cannot be a bit-field", value); |
| return NULL_TREE; |
| } |
| |
| int flags = LOOKUP_IMPLICIT; |
| if (init && DIRECT_LIST_INIT_P (init)) |
| flags = LOOKUP_NORMAL; |
| cp_finish_decl (value, init, false, NULL_TREE, flags); |
| |
| if (width != error_mark_node) |
| { |
| /* The width must be an integer type. */ |
| if (!type_dependent_expression_p (width) |
| && !INTEGRAL_OR_UNSCOPED_ENUMERATION_TYPE_P (TREE_TYPE (width))) |
| error ("width of bit-field %qD has non-integral type %qT", value, |
| TREE_TYPE (width)); |
| else if (!check_for_bare_parameter_packs (width)) |
| { |
| /* Temporarily stash the width in DECL_BIT_FIELD_REPRESENTATIVE. |
| check_bitfield_decl picks it from there later and sets DECL_SIZE |
| accordingly. */ |
| DECL_BIT_FIELD_REPRESENTATIVE (value) = width; |
| SET_DECL_C_BIT_FIELD (value); |
| } |
| } |
| |
| DECL_IN_AGGR_P (value) = 1; |
| |
| if (attrlist) |
| cplus_decl_attributes (&value, attrlist, /*flags=*/0); |
| |
| return value; |
| } |
| |
| |
| /* Returns true iff ATTR is an attribute which needs to be applied at |
| instantiation time rather than template definition time. */ |
| |
| static bool |
| is_late_template_attribute (tree attr, tree decl) |
| { |
| tree name = get_attribute_name (attr); |
| tree args = TREE_VALUE (attr); |
| const struct attribute_spec *spec = lookup_attribute_spec (name); |
| tree arg; |
| |
| if (!spec) |
| /* Unknown attribute. */ |
| return false; |
| |
| /* Attribute weak handling wants to write out assembly right away. */ |
| if (is_attribute_p ("weak", name)) |
| return true; |
| |
| /* Attributes used and unused are applied directly to typedefs for the |
| benefit of maybe_warn_unused_local_typedefs. */ |
| if (TREE_CODE (decl) == TYPE_DECL |
| && (is_attribute_p ("unused", name) |
| || is_attribute_p ("used", name))) |
| return false; |
| |
| /* Attribute tls_model wants to modify the symtab. */ |
| if (is_attribute_p ("tls_model", name)) |
| return true; |
| |
| /* #pragma omp declare simd attribute needs to be always deferred. */ |
| if (flag_openmp |
| && is_attribute_p ("omp declare simd", name)) |
| return true; |
| |
| if (args == error_mark_node) |
| return false; |
| |
| /* An attribute pack is clearly dependent. */ |
| if (args && PACK_EXPANSION_P (args)) |
| return true; |
| |
| /* If any of the arguments are dependent expressions, we can't evaluate |
| the attribute until instantiation time. */ |
| for (arg = args; arg; arg = TREE_CHAIN (arg)) |
| { |
| tree t = TREE_VALUE (arg); |
| |
| /* If the first attribute argument is an identifier, only consider |
| second and following arguments. Attributes like mode, format, |
| cleanup and several target specific attributes aren't late |
| just because they have an IDENTIFIER_NODE as first argument. */ |
| if (arg == args && attribute_takes_identifier_p (name) |
| && identifier_p (t)) |
| continue; |
| |
| if (value_dependent_expression_p (t)) |
| return true; |
| } |
| |
| if (TREE_CODE (decl) == TYPE_DECL |
| || TYPE_P (decl) |
| || spec->type_required) |
| { |
| tree type = TYPE_P (decl) ? decl : TREE_TYPE (decl); |
| |
| if (!type) |
| return true; |
| |
| /* We can't apply any attributes to a completely unknown type until |
| instantiation time. */ |
| enum tree_code code = TREE_CODE (type); |
| if (code == TEMPLATE_TYPE_PARM |
| || code == BOUND_TEMPLATE_TEMPLATE_PARM |
| || code == TYPENAME_TYPE) |
| return true; |
| /* Also defer most attributes on dependent types. This is not |
| necessary in all cases, but is the better default. */ |
| else if (dependent_type_p (type) |
| /* But some attributes specifically apply to templates. */ |
| && !is_attribute_p ("abi_tag", name) |
| && !is_attribute_p ("deprecated", name) |
| && !is_attribute_p ("unavailable", name) |
| && !is_attribute_p ("visibility", name)) |
| return true; |
| else |
| return false; |
| } |
| else |
| return false; |
| } |
| |
| /* ATTR_P is a list of attributes. Remove any attributes which need to be |
| applied at instantiation time and return them. If IS_DEPENDENT is true, |
| the declaration itself is dependent, so all attributes should be applied |
| at instantiation time. */ |
| |
| tree |
| splice_template_attributes (tree *attr_p, tree decl) |
| { |
| tree *p = attr_p; |
| tree late_attrs = NULL_TREE; |
| tree *q = &late_attrs; |
| |
| if (!p || *p == error_mark_node) |
| return NULL_TREE; |
| |
| for (; *p; ) |
| { |
| if (is_late_template_attribute (*p, decl)) |
| { |
| ATTR_IS_DEPENDENT (*p) = 1; |
| *q = *p; |
| *p = TREE_CHAIN (*p); |
| q = &TREE_CHAIN (*q); |
| *q = NULL_TREE; |
| } |
| else |
| p = &TREE_CHAIN (*p); |
| } |
| |
| return late_attrs; |
| } |
| |
| /* Attach any LATE_ATTRS to DECL_P, after the non-dependent attributes have |
| been applied by a previous call to decl_attributes. */ |
| |
| static void |
| save_template_attributes (tree late_attrs, tree *decl_p, int flags) |
| { |
| tree *q; |
| |
| if (!late_attrs) |
| return; |
| |
| if (DECL_P (*decl_p)) |
| q = &DECL_ATTRIBUTES (*decl_p); |
| else |
| q = &TYPE_ATTRIBUTES (*decl_p); |
| |
| tree old_attrs = *q; |
| |
| /* Place the late attributes at the beginning of the attribute |
| list. */ |
| late_attrs = chainon (late_attrs, *q); |
| if (*q != late_attrs |
| && !DECL_P (*decl_p) |
| && !(flags & ATTR_FLAG_TYPE_IN_PLACE)) |
| { |
| if (!dependent_type_p (*decl_p)) |
| *decl_p = cp_build_type_attribute_variant (*decl_p, late_attrs); |
| else |
| { |
| *decl_p = build_variant_type_copy (*decl_p); |
| TYPE_ATTRIBUTES (*decl_p) = late_attrs; |
| } |
| } |
| else |
| *q = late_attrs; |
| |
| if (!DECL_P (*decl_p) && *decl_p == TYPE_MAIN_VARIANT (*decl_p)) |
| { |
| /* We've added new attributes directly to the main variant, so |
| now we need to update all of the other variants to include |
| these new attributes. */ |
| tree variant; |
| for (variant = TYPE_NEXT_VARIANT (*decl_p); variant; |
| variant = TYPE_NEXT_VARIANT (variant)) |
| { |
| gcc_assert (TYPE_ATTRIBUTES (variant) == old_attrs); |
| TYPE_ATTRIBUTES (variant) = TYPE_ATTRIBUTES (*decl_p); |
| } |
| } |
| } |
| |
| /* True if ATTRS contains any dependent attributes that affect type |
| identity. */ |
| |
| bool |
| any_dependent_type_attributes_p (tree attrs) |
| { |
| for (tree a = attrs; a; a = TREE_CHAIN (a)) |
| if (ATTR_IS_DEPENDENT (a)) |
| { |
| const attribute_spec *as = lookup_attribute_spec (TREE_PURPOSE (a)); |
| if (as && as->affects_type_identity) |
| return true; |
| } |
| return false; |
| } |
| |
| /* Return true iff ATTRS are acceptable attributes to be applied in-place |
| to a typedef which gives a previously unnamed class or enum a name for |
| linkage purposes. */ |
| |
| bool |
| attributes_naming_typedef_ok (tree attrs) |
| { |
| for (; attrs; attrs = TREE_CHAIN (attrs)) |
| { |
| tree name = get_attribute_name (attrs); |
| if (is_attribute_p ("vector_size", name)) |
| return false; |
| } |
| return true; |
| } |
| |
| /* Like reconstruct_complex_type, but handle also template trees. */ |
| |
| tree |
| cp_reconstruct_complex_type (tree type, tree bottom) |
| { |
| tree inner, outer; |
| |
| if (TYPE_PTR_P (type)) |
| { |
| inner = cp_reconstruct_complex_type (TREE_TYPE (type), bottom); |
| outer = build_pointer_type_for_mode (inner, TYPE_MODE (type), |
| TYPE_REF_CAN_ALIAS_ALL (type)); |
| } |
| else if (TYPE_REF_P (type)) |
| { |
| inner = cp_reconstruct_complex_type (TREE_TYPE (type), bottom); |
| outer = build_reference_type_for_mode (inner, TYPE_MODE (type), |
| TYPE_REF_CAN_ALIAS_ALL (type)); |
| } |
| else if (TREE_CODE (type) == ARRAY_TYPE) |
| { |
| inner = cp_reconstruct_complex_type (TREE_TYPE (type), bottom); |
| outer = build_cplus_array_type (inner, TYPE_DOMAIN (type)); |
| /* Don't call cp_build_qualified_type on ARRAY_TYPEs, the |
| element type qualification will be handled by the recursive |
| cp_reconstruct_complex_type call and cp_build_qualified_type |
| for ARRAY_TYPEs changes the element type. */ |
| return outer; |
| } |
| else if (TREE_CODE (type) == FUNCTION_TYPE) |
| { |
| inner = cp_reconstruct_complex_type (TREE_TYPE (type), bottom); |
| outer = build_function_type (inner, TYPE_ARG_TYPES (type)); |
| outer = apply_memfn_quals (outer, type_memfn_quals (type)); |
| } |
| else if (TREE_CODE (type) == METHOD_TYPE) |
| { |
| inner = cp_reconstruct_complex_type (TREE_TYPE (type), bottom); |
| /* The build_method_type_directly() routine prepends 'this' to argument list, |
| so we must compensate by getting rid of it. */ |
| outer |
| = build_method_type_directly |
| (class_of_this_parm (type), inner, |
| TREE_CHAIN (TYPE_ARG_TYPES (type))); |
| } |
| else if (TREE_CODE (type) == OFFSET_TYPE) |
| { |
| inner = cp_reconstruct_complex_type (TREE_TYPE (type), bottom); |
| outer = build_offset_type (TYPE_OFFSET_BASETYPE (type), inner); |
| } |
| else |
| return bottom; |
| |
| if (TYPE_ATTRIBUTES (type)) |
| outer = cp_build_type_attribute_variant (outer, TYPE_ATTRIBUTES (type)); |
| outer = cp_build_qualified_type (outer, cp_type_quals (type)); |
| outer = cxx_copy_lang_qualifiers (outer, type); |
| |
| return outer; |
| } |
| |
| /* Replaces any constexpr expression that may be into the attributes |
| arguments with their reduced value. */ |
| |
| void |
| cp_check_const_attributes (tree attributes) |
| { |
| if (attributes == error_mark_node) |
| return; |
| |
| tree attr; |
| for (attr = attributes; attr; attr = TREE_CHAIN (attr)) |
| { |
| tree arg; |
| /* As we implement alignas using gnu::aligned attribute and |
| alignas argument is a constant expression, force manifestly |
| constant evaluation of aligned attribute argument. */ |
| bool manifestly_const_eval |
| = is_attribute_p ("aligned", get_attribute_name (attr)); |
| for (arg = TREE_VALUE (attr); arg && TREE_CODE (arg) == TREE_LIST; |
| arg = TREE_CHAIN (arg)) |
| { |
| tree expr = TREE_VALUE (arg); |
| if (EXPR_P (expr)) |
| TREE_VALUE (arg) |
| = fold_non_dependent_expr (expr, tf_warning_or_error, |
| manifestly_const_eval); |
| } |
| } |
| } |
| |
| /* Return true if TYPE is an OpenMP mappable type. |
| If NOTES is non-zero, emit a note message for each problem. */ |
| static bool |
| cp_omp_mappable_type_1 (tree type, bool notes) |
| { |
| bool result = true; |
| |
| /* Mappable type has to be complete. */ |
| if (type == error_mark_node || !COMPLETE_TYPE_P (type)) |
| { |
| if (notes && type != error_mark_node) |
| { |
| tree decl = TYPE_MAIN_DECL (type); |
| inform ((decl ? DECL_SOURCE_LOCATION (decl) : input_location), |
| "incomplete type %qT is not mappable", type); |
| } |
| result = false; |
| } |
| /* Arrays have mappable type if the elements have mappable type. */ |
| while (TREE_CODE (type) == ARRAY_TYPE) |
| type = TREE_TYPE (type); |
| /* All data members must be non-static. */ |
| if (CLASS_TYPE_P (type)) |
| { |
| tree field; |
| for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) |
| if (VAR_P (field)) |
| { |
| if (notes) |
| inform (DECL_SOURCE_LOCATION (field), |
| "static field %qD is not mappable", field); |
| result = false; |
| } |
| /* All fields must have mappable types. */ |
| else if (TREE_CODE (field) == FIELD_DECL |
| && !cp_omp_mappable_type_1 (TREE_TYPE (field), notes)) |
| result = false; |
| } |
| return result; |
| } |
| |
| /* Return true if TYPE is an OpenMP mappable type. */ |
| bool |
| cp_omp_mappable_type (tree type) |
| { |
| return cp_omp_mappable_type_1 (type, false); |
| } |
| |
| /* Return true if TYPE is an OpenMP mappable type. |
| Emit an error messages if not. */ |
| bool |
| cp_omp_emit_unmappable_type_notes (tree type) |
| { |
| return cp_omp_mappable_type_1 (type, true); |
| } |
| |
| /* Return the last pushed declaration for the symbol DECL or NULL |
| when no such declaration exists. */ |
| |
| static tree |
| find_last_decl (tree decl) |
| { |
| tree last_decl = NULL_TREE; |
| |
| if (tree name = DECL_P (decl) ? DECL_NAME (decl) : NULL_TREE) |
| { |
| /* Look up the declaration in its scope. */ |
| tree pushed_scope = NULL_TREE; |
| if (tree ctype = DECL_CONTEXT (decl)) |
| pushed_scope = push_scope (ctype); |
| |
| last_decl = lookup_name (name); |
| |
| if (pushed_scope) |
| pop_scope (pushed_scope); |
| |
| /* The declaration may be a member conversion operator |
| or a bunch of overfloads (handle the latter below). */ |
| if (last_decl && BASELINK_P (last_decl)) |
| last_decl = BASELINK_FUNCTIONS (last_decl); |
| } |
| |
| if (!last_decl) |
| return NULL_TREE; |
| |
| if (DECL_P (last_decl) || TREE_CODE (last_decl) == OVERLOAD) |
| { |
| /* A set of overloads of the same function. */ |
| for (lkp_iterator iter (last_decl); iter; ++iter) |
| { |
| if (TREE_CODE (*iter) == OVERLOAD) |
| continue; |
| |
| tree d = *iter; |
| |
| /* We can't compare versions in the middle of processing the |
| attribute that has the version. */ |
| if (TREE_CODE (d) == FUNCTION_DECL |
| && DECL_FUNCTION_VERSIONED (d)) |
| return NULL_TREE; |
| |
| if (decls_match (decl, d, /*record_decls=*/false)) |
| return d; |
| } |
| return NULL_TREE; |
| } |
| |
| return NULL_TREE; |
| } |
| |
| /* Like decl_attributes, but handle C++ complexity. */ |
| |
| void |
| cplus_decl_attributes (tree *decl, tree attributes, int flags) |
| { |
| if (*decl == NULL_TREE || *decl == void_type_node |
| || *decl == error_mark_node || attributes == error_mark_node) |
| return; |
| |
| /* Add implicit "omp declare target" attribute if requested. */ |
| if (vec_safe_length (scope_chain->omp_declare_target_attribute) |
| && ((VAR_P (*decl) |
| && (TREE_STATIC (*decl) || DECL_EXTERNAL (*decl))) |
| || TREE_CODE (*decl) == FUNCTION_DECL)) |
| { |
| if (VAR_P (*decl) |
| && DECL_CLASS_SCOPE_P (*decl)) |
| error ("%q+D static data member inside of declare target directive", |
| *decl); |
| else if (VAR_P (*decl) |
| && (processing_template_decl |
| || !cp_omp_mappable_type (TREE_TYPE (*decl)))) |
| attributes = tree_cons (get_identifier ("omp declare target implicit"), |
| NULL_TREE, attributes); |
| else |
| { |
| attributes = tree_cons (get_identifier ("omp declare target"), |
| NULL_TREE, attributes); |
| attributes = tree_cons (get_identifier ("omp declare target block"), |
| NULL_TREE, attributes); |
| } |
| } |
| |
| tree late_attrs = NULL_TREE; |
| if (processing_template_decl) |
| { |
| if (check_for_bare_parameter_packs (attributes)) |
| return; |
| late_attrs = splice_template_attributes (&attributes, *decl); |
| } |
| |
| cp_check_const_attributes (attributes); |
| |
| if (flag_openmp || flag_openmp_simd) |
| { |
| bool diagnosed = false; |
| for (tree *pa = &attributes; *pa; ) |
| { |
| if (get_attribute_namespace (*pa) == omp_identifier) |
| { |
| tree name = get_attribute_name (*pa); |
| if (is_attribute_p ("directive", name) |
| || is_attribute_p ("sequence", name)) |
| { |
| if (!diagnosed) |
| { |
| error ("%<omp::%E%> not allowed to be specified in this " |
| "context", name); |
| diagnosed = true; |
| } |
| *pa = TREE_CHAIN (*pa); |
| continue; |
| } |
| } |
| pa = &TREE_CHAIN (*pa); |
| } |
| } |
| |
| if (TREE_CODE (*decl) == TEMPLATE_DECL) |
| decl = &DECL_TEMPLATE_RESULT (*decl); |
| |
| if (TREE_TYPE (*decl) && TYPE_PTRMEMFUNC_P (TREE_TYPE (*decl))) |
| { |
| attributes |
| = decl_attributes (decl, attributes, flags | ATTR_FLAG_FUNCTION_NEXT); |
| decl_attributes (&TYPE_PTRMEMFUNC_FN_TYPE_RAW (TREE_TYPE (*decl)), |
| attributes, flags); |
| } |
| else |
| { |
| tree last_decl = find_last_decl (*decl); |
| decl_attributes (decl, attributes, flags, last_decl); |
| } |
| |
| if (late_attrs) |
| save_template_attributes (late_attrs, decl, flags); |
| |
| /* Propagate deprecation out to the template. */ |
| if (TREE_DEPRECATED (*decl)) |
| if (tree ti = get_template_info (*decl)) |
| { |
| tree tmpl = TI_TEMPLATE (ti); |
| tree pattern = (TYPE_P (*decl) ? TREE_TYPE (tmpl) |
| : DECL_TEMPLATE_RESULT (tmpl)); |
| if (*decl == pattern) |
| TREE_DEPRECATED (tmpl) = true; |
| } |
| |
| /* Likewise, propagate unavailability out to the template. */ |
| if (TREE_UNAVAILABLE (*decl)) |
| if (tree ti = get_template_info (*decl)) |
| { |
| tree tmpl = TI_TEMPLATE (ti); |
| tree pattern = (TYPE_P (*decl) ? TREE_TYPE (tmpl) |
| : DECL_TEMPLATE_RESULT (tmpl)); |
| if (*decl == pattern) |
| TREE_UNAVAILABLE (tmpl) = true; |
| } |
| } |
| |
| /* Walks through the namespace- or function-scope anonymous union |
| OBJECT, with the indicated TYPE, building appropriate VAR_DECLs. |
| Returns one of the fields for use in the mangled name. */ |
| |
| static tree |
| build_anon_union_vars (tree type, tree object) |
| { |
| tree main_decl = NULL_TREE; |
| tree field; |
| |
| /* Rather than write the code to handle the non-union case, |
| just give an error. */ |
| if (TREE_CODE (type) != UNION_TYPE) |
| { |
| error_at (DECL_SOURCE_LOCATION (TYPE_MAIN_DECL (type)), |
| "anonymous struct not inside named type"); |
| return error_mark_node; |
| } |
| |
| for (field = TYPE_FIELDS (type); |
| field != NULL_TREE; |
| field = DECL_CHAIN (field)) |
| { |
| tree decl; |
| tree ref; |
| |
| if (DECL_ARTIFICIAL (field)) |
| continue; |
| if (TREE_CODE (field) != FIELD_DECL) |
| { |
| permerror (DECL_SOURCE_LOCATION (field), |
| "%q#D invalid; an anonymous union can only " |
| "have non-static data members", field); |
| continue; |
| } |
| |
| if (TREE_PRIVATE (field)) |
| permerror (DECL_SOURCE_LOCATION (field), |
| "private member %q#D in anonymous union", field); |
| else if (TREE_PROTECTED (field)) |
| permerror (DECL_SOURCE_LOCATION (field), |
| "protected member %q#D in anonymous union", field); |
| |
| if (processing_template_decl) |
| ref = build_min_nt_loc (UNKNOWN_LOCATION, COMPONENT_REF, object, |
| DECL_NAME (field), NULL_TREE); |
| else |
| ref = build_class_member_access_expr (object, field, NULL_TREE, |
| false, tf_warning_or_error); |
| |
| if (DECL_NAME (field)) |
| { |
| tree base; |
| |
| decl = build_decl (input_location, |
| VAR_DECL, DECL_NAME (field), TREE_TYPE (field)); |
| DECL_ANON_UNION_VAR_P (decl) = 1; |
| DECL_ARTIFICIAL (decl) = 1; |
| |
| base = get_base_address (object); |
| TREE_PUBLIC (decl) = TREE_PUBLIC (base); |
| TREE_STATIC (decl) = TREE_STATIC (base); |
| DECL_EXTERNAL (decl) = DECL_EXTERNAL (base); |
| |
| SET_DECL_VALUE_EXPR (decl, ref); |
| DECL_HAS_VALUE_EXPR_P (decl) = 1; |
| |
| decl = pushdecl (decl); |
| } |
| else if (ANON_AGGR_TYPE_P (TREE_TYPE (field))) |
| decl = build_anon_union_vars (TREE_TYPE (field), ref); |
| else |
| decl = 0; |
| |
| if (main_decl == NULL_TREE) |
| main_decl = decl; |
| } |
| |
| return main_decl; |
| } |
| |
| /* Finish off the processing of a UNION_TYPE structure. If the union is an |
| anonymous union, then all members must be laid out together. PUBLIC_P |
| is nonzero if this union is not declared static. */ |
| |
| void |
| finish_anon_union (tree anon_union_decl) |
| { |
| tree type; |
| tree main_decl; |
| bool public_p; |
| |
| if (anon_union_decl == error_mark_node) |
| return; |
| |
| type = TREE_TYPE (anon_union_decl); |
| public_p = TREE_PUBLIC (anon_union_decl); |
| |
| /* The VAR_DECL's context is the same as the TYPE's context. */ |
| DECL_CONTEXT (anon_union_decl) = DECL_CONTEXT (TYPE_NAME (type)); |
| |
| if (TYPE_FIELDS (type) == NULL_TREE) |
| return; |
| |
| if (public_p) |
| { |
| error ("namespace-scope anonymous aggregates must be static"); |
| return; |
| } |
| |
| main_decl = build_anon_union_vars (type, anon_union_decl); |
| if (main_decl == error_mark_node) |
| return; |
| if (main_decl == NULL_TREE) |
| { |
| pedwarn (input_location, 0, "anonymous union with no members"); |
| return; |
| } |
| |
| if (!processing_template_decl) |
| { |
| /* Use main_decl to set the mangled name. */ |
| DECL_NAME (anon_union_decl) = DECL_NAME (main_decl); |
| maybe_commonize_var (anon_union_decl); |
| if (TREE_STATIC (anon_union_decl) || DECL_EXTERNAL (anon_union_decl)) |
| { |
| if (DECL_DISCRIMINATOR_P (anon_union_decl)) |
| determine_local_discriminator (anon_union_decl); |
| mangle_decl (anon_union_decl); |
| } |
| DECL_NAME (anon_union_decl) = NULL_TREE; |
| } |
| |
| pushdecl (anon_union_decl); |
| cp_finish_decl (anon_union_decl, NULL_TREE, false, NULL_TREE, 0); |
| } |
| |
| /* Auxiliary functions to make type signatures for |
| `operator new' and `operator delete' correspond to |
| what compiler will be expecting. */ |
| |
| tree |
| coerce_new_type (tree type, location_t loc) |
| { |
| int e = 0; |
| tree args = TYPE_ARG_TYPES (type); |
| |
| gcc_assert (TREE_CODE (type) == FUNCTION_TYPE); |
| |
| if (!same_type_p (TREE_TYPE (type), ptr_type_node)) |
| { |
| e = 1; |
| error_at (loc, "%<operator new%> must return type %qT", |
| ptr_type_node); |
| } |
| |
| if (args && args != void_list_node) |
| { |
| if (TREE_PURPOSE (args)) |
| { |
| /* [basic.stc.dynamic.allocation] |
| |
| The first parameter shall not have an associated default |
| argument. */ |
| error_at (loc, "the first parameter of %<operator new%> cannot " |
| "have a default argument"); |
| /* Throw away the default argument. */ |
| TREE_PURPOSE (args) = NULL_TREE; |
| } |
| |
| if (!same_type_p (TREE_VALUE (args), size_type_node)) |
| { |
| e = 2; |
| args = TREE_CHAIN (args); |
| } |
| } |
| else |
| e = 2; |
| |
| if (e == 2) |
| permerror (loc, "%<operator new%> takes type %<size_t%> (%qT) " |
| "as first parameter", size_type_node); |
| |
| switch (e) |
| { |
| case 2: |
| args = tree_cons (NULL_TREE, size_type_node, args); |
| /* Fall through. */ |
| case 1: |
| type = (cxx_copy_lang_qualifiers |
| (build_function_type (ptr_type_node, args), |
| type)); |
| /* Fall through. */ |
| default:; |
| } |
| return type; |
| } |
| |
| void |
| coerce_delete_type (tree decl, location_t loc) |
| { |
| int e = 0; |
| tree type = TREE_TYPE (decl); |
| tree args = TYPE_ARG_TYPES (type); |
| |
| gcc_assert (TREE_CODE (type) == FUNCTION_TYPE); |
| |
| if (!same_type_p (TREE_TYPE (type), void_type_node)) |
| { |
| e = 1; |
| error_at (loc, "%<operator delete%> must return type %qT", |
| void_type_node); |
| } |
| |
| tree ptrtype = ptr_type_node; |
| if (destroying_delete_p (decl)) |
| { |
| if (DECL_CLASS_SCOPE_P (decl)) |
| /* If the function is a destroying operator delete declared in class |
| type C, the type of its first parameter shall be C*. */ |
| ptrtype = build_pointer_type (DECL_CONTEXT (decl)); |
| else |
| /* A destroying operator delete shall be a class member function named |
| operator delete. */ |
| error_at (loc, |
| "destroying %<operator delete%> must be a member function"); |
| const ovl_op_info_t *op = IDENTIFIER_OVL_OP_INFO (DECL_NAME (decl)); |
| if (op->flags & OVL_OP_FLAG_VEC) |
| error_at (loc, "%<operator delete[]%> cannot be a destroying delete"); |
| if (!usual_deallocation_fn_p (decl)) |
| error_at (loc, "destroying %<operator delete%> must be a usual " |
| "deallocation function"); |
| } |
| |
| if (!args || args == void_list_node |
| || !same_type_p (TREE_VALUE (args), ptrtype)) |
| { |
| e = 2; |
| if (args && args != void_list_node) |
| args = TREE_CHAIN (args); |
| error_at (loc, "%<operator delete%> takes type %qT as first parameter", |
| ptrtype); |
| } |
| switch (e) |
| { |
| case 2: |
| args = tree_cons (NULL_TREE, ptrtype, args); |
| /* Fall through. */ |
| case 1: |
| type = (cxx_copy_lang_qualifiers |
| (build_function_type (void_type_node, args), |
| type)); |
| /* Fall through. */ |
| default:; |
| } |
| |
| TREE_TYPE (decl) = type; |
| } |
| |
| /* DECL is a VAR_DECL for a vtable: walk through the entries in the vtable |
| and mark them as needed. */ |
| |
| static void |
| mark_vtable_entries (tree decl, vec<tree> &consteval_vtables) |
| { |
| /* It's OK for the vtable to refer to deprecated virtual functions. */ |
| warning_sentinel w(warn_deprecated_decl); |
| |
| bool consteval_seen = false; |
| |
| for (auto &e: CONSTRUCTOR_ELTS (DECL_INITIAL (decl))) |
| { |
| tree fnaddr = e.value; |
| |
| STRIP_NOPS (fnaddr); |
| |
| if (TREE_CODE (fnaddr) != ADDR_EXPR |
| && TREE_CODE (fnaddr) != FDESC_EXPR) |
| /* This entry is an offset: a virtual base class offset, a |
| virtual call offset, an RTTI offset, etc. */ |
| continue; |
| |
| tree fn = TREE_OPERAND (fnaddr, 0); |
| if (TREE_CODE (fn) == FUNCTION_DECL && DECL_IMMEDIATE_FUNCTION_P (fn)) |
| { |
| if (!consteval_seen) |
| { |
| consteval_seen = true; |
| consteval_vtables.safe_push (decl); |
| } |
| continue; |
| } |
| TREE_ADDRESSABLE (fn) = 1; |
| /* When we don't have vcall offsets, we output thunks whenever |
| we output the vtables that contain them. With vcall offsets, |
| we know all the thunks we'll need when we emit a virtual |
| function, so we emit the thunks there instead. */ |
| if (DECL_THUNK_P (fn)) |
| use_thunk (fn, /*emit_p=*/0); |
| /* Set the location, as marking the function could cause |
| instantiation. We do not need to preserve the incoming |
| location, as we're called from c_parse_final_cleanups, which |
| takes care of that. */ |
| input_location = DECL_SOURCE_LOCATION (fn); |
| mark_used (fn); |
| } |
| } |
| |
| /* Replace any consteval functions in vtables with null pointers. */ |
| |
| static void |
| clear_consteval_vfns (vec<tree> &consteval_vtables) |
| { |
| for (tree vtable : consteval_vtables) |
| for (constructor_elt &elt : CONSTRUCTOR_ELTS (DECL_INITIAL (vtable))) |
| { |
| tree fn = cp_get_fndecl_from_callee (elt.value, /*fold*/false); |
| if (fn && DECL_IMMEDIATE_FUNCTION_P (fn)) |
| elt.value = build_zero_cst (vtable_entry_type); |
| } |
| } |
| |
| /* Adjust the TLS model on variable DECL if need be, typically after |
| the linkage of DECL has been modified. */ |
| |
| static void |
| adjust_var_decl_tls_model (tree decl) |
| { |
| if (CP_DECL_THREAD_LOCAL_P (decl) |
| && !lookup_attribute ("tls_model", DECL_ATTRIBUTES (decl))) |
| set_decl_tls_model (decl, decl_default_tls_model (decl)); |
| } |
| |
| /* Set DECL up to have the closest approximation of "initialized common" |
| linkage available. */ |
| |
| void |
| comdat_linkage (tree decl) |
| { |
| if (flag_weak) |
| make_decl_one_only (decl, cxx_comdat_group (decl)); |
| else if (TREE_CODE (decl) == FUNCTION_DECL |
| || (VAR_P (decl) && DECL_ARTIFICIAL (decl))) |
| /* We can just emit function and compiler-generated variables |
| statically; having multiple copies is (for the most part) only |
| a waste of space. |
| |
| There are two correctness issues, however: the address of a |
| template instantiation with external linkage should be the |
| same, independent of what translation unit asks for the |
| address, and this will not hold when we emit multiple copies of |
| the function. However, there's little else we can do. |
| |
| Also, by default, the typeinfo implementation assumes that |
| there will be only one copy of the string used as the name for |
| each type. Therefore, if weak symbols are unavailable, the |
| run-time library should perform a more conservative check; it |
| should perform a string comparison, rather than an address |
| comparison. */ |
| TREE_PUBLIC (decl) = 0; |
| else |
| { |
| /* Static data member template instantiations, however, cannot |
| have multiple copies. */ |
| if (DECL_INITIAL (decl) == 0 |
| || DECL_INITIAL (decl) == error_mark_node) |
| DECL_COMMON (decl) = 1; |
| else if (EMPTY_CONSTRUCTOR_P (DECL_INITIAL (decl))) |
| { |
| DECL_COMMON (decl) = 1; |
| DECL_INITIAL (decl) = error_mark_node; |
| } |
| else if (!DECL_EXPLICIT_INSTANTIATION (decl)) |
| { |
| /* We can't do anything useful; leave vars for explicit |
| instantiation. */ |
| DECL_EXTERNAL (decl) = 1; |
| DECL_NOT_REALLY_EXTERN (decl) = 0; |
| } |
| } |
| |
| if (TREE_PUBLIC (decl)) |
| DECL_COMDAT (decl) = 1; |
| |
| if (VAR_P (decl)) |
| adjust_var_decl_tls_model (decl); |
| } |
| |
| /* For win32 we also want to put explicit instantiations in |
| linkonce sections, so that they will be merged with implicit |
| instantiations; otherwise we get duplicate symbol errors. |
| For Darwin we do not want explicit instantiations to be |
| linkonce. */ |
| |
| void |
| maybe_make_one_only (tree decl) |
| { |
| /* We used to say that this was not necessary on targets that support weak |
| symbols, because the implicit instantiations will defer to the explicit |
| one. However, that's not actually the case in SVR4; a strong definition |
| after a weak one is an error. Also, not making explicit |
| instantiations one_only means that we can end up with two copies of |
| some template instantiations. */ |
| if (! flag_weak) |
| return; |
| |
| /* We can't set DECL_COMDAT on functions, or cp_finish_file will think |
| we can get away with not emitting them if they aren't used. We need |
| to for variables so that cp_finish_decl will update their linkage, |
| because their DECL_INITIAL may not have been set properly yet. */ |
| |
| if (!TARGET_WEAK_NOT_IN_ARCHIVE_TOC |
| || (! DECL_EXPLICIT_INSTANTIATION (decl) |
| && ! DECL_TEMPLATE_SPECIALIZATION (decl))) |
| { |
| make_decl_one_only (decl, cxx_comdat_group (decl)); |
| |
| if (VAR_P (decl)) |
| { |
| varpool_node *node = varpool_node::get_create (decl); |
| DECL_COMDAT (decl) = 1; |
| /* Mark it needed so we don't forget to emit it. */ |
| node->forced_by_abi = true; |
| TREE_USED (decl) = 1; |
| |
| adjust_var_decl_tls_model (decl); |
| } |
| } |
| } |
| |
| /* Returns true iff DECL, a FUNCTION_DECL or VAR_DECL, has vague linkage. |
| This predicate will give the right answer during parsing of the |
| function, which other tests may not. */ |
| |
| bool |
| vague_linkage_p (tree decl) |
| { |
| if (!TREE_PUBLIC (decl)) |
| { |
| /* maybe_thunk_body clears TREE_PUBLIC and DECL_ABSTRACT_P on the |
| maybe-in-charge 'tor variants; in that case we need to check one of |
| the "clones" for the real linkage. But only in that case; before |
| maybe_clone_body we haven't yet copied the linkage to the clones. */ |
| if (DECL_MAYBE_IN_CHARGE_CDTOR_P (decl) |
| && !DECL_ABSTRACT_P (decl) |
| && DECL_CHAIN (decl) |
| && DECL_CLONED_FUNCTION_P (DECL_CHAIN (decl))) |
| return vague_linkage_p (DECL_CHAIN (decl)); |
| |
| gcc_checking_assert (!DECL_COMDAT (decl)); |
| return false; |
| } |
| /* Unfortunately, import_export_decl has not always been called |
| before the function is processed, so we cannot simply check |
| DECL_COMDAT. */ |
| if (DECL_COMDAT (decl) |
| || (TREE_CODE (decl) == FUNCTION_DECL |
| && DECL_DECLARED_INLINE_P (decl)) |
| || (DECL_LANG_SPECIFIC (decl) |
| && DECL_TEMPLATE_INSTANTIATION (decl)) |
| || (VAR_P (decl) && DECL_INLINE_VAR_P (decl))) |
| return true; |
| else if (DECL_FUNCTION_SCOPE_P (decl)) |
| /* A local static in an inline effectively has vague linkage. */ |
| return (TREE_STATIC (decl) |
| && vague_linkage_p (DECL_CONTEXT (decl))); |
| else |
| return false; |
| } |
| |
| /* Determine whether or not we want to specifically import or export CTYPE, |
| using various heuristics. */ |
| |
| static void |
| import_export_class (tree ctype) |
| { |
| /* -1 for imported, 1 for exported. */ |
| int import_export = 0; |
| |
| /* It only makes sense to call this function at EOF. The reason is |
| that this function looks at whether or not the first non-inline |
| non-abstract virtual member function has been defined in this |
| translation unit. But, we can't possibly know that until we've |
| seen the entire translation unit. */ |
| gcc_assert (at_eof); |
| |
| if (CLASSTYPE_INTERFACE_KNOWN (ctype)) |
| return; |
| |
| /* If MULTIPLE_SYMBOL_SPACES is set and we saw a #pragma interface, |
| we will have CLASSTYPE_INTERFACE_ONLY set but not |
| CLASSTYPE_INTERFACE_KNOWN. In that case, we don't want to use this |
| heuristic because someone will supply a #pragma implementation |
| elsewhere, and deducing it here would produce a conflict. */ |
| if (CLASSTYPE_INTERFACE_ONLY (ctype)) |
| return; |
| |
| if (lookup_attribute ("dllimport", TYPE_ATTRIBUTES (ctype))) |
| import_export = -1; |
| else if (lookup_attribute ("dllexport", TYPE_ATTRIBUTES (ctype))) |
| import_export = 1; |
| else if (CLASSTYPE_IMPLICIT_INSTANTIATION (ctype) |
| && !flag_implicit_templates) |
| /* For a template class, without -fimplicit-templates, check the |
| repository. If the virtual table is assigned to this |
| translation unit, then export the class; otherwise, import |
| it. */ |
| import_export = -1; |
| else if (TYPE_POLYMORPHIC_P (ctype)) |
| { |
| /* The ABI specifies that the virtual table and associated |
| information are emitted with the key method, if any. */ |
| tree method = CLASSTYPE_KEY_METHOD (ctype); |
| /* If weak symbol support is not available, then we must be |
| careful not to emit the vtable when the key function is |
| inline. An inline function can be defined in multiple |
| translation units. If we were to emit the vtable in each |
| translation unit containing a definition, we would get |
| multiple definition errors at link-time. */ |
| if (method && (flag_weak || ! DECL_DECLARED_INLINE_P (method))) |
| import_export = (DECL_REALLY_EXTERN (method) ? -1 : 1); |
| } |
| |
| /* When MULTIPLE_SYMBOL_SPACES is set, we cannot count on seeing |
| a definition anywhere else. */ |
| if (MULTIPLE_SYMBOL_SPACES && import_export == -1) |
| import_export = 0; |
| |
| /* Allow back ends the chance to overrule the decision. */ |
| if (targetm.cxx.import_export_class) |
| import_export = targetm.cxx.import_export_class (ctype, import_export); |
| |
| if (import_export) |
| { |
| SET_CLASSTYPE_INTERFACE_KNOWN (ctype); |
| CLASSTYPE_INTERFACE_ONLY (ctype) = (import_export < 0); |
| } |
| } |
| |
| /* Return true if VAR has already been provided to the back end; in that |
| case VAR should not be modified further by the front end. */ |
| static bool |
| var_finalized_p (tree var) |
| { |
| return varpool_node::get_create (var)->definition; |
| } |
| |
| /* DECL is a VAR_DECL or FUNCTION_DECL which, for whatever reason, |
| must be emitted in this translation unit. Mark it as such. */ |
| |
| void |
| mark_needed (tree decl) |
| { |
| TREE_USED (decl) = 1; |
| if (TREE_CODE (decl) == FUNCTION_DECL) |
| { |
| /* Extern inline functions don't become needed when referenced. |
| If we know a method will be emitted in other TU and no new |
| functions can be marked reachable, just use the external |
| definition. */ |
| struct cgraph_node *node = cgraph_node::get_create (decl); |
| node->forced_by_abi = true; |
| |
| /* #pragma interface can call mark_needed for |
| maybe-in-charge 'tors; mark the clones as well. */ |
| tree clone; |
| FOR_EACH_CLONE (clone, decl) |
| mark_needed (clone); |
| } |
| else if (VAR_P (decl)) |
| { |
| varpool_node *node = varpool_node::get_create (decl); |
| /* C++ frontend use mark_decl_references to force COMDAT variables |
| to be output that might appear dead otherwise. */ |
| node->forced_by_abi = true; |
| } |
| } |
| |
| /* DECL is either a FUNCTION_DECL or a VAR_DECL. This function |
| returns true if a definition of this entity should be provided in |
| this object file. Callers use this function to determine whether |
| or not to let the back end know that a definition of DECL is |
| available in this translation unit. */ |
| |
| bool |
| decl_needed_p (tree decl) |
| { |
| gcc_assert (VAR_OR_FUNCTION_DECL_P (decl)); |
| /* This function should only be called at the end of the translation |
| unit. We cannot be sure of whether or not something will be |
| COMDAT until that point. */ |
| gcc_assert (at_eof); |
| |
| /* All entities with external linkage that are not COMDAT/EXTERN should be |
| emitted; they may be referred to from other object files. */ |
| if (TREE_PUBLIC (decl) && !DECL_COMDAT (decl) && !DECL_REALLY_EXTERN (decl)) |
| return true; |
| |
| /* Functions marked "dllexport" must be emitted so that they are |
| visible to other DLLs. */ |
| if (flag_keep_inline_dllexport |
| && lookup_attribute ("dllexport", DECL_ATTRIBUTES (decl))) |
| return true; |
| |
| /* When not optimizing, do not bother to produce definitions for extern |
| symbols. */ |
| if (DECL_REALLY_EXTERN (decl) |
| && ((TREE_CODE (decl) != FUNCTION_DECL |
| && !optimize) |
| || (TREE_CODE (decl) == FUNCTION_DECL |
| && !opt_for_fn (decl, optimize))) |
| && !lookup_attribute ("always_inline", decl)) |
| return false; |
| |
| /* If this entity was used, let the back end see it; it will decide |
| whether or not to emit it into the object file. */ |
| if (TREE_USED (decl)) |
| return true; |
| |
| /* Virtual functions might be needed for devirtualization. */ |
| if (flag_devirtualize |
| && TREE_CODE (decl) == FUNCTION_DECL |
| && DECL_VIRTUAL_P (decl)) |
| return true; |
| |
| /* Otherwise, DECL does not need to be emitted -- yet. A subsequent |
| reference to DECL might cause it to be emitted later. */ |
| return false; |
| } |
| |
| /* If necessary, write out the vtables for the dynamic class CTYPE. |
| Returns true if any vtables were emitted. */ |
| |
| static bool |
| maybe_emit_vtables (tree ctype, vec<tree> &consteval_vtables) |
| { |
| tree vtbl; |
| tree primary_vtbl; |
| int needed = 0; |
| varpool_node *current = NULL, *last = NULL; |
| |
| /* If the vtables for this class have already been emitted there is |
| nothing more to do. */ |
| primary_vtbl = CLASSTYPE_VTABLES (ctype); |
| if (var_finalized_p (primary_vtbl)) |
| return false; |
| /* Ignore dummy vtables made by get_vtable_decl. */ |
| if (TREE_TYPE (primary_vtbl) == void_type_node) |
| return false; |
| |
| /* On some targets, we cannot determine the key method until the end |
| of the translation unit -- which is when this function is |
| called. */ |
| if (!targetm.cxx.key_method_may_be_inline ()) |
| determine_key_method (ctype); |
| |
| /* See if any of the vtables are needed. */ |
| for (vtbl = CLASSTYPE_VTABLES (ctype); vtbl; vtbl = DECL_CHAIN (vtbl)) |
| { |
| import_export_decl (vtbl); |
| if (DECL_NOT_REALLY_EXTERN (vtbl) && decl_needed_p (vtbl)) |
| needed = 1; |
| } |
| if (!needed) |
| { |
| /* If the references to this class' vtables are optimized away, |
| still emit the appropriate debugging information. See |
| dfs_debug_mark. */ |
| if (DECL_COMDAT (primary_vtbl) |
| && CLASSTYPE_DEBUG_REQUESTED (ctype)) |
| note_debug_info_needed (ctype); |
| return false; |
| } |
| |
| /* The ABI requires that we emit all of the vtables if we emit any |
| of them. */ |
| for (vtbl = CLASSTYPE_VTABLES (ctype); vtbl; vtbl = DECL_CHAIN (vtbl)) |
| { |
| /* Mark entities references from the virtual table as used. */ |
| mark_vtable_entries (vtbl, consteval_vtables); |
| |
| if (TREE_TYPE (DECL_INITIAL (vtbl)) == 0) |
| { |
| vec<tree, va_gc> *cleanups = NULL; |
| tree expr = store_init_value (vtbl, DECL_INITIAL (vtbl), &cleanups, |
| LOOKUP_NORMAL); |
| |
| /* It had better be all done at compile-time. */ |
| gcc_assert (!expr && !cleanups); |
| } |
| |
| /* Write it out. */ |
| DECL_EXTERNAL (vtbl) = 0; |
| rest_of_decl_compilation (vtbl, 1, 1); |
| |
| /* Because we're only doing syntax-checking, we'll never end up |
| actually marking the variable as written. */ |
| if (flag_syntax_only) |
| TREE_ASM_WRITTEN (vtbl) = 1; |
| else if (DECL_ONE_ONLY (vtbl)) |
| { |
| current = varpool_node::get_create (vtbl); |
| if (last) |
| current->add_to_same_comdat_group (last); |
| last = current; |
| } |
| } |
| |
| /* For abstract classes, the destructor has been removed from the |
| vtable (in class.cc's build_vtbl_initializer). For a compiler- |
| generated destructor, it hence might not have been generated in |
| this translation unit - and with '#pragma interface' it might |
| never get generated. */ |
| if (CLASSTYPE_PURE_VIRTUALS (ctype) |
| && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (ctype) |
| && !CLASSTYPE_LAZY_DESTRUCTOR (ctype) |
| && DECL_DEFAULTED_IN_CLASS_P (CLASSTYPE_DESTRUCTOR (ctype))) |
| note_vague_linkage_fn (CLASSTYPE_DESTRUCTOR (ctype)); |
| |
| /* Since we're writing out the vtable here, also write the debug |
| info. */ |
| note_debug_info_needed (ctype); |
| |
| return true; |
| } |
| |
| /* A special return value from type_visibility meaning internal |
| linkage. */ |
| |
| enum { VISIBILITY_ANON = VISIBILITY_INTERNAL+1 }; |
| |
| static int expr_visibility (tree); |
| static int type_visibility (tree); |
| |
| /* walk_tree helper function for type_visibility. */ |
| |
| static tree |
| min_vis_r (tree *tp, int *walk_subtrees, void *data) |
| { |
| int *vis_p = (int *)data; |
| int this_vis = VISIBILITY_DEFAULT; |
| if (! TYPE_P (*tp)) |
| *walk_subtrees = 0; |
| else if (OVERLOAD_TYPE_P (*tp) |
| && !TREE_PUBLIC (TYPE_MAIN_DECL (*tp))) |
| { |
| this_vis = VISIBILITY_ANON; |
| *walk_subtrees = 0; |
| } |
| else if (CLASS_TYPE_P (*tp)) |
| { |
| this_vis = CLASSTYPE_VISIBILITY (*tp); |
| *walk_subtrees = 0; |
| } |
| else if (TREE_CODE (*tp) == ARRAY_TYPE |
| && uses_template_parms (TYPE_DOMAIN (*tp))) |
| this_vis = expr_visibility (TYPE_MAX_VALUE (TYPE_DOMAIN (*tp))); |
| |
| if (this_vis > *vis_p) |
| *vis_p = this_vis; |
| |
| /* Tell cp_walk_subtrees to look through typedefs. */ |
| if (*walk_subtrees == 1) |
| *walk_subtrees = 2; |
| |
| return NULL; |
| } |
| |
| /* walk_tree helper function for expr_visibility. */ |
| |
| static tree |
| min_vis_expr_r (tree *tp, int */*walk_subtrees*/, void *data) |
| { |
| int *vis_p = (int *)data; |
| int tpvis = VISIBILITY_DEFAULT; |
| |
| switch (TREE_CODE (*tp)) |
| { |
| case CAST_EXPR: |
| case IMPLICIT_CONV_EXPR: |
| case STATIC_CAST_EXPR: |
| case REINTERPRET_CAST_EXPR: |
| case CONST_CAST_EXPR: |
| case DYNAMIC_CAST_EXPR: |
| case NEW_EXPR: |
| case CONSTRUCTOR: |
| case LAMBDA_EXPR: |
| tpvis = type_visibility (TREE_TYPE (*tp)); |
| break; |
| |
| case VAR_DECL: |
| case FUNCTION_DECL: |
| if (! TREE_PUBLIC (*tp)) |
| tpvis = VISIBILITY_ANON; |
| else |
| tpvis = DECL_VISIBILITY (*tp); |
| break; |
| |
| default: |
| break; |
| } |
| |
| if (tpvis > *vis_p) |
| *vis_p = tpvis; |
| |
| return NULL_TREE; |
| } |
| |
| /* Returns the visibility of TYPE, which is the minimum visibility of its |
| component types. */ |
| |
| static int |
| type_visibility (tree type) |
| { |
| int vis = VISIBILITY_DEFAULT; |
| cp_walk_tree_without_duplicates (&type, min_vis_r, &vis); |
| return vis; |
| } |
| |
| /* Returns the visibility of an expression EXPR that appears in the signature |
| of a function template, which is the minimum visibility of names that appear |
| in its mangling. */ |
| |
| static int |
| expr_visibility (tree expr) |
| { |
| int vis = VISIBILITY_DEFAULT; |
| cp_walk_tree_without_duplicates (&expr, min_vis_expr_r, &vis); |
| return vis; |
| } |
| |
| /* Limit the visibility of DECL to VISIBILITY, if not explicitly |
| specified (or if VISIBILITY is static). If TMPL is true, this |
| constraint is for a template argument, and takes precedence |
| over explicitly-specified visibility on the template. */ |
| |
| static void |
| constrain_visibility (tree decl, int visibility, bool tmpl) |
| { |
| if (visibility == VISIBILITY_ANON) |
| { |
| /* extern "C" declarations aren't affected by the anonymous |
| namespace. */ |
| if (!DECL_EXTERN_C_P (decl)) |
| { |
| TREE_PUBLIC (decl) = 0; |
| DECL_WEAK (decl) = 0; |
| DECL_COMMON (decl) = 0; |
| DECL_COMDAT (decl) = false; |
| if (VAR_OR_FUNCTION_DECL_P (decl)) |
| { |
| struct symtab_node *snode = symtab_node::get (decl); |
| |
| if (snode) |
| snode->set_comdat_group (NULL); |
| } |
| DECL_INTERFACE_KNOWN (decl) = 1; |
| if (DECL_LANG_SPECIFIC (decl)) |
| DECL_NOT_REALLY_EXTERN (decl) = 1; |
| } |
| } |
| else if (visibility > DECL_VISIBILITY (decl) |
| && (tmpl || !DECL_VISIBILITY_SPECIFIED (decl))) |
| { |
| DECL_VISIBILITY (decl) = (enum symbol_visibility) visibility; |
| /* This visibility was not specified. */ |
| DECL_VISIBILITY_SPECIFIED (decl) = false; |
| } |
| } |
| |
| /* Constrain the visibility of DECL based on the visibility of its template |
| arguments. */ |
| |
| static void |
| constrain_visibility_for_template (tree decl, tree targs) |
| { |
| /* If this is a template instantiation, check the innermost |
| template args for visibility constraints. The outer template |
| args are covered by the class check. */ |
| tree args = INNERMOST_TEMPLATE_ARGS (targs); |
| int i; |
| for (i = TREE_VEC_LENGTH (args); i > 0; --i) |
| { |
| int vis = 0; |
| |
| tree arg = TREE_VEC_ELT (args, i-1); |
| if (TYPE_P (arg)) |
| vis = type_visibility (arg); |
| else |
| vis = expr_visibility (arg); |
| if (vis) |
| constrain_visibility (decl, vis, true); |
| } |
| } |
| |
| /* Like c_determine_visibility, but with additional C++-specific |
| behavior. |
| |
| Function-scope entities can rely on the function's visibility because |
| it is set in start_preparsed_function. |
| |
| Class-scope entities cannot rely on the class's visibility until the end |
| of the enclosing class definition. |
| |
| Note that because namespaces have multiple independent definitions, |
| namespace visibility is handled elsewhere using the #pragma visibility |
| machinery rather than by decorating the namespace declaration. |
| |
| The goal is for constraints from the type to give a diagnostic, and |
| other constraints to be applied silently. */ |
| |
| void |
| determine_visibility (tree decl) |
| { |
| /* Remember that all decls get VISIBILITY_DEFAULT when built. */ |
| |
| /* Only relevant for names with external linkage. */ |
| if (!TREE_PUBLIC (decl)) |
| return; |
| |
| /* Cloned constructors and destructors get the same visibility as |
| the underlying function. That should be set up in |
| maybe_clone_body. */ |
| gcc_assert (!DECL_CLONED_FUNCTION_P (decl)); |
| |
| bool orig_visibility_specified = DECL_VISIBILITY_SPECIFIED (decl); |
| enum symbol_visibility orig_visibility = DECL_VISIBILITY (decl); |
| |
| /* The decl may be a template instantiation, which could influence |
| visibilty. */ |
| tree template_decl = NULL_TREE; |
| if (TREE_CODE (decl) == TYPE_DECL) |
| { |
| if (CLASS_TYPE_P (TREE_TYPE (decl))) |
| { |
| if (CLASSTYPE_USE_TEMPLATE (TREE_TYPE (decl))) |
| template_decl = decl; |
| } |
| else if (TYPE_TEMPLATE_INFO (TREE_TYPE (decl))) |
| template_decl = decl; |
| } |
| else if (DECL_LANG_SPECIFIC (decl) && DECL_USE_TEMPLATE (decl)) |
| template_decl = decl; |
| |
| if (TREE_CODE (decl) == TYPE_DECL |
| && LAMBDA_TYPE_P (TREE_TYPE (decl)) |
| && CLASSTYPE_LAMBDA_EXPR (TREE_TYPE (decl)) != error_mark_node) |
| if (tree extra = LAMBDA_TYPE_EXTRA_SCOPE (TREE_TYPE (decl))) |
| { |
| /* The lambda's visibility is limited by that of its extra |
| scope. */ |
| int vis = 0; |
| if (TYPE_P (extra)) |
| vis = type_visibility (extra); |
| else |
| vis = expr_visibility (extra); |
| constrain_visibility (decl, vis, false); |
| } |
| |
| /* If DECL is a member of a class, visibility specifiers on the |
| class can influence the visibility of the DECL. */ |
| tree class_type = NULL_TREE; |
| if (DECL_CLASS_SCOPE_P (decl)) |
| class_type = DECL_CONTEXT (decl); |
| else |
| { |
| /* Not a class member. */ |
| |
| /* Virtual tables have DECL_CONTEXT set to their associated class, |
| so they are automatically handled above. */ |
| gcc_assert (!VAR_P (decl) |
| || !DECL_VTABLE_OR_VTT_P (decl)); |
| |
| if (DECL_FUNCTION_SCOPE_P (decl) && ! DECL_VISIBILITY_SPECIFIED (decl)) |
| { |
| /* Local statics and classes get the visibility of their |
| containing function by default, except that |
| -fvisibility-inlines-hidden doesn't affect them. */ |
| tree fn = DECL_CONTEXT (decl); |
| if (DECL_VISIBILITY_SPECIFIED (fn)) |
| { |
| DECL_VISIBILITY (decl) = DECL_VISIBILITY (fn); |
| DECL_VISIBILITY_SPECIFIED (decl) = |
| DECL_VISIBILITY_SPECIFIED (fn); |
| } |
| else |
| { |
| if (DECL_CLASS_SCOPE_P (fn)) |
| determine_visibility_from_class (decl, DECL_CONTEXT (fn)); |
| else if (determine_hidden_inline (fn)) |
| { |
| DECL_VISIBILITY (decl) = default_visibility; |
| DECL_VISIBILITY_SPECIFIED (decl) = |
| visibility_options.inpragma; |
| } |
| else |
| { |
| DECL_VISIBILITY (decl) = DECL_VISIBILITY (fn); |
| DECL_VISIBILITY_SPECIFIED (decl) = |
| DECL_VISIBILITY_SPECIFIED (fn); |
| } |
| } |
| |
| /* Local classes in templates have CLASSTYPE_USE_TEMPLATE set, |
| but have no TEMPLATE_INFO, so don't try to check it. */ |
| template_decl = NULL_TREE; |
| } |
| else if (VAR_P (decl) && DECL_TINFO_P (decl) |
| && flag_visibility_ms_compat) |
| { |
| /* Under -fvisibility-ms-compat, types are visible by default, |
| even though their contents aren't. */ |
| tree underlying_type = TREE_TYPE (DECL_NAME (decl)); |
| int underlying_vis = type_visibility (underlying_type); |
| if (underlying_vis == VISIBILITY_ANON |
| || (CLASS_TYPE_P (underlying_type) |
| && CLASSTYPE_VISIBILITY_SPECIFIED (underlying_type))) |
| constrain_visibility (decl, underlying_vis, false); |
| else |
| DECL_VISIBILITY (decl) = VISIBILITY_DEFAULT; |
| } |
| else if (VAR_P (decl) && DECL_TINFO_P (decl)) |
| { |
| /* tinfo visibility is based on the type it's for. */ |
| constrain_visibility |
| (decl, type_visibility (TREE_TYPE (DECL_NAME (decl))), false); |
| |
| /* Give the target a chance to override the visibility associated |
| with DECL. */ |
| if (TREE_PUBLIC (decl) |
| && !DECL_REALLY_EXTERN (decl) |
| && CLASS_TYPE_P (TREE_TYPE (DECL_NAME (decl))) |
| && !CLASSTYPE_VISIBILITY_SPECIFIED (TREE_TYPE (DECL_NAME (decl)))) |
| targetm.cxx.determine_class_data_visibility (decl); |
| } |
| else if (template_decl) |
| /* Template instantiations and specializations get visibility based |
| on their template unless they override it with an attribute. */; |
| else if (! DECL_VISIBILITY_SPECIFIED (decl)) |
| { |
| if (determine_hidden_inline (decl)) |
| DECL_VISIBILITY (decl) = VISIBILITY_HIDDEN; |
| else |
| { |
| /* Set default visibility to whatever the user supplied with |
| #pragma GCC visibility or a namespace visibility attribute. */ |
| DECL_VISIBILITY (decl) = default_visibility; |
| DECL_VISIBILITY_SPECIFIED (decl) = visibility_options.inpragma; |
| } |
| } |
| } |
| |
| if (template_decl) |
| { |
| /* If the specialization doesn't specify visibility, use the |
| visibility from the template. */ |
| tree tinfo = get_template_info (template_decl); |
| tree args = TI_ARGS (tinfo); |
| tree attribs = (TREE_CODE (decl) == TYPE_DECL |
| ? TYPE_ATTRIBUTES (TREE_TYPE (decl)) |
| : DECL_ATTRIBUTES (decl)); |
| tree attr = lookup_attribute ("visibility", attribs); |
| |
| if (args != error_mark_node) |
| { |
| tree pattern = DECL_TEMPLATE_RESULT (TI_TEMPLATE (tinfo)); |
| |
| if (!DECL_VISIBILITY_SPECIFIED (decl)) |
| { |
| if (!attr |
| && determine_hidden_inline (decl)) |
| DECL_VISIBILITY (decl) = VISIBILITY_HIDDEN; |
| else |
| { |
| DECL_VISIBILITY (decl) = DECL_VISIBILITY (pattern); |
| DECL_VISIBILITY_SPECIFIED (decl) |
| = DECL_VISIBILITY_SPECIFIED (pattern); |
| } |
| } |
| |
| if (args |
| /* Template argument visibility outweighs #pragma or namespace |
| visibility, but not an explicit attribute. */ |
| && !attr) |
| { |
| int depth = TMPL_ARGS_DEPTH (args); |
| if (DECL_VISIBILITY_SPECIFIED (decl)) |
| { |
| /* A class template member with explicit visibility |
| overrides the class visibility, so we need to apply |
| all the levels of template args directly. */ |
| int i; |
| for (i = 1; i <= depth; ++i) |
| { |
| tree lev = TMPL_ARGS_LEVEL (args, i); |
| constrain_visibility_for_template (decl, lev); |
| } |
| } |
| else if (PRIMARY_TEMPLATE_P (TI_TEMPLATE (tinfo))) |
| /* Limit visibility based on its template arguments. */ |
| constrain_visibility_for_template (decl, args); |
| } |
| } |
| } |
| |
| if (class_type) |
| determine_visibility_from_class (decl, class_type); |
| |
| if (decl_anon_ns_mem_p (decl)) |
| /* Names in an anonymous namespace get internal linkage. */ |
| constrain_visibility (decl, VISIBILITY_ANON, false); |
| else if (TREE_CODE (decl) != TYPE_DECL) |
| { |
| /* Propagate anonymity from type to decl. */ |
| int tvis = type_visibility (TREE_TYPE (decl)); |
| if (tvis == VISIBILITY_ANON |
| || ! DECL_VISIBILITY_SPECIFIED (decl)) |
| constrain_visibility (decl, tvis, false); |
| } |
| else if (no_linkage_check (TREE_TYPE (decl), /*relaxed_p=*/true)) |
| /* DR 757: A type without linkage shall not be used as the type of a |
| variable or function with linkage, unless |
| o the variable or function has extern "C" linkage (7.5 [dcl.link]), or |
| o the variable or function is not used (3.2 [basic.def.odr]) or is |
| defined in the same translation unit. |
| |
| Since non-extern "C" decls need to be defined in the same |
| translation unit, we can make the type internal. */ |
| constrain_visibility (decl, VISIBILITY_ANON, false); |
| |
| /* If visibility changed and DECL already has DECL_RTL, ensure |
| symbol flags are updated. */ |
| if ((DECL_VISIBILITY (decl) != orig_visibility |
| || DECL_VISIBILITY_SPECIFIED (decl) != orig_visibility_specified) |
| && ((VAR_P (decl) && TREE_STATIC (decl)) |
| || TREE_CODE (decl) == FUNCTION_DECL) |
| && DECL_RTL_SET_P (decl)) |
| make_decl_rtl (decl); |
| } |
| |
| /* By default, static data members and function members receive |
| the visibility of their containing class. */ |
| |
| static void |
| determine_visibility_from_class (tree decl, tree class_type) |
| { |
| if (DECL_VISIBILITY_SPECIFIED (decl)) |
| return; |
| |
| if (determine_hidden_inline (decl)) |
| DECL_VISIBILITY (decl) = VISIBILITY_HIDDEN; |
| else |
| { |
| /* Default to the class visibility. */ |
| DECL_VISIBILITY (decl) = CLASSTYPE_VISIBILITY (class_type); |
| DECL_VISIBILITY_SPECIFIED (decl) |
| = CLASSTYPE_VISIBILITY_SPECIFIED (class_type); |
| } |
| |
| /* Give the target a chance to override the visibility associated |
| with DECL. */ |
| if (VAR_P (decl) |
| && TREE_PUBLIC (decl) |
| && (DECL_TINFO_P (decl) || DECL_VTABLE_OR_VTT_P (decl)) |
| && !DECL_REALLY_EXTERN (decl) |
| && !CLASSTYPE_VISIBILITY_SPECIFIED (class_type)) |
| targetm.cxx.determine_class_data_visibility (decl); |
| } |
| |
| /* Returns true iff DECL is an inline that should get hidden visibility |
| because of -fvisibility-inlines-hidden. */ |
| |
| static bool |
| determine_hidden_inline (tree decl) |
| { |
| return (visibility_options.inlines_hidden |
| /* Don't do this for inline templates; specializations might not be |
| inline, and we don't want them to inherit the hidden |
| visibility. We'll set it here for all inline instantiations. */ |
| && !processing_template_decl |
| && TREE_CODE (decl) == FUNCTION_DECL |
| && DECL_DECLARED_INLINE_P (decl) |
| && (! DECL_LANG_SPECIFIC (decl) |
| || ! DECL_EXPLICIT_INSTANTIATION (decl))); |
| } |
| |
| /* Constrain the visibility of a class TYPE based on the visibility of its |
| field types. Warn if any fields require lesser visibility. */ |
| |
| void |
| constrain_class_visibility (tree type) |
| { |
| tree binfo; |
| tree t; |
| int i; |
| |
| int vis = type_visibility (type); |
| |
| if (vis == VISIBILITY_ANON |
| || DECL_IN_SYSTEM_HEADER (TYPE_MAIN_DECL (type))) |
| return; |
| |
| /* Don't warn about visibility if the class has explicit visibility. */ |
| if (CLASSTYPE_VISIBILITY_SPECIFIED (type)) |
| vis = VISIBILITY_INTERNAL; |
| |
| for (t = TYPE_FIELDS (type); t; t = DECL_CHAIN (t)) |
| if (TREE_CODE (t) == FIELD_DECL && TREE_TYPE (t) != error_mark_node |
| && !DECL_ARTIFICIAL (t)) |
| { |
| tree ftype = strip_pointer_or_array_types (TREE_TYPE (t)); |
| int subvis = type_visibility (ftype); |
| |
| if (subvis == VISIBILITY_ANON) |
| { |
| if (!in_main_input_context()) |
| { |
| tree nlt = no_linkage_check (ftype, /*relaxed_p=*/false); |
| if (nlt) |
| { |
| if (same_type_p (TREE_TYPE (t), nlt)) |
| warning (OPT_Wsubobject_linkage, "\ |
| %qT has a field %qD whose type has no linkage", |
| type, t); |
| else |
| warning (OPT_Wsubobject_linkage, "\ |
| %qT has a field %qD whose type depends on the type %qT which has no linkage", |
| type, t, nlt); |
| } |
| else |
| warning (OPT_Wsubobject_linkage, "\ |
| %qT has a field %qD whose type uses the anonymous namespace", |
| type, t); |
| } |
| } |
| else if (MAYBE_CLASS_TYPE_P (ftype) |
| && vis < VISIBILITY_HIDDEN |
| && subvis >= VISIBILITY_HIDDEN) |
| warning (OPT_Wattributes, "\ |
| %qT declared with greater visibility than the type of its field %qD", |
| type, t); |
| } |
| |
| binfo = TYPE_BINFO (type); |
| for (i = 0; BINFO_BASE_ITERATE (binfo, i, t); ++i) |
| { |
| int subvis = type_visibility (TREE_TYPE (t)); |
| |
| if (subvis == VISIBILITY_ANON) |
| { |
| if (!in_main_input_context()) |
| { |
| tree nlt = no_linkage_check (TREE_TYPE (t), /*relaxed_p=*/false); |
| if (nlt) |
| { |
| if (same_type_p (TREE_TYPE (t), nlt)) |
| warning (OPT_Wsubobject_linkage, "\ |
| %qT has a base %qT whose type has no linkage", |
| type, TREE_TYPE (t)); |
| else |
| warning (OPT_Wsubobject_linkage, "\ |
| %qT has a base %qT whose type depends on the type %qT which has no linkage", |
| type, TREE_TYPE (t), nlt); |
| } |
| else |
| warning (OPT_Wsubobject_linkage, "\ |
| %qT has a base %qT whose type uses the anonymous namespace", |
| type, TREE_TYPE (t)); |
| } |
| } |
| else if (vis < VISIBILITY_HIDDEN |
| && subvis >= VISIBILITY_HIDDEN) |
| warning (OPT_Wattributes, "\ |
| %qT declared with greater visibility than its base %qT", |
| type, TREE_TYPE (t)); |
| } |
| } |
| |
| /* Functions for adjusting the visibility of a tagged type and its nested |
| types and declarations when it gets a name for linkage purposes from a |
| typedef. */ |
| // FIXME: It is now a DR for such a class type to contain anything |
| // other than C. So at minium most of this can probably be deleted. |
| |
| /* First reset the visibility of all the types. */ |
| |
| static void |
| reset_type_linkage_1 (tree type) |
| { |
| set_linkage_according_to_type (type, TYPE_MAIN_DECL (type)); |
| if (CLASS_TYPE_P (type)) |
| for (tree member = TYPE_FIELDS (type); member; member = DECL_CHAIN (member)) |
| if (DECL_IMPLICIT_TYPEDEF_P (member)) |
| reset_type_linkage_1 (TREE_TYPE (member)); |
| } |
| |
| /* Then reset the visibility of any static data members or member |
| functions that use those types. */ |
| |
| static void |
| reset_decl_linkage (tree decl) |
| { |
| if (TREE_PUBLIC (decl)) |
| return; |
| if (DECL_CLONED_FUNCTION_P (decl)) |
| return; |
| TREE_PUBLIC (decl) = true; |
| DECL_INTERFACE_KNOWN (decl) = false; |
| determine_visibility (decl); |
| tentative_decl_linkage (decl); |
| } |
| |
| void |
| reset_type_linkage (tree type) |
| { |
| reset_type_linkage_1 (type); |
| if (CLASS_TYPE_P (type)) |
| { |
| if (tree vt = CLASSTYPE_VTABLES (type)) |
| { |
| tree name = mangle_vtbl_for_type (type); |
| DECL_NAME (vt) = name; |
| SET_DECL_ASSEMBLER_NAME (vt, name); |
| reset_decl_linkage (vt); |
| } |
| if (!ANON_AGGR_TYPE_P (type)) |
| if (tree ti = CLASSTYPE_TYPEINFO_VAR (type)) |
| { |
| tree name = mangle_typeinfo_for_type (type); |
| DECL_NAME (ti) = name; |
| SET_DECL_ASSEMBLER_NAME (ti, name); |
| TREE_TYPE (name) = type; |
| reset_decl_linkage (ti); |
| } |
| for (tree m = TYPE_FIELDS (type); m; m = DECL_CHAIN (m)) |
| { |
| tree mem = STRIP_TEMPLATE (m); |
| if (TREE_CODE (mem) == VAR_DECL || TREE_CODE (mem) == FUNCTION_DECL) |
| reset_decl_linkage (mem); |
| else if (DECL_IMPLICIT_TYPEDEF_P (mem)) |
| reset_type_linkage (TREE_TYPE (mem)); |
| } |
| } |
| } |
| |
| /* Set up our initial idea of what the linkage of DECL should be. */ |
| |
| void |
| tentative_decl_linkage (tree decl) |
| { |
| if (DECL_INTERFACE_KNOWN (decl)) |
| /* We've already made a decision as to how this function will |
| be handled. */; |
| else if (vague_linkage_p (decl)) |
| { |
| if (TREE_CODE (decl) == FUNCTION_DECL |
| && decl_defined_p (decl)) |
| { |
| DECL_EXTERNAL (decl) = 1; |
| DECL_NOT_REALLY_EXTERN (decl) = 1; |
| note_vague_linkage_fn (decl); |
| /* A non-template inline function with external linkage will |
| always be COMDAT. As we must eventually determine the |
| linkage of all functions, and as that causes writes to |
| the data mapped in from the PCH file, it's advantageous |
| to mark the functions at this point. */ |
| if (DECL_DECLARED_INLINE_P (decl) |
| && (!DECL_IMPLICIT_INSTANTIATION (decl) |
| || DECL_DEFAULTED_FN (decl))) |
| { |
| /* This function must have external linkage, as |
| otherwise DECL_INTERFACE_KNOWN would have been |
| set. */ |
| gcc_assert (TREE_PUBLIC (decl)); |
| comdat_linkage (decl); |
| DECL_INTERFACE_KNOWN (decl) = 1; |
| } |
| } |
| else if (VAR_P (decl)) |
| maybe_commonize_var (decl); |
| } |
| } |
| |
| /* DECL is a FUNCTION_DECL or VAR_DECL. If the object file linkage |
| for DECL has not already been determined, do so now by setting |
| DECL_EXTERNAL, DECL_COMDAT and other related flags. Until this |
| function is called entities with vague linkage whose definitions |
| are available must have TREE_PUBLIC set. |
| |
| If this function decides to place DECL in COMDAT, it will set |
| appropriate flags -- but will not clear DECL_EXTERNAL. It is up to |
| the caller to decide whether or not to clear DECL_EXTERNAL. Some |
| callers defer that decision until it is clear that DECL is actually |
| required. */ |
| |
| void |
| import_export_decl (tree decl) |
| { |
| bool comdat_p; |
| bool import_p; |
| tree class_type = NULL_TREE; |
| |
| if (DECL_INTERFACE_KNOWN (decl)) |
| return; |
| |
| /* We cannot determine what linkage to give to an entity with vague |
| linkage until the end of the file. For example, a virtual table |
| for a class will be defined if and only if the key method is |
| defined in this translation unit. */ |
| gcc_assert (at_eof); |
| /* Object file linkage for explicit instantiations is handled in |
| mark_decl_instantiated. For static variables in functions with |
| vague linkage, maybe_commonize_var is used. |
| |
| Therefore, the only declarations that should be provided to this |
| function are those with external linkage that are: |
| |
| * implicit instantiations of function templates |
| |
| * inline function |
| |
| * implicit instantiations of static data members of class |
| templates |
| |
| * virtual tables |
| |
| * typeinfo objects |
| |
| Furthermore, all entities that reach this point must have a |
| definition available in this translation unit. |
| |
| The following assertions check these conditions. */ |
| gcc_assert (VAR_OR_FUNCTION_DECL_P (decl)); |
| /* Any code that creates entities with TREE_PUBLIC cleared should |
| also set DECL_INTERFACE_KNOWN. */ |
| gcc_assert (TREE_PUBLIC (decl)); |
| if (TREE_CODE (decl) == FUNCTION_DECL) |
| gcc_assert (DECL_IMPLICIT_INSTANTIATION (decl) |
| || DECL_FRIEND_PSEUDO_TEMPLATE_INSTANTIATION (decl) |
| || DECL_DECLARED_INLINE_P (decl)); |
| else |
| gcc_assert (DECL_IMPLICIT_INSTANTIATION (decl) |
| || DECL_VTABLE_OR_VTT_P (decl) |
| || DECL_TINFO_P (decl)); |
| /* Check that a definition of DECL is available in this translation |
| unit. */ |
| gcc_assert (!DECL_REALLY_EXTERN (decl)); |
| |
| /* Assume that DECL will not have COMDAT linkage. */ |
| comdat_p = false; |
| /* Assume that DECL will not be imported into this translation |
| unit. */ |
| import_p = false; |
| |
| if (VAR_P (decl) && DECL_VTABLE_OR_VTT_P (decl)) |
| { |
| class_type = DECL_CONTEXT (decl); |
| import_export_class (class_type); |
| if (CLASSTYPE_INTERFACE_KNOWN (class_type) |
| && CLASSTYPE_INTERFACE_ONLY (class_type)) |
| import_p = true; |
| else if ((!flag_weak || TARGET_WEAK_NOT_IN_ARCHIVE_TOC) |
| && !CLASSTYPE_USE_TEMPLATE (class_type) |
|