mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-02-04 16:26:46 +00:00
Add an AdjustedType sugar node for adjusting calling conventions
Summary: In general, this type node can be used to represent any type adjustment that occurs implicitly without losing type sugar. The immediate use of this is to adjust the calling conventions of member function pointer types without breaking template instantiation. Fixes PR17996. Reviewers: rsmith Differential Revision: http://llvm-reviews.chandlerc.com/D2332 llvm-svn: 196451
This commit is contained in:
parent
d33ff74b19
commit
0503a870a9
@ -82,7 +82,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
mutable llvm::FoldingSet<ExtQuals> ExtQualNodes;
|
||||
mutable llvm::FoldingSet<ComplexType> ComplexTypes;
|
||||
mutable llvm::FoldingSet<PointerType> PointerTypes;
|
||||
mutable llvm::FoldingSet<DecayedType> DecayedTypes;
|
||||
mutable llvm::FoldingSet<AdjustedType> AdjustedTypes;
|
||||
mutable llvm::FoldingSet<BlockPointerType> BlockPointerTypes;
|
||||
mutable llvm::FoldingSet<LValueReferenceType> LValueReferenceTypes;
|
||||
mutable llvm::FoldingSet<RValueReferenceType> RValueReferenceTypes;
|
||||
@ -915,6 +915,14 @@ public:
|
||||
return CanQualType::CreateUnsafe(getPointerType((QualType) T));
|
||||
}
|
||||
|
||||
/// \brief Return the uniqued reference to a type adjusted from the original
|
||||
/// type to a new type.
|
||||
QualType getAdjustedType(QualType Orig, QualType New) const;
|
||||
CanQualType getAdjustedType(CanQualType Orig, CanQualType New) const {
|
||||
return CanQualType::CreateUnsafe(
|
||||
getAdjustedType((QualType)Orig, (QualType)New));
|
||||
}
|
||||
|
||||
/// \brief Return the uniqued reference to the decayed version of the given
|
||||
/// type. Can only be called on array and function types which decay to
|
||||
/// pointer types.
|
||||
|
@ -874,6 +874,10 @@ DEF_TRAVERSE_TYPE(MemberPointerType, {
|
||||
TRY_TO(TraverseType(T->getPointeeType()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_TYPE(AdjustedType, {
|
||||
TRY_TO(TraverseType(T->getOriginalType()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_TYPE(DecayedType, {
|
||||
TRY_TO(TraverseType(T->getOriginalType()));
|
||||
})
|
||||
@ -1084,6 +1088,10 @@ DEF_TRAVERSE_TYPELOC(MemberPointerType, {
|
||||
TRY_TO(TraverseTypeLoc(TL.getPointeeLoc()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_TYPELOC(AdjustedType, {
|
||||
TRY_TO(TraverseTypeLoc(TL.getOriginalLoc()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_TYPELOC(DecayedType, {
|
||||
TRY_TO(TraverseTypeLoc(TL.getOriginalLoc()));
|
||||
})
|
||||
|
@ -1996,39 +1996,59 @@ public:
|
||||
static bool classof(const Type *T) { return T->getTypeClass() == Pointer; }
|
||||
};
|
||||
|
||||
/// \brief Represents a pointer type decayed from an array or function type.
|
||||
class DecayedType : public Type, public llvm::FoldingSetNode {
|
||||
QualType OriginalType;
|
||||
QualType DecayedPointer;
|
||||
/// \brief Represents a type which was implicitly adjusted by the semantic
|
||||
/// engine for arbitrary reasons. For example, array and function types can
|
||||
/// decay, and function types can have their calling conventions adjusted.
|
||||
class AdjustedType : public Type, public llvm::FoldingSetNode {
|
||||
QualType OriginalTy;
|
||||
QualType AdjustedTy;
|
||||
|
||||
DecayedType(QualType OriginalType, QualType DecayedPointer,
|
||||
QualType CanonicalPtr)
|
||||
: Type(Decayed, CanonicalPtr, OriginalType->isDependentType(),
|
||||
OriginalType->isInstantiationDependentType(),
|
||||
OriginalType->isVariablyModifiedType(),
|
||||
OriginalType->containsUnexpandedParameterPack()),
|
||||
OriginalType(OriginalType), DecayedPointer(DecayedPointer) {
|
||||
assert(isa<PointerType>(DecayedPointer));
|
||||
protected:
|
||||
AdjustedType(TypeClass TC, QualType OriginalTy, QualType AdjustedTy,
|
||||
QualType CanonicalPtr)
|
||||
: Type(TC, CanonicalPtr, OriginalTy->isDependentType(),
|
||||
OriginalTy->isInstantiationDependentType(),
|
||||
OriginalTy->isVariablyModifiedType(),
|
||||
OriginalTy->containsUnexpandedParameterPack()),
|
||||
OriginalTy(OriginalTy), AdjustedTy(AdjustedTy) {}
|
||||
|
||||
friend class ASTContext; // ASTContext creates these.
|
||||
|
||||
public:
|
||||
QualType getOriginalType() const { return OriginalTy; }
|
||||
QualType getAdjustedType() const { return AdjustedTy; }
|
||||
|
||||
bool isSugared() const { return true; }
|
||||
QualType desugar() const { return AdjustedTy; }
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID) {
|
||||
Profile(ID, OriginalTy, AdjustedTy);
|
||||
}
|
||||
static void Profile(llvm::FoldingSetNodeID &ID, QualType Orig, QualType New) {
|
||||
ID.AddPointer(Orig.getAsOpaquePtr());
|
||||
ID.AddPointer(New.getAsOpaquePtr());
|
||||
}
|
||||
|
||||
static bool classof(const Type *T) {
|
||||
return T->getTypeClass() == Adjusted || T->getTypeClass() == Decayed;
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Represents a pointer type decayed from an array or function type.
|
||||
class DecayedType : public AdjustedType {
|
||||
|
||||
DecayedType(QualType OriginalType, QualType DecayedPtr, QualType CanonicalPtr)
|
||||
: AdjustedType(Decayed, OriginalType, DecayedPtr, CanonicalPtr) {
|
||||
assert(isa<PointerType>(getAdjustedType()));
|
||||
}
|
||||
|
||||
friend class ASTContext; // ASTContext creates these.
|
||||
|
||||
public:
|
||||
QualType getDecayedType() const { return DecayedPointer; }
|
||||
QualType getOriginalType() const { return OriginalType; }
|
||||
QualType getDecayedType() const { return getAdjustedType(); }
|
||||
|
||||
QualType getPointeeType() const {
|
||||
return cast<PointerType>(DecayedPointer)->getPointeeType();
|
||||
}
|
||||
|
||||
bool isSugared() const { return true; }
|
||||
QualType desugar() const { return DecayedPointer; }
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID) {
|
||||
Profile(ID, OriginalType);
|
||||
}
|
||||
static void Profile(llvm::FoldingSetNodeID &ID, QualType OriginalType) {
|
||||
ID.AddPointer(OriginalType.getAsOpaquePtr());
|
||||
return cast<PointerType>(getDecayedType())->getPointeeType();
|
||||
}
|
||||
|
||||
static bool classof(const Type *T) { return T->getTypeClass() == Decayed; }
|
||||
|
@ -978,12 +978,10 @@ inline TypeLoc TypeLoc::IgnoreParens() const {
|
||||
}
|
||||
|
||||
|
||||
struct DecayedLocInfo { }; // Nothing.
|
||||
struct AdjustedLocInfo { }; // Nothing.
|
||||
|
||||
/// \brief Wrapper for source info for pointers decayed from arrays and
|
||||
/// functions.
|
||||
class DecayedTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc, DecayedTypeLoc,
|
||||
DecayedType, DecayedLocInfo> {
|
||||
class AdjustedTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc, AdjustedTypeLoc,
|
||||
AdjustedType, AdjustedLocInfo> {
|
||||
public:
|
||||
TypeLoc getOriginalLoc() const {
|
||||
return getInnerTypeLoc();
|
||||
@ -1004,12 +1002,17 @@ public:
|
||||
}
|
||||
|
||||
unsigned getLocalDataSize() const {
|
||||
// sizeof(DecayedLocInfo) is 1, but we don't need its address to be unique
|
||||
// sizeof(AdjustedLocInfo) is 1, but we don't need its address to be unique
|
||||
// anyway. TypeLocBuilder can't handle data sizes of 1.
|
||||
return 0; // No data.
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Wrapper for source info for pointers decayed from arrays and
|
||||
/// functions.
|
||||
class DecayedTypeLoc : public InheritingConcreteTypeLoc<
|
||||
AdjustedTypeLoc, DecayedTypeLoc, DecayedType> {
|
||||
};
|
||||
|
||||
struct PointerLikeLocInfo {
|
||||
SourceLocation StarLoc;
|
||||
|
@ -81,7 +81,8 @@ TYPE(FunctionNoProto, FunctionType)
|
||||
DEPENDENT_TYPE(UnresolvedUsing, Type)
|
||||
NON_CANONICAL_TYPE(Paren, Type)
|
||||
NON_CANONICAL_TYPE(Typedef, Type)
|
||||
NON_CANONICAL_TYPE(Decayed, Type)
|
||||
NON_CANONICAL_TYPE(Adjusted, Type)
|
||||
NON_CANONICAL_TYPE(Decayed, AdjustedType)
|
||||
NON_CANONICAL_UNLESS_DEPENDENT_TYPE(TypeOfExpr, Type)
|
||||
NON_CANONICAL_UNLESS_DEPENDENT_TYPE(TypeOf, Type)
|
||||
NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Decltype, Type)
|
||||
|
@ -841,7 +841,9 @@ namespace clang {
|
||||
/// \brief An AtomicType record.
|
||||
TYPE_ATOMIC = 40,
|
||||
/// \brief A DecayedType record.
|
||||
TYPE_DECAYED = 41
|
||||
TYPE_DECAYED = 41,
|
||||
/// \brief An AdjustedType record.
|
||||
TYPE_ADJUSTED = 42
|
||||
};
|
||||
|
||||
/// \brief The type IDs for special types constructed by semantic
|
||||
|
@ -1632,8 +1632,9 @@ ASTContext::getTypeInfoImpl(const Type *T) const {
|
||||
}
|
||||
case Type::ObjCObject:
|
||||
return getTypeInfo(cast<ObjCObjectType>(T)->getBaseType().getTypePtr());
|
||||
case Type::Adjusted:
|
||||
case Type::Decayed:
|
||||
return getTypeInfo(cast<DecayedType>(T)->getDecayedType().getTypePtr());
|
||||
return getTypeInfo(cast<AdjustedType>(T)->getAdjustedType().getTypePtr());
|
||||
case Type::ObjCInterface: {
|
||||
const ObjCInterfaceType *ObjCI = cast<ObjCInterfaceType>(T);
|
||||
const ASTRecordLayout &Layout = getASTObjCInterfaceLayout(ObjCI->getDecl());
|
||||
@ -2163,15 +2164,30 @@ QualType ASTContext::getPointerType(QualType T) const {
|
||||
return QualType(New, 0);
|
||||
}
|
||||
|
||||
QualType ASTContext::getAdjustedType(QualType Orig, QualType New) const {
|
||||
llvm::FoldingSetNodeID ID;
|
||||
AdjustedType::Profile(ID, Orig, New);
|
||||
void *InsertPos = 0;
|
||||
AdjustedType *AT = AdjustedTypes.FindNodeOrInsertPos(ID, InsertPos);
|
||||
if (AT)
|
||||
return QualType(AT, 0);
|
||||
|
||||
QualType Canonical = getCanonicalType(New);
|
||||
|
||||
// Get the new insert position for the node we care about.
|
||||
AT = AdjustedTypes.FindNodeOrInsertPos(ID, InsertPos);
|
||||
assert(AT == 0 && "Shouldn't be in the map!");
|
||||
|
||||
AT = new (*this, TypeAlignment)
|
||||
AdjustedType(Type::Adjusted, Orig, New, Canonical);
|
||||
Types.push_back(AT);
|
||||
AdjustedTypes.InsertNode(AT, InsertPos);
|
||||
return QualType(AT, 0);
|
||||
}
|
||||
|
||||
QualType ASTContext::getDecayedType(QualType T) const {
|
||||
assert((T->isArrayType() || T->isFunctionType()) && "T does not decay");
|
||||
|
||||
llvm::FoldingSetNodeID ID;
|
||||
DecayedType::Profile(ID, T);
|
||||
void *InsertPos = 0;
|
||||
if (DecayedType *DT = DecayedTypes.FindNodeOrInsertPos(ID, InsertPos))
|
||||
return QualType(DT, 0);
|
||||
|
||||
QualType Decayed;
|
||||
|
||||
// C99 6.7.5.3p7:
|
||||
@ -2189,17 +2205,23 @@ QualType ASTContext::getDecayedType(QualType T) const {
|
||||
if (T->isFunctionType())
|
||||
Decayed = getPointerType(T);
|
||||
|
||||
llvm::FoldingSetNodeID ID;
|
||||
AdjustedType::Profile(ID, T, Decayed);
|
||||
void *InsertPos = 0;
|
||||
AdjustedType *AT = AdjustedTypes.FindNodeOrInsertPos(ID, InsertPos);
|
||||
if (AT)
|
||||
return QualType(AT, 0);
|
||||
|
||||
QualType Canonical = getCanonicalType(Decayed);
|
||||
|
||||
// Get the new insert position for the node we care about.
|
||||
DecayedType *NewIP = DecayedTypes.FindNodeOrInsertPos(ID, InsertPos);
|
||||
assert(NewIP == 0 && "Shouldn't be in the map!"); (void)NewIP;
|
||||
AT = AdjustedTypes.FindNodeOrInsertPos(ID, InsertPos);
|
||||
assert(AT == 0 && "Shouldn't be in the map!");
|
||||
|
||||
DecayedType *New =
|
||||
new (*this, TypeAlignment) DecayedType(T, Decayed, Canonical);
|
||||
Types.push_back(New);
|
||||
DecayedTypes.InsertNode(New, InsertPos);
|
||||
return QualType(New, 0);
|
||||
AT = new (*this, TypeAlignment) DecayedType(T, Decayed, Canonical);
|
||||
Types.push_back(AT);
|
||||
AdjustedTypes.InsertNode(AT, InsertPos);
|
||||
return QualType(AT, 0);
|
||||
}
|
||||
|
||||
/// getBlockPointerType - Return the uniqued reference to the type for
|
||||
|
@ -51,6 +51,11 @@ static QualType Desugar(ASTContext &Context, QualType QT, bool &ShouldAKA) {
|
||||
QT = AT->desugar();
|
||||
continue;
|
||||
}
|
||||
// ...or an adjusted type...
|
||||
if (const AdjustedType *AT = dyn_cast<AdjustedType>(Ty)) {
|
||||
QT = AT->desugar();
|
||||
continue;
|
||||
}
|
||||
// ... or an auto type.
|
||||
if (const AutoType *AT = dyn_cast<AutoType>(Ty)) {
|
||||
if (!AT->isSugared())
|
||||
|
@ -407,10 +407,11 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
|
||||
return false;
|
||||
break;
|
||||
|
||||
case Type::Adjusted:
|
||||
case Type::Decayed:
|
||||
if (!IsStructurallyEquivalent(Context,
|
||||
cast<DecayedType>(T1)->getPointeeType(),
|
||||
cast<DecayedType>(T2)->getPointeeType()))
|
||||
cast<AdjustedType>(T1)->getOriginalType(),
|
||||
cast<AdjustedType>(T2)->getOriginalType()))
|
||||
return false;
|
||||
break;
|
||||
|
||||
|
@ -251,6 +251,11 @@ void DeclInfo::fill() {
|
||||
TL = PointerTL.getPointeeLoc().getUnqualifiedLoc();
|
||||
continue;
|
||||
}
|
||||
// Look through adjusted types.
|
||||
if (AdjustedTypeLoc ATL = TL.getAs<AdjustedTypeLoc>()) {
|
||||
TL = ATL.getOriginalLoc();
|
||||
continue;
|
||||
}
|
||||
if (BlockPointerTypeLoc BlockPointerTL =
|
||||
TL.getAs<BlockPointerTypeLoc>()) {
|
||||
TL = BlockPointerTL.getPointeeLoc().getUnqualifiedLoc();
|
||||
|
@ -2508,11 +2508,8 @@ unsigned FunctionDecl::getBuiltinID() const {
|
||||
/// based on its FunctionType. This is the length of the ParamInfo array
|
||||
/// after it has been created.
|
||||
unsigned FunctionDecl::getNumParams() const {
|
||||
const FunctionType *FT = getType()->castAs<FunctionType>();
|
||||
if (isa<FunctionNoProtoType>(FT))
|
||||
return 0;
|
||||
return cast<FunctionProtoType>(FT)->getNumArgs();
|
||||
|
||||
const FunctionProtoType *FPT = getType()->getAs<FunctionProtoType>();
|
||||
return FPT ? FPT->getNumArgs() : 0;
|
||||
}
|
||||
|
||||
void FunctionDecl::setParams(ASTContext &C,
|
||||
|
@ -423,8 +423,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
|
||||
Ty = PT->getInnerType();
|
||||
}
|
||||
|
||||
if (isa<FunctionType>(Ty)) {
|
||||
const FunctionType *AFT = Ty->getAs<FunctionType>();
|
||||
if (const FunctionType *AFT = Ty->getAs<FunctionType>()) {
|
||||
const FunctionProtoType *FT = 0;
|
||||
if (D->hasWrittenPrototype())
|
||||
FT = dyn_cast<FunctionProtoType>(AFT);
|
||||
|
@ -833,6 +833,7 @@ void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier,
|
||||
switch (type->getTypeClass()) {
|
||||
case Type::Builtin:
|
||||
case Type::Complex:
|
||||
case Type::Adjusted:
|
||||
case Type::Decayed:
|
||||
case Type::Pointer:
|
||||
case Type::BlockPointer:
|
||||
|
@ -593,6 +593,9 @@ namespace {
|
||||
AutoType *VisitAttributedType(const AttributedType *T) {
|
||||
return Visit(T->getModifiedType());
|
||||
}
|
||||
AutoType *VisitAdjustedType(const AdjustedType *T) {
|
||||
return Visit(T->getOriginalType());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -204,6 +204,7 @@ bool TypePrinter::canPrefixQualifiers(const Type *T,
|
||||
NeedARCStrongQualifier = true;
|
||||
// Fall through
|
||||
|
||||
case Type::Adjusted:
|
||||
case Type::Decayed:
|
||||
case Type::Pointer:
|
||||
case Type::BlockPointer:
|
||||
@ -471,12 +472,21 @@ void TypePrinter::printVariableArrayAfter(const VariableArrayType *T,
|
||||
printAfter(T->getElementType(), OS);
|
||||
}
|
||||
|
||||
void TypePrinter::printAdjustedBefore(const AdjustedType *T, raw_ostream &OS) {
|
||||
// Print the adjusted representation, otherwise the adjustment will be
|
||||
// invisible.
|
||||
printBefore(T->getAdjustedType(), OS);
|
||||
}
|
||||
void TypePrinter::printAdjustedAfter(const AdjustedType *T, raw_ostream &OS) {
|
||||
printAfter(T->getAdjustedType(), OS);
|
||||
}
|
||||
|
||||
void TypePrinter::printDecayedBefore(const DecayedType *T, raw_ostream &OS) {
|
||||
// Print as though it's a pointer.
|
||||
printBefore(T->getDecayedType(), OS);
|
||||
printAdjustedBefore(T, OS);
|
||||
}
|
||||
void TypePrinter::printDecayedAfter(const DecayedType *T, raw_ostream &OS) {
|
||||
printAfter(T->getDecayedType(), OS);
|
||||
printAdjustedAfter(T, OS);
|
||||
}
|
||||
|
||||
void TypePrinter::printDependentSizedArrayBefore(
|
||||
|
@ -2123,10 +2123,11 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile Unit) {
|
||||
return CreateType(cast<ComplexType>(Ty));
|
||||
case Type::Pointer:
|
||||
return CreateType(cast<PointerType>(Ty), Unit);
|
||||
case Type::Adjusted:
|
||||
case Type::Decayed:
|
||||
// Decayed types are just pointers in LLVM and DWARF.
|
||||
// Decayed and adjusted types use the adjusted type in LLVM and DWARF.
|
||||
return CreateType(
|
||||
cast<PointerType>(cast<DecayedType>(Ty)->getDecayedType()), Unit);
|
||||
cast<PointerType>(cast<AdjustedType>(Ty)->getAdjustedType()), Unit);
|
||||
case Type::BlockPointer:
|
||||
return CreateType(cast<BlockPointerType>(Ty), Unit);
|
||||
case Type::Typedef:
|
||||
|
@ -1308,6 +1308,10 @@ void CodeGenFunction::EmitVariablyModifiedType(QualType type) {
|
||||
case Type::ObjCObjectPointer:
|
||||
llvm_unreachable("type class is never variably-modified!");
|
||||
|
||||
case Type::Adjusted:
|
||||
type = cast<AdjustedType>(ty)->getAdjustedType();
|
||||
break;
|
||||
|
||||
case Type::Decayed:
|
||||
type = cast<DecayedType>(ty)->getPointeeType();
|
||||
break;
|
||||
|
@ -1812,7 +1812,10 @@ QualType Sema::BuildMemberPointerType(QualType T, QualType Class,
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: Adjust member function pointer calling conventions.
|
||||
// Adjust the default free function calling convention to the default method
|
||||
// calling convention.
|
||||
if (T->isFunctionType())
|
||||
adjustMemberFunctionCC(T, /*IsStatic=*/false);
|
||||
|
||||
return Context.getMemberPointerType(T, Class.getTypePtr());
|
||||
}
|
||||
@ -3681,6 +3684,9 @@ namespace {
|
||||
void VisitAttributedTypeLoc(AttributedTypeLoc TL) {
|
||||
fillAttributedTypeLoc(TL, Chunk.getAttrs());
|
||||
}
|
||||
void VisitAdjustedTypeLoc(AdjustedTypeLoc TL) {
|
||||
// nothing
|
||||
}
|
||||
void VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL) {
|
||||
assert(Chunk.Kind == DeclaratorChunk::BlockPointer);
|
||||
TL.setCaretLoc(Chunk.Loc);
|
||||
@ -3836,6 +3842,10 @@ Sema::GetTypeSourceInfoForDeclarator(Declarator &D, QualType T,
|
||||
CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc();
|
||||
}
|
||||
|
||||
// FIXME: Ordering here?
|
||||
while (AdjustedTypeLoc TL = CurrTL.getAs<AdjustedTypeLoc>())
|
||||
CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc();
|
||||
|
||||
DeclaratorLocFiller(Context, D.getTypeObject(i)).Visit(CurrTL);
|
||||
CurrTL = CurrTL.getNextTypeLoc().getUnqualifiedLoc();
|
||||
}
|
||||
@ -4589,14 +4599,15 @@ void Sema::adjustMemberFunctionCC(QualType &T, bool IsStatic) {
|
||||
const FunctionType *FT = T->castAs<FunctionType>();
|
||||
bool IsVariadic = (isa<FunctionProtoType>(FT) &&
|
||||
cast<FunctionProtoType>(FT)->isVariadic());
|
||||
CallingConv CC = FT->getCallConv();
|
||||
|
||||
// Only adjust types with the default convention. For example, on Windows we
|
||||
// should adjust a __cdecl type to __thiscall for instance methods, and a
|
||||
// __thiscall type to __cdecl for static methods.
|
||||
CallingConv DefaultCC =
|
||||
CallingConv CurCC = FT->getCallConv();
|
||||
CallingConv FromCC =
|
||||
Context.getDefaultCallingConvention(IsVariadic, IsStatic);
|
||||
if (CC != DefaultCC)
|
||||
CallingConv ToCC = Context.getDefaultCallingConvention(IsVariadic, !IsStatic);
|
||||
if (CurCC != FromCC || FromCC == ToCC)
|
||||
return;
|
||||
|
||||
// Check if there was an explicit attribute, but only look through parens.
|
||||
@ -4609,12 +4620,8 @@ void Sema::adjustMemberFunctionCC(QualType &T, bool IsStatic) {
|
||||
R = AT->getModifiedType().IgnoreParens();
|
||||
}
|
||||
|
||||
// FIXME: This loses sugar. This should probably be fixed with an implicit
|
||||
// AttributedType node that adjusts the convention.
|
||||
CC = Context.getDefaultCallingConvention(IsVariadic, !IsStatic);
|
||||
FT = Context.adjustFunctionType(FT, FT->getExtInfo().withCallingConv(CC));
|
||||
FunctionTypeUnwrapper Unwrapped(*this, T);
|
||||
T = Unwrapped.wrap(*this, FT);
|
||||
FT = Context.adjustFunctionType(FT, FT->getExtInfo().withCallingConv(ToCC));
|
||||
T = Context.getAdjustedType(T, QualType(FT, T.getQualifiers()));
|
||||
}
|
||||
|
||||
/// Handle OpenCL image access qualifiers: read_only, write_only, read_write
|
||||
|
@ -3664,6 +3664,13 @@ QualType TreeTransform<Derived>::TransformComplexType(TypeLocBuilder &TLB,
|
||||
return TransformTypeSpecType(TLB, T);
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
QualType TreeTransform<Derived>::TransformAdjustedType(TypeLocBuilder &TLB,
|
||||
AdjustedTypeLoc TL) {
|
||||
// Adjustments applied during transformation are handled elsewhere.
|
||||
return getDerived().TransformType(TLB, TL.getOriginalLoc());
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
QualType TreeTransform<Derived>::TransformDecayedType(TypeLocBuilder &TLB,
|
||||
DecayedTypeLoc TL) {
|
||||
@ -3832,6 +3839,14 @@ TreeTransform<Derived>::TransformMemberPointerType(TypeLocBuilder &TLB,
|
||||
return QualType();
|
||||
}
|
||||
|
||||
// If we had to adjust the pointee type when building a member pointer, make
|
||||
// sure to push TypeLoc info for it.
|
||||
const MemberPointerType *MPT = Result->getAs<MemberPointerType>();
|
||||
if (MPT && PointeeType != MPT->getPointeeType()) {
|
||||
assert(isa<AdjustedType>(MPT->getPointeeType()));
|
||||
TLB.push<AdjustedTypeLoc>(MPT->getPointeeType());
|
||||
}
|
||||
|
||||
MemberPointerTypeLoc NewTL = TLB.push<MemberPointerTypeLoc>(Result);
|
||||
NewTL.setSigilLoc(TL.getSigilLoc());
|
||||
NewTL.setClassTInfo(NewClsTInfo);
|
||||
@ -9391,8 +9406,8 @@ QualType
|
||||
TreeTransform<Derived>::RebuildMemberPointerType(QualType PointeeType,
|
||||
QualType ClassType,
|
||||
SourceLocation Sigil) {
|
||||
return SemaRef.BuildMemberPointerType(PointeeType, ClassType,
|
||||
Sigil, getDerived().getBaseEntity());
|
||||
return SemaRef.BuildMemberPointerType(PointeeType, ClassType, Sigil,
|
||||
getDerived().getBaseEntity());
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
|
@ -4548,6 +4548,16 @@ QualType ASTReader::readTypeRecord(unsigned Index) {
|
||||
return DT;
|
||||
}
|
||||
|
||||
case TYPE_ADJUSTED: {
|
||||
if (Record.size() != 2) {
|
||||
Error("Incorrect encoding of adjusted type");
|
||||
return QualType();
|
||||
}
|
||||
QualType OriginalTy = readType(*Loc.F, Record, Idx);
|
||||
QualType AdjustedTy = readType(*Loc.F, Record, Idx);
|
||||
return Context.getAdjustedType(OriginalTy, AdjustedTy);
|
||||
}
|
||||
|
||||
case TYPE_BLOCK_POINTER: {
|
||||
if (Record.size() != 1) {
|
||||
Error("Incorrect encoding of block pointer type");
|
||||
@ -4997,6 +5007,9 @@ void TypeLocReader::VisitPointerTypeLoc(PointerTypeLoc TL) {
|
||||
void TypeLocReader::VisitDecayedTypeLoc(DecayedTypeLoc TL) {
|
||||
// nothing to do
|
||||
}
|
||||
void TypeLocReader::VisitAdjustedTypeLoc(AdjustedTypeLoc TL) {
|
||||
// nothing to do
|
||||
}
|
||||
void TypeLocReader::VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL) {
|
||||
TL.setCaretLoc(ReadSourceLocation(Record, Idx));
|
||||
}
|
||||
|
@ -113,6 +113,12 @@ void ASTTypeWriter::VisitDecayedType(const DecayedType *T) {
|
||||
Code = TYPE_DECAYED;
|
||||
}
|
||||
|
||||
void ASTTypeWriter::VisitAdjustedType(const AdjustedType *T) {
|
||||
Writer.AddTypeRef(T->getOriginalType(), Record);
|
||||
Writer.AddTypeRef(T->getAdjustedType(), Record);
|
||||
Code = TYPE_ADJUSTED;
|
||||
}
|
||||
|
||||
void ASTTypeWriter::VisitBlockPointerType(const BlockPointerType *T) {
|
||||
Writer.AddTypeRef(T->getPointeeType(), Record);
|
||||
Code = TYPE_BLOCK_POINTER;
|
||||
@ -455,6 +461,9 @@ void TypeLocWriter::VisitPointerTypeLoc(PointerTypeLoc TL) {
|
||||
void TypeLocWriter::VisitDecayedTypeLoc(DecayedTypeLoc TL) {
|
||||
// nothing to do
|
||||
}
|
||||
void TypeLocWriter::VisitAdjustedTypeLoc(AdjustedTypeLoc TL) {
|
||||
// nothing to do
|
||||
}
|
||||
void TypeLocWriter::VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL) {
|
||||
Writer.AddSourceLocation(TL.getCaretLoc(), Record);
|
||||
}
|
||||
|
@ -351,24 +351,25 @@ typedef void (__cdecl fun_cdecl)();
|
||||
typedef void (__stdcall fun_stdcall)();
|
||||
typedef void (__fastcall fun_fastcall)();
|
||||
|
||||
// FIXME: Adjust cdecl to thiscall when forming a member pointer.
|
||||
//fun_default A::*td1 = &A::method_thiscall;
|
||||
fun_cdecl A::*td2 = &A::method_cdecl;
|
||||
fun_default A::*td1 = &A::method_thiscall;
|
||||
fun_cdecl A::*td2 = &A::method_thiscall;
|
||||
fun_stdcall A::*td3 = &A::method_stdcall;
|
||||
fun_fastcall A::*td4 = &A::method_fastcall;
|
||||
|
||||
// Round trip the function type through a template, and verify that only cdecl
|
||||
// gets adjusted.
|
||||
template<typename Fn> struct X {
|
||||
typedef Fn A::*p;
|
||||
};
|
||||
template<typename Fn> struct X { typedef Fn A::*p; };
|
||||
|
||||
// FIXME: Adjust cdecl to thiscall when forming a member pointer.
|
||||
//X<void ()>::p tmpl1 = &A::method_thiscall;
|
||||
//X<void __cdecl ()>::p tmpl2 = &A::method_thiscall;
|
||||
X<void ()>::p tmpl1 = &A::method_thiscall;
|
||||
X<void __cdecl ()>::p tmpl2 = &A::method_thiscall;
|
||||
X<void __stdcall ()>::p tmpl3 = &A::method_stdcall;
|
||||
X<void __fastcall ()>::p tmpl4 = &A::method_fastcall;
|
||||
|
||||
X<fun_default >::p tmpl5 = &A::method_thiscall;
|
||||
X<fun_cdecl >::p tmpl6 = &A::method_thiscall;
|
||||
X<fun_stdcall >::p tmpl7 = &A::method_stdcall;
|
||||
X<fun_fastcall>::p tmpl8 = &A::method_fastcall;
|
||||
|
||||
} // end namespace MemberPointers
|
||||
|
||||
// Test that lambdas that capture nothing convert to cdecl function pointers.
|
||||
|
@ -191,3 +191,15 @@ namespace test5 {
|
||||
};
|
||||
extern template void valarray<int>::bar();
|
||||
}
|
||||
|
||||
namespace test6 {
|
||||
struct foo {
|
||||
int bar();
|
||||
};
|
||||
typedef int bar_t();
|
||||
void zed(bar_t foo::*) {
|
||||
}
|
||||
void baz() {
|
||||
zed(&foo::bar);
|
||||
}
|
||||
}
|
||||
|
@ -1542,6 +1542,10 @@ bool CursorVisitor::VisitDecayedTypeLoc(DecayedTypeLoc TL) {
|
||||
return Visit(TL.getOriginalLoc());
|
||||
}
|
||||
|
||||
bool CursorVisitor::VisitAdjustedTypeLoc(AdjustedTypeLoc TL) {
|
||||
return Visit(TL.getOriginalLoc());
|
||||
}
|
||||
|
||||
bool CursorVisitor::VisitTemplateSpecializationTypeLoc(
|
||||
TemplateSpecializationTypeLoc TL) {
|
||||
// Visit the template name.
|
||||
|
@ -799,6 +799,10 @@ DEF_TRAVERSE_TYPE(DecayedType, {
|
||||
TRY_TO(TraverseType(T->getOriginalType()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_TYPE(AdjustedType, {
|
||||
TRY_TO(TraverseType(T->getOriginalType()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_TYPE(ConstantArrayType, {
|
||||
TRY_TO(TraverseType(T->getElementType()));
|
||||
})
|
||||
@ -1009,6 +1013,10 @@ DEF_TRAVERSE_TYPELOC(DecayedType, {
|
||||
TRY_TO(TraverseTypeLoc(TL.getOriginalLoc()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_TYPELOC(AdjustedType, {
|
||||
TRY_TO(TraverseTypeLoc(TL.getOriginalLoc()));
|
||||
})
|
||||
|
||||
template<typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::TraverseArrayTypeLocHelper(ArrayTypeLoc TL) {
|
||||
// This isn't available for ArrayType, but is for the ArrayTypeLoc.
|
||||
|
Loading…
x
Reference in New Issue
Block a user