From: Jason Merrill Date: Wed, 29 Jun 2011 14:34:58 +0000 (-0400) Subject: re PR c++/45923 (constexpr diagnostics, more more) X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=f732fa7b6cd8f125f19aa150d88d47a15e0099cc;p=gcc.git re PR c++/45923 (constexpr diagnostics, more more) PR c++/45923 * class.c (explain_non_literal_class): New. (finalize_literal_type_property): Call it. * cp-tree.h: Declare it. * semantics.c (ensure_literal_type_for_constexpr_object): Call it. (is_valid_constexpr_fn): Likewise. (massage_constexpr_body): Split out from... (register_constexpr_fundef): ...here. (is_instantiation_of_constexpr): New. (expand_or_defer_fn_1): Leave DECL_SAVED_TREE alone in that case. (explain_invalid_constexpr_fn): New. (cxx_eval_call_expression): Call it. (potential_constant_expression_1): Likewise. Avoid redundant errors. * method.c (process_subob_fn): Diagnose non-constexpr. (walk_field_subobs): Likewise. (synthesized_method_walk): Don't shortcut if we want diagnostics. (explain_implicit_non_constexpr): New. (defaulted_late_check): Use it. * call.c (build_cxx_call): Remember location. From-SVN: r175646 --- diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 2cd5c0a4324..db0478a6285 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,25 @@ 2011-06-29 Jason Merrill + PR c++/45923 + * class.c (explain_non_literal_class): New. + (finalize_literal_type_property): Call it. + * cp-tree.h: Declare it. + * semantics.c (ensure_literal_type_for_constexpr_object): Call it. + (is_valid_constexpr_fn): Likewise. + (massage_constexpr_body): Split out from... + (register_constexpr_fundef): ...here. + (is_instantiation_of_constexpr): New. + (expand_or_defer_fn_1): Leave DECL_SAVED_TREE alone in that case. + (explain_invalid_constexpr_fn): New. + (cxx_eval_call_expression): Call it. + (potential_constant_expression_1): Likewise. Avoid redundant errors. + * method.c (process_subob_fn): Diagnose non-constexpr. + (walk_field_subobs): Likewise. + (synthesized_method_walk): Don't shortcut if we want diagnostics. + (explain_implicit_non_constexpr): New. + (defaulted_late_check): Use it. + * call.c (build_cxx_call): Remember location. + * method.c (maybe_explain_implicit_delete): Use pointer_set instead of htab. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index e2d455afcde..56f3408adc6 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -6721,7 +6721,10 @@ build_cxx_call (tree fn, int nargs, tree *argarray) { tree fndecl; + /* Remember roughly where this call is. */ + location_t loc = EXPR_LOC_OR_HERE (fn); fn = build_call_a (fn, nargs, argarray); + SET_EXPR_LOCATION (fn, loc); /* If this call might throw an exception, note that fact. */ fndecl = get_callee_fndecl (fn); diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 9054b5caa18..6aefd684075 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -37,6 +37,7 @@ along with GCC; see the file COPYING3. If not see #include "cgraph.h" #include "tree-dump.h" #include "splay-tree.h" +#include "pointer-set.h" /* The number of nested classes being processed. If we are not in the scope of any class, this is zero. */ @@ -4582,10 +4583,73 @@ finalize_literal_type_property (tree t) { DECL_DECLARED_CONSTEXPR_P (fn) = false; if (!DECL_TEMPLATE_INFO (fn)) - error ("enclosing class of %q+#D is not a literal type", fn); + { + error ("enclosing class of constexpr non-static member " + "function %q+#D is not a literal type", fn); + explain_non_literal_class (t); + } } } +/* T is a non-literal type used in a context which requires a constant + expression. Explain why it isn't literal. */ + +void +explain_non_literal_class (tree t) +{ + static struct pointer_set_t *diagnosed; + + if (!CLASS_TYPE_P (t)) + return; + t = TYPE_MAIN_VARIANT (t); + + if (diagnosed == NULL) + diagnosed = pointer_set_create (); + if (pointer_set_insert (diagnosed, t) != 0) + /* Already explained. */ + return; + + inform (0, "%q+T is not literal because:", t); + if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t)) + inform (0, " %q+T has a non-trivial destructor", t); + else if (CLASSTYPE_NON_AGGREGATE (t) + && !TYPE_HAS_TRIVIAL_DFLT (t) + && !TYPE_HAS_CONSTEXPR_CTOR (t)) + inform (0, " %q+T is not an aggregate, does not have a trivial " + "default constructor, and has no constexpr constructor that " + "is not a copy or move constructor", t); + else + { + tree binfo, base_binfo, field; int i; + for (binfo = TYPE_BINFO (t), i = 0; + BINFO_BASE_ITERATE (binfo, i, base_binfo); i++) + { + tree basetype = TREE_TYPE (base_binfo); + if (!CLASSTYPE_LITERAL_P (basetype)) + { + inform (0, " base class %qT of %q+T is non-literal", + basetype, t); + explain_non_literal_class (basetype); + return; + } + } + for (field = TYPE_FIELDS (t); field; field = TREE_CHAIN (field)) + { + tree ftype; + if (TREE_CODE (field) != FIELD_DECL) + continue; + ftype = TREE_TYPE (field); + if (!literal_type_p (ftype)) + { + inform (0, " non-static data member %q+D has " + "non-literal type", field); + if (CLASS_TYPE_P (ftype)) + explain_non_literal_class (ftype); + } + } + } +} + /* Check the validity of the bases and members declared in T. Add any implicitly-generated functions (like copy-constructors and assignment operators). Compute various flag bits (like diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 9afb33cc144..7244cc88d4a 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -4816,6 +4816,7 @@ extern bool type_has_virtual_destructor (tree); extern bool type_has_move_constructor (tree); extern bool type_has_move_assign (tree); extern bool type_build_ctor_call (tree); +extern void explain_non_literal_class (tree); extern void defaulted_late_check (tree); extern bool defaultable_fn_check (tree); extern void fixup_type_variants (tree); @@ -5094,6 +5095,7 @@ extern void finish_thunk (tree); extern void use_thunk (tree, bool); extern bool trivial_fn_p (tree); extern bool maybe_explain_implicit_delete (tree); +extern void explain_implicit_non_constexpr (tree); extern void synthesize_method (tree); extern tree lazily_declare_fn (special_function_kind, tree); @@ -5364,6 +5366,7 @@ extern tree maybe_constant_value (tree); extern tree maybe_constant_init (tree); extern bool is_sub_constant_expr (tree); extern bool reduced_constant_expression_p (tree); +extern void explain_invalid_constexpr_fn (tree); extern VEC(tree,heap)* cx_error_context (void); enum { diff --git a/gcc/cp/method.c b/gcc/cp/method.c index ec1c5025278..f10e846d0ea 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -958,7 +958,15 @@ process_subob_fn (tree fn, bool move_p, tree *spec_p, bool *trivial_p, && !DECL_TEMPLATE_INSTANTIATED (fn)) instantiate_decl (fn, /*defer_ok*/false, /*expl_class*/false); if (!DECL_DECLARED_CONSTEXPR_P (fn)) - *constexpr_p = false; + { + *constexpr_p = false; + if (msg) + { + inform (0, "defaulted constructor calls non-constexpr " + "%q+D", fn); + explain_invalid_constexpr_fn (fn); + } + } } return; @@ -1037,7 +1045,12 @@ walk_field_subobs (tree fields, tree fnname, special_function_kind sfk, /* FIXME will need adjustment for non-static data member initializers. */ if (constexpr_p && !CLASS_TYPE_P (mem_type)) - *constexpr_p = false; + { + *constexpr_p = false; + if (msg) + inform (0, "defaulted default constructor does not " + "initialize %q+#D", field); + } } if (!CLASS_TYPE_P (mem_type)) @@ -1071,8 +1084,9 @@ walk_field_subobs (tree fields, tree fnname, special_function_kind sfk, /* The caller wants to generate an implicit declaration of SFK for CTYPE which is const if relevant and CONST_P is set. If spec_p, trivial_p and deleted_p are non-null, set their referent appropriately. If diag is - true, we're being called from maybe_explain_implicit_delete to give - errors. */ + true, we're either being called from maybe_explain_implicit_delete to + give errors, or if constexpr_p is non-null, from + explain_invalid_constexpr_fn. */ static void synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p, @@ -1175,6 +1189,7 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p, resolution, so a constructor can be trivial even if it would otherwise call a non-trivial constructor. */ if (expected_trivial + && !diag && (!copy_arg_p || cxx_dialect < cxx0x)) { if (constexpr_p && sfk == sfk_constructor) @@ -1366,6 +1381,20 @@ maybe_explain_implicit_delete (tree decl) return false; } +/* DECL is a defaulted function which was declared constexpr. Explain why + it can't be constexpr. */ + +void +explain_implicit_non_constexpr (tree decl) +{ + tree parm_type = TREE_VALUE (FUNCTION_FIRST_USER_PARMTYPE (decl)); + bool const_p = CP_TYPE_CONST_P (non_reference (parm_type)); + bool dummy; + synthesized_method_walk (DECL_CLASS_CONTEXT (decl), + special_function_p (decl), const_p, + NULL, NULL, NULL, &dummy, true); +} + /* Implicitly declare the special function indicated by KIND, as a member of TYPE. For copy constructors and assignment operators, CONST_P indicates whether these functions should take a const @@ -1581,7 +1610,12 @@ defaulted_late_check (tree fn) && DECL_DECLARED_CONSTEXPR_P (fn)) { if (!CLASSTYPE_TEMPLATE_INSTANTIATION (ctx)) - error ("%qD cannot be declared as constexpr", fn); + { + error ("explicitly defaulted function %q+D cannot be declared " + "as constexpr because the implicit declaration is not " + "constexpr:", fn); + explain_implicit_non_constexpr (fn); + } DECL_DECLARED_CONSTEXPR_P (fn) = false; } diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 8121a0020b5..458172980b4 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -3538,6 +3538,17 @@ emit_associated_thunks (tree fn) } } +/* Returns true iff FUN is an instantiation of a constexpr function + template. */ + +static inline bool +is_instantiation_of_constexpr (tree fun) +{ + return (DECL_TEMPLATE_INFO (fun) + && DECL_DECLARED_CONSTEXPR_P (DECL_TEMPLATE_RESULT + (DECL_TI_TEMPLATE (fun)))); +} + /* Generate RTL for FN. */ bool @@ -3567,7 +3578,10 @@ expand_or_defer_fn_1 (tree fn) /* We don't want to process FN again, so pretend we've written it out, even though we haven't. */ TREE_ASM_WRITTEN (fn) = 1; - DECL_SAVED_TREE (fn) = NULL_TREE; + /* If this is an instantiation of a constexpr function, keep + DECL_SAVED_TREE for explain_invalid_constexpr_fn. */ + if (!is_instantiation_of_constexpr (fn)) + DECL_SAVED_TREE (fn) = NULL_TREE; return false; } @@ -5299,6 +5313,7 @@ ensure_literal_type_for_constexpr_object (tree decl) { error ("the type %qT of constexpr variable %qD is not literal", type, decl); + explain_non_literal_class (type); return NULL; } } @@ -5365,8 +5380,11 @@ is_valid_constexpr_fn (tree fun, bool complain) { ret = false; if (complain) - error ("invalid type for parameter %d of constexpr " - "function %q+#D", DECL_PARM_INDEX (parm), fun); + { + error ("invalid type for parameter %d of constexpr " + "function %q+#D", DECL_PARM_INDEX (parm), fun); + explain_non_literal_class (TREE_TYPE (parm)); + } } if (!DECL_CONSTRUCTOR_P (fun)) @@ -5376,8 +5394,11 @@ is_valid_constexpr_fn (tree fun, bool complain) { ret = false; if (complain) - error ("invalid return type %qT of constexpr function %q+D", - rettype, fun); + { + error ("invalid return type %qT of constexpr function %q+D", + rettype, fun); + explain_non_literal_class (rettype); + } } /* Check this again here for cxx_eval_call_expression. */ @@ -5386,7 +5407,11 @@ is_valid_constexpr_fn (tree fun, bool complain) { ret = false; if (complain) - error ("enclosing class of %q+#D is not a literal type", fun); + { + error ("enclosing class of constexpr non-static member " + "function %q+#D is not a literal type", fun); + explain_non_literal_class (DECL_CONTEXT (fun)); + } } } @@ -5640,18 +5665,13 @@ constexpr_fn_retval (tree body) } } -/* We are processing the definition of the constexpr function FUN. - Check that its BODY fulfills the propriate requirements and - enter it in the constexpr function definition table. - For constructor BODY is actually the TREE_LIST of the - member-initializer list. */ +/* Subroutine of register_constexpr_fundef. BODY is the DECL_SAVED_TREE of + FUN; do the necessary transformations to turn it into a single expression + that we can store in the hash table. */ -tree -register_constexpr_fundef (tree fun, tree body) +static tree +massage_constexpr_body (tree fun, tree body) { - constexpr_fundef entry; - constexpr_fundef **slot; - if (DECL_CONSTRUCTOR_P (fun)) body = build_constexpr_constructor_member_initializers (DECL_CONTEXT (fun), body); @@ -5666,12 +5686,28 @@ register_constexpr_fundef (tree fun, tree body) if (TREE_CODE (body) == CLEANUP_POINT_EXPR) body = TREE_OPERAND (body, 0); body = constexpr_fn_retval (body); - if (body == NULL_TREE || body == error_mark_node) - { - error ("body of constexpr function %qD not a return-statement", fun); - DECL_DECLARED_CONSTEXPR_P (fun) = false; - return NULL; - } + } + return body; +} + +/* We are processing the definition of the constexpr function FUN. + Check that its BODY fulfills the propriate requirements and + enter it in the constexpr function definition table. + For constructor BODY is actually the TREE_LIST of the + member-initializer list. */ + +tree +register_constexpr_fundef (tree fun, tree body) +{ + constexpr_fundef entry; + constexpr_fundef **slot; + + body = massage_constexpr_body (fun, body); + if (body == NULL_TREE || body == error_mark_node) + { + error ("body of constexpr function %qD not a return-statement", fun); + DECL_DECLARED_CONSTEXPR_P (fun) = false; + return NULL; } if (!potential_rvalue_constant_expression (body)) @@ -5700,6 +5736,44 @@ register_constexpr_fundef (tree fun, tree body) return fun; } +/* FUN is a non-constexpr function called in a context that requires a + constant expression. If it comes from a constexpr template, explain why + the instantiation isn't constexpr. */ + +void +explain_invalid_constexpr_fn (tree fun) +{ + static struct pointer_set_t *diagnosed; + tree body; + location_t save_loc; + /* Only diagnose instantiations of constexpr templates. */ + if (!is_instantiation_of_constexpr (fun)) + return; + if (diagnosed == NULL) + diagnosed = pointer_set_create (); + if (pointer_set_insert (diagnosed, fun) != 0) + /* Already explained. */ + return; + + save_loc = input_location; + input_location = DECL_SOURCE_LOCATION (fun); + inform (0, "%q+D is not constexpr because it does not satisfy the " + "requirements:", fun); + /* First check the declaration. */ + if (is_valid_constexpr_fn (fun, true)) + { + /* Then if it's OK, the body. */ + if (DECL_DEFAULTED_FN (fun)) + explain_implicit_non_constexpr (fun); + else + { + body = massage_constexpr_body (fun, DECL_SAVED_TREE (fun)); + require_potential_rvalue_constant_expression (body); + } + } + input_location = save_loc; +} + /* Objects of this type represent calls to constexpr functions along with the bindings of parameters to their arguments, for the purpose of compile time evaluation. */ @@ -6005,7 +6079,7 @@ cxx_eval_call_expression (const constexpr_call *old_call, tree t, } if (TREE_CODE (fun) != FUNCTION_DECL) { - if (!allow_non_constant) + if (!allow_non_constant && !*non_constant_p) error_at (loc, "expression %qE does not designate a constexpr " "function", fun); *non_constant_p = true; @@ -6020,11 +6094,8 @@ cxx_eval_call_expression (const constexpr_call *old_call, tree t, { if (!allow_non_constant) { - error_at (loc, "%qD is not a constexpr function", fun); - if (DECL_TEMPLATE_INFO (fun) - && DECL_DECLARED_CONSTEXPR_P (DECL_TEMPLATE_RESULT - (DECL_TI_TEMPLATE (fun)))) - is_valid_constexpr_fn (fun, true); + error_at (loc, "call to non-constexpr function %qD", fun); + explain_invalid_constexpr_fn (fun); } *non_constant_p = true; return t; @@ -7023,8 +7094,11 @@ cxx_eval_constant_expression (const constexpr_call *call, tree t, if (!literal_type_p (TREE_TYPE (t))) { if (!allow_non_constant) - error ("temporary of non-literal type %qT in a " - "constant expression", TREE_TYPE (t)); + { + error ("temporary of non-literal type %qT in a " + "constant expression", TREE_TYPE (t)); + explain_non_literal_class (TREE_TYPE (t)); + } *non_constant_p = true; break; } @@ -7574,7 +7648,11 @@ potential_constant_expression_1 (tree t, bool want_rval, tsubst_flags_t flags) && !morally_constexpr_builtin_function_p (fun)) { if (flags & tf_error) - error ("%qD is not %", fun); + { + error_at (EXPR_LOC_OR_HERE (t), + "call to non-constexpr function %qD", fun); + explain_invalid_constexpr_fn (fun); + } return false; } /* A call to a non-static member function takes the address @@ -7588,12 +7666,7 @@ potential_constant_expression_1 (tree t, bool want_rval, tsubst_flags_t flags) if (is_this_parameter (x)) /* OK. */; else if (!potential_constant_expression_1 (x, rval, flags)) - { - if (flags & tf_error) - error ("object argument is not a potential " - "constant expression"); - return false; - } + return false; i = 1; } } @@ -7609,22 +7682,13 @@ potential_constant_expression_1 (tree t, bool want_rval, tsubst_flags_t flags) if (potential_constant_expression_1 (fun, rval, flags)) /* Might end up being a constant function pointer. */; else - { - if (flags & tf_error) - error ("%qE is not a function name", fun); - return false; - } + return false; } for (; i < nargs; ++i) { tree x = get_nth_callarg (t, i); if (!potential_constant_expression_1 (x, rval, flags)) - { - if (flags & tf_error) - error ("argument in position %qP is not a " - "potential constant expression", i); - return false; - } + return false; } return true; } @@ -7853,8 +7917,11 @@ potential_constant_expression_1 (tree t, bool want_rval, tsubst_flags_t flags) if (!literal_type_p (TREE_TYPE (t))) { if (flags & tf_error) - error ("temporary of non-literal type %qT in a " - "constant expression", TREE_TYPE (t)); + { + error ("temporary of non-literal type %qT in a " + "constant expression", TREE_TYPE (t)); + explain_non_literal_class (TREE_TYPE (t)); + } return false; } case INIT_EXPR: diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 4e2ebc3a155..d30d8b053c2 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,12 @@ +2011-06-29 Jason Merrill + + PR c++/45923 + * g++.dg/cpp0x/constexpr-diag3.C: New. + * g++.dg/cpp0x/constexpr-diag1.C: Adjust error message. + * g++.dg/cpp0x/constexpr-ex1.C: Adjust error message. + * g++.dg/cpp0x/constexpr-friend.C: Adjust error message. + * g++.dg/cpp0x/constexpr-incomplete2.C: Adjust error message. + 2011-06-29 Jason Merrill * g++.dg/cpp0x/constexpr-is_literal.C: Adjust. diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-diag1.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-diag1.C index 183d3f768fa..44e6bc7e089 100644 --- a/gcc/testsuite/g++.dg/cpp0x/constexpr-diag1.C +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-diag1.C @@ -13,7 +13,7 @@ struct B { B(); operator int(); }; constexpr A ai = { 42 }; constexpr int i = ai.f(); -constexpr int b = A().f(); // { dg-error "not a constexpr function" } +constexpr int b = A().f(); // { dg-error "non-constexpr function" } template constexpr int f (T t) { return 42; } // { dg-error "parameter" } diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-diag3.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-diag3.C new file mode 100644 index 00000000000..100c17edb45 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-diag3.C @@ -0,0 +1,54 @@ +// PR c++/45923 +// { dg-options -std=c++0x } + +int f(int); + +template +constexpr T g(T t) { return f(t); } // { dg-error "f.int" } + +int main() +{ + constexpr int i = g(1); // { dg-error "g.T" } +} + +// -------------------- + +struct complex // { dg-message "no constexpr constructor" } +{ + complex(double r, double i) : re(r), im(i) { } + constexpr double real() { return re; } // { dg-error "not a literal type" } + double imag() const { return im; } + +private: + double re; + double im; +}; + +constexpr complex co1(0, 1); // { dg-error "not literal" } +constexpr double dd2 = co1.real(); // { dg-error "non-constexpr function" } + +// -------------------- + +struct base // { dg-message "no constexpr constructor" } +{ + int _M_i; + base() : _M_i(5) { } +}; + +struct derived : public base // { dg-message "base class" } +{ + constexpr derived(): base() { } // { dg-error "non-constexpr function" } +}; + +constexpr derived obj; // { dg-error "not literal" } + +// -------------------- + +struct Def +{ + int _M_i; // { dg-message "does not initialize" } + + constexpr Def() = default; // { dg-error "implicit declaration is not constexpr" } +}; + +constexpr Def defobj; // { dg-error "uninitialized" } diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-ex1.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-ex1.C index 4ab4677805f..584a5a09b69 100644 --- a/gcc/testsuite/g++.dg/cpp0x/constexpr-ex1.C +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-ex1.C @@ -88,7 +88,7 @@ struct resource { } }; constexpr resource f(resource d) -{ return d; } // { dg-error "not .constexpr" } +{ return d; } // { dg-error "non-constexpr" } constexpr resource d = f(9); // { dg-error "resource" } // 4.4 floating-point constant expressions diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-friend.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-friend.C index f1d9ccee790..1831a2b003c 100644 --- a/gcc/testsuite/g++.dg/cpp0x/constexpr-friend.C +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-friend.C @@ -19,5 +19,5 @@ struct C constexpr int i = f(C()); constexpr int j = C().m(C()); -constexpr int k = C().m(A()); // { dg-error "not a constexpr function" } -constexpr int l = g(C(),A()); // { dg-error "not a constexpr function" } +constexpr int k = C().m(A()); // { dg-error "non-constexpr function" } +constexpr int l = g(C(),A()); // { dg-error "non-constexpr function" } diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-incomplete2.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-incomplete2.C index dc0b7429dc6..f61535f06be 100644 --- a/gcc/testsuite/g++.dg/cpp0x/constexpr-incomplete2.C +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-incomplete2.C @@ -28,4 +28,4 @@ struct D C c; }; -constexpr D d {}; // { dg-error "not a constexpr function" } +constexpr D d {}; // { dg-error "non-constexpr function" }