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
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits