зеркало из https://github.com/microsoft/clang-1.git
Refactor the application of type attributes so that attributes from
the declaration-specifiers and on the declarator itself are moved to the appropriate declarator chunk. This permits a greatly simplified model for how to apply these attributes, as well as allowing a much more efficient query for the GC attribute. Now all qualifier queries follow the same basic strategy of "local qualifiers, local qualifiers on the canonical type, then look through arrays". This can be easily optimized by changing the canonical qualified-array-type representation. Do not process type attributes as decl attributes on declarations with declarators. When computing the type of a block, synthesize a prototype function declarator chunk if the decl-spec type was not a function. This simplifies the logic for building block signatures. Change the logic which inserts an objc_read_weak on a block literal to only fire if the block has a __weak __block variable, rather than if the return type of the block is __weak qualified, which is not actually a sensible thing to ask. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@122871 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
e6bf90aec0
Коммит
711c52bb20
|
@ -3728,11 +3728,6 @@ inline Qualifiers::GC QualType::getObjCGCAttr() const {
|
|||
|
||||
if (const ArrayType *AT = dyn_cast<ArrayType>(CT))
|
||||
return AT->getElementType().getObjCGCAttr();
|
||||
if (const ObjCObjectPointerType *PT = CT->getAs<ObjCObjectPointerType>())
|
||||
return PT->getPointeeType().getObjCGCAttr();
|
||||
// We most look at all pointer types, not just pointer to interface types.
|
||||
if (const PointerType *PT = CT->getAs<PointerType>())
|
||||
return PT->getPointeeType().getObjCGCAttr();
|
||||
return Qualifiers::GCNone;
|
||||
}
|
||||
|
||||
|
|
|
@ -133,7 +133,18 @@ public:
|
|||
/// \brief Initializes this by copying its information from another
|
||||
/// TypeLoc of the same type.
|
||||
void initializeFullCopy(TypeLoc Other) const {
|
||||
initializeFullCopyImpl(*this, Other);
|
||||
assert(getType() == Other.getType());
|
||||
size_t Size = getFullDataSize();
|
||||
memcpy(getOpaqueData(), Other.getOpaqueData(), Size);
|
||||
}
|
||||
|
||||
/// \brief Initializes this by copying its information from another
|
||||
/// TypeLoc of the same type. The given size must be the full data
|
||||
/// size.
|
||||
void initializeFullCopy(TypeLoc Other, unsigned Size) const {
|
||||
assert(getType() == Other.getType());
|
||||
assert(getFullDataSize() == Size);
|
||||
memcpy(getOpaqueData(), Other.getOpaqueData(), Size);
|
||||
}
|
||||
|
||||
friend bool operator==(const TypeLoc &LHS, const TypeLoc &RHS) {
|
||||
|
@ -148,7 +159,6 @@ public:
|
|||
|
||||
private:
|
||||
static void initializeImpl(TypeLoc TL, SourceLocation Loc);
|
||||
static void initializeFullCopyImpl(TypeLoc TL, TypeLoc Other);
|
||||
static TypeLoc getNextTypeLocImpl(TypeLoc TL);
|
||||
static TypeLoc IgnoreParensImpl(TypeLoc TL);
|
||||
static SourceRange getLocalSourceRangeImpl(TypeLoc TL);
|
||||
|
|
|
@ -46,7 +46,10 @@ private:
|
|||
unsigned NumArgs;
|
||||
AttributeList *Next;
|
||||
bool DeclspecAttribute, CXX0XAttribute;
|
||||
mutable bool Invalid; /// True if already diagnosed as invalid.
|
||||
|
||||
/// True if already diagnosed as invalid.
|
||||
mutable bool Invalid;
|
||||
|
||||
AttributeList(const AttributeList &); // DO NOT IMPLEMENT
|
||||
void operator=(const AttributeList &); // DO NOT IMPLEMENT
|
||||
void operator delete(void *); // DO NOT IMPLEMENT
|
||||
|
@ -302,6 +305,10 @@ public:
|
|||
void clear() { list = 0; }
|
||||
AttributeList *getList() const { return list; }
|
||||
|
||||
/// Returns a reference to the attribute list. Try not to introduce
|
||||
/// dependencies on this method, it may not be long-lived.
|
||||
AttributeList *&getListRef() { return list; }
|
||||
|
||||
private:
|
||||
AttributeList *list;
|
||||
};
|
||||
|
|
|
@ -1002,6 +1002,7 @@ struct DeclaratorChunk {
|
|||
};
|
||||
|
||||
union {
|
||||
TypeInfoCommon Common;
|
||||
PointerTypeInfo Ptr;
|
||||
ReferenceTypeInfo Ref;
|
||||
ArrayTypeInfo Arr;
|
||||
|
@ -1026,19 +1027,12 @@ struct DeclaratorChunk {
|
|||
/// getAttrs - If there are attributes applied to this declaratorchunk, return
|
||||
/// them.
|
||||
const AttributeList *getAttrs() const {
|
||||
switch (Kind) {
|
||||
case Pointer: return Ptr.AttrList;
|
||||
case Reference: return Ref.AttrList;
|
||||
case MemberPointer: return Mem.AttrList;
|
||||
case Array: return Arr.AttrList;
|
||||
case Function: return Fun.AttrList;
|
||||
case BlockPointer: return Cls.AttrList;
|
||||
case Paren: return 0;
|
||||
}
|
||||
llvm_unreachable("Unknown declarator kind!");
|
||||
return 0;
|
||||
return Common.AttrList;
|
||||
}
|
||||
|
||||
AttributeList *&getAttrListRef() {
|
||||
return Common.AttrList;
|
||||
}
|
||||
|
||||
/// getPointer - Return a DeclaratorChunk for a pointer.
|
||||
///
|
||||
|
@ -1133,6 +1127,7 @@ struct DeclaratorChunk {
|
|||
I.Kind = Paren;
|
||||
I.Loc = LParenLoc;
|
||||
I.EndLoc = RParenLoc;
|
||||
I.Common.AttrList = 0;
|
||||
return I;
|
||||
}
|
||||
|
||||
|
@ -1337,6 +1332,11 @@ public:
|
|||
SetRangeEnd(EndLoc);
|
||||
}
|
||||
|
||||
/// AddInnermostTypeInfo - Add a new innermost chunk to this declarator.
|
||||
void AddInnermostTypeInfo(const DeclaratorChunk &TI) {
|
||||
DeclTypeInfo.insert(DeclTypeInfo.begin(), TI);
|
||||
}
|
||||
|
||||
/// getNumTypeObjects() - Return the number of types applied to this
|
||||
/// declarator.
|
||||
unsigned getNumTypeObjects() const { return DeclTypeInfo.size(); }
|
||||
|
@ -1428,6 +1428,8 @@ public:
|
|||
const AttributeList *getAttributes() const { return AttrList; }
|
||||
AttributeList *getAttributes() { return AttrList; }
|
||||
|
||||
AttributeList *&getAttrListRef() { return AttrList; }
|
||||
|
||||
/// hasAttributes - do we contain any attributes?
|
||||
bool hasAttributes() const {
|
||||
if (getAttributes() || getDeclSpec().hasAttributes()) return true;
|
||||
|
|
|
@ -1370,6 +1370,10 @@ public:
|
|||
void ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD);
|
||||
void ProcessDeclAttributeList(Scope *S, Decl *D, const AttributeList *AL);
|
||||
|
||||
bool CheckRegparmAttr(const AttributeList &attr, unsigned &value);
|
||||
bool CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC);
|
||||
bool CheckNoReturnAttr(const AttributeList &attr);
|
||||
|
||||
void WarnUndefinedMethod(SourceLocation ImpLoc, ObjCMethodDecl *method,
|
||||
bool &IncompleteImpl, unsigned DiagID);
|
||||
void WarnConflictingTypedMethods(ObjCMethodDecl *ImpMethod,
|
||||
|
|
|
@ -94,13 +94,6 @@ void TypeLoc::initializeImpl(TypeLoc TL, SourceLocation Loc) {
|
|||
}
|
||||
}
|
||||
|
||||
/// \brief Initializes a type location by copying all its data from
|
||||
/// another type location of the same type.
|
||||
void TypeLoc::initializeFullCopyImpl(TypeLoc TL, TypeLoc Other) {
|
||||
assert(TL.getType() == Other.getType() && "Must copy from same type");
|
||||
memcpy(TL.getOpaqueData(), Other.getOpaqueData(), TL.getFullDataSize());
|
||||
}
|
||||
|
||||
SourceLocation TypeLoc::getBeginLoc() const {
|
||||
TypeLoc Cur = *this;
|
||||
while (true) {
|
||||
|
|
|
@ -198,6 +198,8 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
|
|||
llvm::Constant *C;
|
||||
llvm::Value *V;
|
||||
|
||||
bool hasWeakBlockVariable = false;
|
||||
|
||||
{
|
||||
llvm::Constant *BlockVarLayout;
|
||||
// C = BuildBlockStructInitlist();
|
||||
|
@ -268,6 +270,8 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
|
|||
const BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(E);
|
||||
QualType Ty = E->getType();
|
||||
if (BDRE && BDRE->isByRef()) {
|
||||
if (BDRE->getDecl()->getType().isObjCGCWeak())
|
||||
hasWeakBlockVariable = true;
|
||||
Types[i+BlockFields] =
|
||||
llvm::PointerType::get(BuildByRefType(BDRE->getDecl()), 0);
|
||||
} else if (BDRE && BDRE->getDecl()->getType()->isReferenceType()) {
|
||||
|
@ -404,18 +408,22 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
|
|||
|
||||
QualType BPT = BE->getType();
|
||||
V = Builder.CreateBitCast(V, ConvertType(BPT));
|
||||
// See if this is a __weak block variable and the must call objc_read_weak
|
||||
// on it.
|
||||
const FunctionType *ftype = BPT->getPointeeType()->getAs<FunctionType>();
|
||||
QualType RES = ftype->getResultType();
|
||||
if (RES.isObjCGCWeak()) {
|
||||
|
||||
// We must call objc_read_weak on the block literal itself if it closes
|
||||
// on any __weak __block variables. For some reason.
|
||||
if (hasWeakBlockVariable) {
|
||||
const llvm::Type *OrigTy = V->getType();
|
||||
|
||||
// Must cast argument to id*
|
||||
const llvm::Type *ObjectPtrTy =
|
||||
ConvertType(CGM.getContext().getObjCIdType());
|
||||
const llvm::Type *PtrObjectPtrTy =
|
||||
llvm::PointerType::getUnqual(ObjectPtrTy);
|
||||
V = Builder.CreateBitCast(V, PtrObjectPtrTy);
|
||||
V = CGM.getObjCRuntime().EmitObjCWeakRead(*this, V);
|
||||
V = CGM.getObjCRuntime().EmitObjCWeakRead(*this, V);
|
||||
|
||||
// Cast back to the original type.
|
||||
V = Builder.CreateBitCast(V, OrigTy);
|
||||
}
|
||||
return V;
|
||||
}
|
||||
|
|
|
@ -78,6 +78,13 @@ static bool isFunctionOrMethodOrBlock(const Decl *d) {
|
|||
return isa<BlockDecl>(d);
|
||||
}
|
||||
|
||||
/// Return true if the given decl has a declarator that should have
|
||||
/// been processed by Sema::GetTypeForDeclarator.
|
||||
static bool hasDeclarator(const Decl *d) {
|
||||
// In some sense, TypedefDecl really *ought* to be a DeclaratorDecl.
|
||||
return isa<DeclaratorDecl>(d) || isa<BlockDecl>(d) || isa<TypedefDecl>(d);
|
||||
}
|
||||
|
||||
/// hasFunctionProto - Return true if the given decl has a argument
|
||||
/// information. This decl should have already passed
|
||||
/// isFunctionOrMethod or isFunctionOrMethodOrBlock.
|
||||
|
@ -766,10 +773,28 @@ static void HandleCommonAttr(Decl *d, const AttributeList &Attr, Sema &S) {
|
|||
<< Attr.getName() << 12 /* variable */;
|
||||
}
|
||||
|
||||
static void HandleNoReturnAttr(Decl *d, const AttributeList &Attr, Sema &S) {
|
||||
/* Diagnostics (if any) was emitted by Sema::ProcessFnAttr(). */
|
||||
assert(Attr.isInvalid() == false);
|
||||
d->addAttr(::new (S.Context) NoReturnAttr(Attr.getLoc(), S.Context));
|
||||
static void HandleNoReturnAttr(Decl *d, const AttributeList &attr, Sema &S) {
|
||||
if (hasDeclarator(d)) return;
|
||||
|
||||
if (S.CheckNoReturnAttr(attr)) return;
|
||||
|
||||
if (!isa<ObjCMethodDecl>(d)) {
|
||||
S.Diag(attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
||||
<< attr.getName() << 0 /*function*/;
|
||||
return;
|
||||
}
|
||||
|
||||
d->addAttr(::new (S.Context) NoReturnAttr(attr.getLoc(), S.Context));
|
||||
}
|
||||
|
||||
bool Sema::CheckNoReturnAttr(const AttributeList &attr) {
|
||||
if (attr.getNumArgs() != 0) {
|
||||
Diag(attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
|
||||
attr.setInvalid();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void HandleAnalyzerNoReturnAttr(Decl *d, const AttributeList &Attr,
|
||||
|
@ -2251,26 +2276,36 @@ static void HandleGNUInlineAttr(Decl *d, const AttributeList &Attr, Sema &S) {
|
|||
d->addAttr(::new (S.Context) GNUInlineAttr(Attr.getLoc(), S.Context));
|
||||
}
|
||||
|
||||
static void HandleCallConvAttr(Decl *d, const AttributeList &Attr, Sema &S) {
|
||||
// Diagnostic is emitted elsewhere: here we store the (valid) Attr
|
||||
// in the Decl node for syntactic reasoning, e.g., pretty-printing.
|
||||
assert(Attr.isInvalid() == false);
|
||||
static void HandleCallConvAttr(Decl *d, const AttributeList &attr, Sema &S) {
|
||||
if (hasDeclarator(d)) return;
|
||||
|
||||
switch (Attr.getKind()) {
|
||||
// Diagnostic is emitted elsewhere: here we store the (valid) attr
|
||||
// in the Decl node for syntactic reasoning, e.g., pretty-printing.
|
||||
CallingConv CC;
|
||||
if (S.CheckCallingConvAttr(attr, CC))
|
||||
return;
|
||||
|
||||
if (!isa<ObjCMethodDecl>(d)) {
|
||||
S.Diag(attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
||||
<< attr.getName() << 0 /*function*/;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (attr.getKind()) {
|
||||
case AttributeList::AT_fastcall:
|
||||
d->addAttr(::new (S.Context) FastCallAttr(Attr.getLoc(), S.Context));
|
||||
d->addAttr(::new (S.Context) FastCallAttr(attr.getLoc(), S.Context));
|
||||
return;
|
||||
case AttributeList::AT_stdcall:
|
||||
d->addAttr(::new (S.Context) StdCallAttr(Attr.getLoc(), S.Context));
|
||||
d->addAttr(::new (S.Context) StdCallAttr(attr.getLoc(), S.Context));
|
||||
return;
|
||||
case AttributeList::AT_thiscall:
|
||||
d->addAttr(::new (S.Context) ThisCallAttr(Attr.getLoc(), S.Context));
|
||||
d->addAttr(::new (S.Context) ThisCallAttr(attr.getLoc(), S.Context));
|
||||
return;
|
||||
case AttributeList::AT_cdecl:
|
||||
d->addAttr(::new (S.Context) CDeclAttr(Attr.getLoc(), S.Context));
|
||||
d->addAttr(::new (S.Context) CDeclAttr(attr.getLoc(), S.Context));
|
||||
return;
|
||||
case AttributeList::AT_pascal:
|
||||
d->addAttr(::new (S.Context) PascalAttr(Attr.getLoc(), S.Context));
|
||||
d->addAttr(::new (S.Context) PascalAttr(attr.getLoc(), S.Context));
|
||||
return;
|
||||
default:
|
||||
llvm_unreachable("unexpected attribute kind");
|
||||
|
@ -2278,42 +2313,83 @@ static void HandleCallConvAttr(Decl *d, const AttributeList &Attr, Sema &S) {
|
|||
}
|
||||
}
|
||||
|
||||
static void HandleRegparmAttr(Decl *d, const AttributeList &Attr, Sema &S) {
|
||||
// check the attribute arguments.
|
||||
if (Attr.getNumArgs() != 1) {
|
||||
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
|
||||
bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC) {
|
||||
if (attr.isInvalid())
|
||||
return true;
|
||||
|
||||
if (attr.getNumArgs() != 0) {
|
||||
Diag(attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
|
||||
attr.setInvalid();
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO: diagnose uses of these conventions on the wrong target.
|
||||
switch (attr.getKind()) {
|
||||
case AttributeList::AT_cdecl: CC = CC_C; break;
|
||||
case AttributeList::AT_fastcall: CC = CC_X86FastCall; break;
|
||||
case AttributeList::AT_stdcall: CC = CC_X86StdCall; break;
|
||||
case AttributeList::AT_thiscall: CC = CC_X86ThisCall; break;
|
||||
case AttributeList::AT_pascal: CC = CC_X86Pascal; break;
|
||||
default: llvm_unreachable("unexpected attribute kind"); return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void HandleRegparmAttr(Decl *d, const AttributeList &attr, Sema &S) {
|
||||
if (hasDeclarator(d)) return;
|
||||
|
||||
unsigned numParams;
|
||||
if (S.CheckRegparmAttr(attr, numParams))
|
||||
return;
|
||||
|
||||
if (!isa<ObjCMethodDecl>(d)) {
|
||||
S.Diag(attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
||||
<< attr.getName() << 0 /*function*/;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isFunctionOrMethod(d)) {
|
||||
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
||||
<< Attr.getName() << 0 /*function*/;
|
||||
return;
|
||||
d->addAttr(::new (S.Context) RegparmAttr(attr.getLoc(), S.Context, numParams));
|
||||
}
|
||||
|
||||
/// Checks a regparm attribute, returning true if it is ill-formed and
|
||||
/// otherwise setting numParams to the appropriate value.
|
||||
bool Sema::CheckRegparmAttr(const AttributeList &attr, unsigned &numParams) {
|
||||
if (attr.isInvalid())
|
||||
return true;
|
||||
|
||||
if (attr.getNumArgs() != 1) {
|
||||
Diag(attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
|
||||
attr.setInvalid();
|
||||
return true;
|
||||
}
|
||||
|
||||
Expr *NumParamsExpr = Attr.getArg(0);
|
||||
Expr *NumParamsExpr = attr.getArg(0);
|
||||
llvm::APSInt NumParams(32);
|
||||
if (NumParamsExpr->isTypeDependent() || NumParamsExpr->isValueDependent() ||
|
||||
!NumParamsExpr->isIntegerConstantExpr(NumParams, S.Context)) {
|
||||
S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
|
||||
!NumParamsExpr->isIntegerConstantExpr(NumParams, Context)) {
|
||||
Diag(attr.getLoc(), diag::err_attribute_argument_not_int)
|
||||
<< "regparm" << NumParamsExpr->getSourceRange();
|
||||
return;
|
||||
attr.setInvalid();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (S.Context.Target.getRegParmMax() == 0) {
|
||||
S.Diag(Attr.getLoc(), diag::err_attribute_regparm_wrong_platform)
|
||||
if (Context.Target.getRegParmMax() == 0) {
|
||||
Diag(attr.getLoc(), diag::err_attribute_regparm_wrong_platform)
|
||||
<< NumParamsExpr->getSourceRange();
|
||||
return;
|
||||
attr.setInvalid();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (NumParams.getLimitedValue(255) > S.Context.Target.getRegParmMax()) {
|
||||
S.Diag(Attr.getLoc(), diag::err_attribute_regparm_invalid_number)
|
||||
<< S.Context.Target.getRegParmMax() << NumParamsExpr->getSourceRange();
|
||||
return;
|
||||
numParams = NumParams.getZExtValue();
|
||||
if (numParams > Context.Target.getRegParmMax()) {
|
||||
Diag(attr.getLoc(), diag::err_attribute_regparm_invalid_number)
|
||||
<< Context.Target.getRegParmMax() << NumParamsExpr->getSourceRange();
|
||||
attr.setInvalid();
|
||||
return true;
|
||||
}
|
||||
|
||||
d->addAttr(::new (S.Context) RegparmAttr(Attr.getLoc(), S.Context,
|
||||
NumParams.getZExtValue()));
|
||||
return false;
|
||||
}
|
||||
|
||||
static void HandleLaunchBoundsAttr(Decl *d, const AttributeList &Attr, Sema &S){
|
||||
|
|
|
@ -8297,32 +8297,51 @@ void Sema::ActOnBlockStart(SourceLocation CaretLoc, Scope *BlockScope) {
|
|||
|
||||
void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) {
|
||||
assert(ParamInfo.getIdentifier()==0 && "block-id should have no identifier!");
|
||||
assert(ParamInfo.getContext() == Declarator::BlockLiteralContext);
|
||||
BlockScopeInfo *CurBlock = getCurBlock();
|
||||
|
||||
TypeSourceInfo *Sig = GetTypeForDeclarator(ParamInfo, CurScope);
|
||||
CurBlock->TheDecl->setSignatureAsWritten(Sig);
|
||||
QualType T = Sig->getType();
|
||||
|
||||
bool isVariadic;
|
||||
QualType RetTy;
|
||||
if (const FunctionType *Fn = T->getAs<FunctionType>()) {
|
||||
CurBlock->FunctionType = T;
|
||||
RetTy = Fn->getResultType();
|
||||
isVariadic =
|
||||
!isa<FunctionProtoType>(Fn) || cast<FunctionProtoType>(Fn)->isVariadic();
|
||||
} else {
|
||||
RetTy = T;
|
||||
isVariadic = false;
|
||||
// GetTypeForDeclarator always produces a function type for a block
|
||||
// literal signature. Furthermore, it is always a FunctionProtoType
|
||||
// unless the function was written with a typedef.
|
||||
assert(T->isFunctionType() &&
|
||||
"GetTypeForDeclarator made a non-function block signature");
|
||||
|
||||
// Look for an explicit signature in that function type.
|
||||
FunctionProtoTypeLoc ExplicitSignature;
|
||||
|
||||
TypeLoc tmp = Sig->getTypeLoc().IgnoreParens();
|
||||
if (isa<FunctionProtoTypeLoc>(tmp)) {
|
||||
ExplicitSignature = cast<FunctionProtoTypeLoc>(tmp);
|
||||
|
||||
// Check whether that explicit signature was synthesized by
|
||||
// GetTypeForDeclarator. If so, don't save that as part of the
|
||||
// written signature.
|
||||
if (ExplicitSignature.getLParenLoc() ==
|
||||
ExplicitSignature.getRParenLoc()) {
|
||||
// This would be much cheaper if we stored TypeLocs instead of
|
||||
// TypeSourceInfos.
|
||||
TypeLoc Result = ExplicitSignature.getResultLoc();
|
||||
unsigned Size = Result.getFullDataSize();
|
||||
Sig = Context.CreateTypeSourceInfo(Result.getType(), Size);
|
||||
Sig->getTypeLoc().initializeFullCopy(Result, Size);
|
||||
|
||||
ExplicitSignature = FunctionProtoTypeLoc();
|
||||
}
|
||||
}
|
||||
|
||||
CurBlock->TheDecl->setSignatureAsWritten(Sig);
|
||||
CurBlock->FunctionType = T;
|
||||
|
||||
const FunctionType *Fn = T->getAs<FunctionType>();
|
||||
QualType RetTy = Fn->getResultType();
|
||||
bool isVariadic =
|
||||
(isa<FunctionProtoType>(Fn) && cast<FunctionProtoType>(Fn)->isVariadic());
|
||||
|
||||
CurBlock->TheDecl->setIsVariadic(isVariadic);
|
||||
|
||||
// Don't allow returning an array by value.
|
||||
if (RetTy->isArrayType()) {
|
||||
Diag(ParamInfo.getSourceRange().getBegin(), diag::err_block_returns_array);
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't allow returning a objc interface by value.
|
||||
if (RetTy->isObjCObjectType()) {
|
||||
Diag(ParamInfo.getSourceRange().getBegin(),
|
||||
|
@ -8339,11 +8358,9 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) {
|
|||
|
||||
// Push block parameters from the declarator if we had them.
|
||||
llvm::SmallVector<ParmVarDecl*, 8> Params;
|
||||
if (isa<FunctionProtoType>(T.IgnoreParens())) {
|
||||
FunctionProtoTypeLoc TL
|
||||
= cast<FunctionProtoTypeLoc>(Sig->getTypeLoc().IgnoreParens());
|
||||
for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I) {
|
||||
ParmVarDecl *Param = TL.getArg(I);
|
||||
if (ExplicitSignature) {
|
||||
for (unsigned I = 0, E = ExplicitSignature.getNumArgs(); I != E; ++I) {
|
||||
ParmVarDecl *Param = ExplicitSignature.getArg(I);
|
||||
if (Param->getIdentifier() == 0 &&
|
||||
!Param->isImplicit() &&
|
||||
!Param->isInvalidDecl() &&
|
||||
|
|
|
@ -1153,7 +1153,7 @@ Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
|
|||
}
|
||||
QualType FnRetType = CurBlock->ReturnType;
|
||||
|
||||
if (CurBlock->TheDecl->hasAttr<NoReturnAttr>()) {
|
||||
if (CurBlock->FunctionType->getAs<FunctionType>()->getNoReturnAttr()) {
|
||||
Diag(ReturnLoc, diag::err_noreturn_block_has_return_expr)
|
||||
<< getCurFunctionOrMethodDecl()->getDeclName();
|
||||
return StmtError();
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -6748,15 +6748,7 @@ TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) {
|
|||
else if (BExprResultType != SemaRef.Context.DependentTy)
|
||||
CurBlock->ReturnType = getDerived().TransformType(BExprResultType);
|
||||
}
|
||||
|
||||
// Transform the body
|
||||
StmtResult Body = getDerived().TransformStmt(E->getBody());
|
||||
if (Body.isInvalid())
|
||||
return ExprError();
|
||||
// Set the parameters on the block decl.
|
||||
if (!Params.empty())
|
||||
CurBlock->TheDecl->setParams(Params.data(), Params.size());
|
||||
|
||||
|
||||
QualType FunctionType = getDerived().RebuildFunctionProtoType(
|
||||
CurBlock->ReturnType,
|
||||
ParamTypes.data(),
|
||||
|
@ -6764,8 +6756,17 @@ TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) {
|
|||
BD->isVariadic(),
|
||||
0,
|
||||
BExprFunctionType->getExtInfo());
|
||||
|
||||
CurBlock->FunctionType = FunctionType;
|
||||
|
||||
// Set the parameters on the block decl.
|
||||
if (!Params.empty())
|
||||
CurBlock->TheDecl->setParams(Params.data(), Params.size());
|
||||
|
||||
// Transform the body
|
||||
StmtResult Body = getDerived().TransformStmt(E->getBody());
|
||||
if (Body.isInvalid())
|
||||
return ExprError();
|
||||
|
||||
return SemaRef.ActOnBlockStmtExpr(CaretLoc, Body.get(), /*Scope=*/0);
|
||||
}
|
||||
|
||||
|
|
|
@ -97,7 +97,7 @@ bptr foo5(int j) {
|
|||
}
|
||||
|
||||
int (*funcptr3[5])(long);
|
||||
int sz8 = sizeof(^int (*[5])(long) {return funcptr3;}); // expected-error {{block declared as returning an array}}
|
||||
int sz8 = sizeof(^int (*[5])(long) {return funcptr3;}); // expected-error {{function cannot return array type}} expected-warning {{incompatible pointer to integer conversion}}
|
||||
|
||||
void foo6() {
|
||||
int (^b)(int) __attribute__((noreturn));
|
||||
|
|
|
@ -5,6 +5,6 @@ int __attribute__((stdcall)) var1; // expected-warning{{'stdcall' only applies t
|
|||
int __attribute__((fastcall)) var2; // expected-warning{{'fastcall' only applies to function types; type here is 'int'}}
|
||||
|
||||
// Different CC qualifiers are not compatible
|
||||
void __attribute__((stdcall, fastcall)) foo3(void); // expected-error{{stdcall and fastcall attributes are not compatible}}
|
||||
void __attribute__((stdcall, fastcall)) foo3(void); // expected-error{{fastcall and stdcall attributes are not compatible}}
|
||||
void __attribute__((stdcall)) foo4(); // expected-note{{previous declaration is here}}
|
||||
void __attribute__((fastcall)) foo4(void); // expected-error{{function declared 'fastcall' here was previously declared 'stdcall'}}
|
||||
|
|
Загрузка…
Ссылка в новой задаче