Files
clang-p2996/clang/test/SemaTemplate/typo-dependent-name.cpp
Krystian Stasiowski acf5ad2a4e [Clang][Sema] Diagnose current instantiation used as an incomplete base class (#92597)
Consider the following:
```
template<typename T>
struct A
{
    struct B : A { };
};
```
According to [class.derived.general] p2:
> [...] A _class-or-decltype_ shall denote a (possibly cv-qualified)
class type that is not an incompletely defined class; any cv-qualifiers
are ignored. [...]

Although GCC and EDG rejects this, Clang accepts it. This is incorrect,
as `A` is incomplete within its own definition (outside of a
complete-class context). This patch correctly diagnoses instances where
the current instantiation is used as a base class before it is complete.

Conversely, Clang erroneously rejects the following:
```
template<typename T>
struct A 
{
    struct B;

    struct C : B { };

    struct B : C { }; // error: circular inheritance between 'C' and 'A::B'
};
```
Though it may seem like no valid specialization of this template can be
instantiated, an explicit specialization of either member classes for an
implicit instantiated specialization of `A` would permit the definition
of the other member class to be instantiated, e.g.:
```
template<>
struct A<int>::B { };

A<int>::C c; // ok
```
So this patch also does away with this error. This means that circular
inheritance is diagnosed during instantiation of the definition as a
consequence of requiring the base class type to be complete (matching
the behavior of GCC and EDG).
2024-05-20 14:44:59 -04:00

49 lines
1.1 KiB
C++

// RUN: %clang_cc1 -std=c++14 -fsyntax-only -verify %s
using nullptr_t = decltype(nullptr);
template<typename T>
struct Base {
T inner;
};
int z;
template<typename T>
struct X : Base<T> {
static int z;
template<int U>
struct Inner {
};
bool f(T other) {
// A pair of comparisons; 'inner' is a dependent name so can't be assumed
// to be a template.
return this->inner < other > ::z; // expected-warning {{comparisons like 'X<=Y<=Z' don't have their mathematical meaning}}
}
};
void use_x(X<int> x) { x.f(0); } // expected-note {{requested here}}
template<typename T>
struct Y {
static int z;
template<int U>
struct Inner; // expected-note {{declared here}}
bool f(T other) {
// We can determine that 'inner' does not exist at parse time, so can
// perform typo correction in this case.
return this->inner<other>::z; // expected-error {{no template named 'inner' in 'Y<T>'; did you mean 'Inner'?}}
}
};
template<typename T>
template<int U>
struct Y<T>::Inner : Y { };
struct Q { constexpr operator int() { return 0; } };
void use_y(Y<Q> x) { x.f(Q()); }