Canonicalize UnaryTransformType types when they don't have a known underlying type.

Fixes https://llvm.org/bugs/show_bug.cgi?id=26014

Reviewed by Richard Smith.

llvm-svn: 264937
This commit is contained in:
Vassil Vassilev
2016-03-30 22:18:29 +00:00
parent d8d94652b2
commit bab6f96fff
9 changed files with 117 additions and 18 deletions

View File

@@ -129,6 +129,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
llvm::FoldingSet<PackExpansionType> PackExpansionTypes;
mutable llvm::FoldingSet<ObjCObjectTypeImpl> ObjCObjectTypes;
mutable llvm::FoldingSet<ObjCObjectPointerType> ObjCObjectPointerTypes;
mutable llvm::FoldingSet<DependentUnaryTransformType>
DependentUnaryTransformTypes;
mutable llvm::FoldingSet<AutoType> AutoTypes;
mutable llvm::FoldingSet<AtomicType> AtomicTypes;
llvm::FoldingSet<AttributedType> AttributedTypes;

View File

@@ -3633,6 +3633,28 @@ public:
}
};
/// \brief Internal representation of canonical, dependent
/// __underlying_type(type) types.
///
/// This class is used internally by the ASTContext to manage
/// canonical, dependent types, only. Clients will only see instances
/// of this class via UnaryTransformType nodes.
class DependentUnaryTransformType : public UnaryTransformType,
public llvm::FoldingSetNode {
public:
DependentUnaryTransformType(const ASTContext &C, QualType BaseType,
UTTKind UKind);
void Profile(llvm::FoldingSetNodeID &ID) {
Profile(ID, getBaseType(), getUTTKind());
}
static void Profile(llvm::FoldingSetNodeID &ID, QualType BaseType,
UTTKind UKind) {
ID.AddPointer(BaseType.getAsOpaquePtr());
ID.AddInteger((unsigned)UKind);
}
};
class TagType : public Type {
/// Stores the TagDecl associated with this type. The decl may point to any
/// TagDecl that declares the entity.

View File

@@ -4020,13 +4020,35 @@ QualType ASTContext::getUnaryTransformType(QualType BaseType,
QualType UnderlyingType,
UnaryTransformType::UTTKind Kind)
const {
UnaryTransformType *Ty =
new (*this, TypeAlignment) UnaryTransformType (BaseType, UnderlyingType,
Kind,
UnderlyingType->isDependentType() ?
QualType() : getCanonicalType(UnderlyingType));
Types.push_back(Ty);
return QualType(Ty, 0);
UnaryTransformType *ut = nullptr;
if (BaseType->isDependentType()) {
// Look in the folding set for an existing type.
llvm::FoldingSetNodeID ID;
DependentUnaryTransformType::Profile(ID, getCanonicalType(BaseType), Kind);
void *InsertPos = nullptr;
DependentUnaryTransformType *Canon
= DependentUnaryTransformTypes.FindNodeOrInsertPos(ID, InsertPos);
if (!Canon) {
// Build a new, canonical __underlying_type(type) type.
Canon = new (*this, TypeAlignment)
DependentUnaryTransformType(*this, getCanonicalType(BaseType),
Kind);
DependentUnaryTransformTypes.InsertNode(Canon, InsertPos);
}
ut = new (*this, TypeAlignment) UnaryTransformType (BaseType,
QualType(), Kind,
QualType(Canon, 0));
} else {
QualType CanonType = getCanonicalType(UnderlyingType);
ut = new (*this, TypeAlignment) UnaryTransformType (BaseType,
UnderlyingType, Kind,
CanonType);
}
Types.push_back(ut);
return QualType(ut, 0);
}
/// getAutoType - Return the uniqued reference to the 'auto' type which has been

View File

@@ -2935,6 +2935,24 @@ void DependentDecltypeType::Profile(llvm::FoldingSetNodeID &ID,
E->Profile(ID, Context, true);
}
UnaryTransformType::UnaryTransformType(QualType BaseType,
QualType UnderlyingType,
UTTKind UKind,
QualType CanonicalType)
: Type(UnaryTransform, CanonicalType, BaseType->isDependentType(),
BaseType->isInstantiationDependentType(),
BaseType->isVariablyModifiedType(),
BaseType->containsUnexpandedParameterPack())
, BaseType(BaseType), UnderlyingType(UnderlyingType), UKind(UKind)
{}
DependentUnaryTransformType::DependentUnaryTransformType(const ASTContext &C,
QualType BaseType,
UTTKind UKind)
: UnaryTransformType(BaseType, C.DependentTy, UKind, QualType())
{}
TagType::TagType(TypeClass TC, const TagDecl *D, QualType can)
: Type(TC, can, D->isDependentType(),
/*InstantiationDependent=*/D->isDependentType(),
@@ -2951,17 +2969,6 @@ static TagDecl *getInterestingTagDecl(TagDecl *decl) {
return decl;
}
UnaryTransformType::UnaryTransformType(QualType BaseType,
QualType UnderlyingType,
UTTKind UKind,
QualType CanonicalType)
: Type(UnaryTransform, CanonicalType, UnderlyingType->isDependentType(),
UnderlyingType->isInstantiationDependentType(),
UnderlyingType->isVariablyModifiedType(),
BaseType->containsUnexpandedParameterPack())
, BaseType(BaseType), UnderlyingType(UnderlyingType), UKind(UKind)
{}
TagDecl *TagType::getDecl() const {
return getInterestingTagDecl(decl);
}

View File

@@ -0,0 +1,13 @@
#ifndef _LIBCPP_TYPE_TRAITS
#define _LIBCPP_TYPE_TRAITS
template <class _Tp>
struct underlying_type
{
typedef __underlying_type(_Tp) type;
};
#endif // _LIBCPP_TYPE_TRAITS
#include "B.h"

View File

@@ -0,0 +1,10 @@
#ifndef _LIBCPP_TYPE_TRAITS
#define _LIBCPP_TYPE_TRAITS
template <class _Tp>
struct underlying_type
{
typedef __underlying_type(_Tp) type;
};
#endif // _LIBCPP_TYPE_TRAITS

View File

@@ -0,0 +1,9 @@
module A {
header "A.h"
export *
}
module B {
header "B.h"
export *
}

View File

@@ -0,0 +1,7 @@
// RUN: rm -rf %t
// RUN: %clang_cc1 -I%S/Inputs/PR26014 -verify %s
// RUN: %clang_cc1 -fmodules -fmodule-map-file=%S/Inputs/PR26014/module.modulemap -fmodules-cache-path=%t -I%S/Inputs/PR26014 -verify %s
#include "A.h"
// expected-no-diagnostics

View File

@@ -55,3 +55,10 @@ namespace PR19966 {
// expected-error@-2 {{constant expression}}
};
}
template<typename T> void f(__underlying_type(T));
template<typename T> void f(__underlying_type(T));
enum E {};
void PR26014() { f<E>(0); } // should not yield an ambiguity error.
template<typename ...T> void f(__underlying_type(T) v); // expected-error {{declaration type contains unexpanded parameter pack 'T'}}