Per Richard's suggestion, I moved the creation of the initializer expression
(including analysis of conversion and generation of implicit functions)
following the popping off of the lambda's call operator. This solution seems
to work well.
In passing the following bug regarding VLA's was also fixed:
void foo(int I) {
int v[I];
int x[10];
auto L = [=, &v] (int n) { return v[n] + x[n]; } // Now works
}
Thanks!
}
http://reviews.llvm.org/D6171
Files:
include/clang/Sema/ScopeInfo.h
lib/Sema/SemaDecl.cpp
lib/Sema/SemaExpr.cpp
lib/Sema/SemaLambda.cpp
test/CXX/expr/expr.prim/expr.prim.lambda/p2.cpp
test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp
test/SemaCXX/cxx1y-generic-lambdas-pr20619.cpp
EMAIL PREFERENCES
http://reviews.llvm.org/settings/panel/emailpreferences/
Index: include/clang/Sema/ScopeInfo.h
===================================================================
--- include/clang/Sema/ScopeInfo.h
+++ include/clang/Sema/ScopeInfo.h
@@ -410,14 +410,17 @@
/// non-static data member that would hold the capture.
QualType CaptureType;
+ /// \brief Does this represent an init capture: [x = move(x)]{ ... }
+ bool IsInitCapture;
public:
Capture(VarDecl *Var, bool Block, bool ByRef, bool IsNested,
SourceLocation Loc, SourceLocation EllipsisLoc,
- QualType CaptureType, Expr *Cpy)
+ QualType CaptureType, Expr *Cpy, bool IsInitCapture)
: VarAndNested(Var, IsNested),
InitExprAndCaptureKind(Cpy, Block ? Cap_Block :
ByRef ? Cap_ByRef : Cap_ByCopy),
- Loc(Loc), EllipsisLoc(EllipsisLoc), CaptureType(CaptureType) {}
+ Loc(Loc), EllipsisLoc(EllipsisLoc), CaptureType(CaptureType),
+ IsInitCapture(IsInitCapture) {}
enum IsThisCapture { ThisCapture };
Capture(IsThisCapture, bool IsNested, SourceLocation Loc,
@@ -424,8 +427,11 @@
QualType CaptureType, Expr *Cpy)
: VarAndNested(nullptr, IsNested),
InitExprAndCaptureKind(Cpy, Cap_This),
- Loc(Loc), EllipsisLoc(), CaptureType(CaptureType) {}
+ Loc(Loc), EllipsisLoc(), CaptureType(CaptureType),
+ IsInitCapture(false) {}
+ bool isInitCapture() const { return IsInitCapture; }
+
bool isThisCapture() const {
return InitExprAndCaptureKind.getInt() == Cap_This;
}
@@ -495,9 +501,9 @@
void addCapture(VarDecl *Var, bool isBlock, bool isByref, bool isNested,
SourceLocation Loc, SourceLocation EllipsisLoc,
- QualType CaptureType, Expr *Cpy) {
+ QualType CaptureType, Expr *Cpy, bool IsInitCapture) {
Captures.push_back(Capture(Var, isBlock, isByref, isNested, Loc,
- EllipsisLoc, CaptureType, Cpy));
+ EllipsisLoc, CaptureType, Cpy, IsInitCapture));
CaptureMap[Var] = Captures.size();
}
@@ -505,7 +511,7 @@
Captures.push_back(Capture(/*Var*/ nullptr, /*isBlock*/ false,
/*isByref*/ false, /*isNested*/ false, Loc,
/*EllipsisLoc*/ SourceLocation(), CaptureType,
- /*Cpy*/ nullptr));
+ /*Cpy*/ nullptr, /*IsInitCapture*/false));
}
void addThisCapture(bool isNested, SourceLocation Loc, QualType CaptureType,
@@ -648,13 +654,6 @@
/// \brief Whether the lambda contains an unexpanded parameter pack.
bool ContainsUnexpandedParameterPack;
- /// \brief Variables used to index into by-copy array captures.
- SmallVector<VarDecl *, 4> ArrayIndexVars;
-
- /// \brief Offsets into the ArrayIndexVars array at which each capture starts
- /// its list of array index variables.
- SmallVector<unsigned, 4> ArrayIndexStarts;
-
/// \brief If this is a generic lambda, use this as the depth of
/// each 'auto' parameter, during initial AST construction.
unsigned AutoTemplateParameterDepth;
@@ -842,9 +841,6 @@
Captures.push_back(Capture(Capture::ThisCapture, isNested, Loc, CaptureType,
Cpy));
CXXThisCaptureIndex = Captures.size();
-
- if (LambdaScopeInfo *LSI = dyn_cast<LambdaScopeInfo>(this))
- LSI->ArrayIndexStarts.push_back(LSI->ArrayIndexVars.size());
}
} // end namespace sema
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -10251,7 +10251,7 @@
/*RefersToEnclosingVariableOrCapture*/true, C.getLocation(),
/*EllipsisLoc*/C.isPackExpansion()
? C.getEllipsisLoc() : SourceLocation(),
- CaptureType, /*Expr*/ nullptr);
+ CaptureType, /*Expr*/ nullptr, C.isInitCapture());
} else if (C.capturesThis()) {
LSI->addThisCapture(/*Nested*/ false, C.getLocation(),
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -12137,7 +12137,8 @@
// Actually capture the variable.
if (BuildAndDiagnose)
BSI->addCapture(Var, HasBlocksAttr, ByRef, Nested, Loc,
- SourceLocation(), CaptureType, CopyExpr);
+ SourceLocation(), CaptureType, CopyExpr,
+ /*IsInitCapture*/false);
return true;
@@ -12182,7 +12183,8 @@
// Actually capture the variable.
if (BuildAndDiagnose)
RSI->addCapture(Var, /*isBlock*/false, ByRef, RefersToCapturedVariable, Loc,
- SourceLocation(), CaptureType, CopyExpr);
+ SourceLocation(), CaptureType, CopyExpr,
+ /*IsInitCapture*/false);
return true;
@@ -12190,7 +12192,7 @@
/// \brief Create a field within the lambda class for the variable
/// being captured. Handle Array captures.
-static ExprResult addAsFieldToClosureType(Sema &S,
+static Expr *addAsFieldToClosureType(Sema &S,
LambdaScopeInfo *LSI,
VarDecl *Var, QualType FieldType,
QualType DeclRefType,
@@ -12206,107 +12208,10 @@
Field->setImplicit(true);
Field->setAccess(AS_private);
Lambda->addDecl(Field);
-
- // C++11 [expr.prim.lambda]p21:
- // When the lambda-expression is evaluated, the entities that
- // are captured by copy are used to direct-initialize each
- // corresponding non-static data member of the resulting closure
- // object. (For array members, the array elements are
- // direct-initialized in increasing subscript order.) These
- // initializations are performed in the (unspecified) order in
- // which the non-static data members are declared.
-
- // Introduce a new evaluation context for the initialization, so
- // that temporaries introduced as part of the capture are retained
- // to be re-"exported" from the lambda expression itself.
- EnterExpressionEvaluationContext scope(S, Sema::PotentiallyEvaluated);
-
- // C++ [expr.prim.labda]p12:
- // An entity captured by a lambda-expression is odr-used (3.2) in
- // the scope containing the lambda-expression.
- Expr *Ref = new (S.Context) DeclRefExpr(Var, RefersToCapturedVariable,
- DeclRefType, VK_LValue, Loc);
Var->setReferenced(true);
- Var->markUsed(S.Context);
-
- // When the field has array type, create index variables for each
- // dimension of the array. We use these index variables to subscript
- // the source array, and other clients (e.g., CodeGen) will perform
- // the necessary iteration with these index variables.
- SmallVector<VarDecl *, 4> IndexVariables;
- QualType BaseType = FieldType;
- QualType SizeType = S.Context.getSizeType();
- LSI->ArrayIndexStarts.push_back(LSI->ArrayIndexVars.size());
- while (const ConstantArrayType *Array
- = S.Context.getAsConstantArrayType(BaseType)) {
- // Create the iteration variable for this array index.
- IdentifierInfo *IterationVarName = nullptr;
- {
- SmallString<8> Str;
- llvm::raw_svector_ostream OS(Str);
- OS << "__i" << IndexVariables.size();
- IterationVarName = &S.Context.Idents.get(OS.str());
- }
- VarDecl *IterationVar
- = VarDecl::Create(S.Context, S.CurContext, Loc, Loc,
- IterationVarName, SizeType,
- S.Context.getTrivialTypeSourceInfo(SizeType, Loc),
- SC_None);
- IndexVariables.push_back(IterationVar);
- LSI->ArrayIndexVars.push_back(IterationVar);
-
- // Create a reference to the iteration variable.
- ExprResult IterationVarRef
- = S.BuildDeclRefExpr(IterationVar, SizeType, VK_LValue, Loc);
- assert(!IterationVarRef.isInvalid() &&
- "Reference to invented variable cannot fail!");
- IterationVarRef = S.DefaultLvalueConversion(IterationVarRef.get());
- assert(!IterationVarRef.isInvalid() &&
- "Conversion of invented variable cannot fail!");
-
- // Subscript the array with this iteration variable.
- ExprResult Subscript = S.CreateBuiltinArraySubscriptExpr(
- Ref, Loc, IterationVarRef.get(), Loc);
- if (Subscript.isInvalid()) {
- S.CleanupVarDeclMarking();
- S.DiscardCleanupsInEvaluationContext();
- return ExprError();
- }
-
- Ref = Subscript.get();
- BaseType = Array->getElementType();
- }
-
- // Construct the entity that we will be initializing. For an array, this
- // will be first element in the array, which may require several levels
- // of array-subscript entities.
- SmallVector<InitializedEntity, 4> Entities;
- Entities.reserve(1 + IndexVariables.size());
- Entities.push_back(
- InitializedEntity::InitializeLambdaCapture(Var->getIdentifier(),
- Field->getType(), Loc));
- for (unsigned I = 0, N = IndexVariables.size(); I != N; ++I)
- Entities.push_back(InitializedEntity::InitializeElement(S.Context,
- 0,
- Entities.back()));
-
- InitializationKind InitKind
- = InitializationKind::CreateDirect(Loc, Loc, Loc);
- InitializationSequence Init(S, Entities.back(), InitKind, Ref);
- ExprResult Result(true);
- if (!Init.Diagnose(S, Entities.back(), InitKind, Ref))
- Result = Init.Perform(S, Entities.back(), InitKind, Ref);
-
- // If this initialization requires any cleanups (e.g., due to a
- // default argument to a copy constructor), note that for the
- // lambda.
- if (S.ExprNeedsCleanups)
- LSI->ExprNeedsCleanups = true;
-
- // Exit the expression evaluation context used for the capture.
- S.CleanupVarDeclMarking();
- S.DiscardCleanupsInEvaluationContext();
- return Result;
+ return new (S.Context)
+ DeclRefExpr(Var, RefersToCapturedVariable, DeclRefType, VK_LValue, Loc);
+
}
@@ -12390,11 +12295,9 @@
// Capture this variable in the lambda.
Expr *CopyExpr = nullptr;
if (BuildAndDiagnose) {
- ExprResult Result = addAsFieldToClosureType(S, LSI, Var,
+ CopyExpr = addAsFieldToClosureType(S, LSI, Var,
CaptureType, DeclRefType, Loc,
RefersToCapturedVariable);
- if (!Result.isInvalid())
- CopyExpr = Result.get();
}
// Compute the type of a reference to this captured variable.
@@ -12414,7 +12317,8 @@
// Add the capture.
if (BuildAndDiagnose)
LSI->addCapture(Var, /*IsBlock=*/false, ByRef, RefersToCapturedVariable,
- Loc, EllipsisLoc, CaptureType, CopyExpr);
+ Loc, EllipsisLoc, CaptureType, CopyExpr,
+ /*IsInitCapture*/false);
return true;
}
Index: lib/Sema/SemaLambda.cpp
===================================================================
--- lib/Sema/SemaLambda.cpp
+++ lib/Sema/SemaLambda.cpp
@@ -832,7 +832,7 @@
LSI->addCapture(Var, /*isBlock*/false, Var->getType()->isReferenceType(),
/*isNested*/false, Var->getLocation(), SourceLocation(),
- Var->getType(), Var->getInit());
+ Var->getType(), Var->getInit(), /*IsInitCapture*/true);
return Field;
}
@@ -1374,7 +1374,83 @@
Conversion->setImplicit(true);
Class->addDecl(Conversion);
}
-
+
+static ExprResult performLambdaNonInitCaptureInitialization(
+ Sema &S, DeclRefExpr *const DRExpr, QualType FieldType,
+ const SourceLocation Loc, SmallVectorImpl<VarDecl *> &ArrayIndexVars,
+ SmallVectorImpl<unsigned> &ArrayIndexStarts) {
+
+ VarDecl *const Var = dyn_cast<VarDecl>(DRExpr->getDecl());
+ assert(Var && "Each DeclREfExpr must refer to a variable!");
+ if (!S.CurContext->isDependentContext())
+ Var->markUsed(S.Context);
+ Expr *ExprRet = DRExpr;
+ // When the field has array type, create index variables for each dimension of
+ // the array. We use these index variables to subscript the source array, and
+ // other clients (e.g., CodeGen) will perform the necessary iteration with
+ // these index variables.
+ SmallVector<VarDecl *, 4> IndexVariables;
+ QualType BaseType = FieldType;
+ QualType SizeType = S.Context.getSizeType();
+ ArrayIndexStarts.push_back(ArrayIndexVars.size());
+ while (const ConstantArrayType *Array =
+ S.Context.getAsConstantArrayType(BaseType)) {
+ // Create the iteration variable for this array index.
+ IdentifierInfo *IterationVarName = nullptr;
+ {
+ SmallString<8> Str;
+ llvm::raw_svector_ostream OS(Str);
+ OS << "__i" << IndexVariables.size();
+ IterationVarName = &S.Context.Idents.get(OS.str());
+ }
+ VarDecl *IterationVar = VarDecl::Create(
+ S.Context, S.CurContext, Loc, Loc, IterationVarName, SizeType,
+ S.Context.getTrivialTypeSourceInfo(SizeType, Loc), SC_None);
+ IndexVariables.push_back(IterationVar);
+ ArrayIndexVars.push_back(IterationVar);
+
+ // Create a reference to the iteration variable.
+ ExprResult IterationVarRef =
+ S.BuildDeclRefExpr(IterationVar, SizeType, VK_LValue, Loc);
+ assert(!IterationVarRef.isInvalid() &&
+ "Reference to invented variable cannot fail!");
+ IterationVarRef = S.DefaultLvalueConversion(IterationVarRef.get());
+ assert(!IterationVarRef.isInvalid() &&
+ "Conversion of invented variable cannot fail!");
+
+ // Subscript the array with this iteration variable.
+ ExprResult Subscript =
+ S.CreateBuiltinArraySubscriptExpr(DRExpr, Loc, IterationVarRef.get(), Loc);
+ if (Subscript.isInvalid()) {
+ S.CleanupVarDeclMarking();
+ S.DiscardCleanupsInEvaluationContext();
+ return ExprError();
+ }
+
+ ExprRet = Subscript.get();
+ BaseType = Array->getElementType();
+ }
+ // Construct the entity that we will be initializing. For an array, this will
+ // be first element in the array, which may require several levels of
+ // array-subscript entities.
+ SmallVector<InitializedEntity, 4> Entities;
+ Entities.reserve(1 + IndexVariables.size());
+ Entities.push_back(InitializedEntity::InitializeLambdaCapture(
+ Var->getIdentifier(), FieldType, Loc));
+ for (unsigned I = 0, N = IndexVariables.size(); I != N; ++I)
+ Entities.push_back(
+ InitializedEntity::InitializeElement(S.Context, 0, Entities.back()));
+
+ InitializationKind InitKind = InitializationKind::CreateDirect(Loc, Loc, Loc);
+ InitializationSequence Init(S, Entities.back(), InitKind, ExprRet);
+ ExprResult Result(true);
+
+ if (!Init.Diagnose(S, Entities.back(), InitKind, ExprRet))
+ Result = Init.Perform(S, Entities.back(), InitKind, ExprRet);
+
+ return Result;
+}
+
ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
Scope *CurScope,
bool IsInstantiation) {
@@ -1390,8 +1466,8 @@
bool ExplicitResultType;
bool LambdaExprNeedsCleanups;
bool ContainsUnexpandedParameterPack;
- SmallVector<VarDecl *, 4> ArrayIndexVars;
- SmallVector<unsigned, 4> ArrayIndexStarts;
+ SmallVector<LambdaScopeInfo::Capture, 4> LSICaptures;
+ unsigned NumExplicitCaptures;
{
LambdaScopeInfo *LSI = getCurLambda();
CallOperator = LSI->CallOperator;
@@ -1401,38 +1477,13 @@
ExplicitResultType = !LSI->HasImplicitReturnType;
LambdaExprNeedsCleanups = LSI->ExprNeedsCleanups;
ContainsUnexpandedParameterPack = LSI->ContainsUnexpandedParameterPack;
- ArrayIndexVars.swap(LSI->ArrayIndexVars);
- ArrayIndexStarts.swap(LSI->ArrayIndexStarts);
-
- // Translate captures.
- for (unsigned I = 0, N = LSI->Captures.size(); I != N; ++I) {
- LambdaScopeInfo::Capture From = LSI->Captures[I];
- assert(!From.isBlockCapture() && "Cannot capture __block variables");
- bool IsImplicit = I >= LSI->NumExplicitCaptures;
+ LSICaptures.swap(LSI->Captures);
+ NumExplicitCaptures = LSI->NumExplicitCaptures;
- // Handle 'this' capture.
- if (From.isThisCapture()) {
- Captures.push_back(
- LambdaCapture(From.getLocation(), IsImplicit, LCK_This));
- CaptureInits.push_back(new (Context) CXXThisExpr(From.getLocation(),
- getCurrentThisType(),
- /*isImplicit=*/true));
- continue;
- }
- if (From.isVLATypeCapture()) {
- Captures.push_back(
- LambdaCapture(From.getLocation(), IsImplicit, LCK_VLAType));
- CaptureInits.push_back(nullptr);
- continue;
- }
+ assert((LSICaptures.size() ==
+ SmallVector<FieldDecl *, 8>(Class->fields()).size()) &&
+ "There should be a field for each capture (reference or value)");
- VarDecl *Var = From.getVariable();
- LambdaCaptureKind Kind = From.isCopyCapture()? LCK_ByCopy : LCK_ByRef;
- Captures.push_back(LambdaCapture(From.getLocation(), IsImplicit, Kind,
- Var, From.getEllipsisLoc()));
- CaptureInits.push_back(From.getInitExpr());
- }
-
switch (LSI->ImpCaptureStyle) {
case CapturingScopeInfo::ImpCap_None:
CaptureDefault = LCD_None;
@@ -1484,6 +1535,8 @@
// The lambda-expression's compound-statement yields the
// function-body (8.4) of the function call operator [...].
ActOnFinishFunctionBody(CallOperator, Body, IsInstantiation);
+ assert((!getCurLambda() || getCurLambda()->CallOperator != CallOperator) &&
+ "ActOnFinishFunctionBody should pop the current LambdaScopeInfo");
CallOperator->setLexicalDeclContext(Class);
Decl *TemplateOrNonTemplateCallOperatorDecl =
CallOperator->getDescribedFunctionTemplate()
@@ -1500,7 +1553,7 @@
// has a public non-virtual non-explicit const conversion function
// to pointer to function having the same parameter and return
// types as the closure type's function call operator.
- if (Captures.empty() && CaptureDefault == LCD_None)
+ if (LSICaptures.empty() && CaptureDefault == LCD_None)
addFunctionPointerConversion(*this, IntroducerRange, Class,
CallOperator);
@@ -1520,7 +1573,66 @@
SourceLocation(), nullptr);
CheckCompletedCXXClass(Class);
}
+ // Now that the Lambda's call operator's context has been popped off, process
+ // any analysis or conversion's required for initializing captures by copy or
+ // by reference within the enclosing context. This ensures that any functions
+ // required during the initialization (such as copy contructors of base
+ // classes...) are marked as used depending on the enclosing context of the
+ // lambda and not the context of the lambda's call operator (which for a
+ // generic lambda is a dependent context, and thus would fail to trigger use).
+ // Variables used to index into by-copy array captures.
+ SmallVector<VarDecl *, 4> ArrayIndexVars;
+
+ // ArrayIndexStarts contains offsets into the ArrayIndexVars array at which
+ // each capture starts its list of array index variables. For each capture,
+ // ArrayIndexStarts, stores the number of index variables created prior to it.
+ // Thus, for each capture that is an array, by computing the difference
+ // between its corresponding entry into ArrayIndexStarts and the entry
+ // following it, we can determine the number of indexed variables required for
+ // the array capture initialization.
+ SmallVector<unsigned, 4> ArrayIndexStarts;
+
+ // C++ [expr.prim.labda]p12: An entity captured by a lambda-expression is
+ // odr-used (3.2) in the scope containing the lambda-expression.
+ for (unsigned I = 0, N = LSICaptures.size(); I != N; ++I) {
+ LambdaScopeInfo::Capture From = LSICaptures[I];
+ assert(!From.isBlockCapture() && "Cannot capture __block variables");
+ bool IsImplicit = I >= NumExplicitCaptures;
+
+ // Handle 'this' capture.
+ if (From.isThisCapture()) {
+ Captures.push_back(
+ LambdaCapture(From.getLocation(), IsImplicit, LCK_This));
+ CaptureInits.push_back(new (Context) CXXThisExpr(From.getLocation(),
+ getCurrentThisType(),
+ /*isImplicit=*/true));
+ ArrayIndexStarts.push_back(ArrayIndexVars.size());
+ continue;
+ }
+ if (From.isVLATypeCapture()) {
+ Captures.push_back(
+ LambdaCapture(From.getLocation(), IsImplicit, LCK_VLAType));
+ CaptureInits.push_back(nullptr);
+ ArrayIndexStarts.push_back(ArrayIndexVars.size());
+ continue;
+ }
+
+ VarDecl *Var = From.getVariable();
+ LambdaCaptureKind Kind = From.isCopyCapture() ? LCK_ByCopy : LCK_ByRef;
+ Captures.push_back(LambdaCapture(From.getLocation(), IsImplicit, Kind, Var,
+ From.getEllipsisLoc()));
+ Expr *InitE = From.getInitExpr();
+ if (!From.isInitCapture() && dyn_cast_or_null<DeclRefExpr>(InitE)) {
+ DeclRefExpr *InitDRE = cast<DeclRefExpr>(InitE);
+ ExprResult ER = performLambdaNonInitCaptureInitialization(
+ *this, InitDRE, From.getCaptureType(), From.getLocation(),
+ ArrayIndexVars, ArrayIndexStarts);
+ InitE = ER.isInvalid() ? nullptr : ER.get();
+ }
+ CaptureInits.push_back(InitE);
+ }
+
if (LambdaExprNeedsCleanups)
ExprNeedsCleanups = true;
Index: test/CXX/expr/expr.prim/expr.prim.lambda/p2.cpp
===================================================================
--- test/CXX/expr/expr.prim/expr.prim.lambda/p2.cpp
+++ test/CXX/expr/expr.prim/expr.prim.lambda/p2.cpp
@@ -24,7 +24,6 @@
struct Boom {
Boom(const Boom&) {
T* x = 1; // expected-error{{cannot initialize a variable of type 'int *' with an rvalue of type 'int'}} \
- // expected-error{{cannot initialize a variable of type 'float *' with an rvalue of type 'int'}} \
// expected-error{{cannot initialize a variable of type 'double *' with an rvalue of type 'int'}}
}
void tickle() const;
@@ -35,8 +34,7 @@
const std::type_info &ti1
= typeid([=,&p]() -> P& { boom_int.tickle(); return p; }()); // expected-note{{in instantiation of member function 'Boom<int>::Boom' requested here}}
const std::type_info &ti2
- = typeid([=]() -> int { boom_float.tickle(); return 0; }()); // expected-error{{lambda expression in an unevaluated operand}} \
- // expected-note{{in instantiation of member function 'Boom<float>::Boom' requested here}}
+ = typeid([=]() -> int { boom_float.tickle(); return 0; }()); // expected-error{{lambda expression in an unevaluated operand}}
auto foo = [=]() -> int { boom_double.tickle(); return 0; }; // expected-note{{in instantiation of member function 'Boom<double>::Boom' requested here}}
}
Index: test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp
===================================================================
--- test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp
+++ test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp
@@ -69,8 +69,7 @@
template<typename T>
struct Boom {
Boom(const Boom&) {
- T* x = 1; // expected-error{{cannot initialize a variable of type 'int *' with an rvalue of type 'int'}} \
- // expected-error{{cannot initialize a variable of type 'float *' with an rvalue of type 'int'}}
+ T* x = 1; // expected-error{{cannot initialize a variable of type 'float *' with an rvalue of type 'int'}}
}
void tickle() const;
};
@@ -79,7 +78,7 @@
void odr_used(R &r, Boom<T> boom) {
const std::type_info &ti
= typeid([=,&r] () -> R& { // expected-error{{lambda expression in an unevaluated operand}}
- boom.tickle(); // expected-note{{in instantiation of member function}}
+ boom.tickle();
return r;
}());
}
Index: test/SemaCXX/cxx1y-generic-lambdas-pr20619.cpp
===================================================================
--- test/SemaCXX/cxx1y-generic-lambdas-pr20619.cpp
+++ test/SemaCXX/cxx1y-generic-lambdas-pr20619.cpp
@@ -0,0 +1,55 @@
+// RUN: %clang_cc1 -std=c++14 -verify -fsyntax-only -fblocks -emit-llvm-only %s
+// RUN: %clang_cc1 -std=c++14 -verify -fsyntax-only -fblocks -fdelayed-template-parsing %s -DDELAYED_TEMPLATE_PARSING
+// RUN: %clang_cc1 -std=c++14 -verify -fsyntax-only -fblocks -fms-extensions %s -DMS_EXTENSIONS
+// RUN: %clang_cc1 -std=c++14 -verify -fsyntax-only -fblocks -fdelayed-template-parsing -fms-extensions %s -DMS_EXTENSIONS -DDELAYED_TEMPLATE_PARSING
+
+//expected-no-diagnostics
+
+namespace PR20619_capturing_class_variables_within_generic_lambdas {
+// http://llvm.org/bugs/show_bug.cgi?id=20619
+namespace ns1 {
+int g;
+struct A { };
+struct B : virtual A { int get() const { return g; } };
+void foo0() {
+ B x;
+ auto L = [x=x](auto) { };
+}
+
+void foo() {
+ B x;
+ B arrX[100];
+ auto L = [x, arrX](auto) { };
+ (void) [=](auto) { return arrX[0].get() + x.get(); };
+}
+
+} // end ns1
+
+namespace ns2 {
+
+struct A { A(A &); };
+struct B : A { B(int); };
+
+void foo2() {
+ B x{0};
+ (void)[x](auto) { };
+}
+} //end ns2
+
+
+void bar() {
+ struct S {
+ int m = 0;
+ auto foo(int i) {
+ int x[10] = { 1, 2, 3, 4 };
+ int v[i];
+ v[i-1] = i;
+ return [=,&v](auto n) { return v[n] + x[n] + m; };
+ }
+ };
+ S s;
+ int x1 = s.foo(1)(1);
+ int x2 = s.foo(2)(2);
+}
+
+} // end PR20619_capturing_class_variables_within_generic_lambdas
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits