]> granicus.if.org Git - clang/commitdiff
Accept no-return stripping conversions for pointer type arguments after
authorChandler Carruth <chandlerc@gmail.com>
Sat, 18 Jun 2011 01:19:03 +0000 (01:19 +0000)
committerChandler Carruth <chandlerc@gmail.com>
Sat, 18 Jun 2011 01:19:03 +0000 (01:19 +0000)
deducing template parameter types. Recently Clang began enforcing the
more strict checking that the argument type and the deduced function
parameter type (after substitution) match, but that only consideres
qualification conversions.

One problem with this patch is that we check noreturn conversions and
qualification conversions independently. If a valid conversion would
require *both*, perhaps interleaved with each other, it will be
rejected. If this actually occurs (I'm not yet sure it does) and is in
fact a problem (I'm not yet sure it is), there is a FIXME to implement
more intelligent conversion checking.

However, this step at least allows Clang to resume accepting valid code
we're seeing in the wild.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@133327 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Sema/Sema.h
lib/Sema/SemaOverload.cpp
lib/Sema/SemaTemplateDeduction.cpp
test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3.cpp

index 577c88c92709acc9722c458aefffe8775e16a38b..06d7d58988c1efd43f7990e6f84f7f78a17d1b42 100644 (file)
@@ -1351,6 +1351,8 @@ public:
                                     bool IgnoreBaseAccess);
   bool IsQualificationConversion(QualType FromType, QualType ToType,
                                  bool CStyle, bool &ObjCLifetimeConversion);
+  bool IsNoReturnConversion(QualType FromType, QualType ToType,
+                            QualType &ResultTy);
   bool DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType);
 
 
index 2995e2e6e07b6d09ba77f414f0a2a0df1eead4b4..eb1d661183accb8aac5dac6f16c154cf5b4d8acc 100644 (file)
@@ -924,8 +924,8 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
 
 /// \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) {
+bool Sema::IsNoReturnConversion(QualType FromType, QualType ToType,
+                                QualType &ResultTy) {
   if (Context.hasSameUnqualifiedType(FromType, ToType))
     return false;
 
@@ -1066,7 +1066,7 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
                       S.ExtractUnqualifiedFunctionType(ToType), FromType)) {
         QualType resultTy;
         // if the function type matches except for [[noreturn]], it's ok
-        if (!IsNoReturnConversion(S.Context, FromType, 
+        if (!S.IsNoReturnConversion(FromType,
               S.ExtractUnqualifiedFunctionType(ToType), resultTy))
           // otherwise, only a boolean conversion is standard   
           if (!ToType->isBooleanType()) 
@@ -1234,7 +1234,7 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
     // Compatible conversions (Clang extension for C function overloading)
     SCS.Second = ICK_Compatible_Conversion;
     FromType = ToType.getUnqualifiedType();
-  } else if (IsNoReturnConversion(S.Context, FromType, ToType, FromType)) {
+  } else if (S.IsNoReturnConversion(FromType, ToType, FromType)) {
     // Treat a conversion that strips "noreturn" as an identity conversion.
     SCS.Second = ICK_NoReturn_Adjustment;
   } else if (IsTransparentUnionStandardConversion(S, From, ToType,
@@ -7597,8 +7597,8 @@ private:
       QualType ResultTy;
       if (Context.hasSameUnqualifiedType(TargetFunctionType, 
                                          FunDecl->getType()) ||
-          IsNoReturnConversion(Context, FunDecl->getType(), TargetFunctionType, 
-                               ResultTy)) {
+          S.IsNoReturnConversion(FunDecl->getType(), TargetFunctionType,
+                                 ResultTy)) {
         Matches.push_back(std::make_pair(CurAccessFunPair,
           cast<FunctionDecl>(FunDecl->getCanonicalDecl())));
         FoundNonTemplateFunction = true;
index b5e9c25d8566b7e2011a5491342d4672ad9b2978..dcb4ff286060467a85d279a8410e90f99fb5f596 100644 (file)
@@ -2371,9 +2371,16 @@ CheckOriginalCallArgDeduction(Sema &S, Sema::OriginalCallArg OriginalArg,
   //    - The transformed A can be another pointer or pointer to member 
   //      type that can be converted to the deduced A via a qualification 
   //      conversion.
+  //
+  // Also allow conversions which merely strip [[noreturn]] from function types
+  // (recursively) as an extension.
+  // FIXME: Currently, this doesn't place nicely with qualfication conversions.
   bool ObjCLifetimeConversion = false;
+  QualType ResultTy;
   if ((A->isAnyPointerType() || A->isMemberPointerType()) &&
-      S.IsQualificationConversion(A, DeducedA, false, ObjCLifetimeConversion))
+      (S.IsQualificationConversion(A, DeducedA, false,
+                                   ObjCLifetimeConversion) ||
+       S.IsNoReturnConversion(A, DeducedA, ResultTy)))
     return false;
   
   
index f5481c307d0349a28f8aa9ce09c8435dbdbfa7ca..295f080a75d92e1a5b704de52b9db7c8d3bdbd70 100644 (file)
@@ -71,7 +71,21 @@ void test_f3(int ***ip, volatile int ***vip) {
   A<int> a0 = f3(ip);
   A<volatile int> a1 = f3(vip);
 }
-                             
+
+// Also accept conversions for pointer types which require removing
+// [[noreturn]].
+namespace noreturn_stripping {
+  template <class R>
+  void f(R (*function)());
+
+  void g() __attribute__ ((__noreturn__));
+  void h();
+  void test() {
+    f(g);
+    f(h);
+  }
+}
+
 //   - If P is a class, and P has the form template-id, then A can be a 
 //     derived class of the deduced A. Likewise, if P is a pointer to a class
 //     of the form template-id, A can be a pointer to a derived class pointed