frederic-tingaud-sonarsource created this revision.
frederic-tingaud-sonarsource added a reviewer: rnk.
Herald added a project: All.
frederic-tingaud-sonarsource requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

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.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D124666

Files:
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/lib/Sema/SemaDeclCXX.cpp
  clang/test/SemaTemplate/ms-unqualified-base-class.cpp

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 T>
+class Base {
+};
+
+template <class T>
+class Derived : public Base<T> {
+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<class T> struct AggregateBase {
+  T i;
+};
+
+template<class T>
+struct  AggregateDerived : public AggregateBase<T> {
+  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<class T, typename U> struct MultiTypesBase {
+};
+
+template<class T, class U>
+struct MultiTypesDerived : public MultiTypesBase<T, U> {
+  // 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<int I> struct IntegerBase {
+};
+
+template<int I>
+struct IntegerDerived : public IntegerBase<I> {
+  // 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<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;
+}
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<ClassTemplateDecl>();
+        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/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<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 "
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to