Yanzuo Liu 7a3e555353
[Clang][Sema] Require BaseClass:: (not other classes) in member using-declaration in C++98 mode (#143492)
[CWG400](https://wg21.link/cwg400) rejects member using-declaration
whose nested-name-specifier doesn't refer to a base class of the current
class.

```cpp
struct A {};
struct B {
  using B::A; // error
};
```

Clang didn't reject this case in C++98 mode. This patch fixes this
issue.
2025-06-30 19:00:52 +08:00

348 lines
11 KiB
C++

// RUN: %clang_cc1 -fsyntax-only -verify %s
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
// This is just the test for [namespace.udecl]p4 with 'using'
// uniformly stripped out.
// C++03 [namespace.udecl]p4:
// A using-declaration used as a member-declaration shall refer to a
// member of a base class of the class being defined, shall refer to
// a member of an anonymous union that is a member of a base class
// of the class being defined, or shall refer to an enumerator for
// an enumeration type that is a member of a base class of the class
// being defined.
// There is no directly analogous paragraph in C++0x, and the feature
// works sufficiently differently there that it needs a separate test.
namespace test0 {
namespace NonClass {
typedef int type;
struct hiding {};
int hiding;
static union { double union_member; };
enum tagname { enumerator };
}
class Test0 {
NonClass::type; // expected-error {{not a class}}
#if __cplusplus <= 199711L
// expected-warning@-2 {{access declarations are deprecated; use using declarations instead}}
#else
// expected-error@-4 {{ISO C++11 does not allow access declarations; use using declarations instead}}
#endif
NonClass::hiding; // expected-error {{not a class}}
#if __cplusplus <= 199711L
// expected-warning@-2 {{access declarations are deprecated; use using declarations instead}}
#else
// expected-error@-4 {{ISO C++11 does not allow access declarations; use using declarations instead}}
#endif
NonClass::union_member; // expected-error {{not a class}}
#if __cplusplus <= 199711L
// expected-warning@-2 {{access declarations are deprecated; use using declarations instead}}
#else
// expected-error@-4 {{ISO C++11 does not allow access declarations; use using declarations instead}}
#endif
NonClass::enumerator; // expected-error {{not a class}}
#if __cplusplus <= 199711L
// expected-warning@-2 {{access declarations are deprecated; use using declarations instead}}
#else
// expected-error@-4 {{ISO C++11 does not allow access declarations; use using declarations instead}}
#endif
};
}
struct Opaque0 {};
namespace test1 {
struct A {
typedef int type;
struct hiding {}; // expected-note {{previous use is here}}
Opaque0 hiding;
union { double union_member; };
enum tagname { enumerator };
};
struct B : A {
A::type;
#if __cplusplus <= 199711L
// expected-warning@-2 {{access declarations are deprecated; use using declarations instead}}
#else
// expected-error@-4 {{ISO C++11 does not allow access declarations; use using declarations instead}}
#endif
A::hiding;
#if __cplusplus <= 199711L
// expected-warning@-2 {{access declarations are deprecated; use using declarations instead}}
#else
// expected-error@-4 {{ISO C++11 does not allow access declarations; use using declarations instead}}
#endif
A::union_member;
#if __cplusplus <= 199711L
// expected-warning@-2 {{access declarations are deprecated; use using declarations instead}}
#else
// expected-error@-4 {{ISO C++11 does not allow access declarations; use using declarations instead}}
#endif
A::enumerator;
#if __cplusplus <= 199711L
// expected-warning@-2 {{access declarations are deprecated; use using declarations instead}}
#else
// expected-error@-4 {{ISO C++11 does not allow access declarations; use using declarations instead}}
#endif
A::tagname;
#if __cplusplus <= 199711L
// expected-warning@-2 {{access declarations are deprecated; use using declarations instead}}
#else
// expected-error@-4 {{ISO C++11 does not allow access declarations; use using declarations instead}}
#endif
void test0() {
type t = 0;
}
void test1() {
typedef struct A::hiding local;
struct hiding _ = local();
}
void test2() {
union hiding _; // expected-error {{tag type that does not match previous}}
}
void test3() {
char array[sizeof(union_member) == sizeof(double) ? 1 : -1];
}
void test4() {
enum tagname _ = enumerator;
}
void test5() {
Opaque0 _ = hiding;
}
};
}
namespace test2 {
struct A {
typedef int type;
struct hiding {}; // expected-note {{previous use is here}}
int hiding;
union { double union_member; };
enum tagname { enumerator };
};
template <class T> struct B : A {
A::type;
#if __cplusplus <= 199711L
// expected-warning@-2 {{access declarations are deprecated; use using declarations instead}}
#else
// expected-error@-4 {{ISO C++11 does not allow access declarations; use using declarations instead}}
#endif
A::hiding;
#if __cplusplus <= 199711L
// expected-warning@-2 {{access declarations are deprecated; use using declarations instead}}
#else
// expected-error@-4 {{ISO C++11 does not allow access declarations; use using declarations instead}}
#endif
A::union_member;
#if __cplusplus <= 199711L
// expected-warning@-2 {{access declarations are deprecated; use using declarations instead}}
#else
// expected-error@-4 {{ISO C++11 does not allow access declarations; use using declarations instead}}
#endif
A::enumerator;
#if __cplusplus <= 199711L
// expected-warning@-2 {{access declarations are deprecated; use using declarations instead}}
#else
// expected-error@-4 {{ISO C++11 does not allow access declarations; use using declarations instead}}
#endif
A::tagname;
#if __cplusplus <= 199711L
// expected-warning@-2 {{access declarations are deprecated; use using declarations instead}}
#else
// expected-error@-4 {{ISO C++11 does not allow access declarations; use using declarations instead}}
#endif
void test0() {
type t = 0;
}
void test1() {
typedef struct A::hiding local;
struct hiding _ = local();
}
void test2() {
union hiding _; // expected-error {{tag type that does not match previous}}
}
void test3() {
char array[sizeof(union_member) == sizeof(double) ? 1 : -1];
}
void test4() {
enum tagname _ = enumerator;
}
void test5() {
Opaque0 _ = hiding;
}
};
}
namespace test3 {
struct hiding {};
template <class T> struct A {
typedef int type; // expected-note {{target of using declaration}}
struct hiding {};
Opaque0 hiding;
union { double union_member; };
enum tagname { enumerator }; // expected-note {{target of using declaration}}
};
template <class T> struct B : A<T> {
A<T>::type; // expected-error {{dependent using declaration resolved to type without 'typename'}}
#if __cplusplus <= 199711L
// expected-warning@-2 {{access declarations are deprecated; use using declarations instead}}
#else
// expected-error@-4 {{ISO C++11 does not allow access declarations; use using declarations instead}}
#endif
A<T>::hiding;
#if __cplusplus <= 199711L
// expected-warning@-2 {{access declarations are deprecated; use using declarations instead}}
#else
// expected-error@-4 {{ISO C++11 does not allow access declarations; use using declarations instead}}
#endif
A<T>::union_member;
#if __cplusplus <= 199711L
// expected-warning@-2 {{access declarations are deprecated; use using declarations instead}}
#else
// expected-error@-4 {{ISO C++11 does not allow access declarations; use using declarations instead}}
#endif
A<T>::enumerator;
#if __cplusplus <= 199711L
// expected-warning@-2 {{access declarations are deprecated; use using declarations instead}}
#else
// expected-error@-4 {{ISO C++11 does not allow access declarations; use using declarations instead}}
#endif
A<T>::tagname; // expected-error {{dependent using declaration resolved to type without 'typename'}}
#if __cplusplus <= 199711L
// expected-warning@-2 {{access declarations are deprecated; use using declarations instead}}
#else
// expected-error@-4 {{ISO C++11 does not allow access declarations; use using declarations instead}}
#endif
// FIXME: re-enable these when the various bugs involving tags are fixed
#if 0
void test1() {
typedef struct A<T>::hiding local;
struct hiding _ = local();
}
void test2() {
typedef struct A<T>::hiding local;
union hiding _ = local();
}
#endif
void test3() {
char array[sizeof(union_member) == sizeof(double) ? 1 : -1];
}
#if 0
void test4() {
enum tagname _ = enumerator;
}
#endif
void test5() {
Opaque0 _ = hiding;
}
};
template struct B<int>; // expected-note {{in instantiation}}
}
namespace test4 {
struct Base {
int foo();
};
struct Unrelated {
int foo();
};
struct Subclass : Base {
};
namespace InnerNS {
int foo();
}
// We should be able to diagnose these without instantiation.
template <class T> struct C : Base {
InnerNS::foo; // expected-error {{not a class}}
#if __cplusplus <= 199711L
// expected-warning@-2 {{access declarations are deprecated; use using declarations instead}}
#else
// expected-error@-4 {{ISO C++11 does not allow access declarations; use using declarations instead}}
#endif
Base::bar; // expected-error {{no member named 'bar'}}
#if __cplusplus <= 199711L
// expected-warning@-2 {{access declarations are deprecated; use using declarations instead}}
#else
// expected-error@-4 {{ISO C++11 does not allow access declarations; use using declarations instead}}
#endif
Unrelated::foo; // expected-error {{not a base class}}
#if __cplusplus <= 199711L
// expected-warning@-2 {{access declarations are deprecated; use using declarations instead}}
#else
// expected-error@-4 {{ISO C++11 does not allow access declarations; use using declarations instead}}
#endif
C::foo;
#if __cplusplus <= 199711L
// expected-warning@-2 {{access declarations are deprecated; use using declarations instead}}
#else
// expected-error@-4 {{ISO C++11 does not allow access declarations; use using declarations instead}}
#endif
// expected-error@-6 {{using declaration refers to its own class}}
Subclass::foo;
#if __cplusplus <= 199711L
// expected-warning@-2 {{access declarations are deprecated; use using declarations instead}}
#else
// expected-error@-4 {{ISO C++11 does not allow access declarations; use using declarations instead}}
#endif
// expected-error@-6 {{using declaration refers into 'Subclass', which is not a base class of 'C'}}
int bar();
C::bar;
#if __cplusplus <= 199711L
// expected-warning@-2 {{access declarations are deprecated; use using declarations instead}}
#else
// expected-error@-4 {{ISO C++11 does not allow access declarations; use using declarations instead}}
#endif
// expected-error@-6 {{using declaration refers to its own class}}
};
}