Commit f732fa7b by Jason Merrill Committed by Jason Merrill

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
parent 874d29e5
2011-06-29 Jason Merrill <jason@redhat.com> 2011-06-29 Jason Merrill <jason@redhat.com>
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 * method.c (maybe_explain_implicit_delete): Use pointer_set
instead of htab. instead of htab.
......
...@@ -6721,7 +6721,10 @@ build_cxx_call (tree fn, int nargs, tree *argarray) ...@@ -6721,7 +6721,10 @@ build_cxx_call (tree fn, int nargs, tree *argarray)
{ {
tree fndecl; tree fndecl;
/* Remember roughly where this call is. */
location_t loc = EXPR_LOC_OR_HERE (fn);
fn = build_call_a (fn, nargs, argarray); fn = build_call_a (fn, nargs, argarray);
SET_EXPR_LOCATION (fn, loc);
/* If this call might throw an exception, note that fact. */ /* If this call might throw an exception, note that fact. */
fndecl = get_callee_fndecl (fn); fndecl = get_callee_fndecl (fn);
......
...@@ -37,6 +37,7 @@ along with GCC; see the file COPYING3. If not see ...@@ -37,6 +37,7 @@ along with GCC; see the file COPYING3. If not see
#include "cgraph.h" #include "cgraph.h"
#include "tree-dump.h" #include "tree-dump.h"
#include "splay-tree.h" #include "splay-tree.h"
#include "pointer-set.h"
/* The number of nested classes being processed. If we are not in the /* The number of nested classes being processed. If we are not in the
scope of any class, this is zero. */ scope of any class, this is zero. */
...@@ -4582,10 +4583,73 @@ finalize_literal_type_property (tree t) ...@@ -4582,10 +4583,73 @@ finalize_literal_type_property (tree t)
{ {
DECL_DECLARED_CONSTEXPR_P (fn) = false; DECL_DECLARED_CONSTEXPR_P (fn) = false;
if (!DECL_TEMPLATE_INFO (fn)) 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 /* Check the validity of the bases and members declared in T. Add any
implicitly-generated functions (like copy-constructors and implicitly-generated functions (like copy-constructors and
assignment operators). Compute various flag bits (like assignment operators). Compute various flag bits (like
......
...@@ -4816,6 +4816,7 @@ extern bool type_has_virtual_destructor (tree); ...@@ -4816,6 +4816,7 @@ extern bool type_has_virtual_destructor (tree);
extern bool type_has_move_constructor (tree); extern bool type_has_move_constructor (tree);
extern bool type_has_move_assign (tree); extern bool type_has_move_assign (tree);
extern bool type_build_ctor_call (tree); extern bool type_build_ctor_call (tree);
extern void explain_non_literal_class (tree);
extern void defaulted_late_check (tree); extern void defaulted_late_check (tree);
extern bool defaultable_fn_check (tree); extern bool defaultable_fn_check (tree);
extern void fixup_type_variants (tree); extern void fixup_type_variants (tree);
...@@ -5094,6 +5095,7 @@ extern void finish_thunk (tree); ...@@ -5094,6 +5095,7 @@ extern void finish_thunk (tree);
extern void use_thunk (tree, bool); extern void use_thunk (tree, bool);
extern bool trivial_fn_p (tree); extern bool trivial_fn_p (tree);
extern bool maybe_explain_implicit_delete (tree); extern bool maybe_explain_implicit_delete (tree);
extern void explain_implicit_non_constexpr (tree);
extern void synthesize_method (tree); extern void synthesize_method (tree);
extern tree lazily_declare_fn (special_function_kind, extern tree lazily_declare_fn (special_function_kind,
tree); tree);
...@@ -5364,6 +5366,7 @@ extern tree maybe_constant_value (tree); ...@@ -5364,6 +5366,7 @@ extern tree maybe_constant_value (tree);
extern tree maybe_constant_init (tree); extern tree maybe_constant_init (tree);
extern bool is_sub_constant_expr (tree); extern bool is_sub_constant_expr (tree);
extern bool reduced_constant_expression_p (tree); extern bool reduced_constant_expression_p (tree);
extern void explain_invalid_constexpr_fn (tree);
extern VEC(tree,heap)* cx_error_context (void); extern VEC(tree,heap)* cx_error_context (void);
enum { enum {
......
...@@ -958,7 +958,15 @@ process_subob_fn (tree fn, bool move_p, tree *spec_p, bool *trivial_p, ...@@ -958,7 +958,15 @@ process_subob_fn (tree fn, bool move_p, tree *spec_p, bool *trivial_p,
&& !DECL_TEMPLATE_INSTANTIATED (fn)) && !DECL_TEMPLATE_INSTANTIATED (fn))
instantiate_decl (fn, /*defer_ok*/false, /*expl_class*/false); instantiate_decl (fn, /*defer_ok*/false, /*expl_class*/false);
if (!DECL_DECLARED_CONSTEXPR_P (fn)) 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; return;
...@@ -1037,7 +1045,12 @@ walk_field_subobs (tree fields, tree fnname, special_function_kind sfk, ...@@ -1037,7 +1045,12 @@ walk_field_subobs (tree fields, tree fnname, special_function_kind sfk,
/* FIXME will need adjustment for non-static data member /* FIXME will need adjustment for non-static data member
initializers. */ initializers. */
if (constexpr_p && !CLASS_TYPE_P (mem_type)) 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)) if (!CLASS_TYPE_P (mem_type))
...@@ -1071,8 +1084,9 @@ walk_field_subobs (tree fields, tree fnname, special_function_kind sfk, ...@@ -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 /* 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 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 deleted_p are non-null, set their referent appropriately. If diag is
true, we're being called from maybe_explain_implicit_delete to give true, we're either being called from maybe_explain_implicit_delete to
errors. */ give errors, or if constexpr_p is non-null, from
explain_invalid_constexpr_fn. */
static void static void
synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p, 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, ...@@ -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 resolution, so a constructor can be trivial even if it would otherwise
call a non-trivial constructor. */ call a non-trivial constructor. */
if (expected_trivial if (expected_trivial
&& !diag
&& (!copy_arg_p || cxx_dialect < cxx0x)) && (!copy_arg_p || cxx_dialect < cxx0x))
{ {
if (constexpr_p && sfk == sfk_constructor) if (constexpr_p && sfk == sfk_constructor)
...@@ -1366,6 +1381,20 @@ maybe_explain_implicit_delete (tree decl) ...@@ -1366,6 +1381,20 @@ maybe_explain_implicit_delete (tree decl)
return false; 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 /* Implicitly declare the special function indicated by KIND, as a
member of TYPE. For copy constructors and assignment operators, member of TYPE. For copy constructors and assignment operators,
CONST_P indicates whether these functions should take a const CONST_P indicates whether these functions should take a const
...@@ -1581,7 +1610,12 @@ defaulted_late_check (tree fn) ...@@ -1581,7 +1610,12 @@ defaulted_late_check (tree fn)
&& DECL_DECLARED_CONSTEXPR_P (fn)) && DECL_DECLARED_CONSTEXPR_P (fn))
{ {
if (!CLASSTYPE_TEMPLATE_INSTANTIATION (ctx)) 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; DECL_DECLARED_CONSTEXPR_P (fn) = false;
} }
......
...@@ -3538,6 +3538,17 @@ emit_associated_thunks (tree fn) ...@@ -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. */ /* Generate RTL for FN. */
bool bool
...@@ -3567,7 +3578,10 @@ expand_or_defer_fn_1 (tree fn) ...@@ -3567,7 +3578,10 @@ expand_or_defer_fn_1 (tree fn)
/* We don't want to process FN again, so pretend we've written /* We don't want to process FN again, so pretend we've written
it out, even though we haven't. */ it out, even though we haven't. */
TREE_ASM_WRITTEN (fn) = 1; 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; return false;
} }
...@@ -5299,6 +5313,7 @@ ensure_literal_type_for_constexpr_object (tree decl) ...@@ -5299,6 +5313,7 @@ ensure_literal_type_for_constexpr_object (tree decl)
{ {
error ("the type %qT of constexpr variable %qD is not literal", error ("the type %qT of constexpr variable %qD is not literal",
type, decl); type, decl);
explain_non_literal_class (type);
return NULL; return NULL;
} }
} }
...@@ -5365,8 +5380,11 @@ is_valid_constexpr_fn (tree fun, bool complain) ...@@ -5365,8 +5380,11 @@ is_valid_constexpr_fn (tree fun, bool complain)
{ {
ret = false; ret = false;
if (complain) 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)) if (!DECL_CONSTRUCTOR_P (fun))
...@@ -5376,8 +5394,11 @@ is_valid_constexpr_fn (tree fun, bool complain) ...@@ -5376,8 +5394,11 @@ is_valid_constexpr_fn (tree fun, bool complain)
{ {
ret = false; ret = false;
if (complain) 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. */ /* Check this again here for cxx_eval_call_expression. */
...@@ -5386,7 +5407,11 @@ is_valid_constexpr_fn (tree fun, bool complain) ...@@ -5386,7 +5407,11 @@ is_valid_constexpr_fn (tree fun, bool complain)
{ {
ret = false; ret = false;
if (complain) 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) ...@@ -5640,18 +5665,13 @@ constexpr_fn_retval (tree body)
} }
} }
/* We are processing the definition of the constexpr function FUN. /* Subroutine of register_constexpr_fundef. BODY is the DECL_SAVED_TREE of
Check that its BODY fulfills the propriate requirements and FUN; do the necessary transformations to turn it into a single expression
enter it in the constexpr function definition table. that we can store in the hash table. */
For constructor BODY is actually the TREE_LIST of the
member-initializer list. */
tree static tree
register_constexpr_fundef (tree fun, tree body) massage_constexpr_body (tree fun, tree body)
{ {
constexpr_fundef entry;
constexpr_fundef **slot;
if (DECL_CONSTRUCTOR_P (fun)) if (DECL_CONSTRUCTOR_P (fun))
body = build_constexpr_constructor_member_initializers body = build_constexpr_constructor_member_initializers
(DECL_CONTEXT (fun), body); (DECL_CONTEXT (fun), body);
...@@ -5666,12 +5686,28 @@ register_constexpr_fundef (tree fun, tree body) ...@@ -5666,12 +5686,28 @@ register_constexpr_fundef (tree fun, tree body)
if (TREE_CODE (body) == CLEANUP_POINT_EXPR) if (TREE_CODE (body) == CLEANUP_POINT_EXPR)
body = TREE_OPERAND (body, 0); body = TREE_OPERAND (body, 0);
body = constexpr_fn_retval (body); body = constexpr_fn_retval (body);
if (body == NULL_TREE || body == error_mark_node) }
{ return body;
error ("body of constexpr function %qD not a return-statement", fun); }
DECL_DECLARED_CONSTEXPR_P (fun) = false;
return NULL; /* 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)) if (!potential_rvalue_constant_expression (body))
...@@ -5700,6 +5736,44 @@ register_constexpr_fundef (tree fun, tree body) ...@@ -5700,6 +5736,44 @@ register_constexpr_fundef (tree fun, tree body)
return fun; 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 /* Objects of this type represent calls to constexpr functions
along with the bindings of parameters to their arguments, for along with the bindings of parameters to their arguments, for
the purpose of compile time evaluation. */ the purpose of compile time evaluation. */
...@@ -6005,7 +6079,7 @@ cxx_eval_call_expression (const constexpr_call *old_call, tree t, ...@@ -6005,7 +6079,7 @@ cxx_eval_call_expression (const constexpr_call *old_call, tree t,
} }
if (TREE_CODE (fun) != FUNCTION_DECL) 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 " error_at (loc, "expression %qE does not designate a constexpr "
"function", fun); "function", fun);
*non_constant_p = true; *non_constant_p = true;
...@@ -6020,11 +6094,8 @@ cxx_eval_call_expression (const constexpr_call *old_call, tree t, ...@@ -6020,11 +6094,8 @@ cxx_eval_call_expression (const constexpr_call *old_call, tree t,
{ {
if (!allow_non_constant) if (!allow_non_constant)
{ {
error_at (loc, "%qD is not a constexpr function", fun); error_at (loc, "call to non-constexpr function %qD", fun);
if (DECL_TEMPLATE_INFO (fun) explain_invalid_constexpr_fn (fun);
&& DECL_DECLARED_CONSTEXPR_P (DECL_TEMPLATE_RESULT
(DECL_TI_TEMPLATE (fun))))
is_valid_constexpr_fn (fun, true);
} }
*non_constant_p = true; *non_constant_p = true;
return t; return t;
...@@ -7023,8 +7094,11 @@ cxx_eval_constant_expression (const constexpr_call *call, tree t, ...@@ -7023,8 +7094,11 @@ cxx_eval_constant_expression (const constexpr_call *call, tree t,
if (!literal_type_p (TREE_TYPE (t))) if (!literal_type_p (TREE_TYPE (t)))
{ {
if (!allow_non_constant) 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; *non_constant_p = true;
break; break;
} }
...@@ -7574,7 +7648,11 @@ potential_constant_expression_1 (tree t, bool want_rval, tsubst_flags_t flags) ...@@ -7574,7 +7648,11 @@ potential_constant_expression_1 (tree t, bool want_rval, tsubst_flags_t flags)
&& !morally_constexpr_builtin_function_p (fun)) && !morally_constexpr_builtin_function_p (fun))
{ {
if (flags & tf_error) if (flags & tf_error)
error ("%qD is not %<constexpr%>", fun); {
error_at (EXPR_LOC_OR_HERE (t),
"call to non-constexpr function %qD", fun);
explain_invalid_constexpr_fn (fun);
}
return false; return false;
} }
/* A call to a non-static member function takes the address /* 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) ...@@ -7588,12 +7666,7 @@ potential_constant_expression_1 (tree t, bool want_rval, tsubst_flags_t flags)
if (is_this_parameter (x)) if (is_this_parameter (x))
/* OK. */; /* OK. */;
else if (!potential_constant_expression_1 (x, rval, flags)) else if (!potential_constant_expression_1 (x, rval, flags))
{ return false;
if (flags & tf_error)
error ("object argument is not a potential "
"constant expression");
return false;
}
i = 1; i = 1;
} }
} }
...@@ -7609,22 +7682,13 @@ potential_constant_expression_1 (tree t, bool want_rval, tsubst_flags_t flags) ...@@ -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)) if (potential_constant_expression_1 (fun, rval, flags))
/* Might end up being a constant function pointer. */; /* Might end up being a constant function pointer. */;
else else
{ return false;
if (flags & tf_error)
error ("%qE is not a function name", fun);
return false;
}
} }
for (; i < nargs; ++i) for (; i < nargs; ++i)
{ {
tree x = get_nth_callarg (t, i); tree x = get_nth_callarg (t, i);
if (!potential_constant_expression_1 (x, rval, flags)) if (!potential_constant_expression_1 (x, rval, flags))
{ return false;
if (flags & tf_error)
error ("argument in position %qP is not a "
"potential constant expression", i);
return false;
}
} }
return true; return true;
} }
...@@ -7853,8 +7917,11 @@ potential_constant_expression_1 (tree t, bool want_rval, tsubst_flags_t flags) ...@@ -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 (!literal_type_p (TREE_TYPE (t)))
{ {
if (flags & tf_error) 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; return false;
} }
case INIT_EXPR: case INIT_EXPR:
......
2011-06-29 Jason Merrill <jason@redhat.com> 2011-06-29 Jason Merrill <jason@redhat.com>
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 <jason@redhat.com>
* g++.dg/cpp0x/constexpr-is_literal.C: Adjust. * g++.dg/cpp0x/constexpr-is_literal.C: Adjust.
2011-06-29 Richard Guenther <rguenther@suse.de> 2011-06-29 Richard Guenther <rguenther@suse.de>
......
...@@ -13,7 +13,7 @@ struct B { B(); operator int(); }; ...@@ -13,7 +13,7 @@ struct B { B(); operator int(); };
constexpr A<int> ai = { 42 }; constexpr A<int> ai = { 42 };
constexpr int i = ai.f(); constexpr int i = ai.f();
constexpr int b = A<B>().f(); // { dg-error "not a constexpr function" } constexpr int b = A<B>().f(); // { dg-error "non-constexpr function" }
template <class T> template <class T>
constexpr int f (T t) { return 42; } // { dg-error "parameter" } constexpr int f (T t) { return 42; } // { dg-error "parameter" }
......
// PR c++/45923
// { dg-options -std=c++0x }
int f(int);
template <class T>
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" }
...@@ -88,7 +88,7 @@ struct resource { ...@@ -88,7 +88,7 @@ struct resource {
} }
}; };
constexpr resource f(resource d) 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" } constexpr resource d = f(9); // { dg-error "resource" }
// 4.4 floating-point constant expressions // 4.4 floating-point constant expressions
...@@ -19,5 +19,5 @@ struct C ...@@ -19,5 +19,5 @@ struct C
constexpr int i = f(C<int>()); constexpr int i = f(C<int>());
constexpr int j = C<int>().m(C<int>()); constexpr int j = C<int>().m(C<int>());
constexpr int k = C<double>().m(A()); // { dg-error "not a constexpr function" } constexpr int k = C<double>().m(A()); // { dg-error "non-constexpr function" }
constexpr int l = g(C<double>(),A()); // { dg-error "not a constexpr function" } constexpr int l = g(C<double>(),A()); // { dg-error "non-constexpr function" }
...@@ -28,4 +28,4 @@ struct D ...@@ -28,4 +28,4 @@ struct D
C<D> c; C<D> c;
}; };
constexpr D d {}; // { dg-error "not a constexpr function" } constexpr D d {}; // { dg-error "non-constexpr function" }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment