diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 09fb9185095ed15a3b5a3aee23c47922479ce819..bcd22460a864bdf8540ab897b56291f5ff78fa06 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -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. diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h index d09550f0e2c2ccc954d4ab3b5b291e5cb1bffb2a..3c615c3035f4991244979780a49d429ed441023c 100644 --- a/include/clang/AST/RecursiveASTVisitor.h +++ b/include/clang/AST/RecursiveASTVisitor.h @@ -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())); }) diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index fb829e4d41039a95ef9a83b095a44bdb6050e050..9e5507bcf7ebc1c56ed83c75107d9e6c7392d104 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -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 getDecayedType() const { return DecayedPointer; } - QualType getOriginalType() const { return OriginalType; } - - QualType getPointeeType() const { - return cast<PointerType>(DecayedPointer)->getPointeeType(); - } + QualType getOriginalType() const { return OriginalTy; } + QualType getAdjustedType() const { return AdjustedTy; } bool isSugared() const { return true; } - QualType desugar() const { return DecayedPointer; } + QualType desugar() const { return AdjustedTy; } void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, OriginalType); + Profile(ID, OriginalTy, AdjustedTy); } - static void Profile(llvm::FoldingSetNodeID &ID, QualType OriginalType) { - ID.AddPointer(OriginalType.getAsOpaquePtr()); + 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 getAdjustedType(); } + + QualType getPointeeType() const { + return cast<PointerType>(getDecayedType())->getPointeeType(); } static bool classof(const Type *T) { return T->getTypeClass() == Decayed; } diff --git a/include/clang/AST/TypeLoc.h b/include/clang/AST/TypeLoc.h index 8ddfac7ad373b40e0a68a2fba3dc1385b9d5abde..e080c428896faeec65b4738191b58d43c0c52907 100644 --- a/include/clang/AST/TypeLoc.h +++ b/include/clang/AST/TypeLoc.h @@ -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; diff --git a/include/clang/AST/TypeNodes.def b/include/clang/AST/TypeNodes.def index 3126f48c644a846f945fa760a61584d59c3a4cb9..3b2665bb88e04fe37dc41953ad5d3fb7509f4b29 100644 --- a/include/clang/AST/TypeNodes.def +++ b/include/clang/AST/TypeNodes.def @@ -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) diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h index 03d905054aea1983c504d262acae7a106c2eb55d..440e9a714d93763709983f770f4a989e7fafa7f8 100644 --- a/include/clang/Serialization/ASTBitCodes.h +++ b/include/clang/Serialization/ASTBitCodes.h @@ -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 diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 0528a58f894445da97e9b2b3887c7101bad76cbb..79b8770e0b7b6c5f2ae643eb226b90eee964e830 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -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,14 +2164,29 @@ QualType ASTContext::getPointerType(QualType T) const { return QualType(New, 0); } -QualType ASTContext::getDecayedType(QualType T) const { - assert((T->isArrayType() || T->isFunctionType()) && "T does not decay"); - +QualType ASTContext::getAdjustedType(QualType Orig, QualType New) const { llvm::FoldingSetNodeID ID; - DecayedType::Profile(ID, T); + AdjustedType::Profile(ID, Orig, New); void *InsertPos = 0; - if (DecayedType *DT = DecayedTypes.FindNodeOrInsertPos(ID, InsertPos)) - return QualType(DT, 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"); QualType Decayed; @@ -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 diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp index ff1aea8a98aff7063f8d93f4fcd030c412ab6d57..7f7221fc6ed1371b8a2c76f1202c5a0e3c049c63 100644 --- a/lib/AST/ASTDiagnostic.cpp +++ b/lib/AST/ASTDiagnostic.cpp @@ -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()) diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index e16015b7c4ed0af56f58b536c84a10d156ee7b04..4292d358164f994f744485eff394a873c131c7f8 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -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; diff --git a/lib/AST/Comment.cpp b/lib/AST/Comment.cpp index f24a23d34c573ac6285f98d401956c84bad30fb1..e60eed9630c1d3eca41a0bf89fbc825522cc0516 100644 --- a/lib/AST/Comment.cpp +++ b/lib/AST/Comment.cpp @@ -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(); diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index db3ab9536eb34ce73ddc9a52ce5671b3fce0af2c..c75cf20eb38e29bffc646a1a887bd0418c559057 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -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, diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp index 767f6620a29524aeebcce3d27cbae9118287f9bb..f024f4593ba11bb5e2d5000b1a27c1b80ea7b420 100644 --- a/lib/AST/DeclPrinter.cpp +++ b/lib/AST/DeclPrinter.cpp @@ -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); diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp index ba67fad6489dda3615790d3f0ba2221a6d7d5815..e2d334b316db407433d821130fac70d10aa10275 100644 --- a/lib/AST/ItaniumMangle.cpp +++ b/lib/AST/ItaniumMangle.cpp @@ -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: diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 7421bae7bf5435537e9f1af14bcbca4ae81de3aa..cbb8bc61313330515848f863a0189e53ab22a0b6 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -593,6 +593,9 @@ namespace { AutoType *VisitAttributedType(const AttributedType *T) { return Visit(T->getModifiedType()); } + AutoType *VisitAdjustedType(const AdjustedType *T) { + return Visit(T->getOriginalType()); + } }; } diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp index 571e3db0289f2b318f3f9cde440154603bf7b3dd..082d027791fd866453a8641563b21a99d63eb223 100644 --- a/lib/AST/TypePrinter.cpp +++ b/lib/AST/TypePrinter.cpp @@ -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( diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index fcb26f0da61531781162f93e8f6eded2ef7bf81a..451a6848bafc0cd284dabfe811188f610681d2f7 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -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: diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index c1dc0b3657f3247e95b0f5ce646bf0d13e44f492..ce2c9b05c47a1d8930552c316fd6aa146ada221c 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -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; diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index dd28bfcf7d2111f33cdc03b052d0ca4838009351..63ac15baeb6a0dda203672559677aa3efaccb73e 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -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 diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 44581fd4153320ab85a80ff5b09ea4469d70f983..e9cb95006fedfcd886cbd30c1d1e8723ed8b24ac 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -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> diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index 4d1b4b90b664291bccbece0b1ba1b2feb03c64bf..c531134a9748abca100e64c7a297e08172f344f7 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -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)); } diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index fa5b83d98fbc51efe8bc25efc0e7e55552d0b94a..d8f170fd517c95af3dd38cc8b03b8eab9babca32 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -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); } diff --git a/test/SemaCXX/calling-conv-compat.cpp b/test/SemaCXX/calling-conv-compat.cpp index 2d52386add16ce3370cd55c6412d7c5735860da4..c55124c58050e43d2c7a6b8b5b3ba88cb585f64d 100644 --- a/test/SemaCXX/calling-conv-compat.cpp +++ b/test/SemaCXX/calling-conv-compat.cpp @@ -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. diff --git a/test/SemaCXX/decl-microsoft-call-conv.cpp b/test/SemaCXX/decl-microsoft-call-conv.cpp index 9f1463245ba29c89b673a5cbd7df0104150e0874..fd20ae234ec53b0035815bafd8173f657c8bc0c2 100644 --- a/test/SemaCXX/decl-microsoft-call-conv.cpp +++ b/test/SemaCXX/decl-microsoft-call-conv.cpp @@ -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); + } +} diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index c7d3ea46494d02cc4710b959bcbcf2fde40d8c9d..656fbd1b1b7ff6737dc4e67a34c9d6388af9b98b 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -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. diff --git a/tools/libclang/RecursiveASTVisitor.h b/tools/libclang/RecursiveASTVisitor.h index 3ad5acbb041b211faac5974a16ab65531c74c5be..5907b1dd5a68125ff54ba8d08fcea171aff327f6 100644 --- a/tools/libclang/RecursiveASTVisitor.h +++ b/tools/libclang/RecursiveASTVisitor.h @@ -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.