diff --git a/gcc/attribs.cc b/gcc/attribs.cc index d57c17501075..db9a5c125ac8 100644 --- a/gcc/attribs.cc +++ b/gcc/attribs.cc @@ -1458,6 +1458,10 @@ attribute_value_equal (const_tree attr1, const_tree attr2) && TREE_VALUE (attr2) != NULL_TREE && TREE_CODE (TREE_VALUE (attr2)) == TREE_LIST) { + if (ATTR_UNIQUE_VALUE_P (TREE_VALUE (attr1)) + || ATTR_UNIQUE_VALUE_P (TREE_VALUE (attr2))) + return false; + /* Handle attribute format. */ if (is_attribute_p ("format", get_attribute_name (attr1))) { @@ -1739,11 +1743,34 @@ merge_attributes (tree a1, tree a2) attributes = a2; else { - /* Pick the longest list, and hang on the other list. */ + /* Pick the longest list, and hang on the other list, + unless both lists contain ATTR_UNIQUE_VALUE_P values. + In that case a1 list needs to go after the a2 list + because attributes from a single declaration are stored + in reverse order of their declarations. */ + bool a1_unique_value_p = false, a2_unique_value_p = false; + tree aa1 = a1, aa2 = a2; + for (; aa1 && aa2; aa1 = TREE_CHAIN (aa1), aa2 = TREE_CHAIN (aa2)) + { + if (!a1_unique_value_p + && TREE_VALUE (aa1) + && TREE_CODE (TREE_VALUE (aa1)) == TREE_LIST + && ATTR_UNIQUE_VALUE_P (TREE_VALUE (aa1))) + a1_unique_value_p = true; + if (!a2_unique_value_p + && TREE_VALUE (aa2) + && TREE_CODE (TREE_VALUE (aa2)) == TREE_LIST + && ATTR_UNIQUE_VALUE_P (TREE_VALUE (aa2))) + a2_unique_value_p = true; + } - if (list_length (a1) < list_length (a2)) - attributes = a2, a2 = a1; + if (aa2 && (!a1_unique_value_p || !a2_unique_value_p)) + { + attributes = a2; + a2 = a1; + } + tree a3 = NULL_TREE, *pa = &a3; for (; a2 != 0; a2 = TREE_CHAIN (a2)) { tree a; @@ -1756,10 +1783,15 @@ merge_attributes (tree a1, tree a2) if (a == NULL_TREE) { a1 = copy_node (a2); - TREE_CHAIN (a1) = attributes; - attributes = a1; + *pa = a1; + pa = &TREE_CHAIN (a1); } } + if (a3) + { + *pa = attributes; + attributes = a3; + } } } return attributes; diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc index 3b105df67d08..10d9a51418ef 100644 --- a/gcc/c-family/c-attribs.cc +++ b/gcc/c-family/c-attribs.cc @@ -715,14 +715,20 @@ attribute_takes_identifier_p (const_tree attr_id) { const struct attribute_spec *spec = lookup_attribute_spec (attr_id); if (spec == NULL) - /* Unknown attribute that we'll end up ignoring, return true so we - don't complain about an identifier argument. */ - return true; + { + /* Unknown attribute that we'll end up ignoring, return true so we + don't complain about an identifier argument. Except C++ + annotations. */ + if (c_dialect_cxx () && id_equal (attr_id, "annotation ")) + return false; + return true; + } else if (!strcmp ("mode", spec->name) || !strcmp ("format", spec->name) || !strcmp ("cleanup", spec->name) || !strcmp ("access", spec->name) - || !strcmp ("counted_by", spec->name)) + || !strcmp ("counted_by", spec->name) + || !strcmp ("old parm name", spec->name)) return true; else return targetm.attribute_takes_identifier_p (attr_id); diff --git a/gcc/c-family/c-cppbuiltin.cc b/gcc/c-family/c-cppbuiltin.cc index 68fdf3d9c2da..da7bb98c9da7 100644 --- a/gcc/c-family/c-cppbuiltin.cc +++ b/gcc/c-family/c-cppbuiltin.cc @@ -1116,6 +1116,10 @@ c_cpp_builtins (cpp_reader *pfile) cpp_define (pfile, "__cpp_pp_embed=202502L"); cpp_define (pfile, "__cpp_constexpr_virtual_inheritance=202506L"); cpp_define (pfile, "__cpp_expansion_statements=202506L"); + if (flag_reflection) + cpp_define (pfile, "__cpp_impl_reflection=202506L"); + else + cpp_warn (pfile, "__cpp_impl_reflection"); } if (flag_concepts && cxx_dialect > cxx14) cpp_define (pfile, "__cpp_concepts=202002L"); diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt index 797eb46b1273..e286c3b0535b 100644 --- a/gcc/c-family/c.opt +++ b/gcc/c-family/c.opt @@ -2329,6 +2329,10 @@ frange-for-ext-temps C++ ObjC++ Var(flag_range_for_ext_temps) Enable lifetime extension of range based for temporaries. +freflection +C++ ObjC++ Var(flag_reflection) Init(0) +Enable experimental C++26 Reflection. + freplace-objc-classes ObjC ObjC++ LTO Var(flag_replace_objc_classes) Used in Fix-and-Continue mode to indicate that object files may be swapped in at runtime. diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in index b0ed541f9446..7f476531d84d 100644 --- a/gcc/cp/Make-lang.in +++ b/gcc/cp/Make-lang.in @@ -107,7 +107,7 @@ CXX_AND_OBJCXX_OBJS = \ cp/method.o cp/module.o \ cp/name-lookup.o cp/optimize.o \ cp/parser.o cp/pt.o cp/ptree.o \ - cp/rtti.o \ + cp/reflect.o cp/rtti.o \ cp/search.o cp/semantics.o \ cp/tree.o cp/typeck.o cp/typeck2.o \ cp/vtable-class-hierarchy.o $(CXX_C_OBJS) @@ -188,6 +188,24 @@ endif # This is the file that depends on the generated header file. cp/name-lookup.o: $(srcdir)/cp/std-name-hint.h +ifeq ($(ENABLE_MAINTAINER_RULES), true) +# Special build rule. This is a maintainer rule, that is only +# available when GCC is configured with --enable-maintainer-mode. In +# other cases, it is not available to avoid triggering rebuilds if a +# user has the source checked out with unusual timestamps. +$(srcdir)/cp/metafns.h: $(srcdir)/cp/metafns.gperf +else +# We keep the rule so that you can still force a rebuild, even if you +# didn't configure GCC with --enable-maintainer-mode, by manually +# deleting the $(srcdir)/cp/metafns.h file. +$(srcdir)/cp/metafns.h: +endif + cd $(srcdir)/cp; gperf -o -C -E -k '1,4,5,11,14,$$' -D -N find -L C++ \ + metafns.gperf --output-file metafns.h + +# This is the file that depends on the generated header file. +cp/reflect.o: $(srcdir)/cp/metafns.h + components_in_prev = "bfd opcodes binutils fixincludes gas gcc gmp mpfr mpc isl gold intl ld libbacktrace libcpp libcody libdecnumber libiberty libiberty-linker-plugin libiconv zlib lto-plugin libctf libsframe" components_in_prev_target = "libstdc++-v3 libsanitizer libvtv libgcc libbacktrace libphobos zlib libgomp libatomic" diff --git a/gcc/cp/config-lang.in b/gcc/cp/config-lang.in index 8ff475a09d96..845430f35a4a 100644 --- a/gcc/cp/config-lang.in +++ b/gcc/cp/config-lang.in @@ -51,7 +51,7 @@ gtfiles="\ \$(srcdir)/cp/mangle.cc \$(srcdir)/cp/method.cc \$(srcdir)/cp/module.cc \ \$(srcdir)/cp/name-lookup.cc \ \$(srcdir)/cp/parser.cc \$(srcdir)/cp/pt.cc \ -\$(srcdir)/cp/rtti.cc \ +\$(srcdir)/cp/reflect.cc \$(srcdir)/cp/rtti.cc \ \$(srcdir)/cp/semantics.cc \ \$(srcdir)/cp/tree.cc \$(srcdir)/cp/typeck2.cc \ \$(srcdir)/cp/vtable-class-hierarchy.cc \ diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc index 54a50c4b6b04..0873226bc061 100644 --- a/gcc/cp/constexpr.cc +++ b/gcc/cp/constexpr.cc @@ -1200,15 +1200,29 @@ public: /* If non-null, only allow modification of existing values of the variables in this set. Set by modifiable_tracker, below. */ hash_set *modifiable; + /* If cxx_eval_outermost_constant_expr is called on the consteval block + operator (), this is the FUNCTION_DECL of that operator (). */ + tree consteval_block; /* Number of heap VAR_DECL deallocations. */ unsigned heap_dealloc_count; /* Number of uncaught exceptions. */ unsigned uncaught_exceptions; + /* Some metafunctions aren't dependent just on their arguments, but also + on various other dependencies, e.g. has_identifier on a function parameter + reflection can change depending on further declarations of corresponding + function, is_complete_type depends on type definitions and template + specializations in between the calls, define_aggregate even defines + class types, etc. Thus, we need to arrange for calls which call + at least some metafunctions to be non-cacheable, because their behavior + might not be the same. Until we figure out which exact metafunctions + need this and which don't, do it for all of them. */ + bool metafns_called; /* Constructor. */ constexpr_global_ctx () : constexpr_ops_count (0), cleanups (NULL), modifiable (nullptr), - heap_dealloc_count (0), uncaught_exceptions (0) {} + consteval_block (NULL_TREE), heap_dealloc_count (0), + uncaught_exceptions (0), metafns_called (false) {} bool is_outside_lifetime (tree t) { @@ -1322,6 +1336,42 @@ struct constexpr_ctx { mce_value manifestly_const_eval; }; +/* Return ctx->quiet. For use in reflect.cc. */ + +bool +cxx_constexpr_quiet_p (const constexpr_ctx *ctx) +{ + return ctx->quiet; +} + +/* Return ctx->manifestly_const_eval. For use in reflect.cc. */ + +mce_value +cxx_constexpr_manifestly_const_eval (const constexpr_ctx *ctx) +{ + return ctx->manifestly_const_eval; +} + +/* Return ctx->call->fundef->decl or NULL_TREE. For use in + reflect.cc. */ + +tree +cxx_constexpr_caller (const constexpr_ctx *ctx) +{ + if (ctx->call) + return ctx->call->fundef->decl; + else + return NULL_TREE; +} + +/* Return ctx->global->consteval_block. For use in reflect.cc. */ + +tree +cxx_constexpr_consteval_block (const constexpr_ctx *ctx) +{ + return ctx->global->consteval_block; +} + /* Predicates for the meaning of *jump_target. */ static bool @@ -1589,17 +1639,6 @@ save_fundef_copy (tree fun, tree copy) *slot = copy; } -/* Whether our evaluation wants a prvalue (e.g. CONSTRUCTOR or _CST), - a glvalue (e.g. VAR_DECL or _REF), or nothing. */ - -enum value_cat { - vc_prvalue = 0, - vc_glvalue = 1, - vc_discard = 2 -}; - -static tree cxx_eval_constant_expression (const constexpr_ctx *, tree, - value_cat, bool *, bool *, tree *); static tree cxx_eval_bare_aggregate (const constexpr_ctx *, tree, value_cat, bool *, bool *, tree *); static tree cxx_fold_indirect_ref (const constexpr_ctx *, location_t, tree, tree, @@ -2034,6 +2073,10 @@ cxx_eval_cxa_builtin_fn (const constexpr_ctx *ctx, tree call, { if (type_build_dtor_call (TREE_TYPE (arg))) { + /* So that we don't complain about out-of-consteval use. */ + temp_override ovr (current_function_decl); + if (ctx->call && ctx->call->fundef) + current_function_decl = ctx->call->fundef->decl; tree cleanup = cxx_maybe_build_cleanup (arg, (ctx->quiet ? tf_none : tf_warning_or_error)); @@ -2457,6 +2500,22 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun, } new_call = fold_builtin_is_corresponding_member (loc, nargs, args); } + else if (fndecl_built_in_p (fun, CP_BUILT_IN_IS_STRING_LITERAL, + BUILT_IN_FRONTEND)) + { + location_t loc = EXPR_LOCATION (t); + if (nargs >= 1) + { + tree arg = CALL_EXPR_ARG (t, 0); + arg = cxx_eval_constant_expression (ctx, arg, vc_prvalue, + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; + args[0] = arg; + } + new_call = fold_builtin_is_string_literal (loc, nargs, args); + } else new_call = fold_builtin_call_array (EXPR_LOCATION (t), TREE_TYPE (t), CALL_EXPR_FN (t), nargs, args); @@ -3184,12 +3243,14 @@ is_std_class (tree ctx, const char *name) bool is_std_allocator (tree ctx) { - return is_std_class (ctx, "allocator"); + return (is_std_class (ctx, "allocator") + || (flag_reflection + && is_std_class (ctx, "__new_allocator"))); } /* Return true if FNDECL is std::allocator::{,de}allocate. */ -static inline bool +bool is_std_allocator_allocate (tree fndecl) { tree name = DECL_NAME (fndecl); @@ -3670,6 +3731,43 @@ cxx_set_object_constness (const constexpr_ctx *ctx, tree object, } } +/* Allocate an exception for OBJECT and throw it. */ + +tree +cxa_allocate_and_throw_exception (location_t loc, const constexpr_ctx *ctx, + tree object) +{ + tree type = TREE_TYPE (object); + /* This simulates a call to __cxa_allocate_exception. We need + (struct exception *) &heap -- memory on the heap so that + it can survive the stack being unwound. */ + tree arr = build_array_of_n_type (type, 1); + tree var = cxa_allocate_exception (loc, ctx, arr, size_zero_node); + DECL_NAME (var) = heap_identifier; + ctx->global->put_value (var, NULL_TREE); + + /* *(struct exception *) &heap = exc{ ... } */ + tree ptr = build_nop (build_pointer_type (type), build_address (var)); + object = cp_build_init_expr (cp_build_fold_indirect_ref (ptr), object); + bool non_constant_p = false, overflow_p = false; + tree jump_target = NULL_TREE; + cxx_eval_constant_expression (ctx, object, vc_prvalue, &non_constant_p, + &overflow_p, &jump_target); + if (non_constant_p) + { + if (!ctx->quiet) + error_at (loc, "couldn%'t throw %qT", type); + return NULL_TREE; + } + + /* Now we can __cxa_throw. */ + DECL_EXCEPTION_REFCOUNT (var) + = size_binop (PLUS_EXPR, DECL_EXCEPTION_REFCOUNT (var), size_one_node); + ++ctx->global->uncaught_exceptions; + + return var; +} + /* Subroutine of cxx_eval_constant_expression. Evaluate the call expression tree T in the context of OLD_CALL expression evaluation. */ @@ -3752,6 +3850,35 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, if (DECL_THUNK_P (fun)) return cxx_eval_thunk_call (ctx, t, fun, lval, non_constant_p, overflow_p, jump_target); + if (metafunction_p (fun)) + { + /* To be able to evaluate a metafunction, we may have to instantiate + constexpr functions. If we're not allowed to instantiate, leave + this for later. Don't evaluate metafunctions at all when mce_unknown, + otherwise we might fold those prematurely. See + g++.dg/reflect/p2996-17.C. */ + if (uid_sensitive_constexpr_evaluation_p () + || ctx->manifestly_const_eval == mce_unknown) + { + *non_constant_p = true; + return t; + } + ctx->global->metafns_called = true; + tree e = process_metafunction (ctx, fun, t, non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; + if (*non_constant_p) + return t; + e = cxx_eval_constant_expression (ctx, e, vc_prvalue, + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; + if (*non_constant_p) + return t; + return e; + } bool non_constexpr_call = false; if (!maybe_constexpr_fn (fun)) { @@ -4201,6 +4328,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, call_ctx.call = &new_call; unsigned save_heap_alloc_count = ctx->global->heap_vars.length (); unsigned save_heap_dealloc_count = ctx->global->heap_dealloc_count; + bool save_metafns_called = ctx->global->metafns_called; /* Make sure we fold std::is_constant_evaluated to true in an immediate function. */ @@ -4232,6 +4360,8 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, return NULL_TREE; } + ctx->global->metafns_called = false; + tree jmp_target = NULL_TREE; cxx_eval_constant_expression (&call_ctx, body, vc_discard, non_constant_p, overflow_p, @@ -4265,6 +4395,10 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, } } + if (ctx->global->metafns_called) + cacheable = false; + ctx->global->metafns_called |= save_metafns_called; + /* At this point, the object's constructor will have run, so the object is no longer under construction, and its possible 'const' semantics now apply. Make a note of this fact by @@ -4405,6 +4539,7 @@ reduced_constant_expression_p (tree t, tree sz /* = NULL_TREE */) switch (TREE_CODE (t)) { case PTRMEM_CST: + case REFLECT_EXPR: /* Even if we can't lower this yet, it's constant. */ return true; @@ -4879,6 +5014,11 @@ cxx_eval_binary_expression (const constexpr_ctx *ctx, tree t, lhs = cplus_expand_constant (lhs); else if (TREE_CODE (rhs) == PTRMEM_CST) rhs = cplus_expand_constant (rhs); + else if (REFLECT_EXPR_P (lhs) && REFLECT_EXPR_P (rhs)) + { + const bool eq = compare_reflections (lhs, rhs); + r = constant_boolean_node (eq == is_code_eq, type); + } } if (r == NULL_TREE && TREE_CODE_CLASS (code) == tcc_comparison @@ -8818,7 +8958,7 @@ merge_jump_target (location_t loc, const constexpr_ctx *ctx, tree r, /* FIXME unify with c_fully_fold */ /* FIXME overflow_p is too global */ -static tree +tree cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, value_cat lval, bool *non_constant_p, bool *overflow_p, @@ -9011,6 +9151,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, case CASE_LABEL_EXPR: case PREDICT_EXPR: case OMP_DECLARE_MAPPER: + case REFLECT_EXPR: return t; case PARM_DECL: @@ -9981,6 +10122,14 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, = build_pointer_type (TREE_TYPE (var)); } + /* This can happen for std::meta::info(^^int) where the cast has no + meaning. */ + if (REFLECTION_TYPE_P (type) && REFLECT_EXPR_P (op)) + { + r = op; + break; + } + if (op == oldop && tcode != UNARY_PLUS_EXPR) /* We didn't fold at the top so we could check for ptr-int conversion. */ @@ -10376,7 +10525,7 @@ find_heap_var_refs (tree *tp, int *walk_subtrees, void */*data*/) /* Find immediate function decls in *TP if any. */ static tree -find_immediate_fndecl (tree *tp, int */*walk_subtrees*/, void */*data*/) +find_immediate_fndecl (tree *tp, int *walk_subtrees, void */*data*/) { if (TREE_CODE (*tp) == FUNCTION_DECL && DECL_IMMEDIATE_FUNCTION_P (*tp)) return *tp; @@ -10384,6 +10533,8 @@ find_immediate_fndecl (tree *tp, int */*walk_subtrees*/, void */*data*/) && TREE_CODE (PTRMEM_CST_MEMBER (*tp)) == FUNCTION_DECL && DECL_IMMEDIATE_FUNCTION_P (PTRMEM_CST_MEMBER (*tp))) return PTRMEM_CST_MEMBER (*tp); + if (REFLECT_EXPR_P (*tp)) + *walk_subtrees = 0; return NULL_TREE; } @@ -10468,6 +10619,12 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant, return t; else is_consteval = true; + tree lam; + if (manifestly_const_eval == mce_true + && LAMBDA_FUNCTION_P (fndecl) + && (lam = CLASSTYPE_LAMBDA_EXPR (CP_DECL_CONTEXT (fndecl))) + && LAMBDA_EXPR_CONSTEVAL_BLOCK_P (lam)) + global_ctx.consteval_block = fndecl; } } else if (cxx_dialect >= cxx20 @@ -10684,6 +10841,37 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant, non_constant_p = true; } + /* Detect consteval-only smuggling: turning a consteval-only object + into one that is not. For instance, in + struct B { }; + struct D : B { info r; }; + constexpr D d{^^::}; + constexpr const B &b = d; // #1 + #1 is wrong because D is a consteval-only type but B is not. */ + if (flag_reflection + && !non_constant_p + && object + && POINTER_TYPE_P (TREE_TYPE (object)) + && !consteval_only_p (object) + && check_out_of_consteval_use (r, /*complain=*/false)) + { + if (!allow_non_constant) + { + if (TYPE_REF_P (TREE_TYPE (object))) + error_at (cp_expr_loc_or_input_loc (t), + "reference into an object of consteval-only type is " + "not a constant expression unless it also has " + "consteval-only type"); + else + error_at (cp_expr_loc_or_input_loc (t), + "pointer into an object of consteval-only type is " + "not a constant expression unless it also has " + "consteval-only type"); + } + r = t; + non_constant_p = true; + } + if (!non_constant_p && !constexpr_dtor) verify_constant (r, allow_non_constant, &non_constant_p, &overflow_p); @@ -11476,6 +11664,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, case REQUIRES_EXPR: case STATIC_ASSERT: case DEBUG_BEGIN_STMT: + case REFLECT_EXPR: return true; case RETURN_EXPR: @@ -12567,6 +12756,11 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, case TU_LOCAL_ENTITY: return false; + /* A splice expression is dependent, but will be constant after + substitution. */ + case SPLICE_EXPR: + return true; + case NONTYPE_ARGUMENT_PACK: { tree args = ARGUMENT_PACK_ARGS (t); diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index b70ecf99a30a..0b91e8785631 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -3316,6 +3316,9 @@ diagnose_trait_expr (location_t loc, tree expr, tree args) case CPTK_IS_VOLATILE: inform (loc, "%qT is not a volatile type", t1); break; + case CPTK_IS_CONSTEVAL_ONLY: + inform (decl_loc, "%qT is not consteval-only", t1); + break; case CPTK_RANK: inform (loc, "%qT cannot yield a rank", t1); break; diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc index df86c3903324..3c0f415fa87c 100644 --- a/gcc/cp/cp-gimplify.cc +++ b/gcc/cp/cp-gimplify.cc @@ -486,7 +486,7 @@ lvalue_has_side_effects (tree e) /* Return true if FN is an immediate-escalating function. */ -static bool +bool immediate_escalating_function_p (tree fn) { if (!fn || !flag_immediate_escalation) @@ -524,7 +524,7 @@ unchecked_immediate_escalating_function_p (tree fn) /* Promote FN to an immediate function, including its clones. */ -static void +void promote_function_to_consteval (tree fn) { SET_DECL_IMMEDIATE_FUNCTION_P (fn); @@ -856,6 +856,13 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) case CALL_EXPR: ret = GS_OK; + /* At this point any function that takes/returns a consteval-only + expression is a problem. */ + for (int i = 0; i < call_expr_nargs (*expr_p); ++i) + if (check_out_of_consteval_use (CALL_EXPR_ARG (*expr_p, i))) + ret = GS_ERROR; + if (consteval_only_p (TREE_TYPE (*expr_p))) + ret = GS_ERROR; if (flag_strong_eval_order == 2 && CALL_EXPR_FN (*expr_p) && !CALL_EXPR_OPERATOR_SYNTAX (*expr_p) @@ -965,6 +972,13 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) "__builtin_eh_ptr_adjust_ref"); *expr_p = void_node; break; + case CP_BUILT_IN_IS_STRING_LITERAL: + *expr_p + = fold_builtin_is_string_literal (EXPR_LOCATION (*expr_p), + call_expr_nargs (*expr_p), + &CALL_EXPR_ARG (*expr_p, + 0)); + break; default: break; } @@ -1293,6 +1307,23 @@ cp_build_init_expr_for_ctor (tree call, tree init) return init; } +/* For every DECL_EXPR check if it declares a consteval-only variable and + if so, overwrite it with a no-op. The point here is not to leak + consteval-only variables into the middle end. */ + +static tree +wipe_consteval_only_r (tree *stmt_p, int *, void *) +{ + if (TREE_CODE (*stmt_p) == DECL_EXPR) + { + tree d = DECL_EXPR_DECL (*stmt_p); + if (VAR_P (d) && consteval_only_p (d)) + /* Wipe the DECL_EXPR so that it doesn't get into gimple. */ + *stmt_p = void_node; + } + return NULL_TREE; +} + /* A walk_tree callback for cp_fold_function and cp_fully_fold_init to handle immediate functions. */ @@ -1320,12 +1351,32 @@ cp_fold_immediate_r (tree *stmt_p, int *walk_subtrees, void *data_) return NULL_TREE; } + /* Most invalid uses of consteval-only types should have been already + detected at this point. And the valid ones won't be needed + anymore. */ + if (flag_reflection + && complain + && (data->flags & ff_genericize) + && TREE_CODE (stmt) == STATEMENT_LIST) + for (tree s : tsi_range (stmt)) + if (check_out_of_consteval_use (s)) + *stmt_p = void_node; + tree decl = NULL_TREE; bool call_p = false; /* We are looking for &fn or fn(). */ switch (code) { + case DECL_EXPR: + /* Clear consteval-only DECL_EXPRs. */ + if (flag_reflection) + { + tree d = DECL_EXPR_DECL (stmt); + if (VAR_P (d) && consteval_only_p (d)) + *stmt_p = void_node; + } + break; case CALL_EXPR: case AGGR_INIT_EXPR: if (tree fn = cp_get_callee (stmt)) @@ -1344,8 +1395,15 @@ cp_fold_immediate_r (tree *stmt_p, int *walk_subtrees, void *data_) if (IF_STMT_CONSTEVAL_P (stmt)) { if (!data->pset.add (stmt)) - cp_walk_tree (&ELSE_CLAUSE (stmt), cp_fold_immediate_r, data_, - NULL); + { + cp_walk_tree (&ELSE_CLAUSE (stmt), cp_fold_immediate_r, data_, + nullptr); + if (flag_reflection) + /* Check & clear consteval-only DECL_EXPRs even here, + because we wouldn't be walking this subtree otherwise. */ + cp_walk_tree (&THEN_CLAUSE (stmt), wipe_consteval_only_r, + data_, nullptr); + } *walk_subtrees = 0; return NULL_TREE; } @@ -1419,6 +1477,22 @@ cp_fold_immediate_r (tree *stmt_p, int *walk_subtrees, void *data_) *walk_subtrees = 0; return stmt; } + /* If we called a consteval function and it evaluated to a consteval-only + expression, it could be a problem if we are outside a manifestly + constant-evaluated context. */ + else if ((data->flags & ff_genericize) + && check_out_of_consteval_use (e, complain)) + { + *stmt_p = void_node; + if (complain & tf_error) + return NULL_TREE; + else + { + *walk_subtrees = 0; + return stmt; + } + } + /* We've evaluated the consteval function call. */ if (call_p) { @@ -2030,6 +2104,20 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data) cp_walk_tree (&DECL_INITIAL (decl), cp_genericize_r, data, NULL); wtd->no_sanitize_p = no_sanitize_p; } + if (flag_reflection) + /* Wipe consteval-only vars from BIND_EXPR_VARS and BLOCK_VARS. */ + for (tree *p = &BIND_EXPR_VARS (stmt); *p; ) + { + if (VAR_P (*p) && consteval_only_p (*p)) + { + if (BIND_EXPR_BLOCK (stmt) + && *p == BLOCK_VARS (BIND_EXPR_BLOCK (stmt))) + BLOCK_VARS (BIND_EXPR_BLOCK (stmt)) = DECL_CHAIN (*p); + *p = DECL_CHAIN (*p); + continue; + } + p = &DECL_CHAIN (*p); + } wtd->bind_expr_stack.safe_push (stmt); cp_walk_tree (&BIND_EXPR_BODY (stmt), cp_genericize_r, data, NULL); diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc index 1bbe43715e65..0f0d4a01eebb 100644 --- a/gcc/cp/cp-objcp-common.cc +++ b/gcc/cp/cp-objcp-common.cc @@ -646,6 +646,8 @@ cp_common_init_ts (void) MARK_TS_TYPE_NON_COMMON (TEMPLATE_TYPE_PARM); MARK_TS_TYPE_NON_COMMON (TYPE_PACK_EXPANSION); MARK_TS_TYPE_NON_COMMON (PACK_INDEX_TYPE); + MARK_TS_TYPE_NON_COMMON (META_TYPE); + MARK_TS_TYPE_NON_COMMON (SPLICE_SCOPE); /* Statements. */ MARK_TS_EXP (CLEANUP_STMT); @@ -696,6 +698,8 @@ cp_common_init_ts (void) MARK_TS_EXP (VEC_INIT_EXPR); MARK_TS_EXP (VEC_NEW_EXPR); MARK_TS_EXP (SPACESHIP_EXPR); + MARK_TS_EXP (SPLICE_EXPR); + MARK_TS_EXP (REFLECT_EXPR); /* Fold expressions. */ MARK_TS_EXP (BINARY_LEFT_FOLD_EXPR); diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def index c7fc40d05445..395cadc5767d 100644 --- a/gcc/cp/cp-trait.def +++ b/gcc/cp/cp-trait.def @@ -69,6 +69,7 @@ DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2) DEFTRAIT_EXPR (IS_BOUNDED_ARRAY, "__is_bounded_array", 1) DEFTRAIT_EXPR (IS_CLASS, "__is_class", 1) DEFTRAIT_EXPR (IS_CONST, "__is_const", 1) +DEFTRAIT_EXPR (IS_CONSTEVAL_ONLY, "__builtin_is_consteval_only", 1) DEFTRAIT_EXPR (IS_CONSTRUCTIBLE, "__is_constructible", -1) DEFTRAIT_EXPR (IS_CONVERTIBLE, "__is_convertible", 2) DEFTRAIT_EXPR (IS_DESTRUCTIBLE, "__is_destructible", 1) diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def index 3e11b4deb7ba..770a681e124d 100644 --- a/gcc/cp/cp-tree.def +++ b/gcc/cp/cp-tree.def @@ -586,6 +586,24 @@ DEFTREECODE (POSTCONDITION_STMT, "postcondition_stmt", tcc_statement, 4) wasn't an exposure (e.g. in a non-inline function template). */ DEFTREECODE (TU_LOCAL_ENTITY, "tu_local_entity", tcc_exceptional, 0) +/* C++26 reflection expression. */ +DEFTREECODE (REFLECT_EXPR, "reflect_expr", tcc_expression, 1) + +/* Represents the std::meta::info type. */ +DEFTREECODE (META_TYPE, "meta_type", tcc_type, 0) + +/* Represents a dependent splice expression. If SPLICE_EXPR_EXPRESSION_P + is set, this tree represents a splice-expression (as opposed to + a splice-specifier). */ +DEFTREECODE (SPLICE_EXPR, "splice_expr", tcc_expression, 1) + +/* Represents a dependent splice scope, or a dependent splice type + (SPLICE_SCOPE_TYPE_P says which one it is). Its operand can be accessed + using SPLICE_SCOPE_EXPR. The operand can be a SPLICE_EXPR or a + TEMPLATE_ID_EXPR; the SPLICE_SCOPE is necessary to denote that this + tree should expand to a type/scope. */ +DEFTREECODE (SPLICE_SCOPE, "splice_scope", tcc_type, 0) + /* Local variables: mode:c diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 7dc498ccae37..d7acfc8b7a33 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -175,6 +175,7 @@ enum cp_tree_index CPTI_FOR_END_IDENTIFIER, CPTI_ABI_TAG_IDENTIFIER, CPTI_ALIGNED_IDENTIFIER, + CPTI_ANNOTATION_IDENTIFIER, CPTI_BEGIN_IDENTIFIER, CPTI_END_IDENTIFIER, CPTI_GET_IDENTIFIER, @@ -211,6 +212,7 @@ enum cp_tree_index /* We must find these via the global namespace. */ CPTI_STD, + CPTI_STD_META, CPTI_ABI, /* These are created at init time, but the library/headers provide @@ -236,6 +238,7 @@ enum cp_tree_index CPTI_DCAST, CPTI_PSEUDO_CONTRACT_VIOLATION, + CPTI_META_INFO_TYPE, CPTI_MAX }; @@ -257,6 +260,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; #define vtbl_type_node cp_global_trees[CPTI_VTBL_TYPE] #define vtbl_ptr_type_node cp_global_trees[CPTI_VTBL_PTR_TYPE] #define std_node cp_global_trees[CPTI_STD] +#define std_meta_node cp_global_trees[CPTI_STD_META] #define abi_node cp_global_trees[CPTI_ABI] #define global_namespace cp_global_trees[CPTI_GLOBAL] #define const_type_info_type_node cp_global_trees[CPTI_CONST_TYPE_INFO_TYPE] @@ -266,6 +270,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; /* std::align_val_t */ #define align_type_node cp_global_trees[CPTI_ALIGN_TYPE] #define pseudo_contract_violation_type cp_global_trees[CPTI_PSEUDO_CONTRACT_VIOLATION] +#define meta_info_type_node cp_global_trees[CPTI_META_INFO_TYPE] /* We cache these tree nodes so as to call get_identifier less frequently. For identifiers for functions, including special member functions such @@ -329,6 +334,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; #define for_end_identifier cp_global_trees[CPTI_FOR_END_IDENTIFIER] #define abi_tag_identifier cp_global_trees[CPTI_ABI_TAG_IDENTIFIER] #define aligned_identifier cp_global_trees[CPTI_ALIGNED_IDENTIFIER] +#define annotation_identifier cp_global_trees[CPTI_ANNOTATION_IDENTIFIER] #define begin_identifier cp_global_trees[CPTI_BEGIN_IDENTIFIER] #define end_identifier cp_global_trees[CPTI_END_IDENTIFIER] #define get__identifier cp_global_trees[CPTI_GET_IDENTIFIER] @@ -454,6 +460,9 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; MUST_NOT_THROW_NOEXCEPT_P (in MUST_NOT_THROW_EXPR) CONSTEVAL_BLOCK_P (in STATIC_ASSERT) LAMBDA_EXPR_CONSTEVAL_BLOCK_P (in LAMBDA_EXPR) + SPLICE_EXPR_EXPRESSION_P (in SPLICE_EXPR) + OLD_PARM_DECL_P (in PARM_DECL) + COMPONENT_REF_SPLICE_P (in COMPONENT_REF) 1: IDENTIFIER_KIND_BIT_1 (in IDENTIFIER_NODE) TI_PENDING_TEMPLATE_FLAG. TEMPLATE_PARMS_FOR_INLINE. @@ -476,6 +485,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; STATIC_INIT_DECOMP_BASE_P (in the TREE_LIST for {static,tls}_aggregates) MUST_NOT_THROW_THROW_P (in MUST_NOT_THROW_EXPR) LAMBDA_EXPR_CONST_QUAL_P (in LAMBDA_EXPR) + SPLICE_EXPR_MEMBER_ACCESS_P (in SPLICE_EXPR) 2: IDENTIFIER_KIND_BIT_2 (in IDENTIFIER_NODE) ICS_THIS_FLAG (in _CONV) DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (in VAR_DECL) @@ -499,6 +509,8 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; STATIC_INIT_DECOMP_NONBASE_P (in the TREE_LIST for {static,tls}_aggregates) MUST_NOT_THROW_CATCH_P (in MUST_NOT_THROW_EXPR) + MULTIPLE_NAMES_PARM_P (in PARM_DECL) + SPLICE_EXPR_ADDRESS_P (in SPLICE_EXPR) 3: IMPLICIT_RVALUE_P (in NON_LVALUE_EXPR or STATIC_CAST_EXPR) ICS_BAD_FLAG (in _CONV) FN_TRY_BLOCK_P (in TRY_BLOCK) @@ -541,6 +553,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; 1: TYPE_HAS_USER_CONSTRUCTOR. 2: TYPE_HAS_LATE_RETURN_TYPE (in FUNCTION_TYPE, METHOD_TYPE) TYPE_PTRMEMFUNC_FLAG (in RECORD_TYPE) + ENUM_BEING_DEFINED_P (in ENUMERAL_TYPE) 4: TYPE_HAS_NONTRIVIAL_DESTRUCTOR 5: CLASS_TYPE_P (in RECORD_TYPE and UNION_TYPE) ENUM_FIXED_UNDERLYING_TYPE_P (in ENUMERAL_TYPE) @@ -1883,6 +1896,98 @@ struct GTY(()) tree_tu_local_entity { #define REQUIRES_EXPR_EXTRA_ARGS(NODE) \ TREE_OPERAND (TREE_CHECK (NODE, REQUIRES_EXPR), 2) +/* True iff TYPE is cv decltype(^^int). */ +#define REFLECTION_TYPE_P(TYPE) (TREE_CODE (TYPE) == META_TYPE) + +/* True if NODE is a REFLECT_EXPR. */ +#define REFLECT_EXPR_P(NODE) (TREE_CODE (NODE) == REFLECT_EXPR) + +/* The handle of a reflection expression. */ +#define REFLECT_EXPR_HANDLE(NODE) \ + TREE_OPERAND (TREE_CHECK (NODE, REFLECT_EXPR), 0) + +/* Various kinds of reflections. Sometimes we cannot simply look at the + handle and figure out the kind from it. For instance, + + consteval void fn(int p) { + constexpr auto rp = parameters_of(^^fn)[0]; + // is_variable(^^p) is true + // is_function_parameter(^^p) is false + // is_variable(rp) is false + // is_function_parameter(rp) is true + } + + but we represent the handle p with a PARM_DECL in all cases. + + The size is limited to addr_space_t because we only have 8 bits. */ + +enum reflect_kind : addr_space_t { + /* Detect the category from the handle. */ + REFLECT_UNDEF, + /* The reflection represents an object. */ + REFLECT_OBJECT, + /* The reflection represents a value. */ + REFLECT_VALUE, + /* The reflection represents a variable. Used for underlying + variable of tuple structured binding. */ + REFLECT_VAR, + /* The reflection represents a function parameter. */ + REFLECT_PARM, + /* The reflection represents a data member description. */ + REFLECT_DATA_MEMBER_SPEC, + /* The reflection represents a direct base relationship. */ + REFLECT_BASE, + /* The reflection represents an annotation. */ + REFLECT_ANNOTATION +}; + +/* The reflect_kind of a REFLECT_EXPR. */ +#define REFLECT_EXPR_KIND(NODE) \ + (static_cast \ + (REFLECT_EXPR_CHECK (NODE)->base.u.bits.address_space)) + +#define SET_REFLECT_EXPR_KIND(NODE, VAL) \ + (REFLECT_EXPR_CHECK (NODE)->base.u.bits.address_space = VAL) + +/* True if this SPLICE_EXPR represents a splice-expression (as opposed to + a splice-specifier), so it cannot expand to e.g. a type. */ +#define SPLICE_EXPR_EXPRESSION_P(NODE) \ + TREE_LANG_FLAG_0 (SPLICE_EXPR_CHECK (NODE)) + +/* Helper macro to set SPLICE_EXPR_EXPRESSION_P. This macro handles + dependent_splice_p trees: either [:T:] or [:T:]. */ +#define SET_SPLICE_EXPR_EXPRESSION_P(NODE) \ + (SPLICE_EXPR_EXPRESSION_P (TREE_CODE (NODE) == SPLICE_EXPR \ + ? NODE : TREE_OPERAND (NODE, 0)) = true) + +/* True if this SPLICE_EXPR is used in foo.[: bar :] or foo->[: bar :] + context. */ +#define SPLICE_EXPR_MEMBER_ACCESS_P(NODE) \ + TREE_LANG_FLAG_1 (SPLICE_EXPR_CHECK (NODE)) + +/* Helper macro to set SPLICE_EXPR_MEMBER_ACCESS_P. */ +#define SET_SPLICE_EXPR_MEMBER_ACCESS_P(NODE, VAL) \ + (SPLICE_EXPR_MEMBER_ACCESS_P (TREE_CODE (NODE) == SPLICE_EXPR \ + ? NODE : TREE_OPERAND (NODE, 0)) = (VAL)) + +/* True if we are taking the address of this SPLICE_EXPR. */ +#define SPLICE_EXPR_ADDRESS_P(NODE) \ + TREE_LANG_FLAG_2 (SPLICE_EXPR_CHECK (NODE)) + +/* Helper macro to set SPLICE_EXPR_ADDRESS_P. */ +#define SET_SPLICE_EXPR_ADDRESS_P(NODE, VAL) \ + (SPLICE_EXPR_ADDRESS_P (TREE_CODE (NODE) == SPLICE_EXPR \ + ? NODE : TREE_OPERAND (NODE, 0)) = (VAL)) + +/* The expression in question for a SPLICE_SCOPE. */ +#define SPLICE_SCOPE_EXPR(NODE) \ + (TYPE_VALUES_RAW (SPLICE_SCOPE_CHECK (NODE))) + +/* True if this splice represents a splice-type-specifier rather than + a splice-scope-specifier. */ +#define SPLICE_SCOPE_TYPE_P(NODE) \ + (SPLICE_SCOPE_CHECK (NODE))->type_common.string_flag + enum cp_tree_node_structure_enum { TS_CP_GENERIC, TS_CP_IDENTIFIER, @@ -2366,6 +2471,7 @@ enum languages { lang_c, lang_cplusplus }; || TREE_CODE (T) == DECLTYPE_TYPE \ || TREE_CODE (T) == TRAIT_TYPE \ || TREE_CODE (T) == DEPENDENT_OPERATOR_TYPE \ + || TREE_CODE (T) == SPLICE_SCOPE \ || TREE_CODE (T) == PACK_INDEX_TYPE) /* Nonzero if T is a class (or struct or union) type. Also nonzero @@ -4378,6 +4484,11 @@ templated_operator_saved_lookups (tree t) #define REF_PARENTHESIZED_P(NODE) \ TREE_LANG_FLAG_2 (TREE_CHECK5 ((NODE), COMPONENT_REF, INDIRECT_REF, SCOPE_REF, VIEW_CONVERT_EXPR, PAREN_EXPR)) +/* True on a dependent COMPONENT_REF with a splice expression. */ + +#define COMPONENT_REF_SPLICE_P(NODE) \ + TREE_LANG_FLAG_0 (COMPONENT_REF_CHECK (NODE)) + /* Nonzero if this AGGR_INIT_EXPR provides for initialization via a constructor call, rather than an ordinary function call. */ #define AGGR_INIT_VIA_CTOR_P(NODE) \ @@ -4755,9 +4866,9 @@ get_vec_init_expr (tree t) /* [basic.types] - Arithmetic types, enumeration types, pointer types, - pointer-to-member types, and std::nullptr_t are collectively called - scalar types. + Arithmetic types, enumeration types, pointer types, pointer-to-member types, + std::meta::info, std::nullptr_t and cv-qualified versions of these types + are collectively called scalar types. Keep these checks in ascending code order. */ #define SCALAR_TYPE_P(TYPE) \ @@ -4766,7 +4877,8 @@ get_vec_init_expr (tree t) || ARITHMETIC_TYPE_P (TYPE) \ || TYPE_PTR_P (TYPE) \ || TYPE_PTRMEMFUNC_P (TYPE) \ - || NULLPTR_TYPE_P (TYPE)) + || NULLPTR_TYPE_P (TYPE) \ + || REFLECTION_TYPE_P (TYPE)) /* Determines whether this type is a C++0x scoped enumeration type. Scoped enumerations types are introduced via "enum class" or @@ -4807,6 +4919,11 @@ get_vec_init_expr (tree t) #define OPAQUE_ENUM_P(TYPE) \ (TREE_CODE (TYPE) == ENUMERAL_TYPE && ENUM_IS_OPAQUE (TYPE)) +/* Nonzero when the ENUMERAL_TYPE is being defined (enumerators parsed + or instantiated). */ +#define ENUM_BEING_DEFINED_P(NODE) \ + (TYPE_LANG_FLAG_2 (ENUMERAL_TYPE_CHECK (NODE))) + /* [dcl.init.aggr] An aggregate is an array or a class with no user-provided @@ -5174,6 +5291,18 @@ get_vec_init_expr (tree t) #define DECL_ARRAY_PARAMETER_P(NODE) \ DECL_LANG_FLAG_1 (PARM_DECL_CHECK (NODE)) +/* Nonzero for PARM_DECL node means it is a parameter of an earlier + declaration which is no longer in DECL_ARGUMENTS (DECL_CONTEXT (NODE)) + chain because a function definition has been parsed later. */ +#define OLD_PARM_DECL_P(NODE) \ + TREE_LANG_FLAG_0 (PARM_DECL_CHECK (NODE)) + +/* Nonzero for PARM_DECL node means it has different names on different + declarations of the same FUNCTION_DECL. If it is unnamed on one and + named on another, that is still fine. */ +#define MULTIPLE_NAMES_PARM_P(NODE) \ + TREE_LANG_FLAG_2 (PARM_DECL_CHECK (NODE)) + /* Nonzero for a FIELD_DECL who's NSMDI is currently being instantiated. */ #define DECL_INSTANTIATING_NSDMI_P(NODE) \ @@ -6035,6 +6164,8 @@ extern bool comparing_override_contracts; /* In parser.cc. */ +extern bool cp_preserve_using_decl; + /* Nonzero if we are parsing an unevaluated operand: an operand to sizeof, typeof, or alignof. This is a count since operands to sizeof can be nested. */ @@ -6532,8 +6663,8 @@ enum ovl_op_flags { enum ovl_op_code { OVL_OP_ERROR_MARK, OVL_OP_NOP_EXPR, -#define DEF_OPERATOR(NAME, CODE, MANGLING, FLAGS) OVL_OP_##CODE, -#define DEF_ASSN_OPERATOR(NAME, CODE, MANGLING) /* NOTHING */ +#define DEF_OPERATOR(NAME, CODE, MANGLING, FLAGS, META) OVL_OP_##CODE, +#define DEF_ASSN_OPERATOR(NAME, CODE, MANGLING, META) /* NOTHING */ #include "operators.def" OVL_OP_MAX }; @@ -6548,6 +6679,9 @@ struct GTY(()) ovl_op_info_t { const char *name; /* The mangled name of the operator. */ const char *mangled_name; + /* The name of the std::meta::operators enumerator without + the "op_" prefix if any (otherwise NULL). */ + const char *meta_name; /* The (regular) tree code. */ enum tree_code tree_code : 16; /* The (compressed) operator code. */ @@ -6939,6 +7073,7 @@ enum cp_built_in_function { CP_BUILT_IN_IS_POINTER_INTERCONVERTIBLE_WITH_CLASS, CP_BUILT_IN_SOURCE_LOCATION, CP_BUILT_IN_EH_PTR_ADJUST_REF, + CP_BUILT_IN_IS_STRING_LITERAL, CP_BUILT_IN_LAST }; @@ -7690,6 +7825,7 @@ extern tree get_copy_ctor (tree, tsubst_flags_t); extern tree get_copy_assign (tree); extern tree get_default_ctor (tree); extern tree get_dtor (tree, tsubst_flags_t); +extern tree build_stub_type (tree, int, bool); extern tree build_stub_object (tree); extern bool is_stub_object (tree); extern tree build_invoke (tree, const_tree, @@ -7850,6 +7986,7 @@ extern void remove_dummy_lambda_op (tree, tree); extern tree canonical_type_parameter (tree); extern void push_access_scope (tree); extern void pop_access_scope (tree); +extern tree current_function_decl_without_access_scope (); extern bool check_template_shadow (tree); extern tree get_innermost_template_args (tree, int); extern void maybe_begin_member_template_processing (tree); @@ -7983,6 +8120,7 @@ extern int processing_template_parmlist; extern bool dependent_type_p (tree); extern bool dependent_scope_p (tree); extern bool dependentish_scope_p (tree); +extern bool dependent_namespace_p (tree); extern bool any_dependent_template_arguments_p (const_tree); extern bool any_erroneous_template_args_p (const_tree); extern bool dependent_template_p (tree); @@ -8065,6 +8203,7 @@ extern tree add_outermost_template_args (tree, tree); extern tree add_extra_args (tree, tree, tsubst_flags_t, tree); extern tree build_extra_args (tree, tree, tsubst_flags_t); extern void finish_expansion_stmt (tree, tree, tsubst_flags_t, tree); +extern tree convert_reflect_constant_arg (tree, tree); /* in rtti.cc */ /* A vector of all tinfo decls that haven't been emitted yet. */ @@ -8263,9 +8402,10 @@ extern tree finish_template_template_parm (tree, tree); extern tree begin_class_definition (tree); extern void finish_template_decl (tree); extern tree finish_template_type (tree, tree, int); -extern tree finish_base_specifier (tree, tree, bool); +extern tree finish_base_specifier (tree, tree, bool, tree); extern void finish_member_declaration (tree); extern bool outer_automatic_var_p (tree); +extern bool parsing_lambda_declarator (); extern tree process_outer_var_ref (tree, tsubst_flags_t, bool force_use = false); extern cp_expr finish_id_expression (tree, tree, tree, cp_id_kind *, @@ -8346,6 +8486,7 @@ extern tree finish_decltype_type (tree, bool, tsubst_flags_t); extern tree fold_builtin_is_corresponding_member (location_t, int, tree *); extern bool pointer_interconvertible_base_of_p (tree, tree, bool = false); extern tree fold_builtin_is_pointer_inverconvertible_with_class (location_t, int, tree *); +extern tree fold_builtin_is_string_literal (location_t, int, tree *); extern tree finish_structured_binding_size (location_t, tree, tsubst_flags_t); extern tree finish_trait_expr (location_t, enum cp_trait_kind, tree, tree); extern tree finish_trait_type (enum cp_trait_kind, tree, tree, tsubst_flags_t); @@ -8560,6 +8701,7 @@ extern tree cxx_copy_lang_qualifiers (const_tree, const_tree); extern void cxx_print_statistics (void); extern bool maybe_warn_zero_as_null_pointer_constant (tree, location_t); +extern bool annotation_p (tree) ATTRIBUTE_PURE; /* in ptree.cc */ extern void cxx_print_xnode (FILE *, tree, int); @@ -8613,7 +8755,7 @@ extern tree decay_conversion (tree, extern tree build_class_member_access_expr (cp_expr, tree, tree, bool, tsubst_flags_t); extern tree finish_class_member_access_expr (cp_expr, tree, bool, - tsubst_flags_t); + tsubst_flags_t, bool = false); extern tree lookup_destructor (tree, tree, tree, tsubst_flags_t); extern tree build_dependent_operator_type (tree, enum tree_code, bool); extern tree build_x_indirect_ref (location_t, tree, @@ -8924,6 +9066,8 @@ extern tree process_stmt_assume_attribute (tree, tree, location_t); extern bool simple_empty_class_p (tree, tree, tree_code); extern tree fold_builtin_source_location (const_tree); extern tree get_source_location_impl_type (); +extern bool immediate_escalating_function_p (tree); +extern void promote_function_to_consteval (tree); extern tree cp_fold_immediate (tree *, mce_value, tree = current_function_decl); extern void process_and_check_pending_immediate_escalating_fns (); @@ -9080,6 +9224,7 @@ extern bool is_nondependent_static_init_expression (tree); extern bool is_static_init_expression (tree); extern bool is_std_class (tree, const char *); extern bool is_std_allocator (tree); +extern bool is_std_allocator_allocate (tree); extern bool potential_rvalue_constant_expression (tree); extern bool require_potential_constant_expression (tree); extern bool require_constant_expression (tree); @@ -9121,6 +9266,24 @@ extern tree find_failing_clause (const constexpr_ctx *ctx, tree); extern void diagnose_failing_condition (tree, location_t, bool, const constexpr_ctx * = nullptr); extern bool replace_decl (tree *, tree, tree); +extern tree cxa_allocate_and_throw_exception (location_t, const constexpr_ctx *, + tree); + +/* Whether our evaluation wants a prvalue (e.g. CONSTRUCTOR or _CST), + a glvalue (e.g. VAR_DECL or _REF), or nothing. */ +enum value_cat { + vc_prvalue = 0, + vc_glvalue = 1, + vc_discard = 2 +}; + +extern tree cxx_eval_constant_expression (const constexpr_ctx *, tree, + value_cat, bool *, bool *, + tree *); +extern bool cxx_constexpr_quiet_p (const constexpr_ctx *); +extern mce_value cxx_constexpr_manifestly_const_eval (const constexpr_ctx *); +extern tree cxx_constexpr_caller (const constexpr_ctx *); +extern tree cxx_constexpr_consteval_block (const constexpr_ctx *); /* An RAII sentinel used to restrict constexpr evaluation so that it doesn't do anything that causes extra DECL_UID generation. */ @@ -9168,6 +9331,27 @@ extern tree co_await_get_resume_call (tree await_expr); extern void coro_set_transform_functions (tree, tree, tree); extern void coro_set_ramp_function (tree, tree); +/* In reflect.cc */ +extern void init_reflection (); +extern bool metafunction_p (tree) ATTRIBUTE_PURE; +extern tree direct_base_parent (tree) ATTRIBUTE_PURE; +extern tree process_metafunction (const constexpr_ctx *, tree, tree, + bool *, bool *, tree *); +extern tree get_reflection (location_t, tree, reflect_kind = REFLECT_UNDEF); +extern tree get_null_reflection () ATTRIBUTE_PURE; +extern tree splice (tree); +extern bool check_out_of_consteval_use (tree, bool = true); +extern bool consteval_only_p (tree) ATTRIBUTE_PURE; +extern bool compare_reflections (tree, tree) ATTRIBUTE_PURE; +extern bool valid_splice_type_p (const_tree) ATTRIBUTE_PURE; +extern bool valid_splice_scope_p (const_tree) ATTRIBUTE_PURE; +extern bool check_splice_expr (location_t, location_t, tree, bool, bool, bool) + ATTRIBUTE_PURE; +extern tree make_splice_scope (tree, bool); +extern bool dependent_splice_p (const_tree) ATTRIBUTE_PURE; +extern tree reflection_mangle_prefix (tree, char [3]); +extern void check_consteval_only_fn (tree); + /* Inline bodies. */ inline tree diff --git a/gcc/cp/cvt.cc b/gcc/cp/cvt.cc index 771f72106cd2..a984611ea8e2 100644 --- a/gcc/cp/cvt.cc +++ b/gcc/cp/cvt.cc @@ -1212,6 +1212,12 @@ convert_to_void (tree expr, impl_conv_void implicit, tsubst_flags_t complain) if (concept_check_p (expr)) expr = evaluate_concept_check (expr); + /* Detect using expressions of consteval-only types outside manifestly + constant-evaluated contexts. We are going to discard this expression, + so we can't wait till cp_fold_immediate_r. */ + if (check_out_of_consteval_use (expr)) + return error_mark_node; + if (VOID_TYPE_P (TREE_TYPE (expr))) return expr; diff --git a/gcc/cp/cxx-pretty-print.cc b/gcc/cp/cxx-pretty-print.cc index 3bb1097445ba..db13a83ff902 100644 --- a/gcc/cp/cxx-pretty-print.cc +++ b/gcc/cp/cxx-pretty-print.cc @@ -813,6 +813,7 @@ pp_cxx_delete_expression (cxx_pretty_printer *pp, tree t) sizeof ... ( identifier ) new-expression delete-expression + reflect-expression unary-operator: one of * & + - ! @@ -898,6 +899,19 @@ cxx_pretty_printer::unary_expression (tree t) pp_cxx_cast_expression (this, TREE_OPERAND (t, 0)); break; + case REFLECT_EXPR: + { + pp_cxx_ws_string (this, "^^"); + tree h = REFLECT_EXPR_HANDLE (t); + if (DECL_P (h)) + declaration (h); + else if (TYPE_P (h)) + type_id (h); + else + expression (h); + } + break; + default: c_pretty_printer::unary_expression (t); break; @@ -1184,6 +1198,7 @@ cxx_pretty_printer::expression (tree t) case ALIGNOF_EXPR: case NOEXCEPT_EXPR: case UNARY_PLUS_EXPR: + case REFLECT_EXPR: unary_expression (t); break; @@ -1427,6 +1442,10 @@ cxx_pretty_printer::simple_type_specifier (tree t) pp_cxx_trait (this, t); break; + case META_TYPE: + pp_cxx_ws_string (this, "std::meta::info"); + break; + default: c_pretty_printer::simple_type_specifier (t); break; @@ -1923,6 +1942,7 @@ cxx_pretty_printer::type_id (tree t) case NULLPTR_TYPE: case TEMPLATE_ID_EXPR: case OFFSET_TYPE: + case META_TYPE: pp_cxx_type_specifier_seq (this, t); if (TYPE_PTRMEM_P (t)) abstract_declarator (t); diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index 46a17a596edc..f1ba57cd177e 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -134,6 +134,7 @@ static bool identify_goto (tree, location_t, const location_t *, Namespaces, tree std_node; + tree std_meta_node; tree abi_node; A FUNCTION_DECL which can call `abort'. Not necessarily the @@ -3043,9 +3044,10 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden) /* Merge parameter attributes. */ tree oldarg, newarg; - for (oldarg = DECL_ARGUMENTS(olddecl), newarg = DECL_ARGUMENTS(newdecl); - oldarg && newarg; - oldarg = DECL_CHAIN(oldarg), newarg = DECL_CHAIN(newarg)) + for (oldarg = DECL_ARGUMENTS (olddecl), + newarg = DECL_ARGUMENTS (newdecl); + oldarg && newarg; + oldarg = DECL_CHAIN (oldarg), newarg = DECL_CHAIN (newarg)) { DECL_ATTRIBUTES (newarg) = (*targetm.merge_decl_attributes) (oldarg, newarg); @@ -3063,6 +3065,62 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden) "earlier declaration"); } DECL_ATTRIBUTES (oldarg) = DECL_ATTRIBUTES (newarg); + /* Merge names for std::meta::has_identifier and + std::meta::{,u8}identifier_of purposes. If they are different + and both oldarg and newarg are named, add flag to force that + std::meta::has_identifier returns false. If one is named and + one is unnamed, if neither is a olddecl nor newdecl is definition, + propagate DECL_NAME to both. Otherwise stash the old name into + "old parm name" artificial attribute. */ + if (flag_reflection && DECL_NAME (oldarg) != DECL_NAME (newarg)) + { + if (DECL_NAME (oldarg) && DECL_NAME (newarg)) + { + /* Different names. */ + MULTIPLE_NAMES_PARM_P (oldarg) = 1; + MULTIPLE_NAMES_PARM_P (newarg) = 1; + } + else if (!new_defines_function + && types_match + && DECL_INITIAL (olddecl) == NULL_TREE) + { + /* For 2 non-definitions with matching types, + one is named and one unnamed, propagate name + to both. */ + if (DECL_NAME (oldarg)) + DECL_NAME (newarg) = DECL_NAME (oldarg); + else + DECL_NAME (oldarg) = DECL_NAME (newarg); + } + /* Depending on which PARM_DECL we'll keep, look at the other + PARM_DECL's name. */ + else if (tree name = ((new_defines_function || !types_match) + ? DECL_NAME (oldarg) : DECL_NAME (newarg))) + { + tree opn = lookup_attribute ("old parm name", + DECL_ATTRIBUTES (oldarg)); + if (opn) + { + if (TREE_VALUE (TREE_VALUE (opn)) == name) + /* Name already in "old parm name" attribute. */; + else + { + /* Different names. */ + MULTIPLE_NAMES_PARM_P (oldarg) = 1; + MULTIPLE_NAMES_PARM_P (newarg) = 1; + } + } + else + { + /* Save name into attribute. */ + DECL_ATTRIBUTES (newarg) + = tree_cons (get_identifier ("old parm name"), + tree_cons (NULL_TREE, name, NULL_TREE), + DECL_ATTRIBUTES (newarg)); + DECL_ATTRIBUTES (oldarg) = DECL_ATTRIBUTES (newarg); + } + } + } } if (DECL_TEMPLATE_INSTANTIATION (olddecl) @@ -3160,6 +3218,15 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden) if (tree contracts = DECL_CONTRACTS (newdecl)) remap_contracts (olddecl, newdecl, contracts, true); + /* Mark the old PARM_DECLs in case std::meta::parameters_of has + been called on the old declaration and reflections of those + arguments are held across this point and used later. + Such PARM_DECLs are no longer present in + DECL_ARGUMENTS (DECL_CONTEXT (oldarg)) chain. */ + for (tree oldarg = DECL_ARGUMENTS (olddecl); + oldarg; oldarg = DECL_CHAIN (oldarg)) + OLD_PARM_DECL_P (oldarg) = 1; + /* These need to be copied so that the names are available. Note that if the types do match, we'll preserve inline info and other bits, but if not, we won't. */ @@ -5330,6 +5397,7 @@ initialize_predefined_identifiers (void) {"heap []", &heap_vec_identifier, cik_normal}, {"omp", &omp_identifier, cik_normal}, {"internal ", &internal_identifier, cik_normal}, + {"annotation ", &annotation_identifier, cik_normal}, {NULL, NULL, cik_normal} }; @@ -5563,6 +5631,13 @@ cxx_init_decl_processing (void) set_call_expr_flags (decl, ECF_NOTHROW | ECF_LEAF); } + decl + = add_builtin_function ("__builtin_is_string_literal", + bool_vaftype, + CP_BUILT_IN_IS_STRING_LITERAL, + BUILT_IN_FRONTEND, NULL, NULL_TREE); + set_call_expr_flags (decl, ECF_CONST | ECF_NOTHROW | ECF_LEAF); + integer_two_node = build_int_cst (NULL_TREE, 2); /* Guess at the initial static decls size. */ @@ -5693,6 +5768,9 @@ cxx_init_decl_processing (void) if (modules_p ()) init_modules (parse_in); + if (flag_reflection) + init_reflection (); + make_fname_decl = cp_make_fname_decl; start_fname_decls (); @@ -7220,6 +7298,10 @@ maybe_commonize_var (tree decl) if (DECL_ARTIFICIAL (decl) && !DECL_DECOMPOSITION_P (decl)) return; + /* These are not output at all. */ + if (consteval_only_p (decl)) + return; + /* Static data in a function with comdat linkage also has comdat linkage. */ if ((TREE_STATIC (decl) @@ -8577,6 +8659,16 @@ check_initializer (tree decl, tree init, int flags, vec **cleanups) init = NULL_TREE; } } + else if (!init && REFLECTION_TYPE_P (type)) + { + /* [dcl.init.general]: To default-initialize an object of type + std::meta::info means that the object is zero-initialized. */ + DECL_INITIAL (decl) + = build_zero_init (type, NULL_TREE, /*static_storage_p=*/false); + DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = true; + TREE_CONSTANT (decl) = true; + init = NULL_TREE; + } else { if (CLASS_TYPE_P (core_type = strip_array_types (type)) @@ -8696,6 +8788,14 @@ make_rtl_for_nonlocal_decl (tree decl, tree init, const char* asmspec) if (DECL_FUNCTION_SCOPE_P (decl) && !TREE_STATIC (decl)) return; + /* Don't output reflection variables. */ + if (consteval_only_p (decl)) + { + /* Disable assemble_variable. */ + DECL_EXTERNAL (decl) = true; + return; + } + /* We defer emission of local statics until the corresponding DECL_EXPR is expanded. But with constexpr its function might never be expanded, so go ahead and tell cgraph about the variable now. */ @@ -9743,6 +9843,10 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, } } + /* Detect stuff like 'info r = ^^int;' outside a manifestly + constant-evaluated context. */ + check_out_of_consteval_use (decl); + /* If this is a local variable that will need a mangled name, register it now. We must do this before processing the initializer for the variable, since the initialization might @@ -9751,7 +9855,8 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, variable. */ if (DECL_FUNCTION_SCOPE_P (decl) && TREE_STATIC (decl) - && !DECL_ARTIFICIAL (decl)) + && !DECL_ARTIFICIAL (decl) + && !consteval_only_p (decl)) { /* The variable holding an anonymous union will have had its discriminator set in finish_anon_union, after which it's @@ -10280,7 +10385,7 @@ get_tuple_size (tree type) inst = complete_type (inst); if (inst == error_mark_node || !COMPLETE_TYPE_P (inst) - || !CLASS_TYPE_P (type)) + || !CLASS_TYPE_P (inst)) return NULL_TREE; tree val = lookup_qualified_name (inst, value_identifier, LOOK_want::NORMAL, /*complain*/false); @@ -12574,6 +12679,8 @@ grokfndecl (tree ctype, if (DECL_CONSTRUCTOR_P (decl) && !grok_ctor_properties (ctype, decl)) return NULL_TREE; + check_consteval_only_fn (decl); + if (ctype == NULL_TREE || check) return decl; @@ -18369,6 +18476,8 @@ xref_basetypes (tree ref, tree base_list) unsigned max_vbases = 0; /* Maximum direct & indirect virtual bases. */ unsigned max_bases = 0; /* Maximum direct bases. */ unsigned max_dvbases = 0; /* Maximum direct virtual bases. */ + /* Highest direct base index with annotations. */ + unsigned max_annotated_base = 0; int i; tree default_access; tree igo_prev; /* Track Inheritance Graph Order. */ @@ -18406,6 +18515,8 @@ xref_basetypes (tree ref, tree base_list) else { max_bases++; + if (TREE_CODE (TREE_PURPOSE (*basep)) == TREE_LIST) + max_annotated_base = max_bases; if (TREE_TYPE (*basep)) max_dvbases++; if (CLASS_TYPE_P (basetype)) @@ -18434,7 +18545,8 @@ xref_basetypes (tree ref, tree base_list) if (max_bases) { - vec_alloc (BINFO_BASE_ACCESSES (binfo), max_bases); + vec_alloc (BINFO_BASE_ACCESSES (binfo), max_bases + max_annotated_base); + BINFO_BASE_ACCESSES (binfo)->quick_grow (max_bases + max_annotated_base); /* A C++98 POD cannot have base classes. */ CLASSTYPE_NON_LAYOUT_POD_P (ref) = true; @@ -18464,6 +18576,30 @@ xref_basetypes (tree ref, tree base_list) for (igo_prev = binfo; base_list; base_list = TREE_CHAIN (base_list)) { tree access = TREE_PURPOSE (base_list); + tree annotations = NULL_TREE; + if (TREE_CODE (access) == TREE_LIST) + { + annotations = TREE_VALUE (access); + access = TREE_PURPOSE (access); + for (tree *d = &annotations; *d; ) + { + if (annotation_p (*d)) + { + tree name = get_attribute_name (*d); + tree args = TREE_VALUE (*d); + const attribute_spec *as + = lookup_attribute_spec (TREE_PURPOSE (*d)); + bool no_add_attrs = false; + as->handler (&binfo, name, args, 0, &no_add_attrs); + if (no_add_attrs) + { + *d = TREE_CHAIN (*d); + continue; + } + } + d = &TREE_CHAIN (*d); + } + } int via_virtual = TREE_TYPE (base_list) != NULL_TREE; tree basetype = TREE_VALUE (base_list); @@ -18530,8 +18666,12 @@ xref_basetypes (tree ref, tree base_list) if (!BINFO_INHERITANCE_CHAIN (base_binfo)) BINFO_INHERITANCE_CHAIN (base_binfo) = binfo; + unsigned len; + len = BINFO_N_BASE_BINFOS (binfo); BINFO_BASE_APPEND (binfo, base_binfo); - BINFO_BASE_ACCESS_APPEND (binfo, access); + BINFO_BASE_ACCESS (binfo, len) = access; + if (len < max_annotated_base) + BINFO_BASE_ACCESS (binfo, max_bases + len) = annotations; continue; dropped_base: @@ -18547,6 +18687,17 @@ xref_basetypes (tree ref, tree base_list) -= vec_safe_length (CLASSTYPE_VBASECLASSES (basetype)); } + unsigned len = BINFO_N_BASE_BINFOS (binfo); + if (len < max_bases) + { + if (len && max_annotated_base) + memmove (&BINFO_BASE_ACCESS (binfo, len), + &BINFO_BASE_ACCESS (binfo, max_bases), + MIN (max_annotated_base, len) * sizeof (tree)); + BINFO_BASE_ACCESSES (binfo)->truncate (len + MIN (max_annotated_base, + len)); + } + if (CLASSTYPE_VBASECLASSES (ref) && max_vbases == 0) vec_free (CLASSTYPE_VBASECLASSES (ref)); @@ -18816,6 +18967,8 @@ finish_enum_value_list (tree enumtype) tree minnode, maxnode; tree t; + ENUM_BEING_DEFINED_P (enumtype) = 0; + bool fixed_underlying_type_p = ENUM_UNDERLYING_TYPE (enumtype) != NULL_TREE; diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc index c6449844965c..4de6345135f8 100644 --- a/gcc/cp/decl2.cc +++ b/gcc/cp/decl2.cc @@ -1678,6 +1678,11 @@ is_late_template_attribute (tree attr, tree decl) = lookup_attribute_spec (TREE_PURPOSE (attr)); tree arg; + /* Handle all annotations as late, so that they aren't incorrectly + reordered if some have dependent expressions and others don't. */ + if (annotation_p (attr)) + return true; + if (!spec) /* Unknown attribute. */ return false; @@ -1956,6 +1961,10 @@ cp_check_const_attributes (tree attributes) if (cxx_contract_attribute_p (attr)) continue; + /* Annotation arguments are handled in handle_annotation_attribute. */ + if (annotation_p (attr)) + continue; + tree arg; /* As we implement alignas using gnu::aligned attribute and alignas argument is a constant expression, force manifestly @@ -2666,6 +2675,10 @@ maybe_make_one_only (tree decl) if (! flag_weak) return; + /* These are not to be output. */ + if (consteval_only_p (decl)) + 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, @@ -2822,6 +2835,10 @@ var_finalized_p (tree var) void mark_needed (tree decl) { + /* These are not to be output. */ + if (consteval_only_p (decl)) + return; + TREE_USED (decl) = 1; if (TREE_CODE (decl) == FUNCTION_DECL) { @@ -3040,7 +3057,7 @@ min_vis_r (tree *tp, int *walk_subtrees, void *data) /* walk_tree helper function for expr_visibility. */ static tree -min_vis_expr_r (tree *tp, int */*walk_subtrees*/, void *data) +min_vis_expr_r (tree *tp, int *walk_subtrees, void *data) { int *vis_p = (int *)data; int tpvis = VISIBILITY_DEFAULT; @@ -3112,6 +3129,59 @@ min_vis_expr_r (tree *tp, int */*walk_subtrees*/, void *data) tpvis = type_visibility (DECL_CONTEXT (t)); break; + case REFLECT_EXPR: + tree r; + r = REFLECT_EXPR_HANDLE (t); + switch (REFLECT_EXPR_KIND (t)) + { + case REFLECT_BASE: + /* For direct base class relationship, determine visibility + from both D and B types. */ + tpvis = type_visibility (BINFO_TYPE (r)); + if (tpvis > *vis_p) + *vis_p = tpvis; + tpvis = type_visibility (direct_base_parent (r)); + *walk_subtrees = 0; + break; + case REFLECT_DATA_MEMBER_SPEC: + /* For data member description determine visibility + from the type. */ + tpvis = type_visibility (TREE_VEC_ELT (r, 0)); + *walk_subtrees = 0; + break; + case REFLECT_PARM: + /* For function parameter reflection determine visibility + based on parent_of. */ + tpvis = expr_visibility (DECL_CONTEXT (r)); + *walk_subtrees = 0; + break; + case REFLECT_ANNOTATION: + /* Annotations are always local to the TU. */ + tpvis = VISIBILITY_ANON; + *walk_subtrees = 0; + break; + case REFLECT_OBJECT: + r = get_base_address (r); + gcc_fallthrough (); + default: + if (TYPE_P (r)) + { + tpvis = type_visibility (r); + *walk_subtrees = 0; + break; + } + if ((VAR_P (r) && decl_function_context (r)) + || TREE_CODE (r) == PARM_DECL) + { + /* Block scope variables are local to the TU. */ + tpvis = VISIBILITY_ANON; + *walk_subtrees = 0; + break; + } + break; + } + break; + default: break; } @@ -4994,6 +5064,14 @@ prune_vars_needing_no_initialization (tree *vars) continue; } + /* Reflections are consteval-only types and we don't want them + to survive until gimplification. */ + if (consteval_only_p (decl)) + { + var = &TREE_CHAIN (t); + continue; + } + /* This variable is going to need initialization and/or finalization, so we add it to the list. */ *var = TREE_CHAIN (t); @@ -5342,6 +5420,12 @@ no_linkage_error (tree decl) /* An imported decl is ok. */ return; + /* Metafunctions are magic and should be considered defined even though + they have no bodies. ??? This can't be checked in decl_defined_p; + we'd get redefinition errors for some of our metafunctions. */ + if (TREE_CODE (decl) == FUNCTION_DECL && metafunction_p (decl)) + return; + tree t = no_linkage_check (TREE_TYPE (decl), /*relaxed_p=*/false); if (t == NULL_TREE) /* The type that got us on no_linkage_decls must have gotten a name for @@ -6016,7 +6100,9 @@ c_parse_final_cleanups (void) /* Static data members are just like namespace-scope globals. */ FOR_EACH_VEC_SAFE_ELT (pending_statics, i, decl) { - if (var_finalized_p (decl) || DECL_REALLY_EXTERN (decl) + if (consteval_only_p (decl) + || var_finalized_p (decl) + || DECL_REALLY_EXTERN (decl) /* Don't write it out if we haven't seen a definition. */ || DECL_IN_AGGR_P (decl)) continue; @@ -6058,6 +6144,8 @@ c_parse_final_cleanups (void) should have synthesized it above.) */ && !(header_module_p () && (DECL_DEFAULTED_FN (decl) || decl_tls_wrapper_p (decl))) + /* Metafunctions are never defined. */ + && !metafunction_p (decl) /* Don't complain if the template was defined. */ && !(DECL_TEMPLOID_INSTANTIATION (decl) && DECL_INITIAL (DECL_TEMPLATE_RESULT diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc index c51725555a9d..c184846066e0 100644 --- a/gcc/cp/error.cc +++ b/gcc/cp/error.cc @@ -749,6 +749,7 @@ dump_type (cxx_pretty_printer *pp, tree t, int flags) case TEMPLATE_DECL: case NAMESPACE_DECL: + case CONST_DECL: dump_decl (pp, t, flags & ~TFF_DECL_SPECIFIERS); break; @@ -877,6 +878,14 @@ dump_type (cxx_pretty_printer *pp, tree t, int flags) pp_string (pp, "std::nullptr_t"); break; + case META_TYPE: + pp_string (pp, "std::meta::info"); + break; + + case SPLICE_SCOPE: + dump_expr (pp, SPLICE_SCOPE_EXPR (t), flags & ~TFF_EXPR_IN_PARENS); + break; + default: pp_unsupported_tree (pp, t); /* Fall through. */ @@ -1136,6 +1145,8 @@ dump_type_prefix (cxx_pretty_printer *pp, tree t, int flags) case FIXED_POINT_TYPE: case NULLPTR_TYPE: case PACK_INDEX_TYPE: + case META_TYPE: + case SPLICE_SCOPE: dump_type (pp, t, flags); pp->set_padding (pp_before); break; @@ -1269,6 +1280,8 @@ dump_type_suffix (cxx_pretty_printer *pp, tree t, int flags) case FIXED_POINT_TYPE: case NULLPTR_TYPE: case PACK_INDEX_TYPE: + case META_TYPE: + case SPLICE_SCOPE: break; default: @@ -1615,9 +1628,14 @@ dump_decl (cxx_pretty_printer *pp, tree t, int flags) tree name = TREE_OPERAND (t, 0); tree args = TREE_OPERAND (t, 1); - if (!identifier_p (name)) - name = OVL_NAME (name); - dump_decl (pp, name, flags); + if (TREE_CODE (name) == SPLICE_EXPR) + dump_expr (pp, name, flags); + else + { + if (!identifier_p (name)) + name = OVL_NAME (name); + dump_decl (pp, name, flags); + } pp_cxx_begin_template_argument_list (pp); if (args == error_mark_node) pp_string (pp, M_("