re PR c++/50248 ([C++0x] unnecessary instantiation of constexpr constructor)

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.

From-SVN: r178518
This commit is contained in:
Jason Merrill 2011-09-05 00:33:08 -04:00 committed by Jason Merrill
parent e818d3ff68
commit aee8801251
9 changed files with 146 additions and 42 deletions

View File

@ -1,3 +1,17 @@
2011-09-04 Jason Merrill <jason@redhat.com>
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 <jason@redhat.com> 2011-08-30 Jason Merrill <jason@redhat.com>
PR c++/50084 PR c++/50084

View File

@ -606,15 +606,6 @@ perform_member_init (tree member, tree init)
core_type = strip_array_types (type); 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 %<constexpr%> constructor",
member);
DECL_DECLARED_CONSTEXPR_P (current_function_decl) = false;
}
if (CLASS_TYPE_P (core_type) if (CLASS_TYPE_P (core_type)
&& (CLASSTYPE_READONLY_FIELDS_NEED_INIT (core_type) && (CLASSTYPE_READONLY_FIELDS_NEED_INIT (core_type)
|| CLASSTYPE_REF_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 " OPT_Wextra, "base class %q#T should be explicitly "
"initialized in the copy constructor", "initialized in the copy constructor",
BINFO_TYPE (subobject)); 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 %<constexpr%> constructor",
BINFO_TYPE (subobject));
DECL_DECLARED_CONSTEXPR_P (current_function_decl) = false;
}
} }
/* Initialize the base. */ /* Initialize the base. */

View File

@ -952,23 +952,14 @@ process_subob_fn (tree fn, bool move_p, tree *spec_p, bool *trivial_p,
goto bad; 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 *constexpr_p = false;
force the instantiation now so that we know whether or not it's if (msg)
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; inform (0, "defaulted constructor calls non-constexpr "
if (msg) "%q+D", fn);
{ explain_invalid_constexpr_fn (fn);
inform (0, "defaulted constructor calls non-constexpr "
"%q+D", fn);
explain_invalid_constexpr_fn (fn);
}
} }
} }

View File

@ -5775,6 +5775,53 @@ massage_constexpr_body (tree fun, tree body)
return 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 %<constexpr%> 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. /* We are processing the definition of the constexpr function FUN.
Check that its BODY fulfills the propriate requirements and Check that its BODY fulfills the propriate requirements and
enter it in the constexpr function definition table. 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)) if (!potential_rvalue_constant_expression (body))
{ {
DECL_DECLARED_CONSTEXPR_P (fun) = false;
if (!DECL_TEMPLATE_INFO (fun)) if (!DECL_TEMPLATE_INFO (fun))
require_potential_rvalue_constant_expression (body); require_potential_rvalue_constant_expression (body);
return NULL; 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. */ /* Create the constexpr function table if necessary. */
if (constexpr_fundef_table == NULL) if (constexpr_fundef_table == NULL)
constexpr_fundef_table = htab_create_ggc (101, constexpr_fundef_table = htab_create_ggc (101,
@ -5842,8 +5892,7 @@ explain_invalid_constexpr_fn (tree fun)
save_loc = input_location; save_loc = input_location;
input_location = DECL_SOURCE_LOCATION (fun); input_location = DECL_SOURCE_LOCATION (fun);
inform (0, "%q+D is not constexpr because it does not satisfy the " inform (0, "%q+D is not usable as a constexpr function because:", fun);
"requirements:", fun);
/* First check the declaration. */ /* First check the declaration. */
if (is_valid_constexpr_fn (fun, true)) 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)); body = massage_constexpr_body (fun, DECL_SAVED_TREE (fun));
require_potential_rvalue_constant_expression (body); require_potential_rvalue_constant_expression (body);
if (DECL_CONSTRUCTOR_P (fun))
cx_check_missing_mem_inits (fun, body, true);
} }
} }
input_location = save_loc; 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 (new_call.fundef == NULL || new_call.fundef->body == NULL)
{ {
if (!allow_non_constant) 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; *non_constant_p = true;
return t; return t;
} }
@ -7176,7 +7236,17 @@ cxx_eval_constant_expression (const constexpr_call *call, tree t,
case PARM_DECL: case PARM_DECL:
if (call && DECL_CONTEXT (t) == call->fundef->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) else if (addr)
/* Defer in case this is only used for its type. */; /* Defer in case this is only used for its type. */;
else else

View File

@ -1,3 +1,12 @@
2011-09-04 Jason Merrill <jason@redhat.com>
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 <ebotcazou@adacore.com> 2011-09-04 Eric Botcazou <ebotcazou@adacore.com>
* gnat.dg/specs/debug1.ads: Tweak pattern. * gnat.dg/specs/debug1.ads: Tweak pattern.

View File

@ -14,7 +14,7 @@ struct s {
int v; int v;
}; };
constexpr s bang; // { dg-error "" } constexpr s bang; // { dg-message "" }
struct R { struct R {
int i,j; int i,j;
@ -33,7 +33,7 @@ struct T {
constexpr T t1; constexpr T t1;
// Ill-formed (diagnostic required) // Ill-formed (diagnostic required)
constexpr T t2(t1); // { dg-error "" } constexpr T t2(t1); // { dg-message "" }
// Well-formed // Well-formed
struct U { struct U {

View File

@ -89,6 +89,6 @@ struct resource {
}; };
constexpr resource f(resource d) constexpr resource f(resource d)
{ return d; } // { dg-error "non-constexpr" } { 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 // 4.4 floating-point constant expressions

View File

@ -0,0 +1,27 @@
// PR c++/50248, DR 1358
// { dg-options -std=c++0x }
template<class Elt, unsigned max>
struct earray
{
Elt elts[max];
earray() = default;
template<typename... Elt2>
constexpr earray(Elt2&& ... e): elts(0) { }
};
struct SessionData
{
SessionData(SessionData&) = delete;
SessionData() = default;
};
struct MapSessionData : SessionData
{
earray<short, 11> equip_index;
};
void test()
{
MapSessionData *sd = new MapSessionData;
}

View File

@ -0,0 +1,12 @@
// { dg-options -std=c++0x }
template <class T> struct A
{
T t;
constexpr A() { } // { dg-error "uninitialized" }
};
int main()
{
constexpr A<int> a; // { dg-error "A()" }
}