* [pushed 1/2] c++: always check consteval address
@ 2023-05-10 15:04 Jason Merrill
2023-05-10 15:04 ` [pushed 2/2] c++: be stricter about constinit [CWG2543] Jason Merrill
0 siblings, 1 reply; 2+ messages in thread
From: Jason Merrill @ 2023-05-10 15:04 UTC (permalink / raw)
To: gcc-patches
Tested x86_64-pc-linux-gnu, applying to trunk.
-- 8< --
The restriction on the "permitted result of a constant expression" to not
refer to an immediate function applies regardless of context. The previous
code tried to only check in cases where we wouldn't get the check in
cp_fold_r, but with the next patch I would need to add another case and it
shouldn't be a problem to always check.
We also shouldn't talk about immediate evaluation when we aren't dealing
with one.
gcc/cp/ChangeLog:
* constexpr.cc (cxx_eval_outermost_constant_expr): Always check
for address of immediate fn.
(maybe_constant_init_1): Evaluate PTRMEM_CST.
gcc/testsuite/ChangeLog:
* g++.dg/DRs/dr2478.C: Handle -fimplicit-constexpr.
* g++.dg/cpp23/consteval-if12.C: Adjust diagnostics.
* g++.dg/cpp2a/consteval20.C: Likewise.
* g++.dg/cpp2a/consteval24.C: Likewise.
* g++.dg/cpp2a/srcloc20.C: Likewise.
---
gcc/cp/constexpr.cc | 22 ++++++++++++++-------
gcc/testsuite/g++.dg/DRs/dr2478.C | 17 +++++++++-------
gcc/testsuite/g++.dg/cpp23/consteval-if12.C | 8 ++++----
gcc/testsuite/g++.dg/cpp2a/consteval20.C | 4 ++--
gcc/testsuite/g++.dg/cpp2a/consteval24.C | 8 ++++----
gcc/testsuite/g++.dg/cpp2a/srcloc20.C | 4 ++--
6 files changed, 37 insertions(+), 26 deletions(-)
diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index 987a536d515..7b8090625e8 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -8353,7 +8353,8 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
non_constant_p = true;
}
- if (!global_ctx.heap_vars.is_empty ())
+ if (!non_constant_p && cxx_dialect >= cxx20
+ && !global_ctx.heap_vars.is_empty ())
{
tree heap_var = cp_walk_tree_without_duplicates (&r, find_heap_var_refs,
NULL);
@@ -8384,15 +8385,22 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
/* Check that immediate invocation does not return an expression referencing
any immediate function decls. */
- if (is_consteval || in_immediate_context ())
+ if (!non_constant_p && cxx_dialect >= cxx20)
if (tree immediate_fndecl
= cp_walk_tree_without_duplicates (&r, find_immediate_fndecl,
NULL))
{
if (!allow_non_constant && !non_constant_p)
- error_at (cp_expr_loc_or_input_loc (t),
- "immediate evaluation returns address of immediate "
- "function %qD", immediate_fndecl);
+ {
+ if (is_consteval)
+ error_at (cp_expr_loc_or_input_loc (t),
+ "immediate evaluation returns address of immediate "
+ "function %qD", immediate_fndecl);
+ else
+ error_at (cp_expr_loc_or_input_loc (t),
+ "constant evaluation returns address of immediate "
+ "function %qD", immediate_fndecl);
+ }
r = t;
non_constant_p = true;
}
@@ -8795,8 +8803,8 @@ maybe_constant_init_1 (tree t, tree decl, bool allow_non_constant,
t = TARGET_EXPR_INITIAL (t);
if (!is_nondependent_static_init_expression (t))
/* Don't try to evaluate it. */;
- else if (CONSTANT_CLASS_P (t) && allow_non_constant)
- /* No evaluation needed. */;
+ else if (CONSTANT_CLASS_P (t) && TREE_CODE (t) != PTRMEM_CST)
+ /* No evaluation needed. PTRMEM_CST needs the immediate fn check. */;
else
{
/* [basic.start.static] allows constant-initialization of variables with
diff --git a/gcc/testsuite/g++.dg/DRs/dr2478.C b/gcc/testsuite/g++.dg/DRs/dr2478.C
index 7e939ac6850..7f581cabb7b 100644
--- a/gcc/testsuite/g++.dg/DRs/dr2478.C
+++ b/gcc/testsuite/g++.dg/DRs/dr2478.C
@@ -1,11 +1,14 @@
// DR 2478 - Properties of explicit specializations of implicitly-instantiated class templates
// { dg-do compile { target c++20 } }
+// Defeat -fimplicit-constexpr
+int ii;
+
template <typename T>
struct S {
- int foo () { return 0; }
+ int foo () { return ii; }
constexpr int bar () { return 0; }
- int baz () { return 0; }
+ int baz () { return ii; }
consteval int qux () { return 0; }
constexpr S () {}
static constinit T x;
@@ -14,7 +17,7 @@ struct S {
template <typename T>
T S<T>::x = S<T> ().foo (); // { dg-error "'constinit' variable 'S<char>::x' does not have a constant initializer" }
- // { dg-error "call to non-'constexpr' function" "" { target *-*-* } .-1 }
+ // { dg-error "call to non-'constexpr' function|called in a constant expression" "" { target *-*-* } .-1 }
template <typename T>
T S<T>::y = S<T> ().foo ();
@@ -49,14 +52,14 @@ S<char>::qux ()
template <>
long S<long>::x = S<long> ().foo (); // { dg-bogus "'constinit' variable 'S<long int>::x' does not have a constant initializer" "" { xfail *-*-* } }
- // { dg-bogus "call to non-'constexpr' function" "" { xfail *-*-* } .-1 }
+ // { dg-bogus "call to non-'constexpr' function|called in a constant expression" "" { xfail *-*-* } .-1 }
template <>
constinit long S<long>::y = S<long> ().foo (); // { dg-error "'constinit' variable 'S<long int>::y' does not have a constant initializer" }
- // { dg-error "call to non-'constexpr' function" "" { target *-*-* } .-1 }
+ // { dg-error "call to non-'constexpr' function|called in a constant expression" "" { target *-*-* } .-1 }
constinit auto a = S<char> ().foo (); // { dg-error "'constinit' variable 'a' does not have a constant initializer" }
- // { dg-error "call to non-'constexpr' function" "" { target *-*-* } .-1 }
+ // { dg-error "call to non-'constexpr' function|called in a constant expression" "" { target *-*-* } .-1 }
constinit auto b = S<char> ().bar ();
constinit auto c = S<int> ().foo ();
constinit auto d = S<int> ().bar (); // { dg-error "'constinit' variable 'd' does not have a constant initializer" }
@@ -65,7 +68,7 @@ constinit auto e = S<char> ().baz ();
constinit auto f = S<char> ().qux (); // { dg-error "'constinit' variable 'f' does not have a constant initializer" }
// { dg-error "call to non-'constexpr' function" "" { target *-*-* } .-1 }
constinit auto g = S<int> ().baz (); // { dg-error "'constinit' variable 'g' does not have a constant initializer" }
- // { dg-error "call to non-'constexpr' function" "" { target *-*-* } .-1 }
+ // { dg-error "call to non-'constexpr' function|called in a constant expression" "" { target *-*-* } .-1 }
constinit auto h = S<int> ().qux ();
auto i = S<char>::x;
auto j = S<int>::x;
diff --git a/gcc/testsuite/g++.dg/cpp23/consteval-if12.C b/gcc/testsuite/g++.dg/cpp23/consteval-if12.C
index 7a47680e5d8..03de87c3e09 100644
--- a/gcc/testsuite/g++.dg/cpp23/consteval-if12.C
+++ b/gcc/testsuite/g++.dg/cpp23/consteval-if12.C
@@ -19,10 +19,10 @@ bar ()
{
S s;
if consteval { // { dg-warning "'if consteval' only available with" "" { target c++20_only } }
- constexpr auto fn1 = foo; // { dg-error "immediate evaluation returns address of immediate function" }
- constexpr auto fn2 = &foo; // { dg-error "immediate evaluation returns address of immediate function" }
- constexpr auto fn3 = &S::foo; // { dg-error "immediate evaluation returns address of immediate function" }
- constexpr auto fn4 = &S::bar; // { dg-error "immediate evaluation returns address of immediate function" }
+ constexpr auto fn1 = foo; // { dg-error "constant evaluation returns address of immediate function" }
+ constexpr auto fn2 = &foo; // { dg-error "constant evaluation returns address of immediate function" }
+ constexpr auto fn3 = &S::foo; // { dg-error "constant evaluation returns address of immediate function" }
+ constexpr auto fn4 = &S::bar; // { dg-error "constant evaluation returns address of immediate function" }
constexpr auto fn5 = baz (); // { dg-error "immediate evaluation returns address of immediate function" }
constexpr auto fn6 = qux (); // { dg-error "immediate evaluation returns address of immediate function" }
constexpr auto fn7 = corge (); // { dg-error "immediate evaluation returns address of immediate function" }
diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval20.C b/gcc/testsuite/g++.dg/cpp2a/consteval20.C
index bd44712c535..ba3613318e6 100644
--- a/gcc/testsuite/g++.dg/cpp2a/consteval20.C
+++ b/gcc/testsuite/g++.dg/cpp2a/consteval20.C
@@ -11,12 +11,12 @@ int
bar ()
{
auto c = &S::foo; // { dg-error "taking address of an immediate function" }
- constexpr auto d = &S::foo; // { dg-error "taking address of an immediate function" }
+ constexpr auto d = &S::foo; // { dg-error "constant evaluation returns address of immediate function" }
static auto e = &S::foo; // { dg-error "taking address of an immediate function" }
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" }
+constexpr auto a = &S::foo; // { dg-error "constant evaluation returns address of immediate function" }
auto b = &S::foo; // { dg-error "taking address of an immediate function" }
consteval int
diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval24.C b/gcc/testsuite/g++.dg/cpp2a/consteval24.C
index 6d7034c5515..22a9657e4a1 100644
--- a/gcc/testsuite/g++.dg/cpp2a/consteval24.C
+++ b/gcc/testsuite/g++.dg/cpp2a/consteval24.C
@@ -17,10 +17,10 @@ consteval int
bar ()
{
S s;
- constexpr auto fn1 = foo; // { dg-error "immediate evaluation returns address of immediate function" }
- constexpr auto fn2 = &foo; // { dg-error "immediate evaluation returns address of immediate function" }
- constexpr auto fn3 = &S::foo; // { dg-error "immediate evaluation returns address of immediate function" }
- constexpr auto fn4 = &S::bar; // { dg-error "immediate evaluation returns address of immediate function" }
+ constexpr auto fn1 = foo; // { dg-error "constant evaluation returns address of immediate function" }
+ constexpr auto fn2 = &foo; // { dg-error "constant evaluation returns address of immediate function" }
+ constexpr auto fn3 = &S::foo; // { dg-error "constant evaluation returns address of immediate function" }
+ constexpr auto fn4 = &S::bar; // { dg-error "constant evaluation returns address of immediate function" }
constexpr auto fn5 = baz (); // { dg-error "immediate evaluation returns address of immediate function" }
constexpr auto fn6 = qux (); // { dg-error "immediate evaluation returns address of immediate function" }
constexpr auto fn7 = corge (); // { dg-error "immediate evaluation returns address of immediate function" }
diff --git a/gcc/testsuite/g++.dg/cpp2a/srcloc20.C b/gcc/testsuite/g++.dg/cpp2a/srcloc20.C
index acdf5a6505f..e99f1dcf7c4 100644
--- a/gcc/testsuite/g++.dg/cpp2a/srcloc20.C
+++ b/gcc/testsuite/g++.dg/cpp2a/srcloc20.C
@@ -33,12 +33,12 @@ namespace std {
using namespace std;
auto a = source_location::current; // { dg-error "taking address of an immediate function" }
-constexpr auto b = &source_location::current; // { dg-error "taking address of an immediate function" }
+constexpr auto b = &source_location::current; // { dg-error "constant evaluation returns address of immediate function" }
void
foo ()
{
auto c = &source_location::current; // { dg-error "taking address of an immediate function" }
- constexpr auto d = source_location::current; // { dg-error "taking address of an immediate function" }
+ constexpr auto d = source_location::current; // { dg-error "constant evaluation returns address of immediate function" }
static auto e = source_location::current; // { dg-error "taking address of an immediate function" }
}
base-commit: 204303c81e82ddd01e7dc5a5a63719d476f9043c
--
2.31.1
^ permalink raw reply [flat|nested] 2+ messages in thread
* [pushed 2/2] c++: be stricter about constinit [CWG2543]
2023-05-10 15:04 [pushed 1/2] c++: always check consteval address Jason Merrill
@ 2023-05-10 15:04 ` Jason Merrill
0 siblings, 0 replies; 2+ messages in thread
From: Jason Merrill @ 2023-05-10 15:04 UTC (permalink / raw)
To: gcc-patches
Tested x86_64-pc-linux-gnu, applying to trunk.
-- 8< --
DR 2543 clarifies that constinit variables should follow the language, and
diagnose non-constant initializers (according to [expr.const]) even if they
can actually initialize the variables statically.
DR 2543
gcc/cp/ChangeLog:
* constexpr.cc (cxx_eval_outermost_constant_expr): Preserve
TARGET_EXPR flags.
(potential_constant_expression_1): Check TARGET_EXPR_ELIDING_P.
* typeck2.cc (store_init_value): Diagnose constinit sooner.
gcc/testsuite/ChangeLog:
* g++.dg/DRs/dr2543.C: New test.
---
gcc/cp/constexpr.cc | 12 +++++++
gcc/cp/typeck2.cc | 55 +++++++++++++++++--------------
gcc/testsuite/g++.dg/DRs/dr2543.C | 5 +++
3 files changed, 48 insertions(+), 24 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/DRs/dr2543.C
diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index 7b8090625e8..8f7f0b7d325 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -8448,6 +8448,17 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
}
}
+ if (TREE_CODE (t) == TARGET_EXPR
+ && TREE_CODE (r) == TARGET_EXPR)
+ {
+ /* Preserve this flag for potential_constant_expression, and the others
+ for good measure. */
+ TARGET_EXPR_ELIDING_P (r) = TARGET_EXPR_ELIDING_P (t);
+ TARGET_EXPR_IMPLICIT_P (r) = TARGET_EXPR_IMPLICIT_P (t);
+ TARGET_EXPR_LIST_INIT_P (r) = TARGET_EXPR_LIST_INIT_P (t);
+ TARGET_EXPR_DIRECT_INIT_P (r) = TARGET_EXPR_DIRECT_INIT_P (t);
+ }
+
/* Remember the original location if that wouldn't need a wrapper. */
if (location_t loc = EXPR_LOCATION (t))
protected_set_expr_location (r, loc);
@@ -9774,6 +9785,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
case TARGET_EXPR:
if (!TARGET_EXPR_DIRECT_INIT_P (t)
+ && !TARGET_EXPR_ELIDING_P (t)
&& !literal_type_p (TREE_TYPE (t)))
{
if (flags & tf_error)
diff --git a/gcc/cp/typeck2.cc b/gcc/cp/typeck2.cc
index bf03967a71f..f5cc7c8371c 100644
--- a/gcc/cp/typeck2.cc
+++ b/gcc/cp/typeck2.cc
@@ -843,23 +843,45 @@ store_init_value (tree decl, tree init, vec<tree, va_gc>** cleanups, int flags)
bool const_init;
tree oldval = value;
if (DECL_DECLARED_CONSTEXPR_P (decl)
+ || DECL_DECLARED_CONSTINIT_P (decl)
|| (DECL_IN_AGGR_P (decl)
&& DECL_INITIALIZED_IN_CLASS_P (decl)))
{
value = fold_non_dependent_expr (value, tf_warning_or_error,
/*manifestly_const_eval=*/true,
decl);
+ if (value == error_mark_node)
+ ;
/* Diagnose a non-constant initializer for constexpr variable or
non-inline in-class-initialized static data member. */
- if (!require_constant_expression (value))
- value = error_mark_node;
- else if (processing_template_decl)
- /* In a template we might not have done the necessary
- transformations to make value actually constant,
- e.g. extend_ref_init_temps. */
- value = maybe_constant_init (value, decl, true);
+ else if (!is_constant_expression (value))
+ {
+ /* Maybe we want to give this message for constexpr variables as
+ well, but that will mean a lot of testsuite adjustment. */
+ if (DECL_DECLARED_CONSTINIT_P (decl))
+ error_at (location_of (decl),
+ "%<constinit%> variable %qD does not have a "
+ "constant initializer", decl);
+ require_constant_expression (value);
+ value = error_mark_node;
+ }
else
- value = cxx_constant_init (value, decl);
+ {
+ value = maybe_constant_init (value, decl, true);
+
+ /* In a template we might not have done the necessary
+ transformations to make value actually constant,
+ e.g. extend_ref_init_temps. */
+ if (!processing_template_decl
+ && !TREE_CONSTANT (value))
+ {
+ if (DECL_DECLARED_CONSTINIT_P (decl))
+ error_at (location_of (decl),
+ "%<constinit%> variable %qD does not have a "
+ "constant initializer", decl);
+ value = cxx_constant_init (value, decl);
+ }
+ }
}
else
value = fold_non_dependent_init (value, tf_warning_or_error,
@@ -875,22 +897,7 @@ store_init_value (tree decl, tree init, vec<tree, va_gc>** cleanups, int flags)
if (!TYPE_REF_P (type))
TREE_CONSTANT (decl) = const_init && decl_maybe_constant_var_p (decl);
if (!const_init)
- {
- /* [dcl.constinit]/2 "If a variable declared with the constinit
- specifier has dynamic initialization, the program is
- ill-formed." */
- if (DECL_DECLARED_CONSTINIT_P (decl))
- {
- error_at (location_of (decl),
- "%<constinit%> variable %qD does not have a constant "
- "initializer", decl);
- if (require_constant_expression (value))
- cxx_constant_init (value, decl);
- value = error_mark_node;
- }
- else
- value = oldval;
- }
+ value = oldval;
}
/* Don't fold initializers of automatic variables in constexpr functions,
that might fold away something that needs to be diagnosed at constexpr
diff --git a/gcc/testsuite/g++.dg/DRs/dr2543.C b/gcc/testsuite/g++.dg/DRs/dr2543.C
new file mode 100644
index 00000000000..87512d30455
--- /dev/null
+++ b/gcc/testsuite/g++.dg/DRs/dr2543.C
@@ -0,0 +1,5 @@
+// CWG 2543
+// { dg-do compile { target c++20 } }
+
+float f;
+constinit int * pi = (int*) &f; // { dg-error "constant" } reinterpret_cast, not constant-initialized
--
2.31.1
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2023-05-10 15:05 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-05-10 15:04 [pushed 1/2] c++: always check consteval address Jason Merrill
2023-05-10 15:04 ` [pushed 2/2] c++: be stricter about constinit [CWG2543] Jason Merrill
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).