Patchwork C++ PATCHes for c++/48535 (SFINAE with T{})

login
register
mail settings
Submitter Jason Merrill
Date April 11, 2011, 9:57 p.m.
Message ID <4DA37967.1050403@redhat.com>
Download mbox | patch
Permalink /patch/90663/
State New
Headers show

Comments

Jason Merrill - April 11, 2011, 9:57 p.m.
To make the 48535 testcase work I needed to fix three separate issues:

1) build_compound_literal wasn't sfinae-enabled.
2) build_compound_literal didn't handle list-initialization of references.
3) We weren't dealing properly with invalid array initialization.

Tested x86_64-pc-linux-gnu, applying to trunk.
commit c239f55a59d00fcba928ceef721dc0aeba737fd7
Author: Jason Merrill <jason@redhat.com>
Date:   Sun Apr 10 14:27:54 2011 -0400

    	PR c++/48535
    	* semantics.c (finish_compound_literal): Take complain parm.
    	(build_lambda_object): Adjust.
    	* cp-tree.h: Adjust.
    	* call.c (convert_like_real): Adjust.
    	* decl.c (check_initializer): Adjust.
    	* parser.c (cp_parser_postfix_expression): Adjust.
    	(cp_parser_functional_cast): Adjust.
    	* pt.c (tsubst_copy_and_build): Adjust.
    	* typeck2.c (process_init_constructor_record): Adjust.
commit 9686efb0957204545ff407b1e4a477da5fc16c4e
Author: Jason Merrill <jason@redhat.com>
Date:   Mon Apr 11 12:15:27 2011 -0400

    	PR c++/48535
    	* semantics.c (finish_compound_literal): Handle references.

diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index e08ddb3..461aa0a 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -2315,6 +2315,14 @@ finish_compound_literal (tree type, tree compound_literal,
   if (type == error_mark_node)
     return error_mark_node;
 
+  if (TREE_CODE (type) == REFERENCE_TYPE)
+    {
+      compound_literal
+	= finish_compound_literal (TREE_TYPE (type), compound_literal,
+				   complain);
+      return cp_build_c_cast (type, compound_literal, complain);
+    }
+
   if (!TYPE_OBJ_P (type))
     {
       if (complain & tf_error)
commit bb89d1c05d23fefe0eab8688cdd16a4dc4a0b713
Author: Jason Merrill <jason@redhat.com>
Date:   Mon Apr 11 14:56:50 2011 -0400

    	PR c++/48535
    	* decl.c (cp_complete_array_type_or_error): New.
    	* semantics.c (finish_compound_literal): Use it.
    	* cp-tree.h: Declare it.

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 44a20ea..4321d28 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -4791,6 +4791,7 @@ extern void start_decl_1			(tree, bool);
 extern bool check_array_initializer		(tree, tree, tree);
 extern void cp_finish_decl			(tree, tree, bool, tree, int);
 extern int cp_complete_array_type		(tree *, tree, bool);
+extern int cp_complete_array_type_or_error	(tree *, tree, bool, tsubst_flags_t);
 extern tree build_ptrmemfunc_type		(tree);
 extern tree build_ptrmem_type			(tree, tree);
 /* the grokdeclarator prototype is in decl.h */
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 1393b67..ec45993 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -6691,6 +6691,39 @@ cp_complete_array_type (tree *ptype, tree initial_value, bool do_default)
 
   return failure;
 }
+
+/* As above, but either give an error or reject zero-size arrays, depending
+   on COMPLAIN.  */
+
+int
+cp_complete_array_type_or_error (tree *ptype, tree initial_value,
+				 bool do_default, tsubst_flags_t complain)
+{
+  int failure;
+  bool sfinae = !(complain & tf_error);
+  /* In SFINAE context we can't be lenient about zero-size arrays.  */
+  if (sfinae)
+    ++pedantic;
+  failure = cp_complete_array_type (ptype, initial_value, do_default);
+  if (sfinae)
+    --pedantic;
+  if (failure)
+    {
+      if (sfinae)
+	/* Not an error.  */;
+      else if (failure == 1)
+	error ("initializer fails to determine size of %qT", *ptype);
+      else if (failure == 2)
+	{
+	  if (do_default)
+	    error ("array size missing in %qT", *ptype);
+	}
+      else if (failure == 3)
+	error ("zero-size array %qT", *ptype);
+      *ptype = error_mark_node;
+    }
+  return failure;
+}
 
 /* Return zero if something is declared to be a member of type
    CTYPE when in the context of CUR_TYPE.  STRING is the error
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 461aa0a..61d87be 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -2355,8 +2355,14 @@ finish_compound_literal (tree type, tree compound_literal,
       && check_array_initializer (NULL_TREE, type, compound_literal))
     return error_mark_node;
   compound_literal = reshape_init (type, compound_literal);
-  if (TREE_CODE (type) == ARRAY_TYPE)
-    cp_complete_array_type (&type, compound_literal, false);
+  if (TREE_CODE (type) == ARRAY_TYPE
+      && TYPE_DOMAIN (type) == NULL_TREE)
+    {
+      cp_complete_array_type_or_error (&type, compound_literal,
+				       false, complain);
+      if (type == error_mark_node)
+	return error_mark_node;
+    }
   compound_literal = digest_init (type, compound_literal);
   /* Put static/constant array temporaries in static variables, but always
      represent class temporaries with TARGET_EXPR so we elide copies.  */
diff --git a/gcc/testsuite/g++.dg/cpp0x/sfinae12.C b/gcc/testsuite/g++.dg/cpp0x/sfinae12.C
new file mode 100644
index 0000000..114f1b4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/sfinae12.C
@@ -0,0 +1,18 @@
+// PR c++/48535
+// { dg-options -std=c++0x }
+
+template<class T,
+ class = decltype(T{})
+>
+char f(int);
+
+template<class>
+char (&f(...))[2];
+
+struct A { virtual ~A() = 0; };
+
+static_assert(sizeof(f<A>(0)) != 1, "Error"); // (a)
+static_assert(sizeof(f<void()>(0)) != 1, "Error"); // (b)
+static_assert(sizeof(f<int&>(0)) != 1, "Error"); // (d)
+static_assert(sizeof(f<const int&>(0)) == 1, "Error"); // (e)
+static_assert(sizeof(f<int[]>(0)) != 1, "Error"); // (f)

Patch

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 4d03646..78104b1 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -5495,7 +5495,7 @@  convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
 	elttype = cp_build_qualified_type
 	  (elttype, cp_type_quals (elttype) | TYPE_QUAL_CONST);
 	array = build_array_of_n_type (elttype, len);
-	array = finish_compound_literal (array, new_ctor);
+	array = finish_compound_literal (array, new_ctor, complain);
 
 	/* Build up the initializer_list object.  */
 	totype = complete_type (totype);
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 885b31c..44a20ea 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5297,7 +5297,7 @@  extern tree finish_increment_expr		(tree, enum tree_code);
 extern tree finish_this_expr			(void);
 extern tree finish_pseudo_destructor_expr       (tree, tree, tree);
 extern tree finish_unary_op_expr		(enum tree_code, tree);
-extern tree finish_compound_literal		(tree, tree);
+extern tree finish_compound_literal		(tree, tree, tsubst_flags_t);
 extern tree finish_fname			(tree);
 extern void finish_translation_unit		(void);
 extern tree finish_template_type_parm		(tree, tree);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 6bfc1fd..1393b67 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -5397,7 +5397,8 @@  check_initializer (tree decl, tree init, int flags, tree *cleanup)
 		 init appropriately so we can pass it into store_init_value
 		 for the error.  */
 	      if (init && BRACE_ENCLOSED_INITIALIZER_P (init))
-		init = finish_compound_literal (type, init);
+		init = finish_compound_literal (type, init,
+						tf_warning_or_error);
 	      else if (CLASS_TYPE_P (type)
 		       && (!init || TREE_CODE (init) == TREE_LIST))
 		{
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 607e9b8..8414ab8 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -4897,7 +4897,8 @@  cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
 		postfix_expression
 		  = (finish_compound_literal
 		     (type, build_constructor (init_list_type_node,
-					       initializer_list)));
+					       initializer_list),
+		      tf_warning_or_error));
 		break;
 	      }
 	  }
@@ -19936,7 +19937,8 @@  cp_parser_functional_cast (cp_parser* parser, tree type)
       CONSTRUCTOR_IS_DIRECT_INIT (expression_list) = 1;
       if (TREE_CODE (type) == TYPE_DECL)
 	type = TREE_TYPE (type);
-      return finish_compound_literal (type, expression_list);
+      return finish_compound_literal (type, expression_list,
+				      tf_warning_or_error);
     }
 
 
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 86274e9..208ff2b 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -13262,7 +13262,7 @@  tsubst_copy_and_build (tree t,
 	CONSTRUCTOR_IS_DIRECT_INIT (r) = CONSTRUCTOR_IS_DIRECT_INIT (t);
 
 	if (TREE_HAS_CONSTRUCTOR (t))
-	  return finish_compound_literal (type, r);
+	  return finish_compound_literal (type, r, complain);
 
 	TREE_TYPE (r) = type;
 	return r;
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 0b4d1ec..e08ddb3 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -2309,14 +2309,16 @@  finish_unary_op_expr (enum tree_code code, tree expr)
    the CONSTRUCTOR in COMPOUND_LITERAL is being cast.  */
 
 tree
-finish_compound_literal (tree type, tree compound_literal)
+finish_compound_literal (tree type, tree compound_literal,
+			 tsubst_flags_t complain)
 {
   if (type == error_mark_node)
     return error_mark_node;
 
   if (!TYPE_OBJ_P (type))
     {
-      error ("compound literal of non-object type %qT", type);
+      if (complain & tf_error)
+	error ("compound literal of non-object type %qT", type);
       return error_mark_node;
     }
 
@@ -2338,7 +2340,7 @@  finish_compound_literal (tree type, tree compound_literal)
 	 that it came from T{} rather than T({}).  */
       CONSTRUCTOR_IS_DIRECT_INIT (compound_literal) = 1;
       compound_literal = build_tree_list (NULL_TREE, compound_literal);
-      return build_functional_cast (type, compound_literal, tf_error);
+      return build_functional_cast (type, compound_literal, complain);
     }
 
   if (TREE_CODE (type) == ARRAY_TYPE
@@ -7928,7 +7930,7 @@  build_lambda_object (tree lambda_expr)
      But we briefly treat it as an aggregate to make this simpler.  */
   type = TREE_TYPE (lambda_expr);
   CLASSTYPE_NON_AGGREGATE (type) = 0;
-  expr = finish_compound_literal (type, expr);
+  expr = finish_compound_literal (type, expr, tf_warning_or_error);
   CLASSTYPE_NON_AGGREGATE (type) = 1;
 
  out:
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index f67073b..20b47d5 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -1126,7 +1126,8 @@  process_init_constructor_record (tree type, tree init)
 	  next = build_constructor (init_list_type_node, NULL);
 	  if (MAYBE_CLASS_TYPE_P (TREE_TYPE (field)))
 	    {
-	      next = finish_compound_literal (TREE_TYPE (field), next);
+	      next = finish_compound_literal (TREE_TYPE (field), next,
+					      tf_warning_or_error);
 	      /* direct-initialize the target. No temporary is going
 		  to be involved.  */
 	      if (TREE_CODE (next) == TARGET_EXPR)