diff options
Diffstat (limited to 'gcc/cp')
-rw-r--r-- | gcc/cp/ChangeLog | 32 | ||||
-rw-r--r-- | gcc/cp/class.c | 13 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 1 | ||||
-rw-r--r-- | gcc/cp/decl.c | 226 | ||||
-rw-r--r-- | gcc/cp/decl2.c | 15 | ||||
-rw-r--r-- | gcc/cp/init.c | 44 | ||||
-rw-r--r-- | gcc/cp/parser.c | 55 | ||||
-rw-r--r-- | gcc/cp/semantics.c | 90 |
8 files changed, 308 insertions, 168 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 95a2f8b..5fe0f17 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -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. diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 00af0ae..c3e3c53 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -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 diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 8c0c9b1..1cd776a 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -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); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index e27a64d..8b2af9cd 100644 --- a/gcc/cp/decl.c +++ b/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; diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index f27e7d6..13fa5f6 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -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 diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 9c2afba..3a6e2e7 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -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)) diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index d0bd6bb..0d28345 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -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); diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 4e73068..0ca8c339 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -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)) - return NULL; - - /* For a function template, we have absolutely no guarantee that all - instantiations will be constexpr. */ - if (TREE_CODE (fun) == TEMPLATE_DECL) + if (processing_template_decl || !DECL_DECLARED_CONSTEXPR_P (fun)) 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; } |