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:
parent
3b49d762b5
commit
91ea6df357
@ -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.
|
||||
|
@ -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);
|
||||
|
226
gcc/cp/decl.c
226
gcc/cp/decl.c
@ -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;
|
||||
}
|
||||
|
||||
|
2
gcc/testsuite/g++.dg/cpp0x/constexpr-auto.C
Normal file
2
gcc/testsuite/g++.dg/cpp0x/constexpr-auto.C
Normal file
@ -0,0 +1,2 @@
|
||||
// { dg-options -std=c++0x }
|
||||
constexpr auto value = 0;
|
9
gcc/testsuite/g++.dg/cpp0x/constexpr-condition.C
Normal file
9
gcc/testsuite/g++.dg/cpp0x/constexpr-condition.C
Normal 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" }
|
||||
}
|
7
gcc/testsuite/g++.dg/cpp0x/constexpr-ctor.C
Normal file
7
gcc/testsuite/g++.dg/cpp0x/constexpr-ctor.C
Normal file
@ -0,0 +1,7 @@
|
||||
// { dg-options -std=c++0x }
|
||||
|
||||
struct A
|
||||
{
|
||||
int i;
|
||||
constexpr A() { } // { dg-error "uninitialized member .A::i" }
|
||||
};
|
5
gcc/testsuite/g++.dg/cpp0x/constexpr-expinst.C
Normal file
5
gcc/testsuite/g++.dg/cpp0x/constexpr-expinst.C
Normal 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" }
|
3
gcc/testsuite/g++.dg/cpp0x/constexpr-ice2.C
Normal file
3
gcc/testsuite/g++.dg/cpp0x/constexpr-ice2.C
Normal file
@ -0,0 +1,3 @@
|
||||
// { dg-options -std=c++0x }
|
||||
int x;
|
||||
constexpr int& rx = x; // { dg-error "int&" }
|
Loading…
Reference in New Issue
Block a user