On Tue, Feb 21, 2012 at 11:11 AM, Douglas Gregor <[email protected]> wrote: > Author: dgregor > Date: Tue Feb 21 13:11:17 2012 > New Revision: 151076 > > URL: http://llvm.org/viewvc/llvm-project?rev=151076&view=rev > Log: > Improve our handling of lambda expressions that occur within default > arguments. There are two aspects to this: > > - Make sure that when marking the declarations referenced in a > default argument, we don't try to mark local variables, both because > it's a waste of time and because the semantics are wrong: we're not > in a place where we could capture these variables again even if it > did make sense. > - When a lambda expression occurs in a default argument of a > function template, make sure that the corresponding closure type is > considered dependent, so that it will get properly instantiated. The > second bit is a bit of a hack; to fix it properly, we may have to > rearchitect our handling of default arguments, parsing them only > after creating the function definition. However, I'd like to > separate that work from the lambdas work. > > > Modified: > cfe/trunk/include/clang/AST/DeclCXX.h > cfe/trunk/include/clang/Sema/Sema.h > cfe/trunk/lib/AST/DeclBase.cpp > cfe/trunk/lib/AST/DeclCXX.cpp > cfe/trunk/lib/Sema/SemaExpr.cpp > cfe/trunk/lib/Sema/SemaLambda.cpp > cfe/trunk/lib/Serialization/ASTReaderDecl.cpp > cfe/trunk/lib/Serialization/ASTWriter.cpp > cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p13.cpp > > Modified: cfe/trunk/include/clang/AST/DeclCXX.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=151076&r1=151075&r2=151076&view=diff > ============================================================================== > --- cfe/trunk/include/clang/AST/DeclCXX.h (original) > +++ cfe/trunk/include/clang/AST/DeclCXX.h Tue Feb 21 13:11:17 2012 > @@ -560,18 +560,28 @@ > struct LambdaDefinitionData : public DefinitionData { > typedef LambdaExpr::Capture Capture; > > - LambdaDefinitionData(CXXRecordDecl *D) > - : DefinitionData(D), NumCaptures(0), NumExplicitCaptures(0), > - ContextDecl(0), Captures(0) > + LambdaDefinitionData(CXXRecordDecl *D, bool Dependent) > + : DefinitionData(D), Dependent(Dependent), NumCaptures(0), > + NumExplicitCaptures(0), ManglingNumber(0), ContextDecl(0), > Captures(0) > { > IsLambda = true; > } > > + /// \brief Whether this lambda is known to be dependent, even if its > + /// context isn't dependent. > + /// > + /// A lambda with a non-dependent context can be dependent if it occurs > + /// within the default argument of a function template, because the > + /// lambda will have been created with the enclosing context as its > + /// declaration context, rather than function. This is an unfortunate > + /// artifact of having to parse the default arguments before > + unsigned Dependent : 1; > + > /// \brief The number of captures in this lambda. > unsigned NumCaptures : 16; > > /// \brief The number of explicit captures in this lambda. > - unsigned NumExplicitCaptures : 16; > + unsigned NumExplicitCaptures : 15; > > /// \brief The number used to indicate this lambda expression for name > /// mangling in the Itanium C++ ABI. > @@ -689,7 +699,7 @@ > IdentifierInfo *Id, CXXRecordDecl* PrevDecl=0, > bool DelayTypeCreation = false); > static CXXRecordDecl *CreateLambda(const ASTContext &C, DeclContext *DC, > - SourceLocation Loc); > + SourceLocation Loc, bool > DependentLambda); > static CXXRecordDecl *CreateDeserialized(const ASTContext &C, unsigned ID); > > bool isDynamicClass() const { > @@ -1478,6 +1488,21 @@ > return getLambdaData().ContextDecl; > } > > + /// \brief Determine whether this lambda expression was known to be > dependent > + /// at the time it was created, even if its context does not appear to be > + /// dependent. > + /// > + /// This flag is a workaround for an issue with parsing, where default > + /// arguments are parsed before their enclosing function declarations have > + /// been created. This means that any lambda expressions within those > + /// default arguments will have as their DeclContext the context enclosing > + /// the function declaration, which may be non-dependent even when the > + /// function declaration itself is dependent. This flag indicates when we > + /// know that the lambda is dependent despite that. > + bool isDependentLambda() const { > + return isLambda() && getLambdaData().Dependent; > + } > + > static bool classof(const Decl *D) { return classofKind(D->getKind()); } > static bool classofKind(Kind K) { > return K >= firstCXXRecord && K <= lastCXXRecord; > > Modified: cfe/trunk/include/clang/Sema/Sema.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=151076&r1=151075&r2=151076&view=diff > ============================================================================== > --- cfe/trunk/include/clang/Sema/Sema.h (original) > +++ cfe/trunk/include/clang/Sema/Sema.h Tue Feb 21 13:11:17 2012 > @@ -2386,7 +2386,8 @@ > QualType getCapturedDeclRefType(VarDecl *Var, SourceLocation Loc); > > void MarkDeclarationsReferencedInType(SourceLocation Loc, QualType T); > - void MarkDeclarationsReferencedInExpr(Expr *E); > + void MarkDeclarationsReferencedInExpr(Expr *E, > + bool SkipLocalVariables = false); > > /// \brief Try to recover by turning the given expression into a > /// call. Returns true if recovery was attempted or an error was > @@ -3543,7 +3544,8 @@ > void ActOnCXXExitDeclInitializer(Scope *S, Decl *Dcl); > > /// \brief Create a new lambda closure type. > - CXXRecordDecl *createLambdaClosureType(SourceRange IntroducerRange); > + CXXRecordDecl *createLambdaClosureType(SourceRange IntroducerRange, > + bool KnownDependent = false); > > /// \brief Start the definition of a lambda expression. > CXXMethodDecl *startLambdaDefinition(CXXRecordDecl *Class, > > Modified: cfe/trunk/lib/AST/DeclBase.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclBase.cpp?rev=151076&r1=151075&r2=151076&view=diff > ============================================================================== > --- cfe/trunk/lib/AST/DeclBase.cpp (original) > +++ cfe/trunk/lib/AST/DeclBase.cpp Tue Feb 21 13:11:17 2012 > @@ -741,10 +741,14 @@ > if (isa<ClassTemplatePartialSpecializationDecl>(this)) > return true; > > - if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(this)) > + if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(this)) { > if (Record->getDescribedClassTemplate()) > return true; > - > + > + if (Record->isDependentLambda()) > + return true; > + } > + > if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(this)) { > if (Function->getDescribedFunctionTemplate()) > return true; > > Modified: cfe/trunk/lib/AST/DeclCXX.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=151076&r1=151075&r2=151076&view=diff > ============================================================================== > --- cfe/trunk/lib/AST/DeclCXX.cpp (original) > +++ cfe/trunk/lib/AST/DeclCXX.cpp Tue Feb 21 13:11:17 2012 > @@ -83,11 +83,11 @@ > } > > CXXRecordDecl *CXXRecordDecl::CreateLambda(const ASTContext &C, DeclContext > *DC, > - SourceLocation Loc) { > + SourceLocation Loc, bool > Dependent) { > CXXRecordDecl* R = new (C) CXXRecordDecl(CXXRecord, TTK_Class, DC, Loc, Loc, > 0, 0); > R->IsBeingDefined = true; > - R->DefinitionData = new (C) struct LambdaDefinitionData(R); > + R->DefinitionData = new (C) struct LambdaDefinitionData(R, Dependent); > C.getTypeDeclType(R, /*PrevDecl=*/0); > return R; > } > > Modified: cfe/trunk/lib/Sema/SemaExpr.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=151076&r1=151075&r2=151076&view=diff > ============================================================================== > --- cfe/trunk/lib/Sema/SemaExpr.cpp (original) > +++ cfe/trunk/lib/Sema/SemaExpr.cpp Tue Feb 21 13:11:17 2012 > @@ -3146,7 +3146,8 @@ > // We already type-checked the argument, so we know it works. > // Just mark all of the declarations in this potentially-evaluated > expression > // as being "referenced". > - MarkDeclarationsReferencedInExpr(Param->getDefaultArg()); > + MarkDeclarationsReferencedInExpr(Param->getDefaultArg(), > + /*SkipLocalVariables=*/true); > return Owned(CXXDefaultArgExpr::Create(Context, CallLoc, Param)); > } > > @@ -10145,13 +10146,22 @@ > /// potentially-evaluated subexpressions as "referenced". > class EvaluatedExprMarker : public > EvaluatedExprVisitor<EvaluatedExprMarker> { > Sema &S; > + bool SkipLocalVariables; > > public: > typedef EvaluatedExprVisitor<EvaluatedExprMarker> Inherited; > > - explicit EvaluatedExprMarker(Sema &S) : Inherited(S.Context), S(S) { } > + EvaluatedExprMarker(Sema &S, bool SkipLocalVariables) > + : Inherited(S.Context), S(S), SkipLocalVariables(SkipLocalVariables) { > } > > void VisitDeclRefExpr(DeclRefExpr *E) { > + // If we were asked not to visit local variables, don't. > + if (SkipLocalVariables) { > + if (VarDecl *VD = dyn_cast<VarDecl>(E->getDecl())) > + if (VD->hasLocalStorage()) > + return; > + } > + > S.MarkDeclRefReferenced(E); > } > > @@ -10193,6 +10203,10 @@ > } > > void VisitBlockDeclRefExpr(BlockDeclRefExpr *E) { > + // If we were asked not to visit local variables, don't. > + if (SkipLocalVariables && E->getDecl()->hasLocalStorage()) > + return;
What exactly are the rules for odr-use marking inside a lambda in a default argument, actually? -Eli _______________________________________________ cfe-commits mailing list [email protected] http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
