From 00ccbefcffeb88ea3e2e6323e594fa968753ad14 Mon Sep 17 00:00:00 2001 From: John McCall Date: Tue, 21 Dec 2010 00:44:39 +0000 Subject: [PATCH] Fix the noreturn conversion to only strip off a single level of indirection. Apply the noreturn attribute while creating a builtin function's type. Remove the getNoReturnType() API. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@122295 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/ASTContext.h | 5 --- lib/AST/ASTContext.cpp | 62 ++++++---------------------------- lib/Sema/SemaDecl.cpp | 2 -- lib/Sema/SemaOverload.cpp | 43 +++++++++++++++++++---- 4 files changed, 47 insertions(+), 65 deletions(-) diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index aee1612948..757cddbfd2 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -484,11 +484,6 @@ public: const FunctionType *adjustFunctionType(const FunctionType *Fn, FunctionType::ExtInfo EInfo); - /// getNoReturnType - Add or remove 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, bool AddNoReturn = true); - /// getComplexType - Return the uniqued reference to the type for a complex /// number with the specified element type. QualType getComplexType(QualType T); diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 8e2ef1a95e..90279d8db1 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -1159,53 +1159,6 @@ const FunctionType *ASTContext::adjustFunctionType(const FunctionType *T, return cast(Result.getTypePtr()); } -static QualType getExtFunctionType(ASTContext& Context, QualType T, - FunctionType::ExtInfo Info) { - QualType ResultType; - if (const PointerType *Pointer = T->getAs()) { - QualType Pointee = Pointer->getPointeeType(); - ResultType = getExtFunctionType(Context, Pointee, Info); - if (ResultType == Pointee) - return T; - - ResultType = Context.getPointerType(ResultType); - } else if (const ParenType *Paren = T->getAs()) { - QualType Inner = Paren->getInnerType(); - ResultType = getExtFunctionType(Context, Inner, Info); - if (ResultType == Inner) - return T; - - ResultType = Context.getParenType(ResultType); - } else if (const BlockPointerType *BlockPointer - = T->getAs()) { - QualType Pointee = BlockPointer->getPointeeType(); - ResultType = getExtFunctionType(Context, Pointee, Info); - if (ResultType == Pointee) - return T; - - ResultType = Context.getBlockPointerType(ResultType); - } else if (const MemberPointerType *MemberPointer - = T->getAs()) { - QualType Pointee = MemberPointer->getPointeeType(); - ResultType = getExtFunctionType(Context, Pointee, Info); - if (ResultType == Pointee) - return T; - - ResultType = Context.getMemberPointerType(ResultType, - MemberPointer->getClass()); - } else if (const FunctionType *F = T->getAs()) { - ResultType = QualType(Context.adjustFunctionType(F, Info), 0); - } else - return T; - - return Context.getQualifiedType(ResultType, T.getLocalQualifiers()); -} - -QualType ASTContext::getNoReturnType(QualType T, bool AddNoReturn) { - FunctionType::ExtInfo Info = getFunctionExtInfo(T); - return getExtFunctionType(*this, T, Info.withNoReturn(AddNoReturn)); -} - /// getComplexType - Return the uniqued reference to the type for a complex /// number with the specified element type. QualType ASTContext::getComplexType(QualType T) { @@ -5595,13 +5548,18 @@ QualType ASTContext::GetBuiltinType(unsigned Id, assert((TypeStr[0] != '.' || TypeStr[1] == 0) && "'.' should only occur at end of builtin type list!"); - // handle untyped/variadic arguments "T c99Style();" or "T cppStyle(...);". - if (ArgTypes.size() == 0 && TypeStr[0] == '.') - return getFunctionNoProtoType(ResType); + FunctionType::ExtInfo EI; + if (BuiltinInfo.isNoReturn(Id)) EI = EI.withNoReturn(true); + + bool Variadic = (TypeStr[0] == '.'); + + // We really shouldn't be making a no-proto type here, especially in C++. + if (ArgTypes.empty() && Variadic) + return getFunctionNoProtoType(ResType, EI); FunctionProtoType::ExtProtoInfo EPI; - EPI.Variadic = (TypeStr[0] == '.'); - // FIXME: Should we create noreturn types? + EPI.ExtInfo = EI; + EPI.Variadic = Variadic; return getFunctionType(ResType, ArgTypes.data(), ArgTypes.size(), EPI); } diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 665689ef26..ad0c077aad 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -5594,8 +5594,6 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) { FD->addAttr(::new (Context) ConstAttr(FD->getLocation(), Context)); } - if (Context.BuiltinInfo.isNoReturn(BuiltinID)) - FD->setType(Context.getNoReturnType(FD->getType())); if (Context.BuiltinInfo.isNoThrow(BuiltinID)) FD->addAttr(::new (Context) NoThrowAttr(FD->getLocation(), Context)); if (Context.BuiltinInfo.isConst(BuiltinID)) diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 5a2150664c..6b370fd36a 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -882,13 +882,44 @@ static bool IsNoReturnConversion(ASTContext &Context, QualType FromType, if (Context.hasSameUnqualifiedType(FromType, ToType)) return false; - // Strip the noreturn off the type we're converting from; noreturn can - // safely be removed. - FromType = Context.getNoReturnType(FromType, false); - if (!Context.hasSameUnqualifiedType(FromType, ToType)) - return false; + // Permit the conversion F(t __attribute__((noreturn))) -> F(t) + // where F adds one of the following at most once: + // - a pointer + // - a member pointer + // - a block pointer + CanQualType CanTo = Context.getCanonicalType(ToType); + CanQualType CanFrom = Context.getCanonicalType(FromType); + Type::TypeClass TyClass = CanTo->getTypeClass(); + if (TyClass != CanFrom->getTypeClass()) return false; + if (TyClass != Type::FunctionProto && TyClass != Type::FunctionNoProto) { + if (TyClass == Type::Pointer) { + CanTo = CanTo.getAs()->getPointeeType(); + CanFrom = CanFrom.getAs()->getPointeeType(); + } else if (TyClass == Type::BlockPointer) { + CanTo = CanTo.getAs()->getPointeeType(); + CanFrom = CanFrom.getAs()->getPointeeType(); + } else if (TyClass == Type::MemberPointer) { + CanTo = CanTo.getAs()->getPointeeType(); + CanFrom = CanFrom.getAs()->getPointeeType(); + } else { + return false; + } + + TyClass = CanTo->getTypeClass(); + if (TyClass != CanFrom->getTypeClass()) return false; + if (TyClass != Type::FunctionProto && TyClass != Type::FunctionNoProto) + return false; + } + + const FunctionType *FromFn = cast(CanFrom); + FunctionType::ExtInfo EInfo = FromFn->getExtInfo(); + if (!EInfo.getNoReturn()) return false; + + FromFn = Context.adjustFunctionType(FromFn, EInfo.withNoReturn(false)); + assert(QualType(FromFn, 0).isCanonical()); + if (QualType(FromFn, 0) != CanTo) return false; - ResultTy = FromType; + ResultTy = ToType; return true; } -- 2.40.0