aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/cp/call.c40
-rw-r--r--gcc/cp/constexpr.c4
-rw-r--r--gcc/cp/cp-tree.h4
-rw-r--r--gcc/cp/typeck.c16
-rw-r--r--gcc/testsuite/g++.dg/cpp23/consteval-if11.C27
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/consteval13.C4
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/consteval20.C24
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/consteval21.C35
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/consteval22.C34
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/consteval23.C13
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);