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
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 490f338..fcdd487 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -1200,32 +1200,42 @@
   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());
 }