#include "tree-inline.h"
#include "decl.h"
#include "intl.h"
-#include "output.h"
#include "toplev.h"
#include "hashtab.h"
#include "tm_p.h"
in the TREE_PURPOSE slot. */
tree static_aggregates;
+/* Like static_aggregates, but for thread_local variables. */
+tree tls_aggregates;
+
/* -- end of C++ */
/* A node for the integer constant 2. */
unsigned ix;
cp_label_binding *label_bind;
- timevar_start (TV_NAME_LOOKUP);
+ bool subtime = timevar_cond_start (TV_NAME_LOOKUP);
restart:
block = NULL_TREE;
/* Before we remove the declarations first check for unused variables. */
if ((warn_unused_variable || warn_unused_but_set_variable)
&& !processing_template_decl)
- for (decl = getdecls (); decl; decl = TREE_CHAIN (decl))
- if (TREE_CODE (decl) == VAR_DECL
- && (! TREE_USED (decl) || !DECL_READ_P (decl))
- && ! DECL_IN_SYSTEM_HEADER (decl)
- && DECL_NAME (decl) && ! DECL_ARTIFICIAL (decl))
- {
- if (! TREE_USED (decl))
- warning (OPT_Wunused_variable, "unused variable %q+D", decl);
- else if (DECL_CONTEXT (decl) == current_function_decl
- && TREE_TYPE (decl) != error_mark_node
- && TREE_CODE (TREE_TYPE (decl)) != REFERENCE_TYPE
- && errorcount == unused_but_set_errorcount
- && (!CLASS_TYPE_P (TREE_TYPE (decl))
- || !TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (decl))))
- {
- warning (OPT_Wunused_but_set_variable,
- "variable %q+D set but not used", decl);
- unused_but_set_errorcount = errorcount;
- }
- }
+ for (tree d = getdecls (); d; d = TREE_CHAIN (d))
+ {
+ /* There are cases where D itself is a TREE_LIST. See in
+ push_local_binding where the list of decls returned by
+ getdecls is built. */
+ decl = TREE_CODE (d) == TREE_LIST ? TREE_VALUE (d) : d;
+ if (TREE_CODE (decl) == VAR_DECL
+ && (! TREE_USED (decl) || !DECL_READ_P (decl))
+ && ! DECL_IN_SYSTEM_HEADER (decl)
+ && DECL_NAME (decl) && ! DECL_ARTIFICIAL (decl)
+ && TREE_TYPE (decl) != error_mark_node
+ && (!CLASS_TYPE_P (TREE_TYPE (decl))
+ || !TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (decl))))
+ {
+ if (! TREE_USED (decl))
+ warning (OPT_Wunused_variable, "unused variable %q+D", decl);
+ else if (DECL_CONTEXT (decl) == current_function_decl
+ && TREE_CODE (TREE_TYPE (decl)) != REFERENCE_TYPE
+ && errorcount == unused_but_set_errorcount)
+ {
+ warning (OPT_Wunused_but_set_variable,
+ "variable %q+D set but not used", decl);
+ unused_but_set_errorcount = errorcount;
+ }
+ }
+ }
/* Remove declarations for all the DECLs in this level. */
for (link = decls; link; link = TREE_CHAIN (link))
if (kind == sk_cleanup)
goto restart;
- timevar_stop (TV_NAME_LOOKUP);
+ timevar_cond_stop (TV_NAME_LOOKUP, subtime);
return block;
}
{
error ("declaration of template %q#D", newdecl);
error ("conflicts with previous declaration %q+#D", olddecl);
+ return error_mark_node;
}
else if (TREE_CODE (DECL_TEMPLATE_RESULT (olddecl)) == FUNCTION_DECL
&& TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) == FUNCTION_DECL
DECL_ARGUMENTS (olddecl) = DECL_ARGUMENTS (newdecl);
DECL_RESULT (olddecl) = DECL_RESULT (newdecl);
}
+ /* If redeclaring a builtin function, it stays built in
+ if newdecl is a gnu_inline definition, or if newdecl is just
+ a declaration. */
+ if (DECL_BUILT_IN (olddecl)
+ && (new_defines_function ? GNU_INLINE_P (newdecl) : types_match))
+ {
+ DECL_BUILT_IN_CLASS (newdecl) = DECL_BUILT_IN_CLASS (olddecl);
+ DECL_FUNCTION_CODE (newdecl) = DECL_FUNCTION_CODE (olddecl);
+ /* If we're keeping the built-in definition, keep the rtl,
+ regardless of declaration matches. */
+ COPY_DECL_RTL (olddecl, newdecl);
+ if (DECL_BUILT_IN_CLASS (newdecl) == BUILT_IN_NORMAL)
+ {
+ enum built_in_function fncode = DECL_FUNCTION_CODE (newdecl);
+ switch (fncode)
+ {
+ /* If a compatible prototype of these builtin functions
+ is seen, assume the runtime implements it with the
+ expected semantics. */
+ case BUILT_IN_STPCPY:
+ if (builtin_decl_explicit_p (fncode))
+ set_builtin_decl_implicit_p (fncode, true);
+ break;
+ default:
+ break;
+ }
+ }
+ }
if (new_defines_function)
/* If defining a function declared with other language
linkage, use the previously declared language linkage. */
SET_DECL_LANGUAGE (newdecl, DECL_LANGUAGE (olddecl));
else if (types_match)
{
- /* If redeclaring a builtin function, and not a definition,
- it stays built in. */
- if (DECL_BUILT_IN (olddecl))
- {
- DECL_BUILT_IN_CLASS (newdecl) = DECL_BUILT_IN_CLASS (olddecl);
- DECL_FUNCTION_CODE (newdecl) = DECL_FUNCTION_CODE (olddecl);
- /* If we're keeping the built-in definition, keep the rtl,
- regardless of declaration matches. */
- COPY_DECL_RTL (olddecl, newdecl);
- if (DECL_BUILT_IN_CLASS (newdecl) == BUILT_IN_NORMAL)
- {
- enum built_in_function fncode = DECL_FUNCTION_CODE (newdecl);
- switch (fncode)
- {
- /* If a compatible prototype of these builtin functions
- is seen, assume the runtime implements it with the
- expected semantics. */
- case BUILT_IN_STPCPY:
- if (builtin_decl_explicit_p (fncode))
- set_builtin_decl_implicit_p (fncode, true);
- break;
- default:
- break;
- }
- }
- }
-
DECL_RESULT (newdecl) = DECL_RESULT (olddecl);
/* Don't clear out the arguments if we're just redeclaring a
function. */
if ((cxx_dialect != cxx98)
&& TREE_CODE (ot) == FUNCTION_DECL && DECL_FRIEND_P (ot)
&& !check_default_tmpl_args (nt, DECL_TEMPLATE_PARMS (newdecl),
- /*is_primary=*/1, /*is_partial=*/0,
+ /*is_primary=*/true,
+ /*is_partial=*/false,
/*is_friend_decl=*/2))
return G_("redeclaration of friend %q#D "
"may not have default template arguments");
declare_local_label (tree id)
{
tree decl;
- cp_label_binding *bind;
+ cp_label_binding bind;
/* Add a new entry to the SHADOWED_LABELS list so that when we leave
this scope we can restore the old value of IDENTIFIER_TYPE_VALUE. */
- bind = VEC_safe_push (cp_label_binding, gc,
- current_binding_level->shadowed_labels, NULL);
- bind->prev_value = IDENTIFIER_LABEL_VALUE (id);
+ bind.prev_value = IDENTIFIER_LABEL_VALUE (id);
decl = make_label_decl (id, /*local_p=*/1);
- bind->label = decl;
+ bind.label = decl;
+ VEC_safe_push (cp_label_binding, gc, current_binding_level->shadowed_labels,
+ bind);
return decl;
}
type = strip_array_types (type);
- if (type_has_nontrivial_default_init (TREE_TYPE (decl))
- || DECL_NONTRIVIALLY_INITIALIZED_P (decl))
+ if (DECL_NONTRIVIALLY_INITIALIZED_P (decl))
return 2;
if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (decl)))
name = TREE_OPERAND (fullname, 0) = DECL_NAME (name);
else if (TREE_CODE (name) == OVERLOAD)
{
- error ("%qD is not a type", name);
+ if (complain & tf_error)
+ error ("%qD is not a type", name);
return error_mark_node;
}
}
if (TREE_CODE (name) == TEMPLATE_DECL)
{
- error ("%qD used without template parameters", name);
+ if (complain & tf_error)
+ error ("%qD used without template parameters", name);
return error_mark_node;
}
gcc_assert (TREE_CODE (name) == IDENTIFIER_NODE);
context, name, t);
return error_mark_node;
}
-
- if (complain & tf_error)
- perform_or_defer_access_check (TYPE_BINFO (context), t, t);
+
+ if (!perform_or_defer_access_check (TYPE_BINFO (context), t, t, complain))
+ return error_mark_node;
/* If we are currently parsing a template and if T is a typedef accessed
through CONTEXT then we need to remember and check access of T at
if (DECL_ARTIFICIAL (t) || !(complain & tf_keep_type_decl))
t = TREE_TYPE (t);
-
+
+ maybe_record_typedef_use (t);
+
return t;
}
return error_mark_node;
}
- if (complain & tf_error)
- perform_or_defer_access_check (TYPE_BINFO (context), tmpl, tmpl);
+ if (!perform_or_defer_access_check (TYPE_BINFO (context), tmpl, tmpl,
+ complain))
+ return error_mark_node;
return tmpl;
}
/* As we're using pushdecl_with_scope, we must set the context. */
DECL_CONTEXT (decl) = current_function_decl;
- DECL_PRETTY_FUNCTION_P (decl) = type_dep;
TREE_STATIC (decl) = 1;
TREE_READONLY (decl) = 1;
}
}
+/* Warn for an attribute located at LOCATION that appertains to the
+ class type CLASS_TYPE that has not been properly placed after its
+ class-key, in it class-specifier. */
+
+void
+warn_misplaced_attr_for_class_type (source_location location,
+ tree class_type)
+{
+ gcc_assert (TAGGED_TYPE_P (class_type));
+
+ warning_at (location, OPT_Wattributes,
+ "attribute ignored in declaration "
+ "of %q#T", class_type);
+ inform (location,
+ "attribute for %q#T must follow the %qs keyword",
+ class_type, class_key_or_enum_as_string (class_type));
+}
+
/* Make sure that a declaration with no declarator is well-formed, i.e.
just declares a tagged type or anonymous union.
Returns the type declared; or NULL_TREE if none. */
tree
-check_tag_decl (cp_decl_specifier_seq *declspecs)
+check_tag_decl (cp_decl_specifier_seq *declspecs,
+ bool explicit_type_instantiation_p)
{
- int saw_friend = declspecs->specs[(int)ds_friend] != 0;
- int saw_typedef = declspecs->specs[(int)ds_typedef] != 0;
+ int saw_friend = decl_spec_seq_has_spec_p (declspecs, ds_friend);
+ int saw_typedef = decl_spec_seq_has_spec_p (declspecs, ds_typedef);
/* If a class, struct, or enum type is declared by the DECLSPECS
(i.e, if a class-specifier, enum-specifier, or non-typename
elaborated-type-specifier appears in the DECLSPECS),
else if (declspecs->redefined_builtin_type)
{
if (!in_system_header)
- permerror (input_location, "redeclaration of C++ built-in type %qT",
+ permerror (declspecs->locations[ds_redefined_builtin_type_spec],
+ "redeclaration of C++ built-in type %qT",
declspecs->redefined_builtin_type);
return NULL_TREE;
}
else
{
- if (declspecs->specs[(int)ds_inline]
- || declspecs->specs[(int)ds_virtual])
+ if (decl_spec_seq_has_spec_p (declspecs, ds_inline)
+ || decl_spec_seq_has_spec_p (declspecs, ds_virtual))
error ("%qs can only be specified for functions",
- declspecs->specs[(int)ds_inline]
+ decl_spec_seq_has_spec_p (declspecs, ds_inline)
? "inline" : "virtual");
else if (saw_friend
&& (!current_class_type
|| current_scope () != current_class_type))
error ("%<friend%> can only be specified inside a class");
- else if (declspecs->specs[(int)ds_explicit])
+ else if (decl_spec_seq_has_spec_p (declspecs, ds_explicit))
error ("%<explicit%> can only be specified for constructors");
else if (declspecs->storage_class)
error ("a storage class can only be specified for objects "
"and functions");
- else if (declspecs->specs[(int)ds_const]
- || declspecs->specs[(int)ds_volatile]
- || declspecs->specs[(int)ds_restrict]
- || declspecs->specs[(int)ds_thread])
+ else if (decl_spec_seq_has_spec_p (declspecs, ds_const)
+ || decl_spec_seq_has_spec_p (declspecs, ds_volatile)
+ || decl_spec_seq_has_spec_p (declspecs, ds_restrict)
+ || decl_spec_seq_has_spec_p (declspecs, ds_thread))
error ("qualifiers can only be specified for objects "
"and functions");
else if (saw_typedef)
warning (0, "%<typedef%> was ignored in this declaration");
- else if (declspecs->specs[(int) ds_constexpr])
+ else if (decl_spec_seq_has_spec_p (declspecs, ds_constexpr))
error ("%<constexpr%> cannot be used for type declarations");
}
/* For a template class (an explicit instantiation), use the
current location. */
loc = input_location;
- warning_at (loc, OPT_Wattributes, "attribute ignored in declaration "
- "of %q#T", declared_type);
- inform (loc, "attribute for %q#T must follow the %qs keyword",
- declared_type, class_key_or_enum_as_string (declared_type));
+
+ if (explicit_type_instantiation_p)
+ /* [dcl.attr.grammar]/4:
+
+ No attribute-specifier-seq shall appertain to an explicit
+ instantiation. */
+ {
+ warning_at (loc, OPT_Wattributes,
+ "attribute ignored in explicit instantiation %q#T",
+ declared_type);
+ inform (loc,
+ "no attribute can be applied to "
+ "an explicit instantiation");
+ }
+ else
+ warn_misplaced_attr_for_class_type (loc, declared_type);
}
return declared_type;
tree
shadow_tag (cp_decl_specifier_seq *declspecs)
{
- tree t = check_tag_decl (declspecs);
+ tree t = check_tag_decl (declspecs,
+ /*explicit_type_instantiation_p=*/false);
if (!t)
return NULL_TREE;
context, DECL_NAME (decl));
DECL_CONTEXT (decl) = DECL_CONTEXT (field);
}
- if (processing_specialization
- && template_class_depth (context) == 0
- && CLASSTYPE_TEMPLATE_SPECIALIZATION (context))
- error ("template header not allowed in member definition "
- "of explicitly specialized class");
/* Static data member are tricky; an in-class initialization
still doesn't provide a definition, so the in-class
declaration will have DECL_EXTERNAL set, but will have an
error ("duplicate initialization of %qD", decl);
if (duplicate_decls (decl, field, /*newdecl_is_friend=*/false))
decl = field;
- if (declspecs->specs[(int) ds_constexpr]
+ if (decl_spec_seq_has_spec_p (declspecs, ds_constexpr)
&& !DECL_DECLARED_CONSTEXPR_P (field))
error ("%qD declared %<constexpr%> outside its class", field);
}
if (decl == error_mark_node)
return error_mark_node;
- /* Tell the back end to use or not use .common as appropriate. If we say
- -fconserve-space, we want this to save .data space, at the expense of
- wrong semantics. If we say -fno-conserve-space, we want this to
- produce errors about redefs; to do this we force variables into the
- data segment. */
- if (flag_conserve_space
- && TREE_CODE (decl) == VAR_DECL
- && TREE_PUBLIC (decl)
- && !DECL_THREAD_LOCAL_P (decl)
- && !have_global_bss_p ())
- DECL_COMMON (decl) = 1;
-
if (TREE_CODE (decl) == VAR_DECL
&& DECL_NAMESPACE_SCOPE_P (decl) && !TREE_PUBLIC (decl) && !was_public
&& !DECL_THIS_STATIC (decl) && !DECL_ARTIFICIAL (decl))
while (d->cur != d->end)
{
tree field_init;
+ constructor_elt *old_cur = d->cur;
/* Handle designated initializers, as an extension. */
if (d->cur->index)
if (field_init == error_mark_node)
return error_mark_node;
+ if (d->cur == old_cur && d->cur->index)
+ {
+ /* This can happen with an invalid initializer for a flexible
+ array member (c++/54441). */
+ if (complain & tf_error)
+ error ("invalid initializer for %q#D", field);
+ return error_mark_node;
+ }
+
CONSTRUCTOR_APPEND_ELT (CONSTRUCTOR_ELTS (new_init), field, field_init);
/* [dcl.init.aggr]
&& VEC_length (constructor_elt, CONSTRUCTOR_ELTS (str_init)) == 1)
{
str_init = VEC_index (constructor_elt,
- CONSTRUCTOR_ELTS (str_init), 0)->value;
+ CONSTRUCTOR_ELTS (str_init), 0).value;
}
/* If it's a string literal, then it's the initializer for the array
return init;
/* Recurse on this CONSTRUCTOR. */
- d.cur = VEC_index (constructor_elt, v, 0);
+ d.cur = &VEC_index (constructor_elt, v, 0);
d.end = d.cur + VEC_length (constructor_elt, v);
new_init = reshape_init_r (type, &d, true, complain);
{
init_code = build_aggr_init_full_exprs (decl, init, flags);
+ /* A constructor call is a non-trivial initializer even if
+ it isn't explicitly written. */
+ if (TREE_SIDE_EFFECTS (init_code))
+ DECL_NONTRIVIALLY_INITIALIZED_P (decl) = true;
+
/* If this is a constexpr initializer, expand_default_init will
have returned an INIT_EXPR rather than a CALL_EXPR. In that
case, pull the initializer back out and pass it down into
nelts = VEC_length (constructor_elt, elts);
for (i = 0; i < nelts; ++i)
if (type_dependent_init_p (VEC_index (constructor_elt,
- elts, i)->value))
+ elts, i).value))
return true;
}
else
nelts = VEC_length (constructor_elt, elts);
for (i = 0; i < nelts; ++i)
if (value_dependent_init_p (VEC_index (constructor_elt,
- elts, i)->value))
+ elts, i).value))
return true;
}
else
release_tree_vector (cleanups);
}
else if (!DECL_PRETTY_FUNCTION_P (decl))
- /* Deduce array size even if the initializer is dependent. */
- maybe_deduce_size_from_array_init (decl, init);
+ {
+ /* Deduce array size even if the initializer is dependent. */
+ maybe_deduce_size_from_array_init (decl, init);
+ /* And complain about multiple initializers. */
+ if (init && TREE_CODE (init) == TREE_LIST && TREE_CHAIN (init)
+ && !MAYBE_CLASS_TYPE_P (type))
+ init = build_x_compound_expr_from_list (init, ELK_INIT,
+ tf_warning_or_error);
+ }
if (init)
DECL_INITIAL (decl) = init;
if (TREE_CODE (decl) == VAR_DECL)
{
- /* Only variables with trivial initialization and destruction can
- have thread-local storage. */
- if (DECL_THREAD_LOCAL_P (decl)
- && (type_has_nontrivial_default_init (TREE_TYPE (decl))
- || TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (decl))))
- error ("%qD cannot be thread-local because it has non-trivial "
- "type %qT", decl, TREE_TYPE (decl));
/* If this is a local variable that will need a mangled name,
register it now. We must do this before processing the
initializer for the variable, since the initialization might
/* Normally local_decls is populated during GIMPLE lowering,
but [cd]tors are never actually compiled directly. We need
to put statics on the list so we can deal with the label
- address extension. */
+ address extension. FIXME. */
add_local_decl (cfun, decl);
}
}
cleanups = make_tree_vector ();
init = check_initializer (decl, init, flags, &cleanups);
- /* Thread-local storage cannot be dynamically initialized. */
- if (DECL_THREAD_LOCAL_P (decl) && init)
- {
- error ("%qD is thread-local and so cannot be dynamically "
- "initialized", decl);
- init = NULL_TREE;
- }
/* Check that the initializer for a static data member was a
constant. Although we check in the parser that the
fn_type = build_function_type_list (integer_type_node,
argtype0, argtype1, argtype2,
NULL_TREE);
- fn_ptr_type = build_pointer_type (fn_type);
if (use_aeabi_atexit)
name = "__aeabi_atexit";
else
return atexit_node;
}
+/* Like get_atexit_node, but for thread-local cleanups. */
+
+static tree
+get_thread_atexit_node (void)
+{
+ /* The declaration for `__cxa_thread_atexit' is:
+
+ int __cxa_thread_atexit (void (*)(void *), void *, void *) */
+ tree fn_type = build_function_type_list (integer_type_node,
+ get_atexit_fn_ptr_type (),
+ ptr_type_node, ptr_type_node,
+ NULL_TREE);
+
+ /* Now, build the function declaration. */
+ tree atexit_fndecl = build_library_fn_ptr ("__cxa_thread_atexit", fn_type);
+ return decay_conversion (atexit_fndecl, tf_warning_or_error);
+}
+
/* Returns the __dso_handle VAR_DECL. */
static tree
register_dtor_fn (tree decl)
{
tree cleanup;
+ tree addr;
tree compound_stmt;
tree fcall;
tree type;
- bool use_dtor;
- tree arg0, arg1 = NULL_TREE, arg2 = NULL_TREE;
+ bool ob_parm, dso_parm, use_dtor;
+ tree arg0, arg1, arg2;
+ tree atex_node;
type = TREE_TYPE (decl);
if (TYPE_HAS_TRIVIAL_DESTRUCTOR (type))
return void_zero_node;
- /* If we're using "__cxa_atexit" (or "__aeabi_atexit"), and DECL is
- a class object, we can just pass the destructor to
- "__cxa_atexit"; we don't have to build a temporary function to do
- the cleanup. */
- use_dtor = (flag_use_cxa_atexit
- && !targetm.cxx.use_atexit_for_cxa_atexit ()
- && CLASS_TYPE_P (type));
+ /* If we're using "__cxa_atexit" (or "__cxa_thread_atexit" or
+ "__aeabi_atexit"), and DECL is a class object, we can just pass the
+ destructor to "__cxa_atexit"; we don't have to build a temporary
+ function to do the cleanup. */
+ ob_parm = (DECL_THREAD_LOCAL_P (decl)
+ || (flag_use_cxa_atexit
+ && !targetm.cxx.use_atexit_for_cxa_atexit ()));
+ dso_parm = ob_parm;
+ use_dtor = ob_parm && CLASS_TYPE_P (type);
if (use_dtor)
{
int idx;
gcc_assert (idx >= 0);
cleanup = VEC_index (tree, CLASSTYPE_METHOD_VEC (type), idx);
/* Make sure it is accessible. */
- perform_or_defer_access_check (TYPE_BINFO (type), cleanup, cleanup);
+ perform_or_defer_access_check (TYPE_BINFO (type), cleanup, cleanup,
+ tf_warning_or_error);
}
else
{
/* Call atexit with the cleanup function. */
mark_used (cleanup);
cleanup = build_address (cleanup);
- if (flag_use_cxa_atexit && !targetm.cxx.use_atexit_for_cxa_atexit ())
+
+ if (DECL_THREAD_LOCAL_P (decl))
+ atex_node = get_thread_atexit_node ();
+ else
+ atex_node = get_atexit_node ();
+
+ if (use_dtor)
{
- tree addr;
+ /* We must convert CLEANUP to the type that "__cxa_atexit"
+ expects. */
+ cleanup = build_nop (get_atexit_fn_ptr_type (), cleanup);
+ /* "__cxa_atexit" will pass the address of DECL to the
+ cleanup function. */
+ mark_used (decl);
+ addr = build_address (decl);
+ /* The declared type of the parameter to "__cxa_atexit" is
+ "void *". For plain "T*", we could just let the
+ machinery in cp_build_function_call convert it -- but if the
+ type is "cv-qualified T *", then we need to convert it
+ before passing it in, to avoid spurious errors. */
+ addr = build_nop (ptr_type_node, addr);
+ }
+ else if (ob_parm)
+ /* Since the cleanup functions we build ignore the address
+ they're given, there's no reason to pass the actual address
+ in, and, in general, it's cheaper to pass NULL than any
+ other value. */
+ addr = null_pointer_node;
+
+ if (dso_parm)
+ arg2 = cp_build_addr_expr (get_dso_handle_node (),
+ tf_warning_or_error);
+ else
+ arg2 = NULL_TREE;
- if (use_dtor)
- {
- /* We must convert CLEANUP to the type that "__cxa_atexit"
- expects. */
- cleanup = build_nop (get_atexit_fn_ptr_type (), cleanup);
- /* "__cxa_atexit" will pass the address of DECL to the
- cleanup function. */
- mark_used (decl);
- addr = build_address (decl);
- /* The declared type of the parameter to "__cxa_atexit" is
- "void *". For plain "T*", we could just let the
- machinery in cp_build_function_call convert it -- but if the
- type is "cv-qualified T *", then we need to convert it
- before passing it in, to avoid spurious errors. */
- addr = build_nop (ptr_type_node, addr);
- }
- else
- /* Since the cleanup functions we build ignore the address
- they're given, there's no reason to pass the actual address
- in, and, in general, it's cheaper to pass NULL than any
- other value. */
- addr = null_pointer_node;
- arg2 = cp_build_addr_expr (get_dso_handle_node (),
- tf_warning_or_error);
- if (targetm.cxx.use_aeabi_atexit ())
+ if (ob_parm)
+ {
+ if (!DECL_THREAD_LOCAL_P (decl)
+ && targetm.cxx.use_aeabi_atexit ())
{
arg1 = cleanup;
arg0 = addr;
}
}
else
- arg0 = cleanup;
- return cp_build_function_call_nary (get_atexit_node (), tf_warning_or_error,
+ {
+ arg0 = cleanup;
+ arg1 = NULL_TREE;
+ }
+ return cp_build_function_call_nary (atex_node, tf_warning_or_error,
arg0, arg1, arg2, NULL_TREE);
}
&& TYPE_HAS_TRIVIAL_DESTRUCTOR (TREE_TYPE (decl)))
return;
+ if (DECL_THREAD_LOCAL_P (decl) && DECL_GNU_TLS_P (decl)
+ && !DECL_FUNCTION_SCOPE_P (decl))
+ {
+ if (init)
+ error ("non-local variable %qD declared %<__thread%> "
+ "needs dynamic initialization", decl);
+ else
+ error ("non-local variable %qD declared %<__thread%> "
+ "has a non-trivial destructor", decl);
+ static bool informed;
+ if (!informed)
+ {
+ inform (DECL_SOURCE_LOCATION (decl),
+ "C++11 %<thread_local%> allows dynamic initialization "
+ "and destruction");
+ informed = true;
+ }
+ return;
+ }
+
if (DECL_FUNCTION_SCOPE_P (decl))
{
/* Emit code to perform this initialization but once. */
tree then_clause = NULL_TREE, inner_then_clause = NULL_TREE;
tree guard, guard_addr;
tree flag, begin;
+ /* We don't need thread-safety code for thread-local vars. */
+ bool thread_guard = (flag_threadsafe_statics
+ && !DECL_THREAD_LOCAL_P (decl));
/* Emit code to perform this initialization but once. This code
looks like:
/* This optimization isn't safe on targets with relaxed memory
consistency. On such targets we force synchronization in
__cxa_guard_acquire. */
- if (!targetm.relaxed_ordering || !flag_threadsafe_statics)
+ if (!targetm.relaxed_ordering || !thread_guard)
{
/* Begin the conditional initialization. */
if_stmt = begin_if_stmt ();
then_clause = begin_compound_stmt (BCS_NO_SCOPE);
}
- if (flag_threadsafe_statics)
+ if (thread_guard)
{
tree vfntype = NULL_TREE;
tree acquire_name, release_name, abort_name;
finish_expr_stmt (init);
- if (flag_threadsafe_statics)
+ if (thread_guard)
{
finish_compound_stmt (inner_then_clause);
finish_then_clause (inner_if_stmt);
finish_if_stmt (inner_if_stmt);
}
- if (!targetm.relaxed_ordering || !flag_threadsafe_statics)
+ if (!targetm.relaxed_ordering || !thread_guard)
{
finish_compound_stmt (then_clause);
finish_then_clause (if_stmt);
finish_if_stmt (if_stmt);
}
}
+ else if (DECL_THREAD_LOCAL_P (decl))
+ tls_aggregates = tree_cons (init, decl, tls_aggregates);
else
static_aggregates = tree_cons (init, decl, static_aggregates);
}
&& !VEC_empty (constructor_elt, CONSTRUCTOR_ELTS (initial_value)))
{
VEC(constructor_elt,gc) *v = CONSTRUCTOR_ELTS (initial_value);
- tree value = VEC_index (constructor_elt, v, 0)->value;
+ tree value = VEC_index (constructor_elt, v, 0).value;
if (TREE_CODE (value) == STRING_CST
&& VEC_length (constructor_elt, v) == 1)
TREE_PUBLIC (decl) = DECL_EXTERNAL (decl);
}
- if (declspecs->specs[(int)ds_thread])
- DECL_TLS_MODEL (decl) = decl_default_tls_model (decl);
+ if (decl_spec_seq_has_spec_p (declspecs, ds_thread))
+ {
+ DECL_TLS_MODEL (decl) = decl_default_tls_model (decl);
+ if (declspecs->gnu_thread_keyword_p)
+ DECL_GNU_TLS_P (decl) = true;
+ }
/* If the type of the decl has no linkage, make sure that we'll
notice that in mark_used. */
struct pointer_set_t *pset = pointer_set_create ();
/* Break out any function calls into temporary variables. */
cp_walk_tree (&size, stabilize_save_expr_r, pset, pset);
+ pointer_set_destroy (pset);
+}
+
+/* Helper function for compute_array_index_type. Look for SIZEOF_EXPR
+ not inside of SAVE_EXPR and fold them. */
+
+static tree
+fold_sizeof_expr_r (tree *expr_p, int *walk_subtrees, void *data)
+{
+ tree expr = *expr_p;
+ if (TREE_CODE (expr) == SAVE_EXPR || TYPE_P (expr))
+ *walk_subtrees = 0;
+ else if (TREE_CODE (expr) == SIZEOF_EXPR)
+ {
+ *(bool *)data = true;
+ if (SIZEOF_EXPR_TYPE_P (expr))
+ expr = cxx_sizeof_or_alignof_type (TREE_TYPE (TREE_OPERAND (expr, 0)),
+ SIZEOF_EXPR, false);
+ else if (TYPE_P (TREE_OPERAND (expr, 0)))
+ expr = cxx_sizeof_or_alignof_type (TREE_OPERAND (expr, 0), SIZEOF_EXPR,
+ false);
+ else
+ expr = cxx_sizeof_or_alignof_expr (TREE_OPERAND (expr, 0), SIZEOF_EXPR,
+ false);
+ if (expr == error_mark_node)
+ expr = size_one_node;
+ *expr_p = expr;
+ *walk_subtrees = 0;
+ }
+ return NULL;
}
/* Given the SIZE (i.e., number of elements) in an array, compute an
tree
compute_array_index_type (tree name, tree size, tsubst_flags_t complain)
{
- tree type;
tree itype;
tree osize = size;
tree abi_1_itype = NULL_TREE;
if (error_operand_p (size))
return error_mark_node;
- type = TREE_TYPE (size);
- /* type_dependent_expression_p? */
- if (!dependent_type_p (type))
+ if (!type_dependent_expression_p (size))
{
+ tree type = TREE_TYPE (size);
+
mark_rvalue_use (size);
if (cxx_dialect < cxx0x && TREE_CODE (size) == NOP_EXPR
NOP_EXPR with TREE_SIDE_EFFECTS; don't fold in that case. */;
else
{
- size = fold_non_dependent_expr (size);
+ size = fold_non_dependent_expr_sfinae (size, complain);
if (CLASS_TYPE_P (type)
&& CLASSTYPE_LITERAL_P (type))
/* We can only call value_dependent_expression_p on integral constant
expressions; treat non-constant expressions as dependent, too. */
if (processing_template_decl
- && (dependent_type_p (type)
+ && (type_dependent_expression_p (size)
|| !TREE_CONSTANT (size) || value_dependent_expression_p (size)))
{
/* We cannot do any checking for a SIZE that isn't known to be
processing_template_decl = 0;
itype = cp_build_binary_op (input_location,
MINUS_EXPR,
- cp_convert (ssizetype, size),
- cp_convert (ssizetype, integer_one_node),
- tf_warning_or_error);
+ cp_convert (ssizetype, size, complain),
+ cp_convert (ssizetype, integer_one_node,
+ complain),
+ complain);
itype = fold (itype);
processing_template_decl = saved_processing_template_decl;
if (!TREE_CONSTANT (itype))
- /* A variable sized array. */
- itype = variable_size (itype);
+ {
+ /* A variable sized array. */
+ itype = variable_size (itype);
+ if (TREE_CODE (itype) != SAVE_EXPR)
+ {
+ /* Look for SIZEOF_EXPRs in itype and fold them, otherwise
+ they might survive till gimplification. */
+ tree newitype = itype;
+ bool found = false;
+ cp_walk_tree_without_duplicates (&newitype,
+ fold_sizeof_expr_r, &found);
+ if (found)
+ itype = variable_size (fold (newitype));
+ }
+ }
/* Make sure that there was no overflow when creating to a signed
index type. (For example, on a 32-bit machine, an array with
size 2^32 - 1 is too big.) */
tree
grokdeclarator (const cp_declarator *declarator,
- const cp_decl_specifier_seq *declspecs,
+ cp_decl_specifier_seq *declspecs,
enum decl_context decl_context,
int initialized,
tree* attrlist)
bool parameter_pack_p = declarator? declarator->parameter_pack_p : false;
bool template_type_arg = false;
bool template_parm_flag = false;
- bool constexpr_p = declspecs->specs[(int) ds_constexpr];
+ bool constexpr_p = decl_spec_seq_has_spec_p (declspecs, ds_constexpr);
const char *errmsg;
- signed_p = declspecs->specs[(int)ds_signed];
- unsigned_p = declspecs->specs[(int)ds_unsigned];
- short_p = declspecs->specs[(int)ds_short];
- long_p = declspecs->specs[(int)ds_long];
- longlong = declspecs->specs[(int)ds_long] >= 2;
+ signed_p = decl_spec_seq_has_spec_p (declspecs, ds_signed);
+ unsigned_p = decl_spec_seq_has_spec_p (declspecs, ds_unsigned);
+ short_p = decl_spec_seq_has_spec_p (declspecs, ds_short);
+ long_p = decl_spec_seq_has_spec_p (declspecs, ds_long);
+ longlong = decl_spec_seq_has_spec_p (declspecs, ds_long_long);
explicit_int128 = declspecs->explicit_int128_p;
- thread_p = declspecs->specs[(int)ds_thread];
+ thread_p = decl_spec_seq_has_spec_p (declspecs, ds_thread);
if (decl_context == FUNCDEF)
funcdef_flag = true, decl_context = NORMAL;
}
else if (innermost_code != cdk_function
&& current_class_type
- && !UNIQUELY_DERIVED_FROM_P (ctype,
+ && !uniquely_derived_from_p (ctype,
current_class_type))
{
error ("type %qT is not derived from type %qT",
if (dname && IDENTIFIER_OPNAME_P (dname))
{
- if (declspecs->specs[(int)ds_typedef])
+ if (decl_spec_seq_has_spec_p (declspecs, ds_typedef))
{
error ("declaration of %qD as %<typedef%>", dname);
return error_mark_node;
if (name == NULL)
name = decl_context == PARM ? "parameter" : "type name";
- if (constexpr_p && declspecs->specs[(int)ds_typedef])
+ if (constexpr_p && decl_spec_seq_has_spec_p (declspecs, ds_typedef))
{
error ("%<constexpr%> cannot appear in a typedef declaration");
return error_mark_node;
else if (short_p)
type = short_integer_type_node;
- if (declspecs->specs[(int)ds_complex])
+ if (decl_spec_seq_has_spec_p (declspecs, ds_complex))
{
if (TREE_CODE (type) != INTEGER_TYPE && TREE_CODE (type) != REAL_TYPE)
error ("complex invalid for %qs", name);
}
type_quals = TYPE_UNQUALIFIED;
- if (declspecs->specs[(int)ds_const])
+ if (decl_spec_seq_has_spec_p (declspecs, ds_const))
type_quals |= TYPE_QUAL_CONST;
- if (declspecs->specs[(int)ds_volatile])
+ if (decl_spec_seq_has_spec_p (declspecs, ds_volatile))
type_quals |= TYPE_QUAL_VOLATILE;
- if (declspecs->specs[(int)ds_restrict])
+ if (decl_spec_seq_has_spec_p (declspecs, ds_restrict))
type_quals |= TYPE_QUAL_RESTRICT;
if (sfk == sfk_conversion && type_quals != TYPE_UNQUALIFIED)
error ("qualifiers are not allowed on declaration of %<operator %T%>",
type_quals = cp_type_quals (type);
staticp = 0;
- inlinep = !! declspecs->specs[(int)ds_inline];
- virtualp = !! declspecs->specs[(int)ds_virtual];
- explicitp = !! declspecs->specs[(int)ds_explicit];
+ inlinep = decl_spec_seq_has_spec_p (declspecs, ds_inline);
+ virtualp = decl_spec_seq_has_spec_p (declspecs, ds_virtual);
+ explicitp = decl_spec_seq_has_spec_p (declspecs, ds_explicit);
storage_class = declspecs->storage_class;
if (storage_class == sc_static)
storage_class = sc_none;
staticp = 0;
}
- friendp = !! declspecs->specs[(int)ds_friend];
+ friendp = decl_spec_seq_has_spec_p (declspecs, ds_friend);
if (dependent_name && !friendp)
{
/* Issue errors about use of storage classes for parameters. */
if (decl_context == PARM)
{
- if (declspecs->specs[(int)ds_typedef])
+ if (decl_spec_seq_has_spec_p (declspecs, ds_typedef))
{
error ("typedef declaration invalid in parameter declaration");
return error_mark_node;
&& ((storage_class
&& storage_class != sc_extern
&& storage_class != sc_static)
- || declspecs->specs[(int)ds_typedef]))
+ || decl_spec_seq_has_spec_p (declspecs, ds_typedef)))
{
error ("multiple storage classes in declaration of %qs", name);
thread_p = false;
&& (storage_class == sc_register
|| storage_class == sc_auto))
;
- else if (declspecs->specs[(int)ds_typedef])
+ else if (decl_spec_seq_has_spec_p (declspecs, ds_typedef))
;
else if (decl_context == FIELD
/* C++ allows static class elements. */
&& storage_class != sc_extern
&& storage_class != sc_static)
{
- error ("function-scope %qs implicitly auto and declared %<__thread%>",
- name);
- thread_p = false;
+ if (declspecs->gnu_thread_keyword_p)
+ pedwarn (input_location, 0, "function-scope %qs implicitly auto and "
+ "declared %<__thread%>", name);
+
+ /* When thread_local is applied to a variable of block scope the
+ storage-class-specifier static is implied if it does not appear
+ explicitly. */
+ storage_class = declspecs->storage_class = sc_static;
+ staticp = 1;
}
if (storage_class && friendp)
}
}
+ if (declspecs->std_attributes)
+ {
+ /* Apply the c++11 attributes to the type preceding them. */
+ source_location saved_loc = input_location;
+ input_location = declspecs->locations[ds_std_attribute];
+ decl_attributes (&type, declspecs->std_attributes, 0);
+ input_location = saved_loc;
+ }
+
/* Determine the type of the entity declared by recurring on the
declarator. */
for (; declarator; declarator = declarator->declarator)
case cdk_array:
type = create_array_type_for_decl (dname, type,
declarator->u.array.bounds);
+ if (declarator->std_attributes)
+ /* [dcl.array]/1:
+
+ The optional attribute-specifier-seq appertains to the
+ array. */
+ returned_attrs = chainon (returned_attrs,
+ declarator->std_attributes);
break;
case cdk_function:
error ("%qs declared as function returning an array", name);
return error_mark_node;
}
+ /* When decl_context == NORMAL we emit a better error message
+ later in abstract_virtuals_error. */
+ if (decl_context == TYPENAME && ABSTRACT_CLASS_TYPE_P (type))
+ error ("%qs declared as function returning an abstract "
+ "class type", name);
/* Pick up type qualifiers which should be applied to `this'. */
memfn_quals = declarator->u.function.qualifiers;
}
type = build_function_type (type, arg_types);
+ if (declarator->std_attributes)
+ /* [dcl.fct]/2:
+
+ The optional attribute-specifier-seq appertains to
+ the function type. */
+ decl_attributes (&type, declarator->std_attributes,
+ 0);
}
break;
declarator->u.pointer.qualifiers);
type_quals = cp_type_quals (type);
}
+
+ /* Apply C++11 attributes to the pointer, and not to the
+ type pointed to. This is unlike what is done for GNU
+ attributes above. It is to comply with [dcl.ptr]/1:
+
+ [the optional attribute-specifier-seq (7.6.1) appertains
+ to the pointer and not to the object pointed to]. */
+ if (declarator->std_attributes)
+ decl_attributes (&type, declarator->std_attributes,
+ 0);
+
ctype = NULL_TREE;
break;
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");
if (TREE_CODE (type) != REFERENCE_TYPE)
&& declarator->u.id.qualifying_scope
&& MAYBE_CLASS_TYPE_P (declarator->u.id.qualifying_scope))
{
- tree t;
-
ctype = declarator->u.id.qualifying_scope;
ctype = TYPE_MAIN_VARIANT (ctype);
- t = ctype;
- while (t != NULL_TREE && CLASS_TYPE_P (t))
- {
- /* You're supposed to have one `template <...>' for every
- template class, but you don't need one for a full
- specialization. For example:
-
- template <class T> struct S{};
- template <> struct S<int> { void f(); };
- void S<int>::f () {}
-
- is correct; there shouldn't be a `template <>' for the
- definition of `S<int>::f'. */
- if (CLASSTYPE_TEMPLATE_SPECIALIZATION (t)
- && !any_dependent_template_arguments_p (CLASSTYPE_TI_ARGS (t)))
- /* T is an explicit (not partial) specialization. All
- containing classes must therefore also be explicitly
- specialized. */
- break;
- if ((CLASSTYPE_USE_TEMPLATE (t) || CLASSTYPE_IS_TEMPLATE (t))
- && PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (t)))
- template_count += 1;
-
- t = TYPE_MAIN_DECL (t);
- t = DECL_CONTEXT (t);
- }
+ template_count = num_template_headers_for_class (ctype);
if (ctype == current_class_type)
{
return error_mark_node;
}
}
- else if (declspecs->specs[(int)ds_typedef]
+ else if (decl_spec_seq_has_spec_p (declspecs, ds_typedef)
&& current_class_type)
{
error ("cannot declare member %<%T::%s%> within %qT",
attrlist = &returned_attrs;
}
+ if (declarator
+ && declarator->kind == cdk_id
+ && declarator->std_attributes)
+ /* [dcl.meaning]/1: The optional attribute-specifier-seq following
+ a declarator-id appertains to the entity that is declared. */
+ *attrlist = chainon (*attrlist, declarator->std_attributes);
+
/* Handle parameter packs. */
if (parameter_pack_p)
{
error ("non-member %qs cannot be declared %<mutable%>", name);
storage_class = sc_none;
}
- else if (decl_context == TYPENAME || declspecs->specs[(int)ds_typedef])
+ else if (decl_context == TYPENAME
+ || decl_spec_seq_has_spec_p (declspecs, ds_typedef))
{
error ("non-object member %qs cannot be declared %<mutable%>", name);
storage_class = sc_none;
}
/* If this is declaring a typedef name, return a TYPE_DECL. */
- if (declspecs->specs[(int)ds_typedef] && decl_context != TYPENAME)
+ if (decl_spec_seq_has_spec_p (declspecs, ds_typedef) && decl_context != TYPENAME)
{
tree decl;
clones. */
DECL_ABSTRACT (decl) = 1;
}
- else if (constructor_name_p (unqualified_id, current_class_type))
+ else if (current_class_type
+ && constructor_name_p (unqualified_id, current_class_type))
permerror (input_location, "ISO C++ forbids nested type %qD with same name "
"as enclosing class",
unqualified_id);
memfn_quals != TYPE_UNQUALIFIED,
inlinep, friendp, raises != NULL_TREE);
- if (declspecs->specs[(int)ds_alias])
+ if (decl_spec_seq_has_spec_p (declspecs, ds_alias))
/* Acknowledge that this was written:
`using analias = atype;'. */
TYPE_DECL_ALIAS_P (decl) = 1;
else if (storage_class == sc_register)
error ("storage class %<register%> invalid for function %qs", name);
else if (thread_p)
- error ("storage class %<__thread%> invalid for function %qs", name);
+ {
+ if (declspecs->gnu_thread_keyword_p)
+ error ("storage class %<__thread%> invalid for function %qs",
+ name);
+ else
+ error ("storage class %<thread_local%> invalid for function %qs",
+ name);
+ }
if (virt_specifiers)
error ("virt-specifiers in %qs not allowed outside a class definition", name);
and `extern' makes no difference. */
if (! toplevel_bindings_p ()
&& (storage_class == sc_static
- || declspecs->specs[(int)ds_inline])
+ || decl_spec_seq_has_spec_p (declspecs, ds_inline))
&& pedantic)
{
if (storage_class == sc_static)
static tree
local_variable_p_walkfn (tree *tp, int *walk_subtrees,
- void *data ATTRIBUTE_UNUSED)
+ void * /*data*/)
{
/* Check DECL_NAME to avoid including temporaries. We don't check
DECL_ARTIFICIAL because we do want to complain about 'this'. */
A default argument expression is implicitly converted to the
parameter type. */
- if (!TREE_TYPE (arg)
- || !can_convert_arg (decl_type, TREE_TYPE (arg), arg, LOOKUP_NORMAL,
- tf_warning_or_error))
- {
- if (decl)
- error ("default argument for %q#D has type %qT",
- decl, TREE_TYPE (arg));
- else
- error ("default argument for parameter of type %qT has type %qT",
- decl_type, TREE_TYPE (arg));
-
- return error_mark_node;
- }
+ ++cp_unevaluated_operand;
+ perform_implicit_conversion_flags (decl_type, arg, tf_warning_or_error,
+ LOOKUP_NORMAL);
+ --cp_unevaluated_operand;
if (warn_zero_as_null_pointer_constant
&& c_inhibit_evaluation_warnings == 0
- && (POINTER_TYPE_P (decl_type) || TYPE_PTR_TO_MEMBER_P (decl_type))
+ && TYPE_PTR_OR_PTRMEM_P (decl_type)
&& null_ptr_cst_p (arg)
&& !NULLPTR_TYPE_P (TREE_TYPE (arg)))
{
bool
move_fn_p (const_tree d)
{
- tree args;
- tree arg_type;
- bool result = false;
-
gcc_assert (DECL_FUNCTION_MEMBER_P (d));
if (cxx_dialect == cxx98)
if (TREE_CODE (d) == TEMPLATE_DECL
|| (DECL_TEMPLATE_INFO (d)
&& DECL_MEMBER_TEMPLATE_P (DECL_TI_TEMPLATE (d))))
- /* Instantiations of template member functions are never copy
+ /* Instantiations of template member functions are never move
functions. Note that member functions of templated classes are
represented as template functions internally, and we must
- accept those as copy functions. */
+ accept those as move functions. */
return 0;
+ return move_signature_fn_p (d);
+}
+
+/* D is a constructor or overloaded `operator='.
+
+ Then, this function returns true when D has the same signature as a move
+ constructor or move assignment operator (because either it is such a
+ ctor/op= or it is a template specialization with the same signature),
+ false otherwise. */
+
+bool
+move_signature_fn_p (const_tree d)
+{
+ tree args;
+ tree arg_type;
+ bool result = false;
+
args = FUNCTION_FIRST_USER_PARMTYPE (d);
if (!args)
return 0;
type, tag_name (tag_code));
return error_mark_node;
}
- /* Accept bound template template parameters. */
+ /* Accept template template parameters. */
else if (allow_template_p
- && TREE_CODE (type) == BOUND_TEMPLATE_TEMPLATE_PARM)
+ && (TREE_CODE (type) == BOUND_TEMPLATE_TEMPLATE_PARM
+ || TREE_CODE (type) == TEMPLATE_TEMPLATE_PARM))
;
/* [dcl.type.elab]
else
decl = lookup_type_scope (name, scope);
- if (decl && DECL_CLASS_TEMPLATE_P (decl))
+ if (decl
+ && (DECL_CLASS_TEMPLATE_P (decl)
+ || DECL_TEMPLATE_TEMPLATE_PARM_P (decl)))
decl = DECL_TEMPLATE_RESULT (decl);
if (decl && TREE_CODE (decl) == TYPE_DECL)
&& template_class_depth (current_class_type)
&& template_header_p)
{
+ if (TREE_CODE (t) == TEMPLATE_TEMPLATE_PARM)
+ return t;
+
/* Since SCOPE is not TS_CURRENT, we are not looking at a
definition of this tag. Since, in addition, we are currently
processing a (member) template declaration of a template
{
tree basetype = TREE_VALUE (*basep);
- if (!(processing_template_decl && uses_template_parms (basetype))
+ /* The dependent_type_p call below should really be dependent_scope_p
+ so that we give a hard error about using an incomplete type as a
+ base, but we allow it with a pedwarn for backward
+ compatibility. */
+ if (processing_template_decl
+ && CLASS_TYPE_P (basetype) && TYPE_BEING_DEFINED (basetype))
+ cxx_incomplete_type_diagnostic (NULL_TREE, basetype, DK_PEDWARN);
+ if (!dependent_type_p (basetype)
&& !complete_type_or_else (basetype, NULL))
/* An incomplete type. Remove it from the list. */
*basep = TREE_CHAIN (*basep);
for (t = TYPE_MAIN_VARIANT (enumtype); t; t = TYPE_NEXT_VARIANT (t))
TYPE_VALUES (t) = TYPE_VALUES (enumtype);
+ if (at_class_scope_p ()
+ && COMPLETE_TYPE_P (current_class_type)
+ && UNSCOPED_ENUM_P (enumtype))
+ insert_late_enum_def_into_classtype_sorted_fields (enumtype,
+ current_class_type);
+
/* Finish debugging output for this type. */
rest_of_type_compilation (enumtype, namespace_bindings_p ());
}
{
if (TYPE_VALUES (enumtype))
{
- HOST_WIDE_INT hi;
- unsigned HOST_WIDE_INT lo;
tree prev_value;
bool overflowed;
value = error_mark_node;
else
{
- overflowed = add_double (TREE_INT_CST_LOW (prev_value),
- TREE_INT_CST_HIGH (prev_value),
- 1, 0, &lo, &hi);
+ double_int di = TREE_INT_CST (prev_value)
+ .add_with_sign (double_int_one,
+ false, &overflowed);
if (!overflowed)
{
- double_int di;
tree type = TREE_TYPE (prev_value);
- bool pos = (TYPE_UNSIGNED (type) || hi >= 0);
- di.low = lo; di.high = hi;
+ bool pos = TYPE_UNSIGNED (type) || !di.is_negative ();
if (!double_int_fits_to_tree_p (type, di))
{
unsigned int itk;
course, if we're processing a template, there may be no value. */
type = value ? TREE_TYPE (value) : NULL_TREE;
- if (context && context == current_class_type)
- /* This enum declaration is local to the class. We need the full
- lang_decl so that we can record DECL_CLASS_CONTEXT, for example. */
- decl = build_lang_decl_loc (loc, CONST_DECL, name, type);
- else
- /* It's a global enum, or it's local to a function. (Note local to
- a function could mean local to a class method. */
- decl = build_decl (loc, CONST_DECL, name, type);
+ decl = build_decl (loc, CONST_DECL, name, type);
- DECL_CONTEXT (decl) = FROB_CONTEXT (context);
+ DECL_CONTEXT (decl) = enumtype;
TREE_CONSTANT (decl) = 1;
TREE_READONLY (decl) = 1;
DECL_INITIAL (decl) = value;
an implicit definition), non-placement operator delete shall
be looked up in the scope of the destructor's class and if
found shall be accessible and unambiguous. */
- exprstmt = build_op_delete_call(DELETE_EXPR, current_class_ptr,
- virtual_size,
- /*global_p=*/false,
- /*placement=*/NULL_TREE,
- /*alloc_fn=*/NULL_TREE);
+ exprstmt = build_op_delete_call (DELETE_EXPR, current_class_ptr,
+ virtual_size,
+ /*global_p=*/false,
+ /*placement=*/NULL_TREE,
+ /*alloc_fn=*/NULL_TREE,
+ tf_warning_or_error);
if_stmt = begin_if_stmt ();
finish_if_stmt_cond (build2 (BIT_AND_EXPR, integer_type_node,
there's no need to add any extra bits. */
if (!DECL_CLONED_FUNCTION_P (fndecl))
{
+ /* Make it so that `main' always returns 0 by default. */
if (DECL_MAIN_P (current_function_decl))
- {
- /* Make it so that `main' always returns 0 by default (or
- 1 for VMS). */
-#if VMS_TARGET
- finish_return_stmt (integer_one_node);
-#else
- finish_return_stmt (integer_zero_node);
-#endif
- }
+ finish_return_stmt (integer_zero_node);
if (use_eh_spec_block (current_function_decl))
finish_eh_spec_block (TYPE_RAISES_EXCEPTIONS
&& !TREE_NO_WARNING (fndecl)
/* Structor return values (if any) are set by the compiler. */
&& !DECL_CONSTRUCTOR_P (fndecl)
- && !DECL_DESTRUCTOR_P (fndecl))
+ && !DECL_DESTRUCTOR_P (fndecl)
+ && targetm.warn_func_return (fndecl))
{
warning (OPT_Wreturn_type,
"no return statement in function returning non-void");
|| (TYPE_LANG_SPECIFIC (inner_type)
&& TYPE_BEING_DEFINED (inner_type)))
{
- incomplete_var *iv
- = VEC_safe_push (incomplete_var, gc, incomplete_vars, NULL);
- iv->decl = var;
- iv->incomplete_type = inner_type;
+ incomplete_var iv = {var, inner_type};
+ VEC_safe_push (incomplete_var, gc, incomplete_vars, iv);
}
}
}