diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-12-09 00:47:37 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-12-09 00:47:37 +0000 |
commit | 43c79c2b07abc7ba6d9f243b84ee6539de4d2652 (patch) | |
tree | 790ec22e1b69c168ef89a885b2c4cf1c2a425f36 | |
parent | a498ca67b3d6bb65443c00ef8aa8e3c83ef19b6d (diff) |
Implemented an implicit conversion from "noreturn" function types (and
pointers thereof) to their corresponding non-noreturn function
types. This conversion is considered an exact match for
overload-resolution purposes. Note that we are a little more strict
that GCC is, because we encode noreturn in the type system, but that's
a Good Thing (TM) because it does not allow us to pretend that
potentially-returning function pointers are non-returning function
pointers.
Fxies PR5620.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@90913 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/AST/ASTContext.h | 7 | ||||
-rw-r--r-- | lib/AST/ASTContext.cpp | 50 | ||||
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 10 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 32 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.h | 1 | ||||
-rw-r--r-- | test/SemaCXX/attr-noreturn.cpp | 30 |
6 files changed, 104 insertions, 26 deletions
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index fe270272dd..fffe45b6c9 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -394,9 +394,10 @@ public: /// equivalent to calling T.withConst(). QualType getConstType(QualType T) { return T.withConst(); } - /// 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); + /// 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. diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 490f338d38..fcdd48716e 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -1200,32 +1200,42 @@ QualType ASTContext::getObjCGCQualType(QualType T, return getExtQualType(TypeNode, Quals); } -QualType ASTContext::getNoReturnType(QualType T) { +QualType ASTContext::getNoReturnType(QualType T, bool AddNoReturn) { QualType ResultType; - if (T->isPointerType()) { - QualType Pointee = T->getAs<PointerType>()->getPointeeType(); - ResultType = getNoReturnType(Pointee); + if (const PointerType *Pointer = T->getAs<PointerType>()) { + QualType Pointee = Pointer->getPointeeType(); + ResultType = getNoReturnType(Pointee, AddNoReturn); + if (ResultType == Pointee) + return T; + ResultType = getPointerType(ResultType); - } else if (T->isBlockPointerType()) { - QualType Pointee = T->getAs<BlockPointerType>()->getPointeeType(); - ResultType = getNoReturnType(Pointee); + } else if (const BlockPointerType *BlockPointer + = T->getAs<BlockPointerType>()) { + QualType Pointee = BlockPointer->getPointeeType(); + ResultType = getNoReturnType(Pointee, AddNoReturn); + if (ResultType == Pointee) + return T; + ResultType = getBlockPointerType(ResultType); - } else { - assert (T->isFunctionType() - && "can't noreturn qualify non-pointer to function or block type"); - - if (const FunctionNoProtoType *FNPT = T->getAs<FunctionNoProtoType>()) { - ResultType = getFunctionNoProtoType(FNPT->getResultType(), true); + } else if (const FunctionType *F = T->getAs<FunctionType>()) { + if (F->getNoReturnAttr() == AddNoReturn) + return T; + + if (const FunctionNoProtoType *FNPT = dyn_cast<FunctionNoProtoType>(F)) { + ResultType = getFunctionNoProtoType(FNPT->getResultType(), AddNoReturn); } else { - const FunctionProtoType *F = T->getAs<FunctionProtoType>(); + const FunctionProtoType *FPT = cast<FunctionProtoType>(F); ResultType - = getFunctionType(F->getResultType(), F->arg_type_begin(), - F->getNumArgs(), F->isVariadic(), F->getTypeQuals(), - F->hasExceptionSpec(), F->hasAnyExceptionSpec(), - F->getNumExceptions(), F->exception_begin(), true); + = getFunctionType(FPT->getResultType(), FPT->arg_type_begin(), + FPT->getNumArgs(), FPT->isVariadic(), + FPT->getTypeQuals(), + FPT->hasExceptionSpec(), FPT->hasAnyExceptionSpec(), + FPT->getNumExceptions(), FPT->exception_begin(), + AddNoReturn); } - } - + } else + return T; + return getQualifiedType(ResultType, T.getLocalQualifiers()); } diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index be33c06765..d83148c210 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -1269,6 +1269,16 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, // Nothing else to do. break; + case ICK_NoReturn_Adjustment: + // If both sides are functions (or pointers/references to them), there could + // be incompatible exception declarations. + if (CheckExceptionSpecCompatibility(From, ToType)) + return true; + + ImpCastExprToType(From, Context.getNoReturnType(From->getType(), false), + CastExpr::CK_NoOp); + break; + case ICK_Integral_Promotion: case ICK_Integral_Conversion: ImpCastExprToType(From, ToType, CastExpr::CK_IntegralCast); diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 769adb51cf..47393f7b23 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -38,6 +38,7 @@ GetConversionCategory(ImplicitConversionKind Kind) { ICC_Lvalue_Transformation, ICC_Lvalue_Transformation, ICC_Lvalue_Transformation, + ICC_Identity, ICC_Qualification_Adjustment, ICC_Promotion, ICC_Promotion, @@ -66,6 +67,7 @@ ImplicitConversionRank GetConversionRank(ImplicitConversionKind Kind) { ICR_Exact_Match, ICR_Exact_Match, ICR_Exact_Match, + ICR_Exact_Match, ICR_Promotion, ICR_Promotion, ICR_Promotion, @@ -91,6 +93,7 @@ const char* GetImplicitConversionName(ImplicitConversionKind Kind) { "Lvalue-to-rvalue", "Array-to-pointer", "Function-to-pointer", + "Noreturn adjustment", "Qualification", "Integral promotion", "Floating point promotion", @@ -475,6 +478,23 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType, return ICS; } +/// \brief Determine whether the conversion from FromType to ToType is a valid +/// conversion that strips "noreturn" off the nested function type. +static bool IsNoReturnConversion(ASTContext &Context, QualType FromType, + QualType ToType, QualType &ResultTy) { + 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; + + ResultTy = FromType; + return true; +} + /// IsStandardConversion - Determines whether there is a standard /// conversion sequence (C++ [conv], C++ [over.ics.scs]) from the /// expression From to the type ToType. Standard conversion sequences @@ -554,7 +574,7 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, // function. (C++ 4.3p1). FromType = Context.getPointerType(FromType); } else if (FunctionDecl *Fn - = ResolveAddressOfOverloadedFunction(From, ToType, false)) { + = ResolveAddressOfOverloadedFunction(From, ToType, false)) { // Address of overloaded function (C++ [over.over]). SCS.First = ICK_Function_To_Pointer; @@ -656,6 +676,9 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, Context.typesAreCompatible(ToType, FromType)) { // Compatible conversions (Clang extension for C function overloading) SCS.Second = ICK_Compatible_Conversion; + } else if (IsNoReturnConversion(Context, FromType, ToType, FromType)) { + // Treat a conversion that strips "noreturn" as an identity conversion. + SCS.Second = ICK_NoReturn_Adjustment; } else { // No second conversion required. SCS.Second = ICK_Identity; @@ -1234,7 +1257,7 @@ bool Sema::IsMemberPointerConversion(Expr *From, QualType FromType, return false; } - + /// CheckMemberPointerConversion - Check the member pointer conversion from the /// expression From to the type ToType. This routine checks for ambiguous or /// virtual (FIXME: or inaccessible) base-to-derived member pointer conversions @@ -4455,7 +4478,10 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, continue; if (FunctionDecl *FunDecl = dyn_cast<FunctionDecl>(*I)) { - if (FunctionType == Context.getCanonicalType(FunDecl->getType())) { + QualType ResultTy; + if (Context.hasSameUnqualifiedType(FunctionType, FunDecl->getType()) || + IsNoReturnConversion(Context, FunDecl->getType(), FunctionType, + ResultTy)) { Matches.insert(cast<FunctionDecl>(FunDecl->getCanonicalDecl())); FoundNonTemplateFunction = true; } diff --git a/lib/Sema/SemaOverload.h b/lib/Sema/SemaOverload.h index 0d1f37aa4b..5eef3cebe4 100644 --- a/lib/Sema/SemaOverload.h +++ b/lib/Sema/SemaOverload.h @@ -30,6 +30,7 @@ namespace clang { ICK_Lvalue_To_Rvalue, ///< Lvalue-to-rvalue conversion (C++ 4.1) ICK_Array_To_Pointer, ///< Array-to-pointer conversion (C++ 4.2) ICK_Function_To_Pointer, ///< Function-to-pointer (C++ 4.3) + ICK_NoReturn_Adjustment, ///< Removal of noreturn from a type (Clang) ICK_Qualification, ///< Qualification conversions (C++ 4.4) ICK_Integral_Promotion, ///< Integral promotions (C++ 4.5) ICK_Floating_Promotion, ///< Floating point promotions (C++ 4.6) diff --git a/test/SemaCXX/attr-noreturn.cpp b/test/SemaCXX/attr-noreturn.cpp new file mode 100644 index 0000000000..e4fdc08ae9 --- /dev/null +++ b/test/SemaCXX/attr-noreturn.cpp @@ -0,0 +1,30 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +// PR5620 +void f0() __attribute__((__noreturn__)); +void f1(void (*)()); +void f2() { f1(f0); } + +// Taking the address of a noreturn function +void test_f0a() { + void (*fp)() = f0; + void (*fp1)() __attribute__((noreturn)) = f0; +} + +// Taking the address of an overloaded noreturn function +void f0(int) __attribute__((__noreturn__)); + +void test_f0b() { + void (*fp)() = f0; + void (*fp1)() __attribute__((noreturn)) = f0; +} + +// No-returned function pointers +typedef void (* noreturn_fp)() __attribute__((noreturn)); + +void f3(noreturn_fp); // expected-note{{candidate function}} + +void test_f3() { + f3(f0); // okay + f3(f2); // expected-error{{no matching function for call}} +} |