Commit 91ea6df3 by Gabriel Dos Reis Committed by Jason Merrill

parser.c (cp_parser_ctor_initializer_opt_and_function_body): Make sure a…

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
parent 3b49d762
2010-10-27 Gabriel Dos Reis <gdr@cse.tamu.edu> 2010-10-27 Gabriel Dos Reis <gdr@cse.tamu.edu>
Jason Merrill <jason@redhat.com> 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. * class.c (check_bases): Propagate non-literality.
(check_field_decls): Likewise. (check_field_decls): Likewise.
(finalize_literal_type_property): New. (finalize_literal_type_property): New.
......
...@@ -4325,6 +4325,19 @@ type_has_user_provided_default_constructor (tree t) ...@@ -4325,6 +4325,19 @@ type_has_user_provided_default_constructor (tree t)
return false; 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. */ /* Returns true iff class TYPE has a virtual destructor. */
bool bool
......
...@@ -4721,6 +4721,7 @@ extern tree in_class_defaulted_default_constructor (tree); ...@@ -4721,6 +4721,7 @@ extern tree in_class_defaulted_default_constructor (tree);
extern bool user_provided_p (tree); extern bool user_provided_p (tree);
extern bool type_has_user_provided_constructor (tree); extern bool type_has_user_provided_constructor (tree);
extern bool type_has_user_provided_default_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_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);
......
...@@ -771,21 +771,6 @@ finish_static_data_member_decl (tree decl, ...@@ -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", permerror (input_location, "local class %q#T shall not have static data member %q#D",
current_class_type, decl); 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; DECL_IN_AGGR_P (decl) = 1;
if (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE if (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE
......
...@@ -533,6 +533,15 @@ perform_member_init (tree member, tree init) ...@@ -533,6 +533,15 @@ perform_member_init (tree member, tree init)
"uninitialized member %qD with %<const%> type %qT", "uninitialized member %qD with %<const%> type %qT",
member, type); 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); core_type = strip_array_types (type);
if (CLASS_TYPE_P (core_type) if (CLASS_TYPE_P (core_type)
&& (CLASSTYPE_READONLY_FIELDS_NEED_INIT (core_type) && (CLASSTYPE_READONLY_FIELDS_NEED_INIT (core_type)
...@@ -864,17 +873,30 @@ emit_mem_initializers (tree mem_inits) ...@@ -864,17 +873,30 @@ emit_mem_initializers (tree mem_inits)
tree subobject = TREE_PURPOSE (mem_inits); tree subobject = TREE_PURPOSE (mem_inits);
tree arguments = TREE_VALUE (mem_inits); tree arguments = TREE_VALUE (mem_inits);
/* If these initializations are taking place in a copy constructor, if (arguments == NULL_TREE)
the base class should probably be explicitly initialized if there {
is a user-defined constructor in the base class (other than the /* If these initializations are taking place in a copy constructor,
default constructor, which will be called anyway). */ the base class should probably be explicitly initialized if there
if (extra_warnings && !arguments is a user-defined constructor in the base class (other than the
&& DECL_COPY_CONSTRUCTOR_P (current_function_decl) default constructor, which will be called anyway). */
&& type_has_user_nondefault_constructor (BINFO_TYPE (subobject))) if (extra_warnings
warning_at (DECL_SOURCE_LOCATION (current_function_decl), OPT_Wextra, && DECL_COPY_CONSTRUCTOR_P (current_function_decl)
"base class %q#T should be explicitly initialized in the " && type_has_user_nondefault_constructor (BINFO_TYPE (subobject)))
"copy constructor", warning_at (DECL_SOURCE_LOCATION (current_function_decl),
BINFO_TYPE (subobject)); 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. */ /* Initialize the base. */
if (BINFO_VIRTUAL_P (subobject)) if (BINFO_VIRTUAL_P (subobject))
......
...@@ -1334,7 +1334,10 @@ enum ...@@ -1334,7 +1334,10 @@ enum
CP_PARSER_FLAGS_NO_USER_DEFINED_TYPES = 0x2, CP_PARSER_FLAGS_NO_USER_DEFINED_TYPES = 0x2,
/* When parsing a type-specifier, do not try to parse a class-specifier /* When parsing a type-specifier, do not try to parse a class-specifier
or enum-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 /* This type is used for parameters and variables which hold
...@@ -8509,6 +8512,7 @@ cp_parser_condition (cp_parser* parser) ...@@ -8509,6 +8512,7 @@ cp_parser_condition (cp_parser* parser)
{ {
cp_decl_specifier_seq type_specifiers; cp_decl_specifier_seq type_specifiers;
const char *saved_message; const char *saved_message;
int declares_class_or_enum;
/* Try the declaration first. */ /* Try the declaration first. */
cp_parser_parse_tentatively (parser); cp_parser_parse_tentatively (parser);
...@@ -8518,9 +8522,10 @@ cp_parser_condition (cp_parser* parser) ...@@ -8518,9 +8522,10 @@ cp_parser_condition (cp_parser* parser)
parser->type_definition_forbidden_message parser->type_definition_forbidden_message
= G_("types may not be defined in conditions"); = G_("types may not be defined in conditions");
/* Parse the type-specifier-seq. */ /* Parse the type-specifier-seq. */
cp_parser_type_specifier_seq (parser, /*is_declaration==*/true, cp_parser_decl_specifier_seq (parser,
/*is_trailing_return=*/false, CP_PARSER_FLAGS_ONLY_TYPE_OR_CONSTEXPR,
&type_specifiers); &type_specifiers,
&declares_class_or_enum);
/* Restore the saved message. */ /* Restore the saved message. */
parser->type_definition_forbidden_message = saved_message; parser->type_definition_forbidden_message = saved_message;
/* If all is well, we might be looking at a declaration. */ /* If all is well, we might be looking at a declaration. */
...@@ -9851,6 +9856,11 @@ cp_parser_decl_specifier_seq (cp_parser* parser, ...@@ -9851,6 +9856,11 @@ cp_parser_decl_specifier_seq (cp_parser* parser,
break; 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 /* Constructors are a special case. The `S' in `S()' is not a
decl-specifier; it is the beginning of the declarator. */ decl-specifier; it is the beginning of the declarator. */
constructor_p constructor_p
...@@ -12231,6 +12241,13 @@ cp_parser_explicit_instantiation (cp_parser* parser) ...@@ -12231,6 +12241,13 @@ cp_parser_explicit_instantiation (cp_parser* parser)
decl_specifiers.type_location); decl_specifiers.type_location);
if (declarator != cp_error_declarator) 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, decl = grokdeclarator (declarator, &decl_specifiers,
NORMAL, 0, &decl_specifiers.attributes); NORMAL, 0, &decl_specifiers.attributes);
/* Turn access control back on for names used during /* Turn access control back on for names used during
...@@ -16245,15 +16262,43 @@ cp_parser_function_body (cp_parser *parser) ...@@ -16245,15 +16262,43 @@ cp_parser_function_body (cp_parser *parser)
static bool static bool
cp_parser_ctor_initializer_opt_and_function_body (cp_parser *parser) cp_parser_ctor_initializer_opt_and_function_body (cp_parser *parser)
{ {
tree body; tree body, list;
bool ctor_initializer_p; 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. */ /* Begin the function body. */
body = begin_function_body (); body = begin_function_body ();
/* Parse the optional ctor-initializer. */ /* Parse the optional ctor-initializer. */
ctor_initializer_p = cp_parser_ctor_initializer_opt (parser); 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. */ /* Parse the function-body. */
cp_parser_function_body (parser); 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 the function body. */
finish_function_body (body); finish_function_body (body);
......
...@@ -5277,6 +5277,59 @@ ensure_literal_type_for_constexpr_object (tree decl) ...@@ -5277,6 +5277,59 @@ ensure_literal_type_for_constexpr_object (tree decl)
return 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 /* Return non-null if FUN certainly designates a valid constexpr function
declaration. Otherwise return NULL. Issue appropriate diagnostics declaration. Otherwise return NULL. Issue appropriate diagnostics
if necessary. Note that we only check the declaration, not the body if necessary. Note that we only check the declaration, not the body
...@@ -5285,43 +5338,18 @@ ensure_literal_type_for_constexpr_object (tree decl) ...@@ -5285,43 +5338,18 @@ ensure_literal_type_for_constexpr_object (tree decl)
tree tree
validate_constexpr_fundecl (tree fun) validate_constexpr_fundecl (tree fun)
{ {
tree rettype = NULL; if (processing_template_decl || !DECL_DECLARED_CONSTEXPR_P (fun))
tree parm = NULL;
/* Don't bother if FUN is not marked constexpr. */
if (!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; return NULL;
else if (DECL_CLONED_FUNCTION_P (fun))
parm = FUNCTION_FIRST_USER_PARM (fun); /* We already checked the original function. */
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))
return fun; return fun;
rettype = TREE_TYPE (TREE_TYPE (fun)); if (!is_valid_constexpr_fn (fun, !DECL_TEMPLATE_INSTANTIATION (fun)))
if (dependent_type_p (rettype))
return NULL;
if (!literal_type_p (rettype))
{ {
error ("return type %qT of function %qD is not a literal type", DECL_DECLARED_CONSTEXPR_P (fun) = false;
TREE_TYPE (TREE_TYPE (fun)), fun);
return NULL; return NULL;
} }
return fun; return fun;
} }
......
// { dg-options -std=c++0x }
constexpr auto value = 0;
// { 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" }
}
// { dg-options -std=c++0x }
struct A
{
int i;
constexpr A() { } // { dg-error "uninitialized member .A::i" }
};
// { 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" }
// { dg-options -std=c++0x }
int x;
constexpr int& rx = x; // { dg-error "int&" }
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