/* Nonzero if NODE, a TYPE, has no name for linkage purposes. */
#define TYPE_UNNAMED_P(NODE) \
(TYPE_ANON_P (NODE) \
- && !IDENTIFIER_LAMBDA_P (TYPE_LINKAGE_IDENTIFIER (NODE)))
+ && !IDENTIFIER_LAMBDA_P (TYPE_LINKAGE_IDENTIFIER (NODE)) \
+ && !enum_with_enumerator_for_linkage_p (NODE))
/* The _DECL for this _TYPE. */
#define TYPE_MAIN_DECL(NODE) (TYPE_STUB_DECL (TYPE_MAIN_VARIANT (NODE)))
bool tpl_header_p = false);
extern void xref_basetypes (tree, tree);
extern tree start_enum (tree, tree, tree, tree, bool, bool *);
+extern bool enum_with_enumerator_for_linkage_p (tree);
extern void finish_enum_value_list (tree);
extern void finish_enum (tree);
extern tree build_enumerator (tree, tree, tree, tree, location_t);
void
name_unnamed_type (tree type, tree decl)
{
- gcc_assert (TYPE_UNNAMED_P (type));
+ gcc_assert (TYPE_UNNAMED_P (type)
+ || enum_with_enumerator_for_linkage_p (type));
/* Replace the anonymous decl with the real decl. Be careful not to
rename other typedefs (such as the self-reference) of type. */
/* Check that our job is done, and that it would fail if we
attempted to do it again. */
- gcc_assert (!TYPE_UNNAMED_P (type));
+ gcc_assert (!TYPE_UNNAMED_P (type)
+ && !enum_with_enumerator_for_linkage_p (type));
}
/* Check that decltype(auto) was well-formed: only plain decltype(auto)
&& unqualified_id
&& TYPE_NAME (type)
&& TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
- && TYPE_UNNAMED_P (type)
+ && (TYPE_UNNAMED_P (type)
+ /* An enum may have previously used an enumerator for linkage
+ purposes, but we want the typedef name to take priority. */
+ || enum_with_enumerator_for_linkage_p (type))
&& declspecs->type_definition_p
&& attributes_naming_typedef_ok (*attrlist)
&& cp_type_quals (type) == TYPE_UNQUALIFIED)
return enumtype;
}
+/* Returns true if TYPE is an enum that uses an enumerator name for
+ linkage purposes. */
+
+bool
+enum_with_enumerator_for_linkage_p (tree type)
+{
+ return (cxx_dialect >= cxx20
+ && UNSCOPED_ENUM_P (type)
+ && TYPE_ANON_P (type)
+ && TYPE_VALUES (type));
+}
+
/* After processing and defining all the values of an enumeration type,
install their decls in the enumeration type.
ENUMTYPE is the type object. */
fixup_type_variants (current_class_type);
}
+ /* P2115: An unnamed enum uses the name of its first enumerator for
+ linkage purposes; reset the type linkage if that is the case. */
+ if (enum_with_enumerator_for_linkage_p (enumtype))
+ reset_type_linkage (enumtype);
+
/* Finish debugging output for this type. */
rest_of_type_compilation (enumtype, namespace_bindings_p ());
static void write_source_name (tree);
static void write_literal_operator_name (tree);
static void write_unnamed_type_name (const tree);
+static void write_unnamed_enum_name (const tree);
static void write_closure_type_name (const tree);
static int hwint_to_ascii (unsigned HOST_WIDE_INT, const unsigned int, char *,
const unsigned int);
tree type = TREE_TYPE (decl);
if (TREE_CODE (decl) == TYPE_DECL
- && TYPE_UNNAMED_P (type))
+ && enum_with_enumerator_for_linkage_p (type))
+ write_unnamed_enum_name (type);
+ else if (TREE_CODE (decl) == TYPE_DECL && TYPE_UNNAMED_P (type))
write_unnamed_type_name (type);
else if (TREE_CODE (decl) == TYPE_DECL && LAMBDA_TYPE_P (type))
write_closure_type_name (type);
write_compact_number (discriminator);
}
+/* <unnamed-enum-name> ::= Ue <underlying type> <enumerator source-name> */
+
+static void
+write_unnamed_enum_name (const tree type)
+{
+ MANGLE_TRACE_TREE ("unnamed-enum-name", type);
+ write_string ("Ue");
+ write_type (ENUM_UNDERLYING_TYPE (type));
+ write_source_name (DECL_NAME (TREE_VALUE (TYPE_VALUES (type))));
+}
+
/* ABI issue #47: if a function template parameter is not "natural" for its
argument we must mangle the parameter. */
if (NAMESPACE_SCOPE_P (decl)
&& (!DECL_NAME (decl) || IDENTIFIER_ANON_P (DECL_NAME (decl))))
{
- if (TREE_CODE (decl) == TYPE_DECL && !TYPE_ANON_P (TREE_TYPE (decl)))
- /* This entity has a typedef name for linkage purposes. */;
+ if (TREE_CODE (decl) == TYPE_DECL && !TYPE_UNNAMED_P (TREE_TYPE (decl)))
+ /* This entity has a name for linkage purposes. */;
else if (DECL_DECOMPOSITION_P (decl) && DECL_DECOMP_IS_BASE (decl))
/* Namespace-scope structured bindings can have linkage. */;
else if (TREE_CODE (decl) == NAMESPACE_DECL && cxx_dialect >= cxx11)
struct C
{
typedef struct { }* D;
- typedef enum { e }* E;
+ typedef enum { }* E;
};
// { dg-final { scan-assembler "_Z2g1PN1CUt_E" } }
inline void j()
{
- typedef enum { f }* F;
+ typedef enum { }* F;
// { dg-final { scan-assembler "_Z2h1IPZ1jvEUt_EvT_" } }
h1(F());
typedef struct { }* G;
--- /dev/null
+// PR c++/120503
+// Implement P2115r0 "merging definitions of unnamed unscoped enums"
+// { dg-do compile { target c++14 } }
+
+template<auto V> int Frob () { return int (V); }
+
+enum { A = (unsigned int)12345, B = 0 };
+template int Frob<A> ();
+template int Frob<B> ();
+// { dg-final { scan-assembler {_Z4FrobITnDaLUej1A12345EEiv:} { target c++20 } } }
+// { dg-final { scan-assembler {_Z4FrobITnDaL8._anon_012345EEiv:} { target c++17_down } } }
+// { dg-final { scan-assembler {_Z4FrobITnDaLUej1A0EEiv:} { target c++20 } } }
+// { dg-final { scan-assembler {_Z4FrobITnDaL8._anon_00EEiv:} { target c++17_down } } }
+
+enum { C = 5 } typedef X;
+template int Frob<C> ();
+// typedef name 'X' should take precedence
+// { dg-final { scan-assembler {_Z4FrobITnDaL1X5EEiv:} } }
+
+typedef enum : long long { D = 8 }* Y;
+template int Frob<D> ();
+// but 'Y' is not a typedef name here
+// { dg-final { scan-assembler {_Z4FrobITnDaLUex1D8EEiv:} { target c++20 } } }
+// { dg-final { scan-assembler {_Z4FrobITnDaL8._anon_28EEiv:} { target c++17_down } } }
+
+enum : int { E };
+void foo(decltype(E), decltype(E)) {}
+// { dg-final { scan-assembler {_Z3fooUei1ES_:} { target c++20 } } }
+// { dg-final { scan-assembler {_Z3foo8._anon_3S_:} { target c++17_down } } }
template <typename T> T B<T>::t2 = { };
-enum { E1 } e1; // OK, defined
-extern enum { E2 } e2; // { dg-error "never defined" }
-extern "C" enum { E3 } e3; // OK, extern "C"
+enum { } e1; // OK, defined
+extern enum { } e2; // { dg-error "never defined" }
+extern "C" enum { } e3; // OK, extern "C"
void f() {
struct A { int x; }; // no linkage
// gets internal linkage.
// { dg-options "-mmmx" { target { { i?86-*-* x86_64-*-* } && ilp32 } } } */
-typedef enum { e } T __attribute__((vector_size(8)));
+typedef enum { } T __attribute__((vector_size(8)));
static void foo(T t) {}
void bar (T t) {} // { dg-error "no linkage" "" { target { ! c++11 } } }
// { dg-final { scan-assembler-not "globl\[ \t]*_Z3bar" { target c++11 } } }
--- /dev/null
+// PR c++/120824
+// { dg-additional-options "-fmodules -Wno-global-module -std=c++20" }
+// { dg-module-cmi M }
+
+module;
+enum { E };
+enum { F };
+export module M;
+export using ::E;
+export using ::F;
--- /dev/null
+// PR c++/120824
+// { dg-additional-options "-fmodules -Wno-global-module -std=c++20" }
+// { dg-module-cmi !bad }
+
+module;
+enum { E };
+namespace {
+ enum { G }; // { dg-message "internal" }
+}
+export module bad;
+import M;
+inline void ok() {
+ auto a = E;
+ auto b = F;
+}
+inline void err() { // { dg-error "TU-local" }
+ auto c = G;
+}
// { dg-do compile }
-enum { a = 3 } x; // { dg-warning "unnamed type" "" { target { ! c++11 } } }
+enum { } x; // { dg-warning "unnamed type" "" { target { ! c++11 } } }
DEMANGLE_COMPONENT_DEFAULT_ARG,
/* An unnamed type. */
DEMANGLE_COMPONENT_UNNAMED_TYPE,
+ /* An unnamed enum. */
+ DEMANGLE_COMPONENT_UNNAMED_ENUM,
/* A transactional clone. This has one subtree, the encoding for
which it is providing alternative linkage. */
DEMANGLE_COMPONENT_TRANSACTION_CLONE,
static struct demangle_component *d_unnamed_type (struct d_info *);
+static struct demangle_component *d_unnamed_enum (struct d_info *);
+
static struct demangle_component *
d_clone_suffix (struct d_info *, struct demangle_component *);
{
switch (d_peek_next_char (di))
{
+ case 'e':
+ ret = d_unnamed_enum (di);
+ break;
case 'l':
ret = d_lambda (di);
break;
break;
case 'U':
- d_advance (di, 1);
- ret = d_source_name (di);
- if (d_peek_char (di) == 'I')
- ret = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, ret,
- d_template_args (di));
- ret = d_make_comp (di, DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL,
- cplus_demangle_type (di), ret);
+ peek = d_peek_next_char (di);
+ if (IS_DIGIT (peek))
+ {
+ d_advance (di, 1);
+ ret = d_source_name (di);
+ if (d_peek_char (di) == 'I')
+ ret = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, ret,
+ d_template_args (di));
+ ret = d_make_comp (di, DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL,
+ cplus_demangle_type (di), ret);
+ }
+ else
+ /* Could be a closure type or an unnamed enum. */
+ ret = d_unqualified_name (di, NULL, NULL);
break;
case 'D':
return ret;
}
+/* <unnamed-enum-name> ::= Ue <underlying type> <enumerator source-name> */
+
+static struct demangle_component *
+d_unnamed_enum (struct d_info *di)
+{
+ if (! d_check_char (di, 'U'))
+ return NULL;
+ if (! d_check_char (di, 'e'))
+ return NULL;
+
+ struct demangle_component *underlying = cplus_demangle_type (di);
+ struct demangle_component *name = d_source_name (di);
+
+ struct demangle_component *ret = d_make_empty (di);
+ if (ret)
+ {
+ ret->type = DEMANGLE_COMPONENT_UNNAMED_ENUM;
+ d_left (ret) = underlying;
+ d_right (ret) = name;
+ }
+
+ if (! d_add_substitution (di, ret))
+ return NULL;
+
+ return ret;
+}
+
/* <clone-suffix> ::= [ . <clone-type-identifier> ] [ . <nonnegative number> ]*
*/
case DEMANGLE_COMPONENT_CHARACTER:
case DEMANGLE_COMPONENT_NUMBER:
case DEMANGLE_COMPONENT_UNNAMED_TYPE:
+ case DEMANGLE_COMPONENT_UNNAMED_ENUM:
case DEMANGLE_COMPONENT_STRUCTURED_BINDING:
case DEMANGLE_COMPONENT_MODULE_NAME:
case DEMANGLE_COMPONENT_MODULE_PARTITION:
case DEMANGLE_COMPONENT_CHARACTER:
case DEMANGLE_COMPONENT_FUNCTION_PARAM:
case DEMANGLE_COMPONENT_UNNAMED_TYPE:
+ case DEMANGLE_COMPONENT_UNNAMED_ENUM:
case DEMANGLE_COMPONENT_DEFAULT_ARG:
case DEMANGLE_COMPONENT_NUMBER:
return NULL;
d_append_char (dpi, '}');
return;
+ case DEMANGLE_COMPONENT_UNNAMED_ENUM:
+ d_append_string (dpi, "{enum:");
+ d_print_comp (dpi, options, d_left (dc));
+ d_append_string (dpi, "{");
+ d_print_comp (dpi, options, d_right (dc));
+ d_append_string (dpi, "}}");
+ return;
+
case DEMANGLE_COMPONENT_CLONE:
d_print_comp (dpi, options, d_left (dc));
d_append_string (dpi, " [clone ");
_ZNH1S3bazERKS_
S::baz(this S const&)
+
+_Z3fooUlvE_
+foo({lambda()#1})
+
+# P2115R0 unnamed enums
+_Z3fooUei1ES_
+foo({enum:int{E}}, {enum:int{E}})