From 12df246d6dea2ee1f92c186f922f1afcf499647a Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Mon, 24 Jun 2013 17:51:48 +0000 Subject: [PATCH] [AST] Introduce a new DecayedType sugar node The goal of this sugar node is to be able to look at an arbitrary FunctionType and tell if any of the parameters were decayed from an array or function type. Ultimately this is necessary to implement Microsoft's C++ name mangling scheme, which mangles decayed arrays differently from normal pointers. Reviewers: rsmith Differential Revision: http://llvm-reviews.chandlerc.com/D1014 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@184763 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/ASTContext.h | 9 ++++ include/clang/AST/Decl.h | 6 +-- include/clang/AST/RecursiveASTVisitor.h | 8 +++ include/clang/AST/Type.h | 38 ++++++++++++++ include/clang/AST/TypeLoc.h | 34 +++++++++++++ include/clang/AST/TypeNodes.def | 1 + include/clang/Serialization/ASTBitCodes.h | 4 +- lib/AST/ASTContext.cpp | 60 +++++++++++++++++------ lib/AST/ASTImporter.cpp | 7 +++ lib/AST/Decl.cpp | 8 +++ lib/AST/ItaniumMangle.cpp | 1 + lib/AST/TypePrinter.cpp | 9 ++++ lib/CodeGen/CGDebugInfo.cpp | 4 ++ lib/CodeGen/CodeGenFunction.cpp | 4 ++ lib/Sema/SemaExpr.cpp | 2 + lib/Sema/SemaType.cpp | 7 ++- lib/Sema/TreeTransform.h | 16 ++++++ lib/Serialization/ASTReader.cpp | 15 ++++++ lib/Serialization/ASTWriter.cpp | 8 +++ test/Index/print-type.c | 2 +- test/Sema/function.c | 10 ++++ test/SemaCXX/function-type-qual.cpp | 8 +++ tools/libclang/CIndex.cpp | 4 ++ tools/libclang/RecursiveASTVisitor.h | 8 +++ 24 files changed, 246 insertions(+), 27 deletions(-) diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index ebbf6c99e6..ae7a8f14d4 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -82,6 +82,7 @@ class ASTContext : public RefCountedBase { mutable llvm::FoldingSet ExtQualNodes; mutable llvm::FoldingSet ComplexTypes; mutable llvm::FoldingSet PointerTypes; + mutable llvm::FoldingSet DecayedTypes; mutable llvm::FoldingSet BlockPointerTypes; mutable llvm::FoldingSet LValueReferenceTypes; mutable llvm::FoldingSet RValueReferenceTypes; @@ -889,6 +890,14 @@ public: return CanQualType::CreateUnsafe(getPointerType((QualType) T)); } + /// \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. + QualType getDecayedType(QualType T) const; + CanQualType getDecayedType(CanQualType T) const { + return CanQualType::CreateUnsafe(getDecayedType((QualType) T)); + } + /// \brief Return the uniqued reference to the atomic type for the specified /// type. QualType getAtomicType(QualType T) const; diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index 5d94278e99..25e37099f8 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -1337,11 +1337,7 @@ public: ParmVarDeclBits.HasInheritedDefaultArg = I; } - QualType getOriginalType() const { - if (getTypeSourceInfo()) - return getTypeSourceInfo()->getType(); - return getType(); - } + QualType getOriginalType() const; /// \brief Determine whether this parameter is actually a function /// parameter pack. diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h index 1072b97a14..df71bffe85 100644 --- a/include/clang/AST/RecursiveASTVisitor.h +++ b/include/clang/AST/RecursiveASTVisitor.h @@ -847,6 +847,10 @@ DEF_TRAVERSE_TYPE(MemberPointerType, { TRY_TO(TraverseType(T->getPointeeType())); }) +DEF_TRAVERSE_TYPE(DecayedType, { + TRY_TO(TraverseType(T->getOriginalType())); + }) + DEF_TRAVERSE_TYPE(ConstantArrayType, { TRY_TO(TraverseType(T->getElementType())); }) @@ -1053,6 +1057,10 @@ DEF_TRAVERSE_TYPELOC(MemberPointerType, { TRY_TO(TraverseTypeLoc(TL.getPointeeLoc())); }) +DEF_TRAVERSE_TYPELOC(DecayedType, { + TRY_TO(TraverseTypeLoc(TL.getOriginalLoc())); + }) + template bool RecursiveASTVisitor::TraverseArrayTypeLocHelper(ArrayTypeLoc TL) { // This isn't available for ArrayType, but is for the ArrayTypeLoc. diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index bd2e18878e..2566268a62 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -1991,6 +1991,44 @@ 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; + + DecayedType(QualType OriginalType, QualType DecayedPointer, + QualType CanonicalPtr) + : Type(Decayed, CanonicalPtr, OriginalType->isDependentType(), + OriginalType->isInstantiationDependentType(), + OriginalType->isVariablyModifiedType(), + OriginalType->containsUnexpandedParameterPack()), + OriginalType(OriginalType), DecayedPointer(DecayedPointer) { + assert(isa(DecayedPointer)); + } + + friend class ASTContext; // ASTContext creates these. + +public: + QualType getDecayedType() const { return DecayedPointer; } + QualType getOriginalType() const { return OriginalType; } + + QualType getPointeeType() const { + return cast(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()); + } + + static bool classof(const Type *T) { return T->getTypeClass() == Decayed; } +}; + /// BlockPointerType - pointer to a block type. /// This type is to represent types syntactically represented as /// "void (^)(int)", etc. Pointee is required to always be a function type. diff --git a/include/clang/AST/TypeLoc.h b/include/clang/AST/TypeLoc.h index 1eb8835f4d..a028a6f35c 100644 --- a/include/clang/AST/TypeLoc.h +++ b/include/clang/AST/TypeLoc.h @@ -974,6 +974,40 @@ inline TypeLoc TypeLoc::IgnoreParens() const { return *this; } + +struct DecayedLocInfo { }; // Nothing. + +/// \brief Wrapper for source info for pointers decayed from arrays and +/// funcitons. +class DecayedTypeLoc : public ConcreteTypeLoc { +public: + TypeLoc getOriginalLoc() const { + return getInnerTypeLoc(); + } + + void initializeLocal(ASTContext &Context, SourceLocation Loc) { + // do nothing + } + + QualType getInnerType() const { + // The inner type is the undecayed type, since that's what we have source + // location information for. + return getTypePtr()->getOriginalType(); + } + + SourceRange getLocalSourceRange() const { + return SourceRange(); + } + + unsigned getLocalDataSize() const { + // sizeof(DecayedLocInfo) 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. + } +}; + + struct PointerLikeLocInfo { SourceLocation StarLoc; }; diff --git a/include/clang/AST/TypeNodes.def b/include/clang/AST/TypeNodes.def index 840e07d94a..a29ae231e9 100644 --- a/include/clang/AST/TypeNodes.def +++ b/include/clang/AST/TypeNodes.def @@ -81,6 +81,7 @@ TYPE(FunctionNoProto, FunctionType) DEPENDENT_TYPE(UnresolvedUsing, Type) NON_CANONICAL_TYPE(Paren, Type) NON_CANONICAL_TYPE(Typedef, Type) +NON_CANONICAL_TYPE(Decayed, Type) 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 651b4a9df2..ec05cc216b 100644 --- a/include/clang/Serialization/ASTBitCodes.h +++ b/include/clang/Serialization/ASTBitCodes.h @@ -836,7 +836,9 @@ namespace clang { /// \brief A UnaryTransformType record. TYPE_UNARY_TRANSFORM = 39, /// \brief An AtomicType record. - TYPE_ATOMIC = 40 + TYPE_ATOMIC = 40, + /// \brief A DecayedType record. + TYPE_DECAYED = 41 }; /// \brief The type IDs for special types constructed by semantic diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 70c933e752..9105940076 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -1615,6 +1615,8 @@ ASTContext::getTypeInfoImpl(const Type *T) const { } case Type::ObjCObject: return getTypeInfo(cast(T)->getBaseType().getTypePtr()); + case Type::Decayed: + return getTypeInfo(cast(T)->getDecayedType().getTypePtr()); case Type::ObjCInterface: { const ObjCInterfaceType *ObjCI = cast(T); const ASTRecordLayout &Layout = getASTObjCInterfaceLayout(ObjCI->getDecl()); @@ -2167,6 +2169,45 @@ 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"); + + 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: + // A declaration of a parameter as "array of type" shall be + // adjusted to "qualified pointer to type", where the type + // qualifiers (if any) are those specified within the [ and ] of + // the array type derivation. + if (T->isArrayType()) + Decayed = getArrayDecayedType(T); + + // C99 6.7.5.3p8: + // A declaration of a parameter as "function returning type" + // shall be adjusted to "pointer to function returning type", as + // in 6.3.2.1. + if (T->isFunctionType()) + Decayed = getPointerType(T); + + 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; + + DecayedType *New = + new (*this, TypeAlignment) DecayedType(T, Decayed, Canonical); + Types.push_back(New); + DecayedTypes.InsertNode(New, InsertPos); + return QualType(New, 0); +} + /// getBlockPointerType - Return the uniqued reference to the type for /// a pointer to the specified block. QualType ASTContext::getBlockPointerType(QualType T) const { @@ -4154,22 +4195,9 @@ const ArrayType *ASTContext::getAsArrayType(QualType T) const { } QualType ASTContext::getAdjustedParameterType(QualType T) const { - // C99 6.7.5.3p7: - // A declaration of a parameter as "array of type" shall be - // adjusted to "qualified pointer to type", where the type - // qualifiers (if any) are those specified within the [ and ] of - // the array type derivation. - if (T->isArrayType()) - return getArrayDecayedType(T); - - // C99 6.7.5.3p8: - // A declaration of a parameter as "function returning type" - // shall be adjusted to "pointer to function returning type", as - // in 6.3.2.1. - if (T->isFunctionType()) - return getPointerType(T); - - return T; + if (T->isArrayType() || T->isFunctionType()) + return getDecayedType(T); + return T; } QualType ASTContext::getSignatureParameterType(QualType T) const { diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index 41a67af64d..8490458016 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -400,6 +400,13 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, return false; break; + case Type::Decayed: + if (!IsStructurallyEquivalent(Context, + cast(T1)->getPointeeType(), + cast(T2)->getPointeeType())) + return false; + break; + case Type::Pointer: if (!IsStructurallyEquivalent(Context, cast(T1)->getPointeeType(), diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index c799161e9b..9702d03245 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -1995,6 +1995,14 @@ ParmVarDecl *ParmVarDecl::Create(ASTContext &C, DeclContext *DC, S, DefArg); } +QualType ParmVarDecl::getOriginalType() const { + TypeSourceInfo *TSI = getTypeSourceInfo(); + QualType T = TSI ? TSI->getType() : getType(); + if (const DecayedType *DT = dyn_cast(T)) + return DT->getOriginalType(); + return T; +} + ParmVarDecl *ParmVarDecl::CreateDeserialized(ASTContext &C, unsigned ID) { void *Mem = AllocateDeserializedDecl(C, ID, sizeof(ParmVarDecl)); return new (Mem) ParmVarDecl(ParmVar, 0, SourceLocation(), SourceLocation(), diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp index 065465aa59..7102bf349b 100644 --- a/lib/AST/ItaniumMangle.cpp +++ b/lib/AST/ItaniumMangle.cpp @@ -828,6 +828,7 @@ void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier, switch (type->getTypeClass()) { case Type::Builtin: case Type::Complex: + case Type::Decayed: case Type::Pointer: case Type::BlockPointer: case Type::LValueReference: diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp index 2c439128f2..d19c6a9450 100644 --- a/lib/AST/TypePrinter.cpp +++ b/lib/AST/TypePrinter.cpp @@ -201,6 +201,7 @@ bool TypePrinter::canPrefixQualifiers(const Type *T, NeedARCStrongQualifier = true; // Fall through + case Type::Decayed: case Type::Pointer: case Type::BlockPointer: case Type::LValueReference: @@ -468,6 +469,14 @@ void TypePrinter::printVariableArrayAfter(const VariableArrayType *T, printAfter(T->getElementType(), OS); } +void TypePrinter::printDecayedBefore(const DecayedType *T, raw_ostream &OS) { + // Print as though it's a pointer. + printBefore(T->getDecayedType(), OS); +} +void TypePrinter::printDecayedAfter(const DecayedType *T, raw_ostream &OS) { + printAfter(T->getDecayedType(), OS); +} + void TypePrinter::printDependentSizedArrayBefore( const DependentSizedArrayType *T, raw_ostream &OS) { diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index e38327a927..9d2b23ed18 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -2069,6 +2069,10 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile Unit, return CreateType(cast(Ty)); case Type::Pointer: return CreateType(cast(Ty), Unit); + case Type::Decayed: + // Decayed types are just pointers in LLVM and DWARF. + return CreateType( + cast(cast(Ty)->getDecayedType()), Unit); case Type::BlockPointer: return CreateType(cast(Ty), Unit); case Type::Typedef: diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index 297fc655e4..c6b498cd58 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -1273,6 +1273,10 @@ void CodeGenFunction::EmitVariablyModifiedType(QualType type) { case Type::ObjCObjectPointer: llvm_unreachable("type class is never variably-modified!"); + case Type::Decayed: + type = cast(ty)->getPointeeType(); + break; + case Type::Pointer: type = cast(ty)->getPointeeType(); break; diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 27e8962f71..1d2f39c0da 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -4021,6 +4021,8 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc, static void DiagnoseCalleeStaticArrayParam(Sema &S, ParmVarDecl *PVD) { TypeLoc TL = PVD->getTypeSourceInfo()->getTypeLoc(); + if (DecayedTypeLoc DTL = TL.getAs()) + TL = DTL.getOriginalLoc(); if (ArrayTypeLoc ATL = TL.getAs()) S.Diag(PVD->getLocation(), diag::note_callee_static_array) << ATL.getLocalSourceRange(); diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index f5a28966f8..e1f0739aea 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -2844,10 +2844,6 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, QualType ArgTy = Param->getType(); assert(!ArgTy.isNull() && "Couldn't parse type?"); - // Adjust the parameter type. - assert((ArgTy == Context.getAdjustedParameterType(ArgTy)) && - "Unadjusted type?"); - // Look for 'void'. void is allowed only as a single argument to a // function with no other parameters (C99 6.7.5.3p10). We record // int(void) as a FunctionProtoType with an empty argument list. @@ -3577,6 +3573,9 @@ namespace { void VisitQualifiedTypeLoc(QualifiedTypeLoc TL) { llvm_unreachable("qualified type locs not expected here!"); } + void VisitDecayedTypeLoc(DecayedTypeLoc TL) { + llvm_unreachable("decayed type locs not expected here!"); + } void VisitAttributedTypeLoc(AttributedTypeLoc TL) { fillAttributedTypeLoc(TL, Chunk.getAttrs()); diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 86624c580e..9fbbe2cf1d 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -3585,6 +3585,22 @@ QualType TreeTransform::TransformComplexType(TypeLocBuilder &TLB, return TransformTypeSpecType(TLB, T); } +template +QualType TreeTransform::TransformDecayedType(TypeLocBuilder &TLB, + DecayedTypeLoc TL) { + QualType OriginalType = getDerived().TransformType(TLB, TL.getOriginalLoc()); + if (OriginalType.isNull()) + return QualType(); + + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || + OriginalType != TL.getOriginalLoc().getType()) + Result = SemaRef.Context.getDecayedType(OriginalType); + TLB.push(Result); + // Nothing to set for DecayedTypeLoc. + return Result; +} + template QualType TreeTransform::TransformPointerType(TypeLocBuilder &TLB, PointerTypeLoc TL) { diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index f33e0e14cf..052bef9e5b 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -4531,6 +4531,18 @@ QualType ASTReader::readTypeRecord(unsigned Index) { return Context.getPointerType(PointeeType); } + case TYPE_DECAYED: { + if (Record.size() != 1) { + Error("Incorrect encoding of decayed type"); + return QualType(); + } + QualType OriginalType = readType(*Loc.F, Record, Idx); + QualType DT = Context.getAdjustedParameterType(OriginalType); + if (!isa(DT)) + Error("Decayed type does not decay"); + return DT; + } + case TYPE_BLOCK_POINTER: { if (Record.size() != 1) { Error("Incorrect encoding of block pointer type"); @@ -4977,6 +4989,9 @@ void TypeLocReader::VisitComplexTypeLoc(ComplexTypeLoc TL) { void TypeLocReader::VisitPointerTypeLoc(PointerTypeLoc TL) { TL.setStarLoc(ReadSourceLocation(Record, Idx)); } +void TypeLocReader::VisitDecayedTypeLoc(DecayedTypeLoc 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 3654ec27f4..4a4128b4cf 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -108,6 +108,11 @@ void ASTTypeWriter::VisitPointerType(const PointerType *T) { Code = TYPE_POINTER; } +void ASTTypeWriter::VisitDecayedType(const DecayedType *T) { + Writer.AddTypeRef(T->getOriginalType(), Record); + Code = TYPE_DECAYED; +} + void ASTTypeWriter::VisitBlockPointerType(const BlockPointerType *T) { Writer.AddTypeRef(T->getPointeeType(), Record); Code = TYPE_BLOCK_POINTER; @@ -447,6 +452,9 @@ void TypeLocWriter::VisitComplexTypeLoc(ComplexTypeLoc TL) { void TypeLocWriter::VisitPointerTypeLoc(PointerTypeLoc TL) { Writer.AddSourceLocation(TL.getStarLoc(), Record); } +void TypeLocWriter::VisitDecayedTypeLoc(DecayedTypeLoc TL) { + // nothing to do +} void TypeLocWriter::VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL) { Writer.AddSourceLocation(TL.getCaretLoc(), Record); } diff --git a/test/Index/print-type.c b/test/Index/print-type.c index 4805f59f3f..03f0b7c89a 100644 --- a/test/Index/print-type.c +++ b/test/Index/print-type.c @@ -35,7 +35,7 @@ typedef int __attribute__((vector_size(16))) int4_t; // CHECK: DeclRefExpr=p:3:13 [type=int *] [typekind=Pointer] [isPOD=1] // CHECK: DeclRefExpr=z:3:33 [type=FooType] [typekind=Typedef] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1] // CHECK: ArraySubscriptExpr= [type=int] [typekind=Int] [isPOD=1] -// CHECK: DeclRefExpr=arr:3:40 [type=int *] [typekind=Pointer] [isPOD=1] +// CHECK: UnexposedExpr=arr:3:40 [type=int *] [typekind=Unexposed] [canonicaltype=int *] [canonicaltypekind=Pointer] [isPOD=1] // CHECK: IntegerLiteral= [type=int] [typekind=Int] [isPOD=1] // CHECK: TypedefDecl=OtherType:8:16 (Definition) [type=OtherType] [typekind=Typedef] [canonicaltype=double] [canonicaltypekind=Double] [isPOD=1] // CHECK: TypedefDecl=ArrayType:9:13 (Definition) [type=ArrayType] [typekind=Typedef] [canonicaltype=int [5]] [canonicaltypekind=ConstantArray] [isPOD=1] diff --git a/test/Sema/function.c b/test/Sema/function.c index bbf81a56cb..81d303c27f 100644 --- a/test/Sema/function.c +++ b/test/Sema/function.c @@ -103,3 +103,13 @@ int func_e(int x) { } return x + 3; } + +void decays(int a[3][3]); // expected-note {{passing argument to parameter 'a' here}} +void no_decay(int (*a)[3]); // expected-note {{passing argument to parameter 'a' here}} + +void t22(int *ptr, int (*array)[3]) { + decays(ptr); // expected-warning {{incompatible pointer types passing 'int *' to parameter of type 'int (*)[3]'}} + no_decay(ptr); // expected-warning {{incompatible pointer types passing 'int *' to parameter of type 'int (*)[3]'}} + decays(array); + no_decay(array); +} diff --git a/test/SemaCXX/function-type-qual.cpp b/test/SemaCXX/function-type-qual.cpp index ccb5747292..613ac9b200 100644 --- a/test/SemaCXX/function-type-qual.cpp +++ b/test/SemaCXX/function-type-qual.cpp @@ -29,3 +29,11 @@ cfn C::*mpg; // Don't crash! void (PR14171)() const; // expected-error {{non-member function cannot have 'const' qualifier}} + +// Test template instantiation of decayed array types. Not really related to +// type quals. +template void arrayDecay(const T a[]) { } +void instantiateArrayDecay() { + int a[1]; + arrayDecay(a); +} diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index 83b251968b..09bb0eba8f 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -1546,6 +1546,10 @@ bool CursorVisitor::VisitArrayTypeLoc(ArrayTypeLoc TL) { return false; } +bool CursorVisitor::VisitDecayedTypeLoc(DecayedTypeLoc 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 0958d52e79..17d70d6212 100644 --- a/tools/libclang/RecursiveASTVisitor.h +++ b/tools/libclang/RecursiveASTVisitor.h @@ -786,6 +786,10 @@ DEF_TRAVERSE_TYPE(MemberPointerType, { TRY_TO(TraverseType(T->getPointeeType())); }) +DEF_TRAVERSE_TYPE(DecayedType, { + TRY_TO(TraverseType(T->getOriginalType())); + }) + DEF_TRAVERSE_TYPE(ConstantArrayType, { TRY_TO(TraverseType(T->getElementType())); }) @@ -992,6 +996,10 @@ DEF_TRAVERSE_TYPELOC(MemberPointerType, { TRY_TO(TraverseTypeLoc(TL.getPointeeLoc())); }) +DEF_TRAVERSE_TYPELOC(DecayedType, { + TRY_TO(TraverseTypeLoc(TL.getOriginalLoc())); + }) + template bool RecursiveASTVisitor::TraverseArrayTypeLocHelper(ArrayTypeLoc TL) { // This isn't available for ArrayType, but is for the ArrayTypeLoc. -- 2.40.0