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,
/// 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:
namespace clang {
class BlockDecl;
+class CXXMethodDecl;
class IdentifierInfo;
class LabelDecl;
class ReturnStmt;
class Scope;
class SwitchStmt;
+class VarDecl;
namespace sema {
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
};
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:
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);
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) {
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
// 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,
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.
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;
//
//===----------------------------------------------------------------------===//
+#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/Template.h"
#include "clang/Basic/OpenCL.h"
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,
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);
}
void ASTTypeWriter::VisitDecltypeType(const DecltypeType *T) {
+ Writer.AddTypeRef(T->getUnderlyingType(), Record);
Writer.AddStmt(T->getUnderlyingExpr());
Code = TYPE_DECLTYPE;
}
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;
};
};
--- /dev/null
+// 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&");
+ }();
+ }();
+}
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;