erik.pilkington updated this revision to Diff 168352. erik.pilkington added a comment.
Address @rsmith's review comments. https://reviews.llvm.org/D52521 Files: clang/include/clang/AST/DeclTemplate.h clang/lib/Sema/SemaTemplateInstantiate.cpp clang/test/SemaCXX/member-spec-dr727.cpp
Index: clang/test/SemaCXX/member-spec-dr727.cpp =================================================================== --- /dev/null +++ clang/test/SemaCXX/member-spec-dr727.cpp @@ -0,0 +1,52 @@ +// RUN: %clang_cc1 -std=c++17 -verify %s -emit-llvm -o - + +// expected-no-diagnostics + +namespace PR39031 { +template <class> +struct S { + template <class> + struct Wrapper; + + template <> + struct Wrapper<int> { + template <class T> + void f(T) { + T x; + } + }; +}; + +void Run() { + S<int>::Wrapper<int>().f(1); +} +} // namespace PR39031 + +template <class A, class B> struct is_same { static constexpr bool value = false; }; +template <class A> struct is_same<A, A> { static constexpr bool value = true; }; + +namespace t1 { +template <class Ap> struct A { + template <class Bp> struct B; + + template <> struct B<short> { + template <class Cp> struct C { + static_assert(is_same<Cp, int>::value); + static_assert(is_same<Ap, char>::value); + }; + }; +}; + +A<char>::B<short>::C<int> x; +} + +namespace t2 { +template <class Ap> +struct A { + template <class Bp> static constexpr int p = 0; + template <> static constexpr int p<int> = 1; +}; + +// FIXME: why aren't we selecting the specialization here? +static_assert(A<char>::p<int> == 0); +} Index: clang/lib/Sema/SemaTemplateInstantiate.cpp =================================================================== --- clang/lib/Sema/SemaTemplateInstantiate.cpp +++ clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -71,7 +71,8 @@ dyn_cast<VarTemplateSpecializationDecl>(D)) { // We're done when we hit an explicit specialization. if (Spec->getSpecializationKind() == TSK_ExplicitSpecialization && - !isa<VarTemplatePartialSpecializationDecl>(Spec)) + !isa<VarTemplatePartialSpecializationDecl>(Spec) && + !Spec->isClassScopeSpecialization()) return Result; Result.addOuterTemplateArguments(&Spec->getTemplateInstantiationArgs()); @@ -113,10 +114,19 @@ // Add template arguments from a class template instantiation. if (ClassTemplateSpecializationDecl *Spec = dyn_cast<ClassTemplateSpecializationDecl>(Ctx)) { - // We're done when we hit an explicit specialization. + // We're done when we hit an explicit specialization ... if (Spec->getSpecializationKind() == TSK_ExplicitSpecialization && - !isa<ClassTemplatePartialSpecializationDecl>(Spec)) + !isa<ClassTemplatePartialSpecializationDecl>(Spec)) { + // ... unless this explicit specialization is a member of a template + // (DR727), in which case we need to skip past it to gather the + // enclosing template argument lists. + if (Spec->isClassScopeSpecialization()) { + Ctx = Spec->getDeclContext(); + RelativeToPrimary = false; + continue; + } break; + } Result.addOuterTemplateArguments(&Spec->getTemplateInstantiationArgs()); Index: clang/include/clang/AST/DeclTemplate.h =================================================================== --- clang/include/clang/AST/DeclTemplate.h +++ clang/include/clang/AST/DeclTemplate.h @@ -1765,6 +1765,19 @@ PointOfInstantiation = Loc; } + /// If this class template specialization was declared at class scope, as + /// opposed to out-of-line (DR727). For example, G<int> below: + /// + /// \code + /// template <class T> struct S { + /// template <class> struct G {}; + /// template <> struct G<int> {}; + /// }; + /// \endcode + bool isClassScopeSpecialization() const { + return !getFirstDecl()->isOutOfLine(); + } + /// If this class template specialization is an instantiation of /// a template (rather than an explicit specialization), return the /// class template or class template partial specialization from which it @@ -2704,6 +2717,19 @@ return ExplicitInfo ? ExplicitInfo->TemplateKeywordLoc : SourceLocation(); } + /// If this variable template specialization was declared at class scope, as + /// opposed to out-of-line (DR727). For example, v<int> below: + /// + /// \code + /// template <class T> struct S { + /// template <class> static int v; + /// template <> static int v<int>; + /// }; + /// \endcode + bool isClassScopeSpecialization() const { + return !getFirstDecl()->isOutOfLine(); + } + void Profile(llvm::FoldingSetNodeID &ID) const { Profile(ID, TemplateArgs->asArray(), getASTContext()); }
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits