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>
PR c++/50084

View File

@ -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 %<constexpr%> 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 %<constexpr%> constructor",
BINFO_TYPE (subobject));
DECL_DECLARED_CONSTEXPR_P (current_function_decl) = false;
}
}
/* 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;
}
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);
}
}

View File

@ -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 %<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.
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

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>
* gnat.dg/specs/debug1.ads: Tweak pattern.

View File

@ -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 {

View File

@ -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

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()" }
}