ahatanak created this revision.
ahatanak added a reviewer: rsmith.
ahatanak added a subscriber: cfe-commits.

I'm sending a WIP patch which fixes PR27015 to get an early feedback from the 
community.

This patch attempts to fix a crash which happens when a variable template is 
initialized with a generic lambda expression. Please see the example in the 
email I sent to cfe-dev:

http://lists.llvm.org/pipermail/cfe-dev/2016-April/048391.html

This patch makes changes to ensure the instantiated lambda class (which is the 
lambda class for fn<char> in the example) gets the right parent DeclContex 
(which is Decl::TranslationUnit in the example). After applying this patch, 
clang no longer crash compiling the example program. However, it still crashes 
when it compiles the following code:

$ cat test0.cpp
template <class> auto fn = [] {};
template <typename> void fn1() { fn<char>; }

$ clang -std=c++14 -c -o /dev/null  test0.cpp 

Assertion failed: (isDependentContext() && "cannot iterate dependent 
diagnostics of non-dependent context"), function ddiags, file 
include/clang/AST/DependentDiagnostic.h, line 176.
...
10 clang-3.8                0x000000010b4afd18 
clang::Sema::PerformDependentDiagnostics(clang::DeclContext const*, 
clang::MultiLevelTemplateArgumentList const&) + 40
11 clang-3.8                0x000000010b46ee1b (anonymous 
namespace)::TemplateInstantiator::transformedLocalDecl(clang::Decl*, 
clang::Decl*) + 251

It fails when DeclContext::ddiags() is called on the lambda class of the old 
lambda expression because it's not a dependent context.

http://reviews.llvm.org/D19175

Files:
  include/clang/Sema/Sema.h
  lib/Sema/SemaLambda.cpp
  lib/Sema/SemaTemplateInstantiate.cpp
  lib/Sema/SemaTemplateInstantiateDecl.cpp
  lib/Sema/TreeTransform.h

Index: lib/Sema/TreeTransform.h
===================================================================
--- lib/Sema/TreeTransform.h
+++ lib/Sema/TreeTransform.h
@@ -118,9 +118,13 @@
   /// rather than in the subclass (e.g., lambda closure types).
   llvm::DenseMap<Decl *, Decl *> TransformedLocalDecls;
 
+  /// If not null, this is the variable being initialized.
+  VarDecl *VarInit;
+
 public:
   /// \brief Initializes a new tree transformer.
-  TreeTransform(Sema &SemaRef) : SemaRef(SemaRef) { }
+  TreeTransform(Sema &SemaRef, VarDecl *Var = nullptr)
+      : SemaRef(SemaRef), VarInit(Var) {}
 
   /// \brief Retrieves a reference to the derived class.
   Derived &getDerived() { return static_cast<Derived&>(*this); }
@@ -10043,11 +10047,18 @@
   LSI->GLTemplateParameterList = TPL;
 
   // Create the local class that will describe the lambda.
+  // If the new lambda is used to initialize a variable template specialization,
+  // use the old lambda's DeclContext.
+  DeclContext *DC = nullptr;
+
+  if (VarInit && isa<VarTemplateSpecializationDecl>(VarInit))
+    DC = E->getLambdaClass()->getParent();
+
   CXXRecordDecl *Class
     = getSema().createLambdaClosureType(E->getIntroducerRange(),
                                         NewCallOpTSI,
                                         /*KnownDependent=*/false,
-                                        E->getCaptureDefault());
+                                        E->getCaptureDefault(), DC);
   getDerived().transformedLocalDecl(E->getLambdaClass(), Class);
 
   // Build the call operator.
Index: lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -3898,7 +3898,7 @@
     // Instantiate the initializer.
     ExprResult Init =
         SubstInitializer(OldVar->getInit(), TemplateArgs,
-                         OldVar->getInitStyle() == VarDecl::CallInit);
+                         OldVar->getInitStyle() == VarDecl::CallInit, Var);
     if (!Init.isInvalid()) {
       bool TypeMayContainAuto = true;
       Expr *InitExpr = Init.get();
Index: lib/Sema/SemaTemplateInstantiate.cpp
===================================================================
--- lib/Sema/SemaTemplateInstantiate.cpp
+++ lib/Sema/SemaTemplateInstantiate.cpp
@@ -633,8 +633,8 @@
     TemplateInstantiator(Sema &SemaRef,
                          const MultiLevelTemplateArgumentList &TemplateArgs,
                          SourceLocation Loc,
-                         DeclarationName Entity)
-      : inherited(SemaRef), TemplateArgs(TemplateArgs), Loc(Loc),
+                         DeclarationName Entity, VarDecl *VarInit = nullptr)
+      : inherited(SemaRef, VarInit), TemplateArgs(TemplateArgs), Loc(Loc),
         Entity(Entity) { }
 
     /// \brief Determine whether the given type \p T has already been
@@ -2665,10 +2665,10 @@
 
 ExprResult Sema::SubstInitializer(Expr *Init,
                           const MultiLevelTemplateArgumentList &TemplateArgs,
-                          bool CXXDirectInit) {
+                          bool CXXDirectInit, VarDecl *VarInit) {
   TemplateInstantiator Instantiator(*this, TemplateArgs,
                                     SourceLocation(),
-                                    DeclarationName());
+                                    DeclarationName(), VarInit);
   return Instantiator.TransformInitializer(Init, CXXDirectInit);
 }
 
Index: lib/Sema/SemaLambda.cpp
===================================================================
--- lib/Sema/SemaLambda.cpp
+++ lib/Sema/SemaLambda.cpp
@@ -243,10 +243,14 @@
 CXXRecordDecl *Sema::createLambdaClosureType(SourceRange IntroducerRange,
                                              TypeSourceInfo *Info,
                                              bool KnownDependent, 
-                                             LambdaCaptureDefault CaptureDefault) {
-  DeclContext *DC = CurContext;
-  while (!(DC->isFunctionOrMethod() || DC->isRecord() || DC->isFileContext()))
-    DC = DC->getParent();
+                                             LambdaCaptureDefault CaptureDefault,
+                                             DeclContext *DC) {
+  if (!DC) {
+    DC = CurContext;
+    while (!(DC->isFunctionOrMethod() || DC->isRecord() || DC->isFileContext()))
+      DC = DC->getParent();
+  }
+
   bool IsGenericLambda = getGenericLambdaTemplateParameterList(getCurLambda(),
                                                                *this);  
   // Start constructing the lambda class.
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -5014,7 +5014,8 @@
   CXXRecordDecl *createLambdaClosureType(SourceRange IntroducerRange,
                                          TypeSourceInfo *Info,
                                          bool KnownDependent, 
-                                         LambdaCaptureDefault CaptureDefault);
+                                         LambdaCaptureDefault CaptureDefault,
+                                         DeclContext *DC = nullptr);
 
   /// \brief Start the definition of a lambda expression.
   CXXMethodDecl *startLambdaDefinition(CXXRecordDecl *Class,
@@ -7095,7 +7096,7 @@
 
   ExprResult SubstInitializer(Expr *E,
                        const MultiLevelTemplateArgumentList &TemplateArgs,
-                       bool CXXDirectInit);
+                       bool CXXDirectInit, VarDecl *VarInit = nullptr);
 
   bool
   SubstBaseSpecifiers(CXXRecordDecl *Instantiation,
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to