@@ -9020,6 +9020,13 @@ Do not warn about C++23 constructs in co
an older C++ standard. Even without this option, some C++23 constructs
will only be diagnosed if @option{-Wpedantic} is used.
+@opindex Wc++26-extensions
+@opindex Wno-c++26-extensions
+@item -Wno-c++26-extensions @r{(C++ and Objective-C++ only)}
+Do not warn about C++26 constructs in code being compiled using
+an older C++ standard. Even without this option, some C++26 constructs
+will only be diagnosed if @option{-Wpedantic} is used.
+
@opindex Wcast-qual
@opindex Wno-cast-qual
@item -Wcast-qual
@@ -478,6 +478,10 @@ Wc++23-extensions
C++ ObjC++ Var(warn_cxx23_extensions) Warning Init(1)
Warn about C++23 constructs in code compiled with an older standard.
+Wc++26-extensions
+C++ ObjC++ Var(warn_cxx26_extensions) Warning Init(1)
+Warn about C++26 constructs in code compiled with an older standard.
+
Wcast-function-type
C ObjC C++ ObjC++ Var(warn_cast_function_type) Warning EnabledBy(Wextra)
Warn about casts between incompatible function types.
@@ -1086,6 +1086,7 @@ c_cpp_builtins (cpp_reader *pfile)
{
/* Set feature test macros for C++26. */
cpp_define (pfile, "__cpp_constexpr=202306L");
+ cpp_define (pfile, "__cpp_placeholder_variables=202306L");
}
if (flag_concepts)
{
@@ -519,6 +519,7 @@ extern GTY(()) tree cp_global_trees[CPTI
RANGE_FOR_IVDEP (in RANGE_FOR_STMT)
CALL_EXPR_OPERATOR_SYNTAX (in CALL_EXPR, AGGR_INIT_EXPR)
CONSTRUCTOR_IS_DESIGNATED_INIT (in CONSTRUCTOR)
+ OVL_PLACEHOLDER_P (in OVERLOAD)
Usage of TYPE_LANG_FLAG_?:
0: TYPE_DEPENDENT_P
@@ -807,6 +808,8 @@ typedef struct ptrmem_cst * ptrmem_cst_t
#define OVL_LOOKUP_P(NODE) TREE_LANG_FLAG_4 (OVERLOAD_CHECK (NODE))
/* If set, this OVL_USING_P overload is exported. */
#define OVL_EXPORT_P(NODE) TREE_LANG_FLAG_5 (OVERLOAD_CHECK (NODE))
+/* If set, this overload includes name-independent declarations. */
+#define OVL_PLACEHOLDER_P(NODE) TREE_LANG_FLAG_6 (OVERLOAD_CHECK (NODE))
/* The first decl of an overload. */
#define OVL_FIRST(NODE) ovl_first (NODE)
@@ -7807,7 +7810,7 @@ extern tree lambda_capture_field_type (
extern tree lambda_proxy_type (tree);
extern tree lambda_function (tree);
extern void apply_deduced_return_type (tree, tree);
-extern tree add_capture (tree, tree, tree, bool, bool);
+extern tree add_capture (tree, tree, tree, bool, bool, unsigned *);
extern tree add_default_capture (tree, tree, tree);
extern void insert_capture_proxy (tree);
extern void insert_pending_capture_proxies (void);
@@ -8889,6 +8892,18 @@ extended_float_type_p (tree type)
return false;
}
+/* True if DECL is name-independent declaration. */
+
+inline bool
+name_independent_decl_p (tree decl)
+{
+ return ((VAR_P (decl) || TREE_CODE (decl) == FIELD_DECL)
+ && DECL_NAME (decl)
+ && id_equal (DECL_NAME (decl), "_")
+ && !TREE_STATIC (decl)
+ && !DECL_EXTERNAL (decl));
+}
+
#if CHECKING_P
namespace selftest {
extern void run_cp_tests (void);
@@ -511,10 +511,11 @@ private:
void preserve_state ();
void restore_state ();
-private:
+public:
static tree ambiguous (tree thing, tree current);
- void add_overload (tree fns);
void add_value (tree new_val);
+private:
+ void add_overload (tree fns);
void add_type (tree new_type);
bool process_binding (tree val_bind, tree type_bind);
unsigned process_module_binding (tree val_bind, tree type_bind, unsigned);
@@ -1806,6 +1807,71 @@ fields_linear_search (tree klass, tree n
return NULL_TREE;
}
+/* Like fields_linear_search, but specific for "_" name. There can be multiple
+ name-independent non-static data members and in that case a TREE_LIST with the
+ ambiguous decls should be returned. */
+
+static tree
+placeholder_linear_search (tree val, tree klass, tree name)
+{
+ for (tree fields = TYPE_FIELDS (klass); fields; fields = DECL_CHAIN (fields))
+ {
+ tree decl = fields;
+
+ if (TREE_CODE (decl) == FIELD_DECL
+ && ANON_AGGR_TYPE_P (TREE_TYPE (decl)))
+ {
+ if (tree temp = search_anon_aggr (TREE_TYPE (decl), name, false))
+ {
+ decl = temp;
+ goto add;
+ }
+ }
+
+ if (DECL_NAME (decl) != name)
+ continue;
+
+ if (TREE_CODE (decl) == USING_DECL)
+ {
+ decl = strip_using_decl (decl);
+ if (is_overloaded_fn (decl))
+ continue;
+ }
+
+ if (DECL_DECLARES_FUNCTION_P (decl))
+ /* Functions are found separately. */
+ continue;
+
+ add:
+ if (val == NULL_TREE)
+ val = decl;
+ else
+ {
+ if (TREE_CODE (val) != TREE_LIST)
+ {
+ if (TREE_CODE (val) == OVERLOAD
+ && OVL_DEDUP_P (val)
+ && TREE_CODE (decl) == USING_DECL)
+ {
+ val = ovl_make (decl, val);
+ continue;
+ }
+ val = tree_cons (NULL_TREE, val, NULL_TREE);
+ TREE_TYPE (val) = error_mark_node;
+ }
+ if (TREE_CODE (decl) == TREE_LIST)
+ val = chainon (decl, val);
+ else
+ {
+ val = tree_cons (NULL_TREE, decl, val);
+ TREE_TYPE (val) = error_mark_node;
+ }
+ }
+ }
+
+ return val;
+}
+
/* Look for NAME member inside of anonymous aggregate ANON. Although
such things should only contain FIELD_DECLs, we check that too
late, and would give very confusing errors if we weren't
@@ -1843,6 +1909,34 @@ get_class_binding_direct (tree klass, tr
val = member_vec_binary_search (member_vec, lookup);
if (!val)
;
+ else if (TREE_CODE (val) == OVERLOAD && OVL_PLACEHOLDER_P (val))
+ {
+ if (want_type)
+ {
+ while (TREE_CODE (val) == OVERLOAD && OVL_PLACEHOLDER_P (val))
+ val = OVL_CHAIN (val);
+ if (STAT_HACK_P (val))
+ val = STAT_TYPE (val);
+ else if (!DECL_DECLARES_TYPE_P (val))
+ val = NULL_TREE;
+ }
+ else
+ {
+ tree ovl = val;
+ val = NULL_TREE;
+ while (TREE_CODE (ovl) == OVERLOAD && OVL_PLACEHOLDER_P (ovl))
+ {
+ val = tree_cons (NULL_TREE, OVL_FUNCTION (ovl), val);
+ TREE_TYPE (val) = error_mark_node;
+ ovl = OVL_CHAIN (ovl);
+ }
+ if (STAT_HACK_P (ovl))
+ val = tree_cons (NULL_TREE, STAT_DECL (ovl), val);
+ else
+ val = tree_cons (NULL_TREE, ovl, val);
+ TREE_TYPE (val) = error_mark_node;
+ }
+ }
else if (STAT_HACK_P (val))
val = want_type ? STAT_TYPE (val) : STAT_DECL (val);
else if (want_type && !DECL_DECLARES_TYPE_P (val))
@@ -1853,7 +1947,9 @@ get_class_binding_direct (tree klass, tr
if (member_vec && !want_type)
val = member_vec_linear_search (member_vec, lookup);
- if (!val || (TREE_CODE (val) == OVERLOAD && OVL_DEDUP_P (val)))
+ if (id_equal (lookup, "_") && !want_type)
+ val = placeholder_linear_search (val, klass, lookup);
+ else if (!val || (TREE_CODE (val) == OVERLOAD && OVL_DEDUP_P (val)))
/* Dependent using declarations are a 'field', make sure we
return that even if we saw an overload already. */
if (tree field_val = fields_linear_search (klass, lookup, want_type))
@@ -2049,6 +2145,25 @@ member_name_cmp (const void *a_p, const
if (TREE_CODE (b) == OVERLOAD)
b = OVL_FUNCTION (b);
+ if (id_equal (name_a, "_"))
+ {
+ /* Sort name-independent members first. */
+ if (name_independent_decl_p (a))
+ {
+ if (name_independent_decl_p (b))
+ {
+ if (DECL_UID (a) != DECL_UID (b))
+ return DECL_UID (a) < DECL_UID (b) ? -1 : +1;
+ gcc_assert (a == b);
+ return 0;
+ }
+ else
+ return -1;
+ }
+ else if (name_independent_decl_p (b))
+ return +1;
+ }
+
/* We're in STAT_HACK or USING_DECL territory (or possibly error-land). */
if (TREE_CODE (a) != TREE_CODE (b))
{
@@ -2183,14 +2298,15 @@ member_vec_append_enum_values (vec<tree,
/* MEMBER_VEC has just had new DECLs added to it, but is sorted.
DeDup adjacent DECLS of the same name. We already dealt with
conflict resolution when adding the fields or methods themselves.
- There are three cases (which could all be combined):
+ There are four cases (which could all be combined):
1) a TYPE_DECL and non TYPE_DECL. Deploy STAT_HACK as appropriate.
2) a USING_DECL and an overload. If the USING_DECL is dependent,
it wins. Otherwise the OVERLOAD does.
- 3) two USING_DECLS. ...
+ 3) two USING_DECLS.
+ 4) name-independent members plus others. ...
member_name_cmp will have ordered duplicates as
- <fns><using><type> */
+ <placeholder><fns><using><type> */
static void
member_vec_dedup (vec<tree, va_gc> *member_vec)
@@ -2208,6 +2324,7 @@ member_vec_dedup (vec<tree, va_gc> *memb
tree to_type = NULL_TREE;
tree to_using = NULL_TREE;
tree marker = NULL_TREE;
+ unsigned placeholder = ix;
for (jx = ix; jx < len; jx++)
{
@@ -2251,7 +2368,9 @@ member_vec_dedup (vec<tree, va_gc> *memb
continue;
}
- if (!current)
+ if (name_independent_decl_p (next))
+ placeholder = jx + 1;
+ else if (!current)
current = next;
}
@@ -2271,6 +2390,17 @@ member_vec_dedup (vec<tree, va_gc> *memb
current = stat_hack (current, to_type);
}
+ for (unsigned kx = placeholder; kx > ix; --kx)
+ if (!current)
+ current = (*member_vec)[kx - 1];
+ else if (current == to_type)
+ current = stat_hack ((*member_vec)[kx - 1], to_type);
+ else
+ {
+ current = ovl_make ((*member_vec)[kx - 1], current);
+ OVL_PLACEHOLDER_P (current) = 1;
+ }
+
if (current)
{
if (marker)
@@ -2479,10 +2609,27 @@ pop_local_binding (tree id, tree decl)
away. */
if (binding->value == decl)
binding->value = NULL_TREE;
+ else if (binding->type == decl)
+ binding->type = NULL_TREE;
else
{
- gcc_checking_assert (binding->type == decl);
- binding->type = NULL_TREE;
+ /* Name-independent variable was found after at least one declaration
+ with the same name. */
+ gcc_assert (TREE_CODE (binding->value) == TREE_LIST);
+ if (TREE_VALUE (binding->value) != decl)
+ {
+ binding->value = nreverse (binding->value);
+ /* Skip over TREE_LISTs added for check_local_shadow detected
+ declarations, formerly at the tail, now at the start of the
+ list. */
+ while (TREE_PURPOSE (binding->value) == error_mark_node)
+ binding->value = TREE_CHAIN (binding->value);
+ }
+ gcc_assert (TREE_VALUE (binding->value) == decl);
+ binding->value = TREE_CHAIN (binding->value);
+ while (binding->value
+ && TREE_PURPOSE (binding->value) == error_mark_node)
+ binding->value = TREE_CHAIN (binding->value);
}
if (!binding->value && !binding->type)
@@ -2579,6 +2726,10 @@ supplement_binding (cxx_binding *binding
tree bval = binding->value;
bool ok = true;
+ if (bval
+ && TREE_CODE (bval) == TREE_LIST
+ && name_independent_decl_p (TREE_VALUE (bval)))
+ bval = TREE_VALUE (bval);
tree target_bval = strip_using_decl (bval);
tree target_decl = strip_using_decl (decl);
@@ -2682,6 +2833,14 @@ supplement_binding (cxx_binding *binding
&& CONST_DECL_USING_P (decl))
/* Let the clone hide the using-decl that introduced it. */
binding->value = decl;
+ else if (name_independent_decl_p (decl))
+ {
+ if (cxx_dialect < cxx26)
+ pedwarn (DECL_SOURCE_LOCATION (decl), OPT_Wc__26_extensions,
+ "placeholder variables only available with "
+ "%<-std=c++2c%> or %<-std=gnu++2c%>");
+ binding->value = name_lookup::ambiguous (decl, binding->value);
+ }
else
{
if (!error_operand_p (bval))
@@ -2786,6 +2945,7 @@ update_binding (cp_binding_level *level,
tree old_type = NULL_TREE;
bool hide_type = false;
bool hide_value = false;
+ bool placeholder_p = false;
if (!slot)
{
@@ -2793,6 +2953,7 @@ update_binding (cp_binding_level *level,
hide_type = HIDDEN_TYPE_BINDING_P (binding);
if (!old_type)
hide_value = hide_type, hide_type = false;
+ placeholder_p = name_independent_decl_p (decl);
}
else if (STAT_HACK_P (*slot))
{
@@ -2888,7 +3049,9 @@ update_binding (cp_binding_level *level,
}
else if (old)
{
- if (TREE_CODE (old) != TREE_CODE (decl))
+ if (placeholder_p)
+ to_val = name_lookup::ambiguous (decl, old);
+ else if (TREE_CODE (old) != TREE_CODE (decl))
/* Different kinds of decls conflict. */
goto conflict;
else if (TREE_CODE (old) == TYPE_DECL)
@@ -3088,13 +3251,13 @@ inform_shadowed (tree shadowed)
/* DECL is being declared at a local scope. Emit suitable shadow
warnings. */
-static void
+static tree
check_local_shadow (tree decl)
{
/* Don't complain about the parms we push and then pop
while tentatively parsing a function declarator. */
if (TREE_CODE (decl) == PARM_DECL && !DECL_CONTEXT (decl))
- return;
+ return NULL_TREE;
tree old = NULL_TREE;
cp_binding_level *old_scope = NULL;
@@ -3129,7 +3292,7 @@ check_local_shadow (tree decl)
error_at (DECL_SOURCE_LOCATION (old),
"lambda parameter %qD "
"previously declared as a capture", old);
- return;
+ return NULL_TREE;
}
/* Don't complain if it's from an enclosing function. */
else if (DECL_CONTEXT (old) == current_function_decl
@@ -3153,6 +3316,9 @@ check_local_shadow (tree decl)
in the outermost block of the function definition. */
if (b->kind == sk_function_parms)
{
+ if (name_independent_decl_p (decl))
+ return old;
+
auto_diagnostic_group d;
bool emit = true;
if (DECL_EXTERNAL (decl))
@@ -3165,7 +3331,7 @@ check_local_shadow (tree decl)
if (emit)
inform (DECL_SOURCE_LOCATION (old),
"%q#D previously declared here", old);
- return;
+ return NULL_TREE;
}
}
@@ -3177,7 +3343,7 @@ check_local_shadow (tree decl)
scope != old_scope; scope = scope->level_chain)
if (scope->kind == sk_class
&& !LAMBDA_TYPE_P (scope->this_entity))
- return;
+ return NULL_TREE;
}
/* Error if redeclaring a local declared in a
init-statement or in the condition of an if or
@@ -3189,6 +3355,9 @@ check_local_shadow (tree decl)
&& old_scope == current_binding_level->level_chain
&& (old_scope->kind == sk_cond || old_scope->kind == sk_for))
{
+ if (name_independent_decl_p (decl))
+ return old;
+
auto_diagnostic_group d;
bool emit = true;
if (DECL_EXTERNAL (decl))
@@ -3200,7 +3369,7 @@ check_local_shadow (tree decl)
if (emit)
inform (DECL_SOURCE_LOCATION (old),
"%q#D previously declared here", old);
- return;
+ return NULL_TREE;
}
/* C++11:
3.3.3/3: The name declared in an exception-declaration (...)
@@ -3212,6 +3381,9 @@ check_local_shadow (tree decl)
&& old_scope == current_binding_level->level_chain
&& old_scope->kind == sk_catch)
{
+ if (name_independent_decl_p (decl))
+ return old;
+
auto_diagnostic_group d;
bool emit;
if (DECL_EXTERNAL (decl))
@@ -3223,9 +3395,13 @@ check_local_shadow (tree decl)
if (emit)
inform (DECL_SOURCE_LOCATION (old),
"%q#D previously declared here", old);
- return;
+ return NULL_TREE;
}
+ /* Don't emit -Wshadow* warnings for placeholders. */
+ if (name_independent_decl_p (decl))
+ return NULL_TREE;
+
/* If '-Wshadow=compatible-local' is specified without other
-Wshadow= flags, we will warn only when the type of the
shadowing variable (DECL) can be converted to that of the
@@ -3278,15 +3454,19 @@ check_local_shadow (tree decl)
auto_diagnostic_group d;
if (warning_at (DECL_SOURCE_LOCATION (decl), warning_code, msg, decl))
inform_shadowed (old);
- return;
+ return NULL_TREE;
}
if (!warn_shadow)
- return;
+ return NULL_TREE;
+
+ /* Don't emit -Wshadow for placeholders. */
+ if (name_independent_decl_p (decl))
+ return NULL_TREE;
/* Don't warn for artificial things that are not implicit typedefs. */
if (DECL_ARTIFICIAL (decl) && !DECL_IMPLICIT_TYPEDEF_P (decl))
- return;
+ return NULL_TREE;
if (nonlambda_method_basetype ())
if (tree member = lookup_member (current_nonlambda_class_type (),
@@ -3314,7 +3494,7 @@ check_local_shadow (tree decl)
suppress_warning (decl, OPT_Wshadow);
}
}
- return;
+ return NULL_TREE;
}
/* Now look for a namespace shadow. */
@@ -3337,10 +3517,10 @@ check_local_shadow (tree decl)
inform_shadowed (old);
suppress_warning (decl, OPT_Wshadow);
}
- return;
+ return NULL_TREE;
}
- return;
+ return NULL_TREE;
}
/* DECL is being pushed inside function CTX. Set its context, if
@@ -3659,6 +3839,8 @@ pushdecl (tree decl, bool hiding)
tree *slot = NULL; /* Binding slot in namespace. */
tree *mslot = NULL; /* Current module slot in namespace. */
tree old = NULL_TREE;
+ bool placeholder_p = false;
+ bool placeholder_diagnosed_p = false;
if (level->kind == sk_namespace)
{
@@ -3682,56 +3864,82 @@ pushdecl (tree decl, bool hiding)
binding = find_local_binding (level, name);
if (binding)
old = binding->value;
+ placeholder_p = name_independent_decl_p (decl);
}
if (old == error_mark_node)
old = NULL_TREE;
- for (ovl_iterator iter (old); iter; ++iter)
- if (iter.using_p ())
- ; /* Ignore using decls here. */
- else if (iter.hidden_p ()
- && TREE_CODE (*iter) == FUNCTION_DECL
- && DECL_LANG_SPECIFIC (*iter)
- && DECL_MODULE_IMPORT_P (*iter))
- ; /* An undeclared builtin imported from elsewhere. */
- else if (tree match
- = duplicate_decls (decl, *iter, hiding, iter.hidden_p ()))
- {
- if (match == error_mark_node)
- ;
- else if (TREE_CODE (match) == TYPE_DECL)
- gcc_checking_assert (REAL_IDENTIFIER_TYPE_VALUE (name)
- == (level->kind == sk_namespace
- ? NULL_TREE : TREE_TYPE (match)));
- else if (iter.hidden_p () && !hiding)
+ tree oldi, oldn;
+ for (oldi = old; oldi; oldi = oldn)
+ {
+ if (TREE_CODE (oldi) == TREE_LIST)
+ {
+ gcc_checking_assert (level->kind != sk_namespace
+ && name_independent_decl_p
+ (TREE_VALUE (old)));
+ oldn = TREE_CHAIN (oldi);
+ oldi = TREE_VALUE (oldi);
+ }
+ else
+ oldn = NULL_TREE;
+ for (ovl_iterator iter (oldi); iter; ++iter)
+ if (iter.using_p ())
+ ; /* Ignore using decls here. */
+ else if (iter.hidden_p ()
+ && TREE_CODE (*iter) == FUNCTION_DECL
+ && DECL_LANG_SPECIFIC (*iter)
+ && DECL_MODULE_IMPORT_P (*iter))
+ ; /* An undeclared builtin imported from elsewhere. */
+ else if (placeholder_p)
+ {
+ /* Ignore name-independent declarations. */
+ if (cxx_dialect < cxx26 && !placeholder_diagnosed_p)
+ pedwarn (DECL_SOURCE_LOCATION (decl), OPT_Wc__26_extensions,
+ "placeholder variables only available with "
+ "%<-std=c++2c%> or %<-std=gnu++2c%>");
+ placeholder_diagnosed_p = true;
+ }
+ else if (tree match
+ = duplicate_decls (decl, *iter, hiding, iter.hidden_p ()))
{
- /* Unhiding a previously hidden decl. */
- tree head = iter.reveal_node (old);
- if (head != old)
+ if (match == error_mark_node)
+ ;
+ else if (TREE_CODE (match) == TYPE_DECL)
+ gcc_checking_assert (REAL_IDENTIFIER_TYPE_VALUE (name)
+ == (level->kind == sk_namespace
+ ? NULL_TREE : TREE_TYPE (match)));
+ else if (iter.hidden_p () && !hiding)
+ {
+ /* Unhiding a previously hidden decl. */
+ tree head = iter.reveal_node (oldi);
+ if (head != oldi)
+ {
+ gcc_checking_assert (ns);
+ if (STAT_HACK_P (*slot))
+ STAT_DECL (*slot) = head;
+ else
+ *slot = head;
+ }
+ if (DECL_EXTERN_C_P (match))
+ /* We need to check and register the decl now. */
+ check_extern_c_conflict (match);
+ }
+ else if (slot
+ && !hiding
+ && STAT_HACK_P (*slot)
+ && STAT_DECL_HIDDEN_P (*slot))
{
- gcc_checking_assert (ns);
- if (STAT_HACK_P (*slot))
- STAT_DECL (*slot) = head;
+ /* Unhide the non-function. */
+ gcc_checking_assert (oldi == match);
+ if (!STAT_TYPE (*slot))
+ *slot = match;
else
- *slot = head;
+ STAT_DECL (*slot) = match;
}
- if (DECL_EXTERN_C_P (match))
- /* We need to check and register the decl now. */
- check_extern_c_conflict (match);
+ return match;
}
- else if (slot && !hiding
- && STAT_HACK_P (*slot) && STAT_DECL_HIDDEN_P (*slot))
- {
- /* Unhide the non-function. */
- gcc_checking_assert (old == match);
- if (!STAT_TYPE (*slot))
- *slot = match;
- else
- STAT_DECL (*slot) = match;
- }
- return match;
- }
+ }
/* Check for redeclaring an import. */
if (slot && *slot && TREE_CODE (*slot) == BINDING_VECTOR)
@@ -3780,7 +3988,20 @@ pushdecl (tree decl, bool hiding)
if (level->kind != sk_namespace)
{
- check_local_shadow (decl);
+ tree local_shadow = check_local_shadow (decl);
+ if (placeholder_p && local_shadow)
+ {
+ if (cxx_dialect < cxx26 && !placeholder_diagnosed_p)
+ pedwarn (DECL_SOURCE_LOCATION (decl), OPT_Wc__26_extensions,
+ "placeholder variables only available with "
+ "%<-std=c++2c%> or %<-std=gnu++2c%>");
+ placeholder_diagnosed_p = true;
+ if (old == NULL_TREE)
+ {
+ old = build_tree_list (error_mark_node, local_shadow);
+ TREE_TYPE (old) = error_mark_node;
+ }
+ }
if (TREE_CODE (decl) == NAMESPACE_DECL)
/* A local namespace alias. */
@@ -7579,7 +7800,30 @@ lookup_name (tree name, LOOK_where where
&& (bool (want & LOOK_want::HIDDEN_LAMBDA)
|| !is_lambda_ignored_entity (iter->value))
&& qualify_lookup (iter->value, want))
- binding = iter->value;
+ {
+ binding = iter->value;
+ if (binding
+ && TREE_CODE (binding) == TREE_LIST
+ && name_independent_decl_p (TREE_VALUE (binding)))
+ {
+ for (tree b = binding; b; b = TREE_CHAIN (b))
+ if (TREE_CHAIN (b) == NULL
+ && TREE_CODE (TREE_VALUE (b)) == OVERLOAD)
+ {
+ /* If the scope has an overload with _ function
+ declarations followed by at least one
+ name-independent declaration, we shouldn't return
+ iter->value but a new TREE_LIST containing the
+ name-independent declaration(s) and functions
+ from the OVERLOAD. */
+ name_lookup lookup (name);
+ for (b = binding; b; b = TREE_CHAIN (b))
+ lookup.add_value (TREE_VALUE (b));
+ binding = lookup.value;
+ break;
+ }
+ }
+ }
else if (bool (want & LOOK_want::TYPE)
&& !HIDDEN_TYPE_BINDING_P (iter)
&& iter->type)
@@ -1091,13 +1091,24 @@ lookup_field_r (tree binfo, void *data)
}
/* Add the new value. */
- lfi->ambiguous = tree_cons (NULL_TREE, nval, lfi->ambiguous);
- TREE_TYPE (lfi->ambiguous) = error_mark_node;
+ if (TREE_CODE (nval) == TREE_LIST)
+ lfi->ambiguous = chainon (nval, lfi->ambiguous);
+ else
+ {
+ lfi->ambiguous = tree_cons (NULL_TREE, nval, lfi->ambiguous);
+ TREE_TYPE (lfi->ambiguous) = error_mark_node;
+ }
}
}
else
{
- lfi->rval = nval;
+ if (TREE_CODE (nval) == TREE_LIST)
+ {
+ lfi->ambiguous = chainon (nval, lfi->ambiguous);
+ lfi->rval = TREE_VALUE (nval);
+ }
+ else
+ lfi->rval = nval;
lfi->rval_binfo = binfo;
}
@@ -412,7 +412,11 @@ build_capture_proxy (tree member, tree i
object = TREE_OPERAND (object, 0);
/* Remove the __ inserted by add_capture. */
- name = get_identifier (IDENTIFIER_POINTER (DECL_NAME (member)) + 2);
+ if (IDENTIFIER_POINTER (DECL_NAME (member))[2] == '_'
+ && IDENTIFIER_POINTER (DECL_NAME (member))[3] == '.')
+ name = get_identifier ("_");
+ else
+ name = get_identifier (IDENTIFIER_POINTER (DECL_NAME (member)) + 2);
type = lambda_proxy_type (object);
@@ -516,7 +520,7 @@ vla_capture_type (tree array_type)
tree
add_capture (tree lambda, tree id, tree orig_init, bool by_reference_p,
- bool explicit_init_p)
+ bool explicit_init_p, unsigned *placeholder_cnt)
{
char *buf;
tree type, member, name;
@@ -610,11 +614,28 @@ add_capture (tree lambda, tree id, tree
won't find the field with name lookup. We can't just leave the name
unset because template instantiation uses the name to find
instantiated fields. */
- buf = (char *) alloca (IDENTIFIER_LENGTH (id) + 3);
- buf[1] = buf[0] = '_';
- memcpy (buf + 2, IDENTIFIER_POINTER (id),
- IDENTIFIER_LENGTH (id) + 1);
- name = get_identifier (buf);
+ if (id_equal (id, "_") && placeholder_cnt)
+ {
+ if (*placeholder_cnt == 0)
+ name = get_identifier ("___");
+ else
+ {
+ /* For 2nd and later name-independent capture use
+ unique names. */
+ char buf2[5 + (HOST_BITS_PER_INT + 2) / 3];
+ sprintf (buf2, "___.%u", *placeholder_cnt);
+ name = get_identifier (buf2);
+ }
+ placeholder_cnt[0]++;
+ }
+ else
+ {
+ buf = XALLOCAVEC (char, IDENTIFIER_LENGTH (id) + 3);
+ buf[1] = buf[0] = '_';
+ memcpy (buf + 2, IDENTIFIER_POINTER (id),
+ IDENTIFIER_LENGTH (id) + 1);
+ name = get_identifier (buf);
+ }
if (variadic)
{
@@ -718,7 +739,7 @@ add_default_capture (tree lambda_stack,
(this_capture_p
|| (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda)
== CPLD_REFERENCE)),
- /*explicit_init_p=*/false);
+ /*explicit_init_p=*/false, NULL);
initializer = convert_from_reference (var);
/* Warn about deprecated implicit capture of this via [=]. */
@@ -680,6 +680,8 @@ poplevel (int keep, int reverse, int fun
subobjects. */
&& (DECL_DECOMPOSITION_P (decl) ? !DECL_DECOMP_BASE (decl)
: (DECL_NAME (decl) && !DECL_ARTIFICIAL (decl)))
+ /* Don't warn about name-independent declarations. */
+ && !name_independent_decl_p (decl)
&& type != error_mark_node
&& (!CLASS_TYPE_P (type)
|| !TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type)
@@ -6861,8 +6863,17 @@ reshape_init_class (tree type, reshape_i
if (!field || TREE_CODE (field) != FIELD_DECL)
{
if (complain & tf_error)
- error ("%qT has no non-static data member named %qD", type,
- d->cur->index);
+ {
+ if (field && TREE_CODE (field) == TREE_LIST)
+ {
+ error ("request for member %qD is ambiguous",
+ d->cur->index);
+ print_candidates (field);
+ }
+ else
+ error ("%qT has no non-static data member named %qD", type,
+ d->cur->index);
+ }
return error_mark_node;
}
@@ -11343,6 +11343,7 @@ cp_parser_lambda_introducer (cp_parser*
hash_set<tree, true> ids;
tree first_capture_id = NULL_TREE;
+ unsigned placeholder_cnt = 0;
while (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_SQUARE))
{
cp_token* capture_token;
@@ -11387,7 +11388,7 @@ cp_parser_lambda_introducer (cp_parser*
else
add_capture (lambda_expr, /*id=*/this_identifier,
/*initializer=*/finish_this_expr (),
- /*by_reference_p=*/true, explicit_init_p);
+ /*by_reference_p=*/true, explicit_init_p, NULL);
continue;
}
@@ -11409,7 +11410,7 @@ cp_parser_lambda_introducer (cp_parser*
else
add_capture (lambda_expr, /*id=*/this_identifier,
/*initializer=*/finish_this_expr (),
- /*by_reference_p=*/false, explicit_init_p);
+ /*by_reference_p=*/false, explicit_init_p, NULL);
continue;
}
@@ -11596,13 +11597,15 @@ cp_parser_lambda_introducer (cp_parser*
ids.add (first_capture_id);
ids.add (capture_id);
}
+ if (found && explicit_init_p && id_equal (capture_id, "_"))
+ found = false;
if (found)
pedwarn (input_location, 0,
"already captured %qD in lambda expression", capture_id);
else
add_capture (lambda_expr, capture_id, capture_init_expr,
/*by_reference_p=*/capture_kind == BY_REFERENCE,
- explicit_init_p);
+ explicit_init_p, &placeholder_cnt);
/* If there is any qualification still in effect, clear it
now; we will be starting fresh with the next capture. */
@@ -15832,6 +15835,8 @@ cp_parser_decomposition_declaration (cp_
cp_decl_specifier_seq decl_specs;
clear_decl_specs (&decl_specs);
decl_specs.type = make_auto ();
+ if (decl_specifiers->storage_class == sc_static)
+ decl_specs.storage_class = sc_static;
tree prev = decl;
FOR_EACH_VEC_ELT (v, i, e)
{
@@ -20084,7 +20084,7 @@ tsubst_lambda_expr (tree t, tree args, t
&& LAMBDA_EXPR_PENDING_PROXIES (t) == NULL);
vec<tree,va_gc>* field_packs = NULL;
-
+ unsigned placeholder_cnt = 0;
for (tree cap = LAMBDA_EXPR_CAPTURE_LIST (t); cap;
cap = TREE_CHAIN (cap))
{
@@ -20114,7 +20114,8 @@ tsubst_lambda_expr (tree t, tree args, t
bool by_ref = (TYPE_REF_P (ftype)
|| (TREE_CODE (ftype) == DECLTYPE_TYPE
&& DECLTYPE_FOR_REF_CAPTURE (ftype)));
- add_capture (r, name, init, by_ref, !DECL_NORMAL_CAPTURE_P (ofield));
+ add_capture (r, name, init, by_ref, !DECL_NORMAL_CAPTURE_P (ofield),
+ &placeholder_cnt);
continue;
}
@@ -0,0 +1,194 @@
+// P2169R4 - A nice placeholder with no name
+// { dg-do compile { target c++11 } }
+// { dg-options "-Wunused-variable -Wunused-but-set-variable -Wunused-parameter -Wshadow" }
+
+int a[3];
+
+void
+foo ()
+{
+ {
+ int _ = 1;
+ ++_;
+ }
+ {
+ int _ = 3;
+ ++_;
+ int _ = 4; // { dg-warning "placeholder variables only available with" "" { target c++23_down } }
+ }
+ {
+ int _ = 5;
+ --_;
+ int _ = 6; // { dg-warning "placeholder variables only available with" "" { target c++23_down } }
+ int _ = 7; // { dg-warning "placeholder variables only available with" "" { target c++23_down } }
+ }
+ {
+ auto [i, j, _] = a; // { dg-warning "structured bindings only available with" "" { target c++14_down } }
+ ++i;
+ ++_;
+ }
+ {
+ auto [_, _, k] = a; // { dg-warning "placeholder variables only available with" "" { target c++23_down } }
+ ++k; // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ }
+ {
+ auto [i, j, _] = a; // { dg-warning "structured bindings only available with" "" { target c++14_down } }
+ auto [_, k, l] = a; // { dg-warning "placeholder variables only available with" "" { target c++23_down } }
+ ++i; // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ ++l;
+ }
+ {
+ int _;
+ _ = 1;
+ }
+ {
+ int _ = 1;
+ }
+ {
+ int _;
+ }
+ {
+ static int _; // { dg-warning "unused variable" }
+ int _ = 1; // { dg-warning "placeholder variables only available with" "" { target c++23_down } }
+ }
+ {
+ extern int _ (int);
+ extern long _ (long);
+ extern float _ (float);
+ int _ = 1; // { dg-warning "placeholder variables only available with" "" { target c++23_down } }
+ }
+ {
+ extern double _ (double);
+ extern short _ (short);
+ int _ = 1; // { dg-warning "placeholder variables only available with" "" { target c++23_down } }
+ int _ = 2; // { dg-warning "placeholder variables only available with" "" { target c++23_down } }
+ }
+ {
+ int _ = 1;
+ {
+ int _ = 2;
+ ++_;
+ }
+ {
+ static int _ = 3; // { dg-warning "declaration of '_' shadows a previous local" }
+ ++_;
+ }
+ {
+ auto [i, j, _] = a; // { dg-warning "structured bindings only available with" "" { target c++14_down } }
+ ++_;
+ }
+ }
+}
+
+int
+bar (int _ = 0) // { dg-warning "unused parameter '_'" }
+{
+ int _ = 1; // { dg-warning "placeholder variables only available with" "" { target c++23_down } }
+ return 0;
+}
+
+void
+baz ()
+{
+ if (int _ = bar ())
+ int _ = 2; // { dg-warning "placeholder variables only available with" "" { target c++23_down } }
+ else
+ int _ = 3; // { dg-warning "placeholder variables only available with" "" { target c++23_down } }
+ while (int _ = bar ())
+ int _ = 4; // { dg-warning "placeholder variables only available with" "" { target c++23_down } }
+ for (int _ = bar (); _; ++_)
+ int _ = 5; // { dg-warning "placeholder variables only available with" "" { target c++23_down } }
+ if (int _ = bar ())
+ {
+ int _ = 6; // { dg-warning "placeholder variables only available with" "" { target c++23_down } }
+ }
+ else
+ {
+ int _ = 7; // { dg-warning "placeholder variables only available with" "" { target c++23_down } }
+ }
+ while (int _ = bar ())
+ {
+ int _ = 8; // { dg-warning "placeholder variables only available with" "" { target c++23_down } }
+ }
+ for (int _ = bar (); _; ++_)
+ {
+ int _ = 9; // { dg-warning "placeholder variables only available with" "" { target c++23_down } }
+ }
+}
+
+void
+qux (short _ = 0) // { dg-warning "unused parameter '_'" }
+{
+ {
+ long _ = 1;
+ }
+}
+
+void
+corge ()
+{
+ auto b = [_ = 1] () { (void) _; }; // { dg-warning "lambda capture initializers only available with" "" { target c++11_down } }
+ // { dg-warning "variable 'b' set but not used" "" { target *-*-* } .-1 }
+ auto c = [_ = 2, _ = 3] () {};// { dg-warning "placeholder variables only available with" "" { target c++23_down } }
+ // { dg-warning "lambda capture initializers only available with" "" { target c++11_down } .-1 }
+ // { dg-warning "variable 'c' set but not used" "" { target *-*-* } .-2 }
+ {
+ int _ = 4;
+ auto d = [_, _ = 5] () {}; // { dg-warning "placeholder variables only available with" "" { target c++23_down } }
+ } // { dg-warning "lambda capture initializers only available with" "" { target c++11_down } .-1 }
+ // { dg-warning "variable 'd' set but not used" "" { target *-*-* } .-2 }
+ {
+ int _ = 5;
+ auto e = [_ = 6] () {}; // { dg-warning "lambda capture initializers only available with" "" { target c++11_down } }
+ } // { dg-warning "variable 'e' set but not used" "" { target *-*-* } .-1 }
+}
+
+namespace A {
+ int _ = 11;
+}
+
+void
+garply (int x, // { dg-warning "unused parameter 'x'" }
+ int _, // { dg-warning "unused parameter '_'" }
+ int)
+{
+}
+
+void
+fred ()
+{
+ try {
+ } catch (int _) {
+ int _ = 5; // { dg-warning "placeholder variables only available with" "" { target c++23_down } }
+ }
+}
+
+void
+waldo (int _) // { dg-warning "unused parameter '_'" }
+try
+{
+}
+catch (int _) // { dg-warning "placeholder variables only available with" "" { target c++23_down } }
+{
+ int _ = 7;
+}
+
+void
+grault (int _) // { dg-warning "unused parameter '_'" }
+try
+{
+}
+catch (int)
+{
+ int _ = 8; // { dg-warning "placeholder variables only available with" "" { target c++23_down } }
+}
+
+void
+plugh (int _) // { dg-warning "unused parameter '_'" }
+try
+{
+ int _ = 1; // { dg-warning "placeholder variables only available with" "" { target c++23_down } }
+}
+catch (int)
+{
+}
@@ -0,0 +1,171 @@
+// P2169R4 - A nice placeholder with no name
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+int a[3];
+
+void
+foo ()
+{
+ {
+ extern int _ (int);
+ int _ = 2; // { dg-warning "placeholder variables only available with" "" { target c++23_down } }
+ extern long _ (long); // { dg-error "redeclared as different kind of entity" }
+ }
+ {
+ int _ = 3;
+ extern int _ (int); // { dg-error "redeclared as different kind of entity" }
+ }
+ {
+ int _ = 4;
+ static int _ = 5; // { dg-error "redeclaration of 'int _'" }
+ }
+ {
+ int _ = 6;
+ int _ = 7; // { dg-warning "placeholder variables only available with" "" { target c++23_down } }
+ ++_; // { dg-error "reference to '_' is ambiguous" }
+ }
+ {
+ int _ = 8;
+ int _ = 9; // { dg-warning "placeholder variables only available with" "" { target c++23_down } }
+ int _ = 10; // { dg-warning "placeholder variables only available with" "" { target c++23_down } }
+ ++_; // { dg-error "reference to '_' is ambiguous" }
+ }
+ {
+ static int _ = 11;
+ static int _ = 12; // { dg-error "redeclaration of 'int _'" }
+ int _ = 13; // { dg-warning "placeholder variables only available with" "" { target c++23_down } }
+ }
+ {
+ extern int _ (int);
+ extern long _ (long);
+ extern float _ (float);
+ int _ = 1; // { dg-warning "placeholder variables only available with" "" { target c++23_down } }
+ ++_; // { dg-error "reference to '_' is ambiguous" }
+ }
+ {
+ extern double _ (double);
+ extern short _ (short);
+ int _ = 1; // { dg-warning "placeholder variables only available with" "" { target c++23_down } }
+ ++_; // { dg-error "reference to '_' is ambiguous" }
+ int _ = 2; // { dg-warning "placeholder variables only available with" "" { target c++23_down } }
+ ++_; // { dg-error "reference to '_' is ambiguous" }
+ }
+ {
+ auto [i, _, _] = a; // { dg-warning "placeholder variables only available with" "" { target c++23_down } }
+ // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ ++_; // { dg-error "reference to '_' is ambiguous" }
+ }
+ {
+ auto [i, j, _] = a; // { dg-warning "structured bindings only available with" "" { target c++14_down } }
+ auto [k, _, l] = a; // { dg-warning "placeholder variables only available with" "" { target c++23_down } }
+ // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ ++_; // { dg-error "reference to '_' is ambiguous" }
+ }
+ {
+ static auto [i, _, _] = a; // { dg-error "redeclaration of 'auto _'" }
+ // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-2 }
+ }
+}
+
+int
+bar (int _ = 0)
+{
+ int _ = 1; // { dg-warning "placeholder variables only available with" "" { target c++23_down } }
+ ++_; // { dg-error "reference to '_' is ambiguous" }
+ return 0;
+}
+
+void
+baz ()
+{
+ if (int _ = bar ())
+ {
+ int _ = 6; // { dg-warning "placeholder variables only available with" "" { target c++23_down } }
+ ++_; // { dg-error "reference to '_' is ambiguous" }
+ }
+ else
+ {
+ int _ = 7; // { dg-warning "placeholder variables only available with" "" { target c++23_down } }
+ ++_; // { dg-error "reference to '_' is ambiguous" }
+ }
+ while (int _ = bar ())
+ {
+ int _ = 8; // { dg-warning "placeholder variables only available with" "" { target c++23_down } }
+ ++_; // { dg-error "reference to '_' is ambiguous" }
+ }
+ for (int _ = bar (); _; ++_)
+ {
+ int _ = 9; // { dg-warning "placeholder variables only available with" "" { target c++23_down } }
+ ++_; // { dg-error "reference to '_' is ambiguous" }
+ }
+}
+
+namespace A
+{
+ int _ = 1;
+ int _ = 1; // { dg-error "redefinition of 'int A::_'" }
+}
+
+namespace B
+{
+ auto [_, _, _] = a; // { dg-error "redefinition of 'auto B::_'" }
+ // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+}
+
+void
+qux ()
+{
+ auto c = [_ = 2, _ = 3] () { // { dg-warning "placeholder variables only available with" "" { target c++23_down } }
+ // { dg-warning "lambda capture initializers only available with" "" { target c++11_down } .-1 }
+ (void) _; // { dg-error "reference to '_' is ambiguous" }
+ };
+ {
+ int _ = 4;
+ auto d = [_, _ = 5] () { // { dg-warning "placeholder variables only available with" "" { target c++23_down } }
+ // { dg-warning "lambda capture initializers only available with" "" { target c++11_down } .-1 }
+ (void) _; // { dg-error "reference to '_' is ambiguous" }
+ };
+ }
+ auto e = [_ = 1] (int _) {}; // { dg-warning "lambda capture initializers only available with" "" { target c++11_down } }
+} // { dg-error "lambda parameter '_' previously declared as a capture" "" { target *-*-* } .-1 }
+
+void
+corge (int _, int _) // { dg-error "redefinition of 'int _'" }
+{
+}
+
+namespace C
+{
+ typedef int _;
+ typedef int _;
+}
+
+namespace D
+{
+ namespace {
+ int _;
+ int _; // { dg-error "redefinition of 'int D::.anonymous.::_'" }
+ }
+}
+
+namespace E
+{
+ int _ (int);
+ int _ (int);
+ int _ (int) { return 0; }
+ int _ (int) { return 0; } // { dg-error "redefinition of 'int E::_\\\(int\\\)'" }
+ long _ (long) { return 1; }
+}
+
+template <int _, int _> // { dg-error "redefinition of 'int _'" }
+void
+garply ()
+{
+}
+
+#if __cpp_concepts >= 202002L
+template <typename T>
+concept F = requires (T _, T _) { T{}; }; // { dg-error "redefinition of 'T _'" "" { target c++20 } }
+#endif
@@ -0,0 +1,12 @@
+// P2169R4 - A nice placeholder with no name
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+void
+foo ()
+{
+ extern int _;
+ extern int _;
+ ++_;
+ int _; // { dg-warning "placeholder variables only available with" "" { target c++23_down } }
+}
@@ -0,0 +1,12 @@
+// P2169R4 - A nice placeholder with no name
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+void
+foo ()
+{
+ extern int _;
+ extern int _;
+ int _; // { dg-warning "placeholder variables only available with" "" { target c++23_down } }
+ ++_; // { dg-error "reference to '_' is ambiguous" }
+}
@@ -0,0 +1,92 @@
+// P2169R4 - A nice placeholder with no name
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+struct S {
+ int _;
+ int _; // { dg-warning "placeholder variables only available with" "" { target c++23_down } }
+};
+S s = { 1, 2 };
+
+struct T {
+ int _ = 3;
+ int _ = 4; // { dg-warning "placeholder variables only available with" "" { target c++23_down } }
+};
+T t1;
+#if __cplusplus >= 201402L
+T t2 = { 5, 6 };
+#endif
+
+struct U {
+ int _ (int) { return 1; }
+ long _ (long) { return 2; }
+ int _; // { dg-warning "placeholder variables only available with" "" { target c++23_down } }
+};
+U u = { 7 };
+
+struct V {
+ static int _;
+ int _; // { dg-warning "placeholder variables only available with" "" { target c++23_down } }
+};
+V v = { 8 };
+
+struct W : public S, T { int _; };
+struct X : public S, T {
+ int _;
+ int _; // { dg-warning "placeholder variables only available with" "" { target c++23_down } }
+};
+
+struct Y {
+ int _;
+ int &foo () { return _; }
+};
+
+struct Z : public Y {
+ int _;
+ int bar ();
+};
+
+int
+Z::bar ()
+{
+ return _ + Y::_;
+}
+
+struct A {
+ int _;
+ void foo () {
+ int _;
+ _ = 42;
+ _ += ({ int _ = 0; _; });
+ }
+};
+
+struct B {
+ union { int _; };
+ void foo () { ++_; };
+};
+
+struct C {
+ int _;
+ union { int x; };
+ void foo () { ++_; };
+};
+
+struct D {
+ struct { int _; };
+ void foo () { ++_; };
+};
+
+struct E {
+ struct _ {};
+ int _;
+ void foo () { ++_; int _; _ = 5; }
+};
+typedef struct E::_ E_;
+
+struct F {
+ struct _ {};
+ int _;
+ int _; // { dg-warning "placeholder variables only available with" "" { target c++23_down } }
+};
+typedef struct F::_ F_;
@@ -0,0 +1,135 @@
+// P2169R4 - A nice placeholder with no name
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+struct S {
+ int _;
+ int _; // { dg-warning "placeholder variables only available with" "" { target c++23_down } }
+ int foo ();
+ S () : _ (1) {} // { dg-error "request for member '_' is ambiguous" }
+ void bar () { ++_; } // { dg-error "reference to '_' is ambiguous" }
+};
+
+int
+S::foo ()
+{
+ int x = _; // { dg-error "reference to '_' is ambiguous" }
+ x += S::_; // { dg-error "reference to '_' is ambiguous" }
+ return x;
+}
+
+struct T {
+ int _;
+ int _; // { dg-warning "placeholder variables only available with" "" { target c++23_down } }
+};
+T t = { ._ = 1 }; // { dg-error "request for member '_' is ambiguous" }
+
+auto o = __builtin_offsetof (T, _); // { dg-error "request for member '_' is ambiguous" }
+int T::* p = &T::_; // { dg-error "reference to '_' is ambiguous" }
+
+struct U {
+ U () : _ (42) {} // { dg-error "request for member '_' is ambiguous" }
+ int _;
+ int _; // { dg-warning "placeholder variables only available with" "" { target c++23_down } }
+};
+
+struct V {
+ V ();
+ int _;
+ int _; // { dg-warning "placeholder variables only available with" "" { target c++23_down } }
+};
+
+V::V () : _(42) // { dg-error "request for member '_' is ambiguous" }
+{
+}
+
+struct A {
+ int _;
+ union { int _; }; // { dg-warning "placeholder variables only available with" "" { target c++23_down } }
+ A() : _(42) {} // { dg-error "request for member '_' is ambiguous" }
+};
+
+struct B {
+ union { int _, _; }; // { dg-warning "placeholder variables only available with" "" { target c++23_down } }
+ union { int _, _; }; // { dg-warning "placeholder variables only available with" "" { target c++23_down } }
+ B() : _(42) {} // { dg-error "request for member '_' is ambiguous" }
+};
+
+void
+bar ()
+{
+ union { int _;
+ int _; }; // { dg-warning "placeholder variables only available with" "" { target c++23_down } }
+ _ = 42; // { dg-error "reference to '_' is ambiguous" }
+}
+
+namespace C
+{
+ static union { int _ = 1; };
+ static union { int _ = 2; }; // { dg-error "redeclaration of 'int _'" }
+}
+
+void
+baz ()
+{
+ static union { int _ = 3; };
+ static union { int _ = 4; }; // { dg-error "redeclaration of 'int _'" }
+}
+
+struct D {
+ int _;
+ int _; // { dg-warning "placeholder variables only available with" "" { target c++23_down } }
+};
+
+struct E : public D {};
+
+void
+qux ()
+{
+ D {}._; // { dg-error "request for member '_' is ambiguous" }
+ E {}._; // { dg-error "request for member '_' is ambiguous" }
+}
+
+struct F {
+ struct _ {};
+ int _;
+ int _; // { dg-warning "placeholder variables only available with" "" { target c++23_down } }
+ void foo () { ++_; } // { dg-error "reference to '_' is ambiguous" }
+ void bar ();
+};
+typedef struct F::_ F_;
+
+void
+F::bar ()
+{
+ ++_; // { dg-error "reference to '_' is ambiguous" }
+}
+
+struct G {
+ int _ (int) { return 1; }
+ int _; // { dg-warning "placeholder variables only available with" "" { target c++23_down } }
+ void foo () { ++_; } // { dg-error "reference to '_' is ambiguous" }
+ void bar ();
+};
+
+void
+G::bar ()
+{
+ ++_; // { dg-error "reference to '_' is ambiguous" }
+ this->_ (0); // { dg-error "request for member '_' is ambiguous" }
+}
+
+struct H {
+ int _ (int) { return 1; }
+ long _ (float) { return 2; }
+ int _; // { dg-warning "placeholder variables only available with" "" { target c++23_down } }
+ void foo () { ++_; } // { dg-error "reference to '_' is ambiguous" }
+ void bar ();
+};
+
+void
+H::bar ()
+{
+ ++_; // { dg-error "reference to '_' is ambiguous" }
+ this->_ (0); // { dg-error "request for member '_' is ambiguous" }
+}
@@ -584,7 +584,7 @@
# error "__cpp_auto_cast != 202110"
#endif
-// C++23 attributes:
+// C++23 attributes:
#ifdef __has_cpp_attribute
# if ! __has_cpp_attribute(assume)
@@ -595,3 +595,11 @@
#else
# error "__has_cpp_attribute"
#endif
+
+// C++26 features:
+
+#ifndef __cpp_placeholder_variables
+# error "__cpp_placeholder_variables"
+#elif __cpp_placeholder_variables != 202306
+# error "__cpp_placeholder_variables != 202306"
+#endif