diff options
author | Douglas Gregor <dgregor@apple.com> | 2012-02-21 19:11:17 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2012-02-21 19:11:17 +0000 |
commit | f4b7de1cef3007cc0479775638198287384d9af1 (patch) | |
tree | 58f71d3db597c7a0951820a96177157b77488bae /lib | |
parent | f18a87b1ce1be5ccc3b6b3dbd4f15374710e237b (diff) |
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.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@151076 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r-- | lib/AST/DeclBase.cpp | 8 | ||||
-rw-r--r-- | lib/AST/DeclCXX.cpp | 4 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 26 | ||||
-rw-r--r-- | lib/Sema/SemaLambda.cpp | 15 | ||||
-rw-r--r-- | lib/Serialization/ASTReaderDecl.cpp | 3 | ||||
-rw-r--r-- | lib/Serialization/ASTWriter.cpp | 1 |
6 files changed, 45 insertions, 12 deletions
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index a507215aa8..efbc5f9923 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -741,10 +741,14 @@ bool DeclContext::isDependentContext() const { 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; diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index a4d8220625..9840cc7820 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -83,11 +83,11 @@ CXXRecordDecl *CXXRecordDecl::Create(const ASTContext &C, TagKind TK, } 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; } diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 1008a3ab43..be3fa6c0dc 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -3146,7 +3146,8 @@ ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc, // 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 @@ namespace { /// 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 @@ namespace { } void VisitBlockDeclRefExpr(BlockDeclRefExpr *E) { + // If we were asked not to visit local variables, don't. + if (SkipLocalVariables && E->getDecl()->hasLocalStorage()) + return; + S.MarkBlockDeclRefReferenced(E); } @@ -10211,8 +10225,12 @@ namespace { /// \brief Mark any declarations that appear within this expression or any /// potentially-evaluated subexpressions as "referenced". -void Sema::MarkDeclarationsReferencedInExpr(Expr *E) { - EvaluatedExprMarker(*this).Visit(E); +/// +/// \param SkipLocalVariables If true, don't mark local variables as +/// 'referenced'. +void Sema::MarkDeclarationsReferencedInExpr(Expr *E, + bool SkipLocalVariables) { + EvaluatedExprMarker(*this, SkipLocalVariables).Visit(E); } /// \brief Emit a diagnostic that describes an effect on the run-time behavior diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp index 694fee6776..42040084e1 100644 --- a/lib/Sema/SemaLambda.cpp +++ b/lib/Sema/SemaLambda.cpp @@ -21,14 +21,16 @@ using namespace clang; using namespace sema; -CXXRecordDecl *Sema::createLambdaClosureType(SourceRange IntroducerRange) { +CXXRecordDecl *Sema::createLambdaClosureType(SourceRange IntroducerRange, + bool KnownDependent) { DeclContext *DC = CurContext; while (!(DC->isFunctionOrMethod() || DC->isRecord() || DC->isFileContext())) DC = DC->getParent(); // Start constructing the lambda class. CXXRecordDecl *Class = CXXRecordDecl::CreateLambda(Context, DC, - IntroducerRange.getBegin()); + IntroducerRange.getBegin(), + KnownDependent); DC->addDecl(Class); return Class; @@ -142,7 +144,14 @@ void Sema::addLambdaParameters(CXXMethodDecl *CallOperator, Scope *CurScope) { void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, Declarator &ParamInfo, Scope *CurScope) { - CXXRecordDecl *Class = createLambdaClosureType(Intro.Range); + // Determine if we're within a context where we know that the lambda will + // be dependent, because there are template parameters in scope. + bool KnownDependent = false; + if (Scope *TmplScope = CurScope->getTemplateParamParent()) + if (!TmplScope->decl_empty()) + KnownDependent = true; + + CXXRecordDecl *Class = createLambdaClosureType(Intro.Range, KnownDependent); // Determine the signature of the call operator. TypeSourceInfo *MethodTyInfo; diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index c2a93b99fa..fe09cdafa7 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -1107,6 +1107,7 @@ void ASTDeclReader::ReadCXXDefinitionData( typedef LambdaExpr::Capture Capture; CXXRecordDecl::LambdaDefinitionData &Lambda = static_cast<CXXRecordDecl::LambdaDefinitionData &>(Data); + Lambda.Dependent = Record[Idx++]; Lambda.NumCaptures = Record[Idx++]; Lambda.NumExplicitCaptures = Record[Idx++]; Lambda.ManglingNumber = Record[Idx++]; @@ -1134,7 +1135,7 @@ void ASTDeclReader::VisitCXXRecordDecl(CXXRecordDecl *D) { // allocate the appropriate DefinitionData structure. bool IsLambda = Record[Idx++]; if (IsLambda) - D->DefinitionData = new (C) CXXRecordDecl::LambdaDefinitionData(D); + D->DefinitionData = new (C) CXXRecordDecl::LambdaDefinitionData(D, false); else D->DefinitionData = new (C) struct CXXRecordDecl::DefinitionData(D); diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index 5c3a1e93f6..8dbd6e4471 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -4330,6 +4330,7 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec // Add lambda-specific data. if (Data.IsLambda) { CXXRecordDecl::LambdaDefinitionData &Lambda = D->getLambdaData(); + Record.push_back(Lambda.Dependent); Record.push_back(Lambda.NumCaptures); Record.push_back(Lambda.NumExplicitCaptures); Record.push_back(Lambda.ManglingNumber); |