diff options
24 files changed, 246 insertions, 27 deletions
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index ebbf6c99e66..ae7a8f14d44 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -82,6 +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<BlockPointerType> BlockPointerTypes; mutable llvm::FoldingSet<LValueReferenceType> LValueReferenceTypes; mutable llvm::FoldingSet<RValueReferenceType> 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/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index 5d94278e99d..25e37099f88 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/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/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index 1072b97a14a..df71bffe850 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/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<typename Derived> bool RecursiveASTVisitor<Derived>::TraverseArrayTypeLocHelper(ArrayTypeLoc TL) { // This isn't available for ArrayType, but is for the ArrayTypeLoc. diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index bd2e18878ee..2566268a626 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/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<PointerType>(DecayedPointer)); + } + + 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(); + } + + 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/clang/include/clang/AST/TypeLoc.h b/clang/include/clang/AST/TypeLoc.h index 1eb8835f4d6..a028a6f35c8 100644 --- a/clang/include/clang/AST/TypeLoc.h +++ b/clang/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<UnqualTypeLoc, DecayedTypeLoc, + DecayedType, DecayedLocInfo> { +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/clang/include/clang/AST/TypeNodes.def b/clang/include/clang/AST/TypeNodes.def index 840e07d94a0..a29ae231e94 100644 --- a/clang/include/clang/AST/TypeNodes.def +++ b/clang/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/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h index 651b4a9df2d..ec05cc216bf 100644 --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/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/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 70c933e7521..91059400761 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -1615,6 +1615,8 @@ ASTContext::getTypeInfoImpl(const Type *T) const { } case Type::ObjCObject: return getTypeInfo(cast<ObjCObjectType>(T)->getBaseType().getTypePtr()); + case Type::Decayed: + return getTypeInfo(cast<DecayedType>(T)->getDecayedType().getTypePtr()); case Type::ObjCInterface: { const ObjCInterfaceType *ObjCI = cast<ObjCInterfaceType>(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/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 41a67af64d6..84904580162 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -400,6 +400,13 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, return false; break; + case Type::Decayed: + if (!IsStructurallyEquivalent(Context, + cast<DecayedType>(T1)->getPointeeType(), + cast<DecayedType>(T2)->getPointeeType())) + return false; + break; + case Type::Pointer: if (!IsStructurallyEquivalent(Context, cast<PointerType>(T1)->getPointeeType(), diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index c799161e9b7..9702d032453 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/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<DecayedType>(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/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 065465aa59e..7102bf349b2 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/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/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp index 2c439128f2d..d19c6a94508 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/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/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index e38327a9270..9d2b23ed185 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -2069,6 +2069,10 @@ 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::Decayed: + // Decayed types are just pointers in LLVM and DWARF. + return CreateType( + cast<PointerType>(cast<DecayedType>(Ty)->getDecayedType()), Unit); case Type::BlockPointer: return CreateType(cast<BlockPointerType>(Ty), Unit); case Type::Typedef: diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index 297fc655e44..c6b498cd586 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/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<DecayedType>(ty)->getPointeeType(); + break; + case Type::Pointer: type = cast<PointerType>(ty)->getPointeeType(); break; diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 27e8962f71b..1d2f39c0da3 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/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<DecayedTypeLoc>()) + TL = DTL.getOriginalLoc(); if (ArrayTypeLoc ATL = TL.getAs<ArrayTypeLoc>()) S.Diag(PVD->getLocation(), diag::note_callee_static_array) << ATL.getLocalSourceRange(); diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index f5a28966f86..e1f0739aea7 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/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/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 86624c580e5..9fbbe2cf1d5 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -3586,6 +3586,22 @@ QualType TreeTransform<Derived>::TransformComplexType(TypeLocBuilder &TLB, } template<typename Derived> +QualType TreeTransform<Derived>::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<DecayedTypeLoc>(Result); + // Nothing to set for DecayedTypeLoc. + return Result; +} + +template<typename Derived> QualType TreeTransform<Derived>::TransformPointerType(TypeLocBuilder &TLB, PointerTypeLoc TL) { QualType PointeeType diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index f33e0e14cf6..052bef9e5be 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/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<DecayedType>(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/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index 3654ec27f40..4a4128b4cfd 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/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/clang/test/Index/print-type.c b/clang/test/Index/print-type.c index 4805f59f3fe..03f0b7c89ad 100644 --- a/clang/test/Index/print-type.c +++ b/clang/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/clang/test/Sema/function.c b/clang/test/Sema/function.c index bbf81a56cbb..81d303c27f6 100644 --- a/clang/test/Sema/function.c +++ b/clang/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/clang/test/SemaCXX/function-type-qual.cpp b/clang/test/SemaCXX/function-type-qual.cpp index ccb57472925..613ac9b200f 100644 --- a/clang/test/SemaCXX/function-type-qual.cpp +++ b/clang/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 <typename T> void arrayDecay(const T a[]) { } +void instantiateArrayDecay() { + int a[1]; + arrayDecay(a); +} diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index 83b251968bc..09bb0eba8f5 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/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/clang/tools/libclang/RecursiveASTVisitor.h b/clang/tools/libclang/RecursiveASTVisitor.h index 0958d52e79c..17d70d6212e 100644 --- a/clang/tools/libclang/RecursiveASTVisitor.h +++ b/clang/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<typename Derived> bool RecursiveASTVisitor<Derived>::TraverseArrayTypeLocHelper(ArrayTypeLoc TL) { // This isn't available for ArrayType, but is for the ArrayTypeLoc. |