TemplateSpecializationTypes;
mutable llvm::FoldingSet<ParenType> ParenTypes{GeneralTypesLog2InitSize};
mutable llvm::FoldingSet<UsingType> UsingTypes;
+ mutable llvm::FoldingSet<TypedefType> TypedefTypes;
mutable llvm::FoldingSet<ElaboratedType> ElaboratedTypes{
GeneralTypesLog2InitSize};
mutable llvm::FoldingSet<DependentNameType> DependentNameTypes;
void Visit(const APValue &Value, QualType Ty);
void VisitTypedefType(const TypedefType *TT);
+ void VisitUsingType(const UsingType *TT);
void VisitFunctionType(const FunctionType *T);
void VisitFunctionProtoType(const FunctionProtoType *T);
void VisitRValueReferenceType(const ReferenceType *RT);
unsigned IsUnqual : 1; // If true: typeof_unqual, else: typeof
};
+ class UsingBitfields {
+ friend class UsingType;
+
+ unsigned : NumTypeBits;
+
+ /// True if the underlying type is different from the declared one.
+ unsigned hasTypeDifferentFromDecl : 1;
+ };
+
+ class TypedefBitfields {
+ friend class TypedefType;
+
+ unsigned : NumTypeBits;
+
+ /// True if the underlying type is different from the declared one.
+ unsigned hasTypeDifferentFromDecl : 1;
+ };
+
class SubstTemplateTypeParmTypeBitfields {
friend class SubstTemplateTypeParmType;
AttributedTypeBitfields AttributedTypeBits;
AutoTypeBitfields AutoTypeBits;
TypeOfBitfields TypeOfBits;
+ TypedefBitfields TypedefBits;
+ UsingBitfields UsingBits;
BuiltinTypeBitfields BuiltinTypeBits;
FunctionTypeBitfields FunctionTypeBits;
ObjCObjectTypeBitfields ObjCObjectTypeBits;
}
};
-class UsingType : public Type, public llvm::FoldingSetNode {
+class UsingType final : public Type,
+ public llvm::FoldingSetNode,
+ private llvm::TrailingObjects<UsingType, QualType> {
UsingShadowDecl *Found;
friend class ASTContext; // ASTContext creates these.
+ friend TrailingObjects;
UsingType(const UsingShadowDecl *Found, QualType Underlying, QualType Canon);
QualType getUnderlyingType() const;
bool isSugared() const { return true; }
+
+ // This always has the 'same' type as declared, but not necessarily identical.
QualType desugar() const { return getUnderlyingType(); }
- void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, Found); }
- static void Profile(llvm::FoldingSetNodeID &ID,
- const UsingShadowDecl *Found) {
+ // Internal helper, for debugging purposes.
+ bool typeMatchesDecl() const { return !UsingBits.hasTypeDifferentFromDecl; }
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, Found, typeMatchesDecl() ? QualType() : getUnderlyingType());
+ }
+ static void Profile(llvm::FoldingSetNodeID &ID, const UsingShadowDecl *Found,
+ QualType Underlying) {
ID.AddPointer(Found);
+ if (!Underlying.isNull())
+ Underlying.Profile(ID);
}
static bool classof(const Type *T) { return T->getTypeClass() == Using; }
};
-class TypedefType : public Type {
+class TypedefType final : public Type,
+ public llvm::FoldingSetNode,
+ private llvm::TrailingObjects<TypedefType, QualType> {
TypedefNameDecl *Decl;
-
-private:
friend class ASTContext; // ASTContext creates these.
+ friend TrailingObjects;
TypedefType(TypeClass tc, const TypedefNameDecl *D, QualType underlying,
QualType can);
TypedefNameDecl *getDecl() const { return Decl; }
bool isSugared() const { return true; }
+
+ // This always has the 'same' type as declared, but not necessarily identical.
QualType desugar() const;
+ // Internal helper, for debugging purposes.
+ bool typeMatchesDecl() const { return !TypedefBits.hasTypeDifferentFromDecl; }
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, Decl, typeMatchesDecl() ? QualType() : desugar());
+ }
+ static void Profile(llvm::FoldingSetNodeID &ID, const TypedefNameDecl *Decl,
+ QualType Underlying) {
+ ID.AddPointer(Decl);
+ if (!Underlying.isNull())
+ Underlying.Profile(ID);
+ }
+
static bool classof(const Type *T) { return T->getTypeClass() == Typedef; }
};
def : Property<"declaration", DeclRef> {
let Read = [{ node->getDecl() }];
}
- def : Property<"canonicalType", Optional<QualType>> {
- let Read = [{ makeOptionalFromNullable(node->getCanonicalTypeInternal()) }];
+ def : Property<"underlyingType", QualType> {
+ let Read = [{ node->desugar() }];
}
def : Creator<[{
- QualType finalCanonicalType =
- canonicalType ? ctx.getCanonicalType(*canonicalType)
- : QualType();
- return ctx.getTypedefType(cast<TypedefNameDecl>(declaration),
- finalCanonicalType);
+ return ctx.getTypedefType(cast<TypedefNameDecl>(declaration), underlyingType);
}]>;
}
return getTypeInfo(cast<UsingType>(T)->desugar().getTypePtr());
case Type::Typedef: {
- const TypedefNameDecl *Typedef = cast<TypedefType>(T)->getDecl();
- TypeInfo Info = getTypeInfo(Typedef->getUnderlyingType().getTypePtr());
+ const auto *TT = cast<TypedefType>(T);
+ TypeInfo Info = getTypeInfo(TT->desugar().getTypePtr());
// If the typedef has an aligned attribute on it, it overrides any computed
// alignment we have. This violates the GCC documentation (which says that
// attribute(aligned) can only round up) but matches its implementation.
- if (unsigned AttrAlign = Typedef->getMaxAlignment()) {
+ if (unsigned AttrAlign = TT->getDecl()->getMaxAlignment()) {
Align = AttrAlign;
AlignRequirement = AlignRequirementKind::RequiredByTypedef;
} else {
/// specified typedef name decl.
QualType ASTContext::getTypedefType(const TypedefNameDecl *Decl,
QualType Underlying) const {
- if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0);
+ if (!Decl->TypeForDecl) {
+ if (Underlying.isNull())
+ Underlying = Decl->getUnderlyingType();
+ auto *NewType = new (*this, TypeAlignment) TypedefType(
+ Type::Typedef, Decl, QualType(), getCanonicalType(Underlying));
+ Decl->TypeForDecl = NewType;
+ Types.push_back(NewType);
+ return QualType(NewType, 0);
+ }
+ if (Underlying.isNull() || Decl->getUnderlyingType() == Underlying)
+ return QualType(Decl->TypeForDecl, 0);
+ assert(hasSameType(Decl->getUnderlyingType(), Underlying));
- if (Underlying.isNull())
- Underlying = Decl->getUnderlyingType();
- QualType Canonical = getCanonicalType(Underlying);
- auto *newType = new (*this, TypeAlignment)
- TypedefType(Type::Typedef, Decl, Underlying, Canonical);
- Decl->TypeForDecl = newType;
- Types.push_back(newType);
- return QualType(newType, 0);
+ llvm::FoldingSetNodeID ID;
+ TypedefType::Profile(ID, Decl, Underlying);
+
+ void *InsertPos = nullptr;
+ if (TypedefType *T = TypedefTypes.FindNodeOrInsertPos(ID, InsertPos)) {
+ assert(!T->typeMatchesDecl() &&
+ "non-divergent case should be handled with TypeDecl");
+ return QualType(T, 0);
+ }
+
+ void *Mem =
+ Allocate(TypedefType::totalSizeToAlloc<QualType>(true), TypeAlignment);
+ auto *NewType = new (Mem) TypedefType(Type::Typedef, Decl, Underlying,
+ getCanonicalType(Underlying));
+ TypedefTypes.InsertNode(NewType, InsertPos);
+ Types.push_back(NewType);
+ return QualType(NewType, 0);
}
QualType ASTContext::getUsingType(const UsingShadowDecl *Found,
QualType Underlying) const {
llvm::FoldingSetNodeID ID;
- UsingType::Profile(ID, Found);
+ UsingType::Profile(ID, Found, Underlying);
void *InsertPos = nullptr;
- UsingType *T = UsingTypes.FindNodeOrInsertPos(ID, InsertPos);
- if (T)
+ if (UsingType *T = UsingTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(T, 0);
- assert(!Underlying.hasLocalQualifiers());
- assert(Underlying == getTypeDeclType(cast<TypeDecl>(Found->getTargetDecl())));
- QualType Canon = Underlying.getCanonicalType();
+ const Type *TypeForDecl =
+ cast<TypeDecl>(Found->getTargetDecl())->getTypeForDecl();
- UsingType *NewType =
- new (*this, TypeAlignment) UsingType(Found, Underlying, Canon);
+ assert(!Underlying.hasLocalQualifiers());
+ QualType Canon = Underlying->getCanonicalTypeInternal();
+ assert(TypeForDecl->getCanonicalTypeInternal() == Canon);
+
+ if (Underlying.getTypePtr() == TypeForDecl)
+ Underlying = QualType();
+ void *Mem =
+ Allocate(UsingType::totalSizeToAlloc<QualType>(!Underlying.isNull()),
+ TypeAlignment);
+ UsingType *NewType = new (Mem) UsingType(Found, Underlying, Canon);
Types.push_back(NewType);
UsingTypes.InsertNode(NewType, InsertPos);
return QualType(NewType, 0);
Expected<TypedefNameDecl *> ToDeclOrErr = import(T->getDecl());
if (!ToDeclOrErr)
return ToDeclOrErr.takeError();
+ ExpectedType ToUnderlyingTypeOrErr = import(T->desugar());
+ if (!ToUnderlyingTypeOrErr)
+ return ToUnderlyingTypeOrErr.takeError();
- return Importer.getToContext().getTypeDeclType(*ToDeclOrErr);
+ return Importer.getToContext().getTypedefType(*ToDeclOrErr,
+ *ToUnderlyingTypeOrErr);
}
ExpectedType ASTNodeImporter::VisitTypeOfExprType(const TypeOfExprType *T) {
if (!IsStructurallyEquivalent(Context, cast<UsingType>(T1)->getFoundDecl(),
cast<UsingType>(T2)->getFoundDecl()))
return false;
+ if (!IsStructurallyEquivalent(Context,
+ cast<UsingType>(T1)->getUnderlyingType(),
+ cast<UsingType>(T2)->getUnderlyingType()))
+ return false;
break;
case Type::Typedef:
if (!IsStructurallyEquivalent(Context, cast<TypedefType>(T1)->getDecl(),
- cast<TypedefType>(T2)->getDecl()))
+ cast<TypedefType>(T2)->getDecl()) ||
+ !IsStructurallyEquivalent(Context, cast<TypedefType>(T1)->desugar(),
+ cast<TypedefType>(T2)->desugar()))
return false;
break;
void JSONNodeDumper::VisitTypedefType(const TypedefType *TT) {
JOS.attribute("decl", createBareDeclRef(TT->getDecl()));
+ if (!TT->typeMatchesDecl())
+ JOS.attribute("type", createQualType(TT->desugar()));
+}
+
+void JSONNodeDumper::VisitUsingType(const UsingType *TT) {
+ JOS.attribute("decl", createBareDeclRef(TT->getFoundDecl()));
+ if (!TT->typeMatchesDecl())
+ JOS.attribute("type", createQualType(TT->desugar()));
}
void JSONNodeDumper::VisitFunctionType(const FunctionType *T) {
void TextNodeDumper::VisitUsingType(const UsingType *T) {
dumpDeclRef(T->getFoundDecl());
+ if (!T->typeMatchesDecl())
+ OS << " divergent";
}
void TextNodeDumper::VisitTypedefType(const TypedefType *T) {
dumpDeclRef(T->getDecl());
+ if (!T->typeMatchesDecl())
+ OS << " divergent";
}
void TextNodeDumper::VisitUnaryTransformType(const UnaryTransformType *T) {
}
TypedefType::TypedefType(TypeClass tc, const TypedefNameDecl *D,
- QualType underlying, QualType can)
- : Type(tc, can, toSemanticDependence(underlying->getDependence())),
+ QualType Underlying, QualType can)
+ : Type(tc, can, toSemanticDependence(can->getDependence())),
Decl(const_cast<TypedefNameDecl *>(D)) {
assert(!isa<TypedefType>(can) && "Invalid canonical type");
+ TypedefBits.hasTypeDifferentFromDecl = !Underlying.isNull();
+ if (!typeMatchesDecl())
+ *getTrailingObjects<QualType>() = Underlying;
}
QualType TypedefType::desugar() const {
- return getDecl()->getUnderlyingType();
+ return typeMatchesDecl() ? Decl->getUnderlyingType()
+ : *getTrailingObjects<QualType>();
}
UsingType::UsingType(const UsingShadowDecl *Found, QualType Underlying,
QualType Canon)
- : Type(Using, Canon, toSemanticDependence(Underlying->getDependence())),
+ : Type(Using, Canon, toSemanticDependence(Canon->getDependence())),
Found(const_cast<UsingShadowDecl *>(Found)) {
- assert(Underlying == getUnderlyingType());
+ UsingBits.hasTypeDifferentFromDecl = !Underlying.isNull();
+ if (!typeMatchesDecl())
+ *getTrailingObjects<QualType>() = Underlying;
}
QualType UsingType::getUnderlyingType() const {
- return QualType(cast<TypeDecl>(Found->getTargetDecl())->getTypeForDecl(), 0);
+ return typeMatchesDecl()
+ ? QualType(
+ cast<TypeDecl>(Found->getTargetDecl())->getTypeForDecl(), 0)
+ : *getTrailingObjects<QualType>();
}
QualType MacroQualifiedType::desugar() const { return getUnderlyingType(); }
C2<X2> auto t26_3 = (::SB1){};
N t26 = 0 ? t26_1 : t26_2; // expected-error {{from 'SB1' (aka 'SS1')}}
N t27 = 0 ? t26_1 : t26_3; // expected-error {{from 'SB1' (aka 'SS1')}}
+
+using RPB1 = X1*;
+using RPX1 = RPB1;
+using RPB1 = Y1*; // redeclared
+using RPY1 = RPB1;
+N t28 = *(RPB1){}; // expected-error {{lvalue of type 'Y1' (aka 'int')}}
+auto t29 = 0 ? (RPX1){} : (RPY1){};
+N t30 = t29; // expected-error {{lvalue of type 'RPB1' (aka 'int *')}}
+N t31 = *t29; // expected-error {{lvalue of type 'B1' (aka 'int')}}
+
+namespace A { using type1 = X1*; };
+namespace C { using A::type1; };
+using UPX1 = C::type1;
+namespace A { using type1 = Y1*; }; // redeclared
+namespace C { using A::type1; }; // redeclared
+using UPY1 = C::type1;
+auto t32 = 0 ? (UPX1){} : (UPY1){};
+N t33 = t32; // expected-error {{lvalue of type 'C::type1' (aka 'int *')}}
+N t34 = *t32; // expected-error {{lvalue of type 'B1' (aka 'int')}}