diff mbox

C++ PATCH for c++/81073, constexpr and static var in statement-expression

Message ID CADzB+2knUZB=xvAAYNSdDTxdR4tB5n7RrJ+dHzwwsvnU9-7kXA@mail.gmail.com
State New
Headers show

Commit Message

Jason Merrill June 19, 2017, 5:42 p.m. UTC
The testcase successfully compiles, but then fails to link because
we've optimized away the declaration of the variable.  We catch this
in potential_constant_expression_1, but this path wasn't calling it.

Fixed on trunk by always calling that function, not just in templates.
With that change, I needed to adjust pce1 to not require that a
variable be initialized yet, so that we can check it within the
initializer.  To avoid that causing some missed errors,
decl_maybe_constant_var_p now considers the initializer if it is
already known.

Fixed on 7 branch more simply, by calling p_c_e from
cxx_eval_constant_expression.

Tested x86_64-pc-linux-gnu, applying to trunk and 7.
commit 46761de0ab74a6983c931c13bfb78c095ae4f651
Author: Jason Merrill <jason@redhat.com>
Date:   Sat Jun 17 00:00:21 2017 -0400

            PR c++/81073 - constexpr and static var in statement-expression.
    
            * typeck2.c (store_init_value): Always call
            require_potential_constant_expression.
            * pt.c (convert_nontype_argument): Likewise.
            * constexpr.c (potential_constant_expression_1): Adjust message.
            Use decl_maybe_constant_var_p instead of decl_constant_var_p.
            * decl2.c (decl_maybe_constant_var_p): Consider initializer.
commit c477f412dd8521342ab5a5f702b00177512ad36e
Author: Jason Merrill <jason@redhat.com>
Date:   Mon Jun 19 12:28:11 2017 -0400

            PR c++/81073 - constexpr and static var in statement-expression.
    
            * constexpr.c (cxx_eval_constant_expression) [DECL_EXPR]: Check
            potential_constant_expression.

diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 244b8fd..a28bd02 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -4021,6 +4021,13 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
       break;
 
     case DECL_EXPR:
+      if (!potential_constant_expression (t))
+	{
+	  if (!ctx->quiet)
+	    require_potential_constant_expression (t);
+	  *non_constant_p = true;
+	  break;
+	}
       {
 	r = DECL_EXPR_DECL (t);
 	if (AGGREGATE_TYPE_P (TREE_TYPE (r))
diff --git a/gcc/testsuite/g++.dg/ext/stmtexpr19.C b/gcc/testsuite/g++.dg/ext/stmtexpr19.C
new file mode 100644
index 0000000..0c19a21
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/stmtexpr19.C
@@ -0,0 +1,17 @@
+// PR c++/81073
+// { dg-options "" }
+// { dg-do compile { target c++11 } }
+
+struct test { const int *addr; };
+
+const test* setup()
+{
+  static constexpr test atest =
+    {
+      ({ static const int inner = 123; &inner; }) // { dg-error "static" }
+    };
+
+  return &atest;
+}
+
+int main(){}

Comments

Andreas Schwab June 20, 2017, 9:40 a.m. UTC | #1
FAIL: g++.dg/cpp0x/constexpr-cast.C  -std=c++11  (test for errors, line 10)
FAIL: g++.dg/cpp0x/constexpr-cast.C  -std=c++11 (test for excess errors)
FAIL: g++.dg/cpp0x/constexpr-cast.C  -std=c++14  (test for errors, line 10)
FAIL: g++.dg/cpp0x/constexpr-cast.C  -std=c++14 (test for excess errors)

Andreas.
Jason Merrill June 20, 2017, 6:49 p.m. UTC | #2
On Tue, Jun 20, 2017 at 5:40 AM, Andreas Schwab <schwab@suse.de> wrote:
> FAIL: g++.dg/cpp0x/constexpr-cast.C  -std=c++11  (test for errors, line 10)
> FAIL: g++.dg/cpp0x/constexpr-cast.C  -std=c++11 (test for excess errors)
> FAIL: g++.dg/cpp0x/constexpr-cast.C  -std=c++14  (test for errors, line 10)
> FAIL: g++.dg/cpp0x/constexpr-cast.C  -std=c++14 (test for excess errors)

I'm not seeing this.  Can you give more detail?

Jason
Andreas Schwab June 20, 2017, 7:45 p.m. UTC | #3
On Jun 20 2017, Jason Merrill <jason@redhat.com> wrote:

> On Tue, Jun 20, 2017 at 5:40 AM, Andreas Schwab <schwab@suse.de> wrote:
>> FAIL: g++.dg/cpp0x/constexpr-cast.C  -std=c++11  (test for errors, line 10)
>> FAIL: g++.dg/cpp0x/constexpr-cast.C  -std=c++11 (test for excess errors)
>> FAIL: g++.dg/cpp0x/constexpr-cast.C  -std=c++14  (test for errors, line 10)
>> FAIL: g++.dg/cpp0x/constexpr-cast.C  -std=c++14 (test for excess errors)
>
> I'm not seeing this.  Can you give more detail?

http://gcc.gnu.org/ml/gcc-testresults/2017-06/msg02172.html

Andreas.
diff mbox

Patch

diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index ae24e40..569a247 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -5212,10 +5212,11 @@  potential_constant_expression_1 (tree t, bool want_rval, bool strict,
       if (want_rval
 	  && !var_in_maybe_constexpr_fn (t)
 	  && !type_dependent_expression_p (t)
-	  && !decl_constant_var_p (t)
+	  && !decl_maybe_constant_var_p (t)
 	  && (strict
 	      || !CP_TYPE_CONST_NON_VOLATILE_P (TREE_TYPE (t))
-	      || !DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (t))
+	      || (DECL_INITIAL (t)
+		  && !DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (t)))
 	  && COMPLETE_TYPE_P (TREE_TYPE (t))
 	  && !is_really_empty_class (TREE_TYPE (t)))
         {
@@ -5540,21 +5541,21 @@  potential_constant_expression_1 (tree t, bool want_rval, bool strict,
 	    {
 	      if (flags & tf_error)
 		error_at (DECL_SOURCE_LOCATION (tmp), "%qD declared "
-			  "%<static%> in %<constexpr%> function", tmp);
+			  "%<static%> in %<constexpr%> context", tmp);
 	      return false;
 	    }
 	  else if (CP_DECL_THREAD_LOCAL_P (tmp))
 	    {
 	      if (flags & tf_error)
 		error_at (DECL_SOURCE_LOCATION (tmp), "%qD declared "
-			  "%<thread_local%> in %<constexpr%> function", tmp);
+			  "%<thread_local%> in %<constexpr%> context", tmp);
 	      return false;
 	    }
 	  else if (!DECL_NONTRIVIALLY_INITIALIZED_P (tmp))
 	    {
 	      if (flags & tf_error)
 		error_at (DECL_SOURCE_LOCATION (tmp), "uninitialized "
-			  "variable %qD in %<constexpr%> function", tmp);
+			  "variable %qD in %<constexpr%> context", tmp);
 	      return false;
 	    }
 	}
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 72239ec..a475146 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -4145,10 +4145,19 @@  decl_maybe_constant_var_p (tree decl)
     /* A proxy isn't constant.  */
     return false;
   if (TREE_CODE (type) == REFERENCE_TYPE)
-    /* References can be constant.  */
+    /* References can be constant.  */;
+  else if (CP_TYPE_CONST_NON_VOLATILE_P (type)
+	   && INTEGRAL_OR_ENUMERATION_TYPE_P (type))
+    /* And const integers.  */;
+  else
+    return false;
+
+  if (DECL_INITIAL (decl)
+      && !DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl))
+    /* We know the initializer, and it isn't constant.  */
+    return false;
+  else
     return true;
-  return (CP_TYPE_CONST_NON_VOLATILE_P (type)
-	  && INTEGRAL_OR_ENUMERATION_TYPE_P (type));
 }
 
 /* Complain that DECL uses a type with no linkage.  In C++98 mode this is
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index e5238ad..69ca929 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -6585,10 +6585,10 @@  convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
 	  if (complain & tf_error)
 	    {
 	      int errs = errorcount, warns = warningcount + werrorcount;
-	      if (processing_template_decl
-		  && !require_potential_constant_expression (expr))
-		return NULL_TREE;
-	      expr = cxx_constant_value (expr);
+	      if (!require_potential_constant_expression (expr))
+		expr = error_mark_node;
+	      else
+		expr = cxx_constant_value (expr);
 	      if (errorcount > errs || warningcount + werrorcount > warns)
 		inform (loc, "in template argument for type %qT ", type);
 	      if (expr == error_mark_node)
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index 4623d6d..430ba30 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -821,8 +821,7 @@  store_init_value (tree decl, tree init, vec<tree, va_gc>** cleanups, int flags)
 	  || (DECL_IN_AGGR_P (decl) && !DECL_VAR_DECLARED_INLINE_P (decl)))
 	{
 	  /* Diagnose a non-constant initializer for constexpr.  */
-	  if (processing_template_decl
-	      && !require_potential_constant_expression (value))
+	  if (!require_potential_constant_expression (value))
 	    value = error_mark_node;
 	  else
 	    value = cxx_constant_value (value, decl);
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-diag1.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-diag1.C
index 450a0b5..ccb8d81 100644
--- a/gcc/testsuite/g++.dg/cpp0x/constexpr-diag1.C
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-diag1.C
@@ -16,5 +16,5 @@  constexpr int i = ai.f();
 constexpr int b = A<B>().f();	// { dg-error "" }
 
 template <class T>
-constexpr int f (T t) { return 42; } // { dg-error "parameter" }
-constexpr int x = f(B());	     // { dg-error "constexpr" }
+constexpr int f (T t) { return 42; }
+constexpr int x = f(B());	     // { dg-error "non-literal" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-trivial2.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-trivial2.C
index d241114..005f07b 100644
--- a/gcc/testsuite/g++.dg/cpp0x/constexpr-trivial2.C
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-trivial2.C
@@ -10,5 +10,5 @@  struct T
 
 int main()
 {
-    constexpr T t = (T{} = T{});
+    constexpr T t = (T{} = T{}); // { dg-error "" "" { target c++11_only } }
 }
diff --git a/gcc/testsuite/g++.dg/ext/stmtexpr19.C b/gcc/testsuite/g++.dg/ext/stmtexpr19.C
new file mode 100644
index 0000000..0c19a21
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/stmtexpr19.C
@@ -0,0 +1,17 @@ 
+// PR c++/81073
+// { dg-options "" }
+// { dg-do compile { target c++11 } }
+
+struct test { const int *addr; };
+
+const test* setup()
+{
+  static constexpr test atest =
+    {
+      ({ static const int inner = 123; &inner; }) // { dg-error "static" }
+    };
+
+  return &atest;
+}
+
+int main(){}