[pushed] c++: constexpr and -fno-elide-constructors [PR101072]

Message ID 20220123031837.685619-1-jason@redhat.com
State Committed
Headers
Series [pushed] c++: constexpr and -fno-elide-constructors [PR101072] |

Commit Message

Jason Merrill Jan. 23, 2022, 3:18 a.m. UTC
  We've been trying for a while to avoid TARGET_EXPRs in template code, but
there were still a few that snuck through, and the one in this case broke
the code that tried to handle it.  Fixed by using IMPLICIT_CONV_EXPR, as we
have done elsewhere.

I also noticed that finish_compound_literal was assuming that all T{init}
were for aggregate T, and we got a few more TARGET_EXPRs from that.  Fixed
by only messing with TARGET_EXPR if we actually have an aggregate init.

Tested x86_64-pc-linux-gnu, applying to trunk.

	PR c++/101072

gcc/cp/ChangeLog:

	* cp-tree.h (build_implicit_conv_flags): Declare.
	* call.cc (build_implicit_conv_flags): Split out from...
	(perform_implicit_conversion_flags): ...here.
	* decl.cc (check_initializer): Use it.
	* pt.cc (tsubst_copy_and_build): Remove TARGET_EXPR handling.
	* semantics.cc (finish_compound_literal): Don't treat
	scalar values like CONSTRUCTORs.

gcc/testsuite/ChangeLog:

	* g++.dg/cpp0x/constexpr-empty14a.C: New test.
---
 gcc/cp/cp-tree.h                              |  1 +
 gcc/cp/call.cc                                | 32 ++++++++++++-------
 gcc/cp/decl.cc                                |  7 +++-
 gcc/cp/pt.cc                                  |  9 ------
 gcc/cp/semantics.cc                           |  9 ++++--
 .../g++.dg/cpp0x/constexpr-empty14a.C         | 11 +++++++
 6 files changed, 45 insertions(+), 24 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-empty14a.C


base-commit: d43be9dcc1bef95d70fb411d98b4de0d83c6b85d
  

Patch

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 186c54424a6..b9eb71fbc3a 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -6599,6 +6599,7 @@  extern tree strip_top_quals			(tree);
 extern bool reference_related_p			(tree, tree);
 extern bool reference_compatible_p		(tree, tree);
 extern int remaining_arguments			(tree);
+extern tree build_implicit_conv_flags		(tree, tree, int);
 extern tree perform_implicit_conversion		(tree, tree, tsubst_flags_t);
 extern tree perform_implicit_conversion_flags	(tree, tree, tsubst_flags_t, int);
 extern tree build_converted_constant_expr	(tree, tree, tsubst_flags_t);
diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index d4a07a7a9b3..f7f861cd16e 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -12638,6 +12638,25 @@  can_convert_arg_bad (tree to, tree from, tree arg, int flags,
   return t != NULL;
 }
 
+/* Return an IMPLICIT_CONV_EXPR from EXPR to TYPE with bits set from overload
+   resolution FLAGS.  */
+
+tree
+build_implicit_conv_flags (tree type, tree expr, int flags)
+{
+  /* In a template, we are only concerned about determining the
+     type of non-dependent expressions, so we do not have to
+     perform the actual conversion.  But for initializers, we
+     need to be able to perform it at instantiation
+     (or instantiate_non_dependent_expr) time.  */
+  expr = build1 (IMPLICIT_CONV_EXPR, type, expr);
+  if (!(flags & LOOKUP_ONLYCONVERTING))
+    IMPLICIT_CONV_EXPR_DIRECT_INIT (expr) = true;
+  if (flags & LOOKUP_NO_NARROWING)
+    IMPLICIT_CONV_EXPR_BRACED_INIT (expr) = true;
+  return expr;
+}
+
 /* Convert EXPR to TYPE.  Return the converted expression.
 
    Note that we allow bad conversions here because by the time we get to
@@ -12674,18 +12693,7 @@  perform_implicit_conversion_flags (tree type, tree expr,
       expr = error_mark_node;
     }
   else if (processing_template_decl && conv->kind != ck_identity)
-    {
-      /* In a template, we are only concerned about determining the
-	 type of non-dependent expressions, so we do not have to
-	 perform the actual conversion.  But for initializers, we
-	 need to be able to perform it at instantiation
-	 (or instantiate_non_dependent_expr) time.  */
-      expr = build1 (IMPLICIT_CONV_EXPR, type, expr);
-      if (!(flags & LOOKUP_ONLYCONVERTING))
-	IMPLICIT_CONV_EXPR_DIRECT_INIT (expr) = true;
-      if (flags & LOOKUP_NO_NARROWING)
-	IMPLICIT_CONV_EXPR_BRACED_INIT (expr) = true;
-    }
+    expr = build_implicit_conv_flags (type, expr, flags);
   else
     {
       /* Give a conversion call the same location as expr.  */
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 8e5421848d1..c5d4f2f5369 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -7235,7 +7235,12 @@  check_initializer (tree decl, tree init, int flags, vec<tree, va_gc> **cleanups)
 	      /* In C++20, the call to build_aggr_init could have created
 		 an INIT_EXPR with a CONSTRUCTOR as the RHS to handle
 		 A(1, 2).  */
-	      init = TREE_OPERAND (init_code, 1);
+	      tree rhs = TREE_OPERAND (init_code, 1);
+	      if (processing_template_decl && TREE_CODE (rhs) == TARGET_EXPR)
+		/* Avoid leaking TARGET_EXPR into template trees.  */
+		rhs = build_implicit_conv_flags (type, init, flags);
+	      init = rhs;
+
 	      init_code = NULL_TREE;
 	      /* Don't call digest_init; it's unnecessary and will complain
 		 about aggregate initialization of non-aggregate classes.  */
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 5afcb41eccd..bba62a5800a 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -21151,15 +21151,6 @@  tsubst_copy_and_build (tree t,
 	RETURN (build_lambda_object (r));
       }
 
-    case TARGET_EXPR:
-      /* We can get here for a constant initializer of non-dependent type.
-         FIXME stop folding in cp_parser_initializer_clause.  */
-      {
-	tree r = get_target_expr_sfinae (RECUR (TARGET_EXPR_INITIAL (t)),
-					 complain);
-	RETURN (r);
-      }
-
     case TRANSACTION_EXPR:
       RETURN (tsubst_expr(t, args, complain, in_decl,
 	     integral_constant_expression_p));
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 640b2d75471..07c2b3393be 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -3272,12 +3272,17 @@  finish_compound_literal (tree type, tree compound_literal,
 
   /* Represent other compound literals with TARGET_EXPR so we produce
      a prvalue, and can elide copies.  */
-  if (!VECTOR_TYPE_P (type))
+  if (TREE_CODE (compound_literal) == CONSTRUCTOR
+      || TREE_CODE (compound_literal) == VEC_INIT_EXPR)
     {
       /* The CONSTRUCTOR is now an initializer, not a compound literal.  */
-      TREE_HAS_CONSTRUCTOR (compound_literal) = false;
+      if (TREE_CODE (compound_literal) == CONSTRUCTOR)
+	TREE_HAS_CONSTRUCTOR (compound_literal) = false;
       compound_literal = get_target_expr_sfinae (compound_literal, complain);
     }
+  else
+    /* For e.g. int{42} just make sure it's a prvalue.  */
+    compound_literal = rvalue (compound_literal);
 
   return compound_literal;
 }
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-empty14a.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-empty14a.C
new file mode 100644
index 00000000000..df34cfcb8e7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-empty14a.C
@@ -0,0 +1,11 @@ 
+// PR c++/101072
+// { dg-do compile { target c++11 } }
+// { dg-additional-options -fno-elide-constructors }
+
+struct S {};
+
+template <class T> void
+foo (S s)
+{
+  constexpr S x = s;
+}