[PATCH] c++: requires-expression outside of a template is misevaluated [PR94252]

Patrick Palka ppalka@redhat.com
Wed Mar 25 16:54:22 GMT 2020


On Wed, 25 Mar 2020, Marek Polacek wrote:

> On Wed, Mar 25, 2020 at 12:17:41PM -0400, Patrick Palka via Gcc-patches wrote:
> > diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
> > index 03ecd7838f6..14a22b85318 100644
> > --- a/gcc/cp/parser.c
> > +++ b/gcc/cp/parser.c
> > @@ -27689,7 +27689,12 @@ cp_parser_requires_expression (cp_parser *parser)
> >      else
> >        parms = NULL_TREE;
> >  
> > -    /* Parse the requirement body. */
> > +    /* Always parse the requirement body as if we're inside a template so that
> > +       we always do full semantic processing only during evaluation of this
> > +       requires-expression and not also now during parsing.  */
> > +    processing_template_decl_sentinel ptds;
> 
> This looks weird; this sentinel will always set processing_template_decl to 0,
> right?  So...
> 
> > +    if (!processing_template_decl)
> > +      processing_template_decl = 1;
> 
> ...this will always be true?  Did you mean to use temp_override instead?

Oops, good point.  The intention was to set processing_template_decl to
1 when it is 0, and to otherwise not change it.  So it looks like I
should pass false to processing_template_decl_sentinel's ctor here, like
so.

> 
> I don't dare to say if this approach is OK or not, but I've certainly had
> my share of fun with CALL_EXPRs in templates :).

Hehe :)

-- >8 --

gcc/cp/ChangeLog:

	PR c++/94252
	* parser.c (cp_parser_requires_expression): Always parse the requirement
	body as if we're processing a template, by temporarily setting
	processing_template_decl to non-zero.
	* semantics.c (finish_static_assert): Also explain an assertion failure
	when the condition is a REQUIRES_EXPR.

gcc/testsuite/ChangeLog:

	PR c++/94252
	* g++.dg/concepts/diagnostic7.C: New test.
	* g++.dg/concepts/pr94252.C: New test.
---
 gcc/cp/parser.c                             |  7 ++++++-
 gcc/cp/semantics.c                          |  6 ++++--
 gcc/testsuite/g++.dg/concepts/diagnostic7.C | 12 ++++++++++++
 gcc/testsuite/g++.dg/concepts/pr94252.C     | 14 ++++++++++++++
 4 files changed, 36 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/concepts/diagnostic7.C
 create mode 100644 gcc/testsuite/g++.dg/concepts/pr94252.C

diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 03ecd7838f6..6150814ea9e 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -27689,7 +27689,12 @@ cp_parser_requires_expression (cp_parser *parser)
     else
       parms = NULL_TREE;
 
-    /* Parse the requirement body. */
+    /* Always parse the requirement body as if we're inside a template so that
+       we always do full semantic processing only during evaluation of this
+       requires-expression and not also now during parsing.  */
+    processing_template_decl_sentinel ptds (false);
+    if (!processing_template_decl)
+      processing_template_decl = 1;
     reqs = cp_parser_requirement_body (parser);
     if (reqs == error_mark_node)
       return error_mark_node;
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index bcb2e72fbb5..e998b373af4 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -9691,8 +9691,10 @@ finish_static_assert (tree condition, tree message, location_t location,
             error ("static assertion failed: %s",
 		   TREE_STRING_POINTER (message));
 
-	  /* Actually explain the failure if this is a concept check.  */
-	  if (concept_check_p (orig_condition))
+	  /* Actually explain the failure if this is a concept check or a
+	     requires-expression.  */
+	  if (concept_check_p (orig_condition)
+	      || TREE_CODE (orig_condition) == REQUIRES_EXPR)
 	    diagnose_constraints (location, orig_condition, NULL_TREE);
 	}
       else if (condition && condition != error_mark_node)
diff --git a/gcc/testsuite/g++.dg/concepts/diagnostic7.C b/gcc/testsuite/g++.dg/concepts/diagnostic7.C
new file mode 100644
index 00000000000..f78e9bb8240
--- /dev/null
+++ b/gcc/testsuite/g++.dg/concepts/diagnostic7.C
@@ -0,0 +1,12 @@
+// { dg-do compile { target c++2a } }
+
+template<typename A, typename B>
+  concept same_as = __is_same(A, B); // { dg-message ".void. is not the same as .int." }
+
+void f();
+
+static_assert(requires { { f() } noexcept -> same_as<int>; });
+// { dg-error "static assertion failed" "" { target *-*-* } .-1 }
+// { dg-message "not .noexcept." "" { target *-*-* } .-2 }
+// { dg-message "return-type-requirement" "" { target *-*-* } .-3 }
+// { dg-error "does not satisfy placeholder constraints" "" { target *-*-* } .-4 }
diff --git a/gcc/testsuite/g++.dg/concepts/pr94252.C b/gcc/testsuite/g++.dg/concepts/pr94252.C
new file mode 100644
index 00000000000..7b93997363a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/concepts/pr94252.C
@@ -0,0 +1,14 @@
+// PR c++/94252
+// { dg-do compile { target c++2a } }
+
+auto f = []{ return 0; };
+static_assert(requires { f(); });
+
+template<typename A, typename B>
+  concept same_as = __is_same(A, B);
+
+struct S { int f(int) noexcept; };
+static_assert(requires(S o, int i) {
+  o.f(i);
+  { o.f(i) } noexcept -> same_as<int>;
+});
-- 
2.26.0.rc1.11.g30e9940356



More information about the Gcc-patches mailing list