parser.c (cp_parser_ctor_initializer_opt_and_function_body): Make sure a constexpr ctor has an empty body.

* 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.

Co-Authored-By: Jason Merrill <jason@redhat.com>

From-SVN: r166013
This commit is contained in:
Gabriel Dos Reis 2010-10-27 15:31:33 -04:00 committed by Jason Merrill
parent 3b49d762b5
commit 91ea6df357
13 changed files with 334 additions and 168 deletions

View File

@ -1,6 +1,38 @@
2010-10-27 Gabriel Dos Reis <gdr@cse.tamu.edu>
Jason Merrill <jason@redhat.com>
* 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.
* class.c (check_bases): Propagate non-literality.
(check_field_decls): Likewise.
(finalize_literal_type_property): New.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,2 @@
// { dg-options -std=c++0x }
constexpr auto value = 0;

View File

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

View File

@ -0,0 +1,7 @@
// { dg-options -std=c++0x }
struct A
{
int i;
constexpr A() { } // { dg-error "uninitialized member .A::i" }
};

View File

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

View File

@ -0,0 +1,3 @@
// { dg-options -std=c++0x }
int x;
constexpr int& rx = x; // { dg-error "int&" }