This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[C++ PATCH] Fix PLACEHOLDER_EXPR handling (PR c++/79937, PR c++/82410)


Hi!

The following patch is an attempt to fix PLACEHOLDER_EXPR handling.
As e.g.
struct Y
{
  static Y bar (Y y) { return y; }
  int i;
  int n = bar (Y{2,i}).m + bar {Y{2,i,i}).n;
  int m = i;
};
is rejected - one can't use incomplete ctors which would need NSDMIs
until the class is defined, I believe PLACEHOLDER_EXPRs can't be arbitrarily
intermixed, rather some CONSTRUCTORs into which we've added the NSDMI
expressions can contain PLACEHOLDER_EXPRs and other PLACEHOLDER_EXPRs can be
only found inside such CONSTRUCTORs added earlier.

So, this patch adds a new flag on CONSTRUCTORs, which acts as a barrier
boundary for replace_placeholders, where we replace just PLACEHOLDER_EXPRs
from the outermost expressions and don't dive into CONSTRUCTORs into which
we've added other PLACEHOLDER_EXPRs - those will be handled later on
separately, by cp_gimplify_init_expr calling replace_placeholders.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2018-03-14  Jakub Jelinek  <jakub@redhat.com>

	PR c++/79937
	PR c++/82410
	* cp-tree.h (CONSTRUCTOR_PLACEHOLDER_BOUNDARY): Define.
	(find_placeholder): Declare.
	* tree.c (struct replace_placeholders_t): Add exp member.
	(replace_placeholders_r): Don't walk into ctors with
	CONSTRUCTOR_PLACEHOLDER_BOUNDARY flag set, unless they are equal to
	d->exp.
	(replace_placeholders): Initialize data.exp.
	(find_placeholders_r, find_placeholders): New functions.
	* typeck2.c (process_init_constructor_record,
	process_init_constructor_union): Set CONSTRUCTOR_PLACEHOLDER_BOUNDARY
	if adding NSDMI on which find_placeholder returns true.

	* g++.dg/cpp1y/pr79937-1.C: New test.
	* g++.dg/cpp1y/pr79937-2.C: New test.
	* g++.dg/cpp1y/pr79937-3.C: New test.
	* g++.dg/cpp1y/pr79937-4.C: New test.
	* g++.dg/cpp1y/pr82410.C: New test.

--- gcc/cp/cp-tree.h.jj	2018-03-14 16:21:50.745925263 +0100
+++ gcc/cp/cp-tree.h	2018-03-14 15:57:51.171323825 +0100
@@ -425,6 +425,7 @@ extern GTY(()) tree cp_global_trees[CPTI
       DECL_VTABLE_OR_VTT_P (in VAR_DECL)
       FUNCTION_RVALUE_QUALIFIED (in FUNCTION_TYPE, METHOD_TYPE)
       CALL_EXPR_REVERSE_ARGS (in CALL_EXPR, AGGR_INIT_EXPR)
+      CONSTRUCTOR_PLACEHOLDER_BOUNDARY (in CONSTRUCTOR)
    6: IDENTIFIER_REPO_CHOSEN (in IDENTIFIER_NODE)
       DECL_CONSTRUCTION_VTABLE_P (in VAR_DECL)
       TYPE_MARKED_P (in _TYPE)
@@ -4144,6 +4145,12 @@ more_aggr_init_expr_args_p (const aggr_i
 #define CONSTRUCTOR_C99_COMPOUND_LITERAL(NODE) \
   (TREE_LANG_FLAG_3 (CONSTRUCTOR_CHECK (NODE)))
 
+/* True if this CONSTRUCTOR contains PLACEHOLDER_EXPRs referencing the
+   CONSTRUCTOR's type not nested inside another CONSTRUCTOR marked with
+   CONSTRUCTOR_PLACEHOLDER_BOUNDARY.  */
+#define CONSTRUCTOR_PLACEHOLDER_BOUNDARY(NODE) \
+  (TREE_LANG_FLAG_5 (CONSTRUCTOR_CHECK (NODE)))
+
 #define DIRECT_LIST_INIT_P(NODE) \
    (BRACE_ENCLOSED_INITIALIZER_P (NODE) && CONSTRUCTOR_IS_DIRECT_INIT (NODE))
 
@@ -7021,6 +7028,7 @@ extern tree array_type_nelts_top		(tree)
 extern tree break_out_target_exprs		(tree);
 extern tree build_ctor_subob_ref		(tree, tree, tree);
 extern tree replace_placeholders		(tree, tree, bool * = NULL);
+extern bool find_placeholders			(tree);
 extern tree get_type_decl			(tree);
 extern tree decl_namespace_context		(tree);
 extern bool decl_anon_ns_mem_p			(const_tree);
--- gcc/cp/tree.c.jj	2018-03-14 11:49:58.926816421 +0100
+++ gcc/cp/tree.c	2018-03-14 16:24:29.036987505 +0100
@@ -3096,6 +3096,7 @@ build_ctor_subob_ref (tree index, tree t
 struct replace_placeholders_t
 {
   tree obj;	    /* The object to be substituted for a PLACEHOLDER_EXPR.  */
+  tree exp;	    /* The outermost exp.  */
   bool seen;	    /* Whether we've encountered a PLACEHOLDER_EXPR.  */
   hash_set<tree> *pset;	/* To avoid walking same trees multiple times.  */
 };
@@ -3134,7 +3135,12 @@ replace_placeholders_r (tree* t, int* wa
       {
 	constructor_elt *ce;
 	vec<constructor_elt,va_gc> *v = CONSTRUCTOR_ELTS (*t);
-	if (d->pset->add (*t))
+	/* Don't walk into CONSTRUCTOR_PLACEHOLDER_BOUNDARY ctors
+	   other than the d->exp one, those have PLACEHOLDER_EXPRs
+	   related to another object.  */
+	if ((CONSTRUCTOR_PLACEHOLDER_BOUNDARY (*t)
+	     && *t != d->exp)
+	    || d->pset->add (*t))
 	  {
 	    *walk_subtrees = false;
 	    return NULL_TREE;
@@ -3192,16 +3198,70 @@ replace_placeholders (tree exp, tree obj
     return exp;
 
   tree *tp = &exp;
-  hash_set<tree> pset;
-  replace_placeholders_t data = { obj, false, &pset };
+  /* Use exp instead of *(type *)&exp.  */
+  while (TREE_CODE (exp) == INDIRECT_REF)
+    {
+      tree t = TREE_OPERAND (exp, 0);
+      STRIP_NOPS (t);
+      if (TREE_CODE (t) == ADDR_EXPR
+	  && (t = TREE_OPERAND (t, 0))
+	  && same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (exp),
+							TREE_TYPE (t)))
+	exp = t;
+      else
+	break;
+    }
   if (TREE_CODE (exp) == TARGET_EXPR)
     tp = &TARGET_EXPR_INITIAL (exp);
+  hash_set<tree> pset;
+  replace_placeholders_t data = { obj, *tp, false, &pset };
   cp_walk_tree (tp, replace_placeholders_r, &data, NULL);
   if (seen_p)
     *seen_p = data.seen;
   return exp;
 }
 
+/* Callback function for find_placeholders.  */
+
+static tree
+find_placeholders_r (tree *t, int *walk_subtrees, void *)
+{
+  if (TYPE_P (*t) || TREE_CONSTANT (*t))
+    {
+      *walk_subtrees = false;
+      return NULL_TREE;
+    }
+
+  switch (TREE_CODE (*t))
+    {
+    case PLACEHOLDER_EXPR:
+      return *t;
+
+    case CONSTRUCTOR:
+      if (CONSTRUCTOR_PLACEHOLDER_BOUNDARY (*t))
+	*walk_subtrees = false;
+      break;
+
+    default:
+      break;
+    }
+
+  return NULL_TREE;
+}
+
+/* Return true if EXP contains a PLACEHOLDER_EXPR.  Don't walk into
+   ctors with CONSTRUCTOR_PLACEHOLDER_BOUNDARY flag set.  */
+
+bool
+find_placeholders (tree exp)
+{
+  /* This is only relevant for C++14.  */
+  if (cxx_dialect < cxx14)
+    return false;
+
+  return cp_walk_tree_without_duplicates (&exp, find_placeholders_r, NULL);
+}
+
 /* Similar to `build_nt', but for template definitions of dependent
    expressions  */
 
--- gcc/cp/typeck2.c.jj	2018-03-14 16:25:49.622019191 +0100
+++ gcc/cp/typeck2.c	2018-03-14 16:02:36.093441530 +0100
@@ -1470,6 +1470,9 @@ process_init_constructor_record (tree ty
 	    }
 	  /* C++14 aggregate NSDMI.  */
 	  next = get_nsdmi (field, /*ctor*/false, complain);
+	  if (!CONSTRUCTOR_PLACEHOLDER_BOUNDARY (init)
+	      && find_placeholders (next))
+	    CONSTRUCTOR_PLACEHOLDER_BOUNDARY (init) = 1;
 	}
       else if (type_build_ctor_call (TREE_TYPE (field)))
 	{
@@ -1608,10 +1611,11 @@ process_init_constructor_union (tree typ
 	  if (TREE_CODE (field) == FIELD_DECL
 	      && DECL_INITIAL (field) != NULL_TREE)
 	    {
-	      CONSTRUCTOR_APPEND_ELT (CONSTRUCTOR_ELTS (init),
-				      field,
-				      get_nsdmi (field, /*in_ctor=*/false,
-						 complain));
+	      tree val = get_nsdmi (field, /*in_ctor=*/false, complain);
+	      if (!CONSTRUCTOR_PLACEHOLDER_BOUNDARY (init)
+		  && find_placeholders (val))
+		CONSTRUCTOR_PLACEHOLDER_BOUNDARY (init) = 1;
+	      CONSTRUCTOR_APPEND_ELT (CONSTRUCTOR_ELTS (init), field, val);
 	      break;
 	    }
 	}
--- gcc/testsuite/g++.dg/cpp1y/pr79937-1.C.jj	2018-03-14 14:32:12.230097853 +0100
+++ gcc/testsuite/g++.dg/cpp1y/pr79937-1.C	2018-03-14 14:32:12.230097853 +0100
@@ -0,0 +1,23 @@
+// PR c++/79937
+// { dg-do run { target c++14 } }
+
+struct C {};
+
+struct X {
+  unsigned i;
+  unsigned n = i;
+};
+
+C
+bar (X x)
+{
+  if (x.i != 1 || x.n != 1)
+    __builtin_abort ();
+  return {};
+}
+
+int
+main ()
+{
+  C c = bar (X {1});
+}
--- gcc/testsuite/g++.dg/cpp1y/pr79937-2.C.jj	2018-03-14 14:32:12.231097853 +0100
+++ gcc/testsuite/g++.dg/cpp1y/pr79937-2.C	2018-03-14 14:32:12.231097853 +0100
@@ -0,0 +1,24 @@
+// PR c++/79937
+// { dg-do run { target c++14 } }
+
+struct C {};
+
+struct X {
+  unsigned i;
+  unsigned n = i;
+  unsigned m = i;
+};
+
+C
+bar (X x)
+{
+  if (x.i != 1 || x.n != 2 || x.m != 1)
+    __builtin_abort ();
+  return {};
+}
+
+int
+main ()
+{
+  C c = bar (X {1, X {2}.n});
+}
--- gcc/testsuite/g++.dg/cpp1y/pr79937-3.C.jj	2018-03-14 14:32:12.231097853 +0100
+++ gcc/testsuite/g++.dg/cpp1y/pr79937-3.C	2018-03-14 14:32:12.231097853 +0100
@@ -0,0 +1,24 @@
+// PR c++/79937
+// { dg-do run { target c++14 } }
+
+struct X {
+  unsigned i;
+  unsigned n = i;
+  unsigned m = i;
+};
+
+X
+bar (X x)
+{
+  if (x.i != 1 || x.n != 2 || x.m != 1)
+    __builtin_abort ();
+  return x;
+}
+
+int
+main ()
+{
+  X x = bar (X {1, X {2}.n});
+  if (x.i != 1 || x.n != 2 || x.m != 1)
+    __builtin_abort ();
+}
--- gcc/testsuite/g++.dg/cpp1y/pr79937-4.C.jj	2018-03-14 16:14:50.842757308 +0100
+++ gcc/testsuite/g++.dg/cpp1y/pr79937-4.C	2018-03-14 16:14:45.761755127 +0100
@@ -0,0 +1,32 @@
+// PR c++/79937
+// { dg-do run { target c++14 } }
+
+struct X {
+  unsigned i;
+  unsigned n = i;
+};
+
+X
+bar (X x)
+{
+  return x;
+}
+
+struct Y
+{
+  static Y bar (Y y) { return y; }
+  unsigned i;
+  unsigned n = bar (Y{2,i}).n;
+};
+
+int
+main ()
+{
+  X x { 1, bar (X{2}).n };
+  if (x.n != 2)
+    __builtin_abort ();
+
+  Y y { 1 };
+  if (y.n != 1)
+    __builtin_abort ();
+}
--- gcc/testsuite/g++.dg/cpp1y/pr82410.C.jj	2018-03-14 16:20:07.180884544 +0100
+++ gcc/testsuite/g++.dg/cpp1y/pr82410.C	2018-03-14 16:20:01.626882356 +0100
@@ -0,0 +1,16 @@
+// PR c++/82410
+// { dg-do compile { target c++14 } }
+
+int
+main ()
+{
+  struct A {};
+  struct S
+  {
+    int & p;
+    int x = p;
+    operator A () { return {}; }
+  };
+  int l;
+  [] (A) {} (S{l});
+}

	Jakub


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]