On Jul 25, 2009, at 2:26 PM, Mike Stump wrote: > Author: mrs > Date: Sat Jul 25 16:26:53 2009 > New Revision: 77089 > > URL: http://llvm.org/viewvc/llvm-project?rev=77089&view=rev > Log: > Add noreturn as a type attribute, handle printing for them and handle > calls to noreturn function pointers when CFG building. > > Modified: > cfe/trunk/include/clang/AST/ASTContext.h > cfe/trunk/include/clang/AST/Type.h > cfe/trunk/lib/AST/ASTContext.cpp > cfe/trunk/lib/AST/Type.cpp > cfe/trunk/lib/Analysis/CFG.cpp > cfe/trunk/lib/Sema/SemaDecl.cpp > cfe/trunk/lib/Sema/SemaType.cpp > cfe/trunk/test/CodeGen/array.c > cfe/trunk/test/Sema/return.c
Nice. Couple of comments below. - Fariborz > > > Modified: cfe/trunk/include/clang/AST/ASTContext.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=77089&r1=77088&r2=77089&view=diff > > = > = > = > = > = > = > = > = > ====================================================================== > --- cfe/trunk/include/clang/AST/ASTContext.h (original) > +++ cfe/trunk/include/clang/AST/ASTContext.h Sat Jul 25 16:26:53 2009 > @@ -135,7 +135,7 @@ > /// 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 @@ > > /// \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 @@ > /// 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 @@ > > /// 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 @@ > 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. > > Modified: cfe/trunk/include/clang/AST/Type.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=77089&r1=77088&r2=77089&view=diff > > = > = > = > = > = > = > = > = > ====================================================================== > --- cfe/trunk/include/clang/AST/Type.h (original) > +++ cfe/trunk/include/clang/AST/Type.h Sat Jul 25 16:26:53 2009 > @@ -215,6 +215,9 @@ > bool isObjCGCStrong() const { > return getObjCGCAttr() == Strong; > } > + > + /// getNoReturnAttr() - Return the noreturn attribute of this type. Since functions returns bool, comment is confusing. Maybe, return 'true' if type has noreturn attribute; false, otherwise. > > + bool getNoReturnAttr() const; > }; > > } // end clang. > @@ -545,7 +548,7 @@ > 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 @@ > /// 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 @@ > /// 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 @@ > 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 @@ > 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 @@ > 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 @@ > return PT->getPointeeType().getObjCGCAttr(); > return GCNone; > } > + > +/// getNoReturnAttr - Return the noreturn attribute of this type. See above comment. > > +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" > > Modified: cfe/trunk/lib/AST/ASTContext.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=77089&r1=77088&r2=77089&view=diff > > = > = > = > = > = > = > = > = > ====================================================================== > --- cfe/trunk/lib/AST/ASTContext.cpp (original) > +++ cfe/trunk/lib/AST/ASTContext.cpp Sat Jul 25 16:26:53 2009 > @@ -965,7 +965,7 @@ > > // 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 @@ > 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!"); Thanks for fixing the comments (my bad). > > 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 @@ > 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); > +} This function does not preserve the other attributes. For example, block pointers can be __weak/__strong. See ASTContext::getObjCGCQualType. > > + > /// 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 @@ > > /// 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 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 @@ > 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 @@ > 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 @@ > > 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 @@ > 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 @@ > 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 @@ > 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 @@ > 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) { > > Modified: cfe/trunk/lib/AST/Type.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Type.cpp?rev=77089&r1=77088&r2=77089&view=diff > > = > = > = > = > = > = > = > = > ====================================================================== > --- cfe/trunk/lib/AST/Type.cpp (original) > +++ cfe/trunk/lib/AST/Type.cpp Sat Jul 25 16:26:53 2009 > @@ -904,7 +904,7 @@ > 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 @@ > 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 @@ > 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 @@ > S = "(" + S + ")"; > > S += "()"; > + if (getNoReturnAttr()) > + S += " __attribute__((noreturn))"; > getResultType().getAsStringInternal(S, Policy); > } > > @@ -1442,6 +1445,8 @@ > } > > S += ")"; > + if (getNoReturnAttr()) > + S += " __attribute__((noreturn))"; > getResultType().getAsStringInternal(S, Policy); > } > > > Modified: cfe/trunk/lib/Analysis/CFG.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFG.cpp?rev=77089&r1=77088&r2=77089&view=diff > > = > = > = > = > = > = > = > = > ====================================================================== > --- cfe/trunk/lib/Analysis/CFG.cpp (original) > +++ cfe/trunk/lib/Analysis/CFG.cpp Sat Jul 25 16:26:53 2009 > @@ -501,25 +501,29 @@ > > 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); > + 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); > > - // 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) { > > Modified: cfe/trunk/lib/Sema/SemaDecl.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=77089&r1=77088&r2=77089&view=diff > > = > = > = > = > = > = > = > = > ====================================================================== > --- cfe/trunk/lib/Sema/SemaDecl.cpp (original) > +++ cfe/trunk/lib/Sema/SemaDecl.cpp Sat Jul 25 16:26:53 2009 > @@ -1084,7 +1084,10 @@ > 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; > > Modified: cfe/trunk/lib/Sema/SemaType.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=77089&r1=77088&r2=77089&view=diff > > = > = > = > = > = > = > = > = > ====================================================================== > --- cfe/trunk/lib/Sema/SemaType.cpp (original) > +++ cfe/trunk/lib/Sema/SemaType.cpp Sat Jul 25 16:26:53 2009 > @@ -1506,6 +1506,22 @@ > 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) Don't you want to issue error here? > > + return; > + > + // We only apply this to a pointer to function or a pointer to > block. > + if (!Type->isFunctionPointerType() > + && !Type->isBlockPointerType() > + && !Type->isFunctionType()) And here? > > + 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 @@ > case AttributeList::AT_objc_gc: > HandleObjCGCTypeAttribute(Result, *AL, *this); > break; > + case AttributeList::AT_noreturn: > + HandleNoReturnTypeAttribute(Result, *AL, *this); > + break; > } > } > } > > Modified: cfe/trunk/test/CodeGen/array.c > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/array.c?rev=77089&r1=77088&r2=77089&view=diff > > = > = > = > = > = > = > = > = > ====================================================================== > --- cfe/trunk/test/CodeGen/array.c (original) > +++ cfe/trunk/test/CodeGen/array.c Sat Jul 25 16:26:53 2009 > @@ -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}; > > Modified: cfe/trunk/test/Sema/return.c > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/return.c?rev=77089&r1=77088&r2=77089&view=diff > > = > = > = > = > = > = > = > = > ====================================================================== > --- cfe/trunk/test/Sema/return.c (original) > +++ cfe/trunk/test/Sema/return.c Sat Jul 25 16:26:53 2009 > @@ -158,6 +158,7 @@ > } // 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 @@ > case 5: > while (1) { return 1; } > break; > + case 6: > + fptr(); > + break; > default: > return 1; > } > > > _______________________________________________ > cfe-commits mailing list > [email protected] > http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits _______________________________________________ cfe-commits mailing list [email protected] http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
