[cfe-commits] r147917 - in /cfe/trunk: include/clang/Sema/ScopeInfo.h lib/Driver/ToolChains.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaExprCXX.cpp lib/Sema/SemaExprObjC.cpp lib/Sema/TreeTransform.h
Eli Friedman
eli.friedman at gmail.com
Tue Jan 10 18:36:31 PST 2012
Author: efriedma
Date: Tue Jan 10 20:36:31 2012
New Revision: 147917
URL: http://llvm.org/viewvc/llvm-project?rev=147917&view=rev
Log:
Start refactoring code for capturing variables and 'this' so that it is shared between lambda expressions and block literals.
Modified:
cfe/trunk/include/clang/Sema/ScopeInfo.h
cfe/trunk/lib/Driver/ToolChains.cpp
cfe/trunk/lib/Sema/SemaExpr.cpp
cfe/trunk/lib/Sema/SemaExprCXX.cpp
cfe/trunk/lib/Sema/SemaExprObjC.cpp
cfe/trunk/lib/Sema/TreeTransform.h
Modified: cfe/trunk/include/clang/Sema/ScopeInfo.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/ScopeInfo.h?rev=147917&r1=147916&r2=147917&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/ScopeInfo.h (original)
+++ cfe/trunk/include/clang/Sema/ScopeInfo.h Tue Jan 10 20:36:31 2012
@@ -117,8 +117,86 @@
static bool classof(const FunctionScopeInfo *FSI) { return true; }
};
+class CapturingScopeInfo : public FunctionScopeInfo {
+public:
+ enum ImplicitCaptureStyle {
+ ImpCap_None, ImpCap_LambdaByval, ImpCap_LambdaByref, ImpCap_Block
+ };
+
+ ImplicitCaptureStyle ImpCaptureStyle;
+
+ class Capture {
+ enum CaptureKind {
+ Cap_This, Cap_ByVal, Cap_ByRef
+ };
+
+ // The variable being captured (if we are not capturing 'this'),
+ // and misc bits descibing the capture.
+ llvm::PointerIntPair<VarDecl*, 2, CaptureKind> VarAndKind;
+
+ // Expression to initialize a field of the given type, 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.
+ llvm::PointerIntPair<Expr*, 1, bool> CopyExprAndNested;
+
+ public:
+ Capture(VarDecl *Var, bool isByref, bool isNested, Expr *Cpy)
+ : VarAndKind(Var, isByref ? Cap_ByRef : Cap_ByVal),
+ CopyExprAndNested(Cpy, isNested) {}
+
+ enum IsThisCapture { ThisCapture };
+ Capture(IsThisCapture, bool isNested)
+ : VarAndKind(0, Cap_This),
+ CopyExprAndNested(0, isNested) {
+ }
+
+ bool isThisCapture() const { return VarAndKind.getInt() == Cap_This; }
+ bool isVariableCapture() const { return !isThisCapture(); }
+ bool isCopyCapture() const { return VarAndKind.getInt() == Cap_ByVal; }
+ bool isReferenceCapture() const { return VarAndKind.getInt() == Cap_ByRef; }
+ bool isNested() { return CopyExprAndNested.getInt(); }
+
+ VarDecl *getVariable() const {
+ return VarAndKind.getPointer();
+ }
+ Expr *getCopyExpr() const {
+ return CopyExprAndNested.getPointer();
+ }
+ };
+
+ CapturingScopeInfo(DiagnosticsEngine &Diag, ImplicitCaptureStyle Style)
+ : FunctionScopeInfo(Diag), ImpCaptureStyle(Style), CXXThisCaptureIndex(0)
+ {}
+
+ /// CaptureMap - A map of captured variables to (index+1) into Captures.
+ llvm::DenseMap<VarDecl*, unsigned> CaptureMap;
+
+ /// CXXThisCaptureIndex - The (index+1) of the capture of 'this';
+ /// zero if 'this' is not captured.
+ unsigned CXXThisCaptureIndex;
+
+ /// Captures - The captures.
+ SmallVector<Capture, 4> Captures;
+
+ void AddCapture(VarDecl *Var, bool isByref, bool isNested, Expr *Cpy) {
+ Captures.push_back(Capture(Var, isByref, isNested, Cpy));
+ CaptureMap[Var] = Captures.size();
+ }
+
+ void AddThisCapture(bool isNested) {
+ Captures.push_back(Capture(Capture::ThisCapture, isNested));
+ CXXThisCaptureIndex = Captures.size();
+ }
+
+ static bool classof(const FunctionScopeInfo *FSI) {
+ return FSI->Kind == SK_Block || FSI->Kind == SK_Lambda;
+ }
+ static bool classof(const CapturingScopeInfo *BSI) { return true; }
+};
+
/// \brief Retains information about a block that is currently being parsed.
-class BlockScopeInfo : public FunctionScopeInfo {
+class BlockScopeInfo : public CapturingScopeInfo {
public:
BlockDecl *TheDecl;
@@ -134,18 +212,9 @@
/// Its return type may be BuiltinType::Dependent.
QualType FunctionType;
- /// CaptureMap - A map of captured variables to (index+1) into Captures.
- llvm::DenseMap<VarDecl*, unsigned> CaptureMap;
-
- /// Captures - The captured variables.
- SmallVector<BlockDecl::Capture, 4> Captures;
-
- /// CapturesCXXThis - Whether this block captures 'this'.
- bool CapturesCXXThis;
-
BlockScopeInfo(DiagnosticsEngine &Diag, Scope *BlockScope, BlockDecl *Block)
- : FunctionScopeInfo(Diag), TheDecl(Block), TheScope(BlockScope),
- CapturesCXXThis(false)
+ : CapturingScopeInfo(Diag, ImpCap_Block), TheDecl(Block),
+ TheScope(BlockScope)
{
Kind = SK_Block;
}
@@ -158,70 +227,30 @@
static bool classof(const BlockScopeInfo *BSI) { return true; }
};
-class LambdaScopeInfo : public FunctionScopeInfo {
+class LambdaScopeInfo : public CapturingScopeInfo {
public:
-
- class Capture {
- llvm::PointerIntPair<VarDecl*, 2, LambdaCaptureKind> InitAndKind;
-
- public:
- Capture(VarDecl *Var, LambdaCaptureKind Kind)
- : InitAndKind(Var, Kind) {}
-
- enum IsThisCapture { ThisCapture };
- Capture(IsThisCapture)
- : InitAndKind(0, LCK_This) {}
-
- bool isThisCapture() const { return InitAndKind.getInt() == LCK_This; }
- bool isVariableCapture() const { return !isThisCapture(); }
- bool isCopyCapture() const { return InitAndKind.getInt() == LCK_ByCopy; }
- bool isReferenceCapture() const { return InitAndKind.getInt() == LCK_ByRef; }
-
- VarDecl *getVariable() const {
- return InitAndKind.getPointer();
- }
-
- };
-
/// \brief The class that describes the lambda.
CXXRecordDecl *Lambda;
- /// \brief A mapping from the set of captured variables to the
- /// fields (within the lambda class) that represent the captured variables.
- llvm::DenseMap<VarDecl *, FieldDecl *> CapturedVariables;
-
- /// \brief The list of captured variables, starting with the explicit
- /// captures and then finishing with any implicit captures.
- llvm::SmallVector<Capture, 4> Captures;
-
- // \brief Whether we have already captured 'this'.
- bool CapturesCXXThis;
-
/// \brief The number of captures in the \c Captures list that are
/// explicit captures.
unsigned NumExplicitCaptures;
- LambdaCaptureDefault Default;
-
- /// \brief The field associated with the captured 'this' pointer.
- FieldDecl *ThisCapture;
-
/// \brief - Whether the return type of the lambda is implicit
bool HasImplicitReturnType;
/// ReturnType - The return type of the lambda, or null if unknown.
QualType ReturnType;
- LambdaScopeInfo(DiagnosticsEngine &Diag, CXXRecordDecl *Lambda)
- : FunctionScopeInfo(Diag), Lambda(Lambda), CapturesCXXThis(false),
- NumExplicitCaptures(0), Default(LCD_None), ThisCapture(0),
- HasImplicitReturnType(false)
+ LambdaScopeInfo(DiagnosticsEngine &Diag, CXXRecordDecl *Lambda)
+ : CapturingScopeInfo(Diag, ImpCap_None), Lambda(Lambda),
+ NumExplicitCaptures(0), HasImplicitReturnType(false)
{
Kind = SK_Lambda;
}
-
+
virtual ~LambdaScopeInfo();
-
+
static bool classof(const FunctionScopeInfo *FSI) {
return FSI->Kind == SK_Lambda;
}
Modified: cfe/trunk/lib/Driver/ToolChains.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Driver/ToolChains.cpp?rev=147917&r1=147916&r2=147917&view=diff
==============================================================================
--- cfe/trunk/lib/Driver/ToolChains.cpp (original)
+++ cfe/trunk/lib/Driver/ToolChains.cpp Tue Jan 10 20:36:31 2012
@@ -533,24 +533,15 @@
Arg *iOSVersion = Args.getLastArg(options::OPT_miphoneos_version_min_EQ);
Arg *iOSSimVersion = Args.getLastArg(
options::OPT_mios_simulator_version_min_EQ);
-
- // FIXME: HACK! When compiling for the simulator we don't get a
- // '-miphoneos-version-min' to help us know whether there is an ARC runtime
- // or not; try to parse a __IPHONE_OS_VERSION_MIN_REQUIRED
- // define passed in command-line.
- if (!iOSVersion && !iOSSimVersion) {
+
+ if (!iOSSimVersion) {
+ // As a legacy hack, treat -D__IPHONE_OS_VERSION_MIN_REQUIRED=40201 as
+ // equivalent to -mios-simulator-version-min.
for (arg_iterator it = Args.filtered_begin(options::OPT_D),
ie = Args.filtered_end(); it != ie; ++it) {
StringRef define = (*it)->getValue(Args);
if (define.startswith(SimulatorVersionDefineName())) {
- unsigned Major = 0, Minor = 0, Micro = 0;
- if (GetVersionFromSimulatorDefine(define, Major, Minor, Micro) &&
- Major < 10 && Minor < 100 && Micro < 100) {
- ARCRuntimeForSimulator = Major < 5 ? ARCSimulator_NoARCRuntime
- : ARCSimulator_HasARCRuntime;
- LibCXXForSimulator = Major < 5 ? LibCXXSimulator_NotAvailable
- : LibCXXSimulator_Available;
- }
+ iOSSimVersion = *it;
break;
}
}
@@ -661,11 +652,21 @@
} else {
const Arg *Version = iOSVersion ? iOSVersion : iOSSimVersion;
assert(Version && "Unknown target platform!");
- if (!Driver::GetReleaseVersion(Version->getValue(Args), Major, Minor,
- Micro, HadExtra) || HadExtra ||
- Major >= 10 || Minor >= 100 || Micro >= 100)
- getDriver().Diag(diag::err_drv_invalid_version_number)
- << Version->getAsString(Args);
+ if (Version->getOption().getID() == options::OPT_D) {
+ // If the simulator version comes from a define, parse that.
+ if (!GetVersionFromSimulatorDefine(Version->getValue(Args), Major,
+ Minor, Micro) ||
+ Major >= 10 || Minor >= 100 || Micro >= 100)
+ getDriver().Diag(diag::err_drv_invalid_version_number)
+ << Version->getAsString(Args);
+ } else {
+ // Otherwise, use the normal version parsing code.
+ if (!Driver::GetReleaseVersion(Version->getValue(Args), Major, Minor,
+ Micro, HadExtra) ||
+ HadExtra || Major >= 10 || Minor >= 100 || Micro >= 100)
+ getDriver().Diag(diag::err_drv_invalid_version_number)
+ << Version->getAsString(Args);
+ }
}
bool IsIOSSim = bool(iOSSimVersion);
Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=147917&r1=147916&r2=147917&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Tue Jan 10 20:36:31 2012
@@ -1248,20 +1248,16 @@
/// There is a well-formed capture at a particular scope level;
/// propagate it through all the nested blocks.
static CaptureResult propagateCapture(Sema &S, unsigned ValidScopeIndex,
- const BlockDecl::Capture &Capture) {
- VarDecl *var = Capture.getVariable();
-
+ const CapturingScopeInfo::Capture &Cap) {
// Update all the inner blocks with the capture information.
for (unsigned i = ValidScopeIndex + 1, e = S.FunctionScopes.size();
i != e; ++i) {
BlockScopeInfo *innerBlock = cast<BlockScopeInfo>(S.FunctionScopes[i]);
- innerBlock->Captures.push_back(
- BlockDecl::Capture(Capture.getVariable(), Capture.isByRef(),
- /*nested*/ true, Capture.getCopyExpr()));
- innerBlock->CaptureMap[var] = innerBlock->Captures.size(); // +1
+ innerBlock->AddCapture(Cap.getVariable(), Cap.isReferenceCapture(),
+ /*nested*/ true, Cap.getCopyExpr());
}
- return Capture.isByRef() ? CR_CaptureByRef : CR_Capture;
+ return Cap.isReferenceCapture() ? CR_CaptureByRef : CR_Capture;
}
/// shouldCaptureValueReference - Determine if a reference to the
@@ -1372,9 +1368,7 @@
cast<BlockScopeInfo>(S.FunctionScopes[functionScopesIndex]);
// Build a valid capture in this scope.
- blockScope->Captures.push_back(
- BlockDecl::Capture(var, byRef, /*nested*/ false, copyExpr));
- blockScope->CaptureMap[var] = blockScope->Captures.size(); // +1
+ blockScope->AddCapture(var, byRef, /*nested*/ false, copyExpr);
// Propagate that to inner captures if necessary.
return propagateCapture(S, functionScopesIndex,
@@ -8861,8 +8855,18 @@
QualType BlockTy;
// Set the captured variables on the block.
- BSI->TheDecl->setCaptures(Context, BSI->Captures.begin(), BSI->Captures.end(),
- BSI->CapturesCXXThis);
+ // FIXME: Share capture structure between BlockDecl and CapturingScopeInfo!
+ SmallVector<BlockDecl::Capture, 4> Captures;
+ for (unsigned i = 0, e = BSI->Captures.size(); i != e; i++) {
+ CapturingScopeInfo::Capture &Cap = BSI->Captures[i];
+ if (Cap.isThisCapture())
+ continue;
+ BlockDecl::Capture NewCap(Cap.getVariable(), Cap.isReferenceCapture(),
+ Cap.isNested(), Cap.getCopyExpr());
+ Captures.push_back(NewCap);
+ }
+ BSI->TheDecl->setCaptures(Context, Captures.begin(), Captures.end(),
+ BSI->CXXThisCaptureIndex != 0);
// If the user wrote a function type in some form, try to use that.
if (!BSI->FunctionType.isNull()) {
Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=147917&r1=147916&r2=147917&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Tue Jan 10 20:36:31 2012
@@ -680,19 +680,21 @@
// Otherwise, check that we can capture 'this'.
unsigned NumClosures = 0;
for (unsigned idx = FunctionScopes.size() - 1; idx != 0; idx--) {
- if (LambdaScopeInfo *LSI = dyn_cast<LambdaScopeInfo>(FunctionScopes[idx])) {
- if (LSI->CapturesCXXThis) {
- // This lambda already captures 'this'; there isn't anything more to do.
+ if (CapturingScopeInfo *CSI =
+ dyn_cast<CapturingScopeInfo>(FunctionScopes[idx])) {
+ if (CSI->CXXThisCaptureIndex != 0) {
+ // 'this' is already being captured; there isn't anything more to do.
break;
}
- if (LSI->Default == LCD_ByRef) {
- // This lambda can implicitly capture 'this'; continue looking upwards.
+ if (CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_LambdaByref ||
+ CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_Block) {
+ // This closure can implicitly capture 'this'; continue looking upwards.
// FIXME: Is this check correct? The rules in the standard are a bit
// unclear.
NumClosures++;
continue;
}
- // This lambda can't implicitly capture 'this'; fail out.
+ // This context can't implicitly capture 'this'; fail out.
// (We need to delay the diagnostic in the
// PotentiallyPotentiallyEvaluated case because it doesn't apply to
// unevaluated contexts.)
@@ -703,10 +705,6 @@
Diag(Loc, diag::err_implicit_this_capture);
return;
}
- if (isa<BlockScopeInfo>(FunctionScopes[idx])) {
- NumClosures++;
- continue;
- }
break;
}
@@ -715,14 +713,9 @@
// contexts.
for (unsigned idx = FunctionScopes.size() - 1;
NumClosures; --idx, --NumClosures) {
- if (BlockScopeInfo *BSI = dyn_cast<BlockScopeInfo>(FunctionScopes[idx])) {
- BSI->CapturesCXXThis = true;
- } else {
- LambdaScopeInfo *LSI = dyn_cast<LambdaScopeInfo>(FunctionScopes[idx]);
- assert(LSI && "Unexpected closure");
- LSI->CapturesCXXThis = true;
- LSI->Captures.push_back(LambdaScopeInfo::Capture::ThisCapture);
- }
+ CapturingScopeInfo *CSI = cast<CapturingScopeInfo>(FunctionScopes[idx]);
+ bool isNested = NumClosures > 1;
+ CSI->AddThisCapture(isNested);
}
}
@@ -4831,8 +4824,9 @@
CurContext->addDecl(Class);
QualType ThisCaptureType;
+ llvm::DenseMap<VarDecl*, unsigned> CaptureMap;
+ unsigned CXXThisCaptureIndex = 0;
llvm::SmallVector<LambdaScopeInfo::Capture, 4> Captures;
- llvm::DenseMap<const IdentifierInfo*, SourceLocation> CapturesSoFar;
for (llvm::SmallVector<LambdaCapture, 4>::const_iterator
C = Intro.Captures.begin(), E = Intro.Captures.end(); C != E; ++C) {
if (C->Kind == LCK_This) {
@@ -4853,7 +4847,12 @@
}
CheckCXXThisCapture(C->Loc);
- Captures.push_back(LambdaScopeInfo::Capture::ThisCapture);
+ // FIXME: Need getCurCapture().
+ bool isNested = getCurBlock() || getCurLambda();
+ CapturingScopeInfo::Capture Cap(CapturingScopeInfo::Capture::ThisCapture,
+ isNested);
+ Captures.push_back(Cap);
+ CXXThisCaptureIndex = Captures.size();
continue;
}
@@ -4867,16 +4866,6 @@
continue;
}
- llvm::DenseMap<const IdentifierInfo*, SourceLocation>::iterator Appearance;
- bool IsFirstAppearance;
- llvm::tie(Appearance, IsFirstAppearance)
- = CapturesSoFar.insert(std::make_pair(C->Id, C->Loc));
-
- if (!IsFirstAppearance) {
- Diag(C->Loc, diag::err_capture_more_than_once) << C->Id;
- continue;
- }
-
DeclarationNameInfo Name(C->Id, C->Loc);
LookupResult R(*this, Name, LookupOrdinaryName);
CXXScopeSpec ScopeSpec;
@@ -4893,16 +4882,22 @@
continue;
}
+ if (CaptureMap.count(Var)) {
+ Diag(C->Loc, diag::err_capture_more_than_once) << C->Id;
+ continue;
+ }
+
if (!Var->hasLocalStorage()) {
Diag(C->Loc, diag::err_capture_non_automatic_variable) << C->Id;
continue;
}
- // FIXME: Actually capturing a variable is much more complicated than this
- // in the general case; see shouldCaptureValueReference.
- // FIXME: Should we be building a DeclRefExpr here? We don't really need
- // it until the point where we're actually building the LambdaExpr.
- Captures.push_back(LambdaScopeInfo::Capture(Var, C->Kind));
+ // FIXME: This is completely wrong for nested captures and variables
+ // with a non-trivial constructor.
+ // FIXME: We should refuse to capture __block variables.
+ Captures.push_back(LambdaScopeInfo::Capture(Var, C->Kind == LCK_ByRef,
+ /*isNested*/false, 0));
+ CaptureMap[Var] = Captures.size();
}
// Build the call operator; we don't really have all the relevant information
@@ -4982,15 +4977,20 @@
PushLambdaScope(Class);
LambdaScopeInfo *LSI = getCurLambda();
- LSI->Default = Intro.Default;
- if (!ThisCaptureType.isNull())
- LSI->CapturesCXXThis = true;
+ LSI->CXXThisCaptureIndex = CXXThisCaptureIndex;
+ std::swap(LSI->CaptureMap, CaptureMap);
std::swap(LSI->Captures, Captures);
+ LSI->NumExplicitCaptures = Captures.size();
+ if (Intro.Default == LCD_ByCopy)
+ LSI->ImpCaptureStyle = LambdaScopeInfo::ImpCap_LambdaByval;
+ else if (Intro.Default == LCD_ByRef)
+ LSI->ImpCaptureStyle = LambdaScopeInfo::ImpCap_LambdaByref;
const FunctionType *Fn = MethodTy->getAs<FunctionType>();
QualType RetTy = Fn->getResultType();
if (RetTy != Context.DependentTy) {
LSI->ReturnType = RetTy;
+ } else {
LSI->HasImplicitReturnType = true;
}
Modified: cfe/trunk/lib/Sema/SemaExprObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprObjC.cpp?rev=147917&r1=147916&r2=147917&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprObjC.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprObjC.cpp Tue Jan 10 20:36:31 2012
@@ -265,8 +265,7 @@
if (captureIndex) break;
bool nested = isa<BlockScopeInfo>(FunctionScopes[idx-1]);
- blockScope->Captures.push_back(
- BlockDecl::Capture(self, /*byref*/ false, nested, /*copy*/ 0));
+ blockScope->AddCapture(self, /*byref*/ false, nested, /*copy*/ 0);
captureIndex = blockScope->Captures.size(); // +1
}
Modified: cfe/trunk/lib/Sema/TreeTransform.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=147917&r1=147916&r2=147917&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/TreeTransform.h (original)
+++ cfe/trunk/lib/Sema/TreeTransform.h Tue Jan 10 20:36:31 2012
@@ -1890,6 +1890,7 @@
ExprResult RebuildCXXThisExpr(SourceLocation ThisLoc,
QualType ThisType,
bool isImplicit) {
+ getSema().CheckCXXThisCapture(ThisLoc);
return getSema().Owned(
new (getSema().Context) CXXThisExpr(ThisLoc, ThisType,
isImplicit));
@@ -8114,10 +8115,6 @@
BlockScopeInfo *blockScope = SemaRef.getCurBlock();
blockScope->TheDecl->setIsVariadic(oldBlock->isVariadic());
- // We built a new blockScopeInfo in call to ActOnBlockStart
- // in above, CapturesCXXThis need be set here from the block
- // expression.
- blockScope->CapturesCXXThis = oldBlock->capturesCXXThis();
blockScope->TheDecl->setBlockMissingReturnType(
oldBlock->blockMissingReturnType());
More information about the cfe-commits
mailing list