Index: clang/include/clang/AST/Type.h =================================================================== --- clang/include/clang/AST/Type.h +++ clang/include/clang/AST/Type.h @@ -1891,6 +1891,9 @@ /// SVE vector or predicate, excluding tuple types such as svint32x4_t. bool isVLSTBuiltinType() const; + /// Returns the inner most Pointer Type node. + const PointerType *getInnerMostPointerType() const; + /// Returns the representative type for the element of an SVE builtin type. /// This is used to represent fixed-length SVE vectors created with the /// 'arm_sve_vector_bits' type attribute as VectorType. Index: clang/lib/AST/TemplateBase.cpp =================================================================== --- clang/lib/AST/TemplateBase.cpp +++ clang/lib/AST/TemplateBase.cpp @@ -359,8 +359,27 @@ break; } } - if (!getParamTypeForDecl()->isReferenceType()) - Out << '&'; + bool needsRef = true; + if (auto *VD = dyn_cast(ND)) { + const clang::Type *ArgTy = VD->getType()->getUnqualifiedDesugaredType(); + const clang::Type *ParmTy = + getParamTypeForDecl()->getUnqualifiedDesugaredType(); + clang::ASTContext &Ctx = ND->getASTContext(); + needsRef = !Ctx.hasSameType(ArgTy, ParmTy); + if (needsRef && (ArgTy->isArrayType() || ArgTy->isFunctionType())) { + const clang::Type *decayedArgTy = + Ctx.getDecayedType(clang::QualType(ArgTy, 0)).getTypePtr(); + const clang::QualType InnerArgTy = + clang::QualType(ArgTy->getInnerMostPointerType(), 0); + const clang::QualType InnerParmTy = + clang::QualType(ParmTy->getInnerMostPointerType(), 0); + needsRef = + !(Ctx.hasSameType(decayedArgTy, ParmTy) || + InnerArgTy.getAsString().compare(InnerParmTy.getAsString()) == 0); + } + } + if (!getParamTypeForDecl()->isReferenceType() && needsRef) + Out << "&"; ND->printQualifiedName(Out); break; } Index: clang/lib/AST/Type.cpp =================================================================== --- clang/lib/AST/Type.cpp +++ clang/lib/AST/Type.cpp @@ -2313,6 +2313,26 @@ return false; } +const PointerType *Type::getInnerMostPointerType() const { + const PointerType *res = nullptr; + const Type *T = this; + + while (true) { + const Type *pointeeOrElement = T->getPointeeOrArrayElementType(); + if (pointeeOrElement == T) + // T is neither a pointer nor array type: we’re done. + break; + + // T is a pointer or array type. + if (isa(T)) + res = cast(T); + + // iterate T, keep looking + T = pointeeOrElement; + } + return res; +} + QualType Type::getSveEltType(const ASTContext &Ctx) const { assert(isVLSTBuiltinType() && "unsupported type!"); Index: clang/test/CodeGenCXX/debug-info-codeview-display-name.cpp =================================================================== --- clang/test/CodeGenCXX/debug-info-codeview-display-name.cpp +++ clang/test/CodeGenCXX/debug-info-codeview-display-name.cpp @@ -98,7 +98,7 @@ void fn_tmpl() {} template void fn_tmpl(); -// CHECK-DAG: "fn_tmpl" +// CHECK-DAG: "fn_tmpl" template struct ClassTemplate { A a; B b; C c; }; ClassTemplate > f; Index: clang/test/CodeGenCXX/debug-info-template.cpp =================================================================== --- clang/test/CodeGenCXX/debug-info-template.cpp +++ clang/test/CodeGenCXX/debug-info-template.cpp @@ -1,6 +1,6 @@ // RUN: %clang -S -emit-llvm -target x86_64-unknown_unknown -g %s -o - -std=c++11 | FileCheck %s -// CHECK: @tci = dso_local global %"struct.TC::nested" zeroinitializer, align 1, !dbg [[TCI:![0-9]+]] +// CHECK: @tci = dso_local global %"struct.TC::nested" zeroinitializer, align 1, !dbg [[TCI:![0-9]+]] // CHECK: @tcn = dso_local global %struct.TC zeroinitializer, align 1, !dbg [[TCN:![0-9]+]] // CHECK: @nn = dso_local global %struct.NN zeroinitializer, align 1, !dbg [[NN:![0-9]+]] @@ -31,7 +31,7 @@ // CHECK: ![[TCNESTED]] ={{.*}}!DICompositeType(tag: DW_TAG_structure_type, name: "nested", // CHECK-SAME: scope: ![[TC:[0-9]+]], -// CHECK: ![[TC]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "TC" +// CHECK: ![[TC]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "TC" // CHECK-SAME: templateParams: [[TCARGS:![0-9]*]] TC // CHECK: [[TCARGS]] = !{[[TCARG1:![0-9]*]], [[TCARG2:![0-9]*]], [[TCARG3:![0-9]*]], [[TCARG4:![0-9]*]], [[TCARG5:![0-9]*]], [[TCARG6:![0-9]*]], [[TCARG7:![0-9]*]]} Index: clang/test/SemaTemplate/temp_arg_nontype_cxx11.cpp =================================================================== --- clang/test/SemaTemplate/temp_arg_nontype_cxx11.cpp +++ clang/test/SemaTemplate/temp_arg_nontype_cxx11.cpp @@ -65,3 +65,26 @@ void use() { f(); } } + +using FourChars = const char[4]; +constexpr FourChars kEta = "Eta"; +constexpr const char *kNull = "Phi"; + +template class Column {}; +template class Dolumn {}; +template class Folumn {}; +template class Golumn {}; +template class Holumn {}; + +constexpr const char **kZero[] = {}; +template class Jolumn {}; + +void lookup() { + Column().ls(); // expected-error {{().ls(); // expected-error {{().ls(); // expected-error {{().ls(); // expected-error {{<&kEta,}} + Golumn<&kEta, double>().ls(); // expected-error {{<&kEta,}} + Holumn<&kNull, double>().ls(); // expected-error {{<&kNull,}} + Jolumn().ls(); // expected-error {{