aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/DeclCXX.h35
-rw-r--r--include/clang/Sema/Sema.h6
-rw-r--r--lib/AST/DeclBase.cpp8
-rw-r--r--lib/AST/DeclCXX.cpp4
-rw-r--r--lib/Sema/SemaExpr.cpp26
-rw-r--r--lib/Sema/SemaLambda.cpp15
-rw-r--r--lib/Serialization/ASTReaderDecl.cpp3
-rw-r--r--lib/Serialization/ASTWriter.cpp1
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/p13.cpp6
9 files changed, 85 insertions, 19 deletions
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h
index 453db168b4..45bb647a65 100644
--- a/include/clang/AST/DeclCXX.h
+++ b/include/clang/AST/DeclCXX.h
@@ -560,18 +560,28 @@ class CXXRecordDecl : public RecordDecl {
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 @@ public:
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 @@ public:
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;
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 29d3862b4b..7e3103cfa2 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -2386,7 +2386,8 @@ public:
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 @@ public:
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,
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);
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p13.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p13.cpp
index 53f458a824..8bb707e0db 100644
--- a/test/CXX/expr/expr.prim/expr.prim.lambda/p13.cpp
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p13.cpp
@@ -8,3 +8,9 @@ void f2() {
void g4(int = ([=]{ return 0; })());
void g5(int = ([]{ return sizeof i; })());
}
+
+namespace lambda_in_default_args {
+ int f(int = [] () -> int { int n; return ++n; } ());
+ template<typename T> T g(T = [] () -> T { T n; return ++n; } ());
+ int k = f() + g<int>();
+}