/* Process declarations and variables for C++ compiler.
- Copyright (C) 1988-2014 Free Software Foundation, Inc.
+ Copyright (C) 1988-2015 Free Software Foundation, Inc.
Contributed by Michael Tiemann (tiemann@cygnus.com)
This file is part of GCC.
#include "config.h"
#include "system.h"
#include "coretypes.h"
-#include "tm.h"
-#include "tree.h"
-#include "tree-hasher.h"
+#include "target.h"
+#include "c-family/c-target.h"
+#include "cp-tree.h"
+#include "timevar.h"
#include "stringpool.h"
+#include "cgraph.h"
#include "stor-layout.h"
#include "varasm.h"
#include "attribs.h"
-#include "calls.h"
#include "flags.h"
-#include "cp-tree.h"
#include "tree-iterator.h"
-#include "tree-inline.h"
#include "decl.h"
#include "intl.h"
#include "toplev.h"
-#include "hashtab.h"
-#include "tm_p.h"
-#include "target.h"
-#include "c-family/c-common.h"
#include "c-family/c-objc.h"
#include "c-family/c-pragma.h"
-#include "c-family/c-target.h"
#include "c-family/c-ubsan.h"
-#include "diagnostic.h"
-#include "intl.h"
#include "debug.h"
-#include "timevar.h"
-#include "splay-tree.h"
#include "plugin.h"
-#include "hash-map.h"
-#include "is-a.h"
-#include "plugin-api.h"
-#include "vec.h"
-#include "hash-set.h"
-#include "machmode.h"
-#include "hard-reg-set.h"
-#include "input.h"
-#include "function.h"
-#include "ipa-ref.h"
-#include "cgraph.h"
#include "cilk.h"
-#include "wide-int.h"
#include "builtins.h"
/* Possible cases of bad specifiers type used by bad_specifiers. */
BSP_FIELD /* field */
};
-static tree grokparms (tree parmlist, tree *);
static const char *redeclaration_error_message (tree, tree);
static int decl_jump_unsafe (tree);
static tree cp_make_fname_decl (location_t, tree, int);
static void initialize_predefined_identifiers (void);
static tree check_special_function_return_type
- (special_function_kind, tree, tree);
+ (special_function_kind, tree, tree, int, const location_t*);
static tree push_cp_library_fn (enum tree_code, tree, int);
static tree build_cp_library_fn (tree, enum tree_code, tree, int);
static void store_parm_decls (tree);
tree abort_fndecl;
- The FUNCTION_DECL for the default `::operator delete'.
-
- tree global_delete_fndecl;
-
Used by RTTI
tree type_info_type_node, tinfo_decl_id, tinfo_decl_type;
tree tinfo_var_id; */
bool in_try_scope;
bool in_catch_scope;
bool in_omp_scope;
+ bool in_transaction_scope;
};
#define named_labels cp_function_chain->x_named_labels
/* A list of VAR_DECLs whose type was incomplete at the time the
variable was declared. */
-typedef struct GTY(()) incomplete_var_d {
+struct GTY(()) incomplete_var {
tree decl;
tree incomplete_type;
-} incomplete_var;
+};
static GTY(()) vec<incomplete_var, va_gc> *incomplete_vars;
case sk_omp:
ent->in_omp_scope = true;
break;
+ case sk_transaction:
+ ent->in_transaction_scope = true;
+ break;
default:
break;
}
or if this level is a function body,
create a BLOCK to record them for the life of this function. */
block = NULL_TREE;
- if (keep == 1 || functionbody)
+ /* Avoid function body block if possible. */
+ if (functionbody && subblocks && BLOCK_CHAIN (subblocks) == NULL_TREE)
+ keep = 0;
+ else if (keep == 1 || functionbody)
block = make_node (BLOCK);
if (block != NULL_TREE)
{
TYPE_ATTRIBUTES (TREE_TYPE (decl)))))
{
if (! TREE_USED (decl))
- warning (OPT_Wunused_variable, "unused variable %q+D", decl);
+ warning_at (DECL_SOURCE_LOCATION (decl),
+ OPT_Wunused_variable, "unused variable %qD", decl);
else if (DECL_CONTEXT (decl) == current_function_decl
// For -Wunused-but-set-variable leave references alone.
&& 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);
+ warning_at (DECL_SOURCE_LOCATION (decl),
+ OPT_Wunused_but_set_variable,
+ "variable %qD set but not used", decl);
unused_but_set_errorcount = errorcount;
}
}
check over all the labels. */
if (functionbody)
{
- /* Since this is the top level block of a function, the vars are
- the function's parameters. Don't leave them in the BLOCK
- because they are found in the FUNCTION_DECL instead. */
- BLOCK_VARS (block) = 0;
- pop_labels (block);
+ if (block)
+ {
+ /* Since this is the top level block of a function, the vars are
+ the function's parameters. Don't leave them in the BLOCK
+ because they are found in the FUNCTION_DECL instead. */
+ BLOCK_VARS (block) = 0;
+ pop_labels (block);
+ }
+ else
+ pop_labels (subblocks);
}
kind = current_binding_level->kind;
/* The current function is being defined, so its DECL_INITIAL
should be error_mark_node. */
gcc_assert (DECL_INITIAL (current_function_decl) == error_mark_node);
- DECL_INITIAL (current_function_decl) = block;
+ DECL_INITIAL (current_function_decl) = block ? block : subblocks;
+ if (subblocks)
+ {
+ if (FUNCTION_NEEDS_BODY_BLOCK (current_function_decl))
+ {
+ if (BLOCK_SUBBLOCKS (subblocks))
+ BLOCK_OUTER_CURLY_BRACE_P (BLOCK_SUBBLOCKS (subblocks)) = 1;
+ }
+ else
+ BLOCK_OUTER_CURLY_BRACE_P (subblocks) = 1;
+ }
}
else if (block)
current_binding_level->blocks
return walk_namespaces_r (global_namespace, f, data);
}
-/* Call wrapup_globals_declarations for the globals in NAMESPACE. If
- DATA is non-NULL, this is the last time we will call
- wrapup_global_declarations for this NAMESPACE. */
+/* Call wrapup_globals_declarations for the globals in NAMESPACE. */
int
-wrapup_globals_for_namespace (tree name_space, void* data)
+wrapup_globals_for_namespace (tree name_space, void* data ATTRIBUTE_UNUSED)
{
cp_binding_level *level = NAMESPACE_LEVEL (name_space);
vec<tree, va_gc> *statics = level->static_decls;
tree *vec = statics->address ();
int len = statics->length ();
- int last_time = (data != 0);
-
- if (last_time)
- {
- check_global_declarations (vec, len);
- emit_debug_global_declarations (vec, len);
- return 0;
- }
/* Write out any globals that need to be output. */
return wrapup_global_declarations (vec, len);
}
-
\f
/* In C++, you don't have to write `struct S' to refer to `S'; you
can just use `S'. We accomplish this by creating a TYPE_DECL as
}
else if (TREE_CODE (newdecl) == TEMPLATE_DECL)
{
- if (TREE_CODE (DECL_TEMPLATE_RESULT (newdecl))
- != TREE_CODE (DECL_TEMPLATE_RESULT (olddecl)))
+ tree oldres = DECL_TEMPLATE_RESULT (olddecl);
+ tree newres = DECL_TEMPLATE_RESULT (newdecl);
+
+ if (TREE_CODE (newres) != TREE_CODE (oldres))
return 0;
if (!comp_template_parms (DECL_TEMPLATE_PARMS (newdecl),
return 0;
if (TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) == TYPE_DECL)
- types_match = same_type_p (TREE_TYPE (DECL_TEMPLATE_RESULT (olddecl)),
- TREE_TYPE (DECL_TEMPLATE_RESULT (newdecl)));
+ types_match = (same_type_p (TREE_TYPE (oldres), TREE_TYPE (newres))
+ && equivalently_constrained (olddecl, newdecl));
else
- types_match = decls_match (DECL_TEMPLATE_RESULT (olddecl),
- DECL_TEMPLATE_RESULT (newdecl));
+ // We don't need to check equivalently_constrained for variable and
+ // function templates because we check it on the results.
+ types_match = decls_match (oldres, newres);
}
else
{
COMPARE_REDECLARATION);
}
+ // Normal functions can be constrained, as can variable partial
+ // specializations.
+ if (types_match && VAR_OR_FUNCTION_DECL_P (newdecl))
+ types_match = equivalently_constrained (newdecl, olddecl);
+
return types_match;
}
&& DECL_ARTIFICIAL (olddecl))
return;
- if (permerror (input_location,
+ if (permerror (DECL_SOURCE_LOCATION (newdecl),
"%qD was declared %<extern%> and later %<static%>", newdecl))
- inform (input_location, "previous declaration of %q+D", olddecl);
+ inform (DECL_SOURCE_LOCATION (olddecl),
+ "previous declaration of %qD", olddecl);
}
/* NEW_DECL is a redeclaration of OLD_DECL; both are functions or
all declarations, including the definition and an explicit
specialization, of that function shall have an
exception-specification with the same set of type-ids. */
- if ((pedantic || ! DECL_IN_SYSTEM_HEADER (old_decl))
- && ! DECL_IS_BUILTIN (old_decl)
+ if (! DECL_IS_BUILTIN (old_decl)
&& flag_exceptions
&& !comp_except_specs (new_exceptions, old_exceptions, ce_normal))
{
- error ("declaration of %qF has a different exception specifier",
- new_decl);
- error ("from previous declaration %q+F", old_decl);
+ const char *msg
+ = "declaration of %q+F has a different exception specifier";
+ bool complained = true;
+ if (! DECL_IN_SYSTEM_HEADER (old_decl))
+ error (msg, new_decl);
+ else
+ complained = pedwarn (0, OPT_Wsystem_headers, msg, new_decl);
+ if (complained)
+ inform (0, "from previous declaration %q+F", old_decl);
}
}
&& DECL_TEMPLATE_SPECIALIZATION (new_decl))
return true;
- error ("redeclaration %qD differs in %<constexpr%>", new_decl);
+ error ("redeclaration %q+D differs in %<constexpr%>", new_decl);
error ("from previous declaration %q+D", old_decl);
return false;
}
return true;
}
+// If OLDDECL and NEWDECL are concept declarations with the same type
+// (i.e., and template parameters), but different requirements,
+// emit diagnostics and return true. Otherwise, return false.
+static inline bool
+check_concept_refinement (tree olddecl, tree newdecl)
+{
+ if (!DECL_DECLARED_CONCEPT_P (olddecl) || !DECL_DECLARED_CONCEPT_P (newdecl))
+ return false;
+
+ tree d1 = DECL_TEMPLATE_RESULT (olddecl);
+ tree d2 = DECL_TEMPLATE_RESULT (newdecl);
+ if (TREE_CODE (d1) != TREE_CODE (d2))
+ return false;
+
+ tree t1 = TREE_TYPE (d1);
+ tree t2 = TREE_TYPE (d2);
+ if (TREE_CODE (d1) == FUNCTION_DECL)
+ {
+ if (compparms (TYPE_ARG_TYPES (t1), TYPE_ARG_TYPES (t2))
+ && comp_template_parms (DECL_TEMPLATE_PARMS (olddecl),
+ DECL_TEMPLATE_PARMS (newdecl))
+ && !equivalently_constrained (olddecl, newdecl))
+ {
+ error ("cannot specialize concept %q#D", olddecl);
+ return true;
+ }
+ }
+ return false;
+}
+
/* DECL is a redeclaration of a function or function template. If
it does have default arguments issue a diagnostic. Note: this
function is used to enforce the requirements in C++11 8.3.6 about
t && t != void_list_node; t = TREE_CHAIN (t))
if (TREE_PURPOSE (t))
{
- permerror (input_location,
+ permerror (DECL_SOURCE_LOCATION (decl),
"redeclaration of %q#D may not have default "
"arguments", decl);
return;
&& DECL_UNINLINABLE (olddecl)
&& lookup_attribute ("noinline", DECL_ATTRIBUTES (olddecl)))
{
- if (warning (OPT_Wattributes, "function %q+D redeclared as inline",
- newdecl))
+ if (warning_at (DECL_SOURCE_LOCATION (newdecl),
+ OPT_Wattributes, "function %qD redeclared as inline",
+ newdecl))
inform (DECL_SOURCE_LOCATION (olddecl),
"previous declaration of %qD with attribute noinline",
olddecl);
&& DECL_UNINLINABLE (newdecl)
&& lookup_attribute ("noinline", DECL_ATTRIBUTES (newdecl)))
{
- if (warning (OPT_Wattributes, "function %q+D redeclared with "
- "attribute noinline", newdecl))
+ if (warning_at (DECL_SOURCE_LOCATION (newdecl),
+ OPT_Wattributes, "function %qD redeclared with "
+ "attribute noinline", newdecl))
inform (DECL_SOURCE_LOCATION (olddecl),
"previous declaration of %qD was inline",
olddecl);
/* If the built-in is not ansi, then programs can override
it even globally without an error. */
else if (! DECL_BUILT_IN (olddecl))
- warning (0, "library function %q#D redeclared as non-function %q#D",
- olddecl, newdecl);
+ warning_at (DECL_SOURCE_LOCATION (newdecl), 0,
+ "library function %q#D redeclared as non-function %q#D",
+ olddecl, newdecl);
else
- error ("declaration of %q#D conflicts with built-in "
+ error ("declaration of %q+#D conflicts with built-in "
"declaration %q#D", newdecl, olddecl);
return NULL_TREE;
}
/* A near match; override the builtin. */
if (TREE_PUBLIC (newdecl))
- warning (0, "new declaration %q#D ambiguates built-in "
- "declaration %q#D", newdecl, olddecl);
+ warning_at (DECL_SOURCE_LOCATION (newdecl), 0,
+ "new declaration %q#D ambiguates built-in "
+ "declaration %q#D", newdecl, olddecl);
else
warning (OPT_Wshadow,
DECL_BUILT_IN (olddecl)
if (TREE_CODE (DECL_TEMPLATE_RESULT (olddecl)) == TYPE_DECL
|| TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) == TYPE_DECL)
{
- error ("conflicting declaration of template %q#D", newdecl);
+ error ("conflicting declaration of template %q+#D", newdecl);
inform (DECL_SOURCE_LOCATION (olddecl),
"previous declaration %q#D", olddecl);
return error_mark_node;
/* Template functions can be disambiguated by
return type. */
&& same_type_p (TREE_TYPE (TREE_TYPE (newdecl)),
- TREE_TYPE (TREE_TYPE (olddecl))))
+ TREE_TYPE (TREE_TYPE (olddecl)))
+ // Template functions can also be disambiguated by
+ // constraints.
+ && equivalently_constrained (olddecl, newdecl))
{
- error ("ambiguating new declaration %q#D", newdecl);
+ error ("ambiguating new declaration %q+#D", newdecl);
inform (DECL_SOURCE_LOCATION (olddecl),
"old declaration %q#D", olddecl);
}
+ else if (check_concept_refinement (olddecl, newdecl))
+ return error_mark_node;
return NULL_TREE;
}
if (TREE_CODE (newdecl) == FUNCTION_DECL)
{
if (DECL_EXTERN_C_P (newdecl) && DECL_EXTERN_C_P (olddecl))
{
- error ("conflicting declaration of C function %q#D",
+ error ("conflicting declaration of C function %q+#D",
newdecl);
inform (DECL_SOURCE_LOCATION (olddecl),
"previous declaration %q#D", olddecl);
are not ambiguous. */
else if ((!DECL_FUNCTION_VERSIONED (newdecl)
&& !DECL_FUNCTION_VERSIONED (olddecl))
+ // The functions have the same parameter types.
&& compparms (TYPE_ARG_TYPES (TREE_TYPE (newdecl)),
- TYPE_ARG_TYPES (TREE_TYPE (olddecl))))
+ TYPE_ARG_TYPES (TREE_TYPE (olddecl)))
+ // And the same constraints.
+ && equivalently_constrained (newdecl, olddecl))
{
- error ("ambiguating new declaration of %q#D", newdecl);
+ error ("ambiguating new declaration of %q+#D", newdecl);
inform (DECL_SOURCE_LOCATION (olddecl),
"old declaration %q#D", olddecl);
return error_mark_node;
}
else
{
- error ("conflicting declaration %q#D", newdecl);
+ error ("conflicting declaration %q+#D", newdecl);
inform (DECL_SOURCE_LOCATION (olddecl),
"previous declaration as %q#D", olddecl);
return error_mark_node;
A namespace-name defined at global scope shall not be
declared as the name of any other entity in any global scope
of the program. */
- error ("conflicting declaration of namespace %qD", newdecl);
+ error ("conflicting declaration of namespace %q+D", newdecl);
inform (DECL_SOURCE_LOCATION (olddecl),
"previous declaration of namespace %qD here", olddecl);
return error_mark_node;
{
error_at (DECL_SOURCE_LOCATION (newdecl), errmsg, newdecl);
if (DECL_NAME (olddecl) != NULL_TREE)
- inform (input_location,
+ inform (DECL_SOURCE_LOCATION (olddecl),
(DECL_INITIAL (olddecl) && namespace_bindings_p ())
- ? G_("%q+#D previously defined here")
- : G_("%q+#D previously declared here"), olddecl);
+ ? G_("%q#D previously defined here")
+ : G_("%q#D previously declared here"), olddecl);
return error_mark_node;
}
else if (TREE_CODE (olddecl) == FUNCTION_DECL
}
else
{
- error ("conflicting declaration of %q#D with %qL linkage",
+ error ("conflicting declaration of %q+#D with %qL linkage",
newdecl, DECL_LANGUAGE (newdecl));
inform (DECL_SOURCE_LOCATION (olddecl),
"previous declaration with %qL linkage",
DECL_PURE_VIRTUAL_P (newdecl) |= DECL_PURE_VIRTUAL_P (olddecl);
DECL_VIRTUAL_P (newdecl) |= DECL_VIRTUAL_P (olddecl);
DECL_INVALID_OVERRIDER_P (newdecl) |= DECL_INVALID_OVERRIDER_P (olddecl);
+ DECL_FINAL_P (newdecl) |= DECL_FINAL_P (olddecl);
+ DECL_OVERRIDE_P (newdecl) |= DECL_OVERRIDE_P (olddecl);
DECL_THIS_STATIC (newdecl) |= DECL_THIS_STATIC (olddecl);
if (DECL_OVERLOADED_OPERATOR_P (olddecl) != ERROR_MARK)
SET_OVERLOADED_OPERATOR_CODE
&& (! DECL_TEMPLATE_SPECIALIZATION (newdecl)
|| DECL_TEMPLATE_SPECIALIZATION (olddecl)))
{
- if (warning (OPT_Wredundant_decls,
- "redundant redeclaration of %qD in same scope",
- newdecl))
+ if (warning_at (DECL_SOURCE_LOCATION (newdecl),
+ OPT_Wredundant_decls,
+ "redundant redeclaration of %qD in same scope",
+ newdecl))
inform (DECL_SOURCE_LOCATION (olddecl),
"previous declaration of %qD", olddecl);
}
{
if (DECL_DELETED_FN (newdecl))
{
- error ("deleted definition of %qD", newdecl);
+ error ("deleted definition of %q+D", newdecl);
inform (DECL_SOURCE_LOCATION (olddecl),
"previous declaration of %qD", olddecl);
}
DECL_ATTRIBUTES (newdecl)
= (*targetm.merge_decl_attributes) (olddecl, newdecl);
+ if (DECL_DECLARES_FUNCTION_P (olddecl) && DECL_DECLARES_FUNCTION_P (newdecl))
+ {
+ olddecl_friend = DECL_FRIEND_P (olddecl);
+ hidden_friend = (DECL_ANTICIPATED (olddecl)
+ && DECL_HIDDEN_FRIEND_P (olddecl)
+ && newdecl_is_friend);
+ if (!hidden_friend)
+ {
+ DECL_ANTICIPATED (olddecl) = 0;
+ DECL_HIDDEN_FRIEND_P (olddecl) = 0;
+ }
+ }
+
if (TREE_CODE (newdecl) == TEMPLATE_DECL)
{
tree old_result;
{
/* Per C++11 8.3.6/4, default arguments cannot be added in later
declarations of a function template. */
- check_redeclaration_no_default_args (newdecl);
+ if (DECL_SOURCE_LOCATION (newdecl)
+ != DECL_SOURCE_LOCATION (olddecl))
+ check_redeclaration_no_default_args (newdecl);
check_default_args (newdecl);
/* For typedefs use the old type, as the new type's DECL_NAME points
at newdecl, which will be ggc_freed. */
if (TREE_CODE (newdecl) == TYPE_DECL)
- newtype = oldtype;
+ {
+ newtype = oldtype;
+
+ /* And remove the new type from the variants list. */
+ if (TYPE_NAME (TREE_TYPE (newdecl)) == newdecl)
+ {
+ tree remove = TREE_TYPE (newdecl);
+ for (tree t = TYPE_MAIN_VARIANT (remove); ;
+ t = TYPE_NEXT_VARIANT (t))
+ if (TYPE_NEXT_VARIANT (t) == remove)
+ {
+ TYPE_NEXT_VARIANT (t) = TYPE_NEXT_VARIANT (remove);
+ break;
+ }
+ }
+ }
else
/* Merge the data types specified in the two decls. */
newtype = merge_types (TREE_TYPE (newdecl), TREE_TYPE (olddecl));
}
}
+ /* An explicit specialization of a function template or of a member
+ function of a class template can be declared transaction_safe
+ independently of whether the corresponding template entity is declared
+ transaction_safe. */
+ if (flag_tm && TREE_CODE (newdecl) == FUNCTION_DECL
+ && DECL_TEMPLATE_INSTANTIATION (olddecl)
+ && DECL_TEMPLATE_SPECIALIZATION (newdecl)
+ && tx_safe_fn_type_p (newtype)
+ && !tx_safe_fn_type_p (TREE_TYPE (newdecl)))
+ newtype = tx_unsafe_fn_variant (newtype);
+
TREE_TYPE (newdecl) = TREE_TYPE (olddecl) = newtype;
if (TREE_CODE (newdecl) == FUNCTION_DECL)
TREE_STATIC (olddecl) = TREE_STATIC (newdecl) |= TREE_STATIC (olddecl);
if (! DECL_EXTERNAL (olddecl))
DECL_EXTERNAL (newdecl) = 0;
+ if (! DECL_COMDAT (olddecl))
+ DECL_COMDAT (newdecl) = 0;
new_template_info = NULL_TREE;
if (DECL_LANG_SPECIFIC (newdecl) && DECL_LANG_SPECIFIC (olddecl))
if (DECL_DECLARES_FUNCTION_P (newdecl))
{
DECL_NONCONVERTING_P (newdecl) = DECL_NONCONVERTING_P (olddecl);
- olddecl_friend = DECL_FRIEND_P (olddecl);
- hidden_friend = (DECL_ANTICIPATED (olddecl)
- && DECL_HIDDEN_FRIEND_P (olddecl)
- && newdecl_is_friend);
DECL_BEFRIENDING_CLASSES (newdecl)
= chainon (DECL_BEFRIENDING_CLASSES (newdecl),
DECL_BEFRIENDING_CLASSES (olddecl));
set_builtin_decl_implicit_p (fncode, true);
break;
default:
+ if (builtin_decl_explicit_p (fncode))
+ set_builtin_decl_declared_p (fncode, true);
break;
}
}
{
struct symtab_node *snode = NULL;
- if (TREE_CODE (newdecl) == VAR_DECL
- && (TREE_STATIC (olddecl) || TREE_PUBLIC (olddecl) || DECL_EXTERNAL (olddecl)))
+ if (VAR_P (newdecl)
+ && (TREE_STATIC (olddecl) || TREE_PUBLIC (olddecl)
+ || DECL_EXTERNAL (olddecl)))
snode = symtab_node::get (olddecl);
memcpy ((char *) olddecl + sizeof (struct tree_decl_common),
(char *) newdecl + sizeof (struct tree_decl_common),
size - sizeof (struct tree_decl_common)
+ TREE_CODE_LENGTH (TREE_CODE (newdecl)) * sizeof (char *));
- if (TREE_CODE (newdecl) == VAR_DECL)
+ if (VAR_P (newdecl))
olddecl->decl_with_vis.symtab_node = snode;
}
break;
}
}
- if (TREE_CODE (newdecl) == FUNCTION_DECL
- || TREE_CODE (newdecl) == VAR_DECL)
+ if (VAR_OR_FUNCTION_DECL_P (newdecl))
{
if (DECL_EXTERNAL (olddecl)
|| TREE_PUBLIC (olddecl)
}
}
- if (TREE_CODE (newdecl) == VAR_DECL
- && DECL_THREAD_LOCAL_P (newdecl))
- set_decl_tls_model (olddecl, DECL_TLS_MODEL (newdecl));
+ if (VAR_P (newdecl)
+ && CP_DECL_THREAD_LOCAL_P (newdecl))
+ {
+ CP_DECL_THREAD_LOCAL_P (olddecl) = true;
+ if (!processing_template_decl)
+ set_decl_tls_model (olddecl, DECL_TLS_MODEL (newdecl));
+ }
}
DECL_UID (olddecl) = olddecl_uid;
structure is shared in between newdecl and oldecl. */
if (TREE_CODE (newdecl) == FUNCTION_DECL)
DECL_STRUCT_FUNCTION (newdecl) = NULL;
- if (TREE_CODE (newdecl) == FUNCTION_DECL
- || TREE_CODE (newdecl) == VAR_DECL)
+ if (VAR_OR_FUNCTION_DECL_P (newdecl))
{
struct symtab_node *snode = symtab_node::get (newdecl);
if (snode)
snode->remove ();
}
+
+ /* Remove the associated constraints for newdecl, if any, before
+ reclaiming memory. */
+ if (flag_concepts)
+ remove_constraints (newdecl);
+
ggc_free (newdecl);
return olddecl;
return NULL;
}
else if (VAR_P (newdecl)
- && DECL_THREAD_LOCAL_P (newdecl) != DECL_THREAD_LOCAL_P (olddecl)
+ && CP_DECL_THREAD_LOCAL_P (newdecl) != CP_DECL_THREAD_LOCAL_P (olddecl)
&& (! DECL_LANG_SPECIFIC (olddecl)
|| ! CP_DECL_THREADPRIVATE_P (olddecl)
- || DECL_THREAD_LOCAL_P (newdecl)))
+ || CP_DECL_THREAD_LOCAL_P (newdecl)))
{
/* Only variables can be thread-local, and all declarations must
agree on this property. */
- if (DECL_THREAD_LOCAL_P (newdecl))
+ if (CP_DECL_THREAD_LOCAL_P (newdecl))
return G_("thread-local declaration of %q#D follows "
"non-thread-local declaration");
else
return 0;
}
-/* A subroutine of check_previous_goto_1 to identify a branch to the user. */
+/* A subroutine of check_previous_goto_1 and check_goto to identify a branch
+ to the user. */
static bool
-identify_goto (tree decl, const location_t *locus)
+identify_goto (tree decl, location_t loc, const location_t *locus,
+ diagnostic_t diag_kind)
{
- bool complained = (decl
- ? permerror (input_location, "jump to label %qD", decl)
- : permerror (input_location, "jump to case label"));
+ bool complained
+ = (decl ? emit_diagnostic (diag_kind, loc, 0, "jump to label %qD", decl)
+ : emit_diagnostic (diag_kind, loc, 0, "jump to case label"));
if (complained && locus)
inform (*locus, " from here");
return complained;
bool exited_omp, const location_t *locus)
{
cp_binding_level *b;
- bool identified = false, complained = false;
- bool saw_eh = false, saw_omp = false;
+ bool complained = false;
+ int identified = 0;
+ bool saw_eh = false, saw_omp = false, saw_tm = false;
if (exited_omp)
{
- complained = identify_goto (decl, locus);
+ complained = identify_goto (decl, input_location, locus, DK_ERROR);
if (complained)
inform (input_location, " exits OpenMP structured block");
- identified = saw_omp = true;
+ saw_omp = true;
+ identified = 2;
}
for (b = current_binding_level; b ; b = b->level_chain)
if (!identified)
{
- complained = identify_goto (decl, locus);
- identified = true;
+ complained = identify_goto (decl, input_location, locus,
+ DK_PERMERROR);
+ identified = 1;
}
if (complained)
{
if (problem > 1)
- inform (input_location,
- " crosses initialization of %q+#D", new_decls);
+ inform (DECL_SOURCE_LOCATION (new_decls),
+ " crosses initialization of %q#D", new_decls);
else
- inform (input_location, " enters scope of %q+#D which has "
+ inform (DECL_SOURCE_LOCATION (new_decls),
+ " enters scope of %q#D which has "
"non-trivial destructor", new_decls);
}
}
break;
if ((b->kind == sk_try || b->kind == sk_catch) && !saw_eh)
{
- if (!identified)
+ if (identified < 2)
{
- complained = identify_goto (decl, locus);
- identified = true;
+ complained = identify_goto (decl, input_location, locus,
+ DK_ERROR);
+ identified = 2;
}
if (complained)
{
}
if (b->kind == sk_omp && !saw_omp)
{
- if (!identified)
+ if (identified < 2)
{
- complained = identify_goto (decl, locus);
- identified = true;
+ complained = identify_goto (decl, input_location, locus,
+ DK_ERROR);
+ identified = 2;
}
if (complained)
inform (input_location, " enters OpenMP structured block");
saw_omp = true;
}
+ if (b->kind == sk_transaction && !saw_tm)
+ {
+ if (identified < 2)
+ {
+ complained = identify_goto (decl, input_location, locus,
+ DK_ERROR);
+ identified = 2;
+ }
+ if (complained)
+ inform (input_location,
+ " enters synchronized or atomic statement");
+ saw_tm = true;
+ }
}
return !identified;
check_goto (tree decl)
{
struct named_label_entry *ent, dummy;
- bool saw_catch = false, identified = false, complained = false;
+ bool saw_catch = false, complained = false;
+ int identified = 0;
tree bad;
unsigned ix;
return;
}
- if (ent->in_try_scope || ent->in_catch_scope
+ if (ent->in_try_scope || ent->in_catch_scope || ent->in_transaction_scope
|| ent->in_omp_scope || !vec_safe_is_empty (ent->bad_decls))
{
- complained = permerror (input_location, "jump to label %q+D", decl);
- if (complained)
- inform (input_location, " from here");
- identified = true;
+ diagnostic_t diag_kind = DK_PERMERROR;
+ if (ent->in_try_scope || ent->in_catch_scope
+ || ent->in_transaction_scope || ent->in_omp_scope)
+ diag_kind = DK_ERROR;
+ complained = identify_goto (decl, DECL_SOURCE_LOCATION (decl),
+ &input_location, diag_kind);
+ identified = 1 + (diag_kind == DK_ERROR);
}
FOR_EACH_VEC_SAFE_ELT (ent->bad_decls, ix, bad)
if (u > 1 && DECL_ARTIFICIAL (bad))
{
/* Can't skip init of __exception_info. */
+ if (identified == 1)
+ {
+ complained = identify_goto (decl, DECL_SOURCE_LOCATION (decl),
+ &input_location, DK_ERROR);
+ identified = 2;
+ }
if (complained)
inform (DECL_SOURCE_LOCATION (bad), " enters catch block");
saw_catch = true;
else if (complained)
{
if (u > 1)
- inform (input_location, " skips initialization of %q+#D", bad);
+ inform (DECL_SOURCE_LOCATION (bad),
+ " skips initialization of %q#D", bad);
else
- inform (input_location, " enters scope of %q+#D which has "
+ inform (DECL_SOURCE_LOCATION (bad),
+ " enters scope of %q#D which has "
"non-trivial destructor", bad);
}
}
inform (input_location, " enters try block");
else if (ent->in_catch_scope && !saw_catch)
inform (input_location, " enters catch block");
+ else if (ent->in_transaction_scope)
+ inform (input_location, " enters synchronized or atomic statement");
}
if (ent->in_omp_scope)
break;
if (b->kind == sk_omp)
{
- if (!identified)
+ if (identified < 2)
{
- complained = permerror (input_location,
- "jump to label %q+D", decl);
- if (complained)
- inform (input_location, " from here");
- identified = true;
+ complained = identify_goto (decl,
+ DECL_SOURCE_LOCATION (decl),
+ &input_location, DK_ERROR);
+ identified = 2;
}
if (complained)
inform (input_location, " exits OpenMP structured block");
label. We need a tree, rather than simply a hash table, because
of the GNU case range extension. */
splay_tree cases;
+ /* Remember whether there was a case value that is outside the
+ range of the original type of the controlling expression. */
+ bool outside_range_p;
};
/* A stack of the currently active switch statements. The innermost
p->next = switch_stack;
p->switch_stmt = switch_stmt;
p->cases = splay_tree_new (case_compare, NULL, NULL);
+ p->outside_range_p = false;
switch_stack = p;
}
/* Emit warnings as needed. */
switch_location = EXPR_LOC_OR_LOC (cs->switch_stmt, input_location);
+ const bool bool_cond_p
+ = (SWITCH_STMT_TYPE (cs->switch_stmt)
+ && TREE_CODE (SWITCH_STMT_TYPE (cs->switch_stmt)) == BOOLEAN_TYPE);
if (!processing_template_decl)
c_do_switch_warnings (cs->cases, switch_location,
SWITCH_STMT_TYPE (cs->switch_stmt),
- SWITCH_STMT_COND (cs->switch_stmt));
+ SWITCH_STMT_COND (cs->switch_stmt),
+ bool_cond_p, cs->outside_range_p);
splay_tree_delete (cs->cases);
switch_stack = switch_stack->next;
high_value = case_conversion (type, high_value);
r = c_add_case_label (loc, switch_stack->cases, cond, type,
- low_value, high_value);
+ low_value, high_value,
+ &switch_stack->outside_range_p);
/* After labels, make any new cleanups in the function go into their
own new (temporary) binding contour. */
bool class_p;
};
-struct typename_hasher : ggc_hasher<tree>
+struct typename_hasher : ggc_ptr_hash<tree_node>
{
typedef typename_info *compare_type;
if (TREE_CODE (name) == TEMPLATE_ID_EXPR)
{
name = TREE_OPERAND (name, 0);
- if (TREE_CODE (name) == TEMPLATE_DECL)
+ if (DECL_TYPE_TEMPLATE_P (name))
name = TREE_OPERAND (fullname, 0) = DECL_NAME (name);
- else if (TREE_CODE (name) == OVERLOAD)
+ if (TREE_CODE (name) != IDENTIFIER_NODE)
{
if (complain & tf_error)
error ("%qD is not a type", name);
return lookup_template_class (t, TREE_OPERAND (fullname, 1),
NULL_TREE, context,
/*entering_scope=*/0,
- tf_warning_or_error | tf_user);
+ complain | tf_user);
if (DECL_ARTIFICIAL (t) || !(complain & tf_keep_type_decl))
t = TREE_TYPE (t);
/* A string for which we should create an IDENTIFIER_NODE at
startup. */
-typedef struct predefined_identifier
+struct predefined_identifier
{
/* The name of the identifier. */
const char *const name;
tree *const node;
/* Nonzero if this is the name of a constructor or destructor. */
const int ctor_or_dtor_p;
-} predefined_identifier;
+};
/* Create all the predefined identifiers. */
global_namespace = build_lang_decl (NAMESPACE_DECL, global_scope_name,
void_type_node);
DECL_CONTEXT (global_namespace) = build_translation_unit_decl (NULL_TREE);
+ debug_hooks->register_main_translation_unit
+ (DECL_CONTEXT (global_namespace));
TREE_PUBLIC (global_namespace) = 1;
begin_scope (sk_namespace, global_namespace);
/* Ensure attribs.c is initialized. */
init_attributes ();
+
+ /* Ensure constraint.cc is initialized. */
+ init_constraint_processing ();
+
extvisattr = build_tree_list (get_identifier ("externally_visible"),
NULL_TREE);
newattrs = tree_cons (get_identifier ("alloc_size"),
opnew = push_cp_library_fn (VEC_NEW_EXPR, newtype, 0);
DECL_IS_MALLOC (opnew) = 1;
DECL_IS_OPERATOR_NEW (opnew) = 1;
- global_delete_fndecl = push_cp_library_fn (DELETE_EXPR, deltype, ECF_NOTHROW);
+ push_cp_library_fn (DELETE_EXPR, deltype, ECF_NOTHROW);
push_cp_library_fn (VEC_DELETE_EXPR, deltype, ECF_NOTHROW);
+ if (flag_sized_deallocation)
+ {
+ /* Also push the sized deallocation variants:
+ void operator delete(void*, std::size_t) throw();
+ void operator delete[](void*, std::size_t) throw(); */
+ tree void_ftype_ptr_size
+ = build_function_type_list (void_type_node, ptr_type_node,
+ size_type_node, NULL_TREE);
+ deltype = cp_build_type_attribute_variant (void_ftype_ptr_size,
+ extvisattr);
+ deltype = build_exception_variant (deltype, empty_except_spec);
+ push_cp_library_fn (DELETE_EXPR, deltype, ECF_NOTHROW);
+ push_cp_library_fn (VEC_DELETE_EXPR, deltype, ECF_NOTHROW);
+ }
nullptr_type_node = make_node (NULLPTR_TYPE);
TYPE_SIZE (nullptr_type_node) = bitsize_int (GET_MODE_BITSIZE (ptr_mode));
TYPE_SIZE_UNIT (nullptr_type_node) = size_int (GET_MODE_SIZE (ptr_mode));
TYPE_UNSIGNED (nullptr_type_node) = 1;
TYPE_PRECISION (nullptr_type_node) = GET_MODE_BITSIZE (ptr_mode);
+ if (abi_version_at_least (9))
+ TYPE_ALIGN (nullptr_type_node) = GET_MODE_ALIGNMENT (ptr_mode);
SET_TYPE_MODE (nullptr_type_node, ptr_mode);
record_builtin_type (RID_MAX, "decltype(nullptr)", nullptr_type_node);
nullptr_node = build_int_cst (nullptr_type_node, 0);
permerror (input_location, "declaration does not declare anything");
else if (declared_type != NULL_TREE && type_uses_auto (declared_type))
{
- error ("%<auto%> can only be specified for variables "
- "or function declarations");
+ error_at (declspecs->locations[ds_type_spec],
+ "%<auto%> can only be specified for variables "
+ "or function declarations");
return error_mark_node;
}
/* Check for an anonymous union. */
else
{
- 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",
- decl_spec_seq_has_spec_p (declspecs, ds_inline)
- ? "inline" : "virtual");
+ if (decl_spec_seq_has_spec_p (declspecs, ds_inline))
+ error_at (declspecs->locations[ds_inline],
+ "%<inline%> can only be specified for functions");
+ else if (decl_spec_seq_has_spec_p (declspecs, ds_virtual))
+ error_at (declspecs->locations[ds_virtual],
+ "%<virtual%> can only be specified for functions");
else if (saw_friend
&& (!current_class_type
|| current_scope () != current_class_type))
- error ("%<friend%> can only be specified inside a class");
+ error_at (declspecs->locations[ds_friend],
+ "%<friend%> can only be specified inside a class");
else if (decl_spec_seq_has_spec_p (declspecs, ds_explicit))
- error ("%<explicit%> can only be specified for constructors");
+ error_at (declspecs->locations[ds_explicit],
+ "%<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 (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");
+ error_at (declspecs->locations[ds_storage_class],
+ "a storage class can only be specified for objects "
+ "and functions");
+ else if (decl_spec_seq_has_spec_p (declspecs, ds_const))
+ error_at (declspecs->locations[ds_const],
+ "%<const%> can only be specified for objects and "
+ "functions");
+ else if (decl_spec_seq_has_spec_p (declspecs, ds_volatile))
+ error_at (declspecs->locations[ds_volatile],
+ "%<volatile%> can only be specified for objects and "
+ "functions");
+ else if (decl_spec_seq_has_spec_p (declspecs, ds_restrict))
+ error_at (declspecs->locations[ds_restrict],
+ "%<__restrict%> can only be specified for objects and "
+ "functions");
+ else if (decl_spec_seq_has_spec_p (declspecs, ds_thread))
+ error_at (declspecs->locations[ds_thread],
+ "%<__thread%> can only be specified for objects "
+ "and functions");
else if (saw_typedef)
- warning (0, "%<typedef%> was ignored in this declaration");
+ warning_at (declspecs->locations[ds_typedef], 0,
+ "%<typedef%> was ignored in this declaration");
else if (decl_spec_seq_has_spec_p (declspecs, ds_constexpr))
- error ("%<constexpr%> cannot be used for type declarations");
+ error_at (declspecs->locations[ds_constexpr],
+ "%<constexpr%> cannot be used for type declarations");
}
if (declspecs->attributes && warn_attributes && declared_type)
if (context != global_namespace)
*pushed_scope_p = push_scope (context);
- if (initialized)
- /* Is it valid for this decl to have an initializer at all?
- If not, set INITIALIZED to zero, which will indirectly
- tell `cp_finish_decl' to ignore the initializer once it is parsed. */
- switch (TREE_CODE (decl))
- {
- case TYPE_DECL:
- error ("typedef %qD is initialized (use decltype instead)", decl);
- return error_mark_node;
-
- case FUNCTION_DECL:
- if (initialized == SD_DELETED)
- /* We'll handle the rest of the semantics later, but we need to
- set this now so it's visible to duplicate_decls. */
- DECL_DELETED_FN (decl) = 1;
- break;
-
- default:
- break;
- }
+ /* Is it valid for this decl to have an initializer at all?
+ If not, set INITIALIZED to zero, which will indirectly
+ tell `cp_finish_decl' to ignore the initializer once it is parsed. */
+ if (initialized
+ && TREE_CODE (decl) == TYPE_DECL)
+ {
+ error ("typedef %qD is initialized (use decltype instead)", decl);
+ return error_mark_node;
+ }
if (initialized)
{
&& DECL_DECLARED_INLINE_P (decl)
&& DECL_UNINLINABLE (decl)
&& lookup_attribute ("noinline", DECL_ATTRIBUTES (decl)))
- warning (0, "inline function %q+D given attribute noinline", decl);
+ warning_at (DECL_SOURCE_LOCATION (decl), 0,
+ "inline function %qD given attribute noinline", decl);
if (TYPE_P (context) && COMPLETE_TYPE_P (complete_type (context)))
{
was_public = TREE_PUBLIC (decl);
- /* Enter this declaration into the symbol table. */
- decl = maybe_push_decl (decl);
+ /* Enter this declaration into the symbol table. Don't push the plain
+ VAR_DECL for a variable template. */
+ if (!template_parm_scope_p ()
+ || !VAR_P (decl))
+ decl = maybe_push_decl (decl);
if (processing_template_decl)
decl = push_template_decl (decl);
&& DECL_DECLARED_CONSTEXPR_P (current_function_decl))
{
bool ok = false;
- if (DECL_THREAD_LOCAL_P (decl))
+ if (CP_DECL_THREAD_LOCAL_P (decl))
error ("%qD declared %<thread_local%> in %<constexpr%> function",
decl);
else if (TREE_STATIC (decl))
return false;
}
- ce->index = cxx_constant_value (ce->index);
-
- if (TREE_CODE (ce->index) == INTEGER_CST)
+ tree ce_index = build_expr_type_conversion (WANT_INT | WANT_ENUM,
+ ce->index, true);
+ if (ce_index
+ && INTEGRAL_OR_UNSCOPED_ENUMERATION_TYPE_P (TREE_TYPE (ce_index))
+ && (TREE_CODE (ce_index = maybe_constant_value (ce_index))
+ == INTEGER_CST))
{
/* A C99 designator is OK if it matches the current index. */
- if (wi::eq_p (ce->index, index))
+ if (wi::eq_p (ce_index, index))
return true;
else
sorry ("non-trivial designated initializers not supported");
}
else
- gcc_unreachable ();
+ error ("C99 designator %qE is not an integral constant-expression",
+ ce->index);
return false;
}
inform (DECL_SOURCE_LOCATION (defaulted_ctor),
"constructor is not user-provided because it is "
"explicitly defaulted in the class body");
- inform (0, "and the implicitly-defined constructor does not "
- "initialize %q+#D", field);
+ inform (DECL_SOURCE_LOCATION (field),
+ "and the implicitly-defined constructor does not "
+ "initialize %q#D", field);
}
}
}
/* Structure holding the current initializer being processed by reshape_init.
CUR is a pointer to the current element being processed, END is a pointer
after the last element present in the initializer. */
-typedef struct reshape_iterator_t
+struct reshape_iter
{
constructor_elt *cur;
constructor_elt *end;
-} reshape_iter;
+};
static tree reshape_init_r (tree, reshape_iter *, bool, tsubst_flags_t);
{
tree max_index = NULL_TREE;
- gcc_assert (TREE_CODE (type) == VECTOR_TYPE);
+ gcc_assert (VECTOR_TYPE_P (type));
if (COMPOUND_LITERAL_P (d->cur->value))
{
}
/* For a vector, we initialize it as an array of the appropriate size. */
- if (TREE_CODE (type) == VECTOR_TYPE)
+ if (VECTOR_TYPE_P (type))
max_index = size_int (TYPE_VECTOR_SUBPARTS (type) - 1);
return reshape_init_array_1 (TREE_TYPE (type), max_index, d, complain);
of g++.old-deja/g++.mike/p7626.C: a pointer-to-member constant is
a CONSTRUCTOR (with a record type). */
if (TREE_CODE (init) == CONSTRUCTOR
+ /* Don't complain about a capture-init. */
+ && !CONSTRUCTOR_IS_DIRECT_INIT (init)
&& BRACE_ENCLOSED_INITIALIZER_P (init)) /* p7626.C */
{
if (SCALAR_TYPE_P (type))
return reshape_init_class (type, d, first_initializer_p, complain);
else if (TREE_CODE (type) == ARRAY_TYPE)
return reshape_init_array (type, d, complain);
- else if (TREE_CODE (type) == VECTOR_TYPE)
+ else if (VECTOR_TYPE_P (type))
return reshape_init_vector (type, d, complain);
else
gcc_unreachable();
"not by %<{...}%>",
decl);
}
- else if (TREE_CODE (type) == VECTOR_TYPE && TYPE_VECTOR_OPAQUE (type))
+ else if (VECTOR_TYPE_P (type) && TYPE_VECTOR_OPAQUE (type))
{
error ("opaque vector types cannot be initialized");
init = error_mark_node;
{
int toplev = toplevel_bindings_p ();
int defer_p;
- const char *filename;
/* Set the DECL_ASSEMBLER_NAME for the object. */
if (asmspec)
DECL_EXPR is expanded. */
defer_p = DECL_FUNCTION_SCOPE_P (decl) || DECL_VIRTUAL_P (decl);
- /* We try to defer namespace-scope static constants so that they are
- not emitted into the object file unnecessarily. */
- filename = LOCATION_FILE (input_location);
- if (!DECL_VIRTUAL_P (decl)
- && TREE_READONLY (decl)
- && DECL_INITIAL (decl) != NULL_TREE
- && DECL_INITIAL (decl) != error_mark_node
- && filename != NULL
- && ! EMPTY_CONSTRUCTOR_P (DECL_INITIAL (decl))
- && toplev
- && !TREE_PUBLIC (decl))
- {
- /* Fool with the linkage of static consts according to #pragma
- interface. */
- struct c_fileinfo *finfo = get_fileinfo (filename);
- if (!finfo->interface_unknown && !TREE_PUBLIC (decl))
- {
- TREE_PUBLIC (decl) = 1;
- DECL_EXTERNAL (decl) = finfo->interface_only;
- }
-
- defer_p = 1;
- }
- /* Likewise for template instantiations. */
- else if (DECL_LANG_SPECIFIC (decl)
- && DECL_IMPLICIT_INSTANTIATION (decl))
+ /* Defer template instantiations. */
+ if (DECL_LANG_SPECIFIC (decl)
+ && DECL_IMPLICIT_INSTANTIATION (decl))
defer_p = 1;
/* If we're not deferring, go ahead and assemble the variable. */
return false;
}
+// Returns true if a DECL is VAR_DECL with the concept specifier.
+static inline bool
+is_concept_var (tree decl)
+{
+ return (VAR_P (decl)
+ // Not all variables have DECL_LANG_SPECIFIC.
+ && DECL_LANG_SPECIFIC (decl)
+ && DECL_DECLARED_CONCEPT_P (decl));
+}
+
/* Finish processing of a declaration;
install its line number and initial value.
If the length of an array type is not known before,
tf_warning_or_error);
d_init = resolve_nondeduced_context (d_init);
type = TREE_TYPE (decl) = do_auto_deduction (type, d_init,
- auto_node);
+ auto_node,
+ tf_warning_or_error,
+ adc_variable_type);
if (type == error_mark_node)
return;
cp_apply_type_quals_to_decl (cp_type_quals (type), decl);
then it can be used in future constant expressions, so its value
must be available. */
- if (!VAR_P (decl) || dependent_type_p (type))
+ if (!VAR_P (decl) || type_dependent_p)
/* We can't do anything if the decl has dependent type. */;
else if (init
&& init_const_expr_p
- && !type_dependent_p
&& TREE_CODE (type) != REFERENCE_TYPE
&& decl_maybe_constant_var_p (decl)
&& !type_dependent_init_p (init)
init = NULL_TREE;
release_tree_vector (cleanups);
}
+ else if (!init && is_concept_var (decl))
+ error ("variable concept has no initializer");
else if (!DECL_PRETTY_FUNCTION_P (decl))
{
/* Deduce array size even if the initializer is dependent. */
to put statics on the list so we can deal with the label
address extension. FIXME. */
add_local_decl (cfun, decl);
+ /* And make sure it's in the symbol table for
+ c_parse_final_cleanups to find. */
+ varpool_node::get_create (decl);
}
/* Convert the initializer to the type of DECL, if we have not
function to do the cleanup. */
dso_parm = (flag_use_cxa_atexit
&& !targetm.cxx.use_atexit_for_cxa_atexit ());
- ob_parm = (DECL_THREAD_LOCAL_P (decl) || dso_parm);
+ ob_parm = (CP_DECL_THREAD_LOCAL_P (decl) || dso_parm);
use_dtor = ob_parm && CLASS_TYPE_P (type);
if (use_dtor)
{
mark_used (cleanup);
cleanup = build_address (cleanup);
- if (DECL_THREAD_LOCAL_P (decl))
+ if (CP_DECL_THREAD_LOCAL_P (decl))
atex_node = get_thread_atexit_node ();
else
atex_node = get_atexit_node ();
if (ob_parm)
{
- if (!DECL_THREAD_LOCAL_P (decl)
+ if (!CP_DECL_THREAD_LOCAL_P (decl)
&& targetm.cxx.use_aeabi_atexit ())
{
arg1 = cleanup;
gcc_assert (TREE_STATIC (decl));
/* Some variables require no dynamic initialization. */
- if (!init
- && TYPE_HAS_TRIVIAL_DESTRUCTOR (TREE_TYPE (decl)))
+ if (TYPE_HAS_TRIVIAL_DESTRUCTOR (TREE_TYPE (decl)))
{
/* Make sure the destructor is callable. */
cxx_maybe_build_cleanup (decl, tf_warning_or_error);
- return;
+ if (!init)
+ return;
}
- if (DECL_THREAD_LOCAL_P (decl) && DECL_GNU_TLS_P (decl)
+ if (CP_DECL_THREAD_LOCAL_P (decl) && DECL_GNU_TLS_P (decl)
&& !DECL_FUNCTION_SCOPE_P (decl))
{
if (init)
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));
+ && !CP_DECL_THREAD_LOCAL_P (decl));
/* Emit code to perform this initialization but once. This code
looks like:
static <type> guard;
- if (!guard.first_byte) {
+ if (!__atomic_load (guard.first_byte)) {
if (__cxa_guard_acquire (&guard)) {
bool flag = false;
try {
/* Create the guard variable. */
guard = get_guard (decl);
- /* 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 || !thread_guard)
- {
- /* Begin the conditional initialization. */
- if_stmt = begin_if_stmt ();
- finish_if_stmt_cond (get_guard_cond (guard), if_stmt);
- then_clause = begin_compound_stmt (BCS_NO_SCOPE);
- }
+ /* Begin the conditional initialization. */
+ if_stmt = begin_if_stmt ();
+
+ finish_if_stmt_cond (get_guard_cond (guard, thread_guard), if_stmt);
+ then_clause = begin_compound_stmt (BCS_NO_SCOPE);
if (thread_guard)
{
finish_if_stmt (inner_if_stmt);
}
- if (!targetm.relaxed_ordering || !thread_guard)
- {
- finish_compound_stmt (then_clause);
- finish_then_clause (if_stmt);
- finish_if_stmt (if_stmt);
- }
+ finish_compound_stmt (then_clause);
+ finish_then_clause (if_stmt);
+ finish_if_stmt (if_stmt);
}
- else if (DECL_THREAD_LOCAL_P (decl))
+ else if (CP_DECL_THREAD_LOCAL_P (decl))
tls_aggregates = tree_cons (init, decl, tls_aggregates);
else
static_aggregates = tree_cons (init, decl, static_aggregates);
decl);
}
+// Check that FN takes no arguments and returns bool.
+static void
+check_concept_fn (tree fn)
+{
+ // A constraint is nullary.
+ if (DECL_ARGUMENTS (fn))
+ error ("concept %q#D declared with function parameters", fn);
+
+ // The declared return type of the concept shall be bool, and
+ // it shall not be deduced from it definition.
+ tree type = TREE_TYPE (TREE_TYPE (fn));
+ if (is_auto (type))
+ error ("concept %q#D declared with a deduced return type", fn);
+ else if (type != boolean_type_node)
+ error ("concept %q#D with non-%<bool%> return type %qT", fn, type);
+}
+
/* Helper function. Replace the temporary this parameter injected
during cp_finish_omp_declare_simd with the real this parameter. */
tree declarator,
tree parms,
tree orig_declarator,
+ tree decl_reqs,
int virtualp,
enum overload_flags flags,
cp_cv_quals quals,
int friendp,
int publicp,
int inlinep,
+ bool deletedp,
special_function_kind sfk,
bool funcdef_flag,
int template_count,
int staticp = ctype && TREE_CODE (type) == FUNCTION_TYPE;
tree t;
+ // Was the concept specifier present?
+ bool concept_p = inlinep & 4;
+
+ // Concept declarations must have a corresponding definition.
+ if (concept_p && !funcdef_flag)
+ {
+ error ("concept %qD has no definition", declarator);
+ return NULL_TREE;
+ }
+
if (rqual)
type = build_ref_qualified_type (type, rqual);
if (raises)
decl = build_lang_decl (FUNCTION_DECL, declarator, type);
+ /* Set the constraints on the declaration. */
+ if (flag_concepts)
+ {
+ tree tmpl_reqs = NULL_TREE;
+ if (processing_template_decl > template_class_depth (ctype))
+ tmpl_reqs = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms);
+
+ /* Adjust the required expression into a constraint. */
+ if (decl_reqs)
+ decl_reqs = make_predicate_constraint (decl_reqs);
+
+ tree ci = build_constraints (tmpl_reqs, decl_reqs);
+ set_constraints (decl, ci);
+ }
+
/* If we have an explicit location, use it, otherwise use whatever
build_lang_decl used (probably input_location). */
if (location != UNKNOWN_LOCATION)
parm = build_this_parm (type, quals);
DECL_CHAIN (parm) = parms;
parms = parm;
+
+ /* Allocate space to hold the vptr bit if needed. */
+ DECL_ALIGN (decl) = MINIMUM_METHOD_BOUNDARY;
}
DECL_ARGUMENTS (decl) = parms;
for (t = parms; t; t = DECL_CHAIN (t))
break;
}
- /* If pointers to member functions use the least significant bit to
- indicate whether a function is virtual, ensure a pointer
- to this function will have that bit clear. */
- if (TARGET_PTRMEMFUNC_VBIT_LOCATION == ptrmemfunc_vbit_in_pfn
- && TREE_CODE (type) == METHOD_TYPE
- && DECL_ALIGN (decl) < 2 * BITS_PER_UNIT)
- DECL_ALIGN (decl) = 2 * BITS_PER_UNIT;
-
if (friendp
&& TREE_CODE (orig_declarator) == TEMPLATE_ID_EXPR)
{
}
if (inlinep & 1)
- error ("%<inline%> is not allowed in declaration of friend "
- "template specialization %qD",
- decl);
- if (inlinep & 2)
- error ("%<constexpr%> is not allowed in declaration of friend "
- "template specialization %qD",
- decl);
- if (inlinep)
- return NULL_TREE;
+ {
+ error ("%<inline%> is not allowed in declaration of friend "
+ "template specialization %qD",
+ decl);
+ return NULL_TREE;
+ }
}
}
DECL_CONTEXT (decl) = ctype;
}
+ if (deletedp)
+ DECL_DELETED_FN (decl) = 1;
+
if (ctype)
{
DECL_CONTEXT (decl) = ctype;
/* Members of anonymous types and local classes have no linkage; make
them internal. If a typedef is made later, this will be changed. */
- if (ctype && (TYPE_ANONYMOUS_P (ctype)
+ if (ctype && (!TREE_PUBLIC (TYPE_MAIN_DECL (ctype))
|| decl_function_context (TYPE_MAIN_DECL (ctype))))
publicp = 0;
if (inlinep & 2)
DECL_DECLARED_CONSTEXPR_P (decl) = true;
+ // If the concept declaration specifier was found, check
+ // that the declaration satisfies the necessary requirements.
+ if (concept_p)
+ {
+ DECL_DECLARED_CONCEPT_P (decl) = true;
+ check_concept_fn (decl);
+ }
+
DECL_EXTERNAL (decl) = 1;
if (TREE_CODE (type) == FUNCTION_TYPE)
{
+ if (quals || rqual)
+ TREE_TYPE (decl) = apply_memfn_quals (TREE_TYPE (decl),
+ TYPE_UNQUALIFIED,
+ REF_QUAL_NONE);
+
if (quals)
{
error (ctype
if (TYPE_NOTHROW_P (type) || nothrow_libfn_p (decl))
TREE_NOTHROW (decl) = 1;
- if (flag_openmp || flag_cilkplus)
+ if (flag_openmp || flag_openmp_simd || flag_cilkplus)
{
/* Adjust "omp declare simd" attributes. */
tree ods = lookup_attribute ("omp declare simd", *attrlist);
decl = check_explicit_specialization (orig_declarator, decl,
template_count,
2 * funcdef_flag +
- 4 * (friendp != 0));
+ 4 * (friendp != 0) +
+ 8 * concept_p);
if (decl == error_mark_node)
return NULL_TREE;
tree orig_declarator,
const cp_decl_specifier_seq *declspecs,
int initialized,
- int constp,
+ int flags,
int template_count,
tree scope)
{
gcc_assert (!name || identifier_p (name));
+ bool constp = flags&1;
+ bool conceptp = flags&2;
+
/* Compute the scope in which to place the variable, but remember
whether or not that scope was explicitly specified by the user. */
explicit_scope = scope;
if (decl_spec_seq_has_spec_p (declspecs, ds_thread))
{
if (DECL_EXTERNAL (decl) || TREE_STATIC (decl))
- set_decl_tls_model (decl, decl_default_tls_model (decl));
+ {
+ CP_DECL_THREAD_LOCAL_P (decl) = true;
+ if (!processing_template_decl)
+ set_decl_tls_model (decl, decl_default_tls_model (decl));
+ }
if (declspecs->gnu_thread_keyword_p)
- DECL_GNU_TLS_P (decl) = true;
+ SET_DECL_GNU_TLS_P (decl);
}
/* If the type of the decl has no linkage, make sure that we'll
else
DECL_INTERFACE_KNOWN (decl) = 1;
+ if (DECL_NAME (decl)
+ && MAIN_NAME_P (DECL_NAME (decl))
+ && scope == global_namespace)
+ error ("cannot declare %<::main%> to be a global variable");
+
+ /* Check that the variable can be safely declared as a concept.
+ Note that this also forbids explicit specializations. */
+ if (conceptp)
+ {
+ if (!processing_template_decl)
+ {
+ error ("a non-template variable cannot be %<concept%>");
+ return NULL_TREE;
+ }
+ else
+ DECL_DECLARED_CONCEPT_P (decl) = true;
+ if (!same_type_ignoring_top_level_qualifiers_p (type, boolean_type_node))
+ error_at (declspecs->locations[ds_type_spec],
+ "concept must have type %<bool%>");
+ }
+ else if (flag_concepts
+ && processing_template_decl > template_class_depth (scope))
+ {
+ tree reqs = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms);
+ tree ci = build_constraints (reqs, NULL_TREE);
+ set_constraints (decl, ci);
+ }
+
// Handle explicit specializations and instantiations of variable templates.
if (orig_declarator)
decl = check_explicit_specialization (orig_declarator, decl,
- template_count, 0);
+ template_count, conceptp * 8);
return decl != error_mark_node ? decl : NULL_TREE;
}
if (type == error_mark_node)
return type;
- /* If a canonical type already exists for this type, use it. We use
- this method instead of type_hash_canon, because it only does a
- simple equality check on the list of field members. */
-
- if ((t = TYPE_GET_PTRMEMFUNC_TYPE (type)))
- return t;
-
/* Make sure that we always have the unqualified pointer-to-member
type first. */
if (cp_cv_quals quals = cp_type_quals (type))
return cp_build_qualified_type (unqual, quals);
}
+ /* If a canonical type already exists for this type, use it. We use
+ this method instead of type_hash_canon, because it only does a
+ simple equality check on the list of field members. */
+
+ if ((t = TYPE_GET_PTRMEMFUNC_TYPE (type)))
+ return t;
+
t = make_node (RECORD_TYPE);
/* Let the front end know this is a pointer to member function. */
cp_walk_tree (&size, stabilize_save_expr_r, &pset, &pset);
}
-/* Helper function for compute_array_index_type. Look for SIZEOF_EXPR
- not inside of SAVE_EXPR and fold them. */
+/* Reduce a SIZEOF_EXPR to its value. */
-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;
+tree
+fold_sizeof_expr (tree t)
+{
+ tree r;
+ if (SIZEOF_EXPR_TYPE_P (t))
+ r = cxx_sizeof_or_alignof_type (TREE_TYPE (TREE_OPERAND (t, 0)),
+ SIZEOF_EXPR, false);
+ else if (TYPE_P (TREE_OPERAND (t, 0)))
+ r = cxx_sizeof_or_alignof_type (TREE_OPERAND (t, 0), SIZEOF_EXPR,
+ false);
+ else
+ r = cxx_sizeof_or_alignof_expr (TREE_OPERAND (t, 0), SIZEOF_EXPR,
+ false);
+ if (r == error_mark_node)
+ r = size_one_node;
+ return r;
}
/* Given the SIZE (i.e., number of elements) in an array, compute an
SET_TYPE_STRUCTURAL_EQUALITY (itype);
return itype;
}
-
+
+ if (TREE_CODE (size) != INTEGER_CST)
+ {
+ tree folded = cp_fully_fold (size);
+ if (TREE_CODE (folded) == INTEGER_CST)
+ pedwarn (location_of (size), OPT_Wpedantic,
+ "size of array is not an integral constant-expression");
+ /* Use the folded result for VLAs, too; it will have resolved
+ SIZEOF_EXPR. */
+ size = folded;
+ }
+
/* Normally, the array-bound will be a constant. */
if (TREE_CODE (size) == INTEGER_CST)
{
/* We don't allow VLAs at non-function scopes, or during
tentative template substitution. */
|| !at_function_scope_p ()
- || (cxx_dialect < cxx14 && !(complain & tf_error)))
+ || !(complain & tf_error))
{
if (!(complain & tf_error))
return error_mark_node;
error ("size of array is not an integral constant-expression");
size = integer_one_node;
}
- else if (cxx_dialect < cxx14 && pedantic && warn_vla != 0)
+ else if (pedantic && warn_vla != 0)
{
if (name)
pedwarn (input_location, OPT_Wvla, "ISO C++ forbids variable length array %qD", name);
cp_convert (ssizetype, integer_one_node,
complain),
complain);
- itype = fold (itype);
+ itype = maybe_constant_value (itype);
processing_template_decl = saved_processing_template_decl;
if (!TREE_CONSTANT (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));
- }
-
stabilize_vla_size (itype);
- if (cxx_dialect >= cxx14 && flag_exceptions)
- {
- /* If the VLA bound is larger than half the address space,
- or less than zero, throw std::bad_array_length. */
- tree comp = build2 (LT_EXPR, boolean_type_node, itype,
- ssize_int (-1));
- comp = build3 (COND_EXPR, void_type_node, comp,
- throw_bad_array_length (), void_node);
- finish_expr_stmt (comp);
- }
- else if (flag_sanitize & SANITIZE_VLA
- && current_function_decl != NULL_TREE
- && !lookup_attribute ("no_sanitize_undefined",
- DECL_ATTRIBUTES
- (current_function_decl)))
+ if (flag_sanitize & SANITIZE_VLA
+ && do_ubsan_in_current_function ())
{
- /* From C++14 onwards, we throw an exception on a negative
- length size of an array; see above. */
-
/* We have to add 1 -- in the ubsan routine we generate
LE_EXPR rather than LT_EXPR. */
tree t = fold_build2 (PLUS_EXPR, TREE_TYPE (itype), itype,
return error_mark_node;
}
- if (cxx_dialect >= cxx14 && array_of_runtime_bound_p (type)
- && (flag_iso || warn_vla > 0))
- pedwarn (input_location, OPT_Wvla, "array of array of runtime bound");
-
/* Figure out the index type for the array. */
if (size)
itype = compute_array_index_type (name, size, tf_warning_or_error);
return build_cplus_array_type (type, itype);
}
-/* Check that it's OK to declare a function with the indicated TYPE.
- SFK indicates the kind of special function (if any) that this
- function is. OPTYPE is the type given in a conversion operator
- declaration, or the class type for a constructor/destructor.
- Returns the actual return type of the function; that
- may be different than TYPE if an error occurs, or for certain
- special functions. */
+/* Returns the smallest location != UNKNOWN_LOCATION among the
+ three stored in LOCATIONS[ds_const], LOCATIONS[ds_volatile],
+ and LOCATIONS[ds_restrict]. */
+
+static location_t
+smallest_type_quals_location (int type_quals, const location_t* locations)
+{
+ location_t loc = UNKNOWN_LOCATION;
+
+ if (type_quals & TYPE_QUAL_CONST)
+ loc = locations[ds_const];
+
+ if ((type_quals & TYPE_QUAL_VOLATILE)
+ && (loc == UNKNOWN_LOCATION || locations[ds_volatile] < loc))
+ loc = locations[ds_volatile];
+
+ if ((type_quals & TYPE_QUAL_RESTRICT)
+ && (loc == UNKNOWN_LOCATION || locations[ds_restrict] < loc))
+ loc = locations[ds_restrict];
+
+ return loc;
+}
+
+/* Check that it's OK to declare a function with the indicated TYPE
+ and TYPE_QUALS. SFK indicates the kind of special function (if any)
+ that this function is. OPTYPE is the type given in a conversion
+ operator declaration, or the class type for a constructor/destructor.
+ Returns the actual return type of the function; that may be different
+ than TYPE if an error occurs, or for certain special functions. */
static tree
check_special_function_return_type (special_function_kind sfk,
tree type,
- tree optype)
+ tree optype,
+ int type_quals,
+ const location_t* locations)
{
switch (sfk)
{
case sfk_constructor:
if (type)
error ("return type specification for constructor invalid");
+ else if (type_quals != TYPE_UNQUALIFIED)
+ error_at (smallest_type_quals_location (type_quals, locations),
+ "qualifiers are not allowed on constructor declaration");
if (targetm.cxx.cdtor_returns_this () && !TYPE_FOR_JAVA (optype))
type = build_pointer_type (optype);
case sfk_destructor:
if (type)
error ("return type specification for destructor invalid");
+ else if (type_quals != TYPE_UNQUALIFIED)
+ error_at (smallest_type_quals_location (type_quals, locations),
+ "qualifiers are not allowed on destructor declaration");
+
/* We can't use the proper return type here because we run into
problems with ambiguous bases and covariant returns.
Java classes are left unchanged because (void *) isn't a valid
case sfk_conversion:
if (type)
- error ("return type specified for %<operator %T%>", optype);
+ error ("return type specified for %<operator %T%>", optype);
+ else if (type_quals != TYPE_UNQUALIFIED)
+ error_at (smallest_type_quals_location (type_quals, locations),
+ "qualifiers are not allowed on declaration of "
+ "%<operator %T%>", optype);
+
type = optype;
break;
a member function. */
cp_ref_qualifier rqual = REF_QUAL_NONE;
/* cv-qualifiers that apply to the type specified by the DECLSPECS. */
- int type_quals;
+ int type_quals = TYPE_UNQUALIFIED;
tree raises = NULL_TREE;
int template_count = 0;
tree returned_attrs = NULL_TREE;
bool array_parameter_p = false;
source_location saved_loc = input_location;
const char *errmsg;
+ tree reqs = NULL_TREE;
signed_p = decl_spec_seq_has_spec_p (declspecs, ds_signed);
unsigned_p = decl_spec_seq_has_spec_p (declspecs, ds_unsigned);
explicit_intN = declspecs->explicit_intN_p;
thread_p = decl_spec_seq_has_spec_p (declspecs, ds_thread);
+ // Was concept_p specified? Note that ds_concept
+ // implies ds_constexpr!
+ bool concept_p = decl_spec_seq_has_spec_p (declspecs, ds_concept);
+ if (concept_p)
+ constexpr_p = true;
+
+ if (decl_spec_seq_has_spec_p (declspecs, ds_const))
+ type_quals |= TYPE_QUAL_CONST;
+ if (decl_spec_seq_has_spec_p (declspecs, ds_volatile))
+ type_quals |= TYPE_QUAL_VOLATILE;
+ if (decl_spec_seq_has_spec_p (declspecs, ds_restrict))
+ type_quals |= TYPE_QUAL_RESTRICT;
+
if (decl_context == FUNCDEF)
funcdef_flag = true, decl_context = NORMAL;
else if (decl_context == MEMFUNCDEF)
if (name == NULL)
name = decl_context == PARM ? "parameter" : "type name";
+ if (concept_p && typedef_p)
+ {
+ error ("%<concept%> cannot appear in a typedef declaration");
+ return error_mark_node;
+ }
+
if (constexpr_p && typedef_p)
{
error ("%<constexpr%> cannot appear in a typedef declaration");
ctor_return_type = ctype;
if (sfk != sfk_none)
- type = check_special_function_return_type (sfk, type,
- ctor_return_type);
+ {
+ type = check_special_function_return_type (sfk, type,
+ ctor_return_type,
+ type_quals,
+ declspecs->locations);
+ type_quals = TYPE_UNQUALIFIED;
+ }
else if (type == NULL_TREE)
{
int is_main;
warning (OPT_Wreturn_type,
"ISO C++ forbids declaration of %qs with no type", name);
- type = integer_type_node;
+ if (type_was_error_mark_node && template_parm_flag)
+ /* FIXME we should be able to propagate the error_mark_node as is
+ for other contexts too. */
+ type = error_mark_node;
+ else
+ type = integer_type_node;
}
ctype = NULL_TREE;
type = build_complex_type (type);
}
- type_quals = TYPE_UNQUALIFIED;
- if (decl_spec_seq_has_spec_p (declspecs, ds_const))
- type_quals |= TYPE_QUAL_CONST;
- if (decl_spec_seq_has_spec_p (declspecs, ds_volatile))
- type_quals |= TYPE_QUAL_VOLATILE;
- 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%>",
- ctor_return_type);
-
/* If we're using the injected-class-name to form a compound type or a
declaration, replace it with the underlying class so we don't get
redundant typedefs in the debug output. But if we are returning the
|| thread_p)
error ("storage class specifiers invalid in parameter declarations");
+ /* Function parameters cannot be concept. */
+ if (concept_p)
+ error ("a parameter cannot be declared %<concept%>");
/* Function parameters cannot be constexpr. If we saw one, moan
and pretend it wasn't there. */
- if (constexpr_p)
+ else if (constexpr_p)
{
error ("a parameter cannot be declared %<constexpr%>");
constexpr_p = 0;
if (virtualp
&& (current_class_name == NULL_TREE || decl_context != FIELD))
{
- error ("%<virtual%> outside class declaration");
+ error_at (declspecs->locations[ds_virtual],
+ "%<virtual%> outside class declaration");
virtualp = 0;
}
case cdk_array:
type = create_array_type_for_decl (dname, type,
declarator->u.array.bounds);
+ if (!valid_array_size_p (input_location, type, dname))
+ type = error_mark_node;
+
if (declarator->std_attributes)
/* [dcl.array]/1:
virt_specifiers = declarator->u.function.virt_specifiers;
/* And ref-qualifier, too */
rqual = declarator->u.function.ref_qualifier;
+ /* And tx-qualifier. */
+ tree tx_qual = declarator->u.function.tx_qualifier;
/* Pick up the exception specifications. */
raises = declarator->u.function.exception_specification;
/* If the exception-specification is ill-formed, let's pretend
if (raises == error_mark_node)
raises = NULL_TREE;
+ if (reqs)
+ error_at (location_of (reqs), "requires-clause on return type");
+ reqs = declarator->u.function.requires_clause;
+
/* Say it's a definition only for the CALL_EXPR
closest to the identifier. */
funcdecl_p = inner_declarator && inner_declarator->kind == cdk_id;
virtualp = false;
}
}
- else if (!is_auto (type))
+ else if (!is_auto (type) && sfk != sfk_conversion)
{
error ("%qs function with trailing return type has"
" %qT as its type rather than plain %<auto%>",
return error_mark_node;
}
}
- else if (declarator->u.function.late_return_type)
+ else if (declarator->u.function.late_return_type
+ && sfk != sfk_conversion)
{
if (cxx_dialect < cxx11)
/* Not using maybe_warn_cpp0x because this should
maybe_warn_cpp0x (CPP0X_EXPLICIT_CONVERSION);
explicitp = 2;
}
+ if (late_return_type_p)
+ error ("a conversion function cannot have a trailing return type");
}
arg_types = grokparms (declarator->u.function.parameters,
}
type = build_function_type (type, arg_types);
- if (declarator->std_attributes)
+
+ tree attrs = declarator->std_attributes;
+ if (tx_qual)
+ {
+ tree att = build_tree_list (tx_qual, NULL_TREE);
+ /* transaction_safe applies to the type, but
+ transaction_safe_dynamic applies to the function. */
+ if (is_attribute_p ("transaction_safe", tx_qual))
+ attrs = chainon (attrs, att);
+ else
+ returned_attrs = chainon (returned_attrs, att);
+ }
+ if (attrs)
/* [dcl.fct]/2:
The optional attribute-specifier-seq appertains to
the function type. */
- decl_attributes (&type, declarator->std_attributes,
- 0);
+ decl_attributes (&type, attrs, 0);
}
break;
: G_("cannot declare pointer to qualified function type %qT"),
type);
- if (cxx_dialect >= cxx14 && array_of_runtime_bound_p (type)
- && (flag_iso || warn_vla > 0))
- pedwarn (input_location, OPT_Wvla,
- declarator->kind == cdk_reference
- ? G_("reference to array of runtime bound")
- : G_("pointer to array of runtime bound"));
-
/* When the pointed-to type involves components of variable size,
care must be taken to ensure that the size evaluation code is
emitted early enough to dominate all the possible later uses
the object as `const'. */
if (constexpr_p && innermost_code != cdk_function)
{
- if (type_quals & TYPE_QUAL_VOLATILE)
- error ("both %<volatile%> and %<constexpr%> cannot be used here");
+ /* DR1688 says that a `constexpr' specifier in combination with
+ `volatile' is valid. */
+
if (TREE_CODE (type) != REFERENCE_TYPE)
{
type_quals |= TYPE_QUAL_CONST;
error ("non-parameter %qs cannot be a parameter pack", name);
}
- /* Did array size calculations overflow or does the array cover more
- than half of the address-space? */
- if (TREE_CODE (type) == ARRAY_TYPE
- && COMPLETE_TYPE_P (type)
- && TREE_CODE (TYPE_SIZE_UNIT (type)) == INTEGER_CST
- && ! valid_constant_size_p (TYPE_SIZE_UNIT (type)))
- {
- error ("size of array %qs is too large", name);
- /* If we proceed with the array type as it is, we'll eventually
- crash in tree_to_[su]hwi(). */
- type = error_mark_node;
- }
-
if ((decl_context == FIELD || decl_context == PARM)
&& !processing_template_decl
&& variably_modified_type_p (type, NULL_TREE))
in the declaration of a constructor or conversion function within
a class definition. */
if (!current_class_type)
- error ("%<explicit%> outside class declaration");
+ error_at (declspecs->locations[ds_explicit],
+ "%<explicit%> outside class declaration");
else if (friendp)
- error ("%<explicit%> in friend declaration");
+ error_at (declspecs->locations[ds_explicit],
+ "%<explicit%> in friend declaration");
else
- error ("only declarations of constructors and conversion operators "
- "can be %<explicit%>");
+ error_at (declspecs->locations[ds_explicit],
+ "only declarations of constructors and conversion operators "
+ "can be %<explicit%>");
explicitp = 0;
}
type = error_mark_node;
}
- if (cxx_dialect >= cxx14 && array_of_runtime_bound_p (type)
- && (flag_iso || warn_vla > 0))
- pedwarn (input_location, OPT_Wvla,
- "typedef naming array of runtime bound");
+ if (reqs)
+ error_at (location_of (reqs), "requires-clause on typedef");
if (decl_context == FIELD)
decl = build_lang_decl (TYPE_DECL, unqualified_id, type);
/* Replace the anonymous name with the real name everywhere. */
for (t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t))
{
- if (ANON_AGGRNAME_P (TYPE_IDENTIFIER (t)))
+ if (anon_aggrname_p (TYPE_IDENTIFIER (t)))
/* We do not rename the debug info representing the
anonymous tagged type because the standard says in
[dcl.typedef] that the naming applies only for
if (decl_context == TYPENAME)
{
- /* Note that the grammar rejects storage classes
- in typenames, fields or parameters. */
- if (type_quals != TYPE_UNQUALIFIED)
- type_quals = TYPE_UNQUALIFIED;
+ /* Note that here we don't care about type_quals. */
/* Special case: "friend class foo" looks like a TYPENAME context. */
if (friendp)
{
- if (type_quals != TYPE_UNQUALIFIED)
- {
- error ("type qualifiers specified for friend class declaration");
- type_quals = TYPE_UNQUALIFIED;
- }
if (inlinep)
{
error ("%<inline%> specified for friend class declaration");
error ("invalid qualifiers on non-member function type");
}
+ if (reqs)
+ error_at (location_of (reqs), "requires-clause on type-id");
+
return type;
}
else if (unqualified_id == NULL_TREE && decl_context != PARM
return error_mark_node;
}
+ if (reqs
+ && TREE_CODE (type) != FUNCTION_TYPE
+ && TREE_CODE (type) != METHOD_TYPE)
+ error_at (location_of (reqs),
+ "requires-clause on declaration of non-function type %qT",
+ type);
+
/* We don't check parameter types here because we can emit a better
error message later. */
if (decl_context != PARM)
}
else if (decl_context == FIELD)
{
- if (!staticp && TREE_CODE (type) != METHOD_TYPE
+ if (!staticp && !friendp && TREE_CODE (type) != METHOD_TYPE
&& type_uses_auto (type))
{
error ("non-static data member declared %<auto%>");
uqname, ctype);
return error_mark_node;
}
+ if (concept_p)
+ {
+ error ("a destructor cannot be %<concept%>");
+ return error_mark_node;
+ }
if (constexpr_p)
{
error ("a destructor cannot be %<constexpr%>");
id_declarator->u.id.unqualified_name);
return error_mark_node;
}
+ if (sfk == sfk_constructor)
+ if (concept_p)
+ {
+ error ("a constructor cannot be %<concept%>");
+ return error_mark_node;
+ }
+ if (concept_p)
+ {
+ error ("a concept cannot be a member function");
+ concept_p = false;
+ }
+
+ if (TREE_CODE (unqualified_id) == TEMPLATE_ID_EXPR)
+ {
+ tree tmpl = TREE_OPERAND (unqualified_id, 0);
+ if (variable_template_p (tmpl))
+ {
+ error ("specialization of variable template %qD "
+ "declared as function", tmpl);
+ inform (DECL_SOURCE_LOCATION (tmpl),
+ "variable template declared here");
+ return error_mark_node;
+ }
+ }
/* Tell grokfndecl if it needs to set TREE_PUBLIC on the node. */
function_context = (ctype != NULL_TREE) ?
? unqualified_id : dname,
parms,
unqualified_id,
+ reqs,
virtualp, flags, memfn_quals, rqual, raises,
friendp ? -1 : 0, friendp, publicp,
- inlinep | (2 * constexpr_p),
- sfk,
+ inlinep | (2 * constexpr_p) | (4 * concept_p),
+ initialized == SD_DELETED, sfk,
funcdef_flag, template_count, in_namespace,
attrlist, declarator->id_loc);
decl = set_virt_specifiers (decl, virt_specifiers);
if (thread_p)
{
- set_decl_tls_model (decl, decl_default_tls_model (decl));
+ CP_DECL_THREAD_LOCAL_P (decl) = true;
+ if (!processing_template_decl)
+ set_decl_tls_model (decl, decl_default_tls_model (decl));
if (declspecs->gnu_thread_keyword_p)
- DECL_GNU_TLS_P (decl) = true;
+ SET_DECL_GNU_TLS_P (decl);
}
-
- if (constexpr_p && !initialized)
+ if (concept_p)
+ error ("static data member %qE declared %<concept%>",
+ unqualified_id);
+ else if (constexpr_p && !initialized)
{
error ("constexpr static data member %qD must have an "
"initializer", decl);
}
else
{
- if (constexpr_p)
+ if (concept_p)
+ error ("non-static data member %qE declared %<concept%>",
+ unqualified_id);
+ else if (constexpr_p)
{
error ("non-static data member %qE declared %<constexpr%>",
unqualified_id);
TYPE_HAS_LATE_RETURN_TYPE (type) = 1;
decl = grokfndecl (ctype, type, original_name, parms, unqualified_id,
- virtualp, flags, memfn_quals, rqual, raises,
+ reqs, virtualp, flags, memfn_quals, rqual, raises,
1, friendp,
- publicp, inlinep | (2 * constexpr_p), sfk,
+ publicp,
+ inlinep | (2 * constexpr_p) | (4 * concept_p),
+ initialized == SD_DELETED,
+ sfk,
funcdef_flag,
template_count, in_namespace, attrlist,
declarator->id_loc);
decl = grokvardecl (type, dname, unqualified_id,
declspecs,
initialized,
- (type_quals & TYPE_QUAL_CONST) != 0,
+ ((type_quals & TYPE_QUAL_CONST) != 0) | (2 * concept_p),
template_count,
ctype ? ctype : in_namespace);
if (decl == NULL_TREE)
LOOKUP_IMPLICIT);
--cp_unevaluated_operand;
- if (warn_zero_as_null_pointer_constant
- && TYPE_PTR_OR_PTRMEM_P (decl_type)
- && null_ptr_cst_p (arg)
- && (complain & tf_warning)
- && maybe_warn_zero_as_null_pointer_constant (arg, input_location))
+ /* Avoid redundant -Wzero-as-null-pointer-constant warnings at
+ the call sites. */
+ if (TYPE_PTR_OR_PTRMEM_P (decl_type)
+ && null_ptr_cst_p (arg))
return nullptr_node;
/* [dcl.fct.default]
*PARMS is set to the chain of PARM_DECLs created. */
-static tree
+tree
grokparms (tree parmlist, tree *parms)
{
tree result = NULL_TREE;
/* First try ordinary name lookup, ignoring hidden class name
injected via friend declaration. */
decl = lookup_name_prefer_type (name, 2);
+ decl = strip_using_decl (decl);
/* If that fails, the name will be placed in the smallest
non-class, non-function-prototype scope according to 3.3.1/5.
We may already have a hidden name declared as friend in this
/* In case of anonymous name, xref_tag is only called to
make type node and push name. Name lookup is not required. */
- if (ANON_AGGRNAME_P (name))
+ if (anon_aggrname_p (name))
t = NULL_TREE;
else
t = lookup_and_check_tag (tag_code, name,
{
if (template_header_p && MAYBE_CLASS_TYPE_P (t))
{
- if (!redeclare_class_template (t, current_template_parms))
- return error_mark_node;
+ /* Check that we aren't trying to overload a class with different
+ constraints. */
+ tree constr = NULL_TREE;
+ if (current_template_parms)
+ {
+ tree reqs = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms);
+ constr = build_constraints (reqs, NULL_TREE);
+ }
+ if (!redeclare_class_template (t, current_template_parms, constr))
+ return error_mark_node;
}
else if (!processing_template_decl
&& CLASS_TYPE_P (t)
tree binfo, base_binfo;
unsigned max_vbases = 0; /* Maximum direct & indirect virtual bases. */
unsigned max_bases = 0; /* Maximum direct bases. */
+ unsigned max_dvbases = 0; /* Maximum direct virtual bases. */
int i;
tree default_access;
tree igo_prev; /* Track Inheritance Graph Order. */
{
max_bases++;
if (TREE_TYPE (*basep))
- max_vbases++;
+ max_dvbases++;
if (CLASS_TYPE_P (basetype))
max_vbases += vec_safe_length (CLASSTYPE_VBASECLASSES (basetype));
basep = &TREE_CHAIN (*basep);
}
}
+ max_vbases += max_dvbases;
TYPE_MARKED_P (ref) = 1;
error ("Java class %qT cannot have multiple bases", ref);
return false;
}
+ else
+ warning (OPT_Wmultiple_inheritance,
+ "%qT defined with multiple direct bases", ref);
}
if (max_vbases)
error ("Java class %qT cannot have virtual bases", ref);
return false;
}
+ else if (max_dvbases)
+ warning (OPT_Wvirtual_inheritance,
+ "%qT defined with direct virtual base", ref);
}
for (igo_prev = binfo; base_list; base_list = TREE_CHAIN (base_list))
/* Build and install a CONST_DECL for an enumeration constant of the
enumeration type ENUMTYPE whose NAME and VALUE (if any) are provided.
- LOC is the location of NAME.
+ Apply ATTRIBUTES if available. LOC is the location of NAME.
Assignment of sequential values by default is handled here. */
void
-build_enumerator (tree name, tree value, tree enumtype, location_t loc)
+build_enumerator (tree name, tree value, tree enumtype, tree attributes,
+ location_t loc)
{
tree decl;
tree context;
if (tmp_value)
value = tmp_value;
}
- else if (! INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (value)))
+ else if (! INTEGRAL_OR_UNSCOPED_ENUMERATION_TYPE_P
+ (TREE_TYPE (value)))
value = perform_implicit_conversion_flags
(ENUM_UNDERLYING_TYPE (enumtype), value, tf_warning_or_error,
LOOKUP_IMPLICIT | LOOKUP_NO_NARROWING);
"type %<%T%>", value, ENUM_UNDERLYING_TYPE (enumtype));
/* Convert the value to the appropriate type. */
- value = convert (ENUM_UNDERLYING_TYPE (enumtype), value);
+ value = fold_convert (ENUM_UNDERLYING_TYPE (enumtype), value);
}
}
TREE_READONLY (decl) = 1;
DECL_INITIAL (decl) = value;
+ if (attributes)
+ cplus_decl_attributes (&decl, attributes, 0);
+
if (context && context == current_class_type && !SCOPED_ENUM_P (enumtype))
/* In something like `struct S { enum E { i = 7 }; };' we put `i'
on the TYPE_FIELDS list for `S'. (That's so that you can say
abstract_virtuals_error (decl, TREE_TYPE (fntype));
}
+/* True iff FN is an implicitly-defined default constructor. */
+
+static bool
+implicit_default_ctor_p (tree fn)
+{
+ return (DECL_CONSTRUCTOR_P (fn)
+ && !user_provided_p (fn)
+ && sufficient_parms_p (FUNCTION_FIRST_USER_PARMTYPE (fn)));
+}
+
/* Create the FUNCTION_DECL for a function definition.
DECLSPECS and DECLARATOR are the parts of the declaration;
they describe the function's name and the type it returns,
if (DECL_DECLARED_INLINE_P (decl1)
&& lookup_attribute ("noinline", attrs))
- warning (0, "inline function %q+D given attribute noinline", decl1);
+ warning_at (DECL_SOURCE_LOCATION (decl1), 0,
+ "inline function %qD given attribute noinline", decl1);
/* Handle gnu_inline attribute. */
if (GNU_INLINE_P (decl1))
}
if (context == NULL)
- warning (OPT_Wmissing_declarations,
- "no previous declaration for %q+D", decl1);
+ warning_at (DECL_SOURCE_LOCATION (decl1),
+ OPT_Wmissing_declarations,
+ "no previous declaration for %qD", decl1);
}
decl1 = olddecl;
|| (DECL_CONSTRUCTOR_P (decl1)
&& targetm.cxx.cdtor_returns_this ()))
{
- cdtor_label = build_decl (input_location,
- LABEL_DECL, NULL_TREE, NULL_TREE);
- DECL_CONTEXT (cdtor_label) = current_function_decl;
+ cdtor_label = create_artificial_label (input_location);
}
start_fname_decls ();
store_parm_decls (current_function_parms);
+ if (!processing_template_decl
+ && flag_lifetime_dse && DECL_CONSTRUCTOR_P (decl1)
+ /* We can't clobber safely for an implicitly-defined default constructor
+ because part of the initialization might happen before we enter the
+ constructor, via AGGR_INIT_ZERO_FIRST (c++/68006). */
+ && !implicit_default_ctor_p (decl1))
+ {
+ /* Insert a clobber to let the back end know that the object storage
+ is dead when we enter the constructor. */
+ tree btype = CLASSTYPE_AS_BASE (current_class_type);
+ tree clobber = build_constructor (btype, NULL);
+ TREE_THIS_VOLATILE (clobber) = true;
+ tree bref = build_nop (build_reference_type (btype), current_class_ptr);
+ bref = convert_from_reference (bref);
+ tree exprstmt = build2 (MODIFY_EXPR, btype, bref, clobber);
+ finish_expr_stmt (exprstmt);
+ }
+
return true;
}
tree decl1;
decl1 = grokdeclarator (declarator, declspecs, FUNCDEF, 1, &attrs);
+ invoke_plugin_callbacks (PLUGIN_START_PARSE_FUNCTION, decl1);
if (decl1 == error_mark_node)
return false;
/* If the declarator is not suitable for a function definition,
initialize_vtbl_ptrs (current_class_ptr);
finish_compound_stmt (compound_stmt);
- /* Insert a cleanup to let the back end know that the object is dead
- when we exit the destructor, either normally or via exception. */
- tree btype = CLASSTYPE_AS_BASE (current_class_type);
- tree clobber = build_constructor (btype, NULL);
- TREE_THIS_VOLATILE (clobber) = true;
- tree bref = build_nop (build_reference_type (btype), current_class_ptr);
- bref = convert_from_reference (bref);
- tree exprstmt = build2 (MODIFY_EXPR, btype, bref, clobber);
- finish_decl_cleanup (NULL_TREE, exprstmt);
+ if (flag_lifetime_dse)
+ {
+ /* Insert a cleanup to let the back end know that the object is dead
+ when we exit the destructor, either normally or via exception. */
+ tree btype = CLASSTYPE_AS_BASE (current_class_type);
+ tree clobber = build_constructor (btype, NULL);
+ TREE_THIS_VOLATILE (clobber) = true;
+ tree bref = build_nop (build_reference_type (btype),
+ current_class_ptr);
+ bref = convert_from_reference (bref);
+ tree exprstmt = build2 (MODIFY_EXPR, btype, bref, clobber);
+ finish_decl_cleanup (NULL_TREE, exprstmt);
+ }
/* And insert cleanups for our bases and members so that they
will be properly destroyed if we throw. */
tree
outer_curly_brace_block (tree fndecl)
{
- tree block = BLOCK_SUBBLOCKS (DECL_INITIAL (fndecl));
- if (FUNCTION_NEEDS_BODY_BLOCK (current_function_decl))
- /* Skip the artificial function body block. */
- block = BLOCK_SUBBLOCKS (block);
+ tree block = DECL_INITIAL (fndecl);
+ if (BLOCK_OUTER_CURLY_BRACE_P (block))
+ return block;
+ block = BLOCK_SUBBLOCKS (block);
+ if (BLOCK_OUTER_CURLY_BRACE_P (block))
+ return block;
+ block = BLOCK_SUBBLOCKS (block);
+ gcc_assert (BLOCK_OUTER_CURLY_BRACE_P (block));
return block;
}
fntype = TREE_TYPE (fndecl);
}
+ // If this is a concept, check that the definition is reasonable.
+ if (DECL_DECLARED_CONCEPT_P (fndecl))
+ check_function_concept (fndecl);
+
/* Save constexpr function body before it gets munged by
the NRV transformation. */
maybe_save_function_definition (fndecl);
+ /* Invoke the pre-genericize plugin before we start munging things. */
+ if (!processing_template_decl)
+ invoke_plugin_callbacks (PLUGIN_PRE_GENERICIZE, fndecl);
+
+ /* Perform delayed folding before NRV transformation. */
+ if (!processing_template_decl)
+ cp_fold_function (fndecl);
+
/* Set up the named return value optimization, if we can. Candidate
variables are selected in check_return_expr. */
if (current_function_return_value)
&& TREE_CODE (TREE_TYPE (decl)) != REFERENCE_TYPE
&& (!CLASS_TYPE_P (TREE_TYPE (decl))
|| !TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (decl))))
- warning (OPT_Wunused_but_set_parameter,
- "parameter %q+D set but not used", decl);
+ warning_at (DECL_SOURCE_LOCATION (decl),
+ OPT_Wunused_but_set_parameter,
+ "parameter %qD set but not used", decl);
unused_but_set_errorcount = errorcount;
}
function. */
maybe_warn_unused_local_typedefs ();
+ /* Possibly warn about unused parameters. */
+ if (warn_unused_parameter
+ && !processing_template_decl
+ && !DECL_CLONED_FUNCTION_P (fndecl))
+ do_warn_unused_parameter (fndecl);
+
/* Genericize before inlining. */
if (!processing_template_decl)
{
struct language_function *f = DECL_SAVED_FUNCTION_DATA (fndecl);
- invoke_plugin_callbacks (PLUGIN_PRE_GENERICIZE, fndecl);
cp_genericize (fndecl);
/* Clear out the bits we don't need. */
f->x_current_class_ptr = NULL;
vec_free (deferred_mark_used_calls);
}
+ invoke_plugin_callbacks (PLUGIN_FINISH_PARSE_FUNCTION, fndecl);
return fndecl;
}
\f
check_template_shadow (fndecl);
- DECL_COMDAT (fndecl) = 1;
+ if (TREE_PUBLIC (fndecl))
+ DECL_COMDAT (fndecl) = 1;
DECL_DECLARED_INLINE_P (fndecl) = 1;
DECL_NO_INLINE_WARNING_P (fndecl) = 1;
cp_apply_type_quals_to_decl (cp_type_quals (type), var);
}
- if (DECL_INITIAL (var)
- && decl_constant_var_p (var))
- DECL_INITIAL (var) = cplus_expand_constant (DECL_INITIAL (var));
-
/* Remove this entry from the list. */
incomplete_vars->unordered_remove (ix);
}
ordinary FUNCTION_DECL. */
fn = lookup_name (id);
arg = build_address (decl);
- mark_used (decl);
+ if (!mark_used (decl, complain) && !(complain & tf_error))
+ return error_mark_node;
cleanup = cp_build_function_call_nary (fn, complain, arg, NULL_TREE);
if (cleanup == error_mark_node)
return error_mark_node;
a "jumpy" behaviour for users of debuggers when they step around
the end of the block. So let's unset the location of the
destructor call instead. */
- if (cleanup != NULL && EXPR_P (cleanup))
- SET_EXPR_LOCATION (cleanup, UNKNOWN_LOCATION);
+ protected_set_expr_location (cleanup, UNKNOWN_LOCATION);
if (cleanup
- && !lookup_attribute ("warn_unused", TYPE_ATTRIBUTES (TREE_TYPE (decl))))
- /* Treat objects with destructors as used; the destructor may do
- something substantive. */
- mark_used (decl);
+ && !lookup_attribute ("warn_unused", TYPE_ATTRIBUTES (TREE_TYPE (decl)))
+ /* Treat objects with destructors as used; the destructor may do
+ something substantive. */
+ && !mark_used (decl, complain) && !(complain & tf_error))
+ return error_mark_node;
return cleanup;
}
case TRAIT_EXPR: return TS_CP_TRAIT_EXPR;
case LAMBDA_EXPR: return TS_CP_LAMBDA_EXPR;
case TEMPLATE_INFO: return TS_CP_TEMPLATE_INFO;
+ case CONSTRAINT_INFO: return TS_CP_CONSTRAINT_INFO;
case USERDEF_LITERAL: return TS_CP_USERDEF_LITERAL;
default: return TS_CP_GENERIC;
}