Index: clang/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticSemaKinds.td +++ clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -5508,6 +5508,9 @@ def ext_found_later_in_class : ExtWarn< "use of member %0 before its declaration is a Microsoft extension">, InGroup; +def ext_unqualified_base_class : ExtWarn< + "unqualified base initializer of class templates is a Microsoft extension">, + InGroup; 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 " Index: clang/lib/Sema/SemaDeclCXX.cpp =================================================================== --- clang/lib/Sema/SemaDeclCXX.cpp +++ clang/lib/Sema/SemaDeclCXX.cpp @@ -4345,6 +4345,15 @@ } } + if (getLangOpts().MSVCCompat && !getLangOpts().CPlusPlus20) { + auto UnqualifiedBase = R.getAsSingle(); + if (UnqualifiedBase) { + Diag(IdLoc, diag::ext_unqualified_base_class) + << SourceRange(IdLoc, Init->getSourceRange().getEnd()); + BaseType = UnqualifiedBase->getInjectedClassNameSpecialization(); + } + } + if (!TyD && BaseType.isNull()) { Diag(IdLoc, diag::err_mem_init_not_member_or_class) << MemberOrBase << SourceRange(IdLoc,Init->getSourceRange().getEnd()); Index: clang/test/SemaTemplate/ms-unqualified-base-class.cpp =================================================================== --- /dev/null +++ clang/test/SemaTemplate/ms-unqualified-base-class.cpp @@ -0,0 +1,80 @@ +// 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 Base { +}; + +template +class Derived : public Base { +public: + // after-error@+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}} +}; + +template struct AggregateBase { + T i; +}; + +template +struct AggregateDerived : public AggregateBase { + int i; + + // after-error@+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 struct MultiTypesBase { +}; + +template +struct MultiTypesDerived : public MultiTypesBase { + // after-error@+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 struct IntegerBase { +}; + +template +struct IntegerDerived : public IntegerBase { + // after-error@+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 struct ConformingBase { + T i; +}; + +template +struct ConformingDerived : public ConformingBase { + int i; + + ConformingDerived(T j) : ConformingBase{ 4 }, i{ j } {} + int f() { + return i + ConformingBase::i; + } +}; + +int main() { + int I; + Derived t; + + AggregateDerived AD{ 2 }; + AD.AggregateBase::i = 3; + I = AD.f(); + + MultiTypesDerived MTD; + + IntegerDerived<4> ID; + + ConformingDerived CD{ 2 }; + I = CD.f(); + + return I; +}