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,18 +873,31 @@ emit_mem_initializers (tree mem_inits) ...@@ -864,18 +873,31 @@ 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 (arguments == NULL_TREE)
{
/* If these initializations are taking place in a copy constructor, /* If these initializations are taking place in a copy constructor,
the base class should probably be explicitly initialized if there the base class should probably be explicitly initialized if there
is a user-defined constructor in the base class (other than the is a user-defined constructor in the base class (other than the
default constructor, which will be called anyway). */ default constructor, which will be called anyway). */
if (extra_warnings && !arguments if (extra_warnings
&& DECL_COPY_CONSTRUCTOR_P (current_function_decl) && DECL_COPY_CONSTRUCTOR_P (current_function_decl)
&& type_has_user_nondefault_constructor (BINFO_TYPE (subobject))) && type_has_user_nondefault_constructor (BINFO_TYPE (subobject)))
warning_at (DECL_SOURCE_LOCATION (current_function_decl), OPT_Wextra, warning_at (DECL_SOURCE_LOCATION (current_function_decl),
"base class %q#T should be explicitly initialized in the " OPT_Wextra, "base class %q#T should be explicitly "
"copy constructor", "initialized in the copy constructor",
BINFO_TYPE (subobject)); 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))
construct_virtual_base (subobject, arguments); construct_virtual_base (subobject, arguments);
......
...@@ -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,51 +5277,79 @@ ensure_literal_type_for_constexpr_object (tree decl) ...@@ -5277,51 +5277,79 @@ ensure_literal_type_for_constexpr_object (tree decl)
return decl; return decl;
} }
/* Return non-null if FUN certainly designates a valid constexpr function /* Return true if type expression T is a valid parameter type, or
declaration. Otherwise return NULL. Issue appropriate diagnostics a valid return type, of a constexpr function. */
if necessary. Note that we only check the declaration, not the body
of the function. */
tree static bool
validate_constexpr_fundecl (tree fun) valid_type_in_constexpr_fundecl_p (tree t)
{ {
tree rettype = NULL; return (literal_type_p (t)
tree parm = NULL; /* FIXME we allow ref to non-literal; should change standard to
match, or change back if not. */
/* Don't bother if FUN is not marked constexpr. */ || TREE_CODE (t) == REFERENCE_TYPE);
if (!DECL_DECLARED_CONSTEXPR_P (fun)) }
return NULL;
/* For a function template, we have absolutely no guarantee that all /* Check whether the parameter and return types of FUN are valid for a
instantiations will be constexpr. */ constexpr function, and complain if COMPLAIN. */
if (TREE_CODE (fun) == TEMPLATE_DECL)
return NULL;
parm = FUNCTION_FIRST_USER_PARM (fun); 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)) for (; parm != NULL; parm = TREE_CHAIN (parm))
if (!valid_type_in_constexpr_fundecl_p (TREE_TYPE (parm)))
{ {
tree type = TREE_TYPE (parm); ret = false;
if (dependent_type_p (type)) if (complain)
return NULL; error ("invalid type for parameter %q#D of constexpr function",
if (!literal_type_p (type)) parm);
}
if (!DECL_CONSTRUCTOR_P (fun))
{ {
error ("parameter %q#D is not of literal type", parm); tree rettype = TREE_TYPE (TREE_TYPE (fun));
return NULL; 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);
} }
} }
if (DECL_CONSTRUCTOR_P (fun)) return ret;
return fun; }
rettype = TREE_TYPE (TREE_TYPE (fun)); /* Return non-null if FUN certainly designates a valid constexpr function
if (dependent_type_p (rettype)) declaration. Otherwise return NULL. Issue appropriate diagnostics
if necessary. Note that we only check the declaration, not the body
of the function. */
tree
validate_constexpr_fundecl (tree fun)
{
if (processing_template_decl || !DECL_DECLARED_CONSTEXPR_P (fun))
return NULL; return NULL;
if (!literal_type_p (rettype)) else if (DECL_CLONED_FUNCTION_P (fun))
/* We already checked the original function. */
return fun;
if (!is_valid_constexpr_fn (fun, !DECL_TEMPLATE_INSTANTIATION (fun)))
{ {
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