}
}
+/* 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)))
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)
{
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;
&& !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);
/* 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;
}
{
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)
}
}
+ 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;
/* 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)
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
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))
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)
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])
}
}
- /* 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);
}
}
+ /* 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)
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))
{
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)
}
}
+ 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)
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;
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 */
virtualp = 0;
}
}
- else if (staticp < 2)
- type = build_memfn_type (type, ctype, memfn_quals);
}
/* Check that the name used for a destructor makes sense. */
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",
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);
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))
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
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
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)
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)
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
/* 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)
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;
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
{
cp_decl_specifier_seq type_specifiers;
const char *saved_message;
+ int declares_class_or_enum;
/* Try the declaration first. */
cp_parser_parse_tentatively (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. */
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
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
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);
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
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;
}