[c++1z] Fix corner case where we could create a function type whose canonical type is not actually canonical.

llvm-svn: 284528
This commit is contained in:
Richard Smith 2016-10-18 20:13:25 +00:00
parent 6e9043009e
commit 304b124a11
3 changed files with 26 additions and 9 deletions

View 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,

View 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 =

View 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; };