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;
}
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 = decl_spec_seq_has_spec_p (declspecs, ds_friend);
int saw_typedef = decl_spec_seq_has_spec_p (declspecs, ds_typedef);
/* 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
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
}
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)
}
if (decl_spec_seq_has_spec_p (declspecs, ds_thread))
- DECL_TLS_MODEL (decl) = decl_default_tls_model (decl);
+ {
+ 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 = 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)
}
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",
&& 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:
}
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)
{
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)
{
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);
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
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
{
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;
&& !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);
}
}
}