summaryrefslogtreecommitdiff
path: root/gcc/cp/semantics.c
diff options
context:
space:
mode:
authorbstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4>2011-06-30 19:13:32 +0000
committerbstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4>2011-06-30 19:13:32 +0000
commit879e6664462821e8f43500b22229bb2ac1e09cea (patch)
treeff6fbe2138242f2438e6bb48988cae82c4cf1a68 /gcc/cp/semantics.c
parenta36ec8263c25ecfe4e83aa19eaf33244394baa9c (diff)
downloadgcc-879e6664462821e8f43500b22229bb2ac1e09cea.tar.gz
2011-06-30 Basile Starynkevitch <basile@starynkevitch.net>
MELT branch merged with trunk rev 175718 using svnmerge. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/melt-branch@175720 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/cp/semantics.c')
-rw-r--r--gcc/cp/semantics.c200
1 files changed, 145 insertions, 55 deletions
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index d1af0c6bc2d..ad68a012d17 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));
+ }
}
}
@@ -5632,6 +5657,9 @@ constexpr_fn_retval (tree body)
return NULL_TREE;
return error_mark_node;
+ case CLEANUP_POINT_EXPR:
+ return constexpr_fn_retval (TREE_OPERAND (body, 0));
+
case USING_STMT:
return NULL_TREE;
@@ -5640,18 +5668,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);
@@ -5663,15 +5686,29 @@ register_constexpr_fundef (tree fun, tree body)
body = EH_SPEC_STMTS (body);
if (TREE_CODE (body) == MUST_NOT_THROW_EXPR)
body = TREE_OPERAND (body, 0);
- 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 +5737,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 +6080,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 +6095,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;
@@ -6646,7 +6718,7 @@ cxx_eval_vec_init_1 (const constexpr_call *call, tree atype, tree init,
if (!*non_constant_p)
{
- init = build_constructor (TREE_TYPE (atype), n);
+ init = build_constructor (atype, n);
TREE_CONSTANT (init) = true;
return init;
}
@@ -7023,8 +7095,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 +7649,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 %<constexpr%>", 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 +7667,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 +7683,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 +7918,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:
@@ -8422,6 +8490,27 @@ insert_pending_capture_proxies (void)
LAMBDA_EXPR_PENDING_PROXIES (lam) = NULL;
}
+/* Given REF, a COMPONENT_REF designating a field in the lambda closure,
+ return the type we want the proxy to have: the type of the field itself,
+ with added const-qualification if the lambda isn't mutable and the
+ capture is by value. */
+
+tree
+lambda_proxy_type (tree ref)
+{
+ tree type;
+ if (REFERENCE_REF_P (ref))
+ ref = TREE_OPERAND (ref, 0);
+ type = TREE_TYPE (ref);
+ if (!dependent_type_p (type))
+ return type;
+ type = cxx_make_type (DECLTYPE_TYPE);
+ DECLTYPE_TYPE_EXPR (type) = ref;
+ DECLTYPE_FOR_LAMBDA_PROXY (type) = true;
+ SET_TYPE_STRUCTURAL_EQUALITY (type);
+ return type;
+}
+
/* MEMBER is a capture field in a lambda closure class. Now that we're
inside the operator(), build a placeholder var for future lookups and
debugging. */
@@ -8429,7 +8518,7 @@ insert_pending_capture_proxies (void)
tree
build_capture_proxy (tree member)
{
- tree var, object, fn, closure, name, lam;
+ tree var, object, fn, closure, name, lam, type;
closure = DECL_CONTEXT (member);
fn = lambda_function (closure);
@@ -8444,7 +8533,8 @@ build_capture_proxy (tree member)
/* Remove the __ inserted by add_capture. */
name = get_identifier (IDENTIFIER_POINTER (DECL_NAME (member)) + 2);
- var = build_decl (input_location, VAR_DECL, name, TREE_TYPE (object));
+ type = lambda_proxy_type (object);
+ var = build_decl (input_location, VAR_DECL, name, type);
SET_DECL_VALUE_EXPR (var, object);
DECL_HAS_VALUE_EXPR_P (var) = 1;
DECL_ARTIFICIAL (var) = 1;