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