ABataev created this revision.
ABataev added reviewers: rnk, rsmith, majnemer.
ABataev added subscribers: cfe-commits, andreybokhanko.

MSVC actively uses unqualified lookup in dependent bases, lookup at the 
instantiation point (non-dependent names may be resolved on things declared 
later) etc. and all this stuff is the main cause of incompatibility between 
clang and MSVC.
Clang tries to emulate MSVC behavior but it may fail in many cases. Patch tries 
to improve compatibility between clang and MSVC. Each time a new instantiation 
of the function is required, a new copy of the original templated function is 
created and the body of original function is parsed in the context of this new 
copy. If unqualified lookup is detected, patch tries to find the required name 
in the instantiated context. Also, if the original template function is 
instantiated, but not used, its body is not parsed and not instantiated (it 
emulates MSVC behavior).
Patch significantly improves compatibility with ATL/WTL headers, but does not 
solve troubles with unqualified lookup in dependent bases in default 
initializers of members, types of member functions/data members and default 
values of function arguments. This must be fixed later.

https://reviews.llvm.org/D22955

Files:
  include/clang/Sema/Sema.h
  lib/AST/DeclBase.cpp
  lib/Parse/ParseTemplate.cpp
  lib/Sema/SemaDecl.cpp
  lib/Sema/SemaExpr.cpp
  lib/Sema/SemaLookup.cpp
  lib/Sema/SemaTemplate.cpp
  lib/Sema/SemaTemplateInstantiate.cpp
  lib/Sema/SemaTemplateInstantiateDecl.cpp
  lib/Serialization/ASTReader.cpp
  lib/Serialization/ASTWriter.cpp
  test/SemaCXX/ms-property.cpp
  test/SemaTemplate/lookup-dependent-bases.cpp
  test/SemaTemplate/ms-lookup-template-base-classes.cpp
  test/SemaTemplate/typename-specifier.cpp

Index: test/SemaTemplate/typename-specifier.cpp
===================================================================
--- test/SemaTemplate/typename-specifier.cpp
+++ test/SemaTemplate/typename-specifier.cpp
@@ -1,9 +1,9 @@
 // RUN: %clang_cc1 -fsyntax-only -verify %s -Wno-unused
-// RUN: %clang_cc1 -fsyntax-only -verify %s -Wno-unused -fms-compatibility -DMSVC
+// RUN: %clang_cc1 -fsyntax-only -verify %s -Wno-unused -fms-compatibility -fdelayed-template-parsing -DMSVC
 // RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s -Wno-unused
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s -Wno-unused -fms-compatibility -DMSVC
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s -Wno-unused -fms-compatibility -fdelayed-template-parsing -DMSVC
 // RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s -Wno-unused
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s -Wno-unused -fms-compatibility -DMSVC
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s -Wno-unused -fms-compatibility -fdelayed-template-parsing -DMSVC
 namespace N {
   struct A {
     typedef int type;
@@ -139,7 +139,12 @@
 
 
 namespace missing_typename {
-template <class T1, class T2> struct pair {}; // expected-note 7 {{template parameter is declared here}}
+#ifdef MSVC
+// expected-note@+4 3 {{template parameter is declared here}}
+#else
+// expected-note@+2 7 {{template parameter is declared here}}
+#endif // MSVC
+template <class T1, class T2> struct pair {};
 
 template <class T1, class T2>
 struct map {
@@ -157,14 +162,18 @@
   };
 
   void foo() {
-#ifdef MSVC
-    // expected-warning@+4 {{omitted 'typename' is a Microsoft extension}}
-#else
+#ifndef MSVC
     // expected-error@+2 {{template argument for template type parameter must be a type; did you forget 'typename'?}}
 #endif
     pair<ExampleItemSet::iterator, int> i;
-    pair<this->ExampleItemSet::iterator, int> i; // expected-error-re {{template argument for template type parameter must be a type{{$}}}}
-    pair<ExampleItemSet::operator[], int> i; // expected-error-re {{template argument for template type parameter must be a type{{$}}}}
+#ifndef MSVC
+    // expected-error-re@+2 {{template argument for template type parameter must be a type{{$}}}}}
+#endif
+    pair<this->ExampleItemSet::iterator, int> i;
+#ifndef MSVC
+    // expected-error-re@+2 {{template argument for template type parameter must be a type{{$}}}}}
+#endif
+    pair<ExampleItemSet::operator[], int> i;
   }
 #ifdef MSVC
     // expected-warning@+4 {{omitted 'typename' is a Microsoft extension}}
@@ -177,9 +186,7 @@
   typedef map<int, ExampleItem*> ExampleItemMap;
 
   static void bar() {
-#ifdef MSVC
-    // expected-warning@+4 {{omitted 'typename' is a Microsoft extension}}
-#else
+#ifndef MSVC
     // expected-error@+2 {{template argument for template type parameter must be a type; did you forget 'typename'?}}
 #endif
     pair<ExampleItemMap::iterator, int> i;
Index: test/SemaTemplate/ms-lookup-template-base-classes.cpp
===================================================================
--- test/SemaTemplate/ms-lookup-template-base-classes.cpp
+++ test/SemaTemplate/ms-lookup-template-base-classes.cpp
@@ -1,11 +1,11 @@
-// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -std=c++1y -fms-compatibility -fno-spell-checking -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -std=c++1y -fms-compatibility -fdelayed-template-parsing -fno-spell-checking -fsyntax-only -verify %s
 
 
 template <class T>
 class A {
 public:
-   void f(T a) { }// expected-note 2{{must qualify identifier to find this declaration in dependent base class}}
-   void g();// expected-note 2{{must qualify identifier to find this declaration in dependent base class}}
+   void f(T a) { }
+   void g();
 };
 
 template <class T>
@@ -16,10 +16,11 @@
        f(a); // expected-warning 2{{use of identifier 'f' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}}
        g(); // expected-warning 2{{use of identifier 'g' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}}
     }
+  B() : A<T>() {}
 };
 
-template class B<int>; // expected-note {{requested here}}
-template class B<char>; // expected-note {{requested here}}
+template class B<int>;
+template class B<char>;
 
 void test()
 {
@@ -64,7 +65,7 @@
 class B : public A<T> {
 public:
   void f() {
-    var = 3; // expected-warning {{use of undeclared identifier 'var'; unqualified lookup into dependent bases of class template 'B' is a Microsoft extension}}
+    var = 3; // expected-warning {{use of identifier 'var' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}}
   }
 };
 
@@ -79,8 +80,8 @@
 template <class T>
 class A {
 public:
-   static void static_func();// expected-note {{must qualify identifier to find this declaration in dependent base class}}
-   void func();// expected-note {{must qualify identifier to find this declaration in dependent base class}}
+   static void static_func();
+   void func();
 };
 
 
@@ -129,7 +130,7 @@
 template <class T>
 class B {
 public:
-  static void g();  // expected-note {{must qualify identifier to find this declaration in dependent base class}} 
+  static void g();
 };
 
 template <class T>
@@ -143,7 +144,7 @@
 int main2()
 {
   A<int> a;
-  foo(a); // expected-note {{requested here}}
+  foo(a);
 }
 
 }
@@ -154,13 +155,21 @@
 class C {
 public:
   int m_hWnd;
+  static int c_hWnd;
+};
+
+class B {
+public:
+  static bool b_hWnd;
 };
 
 template <class T>
 class A : public T {
 public:
   void f(int hWnd) {
-    m_hWnd = 1; // expected-warning {{use of undeclared identifier 'm_hWnd'; unqualified lookup into dependent bases of class template 'A' is a Microsoft extension}}
+    m_hWnd = 1; // expected-warning {{use of identifier 'm_hWnd' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}}
+    B::b_hWnd = this->m_hWnd < 0;
+    C::c_hWnd = 0;
   }
 };
 
@@ -176,23 +185,23 @@
 template <class T>
 class Base {
  public:
-  bool base_fun(void* p) { return false; }  // expected-note {{must qualify identifier to find this declaration in dependent base class}}
+  bool base_fun(void* p) { return false; }
   operator T*() const { return 0; }
 };
 
 template <class T>
 class Container : public Base<T> {
  public:
   template <typename S>
   bool operator=(const Container<S>& rhs) {
-    return base_fun(rhs);  // expected-warning {{use of identifier 'base_fun' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}}
+    return base_fun(rhs);  // expected-warning 2 {{use of identifier 'base_fun' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}}
   }
 };
 
 void f() {
   Container<A> text_provider;
   Container<B> text_provider2;
-  text_provider2 = text_provider;  // expected-note {{in instantiation of function template specialization}}
+  text_provider2 = text_provider;
 }
 
 }  // namespace PR12701
@@ -205,7 +214,7 @@
 };
 template <typename T> struct B : T {
   int     foo() { return a; }           // expected-warning {{lookup into dependent bases}}
-  int    *bar() { return &a; }          // expected-warning {{lookup into dependent bases}}
+  int    *bar() { return &a; }          // expected-warning {{lookup into dependent bases}} expected-error {{cannot initialize return object of type 'int *' with an rvalue of type 'int PR16014::A::*'}}
   int     baz() { return T::a; }
   int T::*qux() { return &T::a; }
   static int T::*stuff() { return &T::a; }
@@ -216,23 +225,21 @@
 };
 
 template <typename T> struct C : T {
-  int     foo() { return b; }      // expected-error {{no member named 'b' in 'PR16014::C<PR16014::A>'}} expected-warning {{lookup into dependent bases}}
-  int    *bar() { return &b; }     // expected-error {{no member named 'b' in 'PR16014::C<PR16014::A>'}} expected-warning {{lookup into dependent bases}}
+  int     foo() { return b; }      // expected-error {{use of undeclared identifier 'b'}}
+  int    *bar() { return &b; }     // expected-error {{use of undeclared identifier 'b'}}
   int     baz() { return T::b; }   // expected-error {{no member named 'b' in 'PR16014::A'}}
   int T::*qux() { return &T::b; }  // expected-error {{no member named 'b' in 'PR16014::A'}}
   int T::*fuz() { return &U::a; }  // expected-error {{use of undeclared identifier 'U'}} \
   // expected-warning {{unqualified lookup into dependent bases of class template 'C'}}
 };
 
-template struct B<A>;
+template struct B<A>; // expected-note {{in instantiation of member function 'PR16014::B<PR16014::A>::bar' requested here}}
 template struct C<A>;  // expected-note-re 1+ {{in instantiation of member function 'PR16014::C<PR16014::A>::{{.*}}' requested here}}
 
 template <typename T> struct D : T {
   struct Inner {
     int foo() {
-      // FIXME: MSVC can find this in D's base T!  Even worse, if ::sa exists,
-      // clang will use it instead.
-      return sa; // expected-error {{use of undeclared identifier 'sa'}}
+      return sa; // expected-warning {{use of identifier 'sa' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}}
     }
   };
 };
@@ -244,14 +251,13 @@
 template <class T>
 struct A : T {
   void foo() {
-    ::undef(); // expected-error {{no member named 'undef' in the global namespace}}
+    ::undef(); // expected-error 2 {{no member named 'undef' in the global namespace}}
   }
   void bar() {
-    ::UndefClass::undef(); // expected-error {{no member named 'UndefClass' in the global namespace}}
+    ::UndefClass::undef(); // expected-error 2 {{no member named 'UndefClass' in the global namespace}}
   }
   void baz() {
-    B::qux(); // expected-error {{use of undeclared identifier 'B'}} \
-    // expected-warning {{unqualified lookup into dependent bases of class template 'A'}}
+    B::qux(); // expected-error {{'PR19233::B::qux' is not a member of class 'PR19233::A<PR19233::D>'}}
   }
 };
 
@@ -470,7 +476,7 @@
   void localClassMethod() {
     struct X {
       void bar() {
-        NameFromBase m; // expected-warning {{lookup into dependent bases}}
+        NameFromBase m;
       }
     } x;
     x.bar();
@@ -523,8 +529,8 @@
 namespace function_template_undef_impl {
 template<class T>
 void f() {
-  Undef::staticMethod(); // expected-error {{use of undeclared identifier 'Undef'}}
-  UndefVar.method(); // expected-error {{use of undeclared identifier 'UndefVar'}}
+  Undef::staticMethod();
+  UndefVar.method();
 }
 }
 
@@ -551,16 +557,16 @@
 namespace PR23810 {
 void f(int);
 struct Base {
-  void f(); // expected-note{{must qualify identifier to find this declaration in dependent base class}}
+  void f();
 };
 template <typename T> struct Template : T {
   void member() {
     f(); // expected-warning {{found via unqualified lookup into dependent bases}}
   }
 };
 void test() {
   Template<Base> x;
-  x.member(); // expected-note{{requested here}}
+  x.member();
 };
 }
 
@@ -580,19 +586,19 @@
 template <typename T>
 struct UseUnqualifiedTypeNames : T {
   void foo() {
-    void *P = new TheType; // expected-warning {{unqualified lookup}} expected-error {{no type}}
-    size_t x = __builtin_offsetof(TheType, f2); // expected-warning {{unqualified lookup}} expected-error {{no type}}
+    void *P = new TheType; // expected-warning 2 {{unqualified lookup}} expected-error {{no type}}
+    size_t x = __builtin_offsetof(TheType, f2); // expected-warning 2 {{unqualified lookup}} expected-error {{no type}}
     try {
-    } catch (TheType) { // expected-warning {{unqualified lookup}} expected-error {{no type}}
+    } catch (TheType) { // expected-warning 2 {{unqualified lookup}} expected-error {{no type}}
     }
-    enum E : IntegerType { E0 = 42 }; // expected-warning {{unqualified lookup}} expected-error {{no type}}
-    _Atomic(TheType) a; // expected-warning {{unqualified lookup}} expected-error {{no type}}
+    enum E : IntegerType { E0 = 42 }; // expected-warning 2 {{unqualified lookup}} expected-error {{no type}}
+    _Atomic(TheType) a; // expected-warning 2 {{unqualified lookup}} expected-error {{no type}}
   }
   void out_of_line();
 };
 template <typename T>
 void UseUnqualifiedTypeNames<T>::out_of_line() {
-  void *p = new TheType; // expected-warning {{unqualified lookup}} expected-error {{no type}}
+  void *p = new TheType; // expected-warning 2 {{unqualified lookup}} expected-error {{no type}}
 }
 struct Base {
   typedef int IntegerType;
Index: test/SemaTemplate/lookup-dependent-bases.cpp
===================================================================
--- test/SemaTemplate/lookup-dependent-bases.cpp
+++ test/SemaTemplate/lookup-dependent-bases.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fms-compatibility -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fms-compatibility -fdelayed-template-parsing -fsyntax-only -verify %s
 
 namespace basic {
 struct C {
@@ -12,23 +12,22 @@
 template <typename T>
 struct B : A<T> {
   void foo() {
-    D::foo2(); // expected-warning {{use of undeclared identifier 'D'; unqualified lookup into dependent bases of class template 'B' is a Microsoft extension}}
+    D::foo2(); // expected-warning {{use of identifier 'D' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}}
   }
 };
 
 template struct B<int>; // Instantiation has no warnings.
 }
 
 namespace nested_nodep_base {
-// There are limits to our hacks, MSVC accepts this, but we don't.
 struct A {
   struct D { static void foo2(); };
 };
 template <typename T>
 struct B : T {
   struct C {
     void foo() {
-      D::foo2(); // expected-error {{use of undeclared identifier 'D'}}
+      D::foo2(); // expected-warning {{use of identifier 'D' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}}
     }
   };
 };
@@ -46,7 +45,7 @@
 struct B {
   struct C : T {
     void foo() {
-      D::foo2(); // expected-warning {{use of undeclared identifier 'D'; unqualified lookup into dependent bases of class template 'C' is a Microsoft extension}}
+      D::foo2(); // expected-warning {{use of identifier 'D' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}}
     }
   };
 };
Index: test/SemaCXX/ms-property.cpp
===================================================================
--- test/SemaCXX/ms-property.cpp
+++ test/SemaCXX/ms-property.cpp
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -ast-print -verify -triple=x86_64-pc-win32 -fms-compatibility %s -o - | FileCheck %s
-// RUN: %clang_cc1 -triple=x86_64-pc-win32 -fms-compatibility -emit-pch -o %t %s
-// RUN: %clang_cc1 -triple=x86_64-pc-win32 -fms-compatibility -include-pch %t -verify %s -ast-print -o - | FileCheck %s
+// RUN: %clang_cc1 -ast-print -verify -triple=x86_64-pc-win32 -fms-compatibility -fdelayed-template-parsing %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple=x86_64-pc-win32 -fms-compatibility -fdelayed-template-parsing -emit-pch -o %t %s
+// RUN: %clang_cc1 -triple=x86_64-pc-win32 -fms-compatibility -fdelayed-template-parsing -include-pch %t -verify %s -ast-print -o - | FileCheck %s
 // expected-no-diagnostics
 
 #ifndef HEADER
@@ -42,7 +42,9 @@
   St<float> *p2 = 0;
   // CHECK: St<int> a;
   St<int> a;
-  // CHECK-NEXT: int j = (p1->x)[223][11];
+  St<float> b;
+  p2 = &b;
+  // CHECK: int j = (p1->x)[223][11];
   int j = (p1->x)[223][11];
   // CHECK-NEXT: (p1->x[23])[1] = j;
   (p1->x[23])[1] = j;
Index: lib/Serialization/ASTWriter.cpp
===================================================================
--- lib/Serialization/ASTWriter.cpp
+++ lib/Serialization/ASTWriter.cpp
@@ -3995,11 +3995,16 @@
 
 void ASTWriter::AddToken(const Token &Tok, RecordDataImpl &Record) {
   AddSourceLocation(Tok.getLocation(), Record);
-  Record.push_back(Tok.getLength());
+  if (Tok.isAnnotation()) {
+    assert(!Tok.getAnnotationValue());
+    Record.push_back(0);
+  } else {
+    Record.push_back(Tok.getLength());
 
-  // FIXME: When reading literal tokens, reconstruct the literal pointer
-  // if it is needed.
-  AddIdentifierRef(Tok.getIdentifierInfo(), Record);
+    // FIXME: When reading literal tokens, reconstruct the literal pointer
+    // if it is needed.
+    AddIdentifierRef(Tok.getIdentifierInfo(), Record);
+  }
   // FIXME: Should translate token kind to a stable encoding.
   Record.push_back(Tok.getKind());
   // FIXME: Should translate token flags to a stable encoding.
Index: lib/Serialization/ASTReader.cpp
===================================================================
--- lib/Serialization/ASTReader.cpp
+++ lib/Serialization/ASTReader.cpp
@@ -1400,8 +1400,9 @@
   Tok.startToken();
   Tok.setLocation(ReadSourceLocation(F, Record, Idx));
   Tok.setLength(Record[Idx++]);
-  if (IdentifierInfo *II = getLocalIdentifier(F, Record[Idx++]))
-    Tok.setIdentifierInfo(II);
+  if (Tok.getLength())
+    if (IdentifierInfo *II = getLocalIdentifier(F, Record[Idx++]))
+      Tok.setIdentifierInfo(II);
   Tok.setKind((tok::TokenKind)Record[Idx++]);
   Tok.setFlag((Token::TokenFlags)Record[Idx++]);
   return Tok;
Index: lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -3492,6 +3492,140 @@
   return false;
 }
 
+namespace {
+class MSVCTemplateFunctionRebuilderRAII final {
+  Sema &S;
+  FunctionDecl *NewTemplateDecl = nullptr;
+  FunctionDecl *OldMSVCInstantiation = nullptr;
+  FunctionDecl *PatternDecl = nullptr;
+  DeclarationNameInfo NameInfo;
+
+public:
+  MSVCTemplateFunctionRebuilderRAII(Sema &S, FunctionDecl *PatternDecl,
+                                    FunctionDecl *InstDecl)
+      : S(S), OldMSVCInstantiation(S.MSVCInstantiation),
+        PatternDecl(PatternDecl) {
+    if (!S.getLangOpts().DelayedTemplateParsing ||
+        !S.getLangOpts().MSVCCompat || InstDecl->isDependentContext() ||
+        !PatternDecl)
+      return;
+    NameInfo = {PatternDecl->getDeclName(), PatternDecl->getLocation()};
+    ASTContext &C = S.getASTContext();
+    OldMSVCInstantiation = S.MSVCInstantiation;
+    S.MSVCInstantiation = InstDecl;
+
+    if (auto *CD = dyn_cast<CXXConstructorDecl>(PatternDecl)) {
+      NewTemplateDecl = CXXConstructorDecl::Create(
+          C, cast<CXXRecordDecl>(PatternDecl->getParent()), CD->getLocStart(),
+          NameInfo, CD->getType(), CD->getTypeSourceInfo(),
+          CD->isExplicitSpecified(), CD->isInlineSpecified(), CD->isImplicit(),
+          CD->isConstexpr());
+    } else if (auto *DD = dyn_cast<CXXDestructorDecl>(PatternDecl)) {
+      NewTemplateDecl = CXXDestructorDecl::Create(
+          C, cast<CXXRecordDecl>(PatternDecl->getParent()), DD->getLocStart(),
+          NameInfo, DD->getType(), DD->getTypeSourceInfo(),
+          DD->isInlineSpecified(), DD->isImplicit());
+    } else if (auto *CD = dyn_cast<CXXConversionDecl>(PatternDecl)) {
+      NewTemplateDecl = CXXConversionDecl::Create(
+          C, cast<CXXRecordDecl>(PatternDecl->getParent()), CD->getLocStart(),
+          NameInfo, CD->getType(), CD->getTypeSourceInfo(),
+          CD->isInlineSpecified(), CD->isExplicitSpecified(), CD->isConstexpr(),
+          CD->getLocEnd());
+    } else if (auto *MD = dyn_cast<CXXMethodDecl>(PatternDecl)) {
+      NewTemplateDecl = CXXMethodDecl::Create(
+          C, cast<CXXRecordDecl>(PatternDecl->getParent()), MD->getLocStart(),
+          NameInfo, MD->getType(), MD->getTypeSourceInfo(),
+          MD->getStorageClass(), MD->isInlineSpecified(), MD->isConstexpr(),
+          MD->getLocEnd());
+    } else {
+      assert(PatternDecl->getKind() == Decl::Function);
+      NewTemplateDecl = FunctionDecl::Create(
+          C, PatternDecl->getParent(), PatternDecl->getLocStart(), NameInfo,
+          PatternDecl->getType(), PatternDecl->getTypeSourceInfo(),
+          PatternDecl->getStorageClass(), PatternDecl->isInlineSpecified(),
+          PatternDecl->hasWrittenPrototype(), PatternDecl->isConstexpr());
+    }
+    NewTemplateDecl->setAccess(PatternDecl->getAccess());
+    if (PatternDecl->isInlined() && !PatternDecl->isInlineSpecified())
+      NewTemplateDecl->setImplicitlyInline();
+    switch (PatternDecl->getTemplatedKind()) {
+    case FunctionDecl::TK_FunctionTemplate:
+      NewTemplateDecl->setDescribedFunctionTemplate(
+          PatternDecl->getDescribedFunctionTemplate());
+      break;
+    case FunctionDecl::TK_MemberSpecialization:
+      NewTemplateDecl->setInstantiationOfMemberFunction(
+          PatternDecl->getInstantiatedFromMemberFunction(),
+          PatternDecl->getTemplateSpecializationKind());
+      break;
+    case FunctionDecl::TK_FunctionTemplateSpecialization: {
+      const ASTTemplateArgumentListInfo *Info =
+          PatternDecl->getTemplateSpecializationArgsAsWritten();
+      TemplateArgumentListInfo Args(Info->LAngleLoc, Info->RAngleLoc);
+      for (unsigned I = 0, E = Info->NumTemplateArgs; I != E; ++I)
+        Args.addArgument((*Info)[I]);
+      NewTemplateDecl->setFunctionTemplateSpecialization(
+          PatternDecl->getPrimaryTemplate(),
+          PatternDecl->getTemplateSpecializationArgs(), nullptr,
+          PatternDecl->getTemplateSpecializationKind(), &Args,
+          PatternDecl->getPointOfInstantiation());
+      break;
+    }
+    case FunctionDecl::TK_DependentFunctionTemplateSpecialization: {
+      UnresolvedSet<4> Decls;
+      DependentFunctionTemplateSpecializationInfo *Info =
+          PatternDecl->getDependentSpecializationInfo();
+      for (unsigned I = 0, E = Info->getNumTemplates(); I != E; ++I)
+        Decls.addDecl(Info->getTemplate(I));
+      TemplateArgumentListInfo Args(Info->getLAngleLoc(), Info->getRAngleLoc());
+      for (unsigned I = 0, E = Info->getNumTemplateArgs(); I != E; ++I)
+        Args.addArgument(Info->getTemplateArg(I));
+      NewTemplateDecl->setDependentTemplateSpecialization(C, Decls, Args);
+      break;
+    }
+    case FunctionDecl::TK_NonTemplate:
+      break;
+    }
+    NewTemplateDecl->setLexicalDeclContext(PatternDecl->getLexicalParent());
+    NewTemplateDecl->setInnerLocStart(PatternDecl->getInnerLocStart());
+    SmallVector<ParmVarDecl *, 4> Params;
+    for (auto *Parm : PatternDecl->parameters()) {
+      auto *NewParm = ParmVarDecl::Create(
+          C, NewTemplateDecl, Parm->getLocStart(), Parm->getLocation(),
+          Parm->getIdentifier(), Parm->getType(), Parm->getTypeSourceInfo(),
+          Parm->getStorageClass(), Parm->getDefaultArg());
+      Params.push_back(NewParm);
+    }
+    if (PatternDecl->getNumTemplateParameterLists() > 0) {
+      SmallVector<TemplateParameterList *, 4> ParameterLists;
+      for (unsigned I = 0, E = PatternDecl->getNumTemplateParameterLists();
+           I < E; ++I)
+        ParameterLists.push_back(PatternDecl->getTemplateParameterList(I));
+      NewTemplateDecl->setTemplateParameterListsInfo(C, ParameterLists);
+    }
+    NewTemplateDecl->setParams(Params);
+    NewTemplateDecl->setLateTemplateParsed(/*ILT=*/true);
+    NewTemplateDecl->setImplicit(/*I=*/true);
+    NewTemplateDecl->setLexicalDeclContext(PatternDecl->getLexicalParent());
+    if (PatternDecl->hasAttrs()) {
+      for (auto *Attr : PatternDecl->attrs())
+        NewTemplateDecl->addAttr(Attr);
+    }
+  }
+  FunctionDecl *getTemplateDecl() const { return NewTemplateDecl; }
+  ~MSVCTemplateFunctionRebuilderRAII() {
+    if (NewTemplateDecl) {
+      assert(S.getLangOpts().DelayedTemplateParsing &&
+             S.getLangOpts().MSVCCompat);
+      NewTemplateDecl->setLateTemplateParsed(/*ILT=*/true);
+      S.MSVCInstantiation = OldMSVCInstantiation;
+      if (NewTemplateDecl->isInvalidDecl())
+        PatternDecl->setInvalidDecl(/*Invalid=*/true);
+    }
+  }
+};
+} // namespace
+
 /// \brief Instantiate the definition of the given function from its
 /// template.
 ///
@@ -3553,17 +3687,35 @@
   SavePendingInstantiationsAndVTableUsesRAII
       SavePendingInstantiationsAndVTableUses(*this, /*Enabled=*/Recursive);
 
+  // Do not perform instantiation in MSVC compatibility mode if function is not
+  // used yet. MSVC instantiates function only if it is used.
+  if (getLangOpts().DelayedTemplateParsing && getLangOpts().MSVCCompat &&
+      (Function->isDependentContext() ||
+       (PatternDecl->isLateTemplateParsed() && !DefinitionRequired &&
+        !PatternDecl->isUsed(/*CheckUsedAttr=*/true) && !Function->isUsed())))
+    return;
   // Call the LateTemplateParser callback if there is a need to late parse
   // a templated function definition.
+  LateParsedTemplate NewLPT;
   if (!Pattern && PatternDecl->isLateTemplateParsed() &&
       LateTemplateParser) {
     // FIXME: Optimize to allow individual templates to be deserialized.
     if (PatternDecl->isFromASTFile())
       ExternalSource->ReadLateParsedTemplates(LateParsedTemplateMap);
 
     LateParsedTemplate *LPT = LateParsedTemplateMap.lookup(PatternDecl);
     assert(LPT && "missing LateParsedTemplate");
-    LateTemplateParser(OpaqueParser, *LPT);
+    NewLPT = *LPT;
+  }
+  MSVCTemplateFunctionRebuilderRAII MSVCRebuilder(
+      *this, NewLPT.D ? NewLPT.D->getAsFunction() : nullptr, Function);
+  if (!Pattern && PatternDecl->isLateTemplateParsed() && LateTemplateParser &&
+      NewLPT.D) {
+    if (getLangOpts().DelayedTemplateParsing && getLangOpts().MSVCCompat) {
+      PatternDecl = MSVCRebuilder.getTemplateDecl();
+      NewLPT.D = MSVCRebuilder.getTemplateDecl();
+    }
+    LateTemplateParser(OpaqueParser, NewLPT);
     Pattern = PatternDecl->getBody(PatternDecl);
   }
 
Index: lib/Sema/SemaTemplateInstantiate.cpp
===================================================================
--- lib/Sema/SemaTemplateInstantiate.cpp
+++ lib/Sema/SemaTemplateInstantiate.cpp
@@ -2008,6 +2008,12 @@
     if (Member->getDeclContext() != Pattern)
       continue;
 
+    if (getLangOpts().DelayedTemplateParsing && getLangOpts().MSVCCompat &&
+        Member->isImplicit())
+      if (auto *FD = dyn_cast<FunctionDecl>(Member))
+        if (FD->isLateTemplateParsed())
+          continue;
+
     if (Member->isInvalidDecl()) {
       Instantiation->setInvalidDecl();
       continue;
Index: lib/Sema/SemaTemplate.cpp
===================================================================
--- lib/Sema/SemaTemplate.cpp
+++ lib/Sema/SemaTemplate.cpp
@@ -247,6 +247,21 @@
   return true;
 }
 
+namespace {
+/// Do not perform lookup in instantiations during qualified lookup.
+class MSVCDoNotLookupInInstance {
+  Sema &S;
+  FunctionDecl *MSVCInstantiation = nullptr;
+
+public:
+  MSVCDoNotLookupInInstance(Sema &S)
+      : S(S), MSVCInstantiation(S.MSVCInstantiation) {
+    S.MSVCInstantiation = nullptr;
+  }
+  ~MSVCDoNotLookupInInstance() { S.MSVCInstantiation = MSVCInstantiation; }
+};
+} // namespace
+
 void Sema::LookupTemplateName(LookupResult &Found,
                               Scope *S, CXXScopeSpec &SS,
                               QualType ObjectType,
@@ -300,7 +315,10 @@
       //   expression. If the identifier is not found, it is then looked up in
       //   the context of the entire postfix-expression and shall name a class
       //   or function template.
-      if (S) LookupName(Found, S);
+      if (S) {
+        MSVCDoNotLookupInInstance QualifiedLookupScope(*this);
+        LookupName(Found, S);
+      }
       ObjectTypeSearchedInScope = true;
       AllowFunctionTemplatesInLookup = false;
     }
Index: lib/Sema/SemaLookup.cpp
===================================================================
--- lib/Sema/SemaLookup.cpp
+++ lib/Sema/SemaLookup.cpp
@@ -1027,6 +1027,48 @@
 };
 } // end anonymous namespace
 
+static DeclContext *GetMSVCInstantiationContext(Sema &S, DeclContext *Ctx) {
+  assert(S.getLangOpts().MSVCCompat && S.MSVCInstantiation);
+  if (auto *RD = dyn_cast<CXXRecordDecl>(Ctx)) {
+    for (DeclContext *C = S.MSVCInstantiation; C && !C->isTranslationUnit();
+         C = C->getLookupParent()) {
+      if (auto *InstRD = dyn_cast<CXXRecordDecl>(C))
+        if (isTemplateInstantiation(InstRD->getTemplateSpecializationKind()) &&
+            RD->Equals(InstRD->getTemplateInstantiationPattern()))
+          return C;
+    }
+  }
+  return nullptr;
+}
+
+static bool isBaseClass(const CXXRecordDecl *Record, CXXRecordDecl *Base) {
+  SmallVector<const CXXRecordDecl *, 8> Queue;
+
+  while (true) {
+    for (const auto &I : Record->bases()) {
+      const RecordType *Ty = I.getType()->getAs<RecordType>();
+      if (!Ty)
+        continue;
+
+      CXXRecordDecl *RecBase =
+          cast_or_null<CXXRecordDecl>(Ty->getDecl()->getDefinition());
+      if (!RecBase || (RecBase->isDependentContext() &&
+                       !RecBase->isCurrentInstantiation(Record)))
+        continue;
+
+      Queue.push_back(RecBase);
+      if (RecBase->getCanonicalDecl() == Base)
+        return true;
+    }
+
+    if (Queue.empty())
+      break;
+    Record = Queue.pop_back_val(); // not actually a queue.
+  }
+
+  return false;
+}
+
 bool Sema::CppLookupName(LookupResult &R, Scope *S) {
   assert(getLangOpts().CPlusPlus && "Can perform only C++ lookup");
 
@@ -1214,6 +1256,53 @@
         // identifier chain.
         if (LookupQualifiedName(R, Ctx, /*InUnqualifiedLookup=*/true))
           return true;
+        if (!R.wasNotFoundInCurrentInstantiation() &&
+            getLangOpts().MSVCCompat && MSVCInstantiation) {
+          if (DeclContext *InstCtx = GetMSVCInstantiationContext(*this, Ctx)) {
+            if (LookupQualifiedName(R, InstCtx,
+                                    /*InUnqualifiedLookup=*/true)) {
+              auto *ND = cast<NamedDecl>((*R.begin())->getCanonicalDecl());
+              if (auto *RD = dyn_cast<CXXRecordDecl>(ND)) {
+                if (const auto *Ty = RD->getTypeForDecl()->castAs<RecordType>())
+                  if (Decl *D = Ty->getDecl()->getCanonicalDecl())
+                    ND = cast<NamedDecl>(D);
+              }
+              if (ND->isCXXClassMember()) {
+                auto *Parent = cast<CXXRecordDecl>(ND->getDeclContext())
+                                   ->getCanonicalDecl();
+                auto *DepParent = cast<CXXRecordDecl>(Ctx);
+                bool EnableDiag =
+                    isTemplateInstantiation(
+                        Parent->getTemplateSpecializationKind()) ||
+                    !isBaseClass(DepParent, Parent);
+                if (auto *RD = dyn_cast<CXXRecordDecl>(ND)) {
+                  auto *InstParent = cast<CXXRecordDecl>(InstCtx);
+                  EnableDiag =
+                      (isTemplateInstantiation(
+                           RD->getTemplateSpecializationKind()) &&
+                       InstParent->isProvablyNotDerivedFrom(RD)) ||
+                      (!isTemplateInstantiation(
+                           RD->getTemplateSpecializationKind()) &&
+                       !isBaseClass(DepParent, RD) &&
+                       !(Parent->Encloses(InstCtx) || Parent == InstCtx));
+                }
+                if (EnableDiag) {
+                  auto DB = Diag(R.getNameLoc(),
+                                 diag::ext_found_via_dependent_bases_lookup)
+                            << R.getLookupName();
+                  if (ND->isCXXInstanceMember() && !isa<TypeDecl>(ND))
+                    DB << FixItHint::CreateInsertion(R.getNameLoc(), "this->");
+                }
+                if (!isa<TypeDecl>(ND)) {
+                  R.clear();
+                  R.setNotFoundInCurrentInstantiation();
+                  R.setNamingClass(cast<CXXRecordDecl>(Ctx));
+                }
+              }
+              return true;
+            }
+          }
+        }
       }
     }
   }
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -1900,11 +1900,10 @@
         bool isInstance = CurMethod &&
                           CurMethod->isInstance() &&
                           DC == CurMethod->getParent() && !isDefaultArgument;
-
         // Give a code modification hint to insert 'this->'.
         // TODO: fixit for inserting 'Base<T>::' in the other cases.
         // Actually quite difficult!
-        if (getLangOpts().MSVCCompat)
+        if (getLangOpts().MSVCCompat && !MSVCInstantiation)
           diagnostic = diag::ext_found_via_dependent_bases_lookup;
         if (isInstance) {
           Diag(R.getNameLoc(), diagnostic) << Name
@@ -2108,6 +2107,19 @@
       TemplateArgs);
 }
 
+void Sema::MSVCMakeFakeCXXScopeSpec(LookupResult &R, CXXScopeSpec &SS) const {
+  assert(SS.isEmpty() && getLangOpts().MSVCCompat && MSVCInstantiation);
+  if (R.getNamingClass() &&
+      R.getResultKind() == LookupResult::NotFoundInCurrentInstantiation) {
+    // Synthesize a fake NNS that points to the derived class.  This will
+    // perform name lookup during template instantiation.
+    auto *NNS = NestedNameSpecifier::Create(
+        getASTContext(), nullptr, true, R.getNamingClass()->getTypeForDecl());
+    SourceLocation Loc = R.getNameLoc();
+    SS.MakeTrivial(getASTContext(), NNS, SourceRange(Loc, Loc));
+  }
+}
+
 ExprResult
 Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
                         SourceLocation TemplateKWLoc, UnqualifiedId &Id,
@@ -2171,20 +2183,26 @@
     bool MemberOfUnknownSpecialization;
     LookupTemplateName(R, S, SS, QualType(), /*EnteringContext=*/false,
                        MemberOfUnknownSpecialization);
-    
+
     if (MemberOfUnknownSpecialization ||
-        (R.getResultKind() == LookupResult::NotFoundInCurrentInstantiation))
+        (R.getResultKind() == LookupResult::NotFoundInCurrentInstantiation)) {
+      if (SS.isEmpty() && getLangOpts().MSVCCompat && MSVCInstantiation)
+        MSVCMakeFakeCXXScopeSpec(R, SS);
       return ActOnDependentIdExpression(SS, TemplateKWLoc, NameInfo,
                                         IsAddressOfOperand, TemplateArgs);
+    }
   } else {
     bool IvarLookupFollowUp = II && !SS.isSet() && getCurMethodDecl();
     LookupParsedName(R, S, &SS, !IvarLookupFollowUp);
 
     // If the result might be in a dependent base class, this is a dependent 
     // id-expression.
-    if (R.getResultKind() == LookupResult::NotFoundInCurrentInstantiation)
+    if (R.getResultKind() == LookupResult::NotFoundInCurrentInstantiation) {
+      if (SS.isEmpty() && getLangOpts().MSVCCompat && MSVCInstantiation)
+        MSVCMakeFakeCXXScopeSpec(R, SS);
       return ActOnDependentIdExpression(SS, TemplateKWLoc, NameInfo,
                                         IsAddressOfOperand, TemplateArgs);
+    }
 
     // If this reference is in an Objective-C method, then we need to do
     // some special Objective-C lookup, too.
@@ -2213,7 +2231,7 @@
   bool ADL = UseArgumentDependentLookup(SS, R, HasTrailingLParen);
 
   if (R.empty() && !ADL) {
-    if (SS.isEmpty() && getLangOpts().MSVCCompat) {
+    if (SS.isEmpty() && getLangOpts().MSVCCompat && !MSVCInstantiation) {
       if (Expr *E = recoverFromMSUnqualifiedLookup(*this, Context, NameInfo,
                                                    TemplateKWLoc, TemplateArgs))
         return E;
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -321,9 +321,11 @@
     // Perform unqualified name lookup.
     LookupName(Result, S);
 
+    // Use workaround only in non-instantiation mode.
     // For unqualified lookup in a class template in MSVC mode, look into
     // dependent base classes where the primary class template is known.
-    if (Result.empty() && getLangOpts().MSVCCompat && (!SS || SS->isEmpty())) {
+    if (Result.empty() && getLangOpts().MSVCCompat && (!SS || SS->isEmpty()) &&
+        !MSVCInstantiation) {
       if (ParsedType TypeInBase =
               recoverFromTypeInKnownDependentBase(*this, II, NameLoc))
         return TypeInBase;
@@ -788,9 +790,11 @@
   LookupResult Result(*this, Name, NameLoc, LookupOrdinaryName);
   LookupParsedName(Result, S, &SS, !CurMethod);
 
+  // Use workaround only in non-instantiation mode
   // For unqualified lookup in a class template in MSVC mode, look into
   // dependent base classes where the primary class template is known.
-  if (Result.empty() && SS.isEmpty() && getLangOpts().MSVCCompat) {
+  if (Result.empty() && SS.isEmpty() && getLangOpts().MSVCCompat &&
+      !MSVCInstantiation) {
     if (ParsedType TypeInBase =
             recoverFromTypeInKnownDependentBase(*this, *Name, NameLoc))
       return TypeInBase;
@@ -930,6 +934,8 @@
     // perform some heroics to see if we actually have a
     // template-argument-list, which would indicate a missing 'template'
     // keyword here.
+    if (SS.isEmpty() && getLangOpts().MSVCCompat && MSVCInstantiation)
+      MSVCMakeFakeCXXScopeSpec(Result, SS);
     return ActOnDependentIdExpression(SS, /*TemplateKWLoc=*/SourceLocation(),
                                       NameInfo, IsAddressOfOperand,
                                       /*TemplateArgs=*/nullptr);
Index: lib/Parse/ParseTemplate.cpp
===================================================================
--- lib/Parse/ParseTemplate.cpp
+++ lib/Parse/ParseTemplate.cpp
@@ -1403,7 +1403,8 @@
              "TemplateParameterDepth should be greater than the depth of "
              "current template being instantiated!");
       ParseFunctionStatementBody(LPT.D, FnScope);
-      Actions.UnmarkAsLateParsedTemplate(FunD);
+      if (!getLangOpts().MSVCCompat)
+        Actions.UnmarkAsLateParsedTemplate(FunD);
     } else
       Actions.ActOnFinishFunctionBody(LPT.D, nullptr);
   }
Index: lib/AST/DeclBase.cpp
===================================================================
--- lib/AST/DeclBase.cpp
+++ lib/AST/DeclBase.cpp
@@ -943,6 +943,11 @@
     // context is dependent.
     if (cast<Decl>(this)->getFriendObjectKind())
       return getLexicalParent()->isDependentContext();
+
+    const LangOptions &LO = getParentASTContext().getLangOpts();
+    if (LO.DelayedTemplateParsing && LO.MSVCCompat &&
+        Function->isLateTemplateParsed())
+      return true;
   }
 
   // FIXME: A variable template is a dependent context, but is not a
@@ -1329,9 +1334,14 @@
   // from being visible?
   if (isa<ClassTemplateSpecializationDecl>(D))
     return true;
-  if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
+  if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
     if (FD->isFunctionTemplateSpecialization())
       return true;
+    const LangOptions &LO = FD->getASTContext().getLangOpts();
+    if (LO.DelayedTemplateParsing && LO.MSVCCompat &&
+        FD->isLateTemplateParsed() && FD->isImplicit())
+      return true;
+  }
 
   return false;
 }
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -569,6 +569,8 @@
     OpaqueParser = P;
   }
 
+  FunctionDecl *MSVCInstantiation = nullptr;
+
   class DelayedDiagnostics;
 
   class DelayedDiagnosticsState {
@@ -3799,6 +3801,7 @@
                                 IdentifierInfo *II,
                                 bool AllowBuiltinCreation=false);
 
+  void MSVCMakeFakeCXXScopeSpec(LookupResult &R, CXXScopeSpec &SS) const;
   ExprResult ActOnDependentIdExpression(const CXXScopeSpec &SS,
                                         SourceLocation TemplateKWLoc,
                                         const DeclarationNameInfo &NameInfo,
@@ -9661,7 +9664,7 @@
 struct LateParsedTemplate {
   CachedTokens Toks;
   /// \brief The template function declaration to be late parsed.
-  Decl *D;
+  Decl *D = nullptr;
 };
 
 } // end namespace clang
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to