forked from OSchip/llvm-project
Revert r343518.
Bots are still failing. http://lab.llvm.org:8011/builders/sanitizer-x86_64-linux-fast/builds/24420 http://lab.llvm.org:8011/builders/llvm-clang-x86_64-expensive-checks-win/builds/12958 llvm-svn: 343531
This commit is contained in:
parent
97e0f52642
commit
3197484701
|
@ -965,8 +965,6 @@ protected:
|
|||
/// Defines kind of the ImplicitParamDecl: 'this', 'self', 'vtt', '_cmd' or
|
||||
/// something else.
|
||||
unsigned ImplicitParamKind : 3;
|
||||
|
||||
unsigned EscapingByref : 1;
|
||||
};
|
||||
|
||||
union {
|
||||
|
@ -1409,19 +1407,6 @@ public:
|
|||
NonParmVarDeclBits.PreviousDeclInSameBlockScope = Same;
|
||||
}
|
||||
|
||||
/// Indicates the capture is a __block variable that is captured by a block
|
||||
/// that can potentially escape (a block for which BlockDecl::doesNotEscape
|
||||
/// returns false).
|
||||
bool isEscapingByref() const;
|
||||
|
||||
/// Indicates the capture is a __block variable that is never captured by an
|
||||
/// escaping block.
|
||||
bool isNonEscapingByref() const;
|
||||
|
||||
void setEscapingByref() {
|
||||
NonParmVarDeclBits.EscapingByref = true;
|
||||
}
|
||||
|
||||
/// Retrieve the variable declaration from which this variable could
|
||||
/// be instantiated, if it is an instantiation (rather than a non-template).
|
||||
VarDecl *getTemplateInstantiationPattern() const;
|
||||
|
@ -3880,14 +3865,6 @@ public:
|
|||
/// variable.
|
||||
bool isByRef() const { return VariableAndFlags.getInt() & flag_isByRef; }
|
||||
|
||||
bool isEscapingByref() const {
|
||||
return getVariable()->isEscapingByref();
|
||||
}
|
||||
|
||||
bool isNonEscapingByref() const {
|
||||
return getVariable()->isNonEscapingByref();
|
||||
}
|
||||
|
||||
/// Whether this is a nested capture, i.e. the variable captured
|
||||
/// is not from outside the immediately enclosing function/block.
|
||||
bool isNested() const { return VariableAndFlags.getInt() & flag_isNested; }
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ADT/StringSwitch.h"
|
||||
#include "llvm/ADT/TinyPtrVector.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include <algorithm>
|
||||
|
@ -203,12 +202,6 @@ public:
|
|||
/// function.
|
||||
SmallVector<CompoundScopeInfo, 4> CompoundScopes;
|
||||
|
||||
/// The set of blocks that are introduced in this function.
|
||||
llvm::SmallPtrSet<const BlockDecl *, 1> Blocks;
|
||||
|
||||
/// The set of __block variables that are introduced in this function.
|
||||
llvm::TinyPtrVector<VarDecl *> ByrefBlockVars;
|
||||
|
||||
/// A list of PartialDiagnostics created but delayed within the
|
||||
/// current function scope. These diagnostics are vetted for reachability
|
||||
/// prior to being emitted.
|
||||
|
@ -433,16 +426,6 @@ public:
|
|||
(HasBranchProtectedScope && HasBranchIntoScope));
|
||||
}
|
||||
|
||||
// Add a block introduced in this function.
|
||||
void addBlock(const BlockDecl *BD) {
|
||||
Blocks.insert(BD);
|
||||
}
|
||||
|
||||
// Add a __block variable introduced in this function.
|
||||
void addByrefBlockVar(VarDecl *VD) {
|
||||
ByrefBlockVars.push_back(VD);
|
||||
}
|
||||
|
||||
bool isCoroutine() const { return !FirstCoroutineStmtLoc.isInvalid(); }
|
||||
|
||||
void setFirstCoroutineStmt(SourceLocation Loc, StringRef Keyword) {
|
||||
|
|
|
@ -2361,14 +2361,6 @@ static DeclT *getDefinitionOrSelf(DeclT *D) {
|
|||
return D;
|
||||
}
|
||||
|
||||
bool VarDecl::isEscapingByref() const {
|
||||
return hasAttr<BlocksAttr>() && NonParmVarDeclBits.EscapingByref;
|
||||
}
|
||||
|
||||
bool VarDecl::isNonEscapingByref() const {
|
||||
return hasAttr<BlocksAttr>() && !NonParmVarDeclBits.EscapingByref;
|
||||
}
|
||||
|
||||
VarDecl *VarDecl::getTemplateInstantiationPattern() const {
|
||||
// If it's a variable template specialization, find the template or partial
|
||||
// specialization from which it was instantiated.
|
||||
|
|
|
@ -493,11 +493,7 @@ static QualType getCaptureFieldType(const CodeGenFunction &CGF,
|
|||
return CGF.BlockInfo->getCapture(VD).fieldType();
|
||||
if (auto *FD = CGF.LambdaCaptureFields.lookup(VD))
|
||||
return FD->getType();
|
||||
// If the captured variable is a non-escaping __block variable, the field
|
||||
// type is the reference type. If the variable is a __block variable that
|
||||
// already has a reference type, the field type is the variable's type.
|
||||
return VD->isNonEscapingByref() ?
|
||||
CGF.getContext().getLValueReferenceType(VD->getType()) : VD->getType();
|
||||
return VD->getType();
|
||||
}
|
||||
|
||||
/// Compute the layout of the given block. Attempts to lay the block
|
||||
|
@ -553,7 +549,7 @@ static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF,
|
|||
for (const auto &CI : block->captures()) {
|
||||
const VarDecl *variable = CI.getVariable();
|
||||
|
||||
if (CI.isEscapingByref()) {
|
||||
if (CI.isByRef()) {
|
||||
// We have to copy/dispose of the __block reference.
|
||||
info.NeedsCopyDispose = true;
|
||||
|
||||
|
@ -1036,7 +1032,7 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) {
|
|||
// The lambda capture in a lambda's conversion-to-block-pointer is
|
||||
// special; we'll simply emit it directly.
|
||||
src = Address::invalid();
|
||||
} else if (CI.isEscapingByref()) {
|
||||
} else if (CI.isByRef()) {
|
||||
if (BlockInfo && CI.isNested()) {
|
||||
// We need to use the capture from the enclosing block.
|
||||
const CGBlockInfo::Capture &enclosingCapture =
|
||||
|
@ -1064,7 +1060,7 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) {
|
|||
// the block field. There's no need to chase the forwarding
|
||||
// pointer at this point, since we're building something that will
|
||||
// live a shorter life than the stack byref anyway.
|
||||
if (CI.isEscapingByref()) {
|
||||
if (CI.isByRef()) {
|
||||
// Get a void* that points to the byref struct.
|
||||
llvm::Value *byrefPointer;
|
||||
if (CI.isNested())
|
||||
|
@ -1283,7 +1279,8 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr *E,
|
|||
return EmitCall(FnInfo, Callee, ReturnValue, Args);
|
||||
}
|
||||
|
||||
Address CodeGenFunction::GetAddrOfBlockDecl(const VarDecl *variable) {
|
||||
Address CodeGenFunction::GetAddrOfBlockDecl(const VarDecl *variable,
|
||||
bool isByRef) {
|
||||
assert(BlockInfo && "evaluating block ref without block information?");
|
||||
const CGBlockInfo::Capture &capture = BlockInfo->getCapture(variable);
|
||||
|
||||
|
@ -1294,7 +1291,7 @@ Address CodeGenFunction::GetAddrOfBlockDecl(const VarDecl *variable) {
|
|||
Builder.CreateStructGEP(LoadBlockStruct(), capture.getIndex(),
|
||||
capture.getOffset(), "block.capture.addr");
|
||||
|
||||
if (variable->isEscapingByref()) {
|
||||
if (isByRef) {
|
||||
// addr should be a void** right now. Load, then cast the result
|
||||
// to byref*.
|
||||
|
||||
|
@ -1308,10 +1305,6 @@ Address CodeGenFunction::GetAddrOfBlockDecl(const VarDecl *variable) {
|
|||
variable->getName());
|
||||
}
|
||||
|
||||
assert((!variable->isNonEscapingByref() ||
|
||||
capture.fieldType()->isReferenceType()) &&
|
||||
"the capture field of a non-escaping variable should have a "
|
||||
"reference type");
|
||||
if (capture.fieldType()->isReferenceType())
|
||||
addr = EmitLoadOfReference(MakeAddrLValue(addr, capture.fieldType()));
|
||||
|
||||
|
@ -1663,7 +1656,7 @@ computeCopyInfoForBlockCapture(const BlockDecl::Capture &CI, QualType T,
|
|||
return std::make_pair(BlockCaptureEntityKind::CXXRecord, BlockFieldFlags());
|
||||
}
|
||||
BlockFieldFlags Flags;
|
||||
if (CI.isEscapingByref()) {
|
||||
if (CI.isByRef()) {
|
||||
Flags = BLOCK_FIELD_IS_BYREF;
|
||||
if (T.isObjCGCWeak())
|
||||
Flags |= BLOCK_FIELD_IS_WEAK;
|
||||
|
@ -2109,7 +2102,7 @@ getBlockFieldFlagsForObjCObjectPointer(const BlockDecl::Capture &CI,
|
|||
static std::pair<BlockCaptureEntityKind, BlockFieldFlags>
|
||||
computeDestroyInfoForBlockCapture(const BlockDecl::Capture &CI, QualType T,
|
||||
const LangOptions &LangOpts) {
|
||||
if (CI.isEscapingByref()) {
|
||||
if (CI.isByRef()) {
|
||||
BlockFieldFlags Flags = BLOCK_FIELD_IS_BYREF;
|
||||
if (T.isObjCGCWeak())
|
||||
Flags |= BLOCK_FIELD_IS_WEAK;
|
||||
|
@ -2571,9 +2564,6 @@ BlockByrefHelpers *
|
|||
CodeGenFunction::buildByrefHelpers(llvm::StructType &byrefType,
|
||||
const AutoVarEmission &emission) {
|
||||
const VarDecl &var = *emission.Variable;
|
||||
assert(var.isEscapingByref() &&
|
||||
"only escaping __block variables need byref helpers");
|
||||
|
||||
QualType type = var.getType();
|
||||
|
||||
auto &byrefInfo = getBlockByrefInfo(&var);
|
||||
|
|
|
@ -2839,7 +2839,7 @@ void CodeGenFunction::EmitLambdaBlockInvokeBody() {
|
|||
CallArgList CallArgs;
|
||||
|
||||
QualType ThisType = getContext().getPointerType(getContext().getRecordType(Lambda));
|
||||
Address ThisPtr = GetAddrOfBlockDecl(variable);
|
||||
Address ThisPtr = GetAddrOfBlockDecl(variable, false);
|
||||
CallArgs.add(RValue::get(ThisPtr.getPointer()), ThisType);
|
||||
|
||||
// Add the rest of the parameters.
|
||||
|
|
|
@ -1125,8 +1125,8 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
|
|||
|
||||
AutoVarEmission emission(D);
|
||||
|
||||
bool isEscapingByRef = D.isEscapingByref();
|
||||
emission.IsEscapingByRef = isEscapingByRef;
|
||||
bool isByRef = D.hasAttr<BlocksAttr>();
|
||||
emission.IsByRef = isByRef;
|
||||
|
||||
CharUnits alignment = getContext().getDeclAlign(&D);
|
||||
|
||||
|
@ -1165,8 +1165,8 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
|
|||
// in OpenCL.
|
||||
if ((!getLangOpts().OpenCL ||
|
||||
Ty.getAddressSpace() == LangAS::opencl_constant) &&
|
||||
(CGM.getCodeGenOpts().MergeAllConstants && !NRVO &&
|
||||
!isEscapingByRef && CGM.isTypeConstant(Ty, true))) {
|
||||
(CGM.getCodeGenOpts().MergeAllConstants && !NRVO && !isByRef &&
|
||||
CGM.isTypeConstant(Ty, true))) {
|
||||
EmitStaticVarDecl(D, llvm::GlobalValue::InternalLinkage);
|
||||
|
||||
// Signal this condition to later callbacks.
|
||||
|
@ -1218,7 +1218,7 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
|
|||
} else {
|
||||
CharUnits allocaAlignment;
|
||||
llvm::Type *allocaTy;
|
||||
if (isEscapingByRef) {
|
||||
if (isByRef) {
|
||||
auto &byrefInfo = getBlockByrefInfo(&D);
|
||||
allocaTy = byrefInfo.Type;
|
||||
allocaAlignment = byrefInfo.ByrefAlignment;
|
||||
|
@ -1418,7 +1418,7 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) {
|
|||
}
|
||||
|
||||
// Initialize the structure of a __block variable.
|
||||
if (emission.IsEscapingByRef)
|
||||
if (emission.IsByRef)
|
||||
emitByrefStructureInit(emission);
|
||||
|
||||
// Initialize the variable here if it doesn't have a initializer and it is a
|
||||
|
@ -1428,7 +1428,7 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) {
|
|||
type.isNonTrivialToPrimitiveDefaultInitialize() ==
|
||||
QualType::PDIK_Struct) {
|
||||
LValue Dst = MakeAddrLValue(emission.getAllocatedAddress(), type);
|
||||
if (emission.IsEscapingByRef)
|
||||
if (emission.IsByRef)
|
||||
drillIntoBlockVariable(*this, Dst, &D);
|
||||
defaultInitNonTrivialCStructVar(Dst);
|
||||
return;
|
||||
|
@ -1440,7 +1440,7 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) {
|
|||
// Check whether this is a byref variable that's potentially
|
||||
// captured and moved by its own initializer. If so, we'll need to
|
||||
// emit the initializer first, then copy into the variable.
|
||||
bool capturedByInit = emission.IsEscapingByRef && isCapturedBy(D, Init);
|
||||
bool capturedByInit = emission.IsByRef && isCapturedBy(D, Init);
|
||||
|
||||
Address Loc =
|
||||
capturedByInit ? emission.Addr : emission.getObjectAddress(*this);
|
||||
|
@ -1634,8 +1634,7 @@ void CodeGenFunction::EmitAutoVarCleanups(const AutoVarEmission &emission) {
|
|||
// If this is a block variable, call _Block_object_destroy
|
||||
// (on the unforwarded address). Don't enter this cleanup if we're in pure-GC
|
||||
// mode.
|
||||
if (emission.IsEscapingByRef &&
|
||||
CGM.getLangOpts().getGC() != LangOptions::GCOnly) {
|
||||
if (emission.IsByRef && CGM.getLangOpts().getGC() != LangOptions::GCOnly) {
|
||||
BlockFieldFlags Flags = BLOCK_FIELD_IS_BYREF;
|
||||
if (emission.Variable->getType().isObjCGCWeak())
|
||||
Flags |= BLOCK_FIELD_IS_WEAK;
|
||||
|
|
|
@ -2486,7 +2486,7 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
|
|||
}
|
||||
|
||||
assert(isa<BlockDecl>(CurCodeDecl));
|
||||
Address addr = GetAddrOfBlockDecl(VD);
|
||||
Address addr = GetAddrOfBlockDecl(VD, VD->hasAttr<BlocksAttr>());
|
||||
return MakeAddrLValue(addr, T, AlignmentSource::Decl);
|
||||
}
|
||||
}
|
||||
|
@ -2538,7 +2538,7 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
|
|||
}
|
||||
|
||||
// Drill into block byref variables.
|
||||
bool isBlockByref = VD->isEscapingByref();
|
||||
bool isBlockByref = VD->hasAttr<BlocksAttr>();
|
||||
if (isBlockByref) {
|
||||
addr = emitBlockByrefAddress(addr, VD);
|
||||
}
|
||||
|
|
|
@ -1787,7 +1787,7 @@ public:
|
|||
llvm::Value *ptr);
|
||||
|
||||
Address LoadBlockStruct();
|
||||
Address GetAddrOfBlockDecl(const VarDecl *var);
|
||||
Address GetAddrOfBlockDecl(const VarDecl *var, bool ByRef);
|
||||
|
||||
/// BuildBlockByrefAddress - Computes the location of the
|
||||
/// data in a variable which is declared as __block.
|
||||
|
@ -2683,9 +2683,8 @@ public:
|
|||
|
||||
llvm::Value *NRVOFlag;
|
||||
|
||||
/// True if the variable is a __block variable that is captured by an
|
||||
/// escaping block.
|
||||
bool IsEscapingByRef;
|
||||
/// True if the variable is a __block variable.
|
||||
bool IsByRef;
|
||||
|
||||
/// True if the variable is of aggregate type and has a constant
|
||||
/// initializer.
|
||||
|
@ -2705,7 +2704,7 @@ public:
|
|||
|
||||
AutoVarEmission(const VarDecl &variable)
|
||||
: Variable(&variable), Addr(Address::invalid()), NRVOFlag(nullptr),
|
||||
IsEscapingByRef(false), IsConstantAggregate(false),
|
||||
IsByRef(false), IsConstantAggregate(false),
|
||||
SizeForLifetimeMarkers(nullptr), AllocaAddr(Address::invalid()) {}
|
||||
|
||||
bool wasEmittedAsGlobal() const { return !Addr.isValid(); }
|
||||
|
@ -2735,7 +2734,7 @@ public:
|
|||
/// Note that this does not chase the forwarding pointer for
|
||||
/// __block decls.
|
||||
Address getObjectAddress(CodeGenFunction &CGF) const {
|
||||
if (!IsEscapingByRef) return Addr;
|
||||
if (!IsByRef) return Addr;
|
||||
|
||||
return CGF.emitBlockByrefAddress(Addr, Variable, /*forward*/ false);
|
||||
}
|
||||
|
|
|
@ -54,8 +54,6 @@ void FunctionScopeInfo::Clear() {
|
|||
PossiblyUnreachableDiags.clear();
|
||||
WeakObjectUses.clear();
|
||||
ModifiedNonNullParams.clear();
|
||||
Blocks.clear();
|
||||
ByrefBlockVars.clear();
|
||||
}
|
||||
|
||||
static const NamedDecl *getBestPropertyDecl(const ObjCPropertyRefExpr *PropE) {
|
||||
|
|
|
@ -1401,68 +1401,9 @@ void Sema::RecordParsingTemplateParameterDepth(unsigned Depth) {
|
|||
"Remove assertion if intentionally called in a non-lambda context.");
|
||||
}
|
||||
|
||||
// Check that the type of the VarDecl has an accessible copy constructor and
|
||||
// resolve its destructor's exception spefication.
|
||||
static void checkEscapingByref(VarDecl *VD, Sema &S) {
|
||||
QualType T = VD->getType();
|
||||
EnterExpressionEvaluationContext scope(
|
||||
S, Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
|
||||
SourceLocation Loc = VD->getLocation();
|
||||
Expr *VarRef = new (S.Context) DeclRefExpr(VD, false, T, VK_LValue, Loc);
|
||||
ExprResult Result = S.PerformMoveOrCopyInitialization(
|
||||
InitializedEntity::InitializeBlock(Loc, T, false), VD, VD->getType(),
|
||||
VarRef, /*AllowNRVO=*/true);
|
||||
if (!Result.isInvalid()) {
|
||||
Result = S.MaybeCreateExprWithCleanups(Result);
|
||||
Expr *Init = Result.getAs<Expr>();
|
||||
S.Context.setBlockVarCopyInit(VD, Init, S.canThrow(Init));
|
||||
}
|
||||
|
||||
// The destructor's exception spefication is needed when IRGen generates
|
||||
// block copy/destroy functions. Resolve it here.
|
||||
if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl())
|
||||
if (CXXDestructorDecl *DD = RD->getDestructor()) {
|
||||
auto *FPT = DD->getType()->getAs<FunctionProtoType>();
|
||||
S.ResolveExceptionSpec(Loc, FPT);
|
||||
}
|
||||
}
|
||||
|
||||
static void markEscapingByrefs(const FunctionScopeInfo &FSI, Sema &S) {
|
||||
// Set the EscapingByref flag of __block variables captured by
|
||||
// escaping blocks.
|
||||
for (const BlockDecl *BD : FSI.Blocks) {
|
||||
if (BD->doesNotEscape())
|
||||
continue;
|
||||
for (const BlockDecl::Capture &BC : BD->captures()) {
|
||||
VarDecl *VD = BC.getVariable();
|
||||
if (VD->hasAttr<BlocksAttr>())
|
||||
VD->setEscapingByref();
|
||||
}
|
||||
}
|
||||
|
||||
for (VarDecl *VD : FSI.ByrefBlockVars) {
|
||||
// __block variables might require us to capture a copy-initializer.
|
||||
if (!VD->isEscapingByref())
|
||||
continue;
|
||||
// It's currently invalid to ever have a __block variable with an
|
||||
// array type; should we diagnose that here?
|
||||
// Regardless, we don't want to ignore array nesting when
|
||||
// constructing this copy.
|
||||
if (VD->getType()->isStructureOrClassType())
|
||||
checkEscapingByref(VD, S);
|
||||
}
|
||||
}
|
||||
|
||||
void Sema::PopFunctionScopeInfo(const AnalysisBasedWarnings::Policy *WP,
|
||||
const Decl *D, const BlockExpr *blkExpr) {
|
||||
assert(!FunctionScopes.empty() && "mismatched push/pop!");
|
||||
|
||||
// This function shouldn't be called after popping the current function scope.
|
||||
// markEscapingByrefs calls PerformMoveOrCopyInitialization, which can call
|
||||
// PushFunctionScope, which can cause clearing out PreallocatedFunctionScope
|
||||
// when FunctionScopes is empty.
|
||||
markEscapingByrefs(*FunctionScopes.back(), *this);
|
||||
|
||||
FunctionScopeInfo *Scope = FunctionScopes.pop_back_val();
|
||||
|
||||
if (LangOpts.OpenMP)
|
||||
|
|
|
@ -11826,8 +11826,37 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
|
|||
QualType type = var->getType();
|
||||
if (type->isDependentType()) return;
|
||||
|
||||
if (var->hasAttr<BlocksAttr>())
|
||||
getCurFunction()->addByrefBlockVar(var);
|
||||
// __block variables might require us to capture a copy-initializer.
|
||||
if (var->hasAttr<BlocksAttr>()) {
|
||||
// It's currently invalid to ever have a __block variable with an
|
||||
// array type; should we diagnose that here?
|
||||
|
||||
// Regardless, we don't want to ignore array nesting when
|
||||
// constructing this copy.
|
||||
if (type->isStructureOrClassType()) {
|
||||
EnterExpressionEvaluationContext scope(
|
||||
*this, ExpressionEvaluationContext::PotentiallyEvaluated);
|
||||
SourceLocation poi = var->getLocation();
|
||||
Expr *varRef =new (Context) DeclRefExpr(var, false, type, VK_LValue, poi);
|
||||
ExprResult result
|
||||
= PerformMoveOrCopyInitialization(
|
||||
InitializedEntity::InitializeBlock(poi, type, false),
|
||||
var, var->getType(), varRef, /*AllowNRVO=*/true);
|
||||
if (!result.isInvalid()) {
|
||||
result = MaybeCreateExprWithCleanups(result);
|
||||
Expr *init = result.getAs<Expr>();
|
||||
Context.setBlockVarCopyInit(var, init, canThrow(init));
|
||||
}
|
||||
|
||||
// The destructor's exception spefication is needed when IRGen generates
|
||||
// block copy/destroy functions. Resolve it here.
|
||||
if (const CXXRecordDecl *RD = type->getAsCXXRecordDecl())
|
||||
if (CXXDestructorDecl *DD = RD->getDestructor()) {
|
||||
auto *FPT = DD->getType()->getAs<FunctionProtoType>();
|
||||
FPT = ResolveExceptionSpec(poi, FPT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Expr *Init = var->getInit();
|
||||
bool IsGlobal = GlobalStorage && !var->isStaticLocal();
|
||||
|
|
|
@ -13530,9 +13530,6 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
|
|||
}
|
||||
}
|
||||
|
||||
if (getCurFunction())
|
||||
getCurFunction()->addBlock(BSI->TheDecl);
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
|
|
|
@ -1365,7 +1365,6 @@ ASTDeclReader::RedeclarableResult ASTDeclReader::VisitVarDeclImpl(VarDecl *VD) {
|
|||
VD->NonParmVarDeclBits.IsInitCapture = Record.readInt();
|
||||
VD->NonParmVarDeclBits.PreviousDeclInSameBlockScope = Record.readInt();
|
||||
VD->NonParmVarDeclBits.ImplicitParamKind = Record.readInt();
|
||||
VD->NonParmVarDeclBits.EscapingByref = Record.readInt();
|
||||
}
|
||||
auto VarLinkage = Linkage(Record.readInt());
|
||||
VD->setCachedLinkage(VarLinkage);
|
||||
|
|
|
@ -938,7 +938,6 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) {
|
|||
Record.push_back(static_cast<unsigned>(IPD->getParameterKind()));
|
||||
else
|
||||
Record.push_back(0);
|
||||
Record.push_back(D->isEscapingByref());
|
||||
}
|
||||
Record.push_back(D->getLinkageInternal());
|
||||
|
||||
|
@ -1009,7 +1008,6 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) {
|
|||
!D->isInitCapture() &&
|
||||
!D->isPreviousDeclInSameBlockScope() &&
|
||||
!(D->hasAttr<BlocksAttr>() && D->getType()->getAsCXXRecordDecl()) &&
|
||||
!D->isEscapingByref() &&
|
||||
D->getStorageDuration() != SD_Static &&
|
||||
!D->getMemberSpecializationInfo())
|
||||
AbbrevToUse = Writer.getDeclVarAbbrev();
|
||||
|
@ -2074,7 +2072,6 @@ void ASTWriter::WriteDeclAbbrevs() {
|
|||
Abv->Add(BitCodeAbbrevOp(0)); // isInitCapture
|
||||
Abv->Add(BitCodeAbbrevOp(0)); // isPrevDeclInSameScope
|
||||
Abv->Add(BitCodeAbbrevOp(0)); // ImplicitParamKind
|
||||
Abv->Add(BitCodeAbbrevOp(0)); // EscapingByref
|
||||
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // Linkage
|
||||
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // IsInitICE (local)
|
||||
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // VarKind (local enum)
|
||||
|
|
|
@ -9,13 +9,11 @@ Agg makeAgg(void);
|
|||
// cause a block copy. rdar://9309454
|
||||
void test0() {
|
||||
__block Agg a = {100};
|
||||
^{ (void)a; };
|
||||
|
||||
a = makeAgg();
|
||||
}
|
||||
// CHECK-LABEL: define void @test0()
|
||||
// CHECK: [[A:%.*]] = alloca [[BYREF:%.*]], align 8
|
||||
// CHECK-NEXT: alloca <{ i8*, i32, i32, i8*, %{{.*}}*, i8* }>, align 8
|
||||
// CHECK-NEXT: [[TEMP:%.*]] = alloca [[AGG]], align 4
|
||||
// CHECK: [[RESULT:%.*]] = call i32 @makeAgg()
|
||||
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[AGG]], [[AGG]]* [[TEMP]], i32 0, i32 0
|
||||
|
@ -37,13 +35,11 @@ void test0() {
|
|||
// rdar://11757470
|
||||
void test1() {
|
||||
__block Agg a, b;
|
||||
^{ (void)a; (void)b; };
|
||||
a = b = makeAgg();
|
||||
}
|
||||
// CHECK-LABEL: define void @test1()
|
||||
// CHECK: [[A:%.*]] = alloca [[A_BYREF:%.*]], align 8
|
||||
// CHECK-NEXT: [[B:%.*]] = alloca [[B_BYREF:%.*]], align 8
|
||||
// CHECK-NEXT: alloca <{ i8*, i32, i32, i8*, %{{.*}}*, i8*, i8* }>, align 8
|
||||
// CHECK-NEXT: [[TEMP:%.*]] = alloca [[AGG]], align 4
|
||||
// CHECK: [[RESULT:%.*]] = call i32 @makeAgg()
|
||||
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[AGG]], [[AGG]]* [[TEMP]], i32 0, i32 0
|
||||
|
|
|
@ -11,7 +11,6 @@ int rhs();
|
|||
|
||||
void foo() {
|
||||
__block int i;
|
||||
^{ (void)i; };
|
||||
i = rhs();
|
||||
i += rhs();
|
||||
}
|
||||
|
|
|
@ -23,7 +23,6 @@ void test1() {
|
|||
void test2_helper();
|
||||
void test2() {
|
||||
__block int x = 10;
|
||||
^{ (void)x; };
|
||||
test2_helper(5, 6, 7);
|
||||
}
|
||||
void test2_helper(int x, int y) {
|
||||
|
|
|
@ -26,7 +26,6 @@ extern void i(void);
|
|||
|
||||
void f(void) {
|
||||
__block int i;
|
||||
^{ (void)i; };
|
||||
g(^ { });
|
||||
}
|
||||
|
||||
|
|
|
@ -4,12 +4,10 @@
|
|||
// CHECK: [[baz:%[0-9a-z_]*]] = alloca %struct.__block_byref_baz
|
||||
// CHECK: [[bazref:%[0-9a-z_\.]*]] = getelementptr inbounds %struct.__block_byref_baz, %struct.__block_byref_baz* [[baz]], i32 0, i32 1
|
||||
// CHECK: store %struct.__block_byref_baz* [[baz]], %struct.__block_byref_baz** [[bazref]]
|
||||
// CHECK: bitcast %struct.__block_byref_baz* [[baz]] to i8*
|
||||
// CHECK: [[disposable:%[0-9a-z_]*]] = bitcast %struct.__block_byref_baz* [[baz]] to i8*
|
||||
// CHECK: call void @_Block_object_dispose(i8* [[disposable]]
|
||||
|
||||
int main() {
|
||||
__block int baz = [&]() { return 0; }();
|
||||
^{ (void)baz; };
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -76,7 +76,6 @@ namespace test2 {
|
|||
void test() {
|
||||
__block A a;
|
||||
__block B b;
|
||||
^{ (void)a; (void)b; };
|
||||
}
|
||||
|
||||
// CHECK-LABEL: define internal void @__Block_byref_object_copy
|
||||
|
|
|
@ -9,7 +9,6 @@ struct A {
|
|||
|
||||
void test() {
|
||||
__block A a;
|
||||
^{ (void)a; };
|
||||
}
|
||||
|
||||
// CHECK: !DISubprogram(name: "__Block_byref_object_copy_",
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -emit-llvm -fblocks -o - %s | FileCheck %s
|
||||
// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -emit-llvm -o - %s | FileCheck %s
|
||||
|
||||
struct S {
|
||||
int a[4];
|
||||
|
@ -65,32 +65,3 @@ typedef void (*NoEscapeFunc)(__attribute__((noescape)) int *);
|
|||
void test3(NoEscapeFunc f, int *p) {
|
||||
f(p);
|
||||
}
|
||||
|
||||
namespace TestByref {
|
||||
|
||||
struct S {
|
||||
S();
|
||||
~S();
|
||||
S(const S &);
|
||||
int a;
|
||||
};
|
||||
|
||||
typedef void (^BlockTy)(void);
|
||||
S &getS();
|
||||
void noescapefunc(__attribute__((noescape)) BlockTy);
|
||||
|
||||
// Check that __block variables with reference types are handled correctly.
|
||||
|
||||
// CHECK: define void @_ZN9TestByref4testEv(
|
||||
// CHECK: %[[X:.*]] = alloca %[[STRUCT_TESTBYREF:.*]]*, align 8
|
||||
// CHECK: %[[BLOCK:.*]] = alloca <{ i8*, i32, i32, i8*, %{{.*}}*, %[[STRUCT_TESTBYREF]]* }>, align 8
|
||||
// CHECK: %[[BLOCK_CAPTURED:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %{{.*}}*, %[[STRUCT_TESTBYREF]]* }>, <{ i8*, i32, i32, i8*, %{{.*}}*, %[[STRUCT_TESTBYREF]]* }>* %[[BLOCK]], i32 0, i32 5
|
||||
// CHECK: %[[V0:.*]] = load %[[STRUCT_TESTBYREF]]*, %[[STRUCT_TESTBYREF]]** %[[X]], align 8
|
||||
// CHECK: store %[[STRUCT_TESTBYREF]]* %[[V0]], %[[STRUCT_TESTBYREF]]** %[[BLOCK_CAPTURED]], align 8
|
||||
|
||||
void test() {
|
||||
__block S &x = getS();
|
||||
noescapefunc(^{ (void)x; });
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -42,7 +42,6 @@ void NSLog(id, ...);
|
|||
void test2(void) {
|
||||
@autoreleasepool {
|
||||
__attribute__((__blocks__(byref))) int x;
|
||||
^{ (void)x; };
|
||||
NSLog(@"Address of x outside of block: %p", &x);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
|
||||
void test19() {
|
||||
__block id x;
|
||||
^{ (void)x; };
|
||||
// CHECK-UNOPT-LABEL: define internal void @__Block_byref_object_copy
|
||||
// CHECK-UNOPT: [[X:%.*]] = getelementptr inbounds [[BYREF_T:%.*]], [[BYREF_T:%.*]]* [[VAR:%.*]], i32 0, i32 6
|
||||
// CHECK-UNOPT: [[X2:%.*]] = getelementptr inbounds [[BYREF_T:%.*]], [[BYREF_T:%.*]]* [[VAR1:%.*]], i32 0, i32 6
|
||||
|
|
|
@ -1,31 +1,23 @@
|
|||
// RUN: %clang_cc1 %s -emit-llvm -o - -fobjc-gc -fblocks -triple i386-apple-darwin10 -fobjc-runtime=macosx-fragile-10.5 | FileCheck %s --check-prefix=CHECK --check-prefix=OBJC
|
||||
// RUN: %clang_cc1 -x objective-c++ %s -emit-llvm -o - -fobjc-gc -fblocks -triple i386-apple-darwin10 -fobjc-runtime=macosx-fragile-10.5 | FileCheck %s --check-prefix=CHECK --check-prefix=OBJCXX
|
||||
|
||||
// OBJC-LABEL: define void @test1(
|
||||
// OBJCXX-LABEL: define void @_Z5test1P12NSDictionary(
|
||||
|
||||
// CHECK-LABEL: define linkonce_odr hidden void @__copy_helper_block_
|
||||
// CHECK: call void @_Block_object_assign(
|
||||
|
||||
// CHECK-LABEL: define linkonce_odr hidden void @__destroy_helper_block_
|
||||
// CHECK: call void @_Block_object_dispose(
|
||||
|
||||
// OBJC-LABEL: define void @foo(
|
||||
// OBJCXX-LABEL: define void @_Z3foov(
|
||||
// CHECK: call i8* @objc_read_weak(
|
||||
// CHECK: call i8* @objc_assign_weak(
|
||||
// CHECK: call void @_Block_object_dispose(
|
||||
|
||||
// OBJC-LABEL: define void @test2(
|
||||
// OBJCXX-LABEL: define void @_Z5test2v(
|
||||
// CHECK: call i8* @objc_assign_weak(
|
||||
// CHECK: call void @_Block_object_dispose(
|
||||
|
||||
// CHECK-LABEL: define linkonce_odr hidden void @__copy_helper_block_
|
||||
// CHECK: call void @_Block_object_assign(
|
||||
|
||||
// CHECK-LABEL: define linkonce_odr hidden void @__destroy_helper_block_
|
||||
// CHECK: call void @_Block_object_dispose(
|
||||
// RUN: %clang_cc1 %s -emit-llvm -o %t -fobjc-gc -fblocks -triple i386-apple-darwin10 -fobjc-runtime=macosx-fragile-10.5
|
||||
// RUN: grep "_Block_object_dispose" %t | count 6
|
||||
// RUN: grep "__copy_helper_block_" %t | count 4
|
||||
// RUN: grep "__destroy_helper_block_" %t | count 4
|
||||
// RUN: grep "__Block_byref_object_copy_" %t | count 2
|
||||
// RUN: grep "__Block_byref_object_dispose_" %t | count 2
|
||||
// RUN: not grep "i32 135)" %t
|
||||
// RUN: grep "_Block_object_assign" %t | count 4
|
||||
// RUN: grep "objc_read_weak" %t | count 2
|
||||
// RUN: grep "objc_assign_weak" %t | count 3
|
||||
// RUN: %clang_cc1 -x objective-c++ %s -emit-llvm -o %t -fobjc-gc -fblocks -triple i386-apple-darwin10 -fobjc-runtime=macosx-fragile-10.5
|
||||
// RUN: grep "_Block_object_dispose" %t | count 6
|
||||
// RUN: grep "__copy_helper_block_" %t | count 4
|
||||
// RUN: grep "__destroy_helper_block_" %t | count 4
|
||||
// RUN: grep "__Block_byref_object_copy_" %t | count 2
|
||||
// RUN: grep "__Block_byref_object_dispose_" %t | count 2
|
||||
// RUN: not grep "i32 135)" %t
|
||||
// RUN: grep "_Block_object_assign" %t | count 4
|
||||
// RUN: grep "objc_read_weak" %t | count 2
|
||||
// RUN: grep "objc_assign_weak" %t | count 3
|
||||
|
||||
@interface NSDictionary @end
|
||||
|
||||
|
@ -38,7 +30,6 @@ void test1(NSDictionary * dict) {
|
|||
|
||||
void foo() {
|
||||
__block __weak D *weakSelf;
|
||||
^{ (void)weakSelf; };
|
||||
D *l;
|
||||
l = weakSelf;
|
||||
weakSelf = l;
|
||||
|
|
|
@ -8,7 +8,6 @@ union U {
|
|||
long long *ll;
|
||||
} __attribute__((transparent_union));
|
||||
|
||||
void escapingFunc0(BlockTy);
|
||||
void noescapeFunc0(id, __attribute__((noescape)) BlockTy);
|
||||
void noescapeFunc1(__attribute__((noescape)) int *);
|
||||
void noescapeFunc2(__attribute__((noescape)) id);
|
||||
|
@ -22,9 +21,6 @@ void noescapeFunc3(__attribute__((noescape)) union U);
|
|||
// When the block is non-escaping, copy/dispose helpers aren't generated, so the
|
||||
// block layout string must include information about __strong captures.
|
||||
|
||||
// CHECK-NOARC: %[[STRUCT_BLOCK_BYREF_B0:.*]] = type { i8*, %[[STRUCT_BLOCK_BYREF_B0]]*, i32, i32, i8*, %[[STRUCT_S0:.*]] }
|
||||
// CHECK-ARC: %[[STRUCT_BLOCK_BYREF_B0:.*]] = type { i8*, %[[STRUCT_BLOCK_BYREF_B0]]*, i32, i32, i8*, i8*, i8*, %[[STRUCT_S0:.*]] }
|
||||
// CHECK: %[[STRUCT_S0]] = type { i8*, i8* }
|
||||
// CHECK: @[[BLOCK_DESCIPTOR_TMP_2:.*ls32l8"]] = linkonce_odr hidden unnamed_addr constant { i64, i64, i8*, i64 } { i64 0, i64 40, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @{{.*}}, i32 0, i32 0), i64 256 }, align 8
|
||||
|
||||
// CHECK-LABEL: define void @test0(
|
||||
|
@ -106,7 +102,7 @@ void test5(BlockTy2 b, int *p) {
|
|||
// CHECK-NOARC: %[[V1:.*]] = load i8*, i8** %[[B_ADDR]], align 8
|
||||
// CHECK-NOARC: store i8* %[[V1]], i8** %[[BLOCK_CAPTURED]], align 8
|
||||
// CHECK-ARC: %[[V2:.*]] = load i8*, i8** %[[B_ADDR]], align 8
|
||||
// CHECK-ARC: %[[V3:.*]] = call i8* @objc_retain(i8* %[[V2]])
|
||||
// CHECK-ARC: %[[V3:.*]] = call i8* @objc_retain(i8* %[[V2]]) #3
|
||||
// CHECK-ARC: store i8* %[[V3]], i8** %[[BLOCK_CAPTURED]], align 8
|
||||
// CHECK: call void @noescapeFunc0(
|
||||
// CHECK-ARC: call void @objc_storeStrong(i8** %[[V0]], i8* null)
|
||||
|
@ -122,49 +118,3 @@ void func(id);
|
|||
void test6(id a, id b) {
|
||||
noescapeFunc0(a, ^{ func(b); });
|
||||
}
|
||||
|
||||
// We don't need either the byref helper functions or the byref structs for
|
||||
// __block variables that are not captured by escaping blocks.
|
||||
|
||||
// CHECK: define void @test7(
|
||||
// CHECK: alloca i8*, align 8
|
||||
// CHECK: %[[B0:.*]] = alloca i8*, align 8
|
||||
// CHECK: %[[BLOCK:.*]] = alloca <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8** }>, align 8
|
||||
// CHECK: %[[BLOCK_CAPTURED:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8** }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8** }>* %[[BLOCK]], i32 0, i32 5
|
||||
// CHECK: store i8** %[[B0]], i8*** %[[BLOCK_CAPTURED]], align 8
|
||||
|
||||
// CHECK-ARC-NOT: define internal void @__Block_byref_object_copy_
|
||||
// CHECK-ARC-NOT: define internal void @__Block_byref_object_dispose_
|
||||
|
||||
void test7() {
|
||||
id a;
|
||||
__block id b0;
|
||||
noescapeFunc0(a, ^{ (void)b0; });
|
||||
}
|
||||
|
||||
// __block variables captured by escaping blocks need byref helper functions.
|
||||
|
||||
// CHECK: define void @test8(
|
||||
// CHECK: %[[A:.*]] = alloca i8*, align 8
|
||||
// CHECK: %[[B0:.*]] = alloca %[[STRUCT_BLOCK_BYREF_B0]], align 8
|
||||
// CHECK: alloca <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, align 8
|
||||
// CHECK: %[[BLOCK1:.*]] = alloca <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, align 8
|
||||
// CHECK: %[[BLOCK_CAPTURED7:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>* %[[BLOCK1]], i32 0, i32 5
|
||||
// CHECK: %[[V3:.*]] = bitcast %[[STRUCT_BLOCK_BYREF_B0]]* %[[B0]] to i8*
|
||||
// CHECK: store i8* %[[V3]], i8** %[[BLOCK_CAPTURED7]], align 8
|
||||
|
||||
// CHECK-ARC: define internal void @__Block_byref_object_copy_
|
||||
// CHECK-ARC: define internal void @__Block_byref_object_dispose_
|
||||
// CHECK: define linkonce_odr hidden void @__copy_helper_block_
|
||||
// CHECK: define linkonce_odr hidden void @__destroy_helper_block_
|
||||
|
||||
struct S0 {
|
||||
id a, b;
|
||||
};
|
||||
|
||||
void test8() {
|
||||
id a;
|
||||
__block struct S0 b0;
|
||||
noescapeFunc0(a, ^{ (void)b0; });
|
||||
escapingFunc0(^{ (void)b0; });
|
||||
}
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
// RUN: %clang_cc1 -std=gnu++98 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-runtime-has-weak -fblocks -fobjc-arc -o - %s | FileCheck -check-prefix CHECK-NOEXCP %s
|
||||
|
||||
// CHECK: [[A:.*]] = type { i64, [10 x i8*] }
|
||||
// CHECK: %[[STRUCT_BLOCK_DESCRIPTOR:.*]] = type { i64, i64 }
|
||||
// CHECK: %[[STRUCT_TEST1_S0:.*]] = type { i32 }
|
||||
// CHECK: %[[STRUCT_TRIVIAL_INTERNAL:.*]] = type { i32 }
|
||||
// CHECK: %[[STRUCT_BLOCK_DESCRIPTOR:.*]] = type { i64, i64 }
|
||||
|
||||
// CHECK: [[LAYOUT0:@.*]] = private unnamed_addr constant [3 x i8] c" 9\00"
|
||||
|
||||
|
@ -20,7 +20,6 @@ namespace test0 {
|
|||
|
||||
void foo() {
|
||||
__block A v;
|
||||
^{ (void)v; };
|
||||
}
|
||||
// CHECK-LABEL: define void @_ZN5test03fooEv()
|
||||
// CHECK: [[V:%.*]] = alloca [[BYREF_A:%.*]], align 8
|
||||
|
@ -33,8 +32,7 @@ namespace test0 {
|
|||
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[BYREF_A]], [[BYREF_A]]* [[V]], i32 0, i32 7
|
||||
// CHECK-NEXT: call void @_ZN5test01AC1Ev([[A]]* [[T0]])
|
||||
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[BYREF_A]], [[BYREF_A]]* [[V]], i32 0, i32 7
|
||||
// CHECK: bitcast [[BYREF_A]]* [[V]] to i8*
|
||||
// CHECK: [[T1:%.*]] = bitcast [[BYREF_A]]* [[V]] to i8*
|
||||
// CHECK-NEXT: [[T1:%.*]] = bitcast [[BYREF_A]]* [[V]] to i8*
|
||||
// CHECK-NEXT: call void @_Block_object_dispose(i8* [[T1]], i32 8)
|
||||
// CHECK-NEXT: call void @_ZN5test01AD1Ev([[A]]* [[T0]])
|
||||
// CHECK-NEXT: ret void
|
||||
|
@ -55,11 +53,6 @@ namespace test0 {
|
|||
// CHECK-NEXT: ret void
|
||||
}
|
||||
|
||||
// CHECK-LABEL: define linkonce_odr hidden void @__copy_helper_block_
|
||||
// CHECK-LABEL: define linkonce_odr hidden void @__destroy_helper_block_
|
||||
// CHECK-LABEL-O1: define linkonce_odr hidden void @__copy_helper_block_
|
||||
// CHECK-LABEL-O1: define linkonce_odr hidden void @__destroy_helper_block_
|
||||
|
||||
namespace test1 {
|
||||
|
||||
// Check that copy/dispose helper functions are exception safe.
|
||||
|
|
|
@ -1,26 +1,6 @@
|
|||
// RUN: %clang_cc1 -x c++-header -triple x86_64-apple-darwin11 -emit-pch -fblocks -fexceptions -o %t %S/block-helpers.h
|
||||
// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -include-pch %t -emit-llvm -fblocks -fexceptions -o - %s | FileCheck %s
|
||||
|
||||
// CHECK: %[[STRUCT_BLOCK_BYREF_X:.*]] = type { i8*, %[[STRUCT_BLOCK_BYREF_X]]*, i32, i32, i8*, i8*, %[[STRUCT_S0:.*]] }
|
||||
// CHECK: %[[STRUCT_S0]] = type { i32 }
|
||||
// CHECK: %[[STRUCT_BLOCK_BYREF_Y:.*]] = type { i8*, %[[STRUCT_BLOCK_BYREF_Y]]*, i32, i32, i8*, i8*, %[[STRUCT_S0]] }
|
||||
// CHECK: %[[STRUCT_BLOCK_DESCRIPTOR:.*]] = type { i64, i64 }
|
||||
|
||||
// Check that byref structs are allocated for x and y.
|
||||
|
||||
// CHECK-LABEL: define linkonce_odr void @_ZN1S1mEv(
|
||||
// CHECK: %[[X:.*]] = alloca %[[STRUCT_BLOCK_BYREF_X]], align 8
|
||||
// CHECK: %[[Y:.*]] = alloca %[[STRUCT_BLOCK_BYREF_Y]], align 8
|
||||
// CHECK: %[[BLOCK:.*]] = alloca <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8* }>, align 8
|
||||
// CHECK: %[[BLOCK_CAPTURED:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8* }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8* }>* %[[BLOCK]], i32 0, i32 5
|
||||
// CHECK: %[[V0:.*]] = bitcast %[[STRUCT_BLOCK_BYREF_X]]* %[[X]] to i8*
|
||||
// CHECK: store i8* %[[V0]], i8** %[[BLOCK_CAPTURED]], align 8
|
||||
// CHECK: %[[BLOCK_CAPTURED10:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8* }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8* }>* %[[BLOCK]], i32 0, i32 6
|
||||
// CHECK: %[[V1:.*]] = bitcast %[[STRUCT_BLOCK_BYREF_Y]]* %[[Y]] to i8*
|
||||
// CHECK: store i8* %[[V1]], i8** %[[BLOCK_CAPTURED10]], align 8
|
||||
|
||||
// CHECK-LABEL: define internal void @___ZN1S1mEv_block_invoke(
|
||||
|
||||
// The second call to block_object_assign should be an invoke.
|
||||
|
||||
// CHECK-LABEL: define linkonce_odr hidden void @__copy_helper_block_e8_32rc40rc(
|
||||
|
|
|
@ -76,27 +76,21 @@ namespace N1 {
|
|||
}
|
||||
|
||||
// Make sure we successfully instantiate the copy constructor of a
|
||||
// __block variable's type when the variable is captured by an escaping block.
|
||||
// __block variable's type.
|
||||
namespace N2 {
|
||||
template <int n> struct A {
|
||||
A() {}
|
||||
A(const A &other) {
|
||||
int invalid[-n]; // expected-error 2 {{array with a negative size}}
|
||||
}
|
||||
void m() {}
|
||||
};
|
||||
|
||||
typedef void (^BlockFnTy)();
|
||||
void func(BlockFnTy);
|
||||
|
||||
void test1() {
|
||||
__block A<1> x; // expected-note {{requested here}}
|
||||
func(^{ x.m(); });
|
||||
}
|
||||
|
||||
template <int n> void test2() {
|
||||
__block A<n> x; // expected-note {{requested here}}
|
||||
func(^{ x.m(); });
|
||||
}
|
||||
template void test2<2>();
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@ struct S {
|
|||
void m();
|
||||
};
|
||||
|
||||
void escapingFunc0(BlockTy);
|
||||
void noescapeFunc0(id, __attribute__((noescape)) BlockTy);
|
||||
void noescapeFunc1(id, [[clang::noescape]] BlockTy);
|
||||
void noescapeFunc2(__attribute__((noescape)) int *); // expected-note {{previous declaration is here}}
|
||||
|
@ -128,27 +127,3 @@ __attribute__((objc_root_class))
|
|||
-(void) m1:(int*) p {
|
||||
}
|
||||
@end
|
||||
|
||||
struct S6 {
|
||||
S6();
|
||||
S6(const S6 &) = delete; // expected-note 3 {{'S6' has been explicitly marked deleted here}}
|
||||
int f;
|
||||
};
|
||||
|
||||
void test1() {
|
||||
id a;
|
||||
// __block variables that are not captured by escaping blocks don't
|
||||
// necessitate having accessible copy constructors.
|
||||
__block S6 b0;
|
||||
__block S6 b1; // expected-error {{call to deleted constructor of 'S6'}}
|
||||
__block S6 b2; // expected-error {{call to deleted constructor of 'S6'}}
|
||||
__block S6 b3; // expected-error {{call to deleted constructor of 'S6'}}
|
||||
|
||||
noescapeFunc0(a, ^{ (void)b0; });
|
||||
escapingFunc0(^{ (void)b1; });
|
||||
{
|
||||
noescapeFunc0(a, ^{ (void)b0; (void)b1; });
|
||||
}
|
||||
noescapeFunc0(a, ^{ escapingFunc0(^{ (void)b2; }); });
|
||||
escapingFunc0(^{ noescapeFunc0(a, ^{ (void)b3; }); });
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue