[clang] c894e85 - In MSVC compatibility mode, handle unqualified templated base class initialization
Marco Antognini via cfe-commits
cfe-commits at lists.llvm.org
Thu May 5 07:03:48 PDT 2022
Author: Fred Tingaud
Date: 2022-05-05T16:03:39+02:00
New Revision: c894e85fc64dd8d83b460de81080fff93c5ca334
URL: https://github.com/llvm/llvm-project/commit/c894e85fc64dd8d83b460de81080fff93c5ca334
DIFF: https://github.com/llvm/llvm-project/commit/c894e85fc64dd8d83b460de81080fff93c5ca334.diff
LOG: 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
Added:
clang/test/SemaTemplate/ms-unqualified-base-class.cpp
Modified:
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/lib/Sema/SemaDeclCXX.cpp
Removed:
################################################################################
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 45540fae58538..614bacc34af51 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -5509,6 +5509,9 @@ def err_found_later_in_class : Error<"member %0 used before its declaration">;
def ext_found_later_in_class : ExtWarn<
"use of member %0 before its declaration is a Microsoft extension">,
InGroup<MicrosoftTemplate>;
+def ext_unqualified_base_class : ExtWarn<
+ "unqualified base initializer of class templates is a Microsoft extension">,
+ InGroup<MicrosoftTemplate>;
def note_dependent_member_use : Note<
"must qualify identifier to find this declaration in dependent base class">;
def err_not_found_by_two_phase_lookup : Error<"call to function %0 that is neither "
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index b45e8e396b31a..a16fe0b1b72a4 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -4307,6 +4307,15 @@ Sema::BuildMemInitializer(Decl *ConstructorD,
}
}
+ if (getLangOpts().MSVCCompat && !getLangOpts().CPlusPlus20) {
+ auto UnqualifiedBase = R.getAsSingle<ClassTemplateDecl>();
+ if (UnqualifiedBase) {
+ Diag(IdLoc, diag::ext_unqualified_base_class)
+ << SourceRange(IdLoc, Init->getSourceRange().getEnd());
+ BaseType = UnqualifiedBase->getInjectedClassNameSpecialization();
+ }
+ }
+
// If no results were found, try to correct typos.
TypoCorrection Corr;
MemInitializerValidatorCCC CCC(ClassDecl);
diff --git a/clang/test/SemaTemplate/ms-unqualified-base-class.cpp b/clang/test/SemaTemplate/ms-unqualified-base-class.cpp
new file mode 100644
index 0000000000000..6d9a072769c63
--- /dev/null
+++ b/clang/test/SemaTemplate/ms-unqualified-base-class.cpp
@@ -0,0 +1,85 @@
+// RUN: %clang_cc1 -std=c++17 -fms-compatibility -fsyntax-only -verify=before,expected %s
+// RUN: %clang_cc1 -std=c++17 -fms-compatibility -fdelayed-template-parsing -fsyntax-only -verify=before,expected %s
+// RUN: %clang_cc1 -std=c++20 -fms-compatibility -fsyntax-only -verify=after,expected %s
+// RUN: %clang_cc1 -std=c++20 -fms-compatibility -fdelayed-template-parsing -fsyntax-only -verify=after,expected %s
+
+template <class T>
+class Base {
+};
+
+template <class T>
+class Based {}; // Trying to trick the typo detection
+
+template <class T>
+class Derived : public Base<T> {
+public:
+ // after-error at +1 {{member initializer 'Base' does not name a non-static data member or base class}}
+ Derived() : Base() {} // before-warning {{unqualified base initializer of class templates is a Microsoft extension}}
+private:
+ int Baze; // Trying to trick the typo detection
+};
+
+template <class T> struct AggregateBase {
+ T i;
+};
+
+template <class T>
+struct AggregateDerived : public AggregateBase<T> {
+ int i;
+
+ // after-error at +1 {{member initializer 'AggregateBase' does not name a non-static data member or base class}}
+ AggregateDerived(T j) : AggregateBase{4}, i{j} {} // before-warning {{unqualified base initializer of class templates is a Microsoft extension}}
+ int f() {
+ return i + AggregateBase::i; // expected-warning {{use of undeclared identifier 'AggregateBase'; unqualified lookup into dependent bases of class template 'AggregateDerived' is a Microsoft extension}}
+ }
+};
+
+template <class T, typename U> struct MultiTypesBase {
+};
+
+template <class T, class U>
+struct MultiTypesDerived : public MultiTypesBase<T, U> {
+ // after-error at +1 {{member initializer 'MultiTypesBase' does not name a non-static data member or base class}}
+ MultiTypesDerived() : MultiTypesBase{} {} // before-warning {{unqualified base initializer of class templates is a Microsoft extension}}
+};
+
+template <int I> struct IntegerBase {
+};
+
+template <int I>
+struct IntegerDerived : public IntegerBase<I> {
+ // after-error at +1 {{member initializer 'IntegerBase' does not name a non-static data member or base class}}
+ IntegerDerived() : IntegerBase{} {} // before-warning {{unqualified base initializer of class templates is a Microsoft extension}}
+};
+
+template <class T> struct ConformingBase {
+ T i;
+};
+
+template <class T>
+struct ConformingDerived : public ConformingBase<T> {
+ int i;
+
+ ConformingDerived(T j) : ConformingBase<T>{4}, i{j} {}
+ int f() {
+ return i + ConformingBase<T>::i;
+ }
+};
+
+int main() {
+ int I;
+ Derived<int> t;
+
+ AggregateDerived<int> AD{2};
+ AD.AggregateBase::i = 3;
+ I = AD.f();
+
+ MultiTypesDerived<int, double> MTD;
+
+ IntegerDerived<4> ID;
+
+ ConformingDerived<int> CD{2};
+ I = CD.f();
+
+ return I;
+}
More information about the cfe-commits
mailing list