diff options
-rw-r--r-- | gcc/cp/call.c | 40 | ||||
-rw-r--r-- | gcc/cp/constexpr.c | 4 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 4 | ||||
-rw-r--r-- | gcc/cp/typeck.c | 16 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp23/consteval-if11.C | 27 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp2a/consteval13.C | 4 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp2a/consteval20.C | 24 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp2a/consteval21.C | 35 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp2a/consteval22.C | 34 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp2a/consteval23.C | 13 |
10 files changed, 188 insertions, 13 deletions
diff --git a/gcc/cp/call.c b/gcc/cp/call.c index c5601d9..20e66c6 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -9025,6 +9025,20 @@ build_trivial_dtor_call (tree instance, bool no_ptr_deref) instance, clobber); } +/* Return true if in an immediate function context, or an unevaluated operand, + or a subexpression of an immediate invocation. */ + +bool +in_immediate_context () +{ + return (cp_unevaluated_operand != 0 + || (current_function_decl != NULL_TREE + && DECL_IMMEDIATE_FUNCTION_P (current_function_decl)) + || (current_binding_level->kind == sk_function_parms + && current_binding_level->immediate_fn_ctx_p) + || in_consteval_if_p); +} + /* Return true if a call to FN with number of arguments NARGS is an immediate invocation. */ @@ -9033,18 +9047,25 @@ immediate_invocation_p (tree fn, int nargs) { return (TREE_CODE (fn) == FUNCTION_DECL && DECL_IMMEDIATE_FUNCTION_P (fn) - && cp_unevaluated_operand == 0 - && (current_function_decl == NULL_TREE - || !DECL_IMMEDIATE_FUNCTION_P (current_function_decl)) - && (current_binding_level->kind != sk_function_parms - || !current_binding_level->immediate_fn_ctx_p) - && !in_consteval_if_p + && !in_immediate_context () /* As an exception, we defer std::source_location::current () invocations until genericization because LWG3396 mandates special behavior for it. */ && (nargs > 1 || !source_location_current_p (fn))); } +/* temp_override for in_consteval_if_p, which can't use make_temp_override + because it is a bitfield. */ + +struct in_consteval_if_p_temp_override { + bool save_in_consteval_if_p; + in_consteval_if_p_temp_override () + : save_in_consteval_if_p (in_consteval_if_p) {} + void reset () { in_consteval_if_p = save_in_consteval_if_p; } + ~in_consteval_if_p_temp_override () + { reset (); } +}; + /* Subroutine of the various build_*_call functions. Overload resolution has chosen a winning candidate CAND; build up a CALL_EXPR accordingly. ARGS is a TREE_LIST of the unconverted arguments to the call. FLAGS is a @@ -9254,6 +9275,12 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) nargs = parmlen; argarray = XALLOCAVEC (tree, nargs); + in_consteval_if_p_temp_override icip; + /* If the call is immediate function invocation, make sure + taking address of immediate functions is allowed in its arguments. */ + if (immediate_invocation_p (STRIP_TEMPLATE (fn), nargs)) + in_consteval_if_p = true; + /* The implicit parameters to a constructor are not considered by overload resolution, and must be of the proper type. */ if (DECL_CONSTRUCTOR_P (fn)) @@ -9498,6 +9525,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) gcc_assert (j <= nargs); nargs = j; + icip.reset (); /* Avoid performing argument transformation if warnings are disabled. When tf_warning is set and at least one of the warnings is active diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 6f83d30..daa6358 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -7276,6 +7276,10 @@ find_immediate_fndecl (tree *tp, int */*walk_subtrees*/, void */*data*/) { if (TREE_CODE (*tp) == FUNCTION_DECL && DECL_IMMEDIATE_FUNCTION_P (*tp)) return *tp; + if (TREE_CODE (*tp) == PTRMEM_CST + && TREE_CODE (PTRMEM_CST_MEMBER (*tp)) == FUNCTION_DECL + && DECL_IMMEDIATE_FUNCTION_P (PTRMEM_CST_MEMBER (*tp))) + return PTRMEM_CST_MEMBER (*tp); return NULL_TREE; } diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 5248ecd..f387b50 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -1825,7 +1825,8 @@ struct GTY(()) saved_scope { if-statement. */ BOOL_BITFIELD discarded_stmt : 1; /* Nonzero if we are parsing or instantiating the compound-statement - of consteval if statement. */ + of consteval if statement. Also set while processing an immediate + invocation. */ BOOL_BITFIELD consteval_if_p : 1; int unevaluated_operand; @@ -6547,6 +6548,7 @@ extern tree perform_direct_initialization_if_possible (tree, tree, bool, tsubst_flags_t); extern vec<tree,va_gc> *resolve_args (vec<tree,va_gc>*, tsubst_flags_t); extern tree in_charge_arg_for_name (tree); +extern bool in_immediate_context (); extern tree build_cxx_call (tree, int, tree *, tsubst_flags_t, tree = NULL_TREE); diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index ab0f9da..d5f5000 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -6773,9 +6773,19 @@ cp_build_addr_expr_1 (tree arg, bool strict_lvalue, tsubst_flags_t complain) return error_mark_node; } + if (TREE_CODE (t) == FUNCTION_DECL + && DECL_IMMEDIATE_FUNCTION_P (t) + && !in_immediate_context ()) + { + if (complain & tf_error) + error_at (loc, "taking address of an immediate function %qD", + t); + return error_mark_node; + } + type = build_ptrmem_type (context_for_name_lookup (t), TREE_TYPE (t)); - t = make_ptrmem_cst (type, TREE_OPERAND (arg, 1)); + t = make_ptrmem_cst (type, t); return t; } @@ -6800,9 +6810,7 @@ cp_build_addr_expr_1 (tree arg, bool strict_lvalue, tsubst_flags_t complain) tree stripped_arg = tree_strip_any_location_wrapper (arg); if (TREE_CODE (stripped_arg) == FUNCTION_DECL && DECL_IMMEDIATE_FUNCTION_P (stripped_arg) - && cp_unevaluated_operand == 0 - && (current_function_decl == NULL_TREE - || !DECL_IMMEDIATE_FUNCTION_P (current_function_decl))) + && !in_immediate_context ()) { if (complain & tf_error) error_at (loc, "taking address of an immediate function %qD", diff --git a/gcc/testsuite/g++.dg/cpp23/consteval-if11.C b/gcc/testsuite/g++.dg/cpp23/consteval-if11.C new file mode 100644 index 0000000..a22736c --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/consteval-if11.C @@ -0,0 +1,27 @@ +// PR c++/102753 +// { dg-do compile { target c++20 } } +// { dg-options "" } + +struct S { + constexpr S () : s (0) {} + consteval int foo () { return 1; } + virtual consteval int bar () { return 2; } + int s; +}; + +consteval int foo () { return 42; } + +constexpr int +bar () +{ + if consteval { // { dg-warning "'if consteval' only available with" "" { target c++20_only } } + int (*fn1) () = foo; + int (S::*fn2) () = &S::foo; + int (S::*fn3) () = &S::bar; + S s; + return fn1 () + (s.*fn2) () + (s.*fn3) (); + } + return 0; +} + +static_assert (bar () == 45); diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval13.C b/gcc/testsuite/g++.dg/cpp2a/consteval13.C index a2e1750..09ea6b7 100644 --- a/gcc/testsuite/g++.dg/cpp2a/consteval13.C +++ b/gcc/testsuite/g++.dg/cpp2a/consteval13.C @@ -10,8 +10,8 @@ void foo () { auto qux = [] (fnptr a = quux ()) consteval { return a (); }; - constexpr auto c = qux (baz); // { dg-error "28:taking address of an immediate function" } - constexpr auto d = qux (bar); // { dg-error "28:taking address of an immediate function" } + constexpr auto c = qux (baz); + constexpr auto d = qux (bar); static_assert (c == 1); static_assert (d == 42); } diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval20.C b/gcc/testsuite/g++.dg/cpp2a/consteval20.C new file mode 100644 index 0000000..2c35963 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/consteval20.C @@ -0,0 +1,24 @@ +// PR c++/102753 +// { dg-do compile { target c++20 } } + +struct S { + consteval int foo () const { return 42; } +}; + +constexpr S s; + +int +bar () +{ + return (s.*&S::foo) (); // { dg-error "taking address of an immediate function" } +} + +constexpr auto a = &S::foo; // { dg-error "taking address of an immediate function" } + +consteval int +baz () +{ + return (s.*&S::foo) (); +} + +static_assert (baz () == 42); diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval21.C b/gcc/testsuite/g++.dg/cpp2a/consteval21.C new file mode 100644 index 0000000..06ec705 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/consteval21.C @@ -0,0 +1,35 @@ +// PR c++/102753 +// { dg-do compile { target c++20 } } + +struct S { + constexpr S () : s (0) {} + consteval int foo () { return 1; } + virtual consteval int bar () { return 2; } + int s; +}; + +consteval int foo () { return 42; } + +consteval int +bar (int (*fn) () = &foo) +{ + return fn (); +} + +consteval int +baz (int (S::*fn) () = &S::foo) +{ + S s; + return (s.*fn) (); +} + +consteval int +qux (int (S::*fn) () = &S::bar) +{ + S s; + return (s.*fn) (); +} + +static_assert (bar () == 42); +static_assert (baz () == 1); +static_assert (qux () == 2); diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval22.C b/gcc/testsuite/g++.dg/cpp2a/consteval22.C new file mode 100644 index 0000000..5c36371 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/consteval22.C @@ -0,0 +1,34 @@ +// PR c++/102753 +// { dg-do compile { target c++20 } } + +struct S { + constexpr S () : s (0) {} + consteval int foo () { return 1; } + virtual consteval int bar () { return 2; } + int s; +}; +typedef int (S::*P) (); + +consteval P +foo () +{ + return &S::foo; +} + +consteval P +bar () +{ + return &S::bar; +} + +consteval int +baz () +{ + S s; + return (s.*(foo ())) () + (s.*(bar ())) (); +} + +static_assert (baz () == 3); + +constexpr P a = foo (); // { dg-error "immediate evaluation returns address of immediate function" } +constexpr P b = bar (); // { dg-error "immediate evaluation returns address of immediate function" } diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval23.C b/gcc/testsuite/g++.dg/cpp2a/consteval23.C new file mode 100644 index 0000000..4c7e844 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/consteval23.C @@ -0,0 +1,13 @@ +// PR c++/102753 +// { dg-do compile { target c++20 } } + +consteval int foo () { return 42; } + +consteval int +bar (int (*fn) () = foo) +{ + return fn (); +} + +static_assert (bar () == 42); +static_assert (bar (foo) == 42); |