]> granicus.if.org Git - clang/commitdiff
Properly switch into the declaring scope of a template when performing
authorJohn McCall <rjmccall@apple.com>
Thu, 29 Apr 2010 00:35:03 +0000 (00:35 +0000)
committerJohn McCall <rjmccall@apple.com>
Thu, 29 Apr 2010 00:35:03 +0000 (00:35 +0000)
template argument deduction or (more importantly) the final substitution
required by such deduction.  Makes access control magically work in these
cases.

Fixes PR6967.

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

lib/Sema/Sema.h
lib/Sema/SemaTemplateDeduction.cpp
lib/Sema/SemaTemplateInstantiate.cpp
test/CXX/class.access/p6.cpp

index f6af46eca9ae7d9f1d64053e00781b0c0b0af04b..02a86cd94db804ff660a1be7ed37c6a1776c4bef 100644 (file)
@@ -233,6 +233,30 @@ public:
   /// CurContext - This is the current declaration context of parsing.
   DeclContext *CurContext;
 
+  /// A RAII object to temporarily push a declaration context.
+  class ContextRAII {
+  private:
+    Sema &S;
+    DeclContext *SavedContext;
+
+  public:
+    ContextRAII(Sema &S, DeclContext *ContextToPush)
+      : S(S), SavedContext(S.CurContext) {
+      assert(ContextToPush && "pushing null context");
+      S.CurContext = ContextToPush;
+    }
+
+    void pop() {
+      if (!SavedContext) return;
+      S.CurContext = SavedContext;
+      SavedContext = 0;
+    }
+
+    ~ContextRAII() {
+      pop();
+    }
+  };
+
   /// PackContext - Manages the stack for #pragma pack. An alignment
   /// of 0 indicates default alignment.
   void *PackContext; // Really a "PragmaPackStack*"
index 0a2c5ae00e0af64587b2744ae61e9344b3cbc375..13bfc0fdf9e902d3e1af237b24e6cf246266193a 100644 (file)
@@ -988,6 +988,8 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
   if (Inst)
     return TDK_InstantiationDepth;
 
+  ContextRAII SavedContext(*this, Partial->getDeclContext());
+
   // C++ [temp.deduct.type]p2:
   //   [...] or if any template argument remains neither deduced nor
   //   explicitly specified, template argument deduction fails.
@@ -1163,6 +1165,8 @@ Sema::SubstituteExplicitTemplateArguments(
   if (Inst)
     return TDK_InstantiationDepth;
 
+  ContextRAII SavedContext(*this, FunctionTemplate->getDeclContext());
+
   if (CheckTemplateArgumentList(FunctionTemplate,
                                 SourceLocation(),
                                 ExplicitTemplateArgs,
@@ -1311,6 +1315,8 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
   if (Inst)
     return TDK_InstantiationDepth;
 
+  ContextRAII SavedContext(*this, FunctionTemplate->getDeclContext());
+
   // C++ [temp.deduct.type]p2:
   //   [...] or if any template argument remains neither deduced nor
   //   explicitly specified, template argument deduction fails.
index 6fdf243d7bbc47d90084dbca09d8bc1054607658..7dee0ad99bfb9113387ab22b729727963eadbd72 100644 (file)
@@ -1167,8 +1167,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
 
   // Enter the scope of this instantiation. We don't use
   // PushDeclContext because we don't have a scope.
-  DeclContext *PreviousContext = CurContext;
-  CurContext = Instantiation;
+  ContextRAII SavedContext(*this, Instantiation);
 
   // If this is an instantiation of a local class, merge this local
   // instantiation scope with the enclosing scope. Otherwise, every
@@ -1209,7 +1208,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
     Invalid = true;
   
   // Exit the scope of this instantiation.
-  CurContext = PreviousContext;
+  SavedContext.pop();
 
   // If this is a polymorphic C++ class without a key function, we'll
   // have to mark all of the virtual members to allow emission of a vtable
index d51d75d05d6dd3f1de829ed66f7c9b466f8b8c2e..814265d0b049d463f9fe02807162421af7ba60da 100644 (file)
@@ -52,3 +52,56 @@ namespace test1 {
     A apriv = priv; // expected-error {{private constructor}}
   }
 }
+
+// PR6967
+namespace test2 {
+  class A {
+  public:
+    template <class T> static void set(T &t, typename T::type v) {
+      t.value = v;
+    }
+    template <class T> static typename T::type get(const T &t) {
+      return t.value;
+    }
+  };
+
+  class B {
+    friend class A;
+
+  private:
+    typedef int type;
+    type value;
+  };
+
+  int test() {
+    B b;
+    A::set(b, 0);
+    return A::get(b);
+  }
+}
+
+namespace test3 {
+  class Green {}; class Blue {};
+
+  // We have to wrap this in a class because a partial specialization
+  // isn't actually in the context of the template.
+  struct Outer {
+    template <class T, class Nat> class A {
+    };
+  };
+
+  template <class T> class Outer::A<T, typename T::nature> {
+  public:
+    static void foo();
+  };
+
+  class B {
+  private: typedef Green nature;
+    friend class Outer;
+  };
+
+  void test() {
+    Outer::A<B, Green>::foo();
+    Outer::A<B, Blue>::foo(); // expected-error {{no member named 'foo'}}
+  }
+}