@@ -9933,7 +9933,6 @@ grokdeclarator (const cp_declarator *declarator,
return error_mark_node;
}
- DECL_DECLARED_CONSTEXPR_P (decl) = constexpr_p;
decl = do_friend (ctype, unqualified_id, decl,
*attrlist, flags,
funcdef_flag);
@@ -10183,8 +10182,11 @@ grokdeclarator (const cp_declarator *declarator,
}
}
else if (constexpr_p && DECL_EXTERNAL (decl))
- error ("declaration of constexpr variable %qD is not a definition",
- decl);
+ {
+ error ("declaration of constexpr variable %qD is not a definition",
+ decl);
+ constexpr_p = false;
+ }
}
if (storage_class == sc_extern && initialized && !funcdef_flag)
@@ -10213,8 +10215,8 @@ grokdeclarator (const cp_declarator *declarator,
else if (storage_class == sc_static)
DECL_THIS_STATIC (decl) = 1;
- /* Don't forget constexprness. */
- if (constexpr_p)
+ /* Set constexpr flag on vars (functions got it in grokfndecl). */
+ if (constexpr_p && TREE_CODE (decl) == VAR_DECL)
DECL_DECLARED_CONSTEXPR_P (decl) = true;
/* Record constancy and volatility on the DECL itself . There's
commit 90613a6af841f2a8563c0669be47211c52a08d35
Author: Jason Merrill <jason@redhat.com>
Date: Wed May 11 00:31:29 2011 -0400
* semantics.c (register_constexpr_fundef): Add to hash table here.
(validate_constexpr_fundecl): Not here.
@@ -5456,9 +5456,6 @@ is_valid_constexpr_fn (tree fun, bool complain)
tree
validate_constexpr_fundecl (tree fun)
{
- constexpr_fundef entry;
- constexpr_fundef **slot;
-
if (processing_template_decl || !DECL_DECLARED_CONSTEXPR_P (fun))
return NULL;
else if (DECL_CLONED_FUNCTION_P (fun))
@@ -5471,21 +5468,6 @@ validate_constexpr_fundecl (tree fun)
return NULL;
}
- /* Create the constexpr function table if necessary. */
- if (constexpr_fundef_table == NULL)
- constexpr_fundef_table = htab_create_ggc (101,
- constexpr_fundef_hash,
- constexpr_fundef_equal,
- ggc_free);
- entry.decl = fun;
- entry.body = NULL;
- slot = (constexpr_fundef **)
- htab_find_slot (constexpr_fundef_table, &entry, INSERT);
- if (*slot == NULL)
- {
- *slot = ggc_alloc_constexpr_fundef ();
- **slot = entry;
- }
return fun;
}
@@ -5722,8 +5704,8 @@ constexpr_fn_retval (tree body)
tree
register_constexpr_fundef (tree fun, tree body)
{
- constexpr_fundef *fundef = retrieve_constexpr_fundef (fun);
- gcc_assert (fundef != NULL && fundef->body == NULL);
+ constexpr_fundef entry;
+ constexpr_fundef **slot;
if (DECL_CONSTRUCTOR_P (fun))
body = build_constexpr_constructor_member_initializers
@@ -5754,7 +5736,22 @@ register_constexpr_fundef (tree fun, tree body)
require_potential_rvalue_constant_expression (body);
return NULL;
}
- fundef->body = body;
+
+ /* Create the constexpr function table if necessary. */
+ if (constexpr_fundef_table == NULL)
+ constexpr_fundef_table = htab_create_ggc (101,
+ constexpr_fundef_hash,
+ constexpr_fundef_equal,
+ ggc_free);
+ entry.decl = fun;
+ entry.body = body;
+ slot = (constexpr_fundef **)
+ htab_find_slot (constexpr_fundef_table, &entry, INSERT);
+
+ gcc_assert (*slot == NULL);
+ *slot = ggc_alloc_constexpr_fundef ();
+ **slot = entry;
+
return fun;
}
commit 328b9d1a57762cb23d4572771ff8d2ee00d016e4
Author: Jason Merrill <jason@redhat.com>
Date: Wed May 11 00:32:18 2011 -0400
* semantics.c (validate_constexpr_fundecl): Check DECL_TEMPLATE_INFO
rather than DECL_TEMPLATE_INSTANTIATION.
(cxx_eval_call_expression): Likewise.
@@ -5462,7 +5462,7 @@ validate_constexpr_fundecl (tree fun)
/* We already checked the original function. */
return fun;
- if (!is_valid_constexpr_fn (fun, !DECL_TEMPLATE_INSTANTIATION (fun)))
+ if (!is_valid_constexpr_fn (fun, !DECL_TEMPLATE_INFO (fun)))
{
DECL_DECLARED_CONSTEXPR_P (fun) = false;
return NULL;
@@ -5732,7 +5732,7 @@ register_constexpr_fundef (tree fun, tree body)
if (!potential_rvalue_constant_expression (body))
{
DECL_DECLARED_CONSTEXPR_P (fun) = false;
- if (!DECL_TEMPLATE_INSTANTIATION (fun))
+ if (!DECL_TEMPLATE_INFO (fun))
require_potential_rvalue_constant_expression (body);
return NULL;
}
@@ -6076,7 +6076,7 @@ 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_INSTANTIATION (fun)
+ if (DECL_TEMPLATE_INFO (fun)
&& DECL_DECLARED_CONSTEXPR_P (DECL_TEMPLATE_RESULT
(DECL_TI_TEMPLATE (fun))))
is_valid_constexpr_fn (fun, true);
commit abd449ca7061cfd47a36a65e52003dc1c823bfa0
Author: Jason Merrill <jason@redhat.com>
Date: Wed May 11 00:34:33 2011 -0400
PR c++/48948
* semantics.c (validate_constexpr_fundecl): Defer checking if
an argument type is being defined.
(is_valid_constexpr_fn): Add defer_ok parm.
(cxx_eval_call_expression): Adjust.
(check_deferred_constexpr_decls): New.
(literal_type_p): Make sure type isn't being defined.
(ensure_literal_type_for_constexpr_object): Handle type being defined.
* cp-tree.h: Declare check_deferred_constexpr_decls.
* decl.c (grokfndecl): Call validate_constexpr_fundecl here.
(start_preparsed_function, cp_finish_decl): Not here.
* class.c (finalize_literal_type_property): Don't call
validate_constexpr_fundecl.
(finish_struct): Call check_deferred_constexpr_decls.
* pt.c (tsubst_decl): Call validate_constexpr_fundecl.
(instantiate_class_template): Call check_deferred_constexpr_decls.
@@ -4578,8 +4578,6 @@ type_requires_array_cookie (tree type)
static void
finalize_literal_type_property (tree t)
{
- tree fn;
-
if (cxx_dialect < cxx0x
|| TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t)
/* FIXME These constraints seem unnecessary; remove from standard.
@@ -4589,11 +4587,6 @@ finalize_literal_type_property (tree t)
else if (CLASSTYPE_LITERAL_P (t) && !TYPE_HAS_TRIVIAL_DFLT (t)
&& !TYPE_HAS_CONSTEXPR_CTOR (t))
CLASSTYPE_LITERAL_P (t) = false;
-
- for (fn = TYPE_METHODS (t); fn; fn = DECL_CHAIN (fn))
- if (DECL_DECLARED_CONSTEXPR_P (fn)
- && TREE_CODE (fn) != TEMPLATE_DECL)
- validate_constexpr_fundecl (fn);
}
/* Check the validity of the bases and members declared in T. Add any
@@ -5834,6 +5827,8 @@ finish_struct (tree t, tree attributes)
else
error ("trying to finish struct, but kicked out due to previous parse errors");
+ check_deferred_constexpr_decls ();
+
if (processing_template_decl && at_function_scope_p ())
add_stmt (build_min (TAG_DEFN, t));
@@ -5323,6 +5323,7 @@ extern void finish_handler_parms (tree, tree);
extern void finish_handler (tree);
extern void finish_cleanup (tree, tree);
extern bool literal_type_p (tree);
+extern void check_deferred_constexpr_decls (void);
extern tree validate_constexpr_fundecl (tree);
extern tree register_constexpr_fundef (tree, tree);
extern bool check_constexpr_ctor_body (tree, tree);
@@ -5911,13 +5911,7 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
}
}
- if (TREE_CODE (decl) == FUNCTION_DECL
- /* For members, defer until finalize_literal_type_property. */
- && (!DECL_CLASS_SCOPE_P (decl)
- || !TYPE_BEING_DEFINED (DECL_CONTEXT (decl))))
- validate_constexpr_fundecl (decl);
-
- else if (!ensure_literal_type_for_constexpr_object (decl))
+ if (!ensure_literal_type_for_constexpr_object (decl))
DECL_DECLARED_CONSTEXPR_P (decl) = 0;
if (init && TREE_CODE (decl) == FUNCTION_DECL)
@@ -7206,7 +7200,10 @@ grokfndecl (tree ctype,
if (inlinep)
DECL_DECLARED_INLINE_P (decl) = 1;
if (inlinep & 2)
- DECL_DECLARED_CONSTEXPR_P (decl) = true;
+ {
+ DECL_DECLARED_CONSTEXPR_P (decl) = true;
+ validate_constexpr_fundecl (decl);
+ }
DECL_EXTERNAL (decl) = 1;
if (quals && TREE_CODE (type) == FUNCTION_TYPE)
@@ -12524,10 +12521,6 @@ start_preparsed_function (tree decl1, tree attrs, int flags)
maybe_apply_pragma_weak (decl1);
}
- /* constexpr functions must have literal argument types and
- literal return type. */
- validate_constexpr_fundecl (decl1);
-
/* Reset this in case the call to pushdecl changed it. */
current_function_decl = decl1;
@@ -8594,6 +8594,8 @@ instantiate_class_template_1 (tree type)
pop_deferring_access_checks ();
pop_tinst_level ();
+ check_deferred_constexpr_decls ();
+
/* The vtable for a template class can be emitted in any translation
unit in which the class is instantiated. When there is no key
method, however, finish_struct_1 will already have added TYPE to
@@ -9740,6 +9742,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
if (DECL_DEFAULTED_OUTSIDE_CLASS_P (r)
&& !processing_template_decl)
defaulted_late_check (r);
+ validate_constexpr_fundecl (r);
apply_late_template_attributes (&r, DECL_ATTRIBUTES (r), 0,
args, complain, in_decl);
@@ -5336,7 +5336,11 @@ literal_type_p (tree t)
|| TREE_CODE (t) == REFERENCE_TYPE)
return true;
if (CLASS_TYPE_P (t))
- return CLASSTYPE_LITERAL_P (t);
+ {
+ /* We can't answer this question until the class is complete. */
+ gcc_assert (!TYPE_BEING_DEFINED (t) || errorcount);
+ return CLASSTYPE_LITERAL_P (complete_type (t));
+ }
if (TREE_CODE (t) == ARRAY_TYPE)
return literal_type_p (strip_array_types (t));
return false;
@@ -5350,13 +5354,17 @@ ensure_literal_type_for_constexpr_object (tree decl)
{
tree type = TREE_TYPE (decl);
if (TREE_CODE (decl) == VAR_DECL && DECL_DECLARED_CONSTEXPR_P (decl)
- && !processing_template_decl
- /* The call to complete_type is just for initializer_list. */
- && !literal_type_p (complete_type (type)))
+ && !processing_template_decl)
{
- error ("the type %qT of constexpr variable %qD is not literal",
- type, decl);
- return NULL;
+ if (CLASS_TYPE_P (type) && TYPE_BEING_DEFINED (type))
+ /* Don't complain here, we'll complain about incompleteness
+ when we try to initialize the variable. */;
+ else if (!literal_type_p (type))
+ {
+ error ("the type %qT of constexpr variable %qD is not literal",
+ type, decl);
+ return NULL;
+ }
}
return decl;
}
@@ -5409,15 +5417,22 @@ retrieve_constexpr_fundef (tree fun)
}
/* Check whether the parameter and return types of FUN are valid for a
- constexpr function, and complain if COMPLAIN. */
+ constexpr function, and complain if COMPLAIN. If DEFER_OK is true,
+ return -1 if we can't tell yet because some of the types are still being
+ defined. */
-static bool
-is_valid_constexpr_fn (tree fun, bool complain)
+static int
+is_valid_constexpr_fn (tree fun, bool complain, bool defer_ok)
{
+#define IF_NON_LITERAL(TYPE) \
+ if (defer_ok && CLASS_TYPE_P (TYPE) && TYPE_BEING_DEFINED (TYPE)) \
+ return -1; \
+ else if (!literal_type_p (TYPE))
+
tree parm = FUNCTION_FIRST_USER_PARM (fun);
bool ret = true;
for (; parm != NULL; parm = TREE_CHAIN (parm))
- if (!literal_type_p (TREE_TYPE (parm)))
+ IF_NON_LITERAL (TREE_TYPE (parm))
{
ret = false;
if (complain)
@@ -5428,7 +5443,7 @@ is_valid_constexpr_fn (tree fun, bool complain)
if (!DECL_CONSTRUCTOR_P (fun))
{
tree rettype = TREE_TYPE (TREE_TYPE (fun));
- if (!literal_type_p (rettype))
+ IF_NON_LITERAL (rettype)
{
ret = false;
if (complain)
@@ -5436,18 +5451,51 @@ is_valid_constexpr_fn (tree fun, bool complain)
rettype, fun);
}
- if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fun)
- && !CLASSTYPE_LITERAL_P (DECL_CONTEXT (fun)))
+ if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fun))
{
- ret = false;
- if (complain)
- error ("enclosing class of %q+#D is not a literal type", fun);
+ IF_NON_LITERAL (DECL_CONTEXT (fun))
+ {
+ ret = false;
+ if (complain)
+ error ("enclosing class of %q+#D is not a literal type", fun);
+ }
}
}
return ret;
}
+/* We can't check the parameter and return types of a constexpr function
+ for literality until any open classes are complete, so we defer checking
+ of any constexpr functions declared in a class. */
+
+static GTY(()) VEC(tree,gc) *deferred_constexpr_decls;
+
+void
+check_deferred_constexpr_decls (void)
+{
+ unsigned i;
+ tree fn;
+
+ /* Some of the deferred decls might still need to be deferred,
+ so move the vector out of the way. */
+ VEC(tree,gc) *vec = deferred_constexpr_decls;
+ deferred_constexpr_decls = NULL;
+
+ FOR_EACH_VEC_ELT (tree, vec, i, fn)
+ validate_constexpr_fundecl (fn);
+
+ if (deferred_constexpr_decls == NULL)
+ {
+ /* If we didn't need to re-defer any, keep the same vector. */
+ VEC_truncate (tree, vec, 0);
+ deferred_constexpr_decls = vec;
+ }
+ else
+ /* Otherwise, discard the old vector. */
+ release_tree_vector (vec);
+}
+
/* Return non-null if FUN certainly designates a valid constexpr function
declaration. Otherwise return NULL. Issue appropriate diagnostics
if necessary. Note that we only check the declaration, not the body
@@ -5456,13 +5504,22 @@ is_valid_constexpr_fn (tree fun, bool complain)
tree
validate_constexpr_fundecl (tree fun)
{
+ int valid;
+
if (processing_template_decl || !DECL_DECLARED_CONSTEXPR_P (fun))
return NULL;
else if (DECL_CLONED_FUNCTION_P (fun))
/* We already checked the original function. */
return fun;
- if (!is_valid_constexpr_fn (fun, !DECL_TEMPLATE_INFO (fun)))
+ valid = is_valid_constexpr_fn (fun, !DECL_TEMPLATE_INFO (fun),
+ /*defer_ok=*/true);
+ if (valid < 0)
+ {
+ VEC_safe_push (tree, gc, deferred_constexpr_decls, fun);
+ return NULL;
+ }
+ else if (valid == 0)
{
DECL_DECLARED_CONSTEXPR_P (fun) = false;
return NULL;
@@ -6079,7 +6136,7 @@ cxx_eval_call_expression (const constexpr_call *old_call, tree t,
if (DECL_TEMPLATE_INFO (fun)
&& DECL_DECLARED_CONSTEXPR_P (DECL_TEMPLATE_RESULT
(DECL_TI_TEMPLATE (fun))))
- is_valid_constexpr_fn (fun, true);
+ is_valid_constexpr_fn (fun, true, /*defer_ok=*/false);
}
*non_constant_p = true;
return t;
new file mode 100644
@@ -0,0 +1,23 @@
+// PR c++/48948
+// { dg-options -std=c++0x }
+
+struct A { A(); };
+
+struct B {
+ friend constexpr int f(B) { return 0; } // OK
+ friend constexpr int f(A) { return 0; } // { dg-error "constexpr" }
+};
+
+template <class T>
+struct C
+{
+ friend constexpr int f(C) { return 0; }
+ friend constexpr int g(C, A) { return 0; } // { dg-error "double" }
+ constexpr int m(C) { return 0; }
+ constexpr int m(A) { return 0; } // { dg-error "double" }
+};
+
+constexpr int i = f(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 l = g(C<double>(),A()); // { dg-error "not a constexpr function" }
new file mode 100644
@@ -0,0 +1,7 @@
+// { dg-options -std=c++0x }
+
+struct A
+{
+ static constexpr A a = 1; // { dg-error "incomplete" }
+ constexpr A(int i) { }
+};