Refactor capture in blocks to use new-style capture hooks. Start adding a bit of the code for lambdas. The only visible changes are that we use the C++11 odr-used rules to figure out when a variable is captured, and type-checking in lambdas is slightly more accurate.
llvm-svn: 149663
This commit is contained in:
parent
d1956e46dd
commit
9bb33f572f
|
@ -1191,231 +1191,6 @@ Sema::ActOnStringLiteral(const Token *StringToks, unsigned NumStringToks) {
|
||||||
StringTokLocs.size()));
|
StringTokLocs.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
enum CaptureResult {
|
|
||||||
/// No capture is required.
|
|
||||||
CR_NoCapture,
|
|
||||||
|
|
||||||
/// A capture is required.
|
|
||||||
CR_Capture,
|
|
||||||
|
|
||||||
/// A by-ref capture is required.
|
|
||||||
CR_CaptureByRef,
|
|
||||||
|
|
||||||
/// An error occurred when trying to capture the given variable.
|
|
||||||
CR_Error
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Diagnose an uncapturable value reference.
|
|
||||||
///
|
|
||||||
/// \param var - the variable referenced
|
|
||||||
/// \param DC - the context which we couldn't capture through
|
|
||||||
static CaptureResult
|
|
||||||
diagnoseUncapturableValueReference(Sema &S, SourceLocation loc,
|
|
||||||
VarDecl *var, DeclContext *DC) {
|
|
||||||
switch (S.ExprEvalContexts.back().Context) {
|
|
||||||
case Sema::Unevaluated:
|
|
||||||
case Sema::ConstantEvaluated:
|
|
||||||
// The argument will never be evaluated at runtime, so don't complain.
|
|
||||||
return CR_NoCapture;
|
|
||||||
|
|
||||||
case Sema::PotentiallyEvaluated:
|
|
||||||
case Sema::PotentiallyEvaluatedIfUsed:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't diagnose about capture if we're not actually in code right
|
|
||||||
// now; in general, there are more appropriate places that will
|
|
||||||
// diagnose this.
|
|
||||||
if (!S.CurContext->isFunctionOrMethod()) return CR_NoCapture;
|
|
||||||
|
|
||||||
// Certain madnesses can happen with parameter declarations, which
|
|
||||||
// we want to ignore.
|
|
||||||
if (isa<ParmVarDecl>(var)) {
|
|
||||||
// - If the parameter still belongs to the translation unit, then
|
|
||||||
// we're actually just using one parameter in the declaration of
|
|
||||||
// the next. This is useful in e.g. VLAs.
|
|
||||||
if (isa<TranslationUnitDecl>(var->getDeclContext()))
|
|
||||||
return CR_NoCapture;
|
|
||||||
|
|
||||||
// - This particular madness can happen in ill-formed default
|
|
||||||
// arguments; claim it's okay and let downstream code handle it.
|
|
||||||
if (S.CurContext == var->getDeclContext()->getParent())
|
|
||||||
return CR_NoCapture;
|
|
||||||
}
|
|
||||||
|
|
||||||
DeclarationName functionName;
|
|
||||||
if (FunctionDecl *fn = dyn_cast<FunctionDecl>(var->getDeclContext()))
|
|
||||||
functionName = fn->getDeclName();
|
|
||||||
// FIXME: variable from enclosing block that we couldn't capture from!
|
|
||||||
|
|
||||||
S.Diag(loc, diag::err_reference_to_local_var_in_enclosing_function)
|
|
||||||
<< var->getIdentifier() << functionName;
|
|
||||||
S.Diag(var->getLocation(), diag::note_local_variable_declared_here)
|
|
||||||
<< var->getIdentifier();
|
|
||||||
|
|
||||||
return CR_Error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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 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->AddCapture(Cap.getVariable(), Cap.isReferenceCapture(),
|
|
||||||
/*nested*/ true, Cap.getLocation(),
|
|
||||||
Cap.getCopyExpr());
|
|
||||||
}
|
|
||||||
|
|
||||||
return Cap.isReferenceCapture() ? CR_CaptureByRef : CR_Capture;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// shouldCaptureValueReference - Determine if a reference to the
|
|
||||||
/// given value in the current context requires a variable capture.
|
|
||||||
///
|
|
||||||
/// This also keeps the captures set in the BlockScopeInfo records
|
|
||||||
/// up-to-date.
|
|
||||||
static CaptureResult shouldCaptureValueReference(Sema &S, SourceLocation loc,
|
|
||||||
ValueDecl *Value) {
|
|
||||||
// Only variables ever require capture.
|
|
||||||
VarDecl *var = dyn_cast<VarDecl>(Value);
|
|
||||||
if (!var) return CR_NoCapture;
|
|
||||||
|
|
||||||
// Fast path: variables from the current context never require capture.
|
|
||||||
DeclContext *DC = S.CurContext;
|
|
||||||
if (var->getDeclContext() == DC) return CR_NoCapture;
|
|
||||||
|
|
||||||
// Only variables with local storage require capture.
|
|
||||||
// FIXME: What about 'const' variables in C++?
|
|
||||||
if (!var->hasLocalStorage()) return CR_NoCapture;
|
|
||||||
|
|
||||||
// Otherwise, we need to capture.
|
|
||||||
|
|
||||||
unsigned functionScopesIndex = S.FunctionScopes.size() - 1;
|
|
||||||
do {
|
|
||||||
// Only blocks (and eventually C++0x closures) can capture; other
|
|
||||||
// scopes don't work.
|
|
||||||
if (!isa<BlockDecl>(DC))
|
|
||||||
return diagnoseUncapturableValueReference(S, loc, var, DC);
|
|
||||||
|
|
||||||
BlockScopeInfo *blockScope =
|
|
||||||
cast<BlockScopeInfo>(S.FunctionScopes[functionScopesIndex]);
|
|
||||||
assert(blockScope->TheDecl == static_cast<BlockDecl*>(DC));
|
|
||||||
|
|
||||||
// Check whether we've already captured it in this block. If so,
|
|
||||||
// we're done.
|
|
||||||
if (unsigned indexPlus1 = blockScope->CaptureMap[var])
|
|
||||||
return propagateCapture(S, functionScopesIndex,
|
|
||||||
blockScope->Captures[indexPlus1 - 1]);
|
|
||||||
|
|
||||||
functionScopesIndex--;
|
|
||||||
DC = cast<BlockDecl>(DC)->getDeclContext();
|
|
||||||
} while (var->getDeclContext() != DC);
|
|
||||||
|
|
||||||
// Okay, we descended all the way to the block that defines the variable.
|
|
||||||
// Actually try to capture it.
|
|
||||||
QualType type = var->getType();
|
|
||||||
|
|
||||||
// Prohibit variably-modified types.
|
|
||||||
if (type->isVariablyModifiedType()) {
|
|
||||||
S.Diag(loc, diag::err_ref_vm_type);
|
|
||||||
S.Diag(var->getLocation(), diag::note_declared_at);
|
|
||||||
return CR_Error;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prohibit arrays, even in __block variables, but not references to
|
|
||||||
// them.
|
|
||||||
if (type->isArrayType()) {
|
|
||||||
S.Diag(loc, diag::err_ref_array_type);
|
|
||||||
S.Diag(var->getLocation(), diag::note_declared_at);
|
|
||||||
return CR_Error;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The BlocksAttr indicates the variable is bound by-reference.
|
|
||||||
bool byRef = var->hasAttr<BlocksAttr>();
|
|
||||||
|
|
||||||
// Build a copy expression.
|
|
||||||
Expr *copyExpr = 0;
|
|
||||||
const RecordType *rtype;
|
|
||||||
if (!byRef && S.getLangOptions().CPlusPlus && !type->isDependentType() &&
|
|
||||||
(rtype = type->getAs<RecordType>())) {
|
|
||||||
|
|
||||||
// The capture logic needs the destructor, so make sure we mark it.
|
|
||||||
// Usually this is unnecessary because most local variables have
|
|
||||||
// their destructors marked at declaration time, but parameters are
|
|
||||||
// an exception because it's technically only the call site that
|
|
||||||
// actually requires the destructor.
|
|
||||||
if (isa<ParmVarDecl>(var))
|
|
||||||
S.FinalizeVarWithDestructor(var, rtype);
|
|
||||||
|
|
||||||
// According to the blocks spec, the capture of a variable from
|
|
||||||
// the stack requires a const copy constructor. This is not true
|
|
||||||
// of the copy/move done to move a __block variable to the heap.
|
|
||||||
type.addConst();
|
|
||||||
|
|
||||||
Expr *declRef = new (S.Context) DeclRefExpr(var, type, VK_LValue, loc);
|
|
||||||
ExprResult result =
|
|
||||||
S.PerformCopyInitialization(
|
|
||||||
InitializedEntity::InitializeBlock(var->getLocation(),
|
|
||||||
type, false),
|
|
||||||
loc, S.Owned(declRef));
|
|
||||||
|
|
||||||
// Build a full-expression copy expression if initialization
|
|
||||||
// succeeded and used a non-trivial constructor. Recover from
|
|
||||||
// errors by pretending that the copy isn't necessary.
|
|
||||||
if (!result.isInvalid() &&
|
|
||||||
!cast<CXXConstructExpr>(result.get())->getConstructor()->isTrivial()) {
|
|
||||||
result = S.MaybeCreateExprWithCleanups(result);
|
|
||||||
copyExpr = result.take();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// We're currently at the declarer; go back to the closure.
|
|
||||||
functionScopesIndex++;
|
|
||||||
BlockScopeInfo *blockScope =
|
|
||||||
cast<BlockScopeInfo>(S.FunctionScopes[functionScopesIndex]);
|
|
||||||
|
|
||||||
// Build a valid capture in this scope.
|
|
||||||
blockScope->AddCapture(var, byRef, /*nested*/ false, loc, copyExpr);
|
|
||||||
|
|
||||||
// Propagate that to inner captures if necessary.
|
|
||||||
return propagateCapture(S, functionScopesIndex,
|
|
||||||
blockScope->Captures.back());
|
|
||||||
}
|
|
||||||
|
|
||||||
static ExprResult BuildBlockDeclRefExpr(Sema &S, ValueDecl *VD,
|
|
||||||
const DeclarationNameInfo &NameInfo,
|
|
||||||
bool ByRef) {
|
|
||||||
assert(isa<VarDecl>(VD) && "capturing non-variable");
|
|
||||||
|
|
||||||
VarDecl *var = cast<VarDecl>(VD);
|
|
||||||
assert(var->hasLocalStorage() && "capturing non-local");
|
|
||||||
assert(ByRef == var->hasAttr<BlocksAttr>() && "byref set wrong");
|
|
||||||
|
|
||||||
QualType exprType = var->getType().getNonReferenceType();
|
|
||||||
|
|
||||||
BlockDeclRefExpr *BDRE;
|
|
||||||
if (!ByRef) {
|
|
||||||
// The variable will be bound by copy; make it const within the
|
|
||||||
// closure, but record that this was done in the expression.
|
|
||||||
bool constAdded = !exprType.isConstQualified();
|
|
||||||
exprType.addConst();
|
|
||||||
|
|
||||||
BDRE = new (S.Context) BlockDeclRefExpr(var, exprType, VK_LValue,
|
|
||||||
NameInfo.getLoc(), false,
|
|
||||||
constAdded);
|
|
||||||
} else {
|
|
||||||
BDRE = new (S.Context) BlockDeclRefExpr(var, exprType, VK_LValue,
|
|
||||||
NameInfo.getLoc(), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
S.MarkBlockDeclRefReferenced(BDRE);
|
|
||||||
|
|
||||||
return S.Owned(BDRE);
|
|
||||||
}
|
|
||||||
|
|
||||||
ExprResult
|
ExprResult
|
||||||
Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
|
Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
|
||||||
SourceLocation Loc,
|
SourceLocation Loc,
|
||||||
|
@ -2323,6 +2098,68 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
|
||||||
return Owned(ULE);
|
return Owned(ULE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool shouldBuildBlockDeclRef(ValueDecl *D, Sema &S) {
|
||||||
|
// Check for a variable with local storage not from the current scope;
|
||||||
|
// we need to create BlockDeclRefExprs for these.
|
||||||
|
// FIXME: BlockDeclRefExpr shouldn't exist!
|
||||||
|
VarDecl *var = dyn_cast<VarDecl>(D);
|
||||||
|
if (!var)
|
||||||
|
return false;
|
||||||
|
if (var->getDeclContext() == S.CurContext)
|
||||||
|
return false;
|
||||||
|
if (!var->hasLocalStorage())
|
||||||
|
return false;
|
||||||
|
return S.getCurBlock() != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool shouldAddConstQualToVarRef(ValueDecl *D, Sema &S) {
|
||||||
|
VarDecl *var = dyn_cast<VarDecl>(D);
|
||||||
|
if (!var)
|
||||||
|
return false;
|
||||||
|
if (var->getDeclContext() == S.CurContext)
|
||||||
|
return false;
|
||||||
|
if (!var->hasLocalStorage())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
LambdaScopeInfo *LSI = S.getCurLambda();
|
||||||
|
if (!LSI)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// We don't actually allow capturing a __block variable in a lambda, but
|
||||||
|
// this way gives better diagnostics.
|
||||||
|
if (var->hasAttr<BlocksAttr>())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// FIXME: Does the addition of const really only apply in
|
||||||
|
// potentially-evaluated contexts? The text in the lambda spec
|
||||||
|
// about decltype hints that it might apply in unevaluated contexts
|
||||||
|
// as well... and there's precent in our blocks implementation.
|
||||||
|
return !LSI->Mutable &&
|
||||||
|
S.ExprEvalContexts.back().Context != Sema::Unevaluated;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ExprResult BuildBlockDeclRefExpr(Sema &S, ValueDecl *VD,
|
||||||
|
const DeclarationNameInfo &NameInfo) {
|
||||||
|
VarDecl *var = cast<VarDecl>(VD);
|
||||||
|
QualType exprType = var->getType().getNonReferenceType();
|
||||||
|
|
||||||
|
bool HasBlockAttr = var->hasAttr<BlocksAttr>();
|
||||||
|
bool ConstAdded = false;
|
||||||
|
if (!HasBlockAttr) {
|
||||||
|
ConstAdded = !exprType.isConstQualified();
|
||||||
|
exprType.addConst();
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockDeclRefExpr *BDRE =
|
||||||
|
new (S.Context) BlockDeclRefExpr(var, exprType, VK_LValue,
|
||||||
|
NameInfo.getLoc(), HasBlockAttr,
|
||||||
|
ConstAdded);
|
||||||
|
|
||||||
|
S.MarkBlockDeclRefReferenced(BDRE);
|
||||||
|
|
||||||
|
return S.Owned(BDRE);
|
||||||
|
}
|
||||||
|
|
||||||
/// \brief Complete semantic analysis for a reference to the given declaration.
|
/// \brief Complete semantic analysis for a reference to the given declaration.
|
||||||
ExprResult
|
ExprResult
|
||||||
Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
|
Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
|
||||||
|
@ -2373,30 +2210,7 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
|
||||||
return BuildAnonymousStructUnionMemberReference(SS, NameInfo.getLoc(),
|
return BuildAnonymousStructUnionMemberReference(SS, NameInfo.getLoc(),
|
||||||
indirectField);
|
indirectField);
|
||||||
|
|
||||||
// If the identifier reference is inside a block, and it refers to a value
|
{
|
||||||
// that is outside the block, create a BlockDeclRefExpr instead of a
|
|
||||||
// DeclRefExpr. This ensures the value is treated as a copy-in snapshot when
|
|
||||||
// the block is formed.
|
|
||||||
//
|
|
||||||
// We do not do this for things like enum constants, global variables, etc,
|
|
||||||
// as they do not get snapshotted.
|
|
||||||
//
|
|
||||||
switch (shouldCaptureValueReference(*this, NameInfo.getLoc(), VD)) {
|
|
||||||
case CR_Error:
|
|
||||||
return ExprError();
|
|
||||||
|
|
||||||
case CR_Capture:
|
|
||||||
assert(!SS.isSet() && "referenced local variable with scope specifier?");
|
|
||||||
return BuildBlockDeclRefExpr(*this, VD, NameInfo, /*byref*/ false);
|
|
||||||
|
|
||||||
case CR_CaptureByRef:
|
|
||||||
assert(!SS.isSet() && "referenced local variable with scope specifier?");
|
|
||||||
return BuildBlockDeclRefExpr(*this, VD, NameInfo, /*byref*/ true);
|
|
||||||
|
|
||||||
case CR_NoCapture: {
|
|
||||||
// If this reference is not in a block or if the referenced
|
|
||||||
// variable is within the block, create a normal DeclRefExpr.
|
|
||||||
|
|
||||||
QualType type = VD->getType();
|
QualType type = VD->getType();
|
||||||
ExprValueKind valueKind = VK_RValue;
|
ExprValueKind valueKind = VK_RValue;
|
||||||
|
|
||||||
|
@ -2467,6 +2281,13 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
|
||||||
// These are always l-values.
|
// These are always l-values.
|
||||||
valueKind = VK_LValue;
|
valueKind = VK_LValue;
|
||||||
type = type.getNonReferenceType();
|
type = type.getNonReferenceType();
|
||||||
|
|
||||||
|
if (shouldBuildBlockDeclRef(VD, *this))
|
||||||
|
return BuildBlockDeclRefExpr(*this, VD, NameInfo);
|
||||||
|
|
||||||
|
if (shouldAddConstQualToVarRef(VD, *this))
|
||||||
|
type.addConst();
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Decl::Function: {
|
case Decl::Function: {
|
||||||
|
@ -2529,10 +2350,6 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
|
||||||
|
|
||||||
return BuildDeclRefExpr(VD, type, valueKind, NameInfo, &SS);
|
return BuildDeclRefExpr(VD, type, valueKind, NameInfo, &SS);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
llvm_unreachable("unknown capture result");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind) {
|
ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind) {
|
||||||
|
@ -9613,6 +9430,129 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func) {
|
||||||
Func->setUsed(true);
|
Func->setUsed(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
diagnoseUncapturableValueReference(Sema &S, SourceLocation loc,
|
||||||
|
VarDecl *var, DeclContext *DC) {
|
||||||
|
// If the parameter still belongs to the translation unit, then
|
||||||
|
// we're actually just using one parameter in the declaration of
|
||||||
|
// the next.
|
||||||
|
if (isa<ParmVarDecl>(var) &&
|
||||||
|
isa<TranslationUnitDecl>(var->getDeclContext()))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Don't diagnose about capture if we're not actually in code right
|
||||||
|
// now; in general, there are more appropriate places that will
|
||||||
|
// diagnose this.
|
||||||
|
// FIXME: We incorrectly skip diagnosing C++11 member initializers.
|
||||||
|
if (!S.CurContext->isFunctionOrMethod())
|
||||||
|
return;
|
||||||
|
|
||||||
|
DeclarationName functionName;
|
||||||
|
if (FunctionDecl *fn = dyn_cast<FunctionDecl>(var->getDeclContext()))
|
||||||
|
functionName = fn->getDeclName();
|
||||||
|
// FIXME: variable from enclosing block that we couldn't capture from!
|
||||||
|
|
||||||
|
S.Diag(loc, diag::err_reference_to_local_var_in_enclosing_function)
|
||||||
|
<< var->getIdentifier() << functionName;
|
||||||
|
S.Diag(var->getLocation(), diag::note_local_variable_declared_here)
|
||||||
|
<< var->getIdentifier();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tryCaptureVar(Sema &S, VarDecl *var,
|
||||||
|
SourceLocation loc) {
|
||||||
|
// Check if the variable needs to be captured.
|
||||||
|
DeclContext *DC = S.CurContext;
|
||||||
|
if (var->getDeclContext() == DC) return;
|
||||||
|
if (!var->hasLocalStorage()) return;
|
||||||
|
|
||||||
|
// Actually try to capture it.
|
||||||
|
QualType type = var->getType();
|
||||||
|
bool Nested = false;
|
||||||
|
|
||||||
|
unsigned functionScopesIndex = S.FunctionScopes.size() - 1;
|
||||||
|
do {
|
||||||
|
// Only blocks (and eventually C++0x closures) can capture; other
|
||||||
|
// scopes don't work.
|
||||||
|
// FIXME: Make this function support lambdas!
|
||||||
|
if (!isa<BlockDecl>(DC))
|
||||||
|
return diagnoseUncapturableValueReference(S, loc, var, DC);
|
||||||
|
|
||||||
|
BlockScopeInfo *blockScope =
|
||||||
|
cast<BlockScopeInfo>(S.FunctionScopes[functionScopesIndex]);
|
||||||
|
assert(blockScope->TheDecl == static_cast<BlockDecl*>(DC));
|
||||||
|
|
||||||
|
// Check whether we've already captured it in this block.
|
||||||
|
if (blockScope->CaptureMap.count(var)) {
|
||||||
|
Nested = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
functionScopesIndex--;
|
||||||
|
DC = cast<BlockDecl>(DC)->getDeclContext();
|
||||||
|
} while (var->getDeclContext() != DC);
|
||||||
|
|
||||||
|
bool byRef = var->hasAttr<BlocksAttr>();
|
||||||
|
|
||||||
|
for (unsigned i = functionScopesIndex + 1,
|
||||||
|
e = S.FunctionScopes.size(); i != e; ++i) {
|
||||||
|
// Prohibit variably-modified types.
|
||||||
|
if (type->isVariablyModifiedType()) {
|
||||||
|
S.Diag(loc, diag::err_ref_vm_type);
|
||||||
|
S.Diag(var->getLocation(), diag::note_declared_at);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prohibit arrays, even in __block variables, but not references to
|
||||||
|
// them.
|
||||||
|
if (type->isArrayType()) {
|
||||||
|
S.Diag(loc, diag::err_ref_array_type);
|
||||||
|
S.Diag(var->getLocation(), diag::note_declared_at);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build a copy expression.
|
||||||
|
Expr *copyExpr = 0;
|
||||||
|
const RecordType *rtype;
|
||||||
|
if (!byRef && S.getLangOptions().CPlusPlus && !type->isDependentType() &&
|
||||||
|
(rtype = type->getAs<RecordType>())) {
|
||||||
|
|
||||||
|
// The capture logic needs the destructor, so make sure we mark it.
|
||||||
|
// Usually this is unnecessary because most local variables have
|
||||||
|
// their destructors marked at declaration time, but parameters are
|
||||||
|
// an exception because it's technically only the call site that
|
||||||
|
// actually requires the destructor.
|
||||||
|
if (isa<ParmVarDecl>(var))
|
||||||
|
S.FinalizeVarWithDestructor(var, rtype);
|
||||||
|
|
||||||
|
// According to the blocks spec, the capture of a variable from
|
||||||
|
// the stack requires a const copy constructor. This is not true
|
||||||
|
// of the copy/move done to move a __block variable to the heap.
|
||||||
|
type.addConst();
|
||||||
|
|
||||||
|
Expr *declRef = new (S.Context) DeclRefExpr(var, type, VK_LValue, loc);
|
||||||
|
ExprResult result =
|
||||||
|
S.PerformCopyInitialization(
|
||||||
|
InitializedEntity::InitializeBlock(var->getLocation(),
|
||||||
|
type, false),
|
||||||
|
loc, S.Owned(declRef));
|
||||||
|
|
||||||
|
// Build a full-expression copy expression if initialization
|
||||||
|
// succeeded and used a non-trivial constructor. Recover from
|
||||||
|
// errors by pretending that the copy isn't necessary.
|
||||||
|
if (!result.isInvalid() &&
|
||||||
|
!cast<CXXConstructExpr>(result.get())->getConstructor()->isTrivial()) {
|
||||||
|
result = S.MaybeCreateExprWithCleanups(result);
|
||||||
|
copyExpr = result.take();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockScopeInfo *blockScope = cast<BlockScopeInfo>(S.FunctionScopes[i]);
|
||||||
|
blockScope->AddCapture(var, byRef, Nested, loc, copyExpr);
|
||||||
|
|
||||||
|
Nested = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void MarkVarDeclODRUsed(Sema &SemaRef, VarDecl *Var,
|
static void MarkVarDeclODRUsed(Sema &SemaRef, VarDecl *Var,
|
||||||
SourceLocation Loc) {
|
SourceLocation Loc) {
|
||||||
// Keep track of used but undefined variables.
|
// Keep track of used but undefined variables.
|
||||||
|
@ -9622,6 +9562,8 @@ static void MarkVarDeclODRUsed(Sema &SemaRef, VarDecl *Var,
|
||||||
if (old.isInvalid()) old = Loc;
|
if (old.isInvalid()) old = Loc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tryCaptureVar(SemaRef, Var, Loc);
|
||||||
|
|
||||||
Var->setUsed(true);
|
Var->setUsed(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9665,9 +9607,6 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
|
||||||
VarDecl *Var, Expr *E) {
|
VarDecl *Var, Expr *E) {
|
||||||
Var->setReferenced();
|
Var->setReferenced();
|
||||||
|
|
||||||
if (Var->isUsed(false))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!IsPotentiallyEvaluatedContext(SemaRef))
|
if (!IsPotentiallyEvaluatedContext(SemaRef))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue