diff options
Diffstat (limited to 'clang')
-rw-r--r-- | clang/include/clang/AST/ASTContext.h | 2 | ||||
-rw-r--r-- | clang/include/clang/AST/Type.h | 4 | ||||
-rw-r--r-- | clang/include/clang/Sema/ScopeInfo.h | 2 | ||||
-rw-r--r-- | clang/include/clang/Sema/Sema.h | 28 | ||||
-rw-r--r-- | clang/lib/AST/ASTContext.cpp | 37 | ||||
-rw-r--r-- | clang/lib/AST/ASTImporter.cpp | 6 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 202 | ||||
-rw-r--r-- | clang/lib/Sema/SemaType.cpp | 89 | ||||
-rw-r--r-- | clang/lib/Serialization/ASTReader.cpp | 6 | ||||
-rw-r--r-- | clang/lib/Serialization/ASTWriter.cpp | 1 | ||||
-rw-r--r-- | clang/test/CXX/expr/expr.prim/expr.prim.lambda/p12.cpp | 4 | ||||
-rw-r--r-- | clang/test/CXX/expr/expr.prim/expr.prim.lambda/p18.cpp | 41 | ||||
-rw-r--r-- | clang/test/SemaCXX/lambda-expressions.cpp | 3 |
13 files changed, 299 insertions, 126 deletions
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 82570f594d4..7f1f7356e52 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -876,7 +876,7 @@ public: QualType getTypeOfType(QualType t) const; /// getDecltypeType - C++0x decltype. - QualType getDecltypeType(Expr *e) const; + QualType getDecltypeType(Expr *e, QualType UnderlyingType) const; /// getUnaryTransformType - unary type transforms QualType getUnaryTransformType(QualType BaseType, QualType UnderlyingType, diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index dcc9fca3285..29a07f3cb15 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -3040,10 +3040,6 @@ public: /// DecltypeType (C++0x) class DecltypeType : public Type { Expr *E; - - // FIXME: We could get rid of UnderlyingType if we wanted to: We would have to - // Move getDesugaredType to ASTContext so that it can call getDecltypeForExpr - // from it. QualType UnderlyingType; protected: diff --git a/clang/include/clang/Sema/ScopeInfo.h b/clang/include/clang/Sema/ScopeInfo.h index ea77ff49cb5..1861e958ae6 100644 --- a/clang/include/clang/Sema/ScopeInfo.h +++ b/clang/include/clang/Sema/ScopeInfo.h @@ -22,11 +22,13 @@ namespace clang { class BlockDecl; +class CXXMethodDecl; class IdentifierInfo; class LabelDecl; class ReturnStmt; class Scope; class SwitchStmt; +class VarDecl; namespace sema { diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index ce36d23706e..3333e56e714 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -2282,6 +2282,34 @@ public: void UpdateMarkingForLValueToRValue(Expr *E); void CleanupVarDeclMarking(); + /// \brief Determine whether we can capture the given variable in + /// the given scope. + /// + /// \param Explicit Whether this is an explicit capture (vs. an + /// implicit capture). + /// + /// \param Diagnose Diagnose errors that occur when attempting to perform + /// the capture. + /// + /// \param Var The variable to check for capture. + /// + /// \param Type Will be set to the type used to perform the capture. + /// + /// \param FunctionScopesIndex Will be set to the index of the first + /// scope in which capture will need to be performed. + /// + /// \param Nested Whether this will be a nested capture. + bool canCaptureVariable(VarDecl *Var, SourceLocation Loc, bool Explicit, + bool Diagnose, QualType &Type, + unsigned &FunctionScopesIndex, bool &Nested); + + /// \brief Determine the type of the field that will capture the + /// given variable in a lambda expression. + /// + /// \param T The type of the variable being captured. + /// \param ByRef Whether we are capturing by reference or by value. + QualType getLambdaCaptureFieldType(QualType T, bool ByRef); + enum TryCaptureKind { TryCapture_Implicit, TryCapture_ExplicitByVal, TryCapture_ExplicitByRef }; diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index bb93a68d265..cc651f9c9c5 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -2913,44 +2913,13 @@ QualType ASTContext::getTypeOfType(QualType tofType) const { return QualType(tot, 0); } -/// getDecltypeForExpr - Given an expr, will return the decltype for that -/// expression, according to the rules in C++0x [dcl.type.simple]p4 -static QualType getDecltypeForExpr(const Expr *e, const ASTContext &Context) { - if (e->isTypeDependent()) - return Context.DependentTy; - - // If e is an id expression or a class member access, decltype(e) is defined - // as the type of the entity named by e. - if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(e)) { - if (const ValueDecl *VD = dyn_cast<ValueDecl>(DRE->getDecl())) - return VD->getType(); - } - if (const MemberExpr *ME = dyn_cast<MemberExpr>(e)) { - if (const FieldDecl *FD = dyn_cast<FieldDecl>(ME->getMemberDecl())) - return FD->getType(); - } - // If e is a function call or an invocation of an overloaded operator, - // (parentheses around e are ignored), decltype(e) is defined as the - // return type of that function. - if (const CallExpr *CE = dyn_cast<CallExpr>(e->IgnoreParens())) - return CE->getCallReturnType(); - - QualType T = e->getType(); - - // Otherwise, where T is the type of e, if e is an lvalue, decltype(e) is - // defined as T&, otherwise decltype(e) is defined as T. - if (e->isLValue()) - T = Context.getLValueReferenceType(T); - - return T; -} /// getDecltypeType - Unlike many "get<Type>" functions, we don't unique /// DecltypeType AST's. The only motivation to unique these nodes would be /// memory savings. Since decltype(t) is fairly uncommon, space shouldn't be /// an issue. This doesn't effect the type checker, since it operates /// on canonical types (which are always unique). -QualType ASTContext::getDecltypeType(Expr *e) const { +QualType ASTContext::getDecltypeType(Expr *e, QualType UnderlyingType) const { DecltypeType *dt; // C++0x [temp.type]p2: @@ -2976,8 +2945,8 @@ QualType ASTContext::getDecltypeType(Expr *e) const { dt = Canon; } } else { - QualType T = getDecltypeForExpr(e, *this); - dt = new (*this, TypeAlignment) DecltypeType(e, T, getCanonicalType(T)); + dt = new (*this, TypeAlignment) DecltypeType(e, UnderlyingType, + getCanonicalType(UnderlyingType)); } Types.push_back(dt); return QualType(dt, 0); diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 556f97d8582..e15bac0b447 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -1581,7 +1581,11 @@ QualType ASTNodeImporter::VisitDecltypeType(const DecltypeType *T) { if (!ToExpr) return QualType(); - return Importer.getToContext().getDecltypeType(ToExpr); + QualType UnderlyingType = Importer.Import(T->getUnderlyingType()); + if (UnderlyingType.isNull()) + return QualType(); + + return Importer.getToContext().getDecltypeType(ToExpr, UnderlyingType); } QualType ASTNodeImporter::VisitUnaryTransformType(const UnaryTransformType *T) { diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index ce5956ae2f8..9bd1074116f 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -9566,12 +9566,7 @@ static bool shouldAddConstForScope(CapturingScopeInfo *CSI, VarDecl *VD) { return false; } -/// \brief Capture the given variable in the given lambda expression. -static ExprResult captureInLambda(Sema &S, LambdaScopeInfo *LSI, - VarDecl *Var, QualType Type, - SourceLocation Loc, bool ByRef) { - CXXRecordDecl *Lambda = LSI->Lambda; - QualType FieldType; +QualType Sema::getLambdaCaptureFieldType(QualType T, bool ByRef) { if (ByRef) { // C++11 [expr.prim.lambda]p15: // An entity is captured by reference if it is implicitly or @@ -9579,28 +9574,34 @@ static ExprResult captureInLambda(Sema &S, LambdaScopeInfo *LSI, // unspecified whether additional unnamed non-static data // members are declared in the closure type for entities // captured by reference. - FieldType = S.Context.getLValueReferenceType(Type.getNonReferenceType()); - } else { - // C++11 [expr.prim.lambda]p14: - // For each entity captured by copy, an unnamed non-static - // data member is declared in the closure type. The - // declaration order of these members is unspecified. The type - // of such a data member is the type of the corresponding - // captured entity if the entity is not a reference to an - // object, or the referenced type otherwise. [Note: If the - // captured entity is a reference to a function, the - // corresponding data member is also a reference to a - // function. - end note ] - if (const ReferenceType *RefType = Type->getAs<ReferenceType>()) { - if (!RefType->getPointeeType()->isFunctionType()) - FieldType = RefType->getPointeeType(); - else - FieldType = Type; - } else { - FieldType = Type; - } + return Context.getLValueReferenceType(T.getNonReferenceType()); + } + + // C++11 [expr.prim.lambda]p14: + // For each entity captured by copy, an unnamed non-static + // data member is declared in the closure type. The + // declaration order of these members is unspecified. The type + // of such a data member is the type of the corresponding + // captured entity if the entity is not a reference to an + // object, or the referenced type otherwise. [Note: If the + // captured entity is a reference to a function, the + // corresponding data member is also a reference to a + // function. - end note ] + if (const ReferenceType *RefType = T->getAs<ReferenceType>()) { + if (!RefType->getPointeeType()->isFunctionType()) + return RefType->getPointeeType(); } + return T; +} + +/// \brief Capture the given variable in the given lambda expression. +static ExprResult captureInLambda(Sema &S, LambdaScopeInfo *LSI, + VarDecl *Var, QualType Type, + SourceLocation Loc, bool ByRef) { + CXXRecordDecl *Lambda = LSI->Lambda; + QualType FieldType = S.getLambdaCaptureFieldType(Type, ByRef); + // Build the non-static data member. FieldDecl *Field = FieldDecl::Create(S.Context, Lambda, Loc, Loc, 0, FieldType, @@ -9715,20 +9716,20 @@ static ExprResult captureInLambda(Sema &S, LambdaScopeInfo *LSI, return Result; } -// Check if the variable needs to be captured; if so, try to perform -// the capture. -// FIXME: Add support for explicit captures. -void Sema::TryCaptureVar(VarDecl *var, SourceLocation loc, - TryCaptureKind Kind) { +bool Sema::canCaptureVariable(VarDecl *Var, SourceLocation Loc, bool Explicit, + bool Diagnose, QualType &Type, + unsigned &FunctionScopesIndex, bool &Nested) { + Type = Var->getType(); + FunctionScopesIndex = FunctionScopes.size() - 1; + Nested = false; + DeclContext *DC = CurContext; - if (var->getDeclContext() == DC) return; - if (!var->hasLocalStorage()) return; + if (Var->getDeclContext() == DC) return false; + if (!Var->hasLocalStorage()) return false; - // Actually try to capture it. - QualType type = var->getType(); - bool Nested = false; + bool HasBlocksAttr = Var->hasAttr<BlocksAttr>(); - unsigned functionScopesIndex = FunctionScopes.size() - 1; + // Figure out whether we can capture the variable. do { // Only block literals and lambda expressions can capture; other // scopes don't work. @@ -9736,84 +9737,125 @@ void Sema::TryCaptureVar(VarDecl *var, SourceLocation loc, if (isa<BlockDecl>(DC)) ParentDC = DC->getParent(); else if (isa<CXXMethodDecl>(DC) && + cast<CXXMethodDecl>(DC)->getOverloadedOperator() == OO_Call && cast<CXXRecordDecl>(DC->getParent())->isLambda()) ParentDC = DC->getParent()->getParent(); - else - return diagnoseUncapturableValueReference(*this, loc, var, DC); + else { + if (Diagnose) + diagnoseUncapturableValueReference(*this, Loc, Var, DC); + return false; + } CapturingScopeInfo *CSI = - cast<CapturingScopeInfo>(FunctionScopes[functionScopesIndex]); + cast<CapturingScopeInfo>(FunctionScopes[FunctionScopesIndex]); // Check whether we've already captured it. - if (CSI->CaptureMap.count(var)) { + if (CSI->CaptureMap.count(Var)) { // If we found a capture, any subcaptures are nested Nested = true; - if (shouldAddConstForScope(CSI, var)) - type.addConst(); + if (shouldAddConstForScope(CSI, Var)) + Type.addConst(); break; } - functionScopesIndex--; - DC = ParentDC; - } while (var->getDeclContext() != DC); - - bool hasBlocksAttr = var->hasAttr<BlocksAttr>(); - - for (unsigned i = functionScopesIndex + 1, - e = FunctionScopes.size(); i != e; ++i) { - CapturingScopeInfo *CSI = cast<CapturingScopeInfo>(FunctionScopes[i]); - bool isBlock = isa<BlockScopeInfo>(CSI); - bool isLambda = isa<LambdaScopeInfo>(CSI); + bool IsBlock = isa<BlockScopeInfo>(CSI); + bool IsLambda = isa<LambdaScopeInfo>(CSI); // Lambdas are not allowed to capture unnamed variables // (e.g. anonymous unions). // FIXME: The C++11 rule don't actually state this explicitly, but I'm // assuming that's the intent. - if (isLambda && !var->getDeclName()) { - Diag(loc, diag::err_lambda_capture_anonymous_var); - Diag(var->getLocation(), diag::note_declared_at); - return; + if (IsLambda && !Var->getDeclName()) { + if (Diagnose) { + Diag(Loc, diag::err_lambda_capture_anonymous_var); + Diag(Var->getLocation(), diag::note_declared_at); + } + return false; } // Prohibit variably-modified types; they're difficult to deal with. - if (type->isVariablyModifiedType()) { - if (isBlock) - Diag(loc, diag::err_ref_vm_type); - else - Diag(loc, diag::err_lambda_capture_vm_type) << var->getDeclName(); - Diag(var->getLocation(), diag::note_previous_decl) << var->getDeclName(); - return; + if (Type->isVariablyModifiedType()) { + if (Diagnose) { + if (IsBlock) + Diag(Loc, diag::err_ref_vm_type); + else + Diag(Loc, diag::err_lambda_capture_vm_type) << Var->getDeclName(); + Diag(Var->getLocation(), diag::note_previous_decl) + << Var->getDeclName(); + } + return false; } // Blocks are not allowed to capture arrays. - if (isBlock && type->isArrayType()) { - Diag(loc, diag::err_ref_array_type); - Diag(var->getLocation(), diag::note_previous_decl) << var->getDeclName(); - return; + if (IsBlock && Type->isArrayType()) { + if (Diagnose) { + Diag(Loc, diag::err_ref_array_type); + Diag(Var->getLocation(), diag::note_previous_decl) + << Var->getDeclName(); + } + return false; } // Lambdas are not allowed to capture __block variables; they don't // support the expected semantics. - if (isLambda && hasBlocksAttr) { - Diag(loc, diag::err_lambda_capture_block) << var->getDeclName(); - Diag(var->getLocation(), diag::note_previous_decl) << var->getDeclName(); - return; + if (IsLambda && HasBlocksAttr) { + if (Diagnose) { + Diag(Loc, diag::err_lambda_capture_block) + << Var->getDeclName(); + Diag(Var->getLocation(), diag::note_previous_decl) + << Var->getDeclName(); + } + return false; } + if (CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_None && !Explicit) { + // No capture-default + if (Diagnose) { + Diag(Loc, diag::err_lambda_impcap) << Var->getDeclName(); + Diag(Var->getLocation(), diag::note_previous_decl) + << Var->getDeclName(); + Diag(cast<LambdaScopeInfo>(CSI)->Lambda->getLocStart(), + diag::note_lambda_decl); + } + return false; + } + + FunctionScopesIndex--; + DC = ParentDC; + Explicit = false; + } while (!Var->getDeclContext()->Equals(DC)); + + ++FunctionScopesIndex; + return !Type->isVariablyModifiedType(); +} + +// Check if the variable needs to be captured; if so, try to perform +// the capture. +void Sema::TryCaptureVar(VarDecl *var, SourceLocation loc, + TryCaptureKind Kind) { + QualType type; + unsigned functionScopesIndex; + bool Nested; + // Determine whether we can capture this variable, and where to + // start capturing. + if (!canCaptureVariable(var, loc, /*Explicit=*/Kind != TryCapture_Implicit, + /*Diagnose=*/true, type, functionScopesIndex, Nested)) + return; + + bool hasBlocksAttr = var->hasAttr<BlocksAttr>(); + + for (unsigned i = functionScopesIndex, + e = FunctionScopes.size(); i != e; ++i) { + CapturingScopeInfo *CSI = cast<CapturingScopeInfo>(FunctionScopes[i]); + bool isLambda = isa<LambdaScopeInfo>(CSI); + bool byRef; bool isInnermostCapture = (i == e - 1); if (isInnermostCapture && Kind == TryCapture_ExplicitByVal) { byRef = false; } else if (isInnermostCapture && Kind == TryCapture_ExplicitByRef) { byRef = true; - } else if (CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_None) { - // No capture-default - Diag(loc, diag::err_lambda_impcap) << var->getDeclName(); - Diag(var->getLocation(), diag::note_previous_decl) << var->getDeclName(); - Diag(cast<LambdaScopeInfo>(CSI)->Lambda->getLocStart(), - diag::note_lambda_decl); - return; } else if (CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_LambdaByval) { // capture-default '=' byRef = false; diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 7d9a33af11f..a235872d8fa 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -11,6 +11,7 @@ // //===----------------------------------------------------------------------===// +#include "clang/Sema/ScopeInfo.h" #include "clang/Sema/SemaInternal.h" #include "clang/Sema/Template.h" #include "clang/Basic/OpenCL.h" @@ -4368,12 +4369,98 @@ QualType Sema::BuildTypeofExprType(Expr *E, SourceLocation Loc) { return Context.getTypeOfExprType(E); } +/// getDecltypeForExpr - Given an expr, will return the decltype for +/// that expression, according to the rules in C++11 +/// [dcl.type.simple]p4 and C++11 [expr.lambda.prim]p18. +static QualType getDecltypeForExpr(Sema &S, Expr *E) { + if (E->isTypeDependent()) + return S.Context.DependentTy; + + // If e is an id expression or a class member access, decltype(e) is defined + // as the type of the entity named by e. + if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) { + if (const ValueDecl *VD = dyn_cast<ValueDecl>(DRE->getDecl())) + return VD->getType(); + } + if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) { + if (const FieldDecl *FD = dyn_cast<FieldDecl>(ME->getMemberDecl())) + return FD->getType(); + } + // If e is a function call or an invocation of an overloaded operator, + // (parentheses around e are ignored), decltype(e) is defined as the + // return type of that function. + if (const CallExpr *CE = dyn_cast<CallExpr>(E->IgnoreParens())) + return CE->getCallReturnType(); + + // C++11 [expr.lambda.prim]p18: + // Every occurrence of decltype((x)) where x is a possibly + // parenthesized id-expression that names an entity of automatic + // storage duration is treated as if x were transformed into an + // access to a corresponding data member of the closure type that + // would have been declared if x were an odr-use of the denoted + // entity. + using namespace sema; + if (S.getCurLambda()) { + if (isa<ParenExpr>(E)) { + if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParens())) { + if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl())) { + QualType T = Var->getType(); + unsigned FunctionScopesIndex; + bool Nested; + // Determine whether we can capture this variable. + if (S.canCaptureVariable(Var, DRE->getLocation(), + /*Explicit=*/false, /*Diagnose=*/false, + T, FunctionScopesIndex, Nested)) { + // Outer lambda scopes may have an effect on the type of a + // capture. Walk the captures outside-in to determine + // whether they can add 'const' to a capture by copy. + if (FunctionScopesIndex == S.FunctionScopes.size()) + --FunctionScopesIndex; + for (unsigned I = FunctionScopesIndex, + E = S.FunctionScopes.size(); + I != E; ++I) { + LambdaScopeInfo *LSI + = dyn_cast<LambdaScopeInfo>(S.FunctionScopes[I]); + if (!LSI) + continue; + + bool ByRef = false; + if (LSI->isCaptured(Var)) + ByRef = LSI->getCapture(Var).isReferenceCapture(); + else + ByRef = (LSI->ImpCaptureStyle + == CapturingScopeInfo::ImpCap_LambdaByref); + + T = S.getLambdaCaptureFieldType(T, ByRef); + if (!ByRef && !LSI->Mutable) + T.addConst(); + } + + if (!T->isReferenceType()) + T = S.Context.getLValueReferenceType(T); + return T; + } + } + } + } + } + + QualType T = E->getType(); + + // Otherwise, where T is the type of e, if e is an lvalue, decltype(e) is + // defined as T&, otherwise decltype(e) is defined as T. + if (E->isLValue()) + T = S.Context.getLValueReferenceType(T); + + return T; +} + QualType Sema::BuildDecltypeType(Expr *E, SourceLocation Loc) { ExprResult ER = CheckPlaceholderExpr(E); if (ER.isInvalid()) return QualType(); E = ER.take(); - return Context.getDecltypeType(E); + return Context.getDecltypeType(E, getDecltypeForExpr(*this, E)); } QualType Sema::BuildUnaryTransformType(QualType BaseType, diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 312f5c718f0..75b5d68ce65 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -3928,8 +3928,10 @@ QualType ASTReader::readTypeRecord(unsigned Index) { return Context.getTypeOfType(UnderlyingType); } - case TYPE_DECLTYPE: - return Context.getDecltypeType(ReadExpr(*Loc.F)); + case TYPE_DECLTYPE: { + QualType UnderlyingType = readType(*Loc.F, Record, Idx); + return Context.getDecltypeType(ReadExpr(*Loc.F), UnderlyingType); + } case TYPE_UNARY_TRANSFORM: { QualType BaseType = readType(*Loc.F, Record, Idx); diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index 5364aa83cb8..7a0fed720f8 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -222,6 +222,7 @@ void ASTTypeWriter::VisitTypeOfType(const TypeOfType *T) { } void ASTTypeWriter::VisitDecltypeType(const DecltypeType *T) { + Writer.AddTypeRef(T->getUnderlyingType(), Record); Writer.AddStmt(T->getUnderlyingExpr()); Code = TYPE_DECLTYPE; } diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p12.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p12.cpp index fdf6c53633d..e7eb5af8913 100644 --- a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p12.cpp +++ b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p12.cpp @@ -65,11 +65,11 @@ void f1(int i) { // expected-note{{declared here}} void work(int n) { // expected-note{{declared here}} int m = n*n; int j = 40; // expected-note{{declared here}} - auto m3 = [this,m] { // expected-note 2{{lambda expression begins here}} + auto m3 = [this,m] { // expected-note 3{{lambda expression begins here}} auto m4 = [&,j] { // expected-error{{variable 'j' cannot be implicitly captured in a lambda with no capture-default specified}} int x = n; // expected-error{{variable 'n' cannot be implicitly captured in a lambda with no capture-default specified}} x += m; - x += i; // expected-error{{reference to local variable 'i' declared in enclosing function 'f1'}} + x += i; // expected-error{{variable 'i' cannot be implicitly captured in a lambda with no capture-default specified}} x += f; }; }; diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p18.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p18.cpp new file mode 100644 index 00000000000..561ead1271e --- /dev/null +++ b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p18.cpp @@ -0,0 +1,41 @@ +// RUN: %clang_cc1 -std=c++11 %s -Wunused -verify + +template<typename T, typename U> +struct is_same { + static const bool value = false; +}; + +template<typename T> +struct is_same<T, T> { + static const bool value = true; +}; + +void f3() { + float x, &r = x; + int i; + int &ir = i; + const int &irc = i; + + [=,&irc,&ir] { + static_assert(is_same<decltype(x), float>::value, "should be float"); + static_assert(is_same<decltype((x)), const float&>::value, + "should be const float&"); + static_assert(is_same<decltype(r), float&>::value, "should be float&"); + static_assert(is_same<decltype(((r))), float const&>::value, + "should be const float&"); + static_assert(is_same<decltype(ir), int&>::value, "should be int&"); + static_assert(is_same<decltype((ir)), int&>::value, "should be int&"); + static_assert(is_same<decltype(irc), const int&>::value, + "should be const int&"); + static_assert(is_same<decltype((irc)), const int&>::value, + "should be const int&"); + }(); + + [=] { + [=] () mutable { + static_assert(is_same<decltype(x), float>::value, "should be float"); + static_assert(is_same<decltype((x)), const float&>::value, + "should be const float&"); + }(); + }(); +} diff --git a/clang/test/SemaCXX/lambda-expressions.cpp b/clang/test/SemaCXX/lambda-expressions.cpp index 1da57c6c726..afbf9a1fffc 100644 --- a/clang/test/SemaCXX/lambda-expressions.cpp +++ b/clang/test/SemaCXX/lambda-expressions.cpp @@ -72,7 +72,8 @@ namespace ImplicitCapture { int f[10]; // expected-note {{declared}} [&]() { return f[2]; }; - (void) ^{ return []() { return f[2]; }; }; // expected-error {{cannot refer to declaration with an array type inside block}} + (void) ^{ return []() { return f[2]; }; }; // expected-error {{variable 'f' cannot be implicitly captured in a lambda with no capture-default specified}} \ + // expected-note{{lambda expression begins here}} struct G { G(); G(G&); int a; }; // expected-note 6 {{not viable}} G g; |