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 <ja...@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. 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)
commit 9686efb0957204545ff407b1e4a477da5fc16c4e Author: Jason Merrill <ja...@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 <ja...@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)