diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 96ac2377be3..a83d19ba665 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,17 @@ +2011-09-04 Jason Merrill + + PR c++/50248 + Core 1358 + * init.c (perform_member_init): Don't diagnose missing inits here. + (emit_mem_initializers): Or here. + * method.c (process_subob_fn): Don't instantiate constexpr ctors. + * semantics.c (cx_check_missing_mem_inits): New. + (explain_invalid_constexpr_fn): Call it. + (register_constexpr_fundef): Likewise. Leave + DECL_DECLARED_CONSTEXPR_P set when the body is unsuitable. + (cxx_eval_call_expression): Adjust diagnostics. + (cxx_eval_constant_expression): Catch use of 'this' in a constructor. + 2011-08-30 Jason Merrill PR c++/50084 diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 847f5199f1b..ff1884b361d 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -606,15 +606,6 @@ perform_member_init (tree member, tree init) core_type = strip_array_types (type); - if (DECL_DECLARED_CONSTEXPR_P (current_function_decl) - && !type_has_constexpr_default_constructor (core_type)) - { - if (!DECL_TEMPLATE_INSTANTIATION (current_function_decl)) - error ("uninitialized member %qD in % constructor", - member); - DECL_DECLARED_CONSTEXPR_P (current_function_decl) = false; - } - if (CLASS_TYPE_P (core_type) && (CLASSTYPE_READONLY_FIELDS_NEED_INIT (core_type) || CLASSTYPE_REF_FIELDS_NEED_INIT (core_type))) @@ -962,16 +953,6 @@ emit_mem_initializers (tree mem_inits) OPT_Wextra, "base class %q#T should be explicitly " "initialized in the copy constructor", BINFO_TYPE (subobject)); - - if (DECL_DECLARED_CONSTEXPR_P (current_function_decl) - && !(type_has_constexpr_default_constructor - (BINFO_TYPE (subobject)))) - { - if (!DECL_TEMPLATE_INSTANTIATION (current_function_decl)) - error ("uninitialized base %qT in % constructor", - BINFO_TYPE (subobject)); - DECL_DECLARED_CONSTEXPR_P (current_function_decl) = false; - } } /* Initialize the base. */ diff --git a/gcc/cp/method.c b/gcc/cp/method.c index 3d272a33f61..74a3bdbd839 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -952,23 +952,14 @@ process_subob_fn (tree fn, bool move_p, tree *spec_p, bool *trivial_p, goto bad; } - if (constexpr_p) + if (constexpr_p && !DECL_DECLARED_CONSTEXPR_P (fn)) { - /* If this is a specialization of a constexpr template, we need to - force the instantiation now so that we know whether or not it's - really constexpr. */ - if (DECL_DECLARED_CONSTEXPR_P (fn) && DECL_TEMPLATE_INSTANTIATION (fn) - && !DECL_TEMPLATE_INSTANTIATED (fn)) - instantiate_decl (fn, /*defer_ok*/false, /*expl_class*/false); - if (!DECL_DECLARED_CONSTEXPR_P (fn)) + *constexpr_p = false; + if (msg) { - *constexpr_p = false; - if (msg) - { - inform (0, "defaulted constructor calls non-constexpr " - "%q+D", fn); - explain_invalid_constexpr_fn (fn); - } + inform (0, "defaulted constructor calls non-constexpr " + "%q+D", fn); + explain_invalid_constexpr_fn (fn); } } diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index ce84062f918..fd96d706c89 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -5775,6 +5775,53 @@ massage_constexpr_body (tree fun, tree body) return body; } +/* FUN is a constexpr constructor with massaged body BODY. Return true + if some bases/fields are uninitialized, and complain if COMPLAIN. */ + +static bool +cx_check_missing_mem_inits (tree fun, tree body, bool complain) +{ + bool bad; + tree field; + unsigned i, nelts; + + if (TREE_CODE (body) != CONSTRUCTOR) + return false; + + bad = false; + nelts = CONSTRUCTOR_NELTS (body); + field = TYPE_FIELDS (DECL_CONTEXT (fun)); + for (i = 0; i <= nelts; ++i) + { + tree index; + if (i == nelts) + index = NULL_TREE; + else + { + index = CONSTRUCTOR_ELT (body, i)->index; + /* Skip base vtable inits. */ + if (TREE_CODE (index) == COMPONENT_REF) + continue; + } + for (; field != index; field = DECL_CHAIN (field)) + { + if (TREE_CODE (field) != FIELD_DECL + || (DECL_C_BIT_FIELD (field) && !DECL_NAME (field))) + continue; + if (!complain) + return true; + error ("uninitialized member %qD in % constructor", + field); + bad = true; + } + if (field == NULL_TREE) + break; + field = DECL_CHAIN (field); + } + + return bad; +} + /* 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. @@ -5797,12 +5844,15 @@ register_constexpr_fundef (tree fun, tree body) if (!potential_rvalue_constant_expression (body)) { - DECL_DECLARED_CONSTEXPR_P (fun) = false; if (!DECL_TEMPLATE_INFO (fun)) require_potential_rvalue_constant_expression (body); return NULL; } + if (DECL_CONSTRUCTOR_P (fun) + && cx_check_missing_mem_inits (fun, body, !DECL_TEMPLATE_INFO (fun))) + return NULL; + /* Create the constexpr function table if necessary. */ if (constexpr_fundef_table == NULL) constexpr_fundef_table = htab_create_ggc (101, @@ -5842,8 +5892,7 @@ explain_invalid_constexpr_fn (tree fun) 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); + inform (0, "%q+D is not usable as a constexpr function because:", fun); /* First check the declaration. */ if (is_valid_constexpr_fn (fun, true)) { @@ -5854,6 +5903,8 @@ explain_invalid_constexpr_fn (tree fun) { body = massage_constexpr_body (fun, DECL_SAVED_TREE (fun)); require_potential_rvalue_constant_expression (body); + if (DECL_CONSTRUCTOR_P (fun)) + cx_check_missing_mem_inits (fun, body, true); } } input_location = save_loc; @@ -6203,7 +6254,16 @@ cxx_eval_call_expression (const constexpr_call *old_call, tree t, if (new_call.fundef == NULL || new_call.fundef->body == NULL) { if (!allow_non_constant) - error_at (loc, "%qD used before its definition", fun); + { + if (DECL_SAVED_TREE (fun)) + { + /* The definition of fun was somehow unsuitable. */ + error_at (loc, "%qD called in a constant expression", fun); + explain_invalid_constexpr_fn (fun); + } + else + error_at (loc, "%qD used before its definition", fun); + } *non_constant_p = true; return t; } @@ -7176,7 +7236,17 @@ cxx_eval_constant_expression (const constexpr_call *call, tree t, case PARM_DECL: if (call && DECL_CONTEXT (t) == call->fundef->decl) - r = lookup_parameter_binding (call, t); + { + if (DECL_ARTIFICIAL (t) && DECL_CONSTRUCTOR_P (DECL_CONTEXT (t))) + { + if (!allow_non_constant) + sorry ("use of the value of the object being constructed " + "in a constant expression"); + *non_constant_p = true; + } + else + r = lookup_parameter_binding (call, t); + } else if (addr) /* Defer in case this is only used for its type. */; else diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 095ccc8cf67..19441c44b79 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,12 @@ +2011-09-04 Jason Merrill + + PR c++/50248 + Core 1358 + * g++.dg/cpp0x/constexpr-template1.C: New. + * g++.dg/cpp0x/constexpr-template2.C: New. + * g++.dg/cpp0x/constexpr-48089.C: Adjust error markup. + * g++.dg/cpp0x/constexpr-ex1.C: Adjust error markup. + 2011-09-04 Eric Botcazou * gnat.dg/specs/debug1.ads: Tweak pattern. diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-48089.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-48089.C index 5124f7c7f49..a6cf4080756 100644 --- a/gcc/testsuite/g++.dg/cpp0x/constexpr-48089.C +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-48089.C @@ -14,7 +14,7 @@ struct s { int v; }; -constexpr s bang; // { dg-error "" } +constexpr s bang; // { dg-message "" } struct R { int i,j; @@ -33,7 +33,7 @@ struct T { constexpr T t1; // Ill-formed (diagnostic required) -constexpr T t2(t1); // { dg-error "" } +constexpr T t2(t1); // { dg-message "" } // Well-formed struct U { diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-ex1.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-ex1.C index 584a5a09b69..3df7956fd28 100644 --- a/gcc/testsuite/g++.dg/cpp0x/constexpr-ex1.C +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-ex1.C @@ -89,6 +89,6 @@ struct resource { }; constexpr resource f(resource d) { return d; } // { dg-error "non-constexpr" } -constexpr resource d = f(9); // { dg-error "resource" } +constexpr resource d = f(9); // { dg-message "constexpr" } // 4.4 floating-point constant expressions diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-template1.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-template1.C new file mode 100644 index 00000000000..88077231b0d --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-template1.C @@ -0,0 +1,27 @@ +// PR c++/50248, DR 1358 +// { dg-options -std=c++0x } + +template +struct earray +{ + Elt elts[max]; + earray() = default; + template + constexpr earray(Elt2&& ... e): elts(0) { } +}; + +struct SessionData +{ + SessionData(SessionData&) = delete; + SessionData() = default; +}; + +struct MapSessionData : SessionData +{ + earray equip_index; +}; + +void test() +{ + MapSessionData *sd = new MapSessionData; +} diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-template2.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-template2.C new file mode 100644 index 00000000000..6786d1651e5 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-template2.C @@ -0,0 +1,12 @@ +// { dg-options -std=c++0x } + +template struct A +{ + T t; + constexpr A() { } // { dg-error "uninitialized" } +}; + +int main() +{ + constexpr A a; // { dg-error "A()" } +}