Introduce an AttributedType, but don't actually use it anywhere yet.

The initial TreeTransform is a cop-out, but it's more-or-less equivalent
to what we were doing before, or rather what we're doing now and might
eventually stop doing in favor of using this type.
I am simultaneously intrigued by the possibilities of rebuilding a
dependent Attri

llvm-svn: 122942
This commit is contained in:
John McCall 2011-01-06 01:58:22 +00:00
parent 4072e59189
commit 8190451ddc
14 changed files with 439 additions and 3 deletions

View File

@ -109,6 +109,7 @@ class ASTContext {
llvm::FoldingSet<PackExpansionType> PackExpansionTypes;
llvm::FoldingSet<ObjCObjectTypeImpl> ObjCObjectTypes;
llvm::FoldingSet<ObjCObjectPointerType> ObjCObjectPointerTypes;
llvm::FoldingSet<AttributedType> AttributedTypes;
llvm::FoldingSet<QualifiedTemplateName> QualifiedTemplateNames;
llvm::FoldingSet<DependentTemplateName> DependentTemplateNames;
@ -648,6 +649,10 @@ public:
QualType getInjectedClassNameType(CXXRecordDecl *Decl, QualType TST);
QualType getAttributedType(AttributedType::Kind attrKind,
QualType modifiedType,
QualType equivalentType);
QualType getSubstTemplateTypeParmType(const TemplateTypeParmType *Replaced,
QualType Replacement);

View File

@ -726,6 +726,10 @@ DEF_TRAVERSE_TYPE(TemplateSpecializationType, {
DEF_TRAVERSE_TYPE(InjectedClassNameType, { })
DEF_TRAVERSE_TYPE(AttributedType, {
TRY_TO(TraverseType(T->getModifiedType()));
})
DEF_TRAVERSE_TYPE(ParenType, {
TRY_TO(TraverseType(T->getInnerType()));
})
@ -936,6 +940,10 @@ DEF_TRAVERSE_TYPELOC(ParenType, {
TRY_TO(TraverseTypeLoc(TL.getInnerLoc()));
})
DEF_TRAVERSE_TYPELOC(AttributedType, {
TRY_TO(TraverseTypeLoc(TL.getModifiedLoc()));
})
// FIXME: use the sourceloc on qualifier?
DEF_TRAVERSE_TYPELOC(ElaboratedType, {
if (TL.getTypePtr()->getQualifier()) {

View File

@ -993,9 +993,19 @@ protected:
unsigned NumElements : 29 - NumTypeBits;
};
class AttributedTypeBitfields {
friend class AttributedType;
unsigned : NumTypeBits;
/// AttrKind - an AttributedType::Kind
unsigned AttrKind : 32 - NumTypeBits;
};
union {
TypeBitfields TypeBits;
ArrayTypeBitfields ArrayTypeBits;
AttributedTypeBitfields AttributedTypeBits;
BuiltinTypeBitfields BuiltinTypeBits;
FunctionTypeBitfields FunctionTypeBits;
ObjCObjectTypeBitfields ObjCObjectTypeBits;
@ -2657,6 +2667,91 @@ public:
static bool classof(const EnumType *) { return true; }
};
/// AttributedType - An attributed type is a type to which a type
/// attribute has been applied. The "modified type" is the
/// fully-sugared type to which the attributed type was applied;
/// generally it is not canonically equivalent to the attributed type.
/// The "equivalent type" is the minimally-desugared type which the
/// type is canonically equivalent to.
///
/// For example, in the following attributed type:
/// int32_t __attribute__((vector_size(16)))
/// - the modified type is the TypedefType for int32_t
/// - the equivalent type is VectorType(16, int32_t)
/// - the canonical type is VectorType(16, int)
class AttributedType : public Type, public llvm::FoldingSetNode {
public:
// It is really silly to have yet another attribute-kind enum, but
// clang::attr::Kind doesn't currently cover the pure type attrs.
enum Kind {
// Expression operand.
address_space,
regparm,
vector_size,
neon_vector_type,
neon_polyvector_type,
FirstExprOperandKind = address_space,
LastExprOperandKind = neon_polyvector_type,
// Enumerated operand (string or keyword).
objc_gc,
FirstEnumOperandKind = objc_gc,
LastEnumOperandKind = objc_gc,
// No operand.
noreturn,
cdecl,
fastcall,
stdcall,
thiscall,
pascal
};
private:
QualType ModifiedType;
QualType EquivalentType;
friend class ASTContext; // creates these
AttributedType(QualType canon, Kind attrKind,
QualType modified, QualType equivalent)
: Type(Attributed, canon, canon->isDependentType(),
canon->isVariablyModifiedType(),
canon->containsUnexpandedParameterPack()),
ModifiedType(modified), EquivalentType(equivalent) {
AttributedTypeBits.AttrKind = attrKind;
}
public:
Kind getAttrKind() const {
return static_cast<Kind>(AttributedTypeBits.AttrKind);
}
QualType getModifiedType() const { return ModifiedType; }
QualType getEquivalentType() const { return EquivalentType; }
bool isSugared() const { return true; }
QualType desugar() const { return getEquivalentType(); }
void Profile(llvm::FoldingSetNodeID &ID) {
Profile(ID, getAttrKind(), ModifiedType, EquivalentType);
}
static void Profile(llvm::FoldingSetNodeID &ID, Kind attrKind,
QualType modified, QualType equivalent) {
ID.AddInteger(attrKind);
ID.AddPointer(modified.getAsOpaquePtr());
ID.AddPointer(equivalent.getAsOpaquePtr());
}
static bool classof(const Type *T) {
return T->getTypeClass() == Attributed;
}
static bool classof(const AttributedType *T) { return true; }
};
class TemplateTypeParmType : public Type, public llvm::FoldingSetNode {
unsigned Depth : 15;
unsigned ParameterPack : 1;

View File

@ -592,6 +592,130 @@ class SubstTemplateTypeParmTypeLoc :
SubstTemplateTypeParmType> {
};
struct AttributedLocInfo {
union {
Expr *ExprOperand;
/// A raw SourceLocation.
unsigned EnumOperandLoc;
};
SourceRange OperandParens;
SourceLocation AttrLoc;
};
/// \brief Type source information for an attributed type.
class AttributedTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
AttributedTypeLoc,
AttributedType,
AttributedLocInfo> {
public:
AttributedType::Kind getAttrKind() const {
return getTypePtr()->getAttrKind();
}
bool hasAttrExprOperand() const {
return (getAttrKind() >= AttributedType::FirstExprOperandKind &&
getAttrKind() <= AttributedType::LastExprOperandKind);
}
bool hasAttrEnumOperand() const {
return (getAttrKind() >= AttributedType::FirstEnumOperandKind &&
getAttrKind() <= AttributedType::LastEnumOperandKind);
}
bool hasAttrOperand() const {
return hasAttrExprOperand() || hasAttrEnumOperand();
}
/// The modified type, which is generally canonically different from
/// the attribute type.
/// int main(int, char**) __attribute__((noreturn))
/// ~~~ ~~~~~~~~~~~~~
TypeLoc getModifiedLoc() const {
return getInnerTypeLoc();
}
/// The location of the attribute name, i.e.
/// __attribute__((regparm(1000)))
/// ^~~~~~~
SourceLocation getAttrNameLoc() const {
return getLocalData()->AttrLoc;
}
void setAttrNameLoc(SourceLocation loc) {
getLocalData()->AttrLoc = loc;
}
/// The attribute's expression operand, if it has one.
/// void *cur_thread __attribute__((address_space(21)))
/// ^~
Expr *getAttrExprOperand() const {
assert(hasAttrExprOperand());
return getLocalData()->ExprOperand;
}
void setAttrExprOperand(Expr *e) {
assert(hasAttrExprOperand());
getLocalData()->ExprOperand = e;
}
/// The location of the attribute's enumerated operand, if it has one.
/// void * __attribute__((objc_gc(weak)))
/// ^~~~
SourceLocation getAttrEnumOperandLoc() const {
assert(hasAttrEnumOperand());
return SourceLocation::getFromRawEncoding(getLocalData()->EnumOperandLoc);
}
void setAttrEnumOperandLoc(SourceLocation loc) {
assert(hasAttrEnumOperand());
getLocalData()->EnumOperandLoc = loc.getRawEncoding();
}
/// The location of the parentheses around the operand, if there is
/// an operand.
/// void * __attribute__((objc_gc(weak)))
/// ^ ^
SourceRange getAttrOperandParensRange() const {
assert(hasAttrOperand());
return getLocalData()->OperandParens;
}
void setAttrOperandParensRange(SourceRange range) {
assert(hasAttrOperand());
getLocalData()->OperandParens = range;
}
SourceRange getLocalSourceRange() const {
// Note that this does *not* include the range of the attribute
// enclosure, e.g.:
// __attribute__((foo(bar)))
// ^~~~~~~~~~~~~~~ ~~
// or
// [[foo(bar)]]
// ^~ ~~
// That enclosure doesn't necessarily belong to a single attribute
// anyway.
SourceRange range(getAttrNameLoc());
if (hasAttrOperand())
range.setEnd(getAttrOperandParensRange().getEnd());
return range;
}
void initializeLocal(SourceLocation loc) {
setAttrNameLoc(loc);
if (hasAttrExprOperand()) {
setAttrOperandParensRange(SourceRange(loc));
setAttrExprOperand(0);
} else if (hasAttrEnumOperand()) {
setAttrOperandParensRange(SourceRange(loc));
setAttrEnumOperandLoc(loc);
}
}
QualType getInnerType() const {
return getTypePtr()->getModifiedType();
}
};
struct ObjCProtocolListLocInfo {
SourceLocation LAngleLoc;

View File

@ -88,6 +88,7 @@ ABSTRACT_TYPE(Tag, Type)
TYPE(Record, TagType)
TYPE(Enum, TagType)
NON_CANONICAL_TYPE(Elaborated, Type)
NON_CANONICAL_TYPE(Attributed, Type)
DEPENDENT_TYPE(TemplateTypeParm, Type)
NON_CANONICAL_TYPE(SubstTemplateTypeParm, Type)
NON_CANONICAL_UNLESS_DEPENDENT_TYPE(TemplateSpecialization, Type)

View File

@ -553,7 +553,9 @@ namespace clang {
/// \brief A ParenType record.
TYPE_PAREN = 34,
/// \brief A PackExpansionType record.
TYPE_PACK_EXPANSION = 35
TYPE_PACK_EXPANSION = 35,
/// \brief An AttributedType record.
TYPE_ATTRIBUTED = 36
};
/// \brief The type IDs for special types constructed by semantic

View File

@ -844,6 +844,10 @@ ASTContext::getTypeInfo(const Type *T) {
case Type::Elaborated:
return getTypeInfo(cast<ElaboratedType>(T)->getNamedType().getTypePtr());
case Type::Attributed:
return getTypeInfo(
cast<AttributedType>(T)->getEquivalentType().getTypePtr());
case Type::TemplateSpecialization:
assert(getCanonicalType(T) != T &&
"Cannot request the size of a dependent type");
@ -1875,6 +1879,27 @@ QualType ASTContext::getEnumType(const EnumDecl *Decl) {
return QualType(Decl->TypeForDecl, 0);
}
QualType ASTContext::getAttributedType(AttributedType::Kind attrKind,
QualType modifiedType,
QualType equivalentType) {
llvm::FoldingSetNodeID id;
AttributedType::Profile(id, attrKind, modifiedType, equivalentType);
void *insertPos = 0;
AttributedType *type = AttributedTypes.FindNodeOrInsertPos(id, insertPos);
if (type) return QualType(type, 0);
QualType canon = getCanonicalType(equivalentType);
type = new (*this, TypeAlignment)
AttributedType(canon, attrKind, modifiedType, equivalentType);
Types.push_back(type);
AttributedTypes.InsertNode(type, insertPos);
return QualType(type, 0);
}
/// \brief Retrieve a substitution-result type.
QualType
ASTContext::getSubstTemplateTypeParmType(const TemplateTypeParmType *Parm,

View File

@ -557,6 +557,17 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
return false;
break;
case Type::Attributed:
if (!IsStructurallyEquivalent(Context,
cast<AttributedType>(T1)->getModifiedType(),
cast<AttributedType>(T2)->getModifiedType()))
return false;
if (!IsStructurallyEquivalent(Context,
cast<AttributedType>(T1)->getEquivalentType(),
cast<AttributedType>(T2)->getEquivalentType()))
return false;
break;
case Type::Paren:
if (!IsStructurallyEquivalent(Context,

View File

@ -229,4 +229,3 @@ TypeLoc TypeLoc::IgnoreParensImpl(TypeLoc TL) {
TL = PTL->getInnerLoc();
return TL;
}

View File

@ -674,6 +674,84 @@ void TypePrinter::printPackExpansion(const PackExpansionType *T,
S += "...";
}
void TypePrinter::printAttributed(const AttributedType *T,
std::string &S) {
print(T->getModifiedType(), S);
// TODO: not all attributes are GCC-style attributes.
S += "__attribute__((";
switch (T->getAttrKind()) {
case AttributedType::address_space:
S += "address_space(";
S += T->getEquivalentType().getAddressSpace();
S += ")";
break;
case AttributedType::vector_size: {
S += "__vector_size__(";
if (const VectorType *vector =T->getEquivalentType()->getAs<VectorType>()) {
S += vector->getNumElements();
S += " * sizeof(";
std::string tmp;
print(vector->getElementType(), tmp);
S += tmp;
S += ")";
}
S += ")";
break;
}
case AttributedType::neon_vector_type:
case AttributedType::neon_polyvector_type: {
if (T->getAttrKind() == AttributedType::neon_vector_type)
S += "neon_vector_type(";
else
S += "neon_polyvector_type(";
const VectorType *vector = T->getEquivalentType()->getAs<VectorType>();
S += llvm::utostr_32(vector->getNumElements());
S += ")";
break;
}
case AttributedType::regparm: {
S += "regparm(";
QualType t = T->getEquivalentType();
while (!t->isFunctionType())
t = t->getPointeeType();
S += t->getAs<FunctionType>()->getRegParmType();
S += ")";
break;
}
case AttributedType::objc_gc: {
S += "objc_gc(";
QualType tmp = T->getEquivalentType();
while (tmp.getObjCGCAttr() == Qualifiers::GCNone) {
QualType next = tmp->getPointeeType();
if (next == tmp) break;
tmp = next;
}
if (tmp.isObjCGCWeak())
S += "weak";
else
S += "strong";
S += ")";
break;
}
case AttributedType::noreturn: S += "noreturn"; break;
case AttributedType::cdecl: S += "cdecl"; break;
case AttributedType::fastcall: S += "fastcall"; break;
case AttributedType::stdcall: S += "stdcall"; break;
case AttributedType::thiscall: S += "thiscall"; break;
case AttributedType::pascal: S += "pascal"; break;
}
S += "))";
}
void TypePrinter::printObjCInterface(const ObjCInterfaceType *T,
std::string &S) {
if (!S.empty()) // Prefix the basic type, e.g. 'typedefname X'.

View File

@ -1324,6 +1324,8 @@ static QualType UnwrapTypeForDebugInfo(QualType T) {
case Type::Decltype:
T = cast<DecltypeType>(T)->getUnderlyingType();
break;
case Type::Attributed:
T = cast<AttributedType>(T)->getEquivalentType();
case Type::Elaborated:
T = cast<ElaboratedType>(T)->getNamedType();
break;
@ -1423,6 +1425,7 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty,
case Type::MemberPointer:
return CreateType(cast<MemberPointerType>(Ty), Unit);
case Type::Attributed:
case Type::TemplateSpecialization:
case Type::Elaborated:
case Type::Paren:

View File

@ -3778,7 +3778,6 @@ QualType TreeTransform<Derived>::TransformInjectedClassNameType(
return T;
}
template<typename Derived>
QualType TreeTransform<Derived>::TransformTemplateTypeParmType(
TypeLocBuilder &TLB,
@ -3945,6 +3944,43 @@ TreeTransform<Derived>::TransformElaboratedType(TypeLocBuilder &TLB,
return Result;
}
template<typename Derived>
QualType TreeTransform<Derived>::TransformAttributedType(
TypeLocBuilder &TLB,
AttributedTypeLoc TL) {
const AttributedType *oldType = TL.getTypePtr();
QualType modifiedType = getDerived().TransformType(TLB, TL.getModifiedLoc());
if (modifiedType.isNull())
return QualType();
QualType result = TL.getType();
// FIXME: dependent operand expressions?
if (getDerived().AlwaysRebuild() ||
modifiedType != oldType->getModifiedType()) {
// TODO: this is really lame; we should really be rebuilding the
// equivalent type from first principles.
QualType equivalentType
= getDerived().TransformType(oldType->getEquivalentType());
if (equivalentType.isNull())
return QualType();
result = SemaRef.Context.getAttributedType(oldType->getAttrKind(),
modifiedType,
equivalentType);
}
AttributedTypeLoc newTL = TLB.push<AttributedTypeLoc>(result);
newTL.setAttrNameLoc(TL.getAttrNameLoc());
if (TL.hasAttrOperand())
newTL.setAttrOperandParensRange(TL.getAttrOperandParensRange());
if (TL.hasAttrExprOperand())
newTL.setAttrExprOperand(TL.getAttrExprOperand());
else if (TL.hasAttrEnumOperand())
newTL.setAttrEnumOperandLoc(TL.getAttrEnumOperandLoc());
return result;
}
template<typename Derived>
QualType
TreeTransform<Derived>::TransformParenType(TypeLocBuilder &TLB,

View File

@ -2924,6 +2924,17 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) {
return T;
}
case TYPE_ATTRIBUTED: {
if (Record.size() != 3) {
Error("incorrect encoding of attributed type");
return QualType();
}
QualType modifiedType = GetType(Record[0]);
QualType equivalentType = GetType(Record[1]);
AttributedType::Kind kind = static_cast<AttributedType::Kind>(Record[2]);
return Context->getAttributedType(kind, modifiedType, equivalentType);
}
case TYPE_PAREN: {
if (Record.size() != 1) {
Error("incorrect encoding of paren type");
@ -3197,6 +3208,22 @@ void TypeLocReader::VisitRecordTypeLoc(RecordTypeLoc TL) {
void TypeLocReader::VisitEnumTypeLoc(EnumTypeLoc TL) {
TL.setNameLoc(ReadSourceLocation(Record, Idx));
}
void TypeLocReader::VisitAttributedTypeLoc(AttributedTypeLoc TL) {
TL.setAttrNameLoc(ReadSourceLocation(Record, Idx));
if (TL.hasAttrOperand()) {
SourceRange range;
range.setBegin(ReadSourceLocation(Record, Idx));
range.setEnd(ReadSourceLocation(Record, Idx));
TL.setAttrOperandParensRange(range);
}
if (TL.hasAttrExprOperand()) {
if (Record[Idx++])
TL.setAttrExprOperand(Reader.ReadExpr(F));
else
TL.setAttrExprOperand(0);
} else if (TL.hasAttrEnumOperand())
TL.setAttrEnumOperandLoc(ReadSourceLocation(Record, Idx));
}
void TypeLocReader::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) {
TL.setNameLoc(ReadSourceLocation(Record, Idx));
}

View File

@ -228,6 +228,13 @@ void ASTTypeWriter::VisitEnumType(const EnumType *T) {
Code = TYPE_ENUM;
}
void ASTTypeWriter::VisitAttributedType(const AttributedType *T) {
Writer.AddTypeRef(T->getModifiedType(), Record);
Writer.AddTypeRef(T->getEquivalentType(), Record);
Record.push_back(T->getAttrKind());
Code = TYPE_ATTRIBUTED;
}
void
ASTTypeWriter::VisitSubstTemplateTypeParmType(
const SubstTemplateTypeParmType *T) {
@ -462,6 +469,21 @@ void TypeLocWriter::VisitRecordTypeLoc(RecordTypeLoc TL) {
void TypeLocWriter::VisitEnumTypeLoc(EnumTypeLoc TL) {
Writer.AddSourceLocation(TL.getNameLoc(), Record);
}
void TypeLocWriter::VisitAttributedTypeLoc(AttributedTypeLoc TL) {
Writer.AddSourceLocation(TL.getAttrNameLoc(), Record);
if (TL.hasAttrOperand()) {
SourceRange range = TL.getAttrOperandParensRange();
Writer.AddSourceLocation(range.getBegin(), Record);
Writer.AddSourceLocation(range.getEnd(), Record);
}
if (TL.hasAttrExprOperand()) {
Expr *operand = TL.getAttrExprOperand();
Record.push_back(operand ? 1 : 0);
if (operand) Writer.AddStmt(operand);
} else if (TL.hasAttrEnumOperand()) {
Writer.AddSourceLocation(TL.getAttrEnumOperandLoc(), Record);
}
}
void TypeLocWriter::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) {
Writer.AddSourceLocation(TL.getNameLoc(), Record);
}