зеркало из https://github.com/microsoft/clang-1.git
Add noreturn as a type attribute, handle printing for them and handle
calls to noreturn function pointers when CFG building. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@77089 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
742cd1b7bb
Коммит
2455636163
|
@ -135,7 +135,7 @@ class ASTContext {
|
|||
/// Since so few decls have attrs, we keep them in a hash map instead of
|
||||
/// wasting space in the Decl class.
|
||||
llvm::DenseMap<const Decl*, Attr*> DeclAttrs;
|
||||
|
||||
|
||||
/// \brief Keeps track of the static data member templates from which
|
||||
/// static data members of class template specializations were instantiated.
|
||||
///
|
||||
|
@ -218,7 +218,7 @@ public:
|
|||
|
||||
/// \brief Erase the attributes corresponding to the given declaration.
|
||||
void eraseDeclAttrs(const Decl *D) { DeclAttrs.erase(D); }
|
||||
|
||||
|
||||
/// \brief If this variable is an instantiated static data member of a
|
||||
/// class template specialization, returns the templated static data member
|
||||
/// from which it was instantiated.
|
||||
|
@ -287,6 +287,10 @@ public:
|
|||
/// from T and the gc attribute.
|
||||
QualType getObjCGCQualType(QualType T, QualType::GCAttrTypes gcAttr);
|
||||
|
||||
/// getNoReturnType - Add the noreturn attribute to the given type which must
|
||||
/// be a FunctionType or a pointer to an allowable type or a BlockPointer.
|
||||
QualType getNoReturnType(QualType T);
|
||||
|
||||
/// getComplexType - Return the uniqued reference to the type for a complex
|
||||
/// number with the specified element type.
|
||||
QualType getComplexType(QualType T);
|
||||
|
@ -375,7 +379,7 @@ public:
|
|||
|
||||
/// getFunctionNoProtoType - Return a K&R style C function type like 'int()'.
|
||||
///
|
||||
QualType getFunctionNoProtoType(QualType ResultTy);
|
||||
QualType getFunctionNoProtoType(QualType ResultTy, bool NoReturn = false);
|
||||
|
||||
/// getFunctionType - Return a normal function type with a typed argument
|
||||
/// list. isVariadic indicates whether the argument list includes '...'.
|
||||
|
@ -383,7 +387,8 @@ public:
|
|||
unsigned NumArgs, bool isVariadic,
|
||||
unsigned TypeQuals, bool hasExceptionSpec = false,
|
||||
bool hasAnyExceptionSpec = false,
|
||||
unsigned NumExs = 0, const QualType *ExArray = 0);
|
||||
unsigned NumExs = 0, const QualType *ExArray = 0,
|
||||
bool NoReturn = false);
|
||||
|
||||
/// getTypeDeclType - Return the unique reference to the type for
|
||||
/// the specified type declaration.
|
||||
|
|
|
@ -215,6 +215,9 @@ public:
|
|||
bool isObjCGCStrong() const {
|
||||
return getObjCGCAttr() == Strong;
|
||||
}
|
||||
|
||||
/// getNoReturnAttr() - Return the noreturn attribute of this type.
|
||||
bool getNoReturnAttr() const;
|
||||
};
|
||||
|
||||
} // end clang.
|
||||
|
@ -545,7 +548,7 @@ public:
|
|||
Type *getBaseType() const { return BaseType; }
|
||||
QualType::GCAttrTypes getObjCGCAttr() const { return GCAttrType; }
|
||||
unsigned getAddressSpace() const { return AddressSpace; }
|
||||
|
||||
|
||||
virtual void getAsStringInternal(std::string &InnerString,
|
||||
const PrintingPolicy &Policy) const;
|
||||
|
||||
|
@ -1344,19 +1347,25 @@ class FunctionType : public Type {
|
|||
/// cv-qualifier-seq, [...], are part of the function type.
|
||||
///
|
||||
unsigned TypeQuals : 3;
|
||||
|
||||
/// NoReturn - Indicates if the function type is attribute noreturn.
|
||||
unsigned NoReturn : 1;
|
||||
|
||||
// The type returned by the function.
|
||||
QualType ResultType;
|
||||
protected:
|
||||
FunctionType(TypeClass tc, QualType res, bool SubclassInfo,
|
||||
unsigned typeQuals, QualType Canonical, bool Dependent)
|
||||
unsigned typeQuals, QualType Canonical, bool Dependent,
|
||||
bool noReturn = false)
|
||||
: Type(tc, Canonical, Dependent),
|
||||
SubClassData(SubclassInfo), TypeQuals(typeQuals), ResultType(res) {}
|
||||
SubClassData(SubclassInfo), TypeQuals(typeQuals), NoReturn(noReturn),
|
||||
ResultType(res) {}
|
||||
bool getSubClassData() const { return SubClassData; }
|
||||
unsigned getTypeQuals() const { return TypeQuals; }
|
||||
public:
|
||||
|
||||
QualType getResultType() const { return ResultType; }
|
||||
bool getNoReturnAttr() const { return NoReturn; }
|
||||
|
||||
|
||||
static bool classof(const Type *T) {
|
||||
|
@ -1369,9 +1378,10 @@ public:
|
|||
/// FunctionNoProtoType - Represents a K&R-style 'int foo()' function, which has
|
||||
/// no information available about its arguments.
|
||||
class FunctionNoProtoType : public FunctionType, public llvm::FoldingSetNode {
|
||||
FunctionNoProtoType(QualType Result, QualType Canonical)
|
||||
FunctionNoProtoType(QualType Result, QualType Canonical,
|
||||
bool NoReturn = false)
|
||||
: FunctionType(FunctionNoProto, Result, false, 0, Canonical,
|
||||
/*Dependent=*/false) {}
|
||||
/*Dependent=*/false, NoReturn) {}
|
||||
friend class ASTContext; // ASTContext creates these.
|
||||
public:
|
||||
// No additional state past what FunctionType provides.
|
||||
|
@ -1380,9 +1390,11 @@ public:
|
|||
const PrintingPolicy &Policy) const;
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID) {
|
||||
Profile(ID, getResultType());
|
||||
Profile(ID, getResultType(), getNoReturnAttr());
|
||||
}
|
||||
static void Profile(llvm::FoldingSetNodeID &ID, QualType ResultType) {
|
||||
static void Profile(llvm::FoldingSetNodeID &ID, QualType ResultType,
|
||||
bool NoReturn) {
|
||||
ID.AddInteger(NoReturn);
|
||||
ID.AddPointer(ResultType.getAsOpaquePtr());
|
||||
}
|
||||
|
||||
|
@ -1411,10 +1423,10 @@ class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode {
|
|||
FunctionProtoType(QualType Result, const QualType *ArgArray, unsigned numArgs,
|
||||
bool isVariadic, unsigned typeQuals, bool hasExs,
|
||||
bool hasAnyExs, const QualType *ExArray,
|
||||
unsigned numExs, QualType Canonical)
|
||||
unsigned numExs, QualType Canonical, bool NoReturn)
|
||||
: FunctionType(FunctionProto, Result, isVariadic, typeQuals, Canonical,
|
||||
(Result->isDependentType() ||
|
||||
hasAnyDependentType(ArgArray, numArgs))),
|
||||
hasAnyDependentType(ArgArray, numArgs)), NoReturn),
|
||||
NumArgs(numArgs), NumExceptions(numExs), HasExceptionSpec(hasExs),
|
||||
AnyExceptionSpec(hasAnyExs) {
|
||||
// Fill in the trailing argument array.
|
||||
|
@ -1497,7 +1509,8 @@ public:
|
|||
arg_type_iterator ArgTys, unsigned NumArgs,
|
||||
bool isVariadic, unsigned TypeQuals,
|
||||
bool hasExceptionSpec, bool anyExceptionSpec,
|
||||
unsigned NumExceptions, exception_iterator Exs);
|
||||
unsigned NumExceptions, exception_iterator Exs,
|
||||
bool NoReturn);
|
||||
};
|
||||
|
||||
|
||||
|
@ -2068,6 +2081,18 @@ inline QualType::GCAttrTypes QualType::getObjCGCAttr() const {
|
|||
return PT->getPointeeType().getObjCGCAttr();
|
||||
return GCNone;
|
||||
}
|
||||
|
||||
/// getNoReturnAttr - Return the noreturn attribute of this type.
|
||||
inline bool QualType::getNoReturnAttr() const {
|
||||
QualType CT = getTypePtr()->getCanonicalTypeInternal();
|
||||
if (const PointerType *PT = getTypePtr()->getAsPointerType()) {
|
||||
if (const FunctionType *FT = PT->getPointeeType()->getAsFunctionType())
|
||||
return FT->getNoReturnAttr();
|
||||
} else if (const FunctionType *FT = getTypePtr()->getAsFunctionType())
|
||||
return FT->getNoReturnAttr();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// isMoreQualifiedThan - Determine whether this type is more
|
||||
/// qualified than the Other type. For example, "const volatile int"
|
||||
|
|
|
@ -965,7 +965,7 @@ QualType ASTContext::getAddrSpaceQualType(QualType T, unsigned AddressSpace) {
|
|||
|
||||
// Check if we've already instantiated this type.
|
||||
llvm::FoldingSetNodeID ID;
|
||||
ExtQualType::Profile(ID, TypeNode, AddressSpace, GCAttr);
|
||||
ExtQualType::Profile(ID, TypeNode, AddressSpace, GCAttr);
|
||||
void *InsertPos = 0;
|
||||
if (ExtQualType *EXTQy = ExtQualTypes.FindNodeOrInsertPos(ID, InsertPos))
|
||||
return QualType(EXTQy, CVRQuals);
|
||||
|
@ -1007,17 +1007,17 @@ QualType ASTContext::getObjCGCQualType(QualType T,
|
|||
unsigned AddressSpace = 0;
|
||||
|
||||
if (ExtQualType *EQT = dyn_cast<ExtQualType>(TypeNode)) {
|
||||
// If this type already has an address space specified, it cannot get
|
||||
// If this type already has an ObjCGC specified, it cannot get
|
||||
// another one.
|
||||
assert(EQT->getObjCGCAttr() == QualType::GCNone &&
|
||||
"Type cannot be in multiple addr spaces!");
|
||||
"Type cannot have multiple ObjCGCs!");
|
||||
AddressSpace = EQT->getAddressSpace();
|
||||
TypeNode = EQT->getBaseType();
|
||||
}
|
||||
|
||||
// Check if we've already instantiated an gc qual'd type of this type.
|
||||
llvm::FoldingSetNodeID ID;
|
||||
ExtQualType::Profile(ID, TypeNode, AddressSpace, GCAttr);
|
||||
ExtQualType::Profile(ID, TypeNode, AddressSpace, GCAttr);
|
||||
void *InsertPos = 0;
|
||||
if (ExtQualType *EXTQy = ExtQualTypes.FindNodeOrInsertPos(ID, InsertPos))
|
||||
return QualType(EXTQy, CVRQuals);
|
||||
|
@ -1041,6 +1041,30 @@ QualType ASTContext::getObjCGCQualType(QualType T,
|
|||
return QualType(New, CVRQuals);
|
||||
}
|
||||
|
||||
QualType ASTContext::getNoReturnType(QualType T) {
|
||||
if (T->isPointerType()) {
|
||||
QualType Pointee = T->getAsPointerType()->getPointeeType();
|
||||
QualType ResultType = getNoReturnType(Pointee);
|
||||
return getPointerType(ResultType);
|
||||
}
|
||||
if (T->isBlockPointerType()) {
|
||||
QualType Pointee = T->getAsBlockPointerType()->getPointeeType();
|
||||
QualType ResultType = getNoReturnType(Pointee);
|
||||
return getBlockPointerType(ResultType);
|
||||
}
|
||||
if (!T->isFunctionType())
|
||||
assert(0 && "can't noreturn qualify non-pointer to function or block type");
|
||||
|
||||
if (const FunctionNoProtoType *F = dyn_cast<FunctionNoProtoType>(T)) {
|
||||
return getFunctionNoProtoType(F->getResultType(), true);
|
||||
}
|
||||
const FunctionProtoType *F = cast<FunctionProtoType>(T);
|
||||
return getFunctionType(F->getResultType(), F->arg_type_begin(),
|
||||
F->getNumArgs(), F->isVariadic(), F->getTypeQuals(),
|
||||
F->hasExceptionSpec(), F->hasAnyExceptionSpec(),
|
||||
F->getNumExceptions(), F->exception_begin(), true);
|
||||
}
|
||||
|
||||
/// getComplexType - Return the uniqued reference to the type for a complex
|
||||
/// number with the specified element type.
|
||||
QualType ASTContext::getComplexType(QualType T) {
|
||||
|
@ -1474,11 +1498,11 @@ QualType ASTContext::getDependentSizedExtVectorType(QualType vecType,
|
|||
|
||||
/// getFunctionNoProtoType - Return a K&R style C function type like 'int()'.
|
||||
///
|
||||
QualType ASTContext::getFunctionNoProtoType(QualType ResultTy) {
|
||||
QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, bool NoReturn) {
|
||||
// Unique functions, to guarantee there is only one function of a particular
|
||||
// structure.
|
||||
llvm::FoldingSetNodeID ID;
|
||||
FunctionNoProtoType::Profile(ID, ResultTy);
|
||||
FunctionNoProtoType::Profile(ID, ResultTy, NoReturn);
|
||||
|
||||
void *InsertPos = 0;
|
||||
if (FunctionNoProtoType *FT =
|
||||
|
@ -1487,7 +1511,7 @@ QualType ASTContext::getFunctionNoProtoType(QualType ResultTy) {
|
|||
|
||||
QualType Canonical;
|
||||
if (!ResultTy->isCanonical()) {
|
||||
Canonical = getFunctionNoProtoType(getCanonicalType(ResultTy));
|
||||
Canonical = getFunctionNoProtoType(getCanonicalType(ResultTy), NoReturn);
|
||||
|
||||
// Get the new insert position for the node we care about.
|
||||
FunctionNoProtoType *NewIP =
|
||||
|
@ -1495,7 +1519,8 @@ QualType ASTContext::getFunctionNoProtoType(QualType ResultTy) {
|
|||
assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP;
|
||||
}
|
||||
|
||||
FunctionNoProtoType *New =new(*this,8)FunctionNoProtoType(ResultTy,Canonical);
|
||||
FunctionNoProtoType *New
|
||||
= new (*this,8) FunctionNoProtoType(ResultTy, Canonical, NoReturn);
|
||||
Types.push_back(New);
|
||||
FunctionNoProtoTypes.InsertNode(New, InsertPos);
|
||||
return QualType(New, 0);
|
||||
|
@ -1507,13 +1532,13 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray,
|
|||
unsigned NumArgs, bool isVariadic,
|
||||
unsigned TypeQuals, bool hasExceptionSpec,
|
||||
bool hasAnyExceptionSpec, unsigned NumExs,
|
||||
const QualType *ExArray) {
|
||||
const QualType *ExArray, bool NoReturn) {
|
||||
// Unique functions, to guarantee there is only one function of a particular
|
||||
// structure.
|
||||
llvm::FoldingSetNodeID ID;
|
||||
FunctionProtoType::Profile(ID, ResultTy, ArgArray, NumArgs, isVariadic,
|
||||
TypeQuals, hasExceptionSpec, hasAnyExceptionSpec,
|
||||
NumExs, ExArray);
|
||||
NumExs, ExArray, NoReturn);
|
||||
|
||||
void *InsertPos = 0;
|
||||
if (FunctionProtoType *FTP =
|
||||
|
@ -1539,7 +1564,7 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray,
|
|||
|
||||
Canonical = getFunctionType(getCanonicalType(ResultTy),
|
||||
CanonicalArgs.data(), NumArgs,
|
||||
isVariadic, TypeQuals);
|
||||
isVariadic, TypeQuals, NoReturn);
|
||||
|
||||
// Get the new insert position for the node we care about.
|
||||
FunctionProtoType *NewIP =
|
||||
|
@ -1556,7 +1581,7 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray,
|
|||
NumExs*sizeof(QualType), 8);
|
||||
new (FTP) FunctionProtoType(ResultTy, ArgArray, NumArgs, isVariadic,
|
||||
TypeQuals, hasExceptionSpec, hasAnyExceptionSpec,
|
||||
ExArray, NumExs, Canonical);
|
||||
ExArray, NumExs, Canonical, NoReturn);
|
||||
Types.push_back(FTP);
|
||||
FunctionProtoTypes.InsertNode(FTP, InsertPos);
|
||||
return QualType(FTP, 0);
|
||||
|
@ -3344,7 +3369,12 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) {
|
|||
allLTypes = false;
|
||||
if (getCanonicalType(retType) != getCanonicalType(rbase->getResultType()))
|
||||
allRTypes = false;
|
||||
|
||||
bool NoReturn = lbase->getNoReturnAttr() || rbase->getNoReturnAttr();
|
||||
if (NoReturn != lbase->getNoReturnAttr())
|
||||
allLTypes = false;
|
||||
if (NoReturn != rbase->getNoReturnAttr())
|
||||
allRTypes = false;
|
||||
|
||||
if (lproto && rproto) { // two C99 style function prototypes
|
||||
assert(!lproto->hasExceptionSpec() && !rproto->hasExceptionSpec() &&
|
||||
"C++ shouldn't be here");
|
||||
|
@ -3378,7 +3408,8 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) {
|
|||
if (allLTypes) return lhs;
|
||||
if (allRTypes) return rhs;
|
||||
return getFunctionType(retType, types.begin(), types.size(),
|
||||
lproto->isVariadic(), lproto->getTypeQuals());
|
||||
lproto->isVariadic(), lproto->getTypeQuals(),
|
||||
NoReturn);
|
||||
}
|
||||
|
||||
if (lproto) allRTypes = false;
|
||||
|
@ -3405,12 +3436,12 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) {
|
|||
if (allRTypes) return rhs;
|
||||
return getFunctionType(retType, proto->arg_type_begin(),
|
||||
proto->getNumArgs(), lproto->isVariadic(),
|
||||
lproto->getTypeQuals());
|
||||
lproto->getTypeQuals(), NoReturn);
|
||||
}
|
||||
|
||||
if (allLTypes) return lhs;
|
||||
if (allRTypes) return rhs;
|
||||
return getFunctionNoProtoType(retType);
|
||||
return getFunctionNoProtoType(retType, NoReturn);
|
||||
}
|
||||
|
||||
QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) {
|
||||
|
|
|
@ -904,7 +904,7 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result,
|
|||
unsigned NumArgs, bool isVariadic,
|
||||
unsigned TypeQuals, bool hasExceptionSpec,
|
||||
bool anyExceptionSpec, unsigned NumExceptions,
|
||||
exception_iterator Exs) {
|
||||
exception_iterator Exs, bool NoReturn) {
|
||||
ID.AddPointer(Result.getAsOpaquePtr());
|
||||
for (unsigned i = 0; i != NumArgs; ++i)
|
||||
ID.AddPointer(ArgTys[i].getAsOpaquePtr());
|
||||
|
@ -916,12 +916,13 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result,
|
|||
for(unsigned i = 0; i != NumExceptions; ++i)
|
||||
ID.AddPointer(Exs[i].getAsOpaquePtr());
|
||||
}
|
||||
ID.AddInteger(NoReturn);
|
||||
}
|
||||
|
||||
void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID) {
|
||||
Profile(ID, getResultType(), arg_type_begin(), NumArgs, isVariadic(),
|
||||
getTypeQuals(), hasExceptionSpec(), hasAnyExceptionSpec(),
|
||||
getNumExceptions(), exception_begin());
|
||||
getNumExceptions(), exception_begin(), getNoReturnAttr());
|
||||
}
|
||||
|
||||
void ObjCObjectPointerType::Profile(llvm::FoldingSetNodeID &ID,
|
||||
|
@ -1082,7 +1083,7 @@ const Type *QualifierSet::strip(const Type* T) {
|
|||
if (EQT->getObjCGCAttr())
|
||||
GCAttrType = EQT->getObjCGCAttr();
|
||||
return EQT->getBaseType();
|
||||
}else {
|
||||
} else {
|
||||
// Use the sugared type unless desugaring found extra qualifiers.
|
||||
return (DT.getCVRQualifiers() ? DT.getTypePtr() : T);
|
||||
}
|
||||
|
@ -1413,6 +1414,8 @@ void FunctionNoProtoType::getAsStringInternal(std::string &S, const PrintingPoli
|
|||
S = "(" + S + ")";
|
||||
|
||||
S += "()";
|
||||
if (getNoReturnAttr())
|
||||
S += " __attribute__((noreturn))";
|
||||
getResultType().getAsStringInternal(S, Policy);
|
||||
}
|
||||
|
||||
|
@ -1442,6 +1445,8 @@ void FunctionProtoType::getAsStringInternal(std::string &S, const PrintingPolicy
|
|||
}
|
||||
|
||||
S += ")";
|
||||
if (getNoReturnAttr())
|
||||
S += " __attribute__((noreturn))";
|
||||
getResultType().getAsStringInternal(S, Policy);
|
||||
}
|
||||
|
||||
|
|
|
@ -501,25 +501,29 @@ CFGBlock *CFGBuilder::VisitBreakStmt(BreakStmt *B) {
|
|||
|
||||
CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *C, bool alwaysAdd) {
|
||||
// If this is a call to a no-return function, this stops the block here.
|
||||
if (FunctionDecl *FD = C->getDirectCallee()) {
|
||||
|
||||
if (!FD->hasAttr<NoReturnAttr>())
|
||||
return VisitStmt(C, alwaysAdd);
|
||||
|
||||
if (Block && !FinishBlock(Block))
|
||||
return 0;
|
||||
|
||||
// Create new block with no successor for the remaining pieces.
|
||||
Block = createBlock(false);
|
||||
Block->appendStmt(C);
|
||||
|
||||
// Wire this to the exit block directly.
|
||||
Block->addSuccessor(&cfg->getExit());
|
||||
|
||||
return VisitChildren(C);
|
||||
bool NoReturn = false;
|
||||
if (C->getCallee()->getType().getNoReturnAttr()) {
|
||||
NoReturn = true;
|
||||
}
|
||||
|
||||
if (FunctionDecl *FD = C->getDirectCallee())
|
||||
if (FD->hasAttr<NoReturnAttr>())
|
||||
NoReturn = true;
|
||||
|
||||
if (!NoReturn)
|
||||
return VisitStmt(C, alwaysAdd);
|
||||
|
||||
if (Block && !FinishBlock(Block))
|
||||
return 0;
|
||||
|
||||
// Create new block with no successor for the remaining pieces.
|
||||
Block = createBlock(false);
|
||||
Block->appendStmt(C);
|
||||
|
||||
// Wire this to the exit block directly.
|
||||
Block->addSuccessor(&cfg->getExit());
|
||||
|
||||
return VisitStmt(C, alwaysAdd);
|
||||
return VisitChildren(C);
|
||||
}
|
||||
|
||||
CFGBlock *CFGBuilder::VisitChooseExpr(ChooseExpr *C) {
|
||||
|
|
|
@ -1084,7 +1084,10 @@ Sema::ControlFlowKind Sema::CheckFallThrough(Stmt *Root) {
|
|||
bool NoReturnEdge = false;
|
||||
if (CallExpr *C = dyn_cast<CallExpr>(S)) {
|
||||
Expr *CEE = C->getCallee()->IgnoreParenCasts();
|
||||
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CEE)) {
|
||||
if (CEE->getType().getNoReturnAttr()) {
|
||||
NoReturnEdge = true;
|
||||
HasFakeEdge = true;
|
||||
} else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CEE)) {
|
||||
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(DRE->getDecl())) {
|
||||
if (FD->hasAttr<NoReturnAttr>()) {
|
||||
NoReturnEdge = true;
|
||||
|
|
|
@ -1506,6 +1506,22 @@ static void HandleObjCGCTypeAttribute(QualType &Type,
|
|||
Type = S.Context.getObjCGCQualType(Type, GCAttr);
|
||||
}
|
||||
|
||||
/// HandleNoReturnTypeAttribute - Process the noreturn attribute on the
|
||||
/// specified type. The attribute contains 0 arguments.
|
||||
static void HandleNoReturnTypeAttribute(QualType &Type,
|
||||
const AttributeList &Attr, Sema &S) {
|
||||
if (Attr.getNumArgs() != 0)
|
||||
return;
|
||||
|
||||
// We only apply this to a pointer to function or a pointer to block.
|
||||
if (!Type->isFunctionPointerType()
|
||||
&& !Type->isBlockPointerType()
|
||||
&& !Type->isFunctionType())
|
||||
return;
|
||||
|
||||
Type = S.Context.getNoReturnType(Type);
|
||||
}
|
||||
|
||||
void Sema::ProcessTypeAttributeList(QualType &Result, const AttributeList *AL) {
|
||||
// Scan through and apply attributes to this type where it makes sense. Some
|
||||
// attributes (such as __address_space__, __vector_size__, etc) apply to the
|
||||
|
@ -1522,6 +1538,9 @@ void Sema::ProcessTypeAttributeList(QualType &Result, const AttributeList *AL) {
|
|||
case AttributeList::AT_objc_gc:
|
||||
HandleObjCGCTypeAttribute(Result, *AL, *this);
|
||||
break;
|
||||
case AttributeList::AT_noreturn:
|
||||
HandleNoReturnTypeAttribute(Result, *AL, *this);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
// RUN: clang-cc -emit-llvm %s -o %t
|
||||
|
||||
int f() {
|
||||
void f() {
|
||||
int a[2];
|
||||
a[0] = 0;
|
||||
}
|
||||
|
||||
int f2() {
|
||||
void f2() {
|
||||
int x = 0;
|
||||
int y = 1;
|
||||
int a[10] = { y, x, 2, 3};
|
||||
|
|
|
@ -158,6 +158,7 @@ int test26() {
|
|||
} // expected-warning {{control reaches end of non-void function}}
|
||||
|
||||
int j;
|
||||
void (*fptr)() __attribute__((noreturn));
|
||||
int test27() {
|
||||
switch (j) {
|
||||
case 1:
|
||||
|
@ -178,6 +179,9 @@ int test27() {
|
|||
case 5:
|
||||
while (1) { return 1; }
|
||||
break;
|
||||
case 6:
|
||||
fptr();
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче