Files
clang-p2996/clang/test/SemaCXX/cxx20-using-enum.cpp
Vlad Serebrennikov bc4d50f02d [clang] Implement CWG2877 "Type-only lookup for using-enum-declarator" (#95399)
This patch implements 2024-05-31 resolution of a tentatively ready issue
[CWG2877](https://cplusplus.github.io/CWG/issues/2877.html) "Type-only
lookup for using-enum-declarator", which supersedes earlier
[CWG2621](https://cplusplus.github.io/CWG/issues/2621.html) "Kind of
lookup for `using enum` declarations".

Now we perform type-only lookup (not to be confused with type-only
context) for `elaborated-enum-declarator`. This is the same kind of
lookup that elaborated type specifiers and base specifiers undergo.

I also found out (and fixed) that one of our existing tests claimed that
a dependent type can be used in `elaborated-enum-declarator`, but that's
not the case:
> The
[using-enum-declarator](http://eel.is/c++draft/enum.udecl#nt:using-enum-declarator)
shall designate a non-dependent type with a reachable
[enum-specifier](http://eel.is/c++draft/dcl.enum#nt:enum-specifier)[.](http://eel.is/c++draft/enum.udecl#1.sentence-2)
2024-06-21 13:49:43 +04:00

278 lines
5.0 KiB
C++

// RUN: %clang_cc1 -fsyntax-only -std=c++17 -verify %s
// RUN: %clang_cc1 -fsyntax-only -std=c++17 -verify %s -fexperimental-new-constant-interpreter
// RUN: %clang_cc1 -fsyntax-only -std=c++20 -verify %s -fexperimental-new-constant-interpreter
// p1099 'using enum ELABORATED-ENUM-SPECIFIER ;'
namespace One {
namespace Bob {
enum A { a, // expected-note{{declared here}}
b,
c };
class C;
enum class D : int;
enum class D { d,
e,
f };
enum class D : int;
} // namespace Bob
using enum Bob::A;
#if __cplusplus < 202002
// expected-warning@-2{{is a C++20 extension}}
#endif
using enum Bob::B; // expected-error{{unknown type name B}}
#if __cplusplus < 202002
// expected-warning@-2{{is a C++20 extension}}
#endif
using enum Bob::C; // expected-error{{'Bob::C' is not an enumerated type}}
#if __cplusplus < 202002
// expected-warning@-2{{is a C++20 extension}}
#endif
auto v = a;
A g; // expected-error{{unknown type name 'A'}}
int A;
using enum Bob::D;
#if __cplusplus < 202002
// expected-warning@-2{{is a C++20 extension}}
#endif
void DR2621() {
using A_t = Bob::A;
using enum A_t;
#if __cplusplus < 202002
// expected-warning@-2{{is a C++20 extension}}
#endif
A_t x = a;
}
} // namespace One
namespace Two {
namespace Kevin {
enum class B { d,
e,
f };
}
using enum Kevin::B;
#if __cplusplus < 202002
// expected-warning@-2{{is a C++20 extension}}
#endif
auto w = e;
} // namespace Two
#if __cplusplus >= 202002
// Now only check c++20 onwards
namespace Three {
namespace Stuart {
enum class C : int; // expected-note{{declared here}}
}
using enum Stuart::C; // expected-error{{is incomplete}}
} // namespace Three
namespace Four {
class Dave {
public:
enum D { a,
b,
c };
private:
enum class E { d, // expected-note{{declared private here}}
e,
f };
};
using enum Dave::D;
using enum Dave::E; // expected-error{{is a private member}}
} // namespace Four
namespace Five {
enum class A { b,
c };
class Dave {
public:
using enum A;
A f = b;
};
} // namespace Five
namespace Six {
template <typename T> class TPL;
template <> class TPL<int> {
public:
enum A { a };
};
template <typename T> class USR {
using enum TPL<T>::B; // expected-error{{cannot name a dependent type}}
using enum TPL<int>::A;
};
} // namespace Six
// Now instantiate things
namespace Seven {
namespace Stuart {
enum class A { a,
b,
c };
}
static_assert(!int(Stuart::A::a));
constexpr int Bar() {
using enum Stuart::A;
return int(b);
}
static_assert(Bar() == 1);
template <int I> constexpr int Foo() {
using enum Stuart::A;
return int(b) + I;
}
static_assert(Foo<10>() == 11);
template <int I> struct C {
using enum Stuart::A;
static constexpr int V = int(c) + I;
enum class D { d,
e,
f };
using enum D; // expected-error {{using-enum cannot name a dependent type}}
};
static_assert(C<2>::V == 4);
} // namespace Seven
namespace Eight {
enum class Bob : int {};
using enum Bob;
} // namespace Eight
namespace Nine {
template <int I> struct C {
enum class D { i = I };
enum class E : int; // expected-note{{declared here}}
};
using enum C<2>::D;
constexpr auto d = i;
static_assert(unsigned(d) == 2);
using enum C<2>::E; // expected-error{{instantiation of undefined member}}
} // namespace Nine
namespace Ten {
enum class Bob { a };
void Foo() {
extern void a();
}
// We don't see the hidden extern a fn!
using enum Bob;
auto v = a;
} // namespace Ten
namespace Eleven {
enum class Bob { a }; // expected-note{{conflicting declaration}}
struct Base {
enum { a }; // expected-note{{target of using}}
};
template <typename B>
class TPLa : B {
using enum Bob;
using B::a; // expected-error{{target of using declaration}}
};
TPLa<Base> a; // expected-note{{in instantiation}}
} // namespace Eleven
namespace Twelve {
enum class Bob { a }; // expected-note{{target of using}}
struct Base {
enum { a };
};
template <typename B>
class TPLb : B {
using B::a; // expected-note{{conflicting declaration}}
using enum Bob; // expected-error{{target of using declaration}}
};
TPLb<Base> b;
} // namespace Twelve
namespace Thirteen {
enum class Bob { a };
class Foo {
using enum Bob; // expected-note{{previous using-enum}}
using enum Bob; // expected-error{{redeclaration of using-enum}}
};
template <typename B>
class TPLa {
using enum Bob; // expected-note{{previous using-enum}}
using enum Bob; // expected-error{{redeclaration of using-enum}}
};
TPLa<int> a;
} // namespace Thirteen
namespace Fourteen {
template<typename T>
int A = T();
using enum A<int>; // expected-error {{A is not an enumerated type}}
} // namespace Fourteen
namespace GH58057 {
struct Wrap {
enum Things {
Value1,
Value2
};
};
using enum Wrap::Things;
int f() {
return (Value1 | Value2);
}
}
namespace GH59014 {
struct X {
enum Masks {Mask = 1,Shift = 0};
};
void f(int a) {
using enum X::Masks;
auto u = (Mask);
auto v = (Mask << Shift);
void (~(Mask));
}
}
#endif