forked from OSchip/llvm-project
Per latest drafting, switch to implementing init-captures as if by declaring
and capturing a variable declaration, and complete the implementation of them. llvm-svn: 191605
This commit is contained in:
parent
45015d9796
commit
bb13c9a49d
|
@ -707,12 +707,16 @@ private:
|
|||
/// \brief Whether this variable is (C++0x) constexpr.
|
||||
unsigned IsConstexpr : 1;
|
||||
|
||||
/// \brief Whether this variable is the implicit variable for a lambda
|
||||
/// init-capture.
|
||||
unsigned IsInitCapture : 1;
|
||||
|
||||
/// \brief Whether this local extern variable's previous declaration was
|
||||
/// declared in the same block scope. This controls whether we should merge
|
||||
/// the type of this declaration with its previous declaration.
|
||||
unsigned PreviousDeclInSameBlockScope : 1;
|
||||
};
|
||||
enum { NumVarDeclBits = 13 };
|
||||
enum { NumVarDeclBits = 14 };
|
||||
|
||||
friend class ASTDeclReader;
|
||||
friend class StmtIteratorBase;
|
||||
|
@ -1132,6 +1136,10 @@ public:
|
|||
bool isConstexpr() const { return VarDeclBits.IsConstexpr; }
|
||||
void setConstexpr(bool IC) { VarDeclBits.IsConstexpr = IC; }
|
||||
|
||||
/// Whether this variable is the implicit variable for a lambda init-capture.
|
||||
bool isInitCapture() const { return VarDeclBits.IsInitCapture; }
|
||||
void setInitCapture(bool IC) { VarDeclBits.IsInitCapture = IC; }
|
||||
|
||||
/// Whether this local extern variable declaration's previous declaration
|
||||
/// was declared in the same block scope. Only correct in C++.
|
||||
bool isPreviousDeclInSameBlockScope() const {
|
||||
|
|
|
@ -1388,9 +1388,6 @@ public:
|
|||
LambdaCaptureKind Kind, VarDecl *Var = 0,
|
||||
SourceLocation EllipsisLoc = SourceLocation());
|
||||
|
||||
/// \brief Create a new init-capture.
|
||||
Capture(FieldDecl *Field);
|
||||
|
||||
/// \brief Determine the kind of capture.
|
||||
LambdaCaptureKind getCaptureKind() const;
|
||||
|
||||
|
@ -1404,7 +1401,9 @@ public:
|
|||
}
|
||||
|
||||
/// \brief Determine whether this is an init-capture.
|
||||
bool isInitCapture() const { return getCaptureKind() == LCK_Init; }
|
||||
bool isInitCapture() const {
|
||||
return capturesVariable() && getCapturedVar()->isInitCapture();
|
||||
}
|
||||
|
||||
/// \brief Retrieve the declaration of the local variable being
|
||||
/// captured.
|
||||
|
@ -1416,16 +1415,6 @@ public:
|
|||
return cast<VarDecl>(DeclAndBits.getPointer());
|
||||
}
|
||||
|
||||
/// \brief Retrieve the field for an init-capture.
|
||||
///
|
||||
/// This works only for an init-capture. To retrieve the FieldDecl for
|
||||
/// a captured variable or for a capture of \c this, use
|
||||
/// LambdaExpr::getLambdaClass and CXXRecordDecl::getCaptureFields.
|
||||
FieldDecl *getInitCaptureField() const {
|
||||
assert(getCaptureKind() == LCK_Init && "no field for non-init-capture");
|
||||
return cast<FieldDecl>(DeclAndBits.getPointer());
|
||||
}
|
||||
|
||||
/// \brief Determine whether this was an implicit capture (not
|
||||
/// written between the square brackets introducing the lambda).
|
||||
bool isImplicit() const { return DeclAndBits.getInt() & Capture_Implicit; }
|
||||
|
@ -1573,16 +1562,6 @@ public:
|
|||
return capture_init_begin() + NumCaptures;
|
||||
}
|
||||
|
||||
/// \brief Retrieve the initializer for an init-capture.
|
||||
Expr *getInitCaptureInit(capture_iterator Capture) {
|
||||
assert(Capture >= explicit_capture_begin() &&
|
||||
Capture <= explicit_capture_end() && Capture->isInitCapture());
|
||||
return capture_init_begin()[Capture - capture_begin()];
|
||||
}
|
||||
const Expr *getInitCaptureInit(capture_iterator Capture) const {
|
||||
return const_cast<LambdaExpr*>(this)->getInitCaptureInit(Capture);
|
||||
}
|
||||
|
||||
/// \brief Retrieve the set of index variables used in the capture
|
||||
/// initializer of an array captured by copy.
|
||||
///
|
||||
|
|
|
@ -825,7 +825,7 @@ template<typename Derived>
|
|||
bool RecursiveASTVisitor<Derived>::TraverseLambdaCapture(
|
||||
LambdaExpr *LE, const LambdaExpr::Capture *C) {
|
||||
if (C->isInitCapture())
|
||||
TRY_TO(TraverseStmt(LE->getInitCaptureInit(C)));
|
||||
TRY_TO(TraverseDecl(C->getCapturedVar()));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -5074,7 +5074,7 @@ let CategoryName = "Lambda Issue" in {
|
|||
def err_init_capture_multiple_expressions : Error<
|
||||
"initializer for lambda capture %0 contains multiple expressions">;
|
||||
def err_init_capture_deduction_failure : Error<
|
||||
"cannot deduce type for lambda capture %0 from initializer of type %1">;
|
||||
"cannot deduce type for lambda capture %0 from initializer of type %2">;
|
||||
def err_init_capture_deduction_failure_from_init_list : Error<
|
||||
"cannot deduce type for lambda capture %0 from initializer list">;
|
||||
}
|
||||
|
|
|
@ -34,8 +34,7 @@ enum LambdaCaptureDefault {
|
|||
enum LambdaCaptureKind {
|
||||
LCK_This, ///< Capturing the \c this pointer
|
||||
LCK_ByCopy, ///< Capturing by copy (a.k.a., by value)
|
||||
LCK_ByRef, ///< Capturing by reference
|
||||
LCK_Init ///< C++1y "init-capture", value specified by an expression
|
||||
LCK_ByRef ///< Capturing by reference
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
|
|
@ -347,21 +347,17 @@ public:
|
|||
// variables of reference type are captured by reference, and other
|
||||
// variables are captured by copy.
|
||||
enum CaptureKind {
|
||||
Cap_ByCopy, Cap_ByRef, Cap_Block, Cap_ThisOrInit
|
||||
Cap_ByCopy, Cap_ByRef, Cap_Block, Cap_This
|
||||
};
|
||||
|
||||
// The variable being captured (if we are not capturing 'this', and whether
|
||||
// this is a nested capture; the expression is only required if we are
|
||||
// capturing ByVal and the variable's type has a non-trivial copy
|
||||
// constructor, or for an initialized capture.
|
||||
typedef llvm::PointerIntPair<VarDecl*, 1, bool> VarAndNested;
|
||||
/// The variable being captured (if we are not capturing 'this') and whether
|
||||
/// this is a nested capture.
|
||||
llvm::PointerIntPair<VarDecl*, 1, bool> VarAndNested;
|
||||
|
||||
// The variable being captured, or the implicitly-generated field for
|
||||
// an init-capture.
|
||||
llvm::PointerUnion<VarAndNested, FieldDecl*> VarOrField;
|
||||
|
||||
// Expression to initialize a field of the given type, and the kind of
|
||||
// capture (if this is a capture and not an init-capture).
|
||||
/// Expression to initialize a field of the given type, and the kind of
|
||||
/// capture (if this is a capture and not an init-capture). The expression
|
||||
/// is only required if we are capturing ByVal and the variable's type has
|
||||
/// a non-trivial copy constructor.
|
||||
llvm::PointerIntPair<Expr*, 2, CaptureKind> InitExprAndCaptureKind;
|
||||
|
||||
/// \brief The source location at which the first capture occurred.
|
||||
|
@ -378,7 +374,7 @@ public:
|
|||
Capture(VarDecl *Var, bool Block, bool ByRef, bool IsNested,
|
||||
SourceLocation Loc, SourceLocation EllipsisLoc,
|
||||
QualType CaptureType, Expr *Cpy)
|
||||
: VarOrField(VarAndNested(Var, IsNested)),
|
||||
: VarAndNested(Var, IsNested),
|
||||
InitExprAndCaptureKind(Cpy, Block ? Cap_Block :
|
||||
ByRef ? Cap_ByRef : Cap_ByCopy),
|
||||
Loc(Loc), EllipsisLoc(EllipsisLoc), CaptureType(CaptureType) {}
|
||||
|
@ -386,23 +382,15 @@ public:
|
|||
enum IsThisCapture { ThisCapture };
|
||||
Capture(IsThisCapture, bool IsNested, SourceLocation Loc,
|
||||
QualType CaptureType, Expr *Cpy)
|
||||
: VarOrField(VarAndNested(0, IsNested)),
|
||||
InitExprAndCaptureKind(Cpy, Cap_ThisOrInit),
|
||||
: VarAndNested(0, IsNested),
|
||||
InitExprAndCaptureKind(Cpy, Cap_This),
|
||||
Loc(Loc), EllipsisLoc(), CaptureType(CaptureType) {}
|
||||
|
||||
Capture(FieldDecl *Field, Expr *Init)
|
||||
: VarOrField(Field), InitExprAndCaptureKind(Init, Cap_ThisOrInit),
|
||||
Loc(), EllipsisLoc(), CaptureType() {}
|
||||
|
||||
bool isThisCapture() const {
|
||||
return InitExprAndCaptureKind.getInt() == Cap_ThisOrInit &&
|
||||
VarOrField.is<VarAndNested>();
|
||||
return InitExprAndCaptureKind.getInt() == Cap_This;
|
||||
}
|
||||
bool isVariableCapture() const {
|
||||
return InitExprAndCaptureKind.getInt() != Cap_ThisOrInit;
|
||||
}
|
||||
bool isInitCapture() const {
|
||||
return VarOrField.is<FieldDecl*>();
|
||||
return InitExprAndCaptureKind.getInt() != Cap_This;
|
||||
}
|
||||
bool isCopyCapture() const {
|
||||
return InitExprAndCaptureKind.getInt() == Cap_ByCopy;
|
||||
|
@ -413,13 +401,10 @@ public:
|
|||
bool isBlockCapture() const {
|
||||
return InitExprAndCaptureKind.getInt() == Cap_Block;
|
||||
}
|
||||
bool isNested() { return VarOrField.dyn_cast<VarAndNested>().getInt(); }
|
||||
bool isNested() { return VarAndNested.getInt(); }
|
||||
|
||||
VarDecl *getVariable() const {
|
||||
return VarOrField.dyn_cast<VarAndNested>().getPointer();
|
||||
}
|
||||
FieldDecl *getInitCaptureField() const {
|
||||
return VarOrField.dyn_cast<FieldDecl*>();
|
||||
return VarAndNested.getPointer();
|
||||
}
|
||||
|
||||
/// \brief Retrieve the location at which this variable was captured.
|
||||
|
@ -473,10 +458,6 @@ public:
|
|||
void addThisCapture(bool isNested, SourceLocation Loc, QualType CaptureType,
|
||||
Expr *Cpy);
|
||||
|
||||
void addInitCapture(FieldDecl *Field, Expr *Init) {
|
||||
Captures.push_back(Capture(Field, Init));
|
||||
}
|
||||
|
||||
/// \brief Determine whether the C++ 'this' is captured.
|
||||
bool isCXXThisCaptured() const { return CXXThisCaptureIndex != 0; }
|
||||
|
||||
|
|
|
@ -4458,10 +4458,13 @@ public:
|
|||
bool ExplicitResultType,
|
||||
bool Mutable);
|
||||
|
||||
/// \brief Check and build an init-capture with the specified name and
|
||||
/// initializer.
|
||||
FieldDecl *checkInitCapture(SourceLocation Loc, bool ByRef,
|
||||
IdentifierInfo *Id, Expr *Init);
|
||||
/// \brief Check an init-capture and build the implied variable declaration
|
||||
/// with the specified name and initializer.
|
||||
VarDecl *checkInitCapture(SourceLocation Loc, bool ByRef,
|
||||
IdentifierInfo *Id, Expr *Init);
|
||||
|
||||
/// \brief Build the implicit field for an init-capture.
|
||||
FieldDecl *buildInitCaptureField(sema::LambdaScopeInfo *LSI, VarDecl *Var);
|
||||
|
||||
/// \brief Note that we have finished the explicit captures for the
|
||||
/// given lambda.
|
||||
|
|
|
@ -992,6 +992,7 @@ void CXXRecordDecl::getCaptureFields(
|
|||
else if (C->capturesVariable())
|
||||
Captures[C->getCapturedVar()] = *Field;
|
||||
}
|
||||
assert(Field == field_end());
|
||||
}
|
||||
|
||||
TemplateParameterList *
|
||||
|
|
|
@ -905,26 +905,15 @@ LambdaExpr::Capture::Capture(SourceLocation Loc, bool Implicit,
|
|||
case LCK_ByRef:
|
||||
assert(Var && "capture must have a variable!");
|
||||
break;
|
||||
|
||||
case LCK_Init:
|
||||
llvm_unreachable("don't use this constructor for an init-capture");
|
||||
}
|
||||
DeclAndBits.setInt(Bits);
|
||||
}
|
||||
|
||||
LambdaExpr::Capture::Capture(FieldDecl *Field)
|
||||
: DeclAndBits(Field,
|
||||
Field->getType()->isReferenceType() ? 0 : Capture_ByCopy),
|
||||
Loc(Field->getLocation()), EllipsisLoc() {}
|
||||
|
||||
LambdaCaptureKind LambdaExpr::Capture::getCaptureKind() const {
|
||||
Decl *D = DeclAndBits.getPointer();
|
||||
if (!D)
|
||||
return LCK_This;
|
||||
|
||||
if (isa<FieldDecl>(D))
|
||||
return LCK_Init;
|
||||
|
||||
return (DeclAndBits.getInt() & Capture_ByCopy) ? LCK_ByCopy : LCK_ByRef;
|
||||
}
|
||||
|
||||
|
|
|
@ -1460,24 +1460,18 @@ void StmtPrinter::VisitLambdaExpr(LambdaExpr *Node) {
|
|||
break;
|
||||
|
||||
case LCK_ByRef:
|
||||
if (Node->getCaptureDefault() != LCD_ByRef)
|
||||
if (Node->getCaptureDefault() != LCD_ByRef || C->isInitCapture())
|
||||
OS << '&';
|
||||
OS << C->getCapturedVar()->getName();
|
||||
break;
|
||||
|
||||
case LCK_ByCopy:
|
||||
if (Node->getCaptureDefault() != LCD_ByCopy)
|
||||
OS << '=';
|
||||
OS << C->getCapturedVar()->getName();
|
||||
break;
|
||||
|
||||
case LCK_Init:
|
||||
if (C->getInitCaptureField()->getType()->isReferenceType())
|
||||
OS << '&';
|
||||
OS << C->getInitCaptureField()->getName();
|
||||
PrintExpr(Node->getInitCaptureInit(C));
|
||||
break;
|
||||
}
|
||||
|
||||
if (C->isInitCapture())
|
||||
PrintExpr(C->getCapturedVar()->getInit());
|
||||
}
|
||||
OS << ']';
|
||||
|
||||
|
|
|
@ -881,9 +881,6 @@ StmtProfiler::VisitLambdaExpr(const LambdaExpr *S) {
|
|||
VisitDecl(C->getCapturedVar());
|
||||
ID.AddBoolean(C->isPackExpansion());
|
||||
break;
|
||||
case LCK_Init:
|
||||
VisitDecl(C->getInitCaptureField());
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Note: If we actually needed to be able to match lambda
|
||||
|
|
|
@ -7971,14 +7971,17 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
|
|||
// It isn't possible to write this directly, but it is possible to
|
||||
// end up in this situation with "auto x(some_pack...);"
|
||||
Diag(CXXDirectInit->getLocStart(),
|
||||
diag::err_auto_var_init_no_expression)
|
||||
VDecl->isInitCapture() ? diag::err_init_capture_no_expression
|
||||
: diag::err_auto_var_init_no_expression)
|
||||
<< VDecl->getDeclName() << VDecl->getType()
|
||||
<< VDecl->getSourceRange();
|
||||
RealDecl->setInvalidDecl();
|
||||
return;
|
||||
} else if (CXXDirectInit->getNumExprs() > 1) {
|
||||
Diag(CXXDirectInit->getExpr(1)->getLocStart(),
|
||||
diag::err_auto_var_init_multiple_expressions)
|
||||
VDecl->isInitCapture()
|
||||
? diag::err_init_capture_multiple_expressions
|
||||
: diag::err_auto_var_init_multiple_expressions)
|
||||
<< VDecl->getDeclName() << VDecl->getType()
|
||||
<< VDecl->getSourceRange();
|
||||
RealDecl->setInvalidDecl();
|
||||
|
|
|
@ -494,13 +494,12 @@ void Sema::deduceClosureReturnType(CapturingScopeInfo &CSI) {
|
|||
}
|
||||
}
|
||||
|
||||
FieldDecl *Sema::checkInitCapture(SourceLocation Loc, bool ByRef,
|
||||
IdentifierInfo *Id, Expr *InitExpr) {
|
||||
LambdaScopeInfo *LSI = getCurLambda();
|
||||
|
||||
VarDecl *Sema::checkInitCapture(SourceLocation Loc, bool ByRef,
|
||||
IdentifierInfo *Id, Expr *Init) {
|
||||
// C++1y [expr.prim.lambda]p11:
|
||||
// The type of [the] member corresponds to the type of a hypothetical
|
||||
// variable declaration of the form "auto init-capture;"
|
||||
// An init-capture behaves as if it declares and explicitly captures
|
||||
// a variable of the form
|
||||
// "auto init-capture;"
|
||||
QualType DeductType = Context.getAutoDeductType();
|
||||
TypeLocBuilder TLB;
|
||||
TLB.pushTypeSpec(DeductType).setNameLoc(Loc);
|
||||
|
@ -511,69 +510,38 @@ FieldDecl *Sema::checkInitCapture(SourceLocation Loc, bool ByRef,
|
|||
}
|
||||
TypeSourceInfo *TSI = TLB.getTypeSourceInfo(Context, DeductType);
|
||||
|
||||
InitializationKind InitKind = InitializationKind::CreateDefault(Loc);
|
||||
Expr *Init = InitExpr;
|
||||
if (ParenListExpr *Parens = dyn_cast<ParenListExpr>(Init)) {
|
||||
if (Parens->getNumExprs() == 1) {
|
||||
Init = Parens->getExpr(0);
|
||||
InitKind = InitializationKind::CreateDirect(
|
||||
Loc, Parens->getLParenLoc(), Parens->getRParenLoc());
|
||||
} else {
|
||||
// C++1y [dcl.spec.auto]p3:
|
||||
// In an initializer of the form ( expression-list ), the
|
||||
// expression-list shall be a single assignment-expression.
|
||||
if (Parens->getNumExprs() == 0)
|
||||
Diag(Parens->getLocStart(), diag::err_init_capture_no_expression)
|
||||
<< Id;
|
||||
else if (Parens->getNumExprs() > 1)
|
||||
Diag(Parens->getExpr(1)->getLocStart(),
|
||||
diag::err_init_capture_multiple_expressions)
|
||||
<< Id;
|
||||
return 0;
|
||||
}
|
||||
} else if (isa<InitListExpr>(Init))
|
||||
// We do not need to distinguish between direct-list-initialization
|
||||
// and copy-list-initialization here, because we will always deduce
|
||||
// std::initializer_list<T>, and direct- and copy-list-initialization
|
||||
// always behave the same for such a type.
|
||||
// FIXME: We should model whether an '=' was present.
|
||||
InitKind = InitializationKind::CreateDirectList(Loc);
|
||||
else
|
||||
InitKind = InitializationKind::CreateCopy(Loc, Loc);
|
||||
QualType DeducedType;
|
||||
if (DeduceAutoType(TSI, Init, DeducedType) == DAR_Failed) {
|
||||
if (isa<InitListExpr>(Init))
|
||||
Diag(Loc, diag::err_init_capture_deduction_failure_from_init_list)
|
||||
<< Id << Init->getSourceRange();
|
||||
else
|
||||
Diag(Loc, diag::err_init_capture_deduction_failure)
|
||||
<< Id << Init->getType() << Init->getSourceRange();
|
||||
}
|
||||
if (DeducedType.isNull())
|
||||
return 0;
|
||||
// Create a dummy variable representing the init-capture. This is not actually
|
||||
// used as a variable, and only exists as a way to name and refer to the
|
||||
// init-capture.
|
||||
// FIXME: Pass in separate source locations for '&' and identifier.
|
||||
VarDecl *NewVD = VarDecl::Create(Context, CurContext->getLexicalParent(), Loc,
|
||||
Loc, Id, TSI->getType(), TSI, SC_Auto);
|
||||
NewVD->setInitCapture(true);
|
||||
NewVD->setReferenced(true);
|
||||
NewVD->markUsed(Context);
|
||||
|
||||
// [...] a non-static data member named by the identifier is declared in
|
||||
// the closure type. This member is not a bit-field and not mutable.
|
||||
// Core issue: the member is (probably...) public.
|
||||
FieldDecl *NewFD = CheckFieldDecl(
|
||||
Id, DeducedType, TSI, LSI->Lambda,
|
||||
Loc, /*Mutable*/ false, /*BitWidth*/ 0, ICIS_NoInit,
|
||||
Loc, AS_public, /*PrevDecl*/ 0, /*Declarator*/ 0);
|
||||
LSI->Lambda->addDecl(NewFD);
|
||||
// We do not need to distinguish between direct-list-initialization
|
||||
// and copy-list-initialization here, because we will always deduce
|
||||
// std::initializer_list<T>, and direct- and copy-list-initialization
|
||||
// always behave the same for such a type.
|
||||
// FIXME: We should model whether an '=' was present.
|
||||
bool DirectInit = isa<ParenListExpr>(Init) || isa<InitListExpr>(Init);
|
||||
AddInitializerToDecl(NewVD, Init, DirectInit, /*ContainsAuto*/true);
|
||||
return NewVD;
|
||||
}
|
||||
|
||||
if (CurContext->isDependentContext()) {
|
||||
LSI->addInitCapture(NewFD, InitExpr);
|
||||
} else {
|
||||
InitializedEntity Entity = InitializedEntity::InitializeMember(NewFD);
|
||||
InitializationSequence InitSeq(*this, Entity, InitKind, Init);
|
||||
if (!InitSeq.Diagnose(*this, Entity, InitKind, Init)) {
|
||||
ExprResult InitResult = InitSeq.Perform(*this, Entity, InitKind, Init);
|
||||
if (!InitResult.isInvalid())
|
||||
LSI->addInitCapture(NewFD, InitResult.take());
|
||||
}
|
||||
}
|
||||
FieldDecl *Sema::buildInitCaptureField(LambdaScopeInfo *LSI, VarDecl *Var) {
|
||||
FieldDecl *Field = FieldDecl::Create(
|
||||
Context, LSI->Lambda, Var->getLocation(), Var->getLocation(),
|
||||
0, Var->getType(), Var->getTypeSourceInfo(), 0, false, ICIS_NoInit);
|
||||
Field->setImplicit(true);
|
||||
Field->setAccess(AS_private);
|
||||
LSI->Lambda->addDecl(Field);
|
||||
|
||||
return NewFD;
|
||||
LSI->addCapture(Var, /*isBlock*/false, Var->getType()->isReferenceType(),
|
||||
/*isNested*/false, Var->getLocation(), SourceLocation(),
|
||||
Var->getType(), Var->getInit());
|
||||
return Field;
|
||||
}
|
||||
|
||||
void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
|
||||
|
@ -732,62 +700,56 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
|
|||
|
||||
if (C->Init.isInvalid())
|
||||
continue;
|
||||
if (C->Init.isUsable()) {
|
||||
// C++11 [expr.prim.lambda]p8:
|
||||
// An identifier or this shall not appear more than once in a
|
||||
// lambda-capture.
|
||||
if (!CaptureNames.insert(C->Id))
|
||||
Diag(C->Loc, diag::err_capture_more_than_once) << C->Id;
|
||||
|
||||
VarDecl *Var;
|
||||
if (C->Init.isUsable()) {
|
||||
if (C->Init.get()->containsUnexpandedParameterPack())
|
||||
ContainsUnexpandedParameterPack = true;
|
||||
|
||||
FieldDecl *NewFD = checkInitCapture(C->Loc, C->Kind == LCK_ByRef,
|
||||
C->Id, C->Init.take());
|
||||
Var = checkInitCapture(C->Loc, C->Kind == LCK_ByRef,
|
||||
C->Id, C->Init.take());
|
||||
// C++1y [expr.prim.lambda]p11:
|
||||
// Within the lambda-expression's lambda-declarator and
|
||||
// compound-statement, the identifier in the init-capture
|
||||
// hides any declaration of the same name in scopes enclosing
|
||||
// the lambda-expression.
|
||||
if (NewFD)
|
||||
PushOnScopeChains(NewFD, CurScope, false);
|
||||
continue;
|
||||
}
|
||||
|
||||
// C++11 [expr.prim.lambda]p8:
|
||||
// If a lambda-capture includes a capture-default that is &, the
|
||||
// identifiers in the lambda-capture shall not be preceded by &.
|
||||
// If a lambda-capture includes a capture-default that is =, [...]
|
||||
// each identifier it contains shall be preceded by &.
|
||||
if (C->Kind == LCK_ByRef && Intro.Default == LCD_ByRef) {
|
||||
Diag(C->Loc, diag::err_reference_capture_with_reference_default)
|
||||
<< FixItHint::CreateRemoval(
|
||||
SourceRange(PP.getLocForEndOfToken(PrevCaptureLoc), C->Loc));
|
||||
continue;
|
||||
} else if (C->Kind == LCK_ByCopy && Intro.Default == LCD_ByCopy) {
|
||||
Diag(C->Loc, diag::err_copy_capture_with_copy_default)
|
||||
<< FixItHint::CreateRemoval(
|
||||
SourceRange(PP.getLocForEndOfToken(PrevCaptureLoc), C->Loc));
|
||||
continue;
|
||||
}
|
||||
|
||||
// C++11 [expr.prim.lambda]p10:
|
||||
// The identifiers in a capture-list are looked up using the usual
|
||||
// rules for unqualified name lookup (3.4.1)
|
||||
DeclarationNameInfo Name(C->Id, C->Loc);
|
||||
LookupResult R(*this, Name, LookupOrdinaryName);
|
||||
LookupName(R, CurScope);
|
||||
if (R.isAmbiguous())
|
||||
continue;
|
||||
if (R.empty()) {
|
||||
// FIXME: Disable corrections that would add qualification?
|
||||
CXXScopeSpec ScopeSpec;
|
||||
DeclFilterCCC<VarDecl> Validator;
|
||||
if (DiagnoseEmptyLookup(CurScope, ScopeSpec, R, Validator))
|
||||
// An init-capture behaves as if it declares and explicitly
|
||||
// captures a variable [...] whose declarative region is the
|
||||
// lambda-expression's compound-statement
|
||||
if (Var)
|
||||
PushOnScopeChains(Var, CurScope, false);
|
||||
} else {
|
||||
// C++11 [expr.prim.lambda]p8:
|
||||
// If a lambda-capture includes a capture-default that is &, the
|
||||
// identifiers in the lambda-capture shall not be preceded by &.
|
||||
// If a lambda-capture includes a capture-default that is =, [...]
|
||||
// each identifier it contains shall be preceded by &.
|
||||
if (C->Kind == LCK_ByRef && Intro.Default == LCD_ByRef) {
|
||||
Diag(C->Loc, diag::err_reference_capture_with_reference_default)
|
||||
<< FixItHint::CreateRemoval(
|
||||
SourceRange(PP.getLocForEndOfToken(PrevCaptureLoc), C->Loc));
|
||||
continue;
|
||||
}
|
||||
} else if (C->Kind == LCK_ByCopy && Intro.Default == LCD_ByCopy) {
|
||||
Diag(C->Loc, diag::err_copy_capture_with_copy_default)
|
||||
<< FixItHint::CreateRemoval(
|
||||
SourceRange(PP.getLocForEndOfToken(PrevCaptureLoc), C->Loc));
|
||||
continue;
|
||||
}
|
||||
|
||||
VarDecl *Var = R.getAsSingle<VarDecl>();
|
||||
// C++11 [expr.prim.lambda]p10:
|
||||
// The identifiers in a capture-list are looked up using the usual
|
||||
// rules for unqualified name lookup (3.4.1)
|
||||
DeclarationNameInfo Name(C->Id, C->Loc);
|
||||
LookupResult R(*this, Name, LookupOrdinaryName);
|
||||
LookupName(R, CurScope);
|
||||
if (R.isAmbiguous())
|
||||
continue;
|
||||
if (R.empty()) {
|
||||
// FIXME: Disable corrections that would add qualification?
|
||||
CXXScopeSpec ScopeSpec;
|
||||
DeclFilterCCC<VarDecl> Validator;
|
||||
if (DiagnoseEmptyLookup(CurScope, ScopeSpec, R, Validator))
|
||||
continue;
|
||||
}
|
||||
|
||||
Var = R.getAsSingle<VarDecl>();
|
||||
}
|
||||
|
||||
// C++11 [expr.prim.lambda]p8:
|
||||
// An identifier or this shall not appear more than once in a
|
||||
|
@ -799,7 +761,8 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
|
|||
<< FixItHint::CreateRemoval(
|
||||
SourceRange(PP.getLocForEndOfToken(PrevCaptureLoc), C->Loc));
|
||||
} else
|
||||
// Previous capture was an init-capture: no fixit.
|
||||
// Previous capture captured something different (one or both was
|
||||
// an init-cpature): no fixit.
|
||||
Diag(C->Loc, diag::err_capture_more_than_once) << C->Id;
|
||||
continue;
|
||||
}
|
||||
|
@ -838,10 +801,14 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
|
|||
} else if (Var->isParameterPack()) {
|
||||
ContainsUnexpandedParameterPack = true;
|
||||
}
|
||||
|
||||
TryCaptureKind Kind = C->Kind == LCK_ByRef ? TryCapture_ExplicitByRef :
|
||||
TryCapture_ExplicitByVal;
|
||||
tryCaptureVariable(Var, C->Loc, Kind, EllipsisLoc);
|
||||
|
||||
if (C->Init.isUsable()) {
|
||||
buildInitCaptureField(LSI, Var);
|
||||
} else {
|
||||
TryCaptureKind Kind = C->Kind == LCK_ByRef ? TryCapture_ExplicitByRef :
|
||||
TryCapture_ExplicitByVal;
|
||||
tryCaptureVariable(Var, C->Loc, Kind, EllipsisLoc);
|
||||
}
|
||||
}
|
||||
finishLambdaExplicitCaptures(LSI);
|
||||
|
||||
|
@ -1042,12 +1009,6 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
|
|||
continue;
|
||||
}
|
||||
|
||||
if (From.isInitCapture()) {
|
||||
Captures.push_back(LambdaExpr::Capture(From.getInitCaptureField()));
|
||||
CaptureInits.push_back(From.getInitExpr());
|
||||
continue;
|
||||
}
|
||||
|
||||
VarDecl *Var = From.getVariable();
|
||||
LambdaCaptureKind Kind = From.isCopyCapture()? LCK_ByCopy : LCK_ByRef;
|
||||
Captures.push_back(LambdaExpr::Capture(From.getLocation(), IsImplicit,
|
||||
|
|
|
@ -3928,10 +3928,14 @@ TypeSourceInfo* Sema::SubstAutoTypeSourceInfo(TypeSourceInfo *TypeWithAuto,
|
|||
void Sema::DiagnoseAutoDeductionFailure(VarDecl *VDecl, Expr *Init) {
|
||||
if (isa<InitListExpr>(Init))
|
||||
Diag(VDecl->getLocation(),
|
||||
diag::err_auto_var_deduction_failure_from_init_list)
|
||||
VDecl->isInitCapture()
|
||||
? diag::err_init_capture_deduction_failure_from_init_list
|
||||
: diag::err_auto_var_deduction_failure_from_init_list)
|
||||
<< VDecl->getDeclName() << VDecl->getType() << Init->getSourceRange();
|
||||
else
|
||||
Diag(VDecl->getLocation(), diag::err_auto_var_deduction_failure)
|
||||
Diag(VDecl->getLocation(),
|
||||
VDecl->isInitCapture() ? diag::err_init_capture_deduction_failure
|
||||
: diag::err_auto_var_deduction_failure)
|
||||
<< VDecl->getDeclName() << VDecl->getType() << Init->getType()
|
||||
<< Init->getSourceRange();
|
||||
}
|
||||
|
|
|
@ -3369,6 +3369,7 @@ void Sema::BuildVariableInstantiation(
|
|||
NewVar->setInitStyle(OldVar->getInitStyle());
|
||||
NewVar->setCXXForRangeDecl(OldVar->isCXXForRangeDecl());
|
||||
NewVar->setConstexpr(OldVar->isConstexpr());
|
||||
NewVar->setInitCapture(OldVar->isInitCapture());
|
||||
NewVar->setPreviousDeclInSameBlockScope(
|
||||
OldVar->isPreviousDeclInSameBlockScope());
|
||||
NewVar->setAccess(OldVar->getAccess());
|
||||
|
|
|
@ -8313,7 +8313,9 @@ TreeTransform<Derived>::TransformLambdaScope(LambdaExpr *E,
|
|||
if (!C->isInitCapture())
|
||||
continue;
|
||||
InitCaptureExprs[C - E->capture_begin()] =
|
||||
getDerived().TransformExpr(E->getInitCaptureInit(C));
|
||||
getDerived().TransformInitializer(
|
||||
C->getCapturedVar()->getInit(),
|
||||
C->getCapturedVar()->getInitStyle() == VarDecl::CallInit);
|
||||
}
|
||||
|
||||
// Introduce the context of the call operator.
|
||||
|
@ -8353,14 +8355,15 @@ TreeTransform<Derived>::TransformLambdaScope(LambdaExpr *E,
|
|||
Invalid = true;
|
||||
continue;
|
||||
}
|
||||
FieldDecl *OldFD = C->getInitCaptureField();
|
||||
FieldDecl *NewFD = getSema().checkInitCapture(
|
||||
C->getLocation(), OldFD->getType()->isReferenceType(),
|
||||
OldFD->getIdentifier(), Init.take());
|
||||
if (!NewFD)
|
||||
VarDecl *OldVD = C->getCapturedVar();
|
||||
VarDecl *NewVD = getSema().checkInitCapture(
|
||||
C->getLocation(), OldVD->getType()->isReferenceType(),
|
||||
OldVD->getIdentifier(), Init.take());
|
||||
if (!NewVD)
|
||||
Invalid = true;
|
||||
else
|
||||
getDerived().transformedLocalDecl(OldFD, NewFD);
|
||||
getDerived().transformedLocalDecl(OldVD, NewVD);
|
||||
getSema().buildInitCaptureField(LSI, NewVD);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -945,6 +945,7 @@ ASTDeclReader::RedeclarableResult ASTDeclReader::VisitVarDeclImpl(VarDecl *VD) {
|
|||
VD->VarDeclBits.CXXForRangeDecl = Record[Idx++];
|
||||
VD->VarDeclBits.ARCPseudoStrong = Record[Idx++];
|
||||
VD->VarDeclBits.IsConstexpr = Record[Idx++];
|
||||
VD->VarDeclBits.IsInitCapture = Record[Idx++];
|
||||
VD->VarDeclBits.PreviousDeclInSameBlockScope = Record[Idx++];
|
||||
Linkage VarLinkage = Linkage(Record[Idx++]);
|
||||
VD->setCachedLinkage(VarLinkage);
|
||||
|
@ -1223,17 +1224,12 @@ void ASTDeclReader::ReadCXXDefinitionData(
|
|||
*ToCapture++ = Capture(Loc, IsImplicit, Kind, 0, SourceLocation());
|
||||
break;
|
||||
case LCK_ByCopy:
|
||||
case LCK_ByRef: {
|
||||
case LCK_ByRef:
|
||||
VarDecl *Var = ReadDeclAs<VarDecl>(Record, Idx);
|
||||
SourceLocation EllipsisLoc = ReadSourceLocation(Record, Idx);
|
||||
*ToCapture++ = Capture(Loc, IsImplicit, Kind, Var, EllipsisLoc);
|
||||
break;
|
||||
}
|
||||
case LCK_Init:
|
||||
FieldDecl *Field = ReadDeclAs<FieldDecl>(Record, Idx);
|
||||
*ToCapture++ = Capture(Field);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5144,7 +5144,7 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec
|
|||
case LCK_This:
|
||||
break;
|
||||
case LCK_ByCopy:
|
||||
case LCK_ByRef: {
|
||||
case LCK_ByRef:
|
||||
VarDecl *Var =
|
||||
Capture.capturesVariable() ? Capture.getCapturedVar() : 0;
|
||||
AddDeclRef(Var, Record);
|
||||
|
@ -5153,11 +5153,6 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec
|
|||
Record);
|
||||
break;
|
||||
}
|
||||
case LCK_Init:
|
||||
FieldDecl *Field = Capture.getInitCaptureField();
|
||||
AddDeclRef(Field, Record);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -705,6 +705,7 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) {
|
|||
Record.push_back(D->isCXXForRangeDecl());
|
||||
Record.push_back(D->isARCPseudoStrong());
|
||||
Record.push_back(D->isConstexpr());
|
||||
Record.push_back(D->isInitCapture());
|
||||
Record.push_back(D->isPreviousDeclInSameBlockScope());
|
||||
Record.push_back(D->getLinkageInternal());
|
||||
|
||||
|
@ -747,6 +748,7 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) {
|
|||
!isa<ParmVarDecl>(D) &&
|
||||
!isa<VarTemplateSpecializationDecl>(D) &&
|
||||
!D->isConstexpr() &&
|
||||
!D->isInitCapture() &&
|
||||
!D->isPreviousDeclInSameBlockScope() &&
|
||||
!D->getMemberSpecializationInfo())
|
||||
AbbrevToUse = Writer.getDeclVarAbbrev();
|
||||
|
@ -1633,6 +1635,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
|
|||
Abv->Add(BitCodeAbbrevOp(0)); // isCXXForRangeDecl
|
||||
Abv->Add(BitCodeAbbrevOp(0)); // isARCPseudoStrong
|
||||
Abv->Add(BitCodeAbbrevOp(0)); // isConstexpr
|
||||
Abv->Add(BitCodeAbbrevOp(0)); // isInitCapture
|
||||
Abv->Add(BitCodeAbbrevOp(0)); // isPrevDeclInSameScope
|
||||
Abv->Add(BitCodeAbbrevOp(0)); // Linkage
|
||||
Abv->Add(BitCodeAbbrevOp(0)); // HasInit
|
||||
|
@ -1713,6 +1716,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
|
|||
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isCXXForRangeDecl
|
||||
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isARCPseudoStrong
|
||||
Abv->Add(BitCodeAbbrevOp(0)); // isConstexpr
|
||||
Abv->Add(BitCodeAbbrevOp(0)); // isInitCapture
|
||||
Abv->Add(BitCodeAbbrevOp(0)); // isPrevDeclInSameScope
|
||||
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // Linkage
|
||||
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // HasInit
|
||||
|
|
|
@ -10,7 +10,7 @@ void f(X x) { (void) [x]{}; }
|
|||
// CHECK: 1: x
|
||||
// CHECK: 2: [B1.1] (ImplicitCastExpr, NoOp, const struct X)
|
||||
// CHECK: 3: [B1.2] (CXXConstructExpr, struct X)
|
||||
// CHECK: 4: [=x] {
|
||||
// CHECK: 4: [x] {
|
||||
// CHECK: }
|
||||
// CHECK: 5: (void)[B1.4] (CStyleCastExpr, ToVoid, void)
|
||||
// CHECK: Preds (1): B2
|
||||
|
|
|
@ -1,34 +1,26 @@
|
|||
// RUN: %clang_cc1 -std=c++1y %s -verify
|
||||
|
||||
// For every init-capture a non-static data member named by the identifier of
|
||||
// the init-capture is declared in the closure type.
|
||||
const char *has_member_x = [x("hello")] {}.x;
|
||||
// This member is not a bit-field...
|
||||
auto capturing_lambda = [n(0)] {};
|
||||
int decltype(capturing_lambda)::*mem_ptr = &decltype(capturing_lambda)::n;
|
||||
// ... and not mutable.
|
||||
const auto capturing_lambda_copy = capturing_lambda;
|
||||
int &n = capturing_lambda_copy.n; // expected-error {{drops qualifiers}}
|
||||
const char *has_no_member = [x("hello")] {}.x; // expected-error {{no member named 'x'}}
|
||||
|
||||
// The type of that member [...is that of a...] variable declaration of the form
|
||||
// "auto init-capture ;"...
|
||||
auto with_float = [f(1.0f)] {};
|
||||
float &f = with_float.f;
|
||||
// ... except that the variable name is replaced by a unique identifier.
|
||||
auto with_float_2 = [&f(f)] {}; // ok, refers to outer f
|
||||
float &f2 = with_float_2.f;
|
||||
double f;
|
||||
auto with_float = [f(1.0f)] {
|
||||
using T = decltype(f);
|
||||
using T = float;
|
||||
};
|
||||
auto with_float_2 = [&f(f)] { // ok, refers to outer f
|
||||
using T = decltype(f);
|
||||
using T = double&;
|
||||
};
|
||||
|
||||
// Within the lambda-expression's lambda-declarator (FIXME) and
|
||||
// compound-statement, the identifier in the init-capture hides any declaration
|
||||
// Within the lambda-expression's compound-statement,
|
||||
// the identifier in the init-capture hides any declaration
|
||||
// of the same name in scopes enclosing the lambda-expression.
|
||||
void hiding() {
|
||||
char c;
|
||||
(void) [c("foo")] {
|
||||
static_assert(sizeof(c) == sizeof(const char*), "");
|
||||
};
|
||||
(void) [c("bar")] () -> decltype(c) {
|
||||
// FIXME: the 'c' in the return type should be the init-capture, not the
|
||||
// outer c.
|
||||
(void) [c("bar")] () -> decltype(c) { // outer c, not init-capture
|
||||
return "baz"; // expected-error {{cannot initialize}}
|
||||
};
|
||||
}
|
||||
|
@ -54,22 +46,16 @@ int overload_fn(int);
|
|||
auto bad_init_1 = [a()] {}; // expected-error {{expected expression}}
|
||||
auto bad_init_2 = [a(1, 2)] {}; // expected-error {{initializer for lambda capture 'a' contains multiple expressions}}
|
||||
auto bad_init_3 = [&a(void_fn())] {}; // expected-error {{cannot form a reference to 'void'}}
|
||||
auto bad_init_4 = [a(void_fn())] {}; // expected-error {{field has incomplete type 'void'}}
|
||||
auto bad_init_4 = [a(void_fn())] {}; // expected-error {{has incomplete type 'void'}}
|
||||
auto bad_init_5 = [a(overload_fn)] {}; // expected-error {{cannot deduce type for lambda capture 'a' from initializer of type '<overloaded function}}
|
||||
auto bad_init_6 = [a{overload_fn}] {}; // expected-error {{cannot deduce type for lambda capture 'a' from initializer list}}
|
||||
|
||||
template<typename...T> void pack_1(T...t) { [a(t...)] {}; } // expected-error {{initializer missing for lambda capture 'a'}}
|
||||
template<typename...T> void pack_1(T...t) { (void)[a(t...)] {}; } // expected-error {{initializer missing for lambda capture 'a'}}
|
||||
template void pack_1<>(); // expected-note {{instantiation of}}
|
||||
|
||||
auto multi_return(int a, int b) {
|
||||
return [n(a + 2*b), m(a - 2*b)] {};
|
||||
}
|
||||
auto use_multi_return() {
|
||||
auto nm = multi_return(5, 9);
|
||||
return nm.n + nm.m;
|
||||
}
|
||||
|
||||
auto a = [a(4), b = 5, &c = static_cast<const int&&>(0)] { // expected-warning {{binding reference member 'c' to a temporary value}} expected-note {{here}}
|
||||
// FIXME: Might need lifetime extension for the temporary here.
|
||||
// See DR1695.
|
||||
auto a = [a(4), b = 5, &c = static_cast<const int&&>(0)] {
|
||||
static_assert(sizeof(a) == sizeof(int), "");
|
||||
static_assert(sizeof(b) == sizeof(int), "");
|
||||
using T = decltype(c);
|
||||
|
@ -82,3 +68,10 @@ template<typename T> struct remove_reference { typedef T type; };
|
|||
template<typename T> struct remove_reference<T&> { typedef T type; };
|
||||
template<typename T> decltype(auto) move(T &&t) { return static_cast<typename remove_reference<T>::type&&>(t); }
|
||||
auto s = [s(move(S()))] {};
|
||||
|
||||
template<typename T> T instantiate_test(T t) {
|
||||
[x(&t)]() { *x = 1; } (); // expected-error {{assigning to 'const char *'}}
|
||||
return t;
|
||||
}
|
||||
int instantiate_test_1 = instantiate_test(0);
|
||||
const char *instantiate_test_2 = instantiate_test("foo"); // expected-note {{here}}
|
||||
|
|
|
@ -66,7 +66,7 @@ void init_capture_pack_err(Args ...args) {
|
|||
|
||||
template<typename ...Args>
|
||||
void init_capture_pack_multi(Args ...args) {
|
||||
[as(args...)] {} (); // expected-error {{initializer missing}} expected-error {{multiple}}
|
||||
[as(args...)] {} (); // expected-error {{initializer missing for lambda capture 'as'}} expected-error {{multiple}}
|
||||
}
|
||||
template void init_capture_pack_multi(); // expected-note {{instantiation}}
|
||||
template void init_capture_pack_multi(int);
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
// RUN: %clang_cc1 -std=c++1y -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s
|
||||
|
||||
struct S {
|
||||
S();
|
||||
S(S &&);
|
||||
~S();
|
||||
};
|
||||
|
||||
void f() {
|
||||
(void) [s(S{})] {};
|
||||
}
|
||||
|
||||
// CHECK-LABEL: define void @_Z1fv(
|
||||
// CHECK: call void @_ZN1SC1Ev(
|
||||
// CHECK: call void @"_ZZ1fvEN3$_0D1Ev"(
|
||||
|
||||
// CHECK-LABEL: define internal void @"_ZZ1fvEN3$_0D1Ev"(
|
||||
// CHECK: @"_ZZ1fvEN3$_0D2Ev"(
|
||||
|
||||
// D2 at end of file.
|
||||
|
||||
void g() {
|
||||
[a(1), b(2)] { return a + b; } ();
|
||||
}
|
||||
|
||||
// CHECK-LABEL: define void @_Z1gv(
|
||||
// CHECK: getelementptr inbounds {{.*}}, i32 0, i32 0
|
||||
// CHECK: store i32 1, i32*
|
||||
// CHECK: getelementptr inbounds {{.*}}, i32 0, i32 1
|
||||
// CHECK: store i32 2, i32*
|
||||
// CHECK: call i32 @"_ZZ1gvENK3$_1clEv"(
|
||||
|
||||
// CHECK-LABEL: define internal i32 @"_ZZ1gvENK3$_1clEv"(
|
||||
// CHECK: getelementptr inbounds {{.*}}, i32 0, i32 0
|
||||
// CHECK: load i32*
|
||||
// CHECK: getelementptr inbounds {{.*}}, i32 0, i32 1
|
||||
// CHECK: load i32*
|
||||
// CHECK: add nsw i32
|
||||
|
||||
int h(int a) {
|
||||
// CHECK-LABEL: define i32 @_Z1hi(
|
||||
// CHECK: %[[A_ADDR:.*]] = alloca i32,
|
||||
// CHECK: %[[OUTER:.*]] = alloca
|
||||
// CHECK: store i32 {{.*}}, i32* %[[A_ADDR]],
|
||||
//
|
||||
// Initialize init-capture 'b(a)' by reference.
|
||||
// CHECK: getelementptr inbounds {{.*}}* %[[OUTER]], i32 0, i32 0
|
||||
// CHECK: store i32* %[[A_ADDR]], i32** {{.*}},
|
||||
//
|
||||
// Initialize init-capture 'c(a)' by copy.
|
||||
// CHECK: getelementptr inbounds {{.*}}* %[[OUTER]], i32 0, i32 1
|
||||
// CHECK: load i32* %[[A_ADDR]],
|
||||
// CHECK: store i32
|
||||
//
|
||||
// CHECK: call i32 @"_ZZ1hiENK3$_2clEv"({{.*}}* %[[OUTER]])
|
||||
return [&b(a), c(a)] {
|
||||
// CHECK-LABEL: define internal i32 @"_ZZ1hiENK3$_2clEv"(
|
||||
// CHECK: %[[OUTER_ADDR:.*]] = alloca
|
||||
// CHECK: %[[INNER:.*]] = alloca
|
||||
// CHECK: store {{.*}}, {{.*}}** %[[OUTER_ADDR]],
|
||||
//
|
||||
// Capture outer 'c' by reference.
|
||||
// CHECK: %[[OUTER:.*]] = load {{.*}}** %[[OUTER_ADDR]]
|
||||
// CHECK: getelementptr inbounds {{.*}}* %[[INNER]], i32 0, i32 0
|
||||
// CHECK-NEXT: getelementptr inbounds {{.*}}* %[[OUTER]], i32 0, i32 1
|
||||
// CHECK-NEXT: store i32* %
|
||||
//
|
||||
// Capture outer 'b' by copy.
|
||||
// CHECK: getelementptr inbounds {{.*}}* %[[INNER]], i32 0, i32 1
|
||||
// CHECK-NEXT: getelementptr inbounds {{.*}}* %[[OUTER]], i32 0, i32 0
|
||||
// CHECK-NEXT: load i32** %
|
||||
// CHECK-NEXT: load i32* %
|
||||
// CHECK-NEXT: store i32
|
||||
//
|
||||
// CHECK: call i32 @"_ZZZ1hiENK3$_2clEvENKUlvE_clEv"({{.*}}* %[[INNER]])
|
||||
return [=, &c] {
|
||||
// CHECK-LABEL: define internal i32 @"_ZZZ1hiENK3$_2clEvENKUlvE_clEv"(
|
||||
// CHECK: %[[INNER_ADDR:.*]] = alloca
|
||||
// CHECK: store {{.*}}, {{.*}}** %[[INNER_ADDR]],
|
||||
// CHECK: %[[INNER:.*]] = load {{.*}}** %[[INNER_ADDR]]
|
||||
//
|
||||
// Load capture of 'b'
|
||||
// CHECK: getelementptr inbounds {{.*}}* %[[INNER]], i32 0, i32 1
|
||||
// CHECK: load i32* %
|
||||
//
|
||||
// Load capture of 'c'
|
||||
// CHECK: getelementptr inbounds {{.*}}* %[[INNER]], i32 0, i32 0
|
||||
// CHECK: load i32** %
|
||||
// CHECK: load i32* %
|
||||
//
|
||||
// CHECK: add nsw i32
|
||||
return b + c;
|
||||
} ();
|
||||
} ();
|
||||
}
|
||||
|
||||
// CHECK-LABEL: define internal void @"_ZZ1fvEN3$_0D2Ev"(
|
||||
// CHECK: call void @_ZN1SD1Ev(
|
|
@ -0,0 +1,28 @@
|
|||
// No PCH:
|
||||
// RUN: %clang_cc1 -pedantic -std=c++1y -include %s -verify %s
|
||||
//
|
||||
// With PCH:
|
||||
// RUN: %clang_cc1 -pedantic -std=c++1y -emit-pch %s -o %t
|
||||
// RUN: %clang_cc1 -pedantic -std=c++1y -include-pch %t -verify %s
|
||||
|
||||
#ifndef HEADER
|
||||
#define HEADER
|
||||
|
||||
auto counter = [a(0)] () mutable { return a++; };
|
||||
int x = counter();
|
||||
|
||||
template<typename T> void f(T t) {
|
||||
[t(t)] { int n = t; } ();
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int y = counter();
|
||||
|
||||
void g() {
|
||||
f(0); // ok
|
||||
// expected-error@15 {{lvalue of type 'const char *const'}}
|
||||
f("foo"); // expected-note {{here}}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -52,18 +52,16 @@ class C {
|
|||
// We support init-captures in C++11 as an extension.
|
||||
int z;
|
||||
void init_capture() {
|
||||
// FIXME: These diagnostics should all disappear once semantic analysis
|
||||
// for init-captures is complete.
|
||||
[n(0)] () -> int { return ++n; }; // expected-error {{non-static data member}}
|
||||
[n(0)] () mutable -> int { return ++n; };
|
||||
[n{0}] { return; }; // expected-error {{<initializer_list>}}
|
||||
[n = 0] { return ++n; }; // expected-error {{non-static data member}}
|
||||
[n = 0] { return ++n; }; // expected-error {{captured by copy in a non-mutable}}
|
||||
[n = {0}] { return; }; // expected-error {{<initializer_list>}}
|
||||
[a([&b = z]{})](){};
|
||||
|
||||
int x = 4;
|
||||
auto y = [&r = x, x = x + 1]() -> int {
|
||||
r += 2; // expected-error {{non-static data member}}
|
||||
return x + 2; // expected-error {{non-static data member}}
|
||||
r += 2;
|
||||
return x + 2;
|
||||
} ();
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue