From: Mike Stump Date: Sat, 25 Jul 2009 21:26:53 +0000 (+0000) Subject: Add noreturn as a type attribute, handle printing for them and handle X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=2455636163fdd18581d7fdae816433f886d88213;p=clang 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 --- diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 78c6122655..7768ba49d5 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -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 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. diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 761f3fc922..8985051ad5 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -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" diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 4684a806f0..27c8a81975 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -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(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(T)) { + return getFunctionNoProtoType(F->getResultType(), true); + } + const FunctionProtoType *F = cast(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) { diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index c3bb29b8d5..ef75b2b3c2 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -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); } diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp index 217df459b8..c4406858e5 100644 --- a/lib/Analysis/CFG.cpp +++ b/lib/Analysis/CFG.cpp @@ -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()) - 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); + bool NoReturn = false; + if (C->getCallee()->getType().getNoReturnAttr()) { + NoReturn = true; + } + + if (FunctionDecl *FD = C->getDirectCallee()) + if (FD->hasAttr()) + NoReturn = true; + + if (!NoReturn) + return VisitStmt(C, alwaysAdd); - // Wire this to the exit block directly. - Block->addSuccessor(&cfg->getExit()); + if (Block && !FinishBlock(Block)) + return 0; - return VisitChildren(C); - } + // 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) { diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 91de998936..07e1ce77de 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -1084,7 +1084,10 @@ Sema::ControlFlowKind Sema::CheckFallThrough(Stmt *Root) { bool NoReturnEdge = false; if (CallExpr *C = dyn_cast(S)) { Expr *CEE = C->getCallee()->IgnoreParenCasts(); - if (DeclRefExpr *DRE = dyn_cast(CEE)) { + if (CEE->getType().getNoReturnAttr()) { + NoReturnEdge = true; + HasFakeEdge = true; + } else if (DeclRefExpr *DRE = dyn_cast(CEE)) { if (FunctionDecl *FD = dyn_cast(DRE->getDecl())) { if (FD->hasAttr()) { NoReturnEdge = true; diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index a686e1db59..226f214391 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -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; } } } diff --git a/test/CodeGen/array.c b/test/CodeGen/array.c index 5bcc26ecf3..294dabfbbb 100644 --- a/test/CodeGen/array.c +++ b/test/CodeGen/array.c @@ -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}; diff --git a/test/Sema/return.c b/test/Sema/return.c index fd50d0792a..db83a06d2a 100644 --- a/test/Sema/return.c +++ b/test/Sema/return.c @@ -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; }