Skip to content

Commit c894e85

Browse files
In MSVC compatibility mode, handle unqualified templated base class initialization
Before C++20, MSVC was supporting not mentioning the template argument of the base class when initializing a class inheriting a templated base class. So the following code compiled correctly: ``` template <class T> class Base { }; template <class T> class Derived : public Base<T> { public: Derived() : Base() {} }; void test() { Derived<int> d; } ``` See https://godbolt.org/z/Pxxe7nccx for a conformance view. This patch adds support for such construct when in MSVC compatibility mode. Reviewed By: rnk Differential Revision: https://reviews.llvm.org/D124666
1 parent 08b20f2 commit c894e85

File tree

3 files changed

+97
-0
lines changed

3 files changed

+97
-0
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5509,6 +5509,9 @@ def err_found_later_in_class : Error<"member %0 used before its declaration">;
55095509
def ext_found_later_in_class : ExtWarn<
55105510
"use of member %0 before its declaration is a Microsoft extension">,
55115511
InGroup<MicrosoftTemplate>;
5512+
def ext_unqualified_base_class : ExtWarn<
5513+
"unqualified base initializer of class templates is a Microsoft extension">,
5514+
InGroup<MicrosoftTemplate>;
55125515
def note_dependent_member_use : Note<
55135516
"must qualify identifier to find this declaration in dependent base class">;
55145517
def err_not_found_by_two_phase_lookup : Error<"call to function %0 that is neither "

clang/lib/Sema/SemaDeclCXX.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4307,6 +4307,15 @@ Sema::BuildMemInitializer(Decl *ConstructorD,
43074307
}
43084308
}
43094309

4310+
if (getLangOpts().MSVCCompat && !getLangOpts().CPlusPlus20) {
4311+
auto UnqualifiedBase = R.getAsSingle<ClassTemplateDecl>();
4312+
if (UnqualifiedBase) {
4313+
Diag(IdLoc, diag::ext_unqualified_base_class)
4314+
<< SourceRange(IdLoc, Init->getSourceRange().getEnd());
4315+
BaseType = UnqualifiedBase->getInjectedClassNameSpecialization();
4316+
}
4317+
}
4318+
43104319
// If no results were found, try to correct typos.
43114320
TypoCorrection Corr;
43124321
MemInitializerValidatorCCC CCC(ClassDecl);
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
// RUN: %clang_cc1 -std=c++17 -fms-compatibility -fsyntax-only -verify=before,expected %s
2+
// RUN: %clang_cc1 -std=c++17 -fms-compatibility -fdelayed-template-parsing -fsyntax-only -verify=before,expected %s
3+
// RUN: %clang_cc1 -std=c++20 -fms-compatibility -fsyntax-only -verify=after,expected %s
4+
// RUN: %clang_cc1 -std=c++20 -fms-compatibility -fdelayed-template-parsing -fsyntax-only -verify=after,expected %s
5+
6+
template <class T>
7+
class Base {
8+
};
9+
10+
template <class T>
11+
class Based {}; // Trying to trick the typo detection
12+
13+
template <class T>
14+
class Derived : public Base<T> {
15+
public:
16+
// after-error@+1 {{member initializer 'Base' does not name a non-static data member or base class}}
17+
Derived() : Base() {} // before-warning {{unqualified base initializer of class templates is a Microsoft extension}}
18+
private:
19+
int Baze; // Trying to trick the typo detection
20+
};
21+
22+
template <class T> struct AggregateBase {
23+
T i;
24+
};
25+
26+
template <class T>
27+
struct AggregateDerived : public AggregateBase<T> {
28+
int i;
29+
30+
// after-error@+1 {{member initializer 'AggregateBase' does not name a non-static data member or base class}}
31+
AggregateDerived(T j) : AggregateBase{4}, i{j} {} // before-warning {{unqualified base initializer of class templates is a Microsoft extension}}
32+
int f() {
33+
return i + AggregateBase::i; // expected-warning {{use of undeclared identifier 'AggregateBase'; unqualified lookup into dependent bases of class template 'AggregateDerived' is a Microsoft extension}}
34+
}
35+
};
36+
37+
template <class T, typename U> struct MultiTypesBase {
38+
};
39+
40+
template <class T, class U>
41+
struct MultiTypesDerived : public MultiTypesBase<T, U> {
42+
// after-error@+1 {{member initializer 'MultiTypesBase' does not name a non-static data member or base class}}
43+
MultiTypesDerived() : MultiTypesBase{} {} // before-warning {{unqualified base initializer of class templates is a Microsoft extension}}
44+
};
45+
46+
template <int I> struct IntegerBase {
47+
};
48+
49+
template <int I>
50+
struct IntegerDerived : public IntegerBase<I> {
51+
// after-error@+1 {{member initializer 'IntegerBase' does not name a non-static data member or base class}}
52+
IntegerDerived() : IntegerBase{} {} // before-warning {{unqualified base initializer of class templates is a Microsoft extension}}
53+
};
54+
55+
template <class T> struct ConformingBase {
56+
T i;
57+
};
58+
59+
template <class T>
60+
struct ConformingDerived : public ConformingBase<T> {
61+
int i;
62+
63+
ConformingDerived(T j) : ConformingBase<T>{4}, i{j} {}
64+
int f() {
65+
return i + ConformingBase<T>::i;
66+
}
67+
};
68+
69+
int main() {
70+
int I;
71+
Derived<int> t;
72+
73+
AggregateDerived<int> AD{2};
74+
AD.AggregateBase::i = 3;
75+
I = AD.f();
76+
77+
MultiTypesDerived<int, double> MTD;
78+
79+
IntegerDerived<4> ID;
80+
81+
ConformingDerived<int> CD{2};
82+
I = CD.f();
83+
84+
return I;
85+
}

0 commit comments

Comments
 (0)