This feature allows the programmer to import enumerator names into the current scope so later mentions don't need to use the fully-qualified name. These usings are not subject to the usual restrictions on using-decls: in particular, they can move between class and non-class scopes, and between classes that are not related by inheritance. This last caused difficulty for our normal approach to using-decls within a class hierarchy, as we assume that the class where we looked up a used declaration is derived from the class where it was first declared. So to simplify things, in that case we make a clone of the CONST_DECL in the using class. Thanks to Nathan for the start of this work: in particular, the lookup_using_decl rewrite. The changes to dwarf2out revealed an existing issue with the D front-end: we were doing the wrong thing for importing a D CONST_DECL, because dwarf2out_imported_module_or_decl_1 was looking through it to its type, expecting it to be an enumerator, but in one case in thread.d, the constant had type int. Adding the ability to import a C++ enumerator also fixed that, but that led to a crash in force_decl_die, which didn't know what to do with a CONST_DECL. So now it does. Co-authored-by: Nathan Sidwell <nathan@acm.org> gcc/cp/ChangeLog: * cp-tree.h (USING_DECL_UNRELATED_P): New. (CONST_DECL_USING_P): New. * class.c (handle_using_decl): If USING_DECL_UNRELATED_P, clone the CONST_DECL. * name-lookup.c (supplement_binding_1): A clone hides its using-declaration. (lookup_using_decl): Rewrite to separate lookup and validation. (do_class_using_decl): Adjust. (finish_nonmember_using_decl): Adjust. * parser.c (make_location): Add cp_token overload. (finish_using_decl): Split out from... (cp_parser_using_declaration): ...here. Don't look through enums. (cp_parser_using_enum): New. (cp_parser_block_declaration): Call it. (cp_parser_member_declaration): Call it. * semantics.c (finish_id_expression_1): Handle enumerator used from class scope. gcc/ChangeLog: * dwarf2out.c (gen_enumeration_type_die): Call equate_decl_number_to_die for enumerators. (gen_member_die): Don't move enumerators to their enclosing class. (dwarf2out_imported_module_or_decl_1): Allow importing individual enumerators. (force_decl_die): Handle CONST_DECL. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/inh-ctor28.C: Adjust expected diagnostic. * g++.dg/cpp0x/inh-ctor33.C: Likewise. * g++.dg/cpp0x/using-enum-1.C: Add comment. * g++.dg/cpp0x/using-enum-2.C: Allowed in C++20. * g++.dg/cpp0x/using-enum-3.C: Likewise. * g++.dg/cpp1z/class-deduction69.C: Adjust diagnostic. * g++.dg/inherit/using5.C: Likewise. * g++.dg/cpp2a/using-enum-1.C: New test. * g++.dg/cpp2a/using-enum-2.C: New test. * g++.dg/cpp2a/using-enum-3.C: New test. * g++.dg/cpp2a/using-enum-4.C: New test. * g++.dg/cpp2a/using-enum-5.C: New test. * g++.dg/cpp2a/using-enum-6.C: New test. * g++.dg/debug/dwarf2/using-enum.C: New test.
133 lines
2.9 KiB
C
133 lines
2.9 KiB
C
// Examples from P1099R5
|
|
// { dg-do compile { target c++20 } }
|
|
|
|
namespace my_lib {
|
|
|
|
enum class errcode
|
|
{
|
|
SUCCESS = 0,
|
|
ENOMEM = 1,
|
|
EAGAIN = 2,
|
|
ETOOSLOW = 3
|
|
};
|
|
using enum errcode; // import enumerators into namespace
|
|
}
|
|
|
|
namespace NS {
|
|
my_lib::errcode get_widget() {
|
|
using namespace my_lib;
|
|
return ETOOSLOW; // works, and conversions to int don't.
|
|
int i = ETOOSLOW; // { dg-error "" }
|
|
}
|
|
}
|
|
|
|
enum class rgba_color_channel { red, green, blue, alpha};
|
|
|
|
const char * to_string(rgba_color_channel channel) {
|
|
switch (channel) {
|
|
using enum rgba_color_channel;
|
|
case red: return "red";
|
|
case green: return "green";
|
|
case blue: return "blue";
|
|
case alpha: return "alpha";
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
namespace ns {
|
|
struct E_detail {
|
|
enum E { e1, e2 };
|
|
friend void swap(E&, E&); // adl-only swap in the only associated scope of the enum
|
|
};
|
|
using E = E_detail::E; // import E into ns
|
|
using enum E; // expose the enumerators of E in ns. Also note the direct reference to E.
|
|
}
|
|
|
|
int main() {
|
|
auto x = ns::e1;
|
|
auto y = ns::e2;
|
|
swap(x, y); // finds the swap in the associated struct
|
|
}
|
|
|
|
namespace N0 {
|
|
enum E { x };
|
|
struct S {
|
|
enum H { y };
|
|
enum class K { z };
|
|
using E::x; // OK, introduces x into S
|
|
using E::x; // { dg-error "" } redeclaration in class scope
|
|
using H::y; // { dg-error "" } redeclaration in class scope
|
|
using K::z; // OK, introduces z into S
|
|
};
|
|
namespace NS {
|
|
enum H { y };
|
|
enum class K { z };
|
|
using E::x; // OK, introduces x into NS
|
|
using E::x; // OK, just a redeclaration of the same entity
|
|
using H::y; // OK, redeclaration of the same entity
|
|
using K::z; // OK, introduces z into NS
|
|
};
|
|
}
|
|
namespace N1 {
|
|
struct S {
|
|
enum E { x };
|
|
enum class EC { y };
|
|
using EC::y;
|
|
};
|
|
|
|
void f() {
|
|
using S::x; // OK
|
|
x; // resolves to S::E::x;
|
|
using S::y; // OK
|
|
y; // resolves to S::EC::y;
|
|
}
|
|
}
|
|
|
|
namespace N2 {
|
|
enum class E { a, b, c };
|
|
using E::a, E::b, E::c; // OK, imports all three
|
|
auto x = (a,b,c);
|
|
}
|
|
|
|
namespace N3 {
|
|
struct B {
|
|
enum class E { x };
|
|
};
|
|
enum class H { y };
|
|
struct C : B {
|
|
using enum B::E; // OK, introduces E::x into C
|
|
using enum H; // OK, introduces y into C. Does not introduce H
|
|
};
|
|
auto i = C::y; // OK
|
|
C::H h; // { dg-error "" }
|
|
}
|
|
|
|
namespace N4 {
|
|
enum class button { up, down };
|
|
struct S {
|
|
using button::up;
|
|
button b = up; // OK
|
|
};
|
|
}
|
|
|
|
namespace N5 {
|
|
enum class fruit { orange, apple };
|
|
struct S {
|
|
using enum fruit; // OK, introduces orange and apple into S
|
|
};
|
|
void f() {
|
|
S s;
|
|
s.orange; // OK, names fruit::orange
|
|
S::orange; // OK, names fruit::orange
|
|
}
|
|
}
|
|
|
|
namespace N6 {
|
|
enum class fruit { orange, apple };
|
|
enum class color { red, orange };
|
|
void f() {
|
|
using enum fruit; // OK
|
|
using enum color; // { dg-error "" } color::orange and fruit::orange conflict
|
|
}
|
|
}
|