ahatanak updated this revision to Diff 68078.
ahatanak added a comment.

Fix Sema::getTemplateInstantiationArgs to return the template instantiation 
args when variable templates are being instantiated.


https://reviews.llvm.org/D23096

Files:
  include/clang/Sema/Sema.h
  lib/Sema/SemaTemplate.cpp
  lib/Sema/SemaTemplateInstantiate.cpp
  lib/Sema/SemaTemplateInstantiateDecl.cpp
  test/SemaCXX/vartemplate-lambda.cpp
  test/SemaTemplate/default-expr-arguments-3.cpp

Index: test/SemaTemplate/default-expr-arguments-3.cpp
===================================================================
--- /dev/null
+++ test/SemaTemplate/default-expr-arguments-3.cpp
@@ -0,0 +1,52 @@
+// RUN: %clang_cc1 -std=c++14 -ast-dump %s 2>&1 | FileCheck %s
+
+namespace PR28795 {
+  // CHECK: FunctionDecl{{.*}}func 'void (void)'
+  // CHECK:  LambdaExpr
+  // CHECK:   CXXMethodDecl{{.*}}operator() 'enum foo (enum foo) const' inline
+  // CHECK:    ParmVarDecl{{.*}}f 'enum foo' cinit
+  // CHECK:     DeclRefExpr{{.*}}'enum foo' EnumConstant{{.*}}'a' 'enum foo'
+
+  template<typename T>
+  void func() {
+    enum class foo { a, b };
+    auto bar = [](foo f = foo::a) { return f; };
+    bar();
+  }
+
+  void foo() {
+    func<int>();
+  }
+}
+
+// Template struct case:
+
+// CHECK: ClassTemplateSpecializationDecl{{.*}}struct class2 definition
+// CHECK:  LambdaExpr
+// CHECK:   CXXMethodDecl{{.*}}used operator() 'enum foo (enum foo) const' inline
+// CHECK:    ParmVarDecl{{.*}}f 'enum foo' cinit
+// CHECK:     DeclRefExpr{{.*}}'enum foo' EnumConstant{{.*}}'a' 'enum foo'
+
+template <class T> struct class2 {
+  void bar() {
+    enum class foo { a, b };
+    [](foo f = foo::a) { return f; }();
+  }
+};
+
+template struct class2<int>;
+
+// CHECK: FunctionDecl{{.*}}f1 'void (void)'
+// CHECK:  CXXMethodDecl{{.*}}g1 'int (enum foo)'
+// CHECK:   ParmVarDecl{{.*}}n 'enum foo' cinit
+// CHECK:    DeclRefExpr{{.*}}'enum foo' EnumConstant{{.*}}'a' 'enum foo'
+
+template<typename T>
+void f1() {
+  enum class foo { a, b };
+  struct S {
+    int g1(foo n = foo::a);
+  };
+}
+
+template void f1<int>();
Index: test/SemaCXX/vartemplate-lambda.cpp
===================================================================
--- test/SemaCXX/vartemplate-lambda.cpp
+++ test/SemaCXX/vartemplate-lambda.cpp
@@ -1,15 +1,22 @@
 // RUN: %clang_cc1 -std=c++14 -fsyntax-only -verify %s
-// expected-no-diagnostics
 
 template <class> auto fn0 = [] {};
 template <typename> void foo0() { fn0<char>(); }
 
 template<typename T> auto fn1 = [](auto a) { return a + T(1); };
+template<typename T> auto v1 = [](int a = T(1)) { return a; }();
+
+struct S {
+  template<class T>
+  static constexpr T t = [](int f = T(7)){return f;}(); // expected-error{{constexpr variable 't<int>' must be initialized by a constant expression}} expected-error{{a lambda expression may not appear inside of a constant expression}} expected-note{{cannot be used in a constant expression}}
+};
 
 template <typename X>
 int foo2() {
   X a = 0x61;
   fn1<char>(a);
+  (void)v1<int>;
+  (void)S::t<int>; // expected-note{{in instantiation of static data member 'S::t<int>' requested here}}
   return 0;
 }
 
Index: lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -3728,7 +3728,8 @@
   if (FromVar->isInvalidDecl())
     return nullptr;
 
-  InstantiatingTemplate Inst(*this, PointOfInstantiation, FromVar);
+  InstantiatingTemplate Inst(*this, PointOfInstantiation, FromVar,
+                             SourceRange(), TemplateArgList.asArray());
   if (Inst.isInvalid())
     return nullptr;
 
@@ -4022,7 +4023,8 @@
         !Var->hasInit()) {
       // FIXME: Factor out the duplicated instantiation context setup/tear down
       // code here.
-      InstantiatingTemplate Inst(*this, PointOfInstantiation, Var);
+      InstantiatingTemplate Inst(*this, PointOfInstantiation, Var,
+                                 SourceRange(), TemplateArgs.getInnermost());
       if (Inst.isInvalid())
         return;
       PrettyDeclStackTraceEntry CrashInfo(*this, Var, SourceLocation(),
Index: lib/Sema/SemaTemplateInstantiate.cpp
===================================================================
--- lib/Sema/SemaTemplateInstantiate.cpp
+++ lib/Sema/SemaTemplateInstantiate.cpp
@@ -57,9 +57,16 @@
   // Accumulate the set of template argument lists in this structure.
   MultiLevelTemplateArgumentList Result;
 
+  ArrayRef<TemplateArgument> VarTemplateArgs = varTemplateArguments();
+
+  if (!VarTemplateArgs.empty()) {
+    Result.addOuterTemplateArguments(VarTemplateArgs);
+    return Result;
+  }
+
   if (Innermost)
     Result.addOuterTemplateArguments(Innermost);
-  
+
   DeclContext *Ctx = dyn_cast<DeclContext>(D);
   if (!Ctx) {
     Ctx = D->getDeclContext();
@@ -183,6 +190,19 @@
   return Result;
 }
 
+ArrayRef<TemplateArgument> Sema::varTemplateArguments() const {
+  if (ActiveTemplateInstantiations.empty())
+    return ArrayRef<TemplateArgument>();
+
+  const auto &Inst = ActiveTemplateInstantiations.back();
+
+  if (const auto *VD = dyn_cast_or_null<VarDecl>(Inst.Entity))
+    if (VD->getDescribedVarTemplate() || VD->getTemplateSpecializationKind())
+      return Inst.template_arguments();
+
+  return ArrayRef<TemplateArgument>();
+}
+
 bool Sema::ActiveTemplateInstantiation::isInstantiationRecord() const {
   switch (Kind) {
   case TemplateInstantiation:
@@ -234,10 +254,11 @@
 
 Sema::InstantiatingTemplate::InstantiatingTemplate(
     Sema &SemaRef, SourceLocation PointOfInstantiation, Decl *Entity,
-    SourceRange InstantiationRange)
+    SourceRange InstantiationRange, ArrayRef<TemplateArgument> TemplateArgs)
     : InstantiatingTemplate(SemaRef,
                             ActiveTemplateInstantiation::TemplateInstantiation,
-                            PointOfInstantiation, InstantiationRange, Entity) {}
+                            PointOfInstantiation, InstantiationRange, Entity,
+                            nullptr, TemplateArgs) {}
 
 Sema::InstantiatingTemplate::InstantiatingTemplate(
     Sema &SemaRef, SourceLocation PointOfInstantiation, FunctionDecl *Entity,
@@ -1670,7 +1691,7 @@
       // Instantiate default arguments for methods of local classes (DR1484)
       // and non-defining declarations.
       Sema::ContextRAII SavedContext(*this, OwningFunc);
-      LocalInstantiationScope Local(*this);
+      LocalInstantiationScope Local(*this, true);
       ExprResult NewArg = SubstExpr(Arg, TemplateArgs);
       if (NewArg.isUsable()) {
         // It would be nice if we still had this.
Index: lib/Sema/SemaTemplate.cpp
===================================================================
--- lib/Sema/SemaTemplate.cpp
+++ lib/Sema/SemaTemplate.cpp
@@ -429,7 +429,12 @@
   bool MightBeCxx11UnevalField =
       getLangOpts().CPlusPlus11 && isUnevaluatedContext();
 
-  if (!MightBeCxx11UnevalField && !isAddressOfOperand &&
+  // Check if the nested name specifier is an enum type.
+  bool IsEnum = false;
+  if (NestedNameSpecifier *NNS = SS.getScopeRep())
+    IsEnum = dyn_cast_or_null<EnumType>(NNS->getAsType());
+
+  if (!MightBeCxx11UnevalField && !isAddressOfOperand && !IsEnum &&
       isa<CXXMethodDecl>(DC) && cast<CXXMethodDecl>(DC)->isInstance()) {
     QualType ThisType = cast<CXXMethodDecl>(DC)->getThisType(Context);
 
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -6616,6 +6616,8 @@
                                bool RelativeToPrimary = false,
                                const FunctionDecl *Pattern = nullptr);
 
+  ArrayRef<TemplateArgument> varTemplateArguments() const;
+
   /// \brief A template instantiation that is currently in progress.
   struct ActiveTemplateInstantiation {
     /// \brief The kind of template instantiation we are performing
@@ -6835,9 +6837,10 @@
     /// \brief Note that we are instantiating a class template,
     /// function template, variable template, alias template,
     /// or a member thereof.
-    InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
-                          Decl *Entity,
-                          SourceRange InstantiationRange = SourceRange());
+    InstantiatingTemplate(
+        Sema &SemaRef, SourceLocation PointOfInstantiation, Decl *Entity,
+        SourceRange InstantiationRange = SourceRange(),
+        ArrayRef<TemplateArgument> TemplateArgs = ArrayRef<TemplateArgument>());
 
     struct ExceptionSpecification {};
     /// \brief Note that we are instantiating an exception specification
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to