[c++1z] Fix corner case where we could create a function type whose canonical type...
authorRichard Smith <richard-llvm@metafoo.co.uk>
Tue, 18 Oct 2016 20:13:25 +0000 (20:13 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Tue, 18 Oct 2016 20:13:25 +0000 (20:13 +0000)
llvm-svn: 284528

clang/include/clang/AST/ASTContext.h
clang/lib/AST/ASTContext.cpp
clang/test/SemaCXX/cxx1z-noexcept-function-type.cpp

index 3d77752..f914dae 100644 (file)
@@ -1224,8 +1224,17 @@ public:
 
   /// \brief Return a normal function type with a typed argument list.
   QualType getFunctionType(QualType ResultTy, ArrayRef<QualType> Args,
-                           const FunctionProtoType::ExtProtoInfo &EPI) const;
+                           const FunctionProtoType::ExtProtoInfo &EPI) const {
+    return getFunctionTypeInternal(ResultTy, Args, EPI, false);
+  }
 
+private:
+  /// \brief Return a normal function type with a typed argument list.
+  QualType getFunctionTypeInternal(QualType ResultTy, ArrayRef<QualType> Args,
+                                   const FunctionProtoType::ExtProtoInfo &EPI,
+                                   bool OnlyWantCanonical) const;
+
+public:
   /// \brief Return the unique reference to the type for the specified type
   /// declaration.
   QualType getTypeDeclType(const TypeDecl *Decl,
index 0ac1e17..6b42883 100644 (file)
@@ -3167,9 +3167,9 @@ static bool isCanonicalExceptionSpecification(
   return false;
 }
 
-QualType
-ASTContext::getFunctionType(QualType ResultTy, ArrayRef<QualType> ArgArray,
-                            const FunctionProtoType::ExtProtoInfo &EPI) const {
+QualType ASTContext::getFunctionTypeInternal(
+    QualType ResultTy, ArrayRef<QualType> ArgArray,
+    const FunctionProtoType::ExtProtoInfo &EPI, bool OnlyWantCanonical) const {
   size_t NumArgs = ArgArray.size();
 
   // Unique functions, to guarantee there is only one function of a particular
@@ -3188,9 +3188,10 @@ ASTContext::getFunctionType(QualType ResultTy, ArrayRef<QualType> ArgArray,
 
     // If we find a pre-existing equivalent FunctionProtoType, we can just reuse
     // it so long as our exception specification doesn't contain a dependent
-    // noexcept expression. If it /does/, we're going to need to create a type
+    // noexcept expression, or we're just looking for a canonical type.
+    // Otherwise, we're going to need to create a type
     // sugar node to hold the concrete expression.
-    if (EPI.ExceptionSpec.Type != EST_ComputedNoexcept ||
+    if (OnlyWantCanonical || EPI.ExceptionSpec.Type != EST_ComputedNoexcept ||
         EPI.ExceptionSpec.NoexceptExpr == FPT->getNoexceptExpr())
       return Existing;
 
@@ -3212,6 +3213,10 @@ ASTContext::getFunctionType(QualType ResultTy, ArrayRef<QualType> ArgArray,
     if (!ArgArray[i].isCanonicalAsParam())
       isCanonical = false;
 
+  if (OnlyWantCanonical)
+    assert(isCanonical &&
+           "given non-canonical parameters constructing canonical type");
+
   // If this type isn't canonical, get the canonical version of it if we don't
   // already have it. The exception spec is only partially part of the
   // canonical type, and only in C++17 onwards.
@@ -3274,15 +3279,14 @@ ASTContext::getFunctionType(QualType ResultTy, ArrayRef<QualType> ArgArray,
             Value.getBoolValue() ? EST_BasicNoexcept : EST_None;
         break;
       }
-      assert(isCanonicalExceptionSpecification(CanonicalEPI.ExceptionSpec,
-                                               NoexceptInType));
     } else {
       CanonicalEPI.ExceptionSpec = FunctionProtoType::ExceptionSpecInfo();
     }
 
     // Adjust the canonical function result type.
     CanQualType CanResultTy = getCanonicalFunctionResultType(ResultTy);
-    Canonical = getFunctionType(CanResultTy, CanonicalArgs, CanonicalEPI);
+    Canonical =
+        getFunctionTypeInternal(CanResultTy, CanonicalArgs, CanonicalEPI, true);
 
     // Get the new insert position for the node we care about.
     FunctionProtoType *NewIP =
index 711e0bc..7358c7d 100644 (file)
@@ -12,6 +12,10 @@ template<bool A, bool B> void redecl2() noexcept(B); // expected-error {{conflic
 template<typename A, typename B> void redecl3() throw(A);
 template<typename A, typename B> void redecl3() throw(B);
 
+typedef int I;
+template<bool B> void redecl4(I) noexcept(B);
+template<bool B> void redecl4(I) noexcept(B);
+
 namespace DependentDefaultCtorExceptionSpec {
   template<typename> struct T { static const bool value = true; };