From 99677afd54fba7deb6a5c8c2de52d46cbb344316 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Tue, 18 Oct 2016 06:47:03 +0000 Subject: [PATCH] [c++1z] Use canonical expression equivalence to determine whether two different dependent noexcept specifications result in the same canonical function type. We still use non-canonical hashing when deduplicating type sugar so that diagnostics will point to the right place. llvm-svn: 284457 --- clang/include/clang/AST/Type.h | 3 ++- clang/lib/AST/ASTContext.cpp | 22 +++++++++++----------- clang/lib/AST/Type.cpp | 6 +++--- .../test/SemaCXX/cxx1z-noexcept-function-type.cpp | 13 +++++++++++++ 4 files changed, 29 insertions(+), 15 deletions(-) create mode 100644 clang/test/SemaCXX/cxx1z-noexcept-function-type.cpp diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index e9351a9..691a7dc 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -3473,7 +3473,8 @@ public: void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx); static void Profile(llvm::FoldingSetNodeID &ID, QualType Result, param_type_iterator ArgTys, unsigned NumArgs, - const ExtProtoInfo &EPI, const ASTContext &Context); + const ExtProtoInfo &EPI, const ASTContext &Context, + bool Canonical); }; /// \brief Represents the dependent type named by a dependently-scoped diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 3da1c74..d2f01c0 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -3170,17 +3170,6 @@ ASTContext::getFunctionType(QualType ResultTy, ArrayRef ArgArray, const FunctionProtoType::ExtProtoInfo &EPI) const { size_t NumArgs = ArgArray.size(); - // Unique functions, to guarantee there is only one function of a particular - // structure. - llvm::FoldingSetNodeID ID; - FunctionProtoType::Profile(ID, ResultTy, ArgArray.begin(), NumArgs, EPI, - *this); - - void *InsertPos = nullptr; - if (FunctionProtoType *FTP = - FunctionProtoTypes.FindNodeOrInsertPos(ID, InsertPos)) - return QualType(FTP, 0); - bool NoexceptInType = getLangOpts().CPlusPlus1z; bool IsCanonicalExceptionSpec = @@ -3193,6 +3182,17 @@ ASTContext::getFunctionType(QualType ResultTy, ArrayRef ArgArray, if (!ArgArray[i].isCanonicalAsParam()) isCanonical = false; + // Unique functions, to guarantee there is only one function of a particular + // structure. + llvm::FoldingSetNodeID ID; + FunctionProtoType::Profile(ID, ResultTy, ArgArray.begin(), NumArgs, EPI, + *this, isCanonical); + + void *InsertPos = nullptr; + if (FunctionProtoType *FTP = + FunctionProtoTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(FTP, 0); + // If this type isn't canonical, get the canonical version of it. // The exception spec is not part of the canonical type. QualType Canonical; diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 2601fa4..3e776e3 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -2850,7 +2850,7 @@ bool FunctionProtoType::isTemplateVariadic() const { void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result, const QualType *ArgTys, unsigned NumParams, const ExtProtoInfo &epi, - const ASTContext &Context) { + const ASTContext &Context, bool Canonical) { // We have to be careful not to get ambiguous profile encodings. // Note that valid type pointers are never ambiguous with anything else. @@ -2889,7 +2889,7 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result, ID.AddPointer(Ex.getAsOpaquePtr()); } else if (epi.ExceptionSpec.Type == EST_ComputedNoexcept && epi.ExceptionSpec.NoexceptExpr) { - epi.ExceptionSpec.NoexceptExpr->Profile(ID, Context, false); + epi.ExceptionSpec.NoexceptExpr->Profile(ID, Context, Canonical); } else if (epi.ExceptionSpec.Type == EST_Uninstantiated || epi.ExceptionSpec.Type == EST_Unevaluated) { ID.AddPointer(epi.ExceptionSpec.SourceDecl->getCanonicalDecl()); @@ -2905,7 +2905,7 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result, void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx) { Profile(ID, getReturnType(), param_type_begin(), NumParams, getExtProtoInfo(), - Ctx); + Ctx, isCanonicalUnqualified()); } QualType TypedefType::desugar() const { diff --git a/clang/test/SemaCXX/cxx1z-noexcept-function-type.cpp b/clang/test/SemaCXX/cxx1z-noexcept-function-type.cpp new file mode 100644 index 0000000..e2a947e --- /dev/null +++ b/clang/test/SemaCXX/cxx1z-noexcept-function-type.cpp @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -std=c++1z -verify %s + +template void redecl1() noexcept(noexcept(T())) {} // expected-note {{previous}} +template void redecl1() noexcept(noexcept(T())); // ok, same type +template void redecl1() noexcept(noexcept(T())) {} // expected-error {{redefinition}} + +template void redecl2() noexcept(A); // expected-note {{previous}} +template void redecl2() noexcept(B); // expected-error {{conflicting types}} + +// These have the same canonical type. +// FIXME: It's not clear whether this is supposed to be valid. +template void redecl3() throw(A); +template void redecl3() throw(B); -- 2.7.4