commit 93c3af7c9f729c6675598c9e47e11b3e2b25673a
Author: Jason Merrill <jason@redhat.com>
Date: Tue Oct 26 18:28:45 2010 -0400
* parser.c (cp_parser_ctor_initializer_opt_and_function_body):
Make sure a constexpr ctor has an empty body.
* class.c (type_has_constexpr_default_constructor): New.
* cp-tree.h: Declare it.
* init.c (perform_member_init): Complain about uninitialized
member in constexpr ctor.
(emit_mem_initializers): And uninitialized base.
* decl.c (check_tag_decl): Fix typo.
* semantics.c (valid_type_in_constexpr_fundecl_p): New fn.
(is_valid_constexpr_fn): New fn.
(validate_constexpr_fundecl): Use it.
* decl.c (validate_constexpr_redeclaration): New.
(duplicate_decls): Use it.
(cp_finish_decl): Call validate_constexpr_fundecl and
ensure_literal_type_for_constexpr_object here.
(start_decl): Not here. Don't ICE on constexpr reference.
(check_for_uninitialized_const_var): Don't handle constexpr specially.
(grokfndecl): Set DECL_DECLARED_CONSTEXPR_P.
(check_static_variable_definition): Give friendly message about
missing constexpr.
(grokdeclarator): Complain about typedef and volatile with constexpr.
Reorganize. Give sorry about non-static data members in C++0x mode.
(start_preparsed_function): Check validate_constexpr_fundecl here.
(check_function_type): Not here.
* decl2.c (finish_static_data_member_decl): Don't complain about
in-class init.
* parser.c (CP_PARSER_FLAGS_ONLY_TYPE_OR_CONSTEXPR): New.
(cp_parser_condition): Pass it to cp_parser_decl_specifier_seq.
(cp_parser_decl_specifier_seq): Handle it.
(cp_parser_explicit_instantiation): Diagnose inline and constexpr.
@@ -4325,6 +4325,19 @@ type_has_user_provided_default_constructor (tree t)
return false;
}
+/* Returns true iff class T has a constexpr default constructor. */
+
+bool
+type_has_constexpr_default_constructor (tree t)
+{
+ tree fns;
+
+ if (!CLASS_TYPE_P (t))
+ return false;
+ fns = get_default_ctor (t);
+ return (fns && DECL_DECLARED_CONSTEXPR_P (fns));
+}
+
/* Returns true iff class TYPE has a virtual destructor. */
bool
@@ -4721,6 +4721,7 @@ extern tree in_class_defaulted_default_constructor (tree);
extern bool user_provided_p (tree);
extern bool type_has_user_provided_constructor (tree);
extern bool type_has_user_provided_default_constructor (tree);
+extern bool type_has_constexpr_default_constructor (tree);
extern bool type_has_virtual_destructor (tree);
extern bool type_has_move_constructor (tree);
extern bool type_has_move_assign (tree);
@@ -1128,6 +1128,32 @@ check_redeclaration_exception_specification (tree new_decl,
}
}
+/* Return true if OLD_DECL and NEW_DECL agree on constexprness.
+ Otherwise issue diagnostics. */
+
+static bool
+validate_constexpr_redeclaration (tree old_decl, tree new_decl)
+{
+ old_decl = STRIP_TEMPLATE (old_decl);
+ new_decl = STRIP_TEMPLATE (new_decl);
+ if (!VAR_OR_FUNCTION_DECL_P (old_decl)
+ || !VAR_OR_FUNCTION_DECL_P (new_decl))
+ return true;
+ if (DECL_DECLARED_CONSTEXPR_P (old_decl)
+ == DECL_DECLARED_CONSTEXPR_P (new_decl))
+ return true;
+ if (TREE_CODE (old_decl) == FUNCTION_DECL && DECL_BUILT_IN (old_decl))
+ {
+ /* Hide a built-in declaration. */
+ DECL_DECLARED_CONSTEXPR_P (old_decl)
+ = DECL_DECLARED_CONSTEXPR_P (new_decl);
+ return true;
+ }
+ error ("redeclaration %qD differs in %<constexpr%>", new_decl);
+ error ("from previous declaration %q+D", old_decl);
+ return false;
+}
+
#define GNU_INLINE_P(fn) (DECL_DECLARED_INLINE_P (fn) \
&& lookup_attribute ("gnu_inline", \
DECL_ATTRIBUTES (fn)))
@@ -1607,6 +1633,9 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
warn about it. */
warn_extern_redeclared_static (newdecl, olddecl);
+ if (!validate_constexpr_redeclaration (olddecl, newdecl))
+ return error_mark_node;
+
/* We have committed to returning 1 at this point. */
if (TREE_CODE (newdecl) == FUNCTION_DECL)
{
@@ -4029,7 +4058,7 @@ check_tag_decl (cp_decl_specifier_seq *declspecs)
else if (saw_typedef)
warning (0, "%<typedef%> was ignored in this declaration");
else if (declspecs->specs[(int) ds_constexpr])
- error ("%<constexpr> cannot be used for type declarations");
+ error ("%<constexpr%> cannot be used for type declarations");
}
return declared_type;
@@ -4310,9 +4339,6 @@ start_decl (const cp_declarator *declarator,
&& !alias)
permerror (input_location, "declaration of %q#D outside of class is not definition",
decl);
-
- if (!ensure_literal_type_for_constexpr_object (decl))
- return error_mark_node;
}
was_public = TREE_PUBLIC (decl);
@@ -4344,7 +4370,7 @@ start_decl (const cp_declarator *declarator,
/* This is a const variable with implicit 'static'. Set
DECL_THIS_STATIC so we can tell it from variables that are
!TREE_PUBLIC because of the anonymous namespace. */
- gcc_assert (CP_TYPE_CONST_P (TREE_TYPE (decl)));
+ gcc_assert (CP_TYPE_CONST_P (TREE_TYPE (decl)) || errorcount);
DECL_THIS_STATIC (decl) = 1;
}
@@ -4753,14 +4779,10 @@ check_for_uninitialized_const_var (tree decl)
{
tree type = strip_array_types (TREE_TYPE (decl));
- if (TREE_CODE (decl) == VAR_DECL && DECL_DECLARED_CONSTEXPR_P (decl)
- && DECL_INITIAL (decl) == NULL)
- error ("missing initializer for constexpr %qD", decl);
-
/* ``Unless explicitly declared extern, a const object does not have
external linkage and must be initialized. ($8.4; $12.1)'' ARM
7.1.6 */
- else if (TREE_CODE (decl) == VAR_DECL
+ if (TREE_CODE (decl) == VAR_DECL
&& TREE_CODE (type) != REFERENCE_TYPE
&& CP_TYPE_CONST_P (type)
&& (!TYPE_NEEDS_CONSTRUCTING (type)
@@ -5691,6 +5713,12 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
}
}
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ validate_constexpr_fundecl (decl);
+
+ else if (!ensure_literal_type_for_constexpr_object (decl))
+ DECL_DECLARED_CONSTEXPR_P (decl) = 0;
+
if (init && TREE_CODE (decl) == FUNCTION_DECL)
{
tree clone;
@@ -6959,6 +6987,8 @@ grokfndecl (tree ctype,
/* If the declaration was declared inline, mark it as such. */
if (inlinep)
DECL_DECLARED_INLINE_P (decl) = 1;
+ if (inlinep & 2)
+ DECL_DECLARED_CONSTEXPR_P (decl) = true;
DECL_EXTERNAL (decl) = 1;
if (quals && TREE_CODE (type) == FUNCTION_TYPE)
@@ -7341,6 +7371,21 @@ build_ptrmem_type (tree class_type, tree member_type)
int
check_static_variable_definition (tree decl, tree type)
{
+ /* If DECL is declared constexpr, we'll do the appropriate checks
+ in check_initializer. */
+ if (DECL_P (decl) && DECL_DECLARED_CONSTEXPR_P (decl))
+ return 0;
+ else if (cxx_dialect >= cxx0x && !INTEGRAL_OR_ENUMERATION_TYPE_P (type))
+ {
+ if (literal_type_p (type))
+ error ("%<constexpr%> needed for in-class initialization of static "
+ "data member %q#D of non-integral type", decl);
+ else
+ error ("in-class initialization of static data member %q#D of "
+ "non-literal type", decl);
+ return 1;
+ }
+
/* Motion 10 at San Diego: If a static const integral data member is
initialized with an integral constant expression, the initializer
may appear either in the declaration (within the class), or in
@@ -7352,10 +7397,6 @@ check_static_variable_definition (tree decl, tree type)
error ("invalid in-class initialization of static data member "
"of non-integral type %qT",
type);
- /* If we just return the declaration, crashes will sometimes
- occur. We therefore return void_type_node, as if this were a
- friend declaration, to cause callers to completely ignore
- this declaration. */
return 1;
}
else if (!CP_TYPE_CONST_P (type))
@@ -8046,6 +8087,12 @@ grokdeclarator (const cp_declarator *declarator,
if (name == NULL)
name = decl_context == PARM ? "parameter" : "type name";
+ if (constexpr_p && declspecs->specs[(int)ds_typedef])
+ {
+ error ("%<constexpr%> cannot appear in a typedef declaration");
+ return error_mark_node;
+ }
+
/* If there were multiple types specified in the decl-specifier-seq,
issue an error message. */
if (declspecs->multiple_types_p)
@@ -8299,17 +8346,6 @@ grokdeclarator (const cp_declarator *declarator,
type_quals = TYPE_UNQUALIFIED;
if (declspecs->specs[(int)ds_const])
type_quals |= TYPE_QUAL_CONST;
- /* A `constexpr' specifier used in an object declaration declares
- the object as `const'. */
- if (constexpr_p)
- {
- if (innermost_code == cdk_function)
- ;
- else if (declspecs->specs[(int)ds_const] != 0)
- error ("both %<const%> and %<constexpr%> cannot be used here");
- else
- type_quals |= TYPE_QUAL_CONST;
- }
if (declspecs->specs[(int)ds_volatile])
type_quals |= TYPE_QUAL_VOLATILE;
if (declspecs->specs[(int)ds_restrict])
@@ -8686,21 +8722,6 @@ grokdeclarator (const cp_declarator *declarator,
}
}
- /* It is not allowed to use `constexpr' in a function
- declaration that is not a definition.
- That is too strict, though. */
- if (constexpr_p && !funcdef_flag)
- {
- error ("the %<constexpr%> specifier cannot be used in "
- "a function declaration that is not a definition");
- constexpr_p = false;
- }
-
- /* A constexpr non-static member function is implicitly const. */
- if (constexpr_p && decl_context == FIELD && staticp == 0
- && sfk != sfk_constructor && sfk != sfk_destructor)
- memfn_quals |= TYPE_QUAL_CONST;
-
arg_types = grokparms (declarator->u.function.parameters,
&parms);
@@ -8878,6 +8899,18 @@ grokdeclarator (const cp_declarator *declarator,
}
}
+ /* A `constexpr' specifier used in an object declaration declares
+ the object as `const'. */
+ if (constexpr_p && innermost_code != cdk_function)
+ {
+ if (type_quals & TYPE_QUAL_CONST)
+ error ("both %<const%> and %<constexpr%> cannot be used here");
+ if (type_quals & TYPE_QUAL_VOLATILE)
+ error ("both %<volatile%> and %<constexpr%> cannot be used here");
+ type_quals |= TYPE_QUAL_CONST;
+ type = cp_build_qualified_type (type, type_quals);
+ }
+
if (unqualified_id && TREE_CODE (unqualified_id) == TEMPLATE_ID_EXPR
&& TREE_CODE (type) != FUNCTION_TYPE
&& TREE_CODE (type) != METHOD_TYPE)
@@ -8964,8 +8997,6 @@ grokdeclarator (const cp_declarator *declarator,
return error_mark_node;
else if (TREE_CODE (type) == FUNCTION_TYPE)
{
- tree sname = declarator->u.id.unqualified_name;
-
if (current_class_type
&& (!friendp || funcdef_flag))
{
@@ -8975,20 +9006,6 @@ grokdeclarator (const cp_declarator *declarator,
ctype, name, current_class_type);
return error_mark_node;
}
-
- /* It is not permitted to define a member function outside ist
- membership class as `constexpr'. */
- if (constexpr_p)
- error ("a constexpr function cannot be defined "
- "outside of its class");
-
- if (TREE_CODE (sname) == IDENTIFIER_NODE
- && NEW_DELETE_OPNAME_P (sname))
- /* Overloaded operator new and operator delete
- are always static functions. */
- ;
- else
- type = build_memfn_type (type, ctype, memfn_quals);
}
else if (declspecs->specs[(int)ds_typedef]
&& current_class_type)
@@ -8999,6 +9016,15 @@ grokdeclarator (const cp_declarator *declarator,
}
}
+ if (ctype == NULL_TREE && decl_context == FIELD && friendp == 0)
+ ctype = current_class_type;
+
+ /* A constexpr non-static member function is implicitly const. */
+ if (constexpr_p && ctype && staticp == 0
+ && TREE_CODE (type) == FUNCTION_TYPE
+ && sfk != sfk_constructor && sfk != sfk_destructor)
+ memfn_quals |= TYPE_QUAL_CONST;
+
/* Now TYPE has the actual type. */
if (returned_attrs)
@@ -9362,6 +9388,10 @@ grokdeclarator (const cp_declarator *declarator,
type = build_pointer_type (type);
}
+ if (ctype && TREE_CODE (type) == FUNCTION_TYPE && staticp < 2
+ && !NEW_DELETE_OPNAME_P (unqualified_id))
+ type = build_memfn_type (type, ctype, memfn_quals);
+
{
tree decl;
@@ -9395,22 +9425,15 @@ grokdeclarator (const cp_declarator *declarator,
error ("invalid use of %<::%>");
return error_mark_node;
}
- else if (TREE_CODE (type) == FUNCTION_TYPE)
+ else if (TREE_CODE (type) == FUNCTION_TYPE
+ || TREE_CODE (type) == METHOD_TYPE)
{
int publicp = 0;
tree function_context;
if (friendp == 0)
{
- if (ctype == NULL_TREE)
- ctype = current_class_type;
-
- if (ctype == NULL_TREE)
- {
- error ("can't make %qD into a method -- not in a class",
- unqualified_id);
- return error_mark_node;
- }
+ gcc_assert (ctype);
/* ``A union may [ ... ] not [ have ] virtual functions.''
ARM 9.5 */
@@ -9431,8 +9454,6 @@ grokdeclarator (const cp_declarator *declarator,
virtualp = 0;
}
}
- else if (staticp < 2)
- type = build_memfn_type (type, ctype, memfn_quals);
}
/* Check that the name used for a destructor makes sense. */
@@ -9455,9 +9476,12 @@ grokdeclarator (const cp_declarator *declarator,
return error_mark_node;
}
if (constexpr_p)
- error ("a destructor cannot be %<constexpr%>");
+ {
+ error ("a destructor cannot be %<constexpr%>");
+ return error_mark_node;
+ }
}
- else if (sfk == sfk_constructor && friendp)
+ else if (sfk == sfk_constructor && friendp && !ctype)
{
error ("expected qualified name in friend declaration "
"for constructor %qD",
@@ -9477,7 +9501,7 @@ grokdeclarator (const cp_declarator *declarator,
unqualified_id,
virtualp, flags, memfn_quals, raises,
friendp ? -1 : 0, friendp, publicp,
- inlinep || constexpr_p,
+ inlinep | (2 * constexpr_p),
sfk,
funcdef_flag, template_count, in_namespace,
attrlist, declarator->id_loc);
@@ -9499,25 +9523,6 @@ grokdeclarator (const cp_declarator *declarator,
if (explicitp == 2)
DECL_NONCONVERTING_P (decl) = 1;
}
- else if (TREE_CODE (type) == METHOD_TYPE)
- {
- /* We only get here for friend declarations of
- members of other classes. */
- /* All method decls are public, so tell grokfndecl to set
- TREE_PUBLIC, also. */
- decl = grokfndecl (ctype, type,
- TREE_CODE (unqualified_id) != TEMPLATE_ID_EXPR
- ? unqualified_id : dname,
- parms,
- unqualified_id,
- virtualp, flags, memfn_quals, raises,
- friendp ? -1 : 0, friendp, 1, 0, sfk,
- funcdef_flag, template_count, in_namespace,
- attrlist,
- declarator->id_loc);
- if (decl == NULL_TREE)
- return error_mark_node;
- }
else if (!staticp && !dependent_type_p (type)
&& !COMPLETE_TYPE_P (complete_type (type))
&& (TREE_CODE (type) != ARRAY_TYPE || initialized == 0))
@@ -9596,15 +9601,25 @@ grokdeclarator (const cp_declarator *declarator,
the rest of the compiler does not correctly
handle the initialization unless the member is
static so we make it static below. */
- permerror (input_location, "ISO C++ forbids initialization of member %qD",
- unqualified_id);
- permerror (input_location, "making %qD static", unqualified_id);
- staticp = 1;
+ if (cxx_dialect >= cxx0x)
+ {
+ sorry ("non-static data member initializers");
+ }
+ else
+ {
+ permerror (input_location, "ISO C++ forbids initialization of member %qD",
+ unqualified_id);
+ permerror (input_location, "making %qD static", unqualified_id);
+ staticp = 1;
+ }
}
if (uses_template_parms (type))
/* We'll check at instantiation time. */
;
+ else if (constexpr_p)
+ /* constexpr has the same requirements. */
+ ;
else if (check_static_variable_definition (unqualified_id,
type))
/* If we just return the declaration, crashes
@@ -9714,11 +9729,6 @@ grokdeclarator (const cp_declarator *declarator,
sfk = sfk_none;
}
}
- else if (TREE_CODE (type) == FUNCTION_TYPE && staticp < 2
- && !NEW_DELETE_OPNAME_P (original_name))
- type = build_method_type_directly (ctype,
- TREE_TYPE (type),
- TYPE_ARG_TYPES (type));
/* Record presence of `static'. */
publicp = (ctype != NULL_TREE
@@ -9728,7 +9738,8 @@ grokdeclarator (const cp_declarator *declarator,
decl = grokfndecl (ctype, type, original_name, parms, unqualified_id,
virtualp, flags, memfn_quals, raises,
1, friendp,
- publicp, inlinep || constexpr_p, sfk, funcdef_flag,
+ publicp, inlinep | (2 * constexpr_p), sfk,
+ funcdef_flag,
template_count, in_namespace, attrlist,
declarator->id_loc);
if (decl == NULL_TREE)
@@ -9797,6 +9808,9 @@ grokdeclarator (const cp_declarator *declarator,
storage_class = sc_none;
}
}
+ else if (constexpr_p && DECL_EXTERNAL (decl))
+ error ("declaration of constexpr variable %qD is not a definition",
+ decl);
}
if (storage_class == sc_extern && initialized && !funcdef_flag)
@@ -9826,8 +9840,8 @@ grokdeclarator (const cp_declarator *declarator,
DECL_THIS_STATIC (decl) = 1;
/* Don't forget constexprness. */
- if (VAR_OR_FUNCTION_DECL_P (decl))
- DECL_DECLARED_CONSTEXPR_P (decl) = constexpr_p;
+ if (constexpr_p)
+ DECL_DECLARED_CONSTEXPR_P (decl) = true;
/* Record constancy and volatility on the DECL itself . There's
no need to do this when processing a template; we'll do this
@@ -11863,10 +11877,6 @@ check_function_type (tree decl, tree current_function_parms)
/* In a function definition, arg types must be complete. */
require_complete_types_for_parms (current_function_parms);
- /* constexpr functions must have literal argument types and
- literal return type. */
- validate_constexpr_fundecl (decl);
-
if (dependent_type_p (return_type))
return;
if (!COMPLETE_OR_VOID_TYPE_P (return_type)
@@ -12126,6 +12136,10 @@ 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;
@@ -771,21 +771,6 @@ finish_static_data_member_decl (tree decl,
permerror (input_location, "local class %q#T shall not have static data member %q#D",
current_class_type, decl);
- /* Static consts need not be initialized in the class definition. */
- if (init != NULL_TREE && TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl)))
- {
- static int explained = 0;
-
- error ("initializer invalid for static member with constructor");
- if (!explained)
- {
- error ("(an out of class initialization is required)");
- explained = 1;
- }
- init = NULL_TREE;
- }
-
- DECL_INITIAL (decl) = init;
DECL_IN_AGGR_P (decl) = 1;
if (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE
@@ -533,6 +533,15 @@ perform_member_init (tree member, tree init)
"uninitialized member %qD with %<const%> type %qT",
member, type);
+ if (DECL_DECLARED_CONSTEXPR_P (current_function_decl)
+ && !type_has_constexpr_default_constructor (type))
+ {
+ if (!DECL_TEMPLATE_INSTANTIATION (current_function_decl))
+ error ("uninitialized member %qD in %<constexpr%> constructor",
+ member);
+ DECL_DECLARED_CONSTEXPR_P (current_function_decl) = false;
+ }
+
core_type = strip_array_types (type);
if (CLASS_TYPE_P (core_type)
&& (CLASSTYPE_READONLY_FIELDS_NEED_INIT (core_type)
@@ -864,17 +873,30 @@ emit_mem_initializers (tree mem_inits)
tree subobject = TREE_PURPOSE (mem_inits);
tree arguments = TREE_VALUE (mem_inits);
- /* If these initializations are taking place in a copy constructor,
- the base class should probably be explicitly initialized if there
- is a user-defined constructor in the base class (other than the
- default constructor, which will be called anyway). */
- if (extra_warnings && !arguments
- && DECL_COPY_CONSTRUCTOR_P (current_function_decl)
- && type_has_user_nondefault_constructor (BINFO_TYPE (subobject)))
- warning_at (DECL_SOURCE_LOCATION (current_function_decl), OPT_Wextra,
- "base class %q#T should be explicitly initialized in the "
- "copy constructor",
- BINFO_TYPE (subobject));
+ if (arguments == NULL_TREE)
+ {
+ /* If these initializations are taking place in a copy constructor,
+ the base class should probably be explicitly initialized if there
+ is a user-defined constructor in the base class (other than the
+ default constructor, which will be called anyway). */
+ if (extra_warnings
+ && DECL_COPY_CONSTRUCTOR_P (current_function_decl)
+ && type_has_user_nondefault_constructor (BINFO_TYPE (subobject)))
+ warning_at (DECL_SOURCE_LOCATION (current_function_decl),
+ 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. */
if (BINFO_VIRTUAL_P (subobject))
@@ -1334,7 +1334,10 @@ enum
CP_PARSER_FLAGS_NO_USER_DEFINED_TYPES = 0x2,
/* When parsing a type-specifier, do not try to parse a class-specifier
or enum-specifier. */
- CP_PARSER_FLAGS_NO_TYPE_DEFINITIONS = 0x4
+ CP_PARSER_FLAGS_NO_TYPE_DEFINITIONS = 0x4,
+ /* When parsing a decl-specifier-seq, only allow type-specifier or
+ constexpr. */
+ CP_PARSER_FLAGS_ONLY_TYPE_OR_CONSTEXPR = 0x8
};
/* This type is used for parameters and variables which hold
@@ -8509,6 +8512,7 @@ cp_parser_condition (cp_parser* parser)
{
cp_decl_specifier_seq type_specifiers;
const char *saved_message;
+ int declares_class_or_enum;
/* Try the declaration first. */
cp_parser_parse_tentatively (parser);
@@ -8518,9 +8522,10 @@ cp_parser_condition (cp_parser* parser)
parser->type_definition_forbidden_message
= G_("types may not be defined in conditions");
/* Parse the type-specifier-seq. */
- cp_parser_type_specifier_seq (parser, /*is_declaration==*/true,
- /*is_trailing_return=*/false,
- &type_specifiers);
+ cp_parser_decl_specifier_seq (parser,
+ CP_PARSER_FLAGS_ONLY_TYPE_OR_CONSTEXPR,
+ &type_specifiers,
+ &declares_class_or_enum);
/* Restore the saved message. */
parser->type_definition_forbidden_message = saved_message;
/* If all is well, we might be looking at a declaration. */
@@ -9851,6 +9856,11 @@ cp_parser_decl_specifier_seq (cp_parser* parser,
break;
}
+ if (found_decl_spec
+ && (flags & CP_PARSER_FLAGS_ONLY_TYPE_OR_CONSTEXPR)
+ && token->keyword != RID_CONSTEXPR)
+ error ("decl-specifier invalid in condition");
+
/* Constructors are a special case. The `S' in `S()' is not a
decl-specifier; it is the beginning of the declarator. */
constructor_p
@@ -12231,6 +12241,13 @@ cp_parser_explicit_instantiation (cp_parser* parser)
decl_specifiers.type_location);
if (declarator != cp_error_declarator)
{
+ if (decl_specifiers.specs[(int)ds_inline])
+ permerror (input_location, "explicit instantiation shall not use"
+ " %<inline%> specifier");
+ if (decl_specifiers.specs[(int)ds_constexpr])
+ permerror (input_location, "explicit instantiation shall not use"
+ " %<constexpr%> specifier");
+
decl = grokdeclarator (declarator, &decl_specifiers,
NORMAL, 0, &decl_specifiers.attributes);
/* Turn access control back on for names used during
@@ -16245,15 +16262,43 @@ cp_parser_function_body (cp_parser *parser)
static bool
cp_parser_ctor_initializer_opt_and_function_body (cp_parser *parser)
{
- tree body;
+ tree body, list;
bool ctor_initializer_p;
+ const bool check_body_p =
+ DECL_CONSTRUCTOR_P (current_function_decl)
+ && DECL_DECLARED_CONSTEXPR_P (current_function_decl);
+ tree last = NULL;
/* Begin the function body. */
body = begin_function_body ();
/* Parse the optional ctor-initializer. */
ctor_initializer_p = cp_parser_ctor_initializer_opt (parser);
+
+ /* If we're parsing a constexpr constructor definition, we need
+ to check that the constructor body is indeed empty. However,
+ before we get to cp_parser_function_body lot of junk has been
+ generated, so we can't just check that we have an empty block.
+ Rather we take a snapshot of the outermost block, and check whether
+ cp_parser_function_body changed its state. */
+ if (check_body_p)
+ {
+ list = body;
+ if (TREE_CODE (list) == BIND_EXPR)
+ list = BIND_EXPR_BODY (list);
+ if (TREE_CODE (list) == STATEMENT_LIST
+ && STATEMENT_LIST_TAIL (list) != NULL)
+ last = STATEMENT_LIST_TAIL (list)->stmt;
+ }
/* Parse the function-body. */
cp_parser_function_body (parser);
+ if (check_body_p
+ && (TREE_CODE (list) != STATEMENT_LIST
+ || (last == NULL && STATEMENT_LIST_TAIL (list) != NULL)
+ || (last != NULL && last != STATEMENT_LIST_TAIL (list)->stmt)))
+ {
+ error ("constexpr constructor does not have empty body");
+ DECL_DECLARED_CONSTEXPR_P (current_function_decl) = false;
+ }
/* Finish the function body. */
finish_function_body (body);
@@ -5277,6 +5277,59 @@ ensure_literal_type_for_constexpr_object (tree decl)
return decl;
}
+/* Return true if type expression T is a valid parameter type, or
+ a valid return type, of a constexpr function. */
+
+static bool
+valid_type_in_constexpr_fundecl_p (tree t)
+{
+ return (literal_type_p (t)
+ /* FIXME we allow ref to non-literal; should change standard to
+ match, or change back if not. */
+ || TREE_CODE (t) == REFERENCE_TYPE);
+}
+
+/* Check whether the parameter and return types of FUN are valid for a
+ constexpr function, and complain if COMPLAIN. */
+
+static bool
+is_valid_constexpr_fn (tree fun, bool complain)
+{
+ tree parm = FUNCTION_FIRST_USER_PARM (fun);
+ bool ret = true;
+ for (; parm != NULL; parm = TREE_CHAIN (parm))
+ if (!valid_type_in_constexpr_fundecl_p (TREE_TYPE (parm)))
+ {
+ ret = false;
+ if (complain)
+ error ("invalid type for parameter %q#D of constexpr function",
+ parm);
+ }
+
+ if (!DECL_CONSTRUCTOR_P (fun))
+ {
+ tree rettype = TREE_TYPE (TREE_TYPE (fun));
+ if (!valid_type_in_constexpr_fundecl_p (rettype))
+ {
+ ret = false;
+ if (complain)
+ error ("invalid return type %qT of constexpr function %qD",
+ rettype, fun);
+ }
+
+ if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fun)
+ && COMPLETE_TYPE_P (DECL_CONTEXT (fun))
+ && !valid_type_in_constexpr_fundecl_p (DECL_CONTEXT (fun)))
+ {
+ ret = false;
+ if (complain)
+ error ("enclosing class of %q#D is not a literal type", fun);
+ }
+ }
+
+ return ret;
+}
+
/* 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
@@ -5285,43 +5338,18 @@ ensure_literal_type_for_constexpr_object (tree decl)
tree
validate_constexpr_fundecl (tree fun)
{
- tree rettype = NULL;
- tree parm = NULL;
-
- /* Don't bother if FUN is not marked constexpr. */
- if (!DECL_DECLARED_CONSTEXPR_P (fun))
+ if (processing_template_decl || !DECL_DECLARED_CONSTEXPR_P (fun))
return NULL;
-
- /* For a function template, we have absolutely no guarantee that all
- instantiations will be constexpr. */
- if (TREE_CODE (fun) == TEMPLATE_DECL)
- return NULL;
-
- parm = FUNCTION_FIRST_USER_PARM (fun);
- for (; parm != NULL; parm = TREE_CHAIN (parm))
- {
- tree type = TREE_TYPE (parm);
- if (dependent_type_p (type))
- return NULL;
- if (!literal_type_p (type))
- {
- error ("parameter %q#D is not of literal type", parm);
- return NULL;
- }
- }
-
- if (DECL_CONSTRUCTOR_P (fun))
+ else if (DECL_CLONED_FUNCTION_P (fun))
+ /* We already checked the original function. */
return fun;
- rettype = TREE_TYPE (TREE_TYPE (fun));
- if (dependent_type_p (rettype))
- return NULL;
- if (!literal_type_p (rettype))
+ if (!is_valid_constexpr_fn (fun, !DECL_TEMPLATE_INSTANTIATION (fun)))
{
- error ("return type %qT of function %qD is not a literal type",
- TREE_TYPE (TREE_TYPE (fun)), fun);
+ DECL_DECLARED_CONSTEXPR_P (fun) = false;
return NULL;
}
+
return fun;
}
new file mode 100644
@@ -0,0 +1,2 @@
+// { dg-options -std=c++0x }
+constexpr auto value = 0;
new file mode 100644
@@ -0,0 +1,9 @@
+// { dg-options -std=c++0x }
+// Core DR 948
+
+constexpr int something() { return 3; }
+
+int main() {
+ if (constexpr long v = something()) {}
+ if (static long v = something()) { } // { dg-error "decl-specifier invalid" }
+}
new file mode 100644
@@ -0,0 +1,7 @@
+// { dg-options -std=c++0x }
+
+struct A
+{
+ int i;
+ constexpr A() { } // { dg-error "uninitialized member .A::i" }
+};
new file mode 100644
@@ -0,0 +1,5 @@
+// { dg-options -std=c++0x }
+// Error: Explicit instantiation of a function template shall not use the
+// inline or constexpr specifiers
+template<class T> constexpr inline T bar(T x) { return x; }
+template constexpr inline float bar(float x); // { dg-error "specifier" }
new file mode 100644
@@ -0,0 +1,3 @@
+// { dg-options -std=c++0x }
+int x;
+constexpr int& rx = x; // { dg-error "int&" }