]> granicus.if.org Git - clang/commitdiff
[modules] Put class template declarations into the scope in which they're
authorRichard Smith <richard-llvm@metafoo.co.uk>
Sat, 23 Aug 2014 00:49:01 +0000 (00:49 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Sat, 23 Aug 2014 00:49:01 +0000 (00:49 +0000)
declared, rather than putting them into the template parameter scope. We
previously had *no record* in the scope for class template declarations, once
those declarations completed and their template parameter scopes were popped.
This in turn caused us to be unable to merge class template declarations that
were declared in the global scope (where we use scope lookup rather than
DeclContext lookup for merging), when loading a module.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@216311 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaTemplate.cpp
test/Modules/Inputs/cxx-templates-common.h
test/Modules/Inputs/cxx-templates-textual.h [new file with mode: 0644]
test/Modules/cxx-templates.cpp

index 63581a44dbe5b365004bec3a552bc8b5e6279f36..fb05718ff1b5571b26cf714d4ed8c9220b43e1ec 100644 (file)
@@ -1105,9 +1105,13 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
 
   AddPushedVisibilityAttribute(NewClass);
 
-  if (TUK != TUK_Friend)
-    PushOnScopeChains(NewTemplate, S);
-  else {
+  if (TUK != TUK_Friend) {
+    // Per C++ [basic.scope.temp]p2, skip the template parameter scopes.
+    Scope *Outer = S;
+    while ((Outer->getFlags() & Scope::TemplateParamScope) != 0)
+      Outer = Outer->getParent();
+    PushOnScopeChains(NewTemplate, Outer);
+  } else {
     if (PrevClassTemplate && PrevClassTemplate->getAccess() != AS_none) {
       NewTemplate->setAccess(PrevClassTemplate->getAccess());
       NewClass->setAccess(PrevClassTemplate->getAccess());
index f7c083249f8a9dcb0aa535aa82277134ca64e0d4..f3c9022309110ee7cf51d92cecf2ac2c32d80ab7 100644 (file)
@@ -40,3 +40,5 @@ template<typename T> struct WithExplicitSpecialization;
 typedef WithExplicitSpecialization<int> WithExplicitSpecializationUse;
 
 template<typename T> struct WithImplicitSpecialMembers { int n; };
+
+#include "cxx-templates-textual.h"
diff --git a/test/Modules/Inputs/cxx-templates-textual.h b/test/Modules/Inputs/cxx-templates-textual.h
new file mode 100644 (file)
index 0000000..8bffb8e
--- /dev/null
@@ -0,0 +1,2 @@
+template<typename T> struct MergeClassTemplateSpecializations_basic_string {};
+typedef MergeClassTemplateSpecializations_basic_string<char> MergeClassTemplateSpecializations_string;
index c173d670802f6a2128457fca73d65a52677eb7b1..fedaa03ef4fc5426c7738a825c5a29017de0b27b 100644 (file)
@@ -3,6 +3,11 @@
 // RUN: not %clang_cc1 -x objective-c++ -fmodules -fno-modules-error-recovery -fmodules-cache-path=%t -I %S/Inputs %s -std=c++11 -ast-dump-lookups -ast-dump-filter N | FileCheck %s --check-prefix=CHECK-NAMESPACE-N
 // RUN: not %clang_cc1 -x objective-c++ -fmodules -fno-modules-error-recovery -fmodules-cache-path=%t -I %S/Inputs %s -std=c++11 -ast-dump | FileCheck %s --check-prefix=CHECK-DUMP
 // RUN: %clang_cc1 -x objective-c++ -fmodules -fno-modules-error-recovery -fmodules-cache-path=%t -I %S/Inputs %s -verify -std=c++11
+// RUN: %clang_cc1 -x objective-c++ -fmodules -fno-modules-error-recovery -fmodules-cache-path=%t -I %S/Inputs %s -verify -std=c++11 -DEARLY_IMPORT
+
+#ifdef EARLY_IMPORT
+#include "cxx-templates-textual.h"
+#endif
 
 @import cxx_templates_a;
 @import cxx_templates_b;
@@ -22,8 +27,14 @@ void g() {
   f<double>(1.0);
   f<int>();
   f(); // expected-error {{no matching function}}
+#ifdef EARLY_IMPORT
+  // FIXME: The textual inclusion above shouldn't affect this!
+  // expected-note@Inputs/cxx-templates-a.h:3 {{couldn't infer template argument}}
+  // expected-note@Inputs/cxx-templates-a.h:4 {{requires 1 argument}}
+#else
   // expected-note@Inputs/cxx-templates-b.h:3 {{couldn't infer template argument}}
   // expected-note@Inputs/cxx-templates-b.h:4 {{requires single argument}}
+#endif
 
   N::f(0);
   N::f<double>(1.0);
@@ -108,11 +119,15 @@ void g() {
   int *r = PartiallyInstantiatePartialSpec<int*>::bar();
 
   (void)&WithImplicitSpecialMembers<int>::n;
+
+  MergeClassTemplateSpecializations_string s;
 }
 
 static_assert(Outer<int>::Inner<int>::f() == 1, "");
 static_assert(Outer<int>::Inner<int>::g() == 2, "");
 
+#ifndef EARLY_IMPORT
+// FIXME: The textual inclusion above shouldn't cause this to fail!
 static_assert(MergeTemplateDefinitions<int>::f() == 1, "");
 static_assert(MergeTemplateDefinitions<int>::g() == 2, "");
 
@@ -126,6 +141,7 @@ MergeSpecializations<int[]>::partially_specialized_in_c spec_in_c_1;
 MergeSpecializations<char>::explicitly_specialized_in_a spec_in_a_2;
 MergeSpecializations<double>::explicitly_specialized_in_b spec_in_b_2;
 MergeSpecializations<bool>::explicitly_specialized_in_c spec_in_c_2;
+#endif
 
 @import cxx_templates_common;