]> granicus.if.org Git - clang/commitdiff
[modules] Handle defining a class template on top of an existing imported-but-not...
authorRichard Smith <richard-llvm@metafoo.co.uk>
Fri, 27 Mar 2015 00:41:57 +0000 (00:41 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Fri, 27 Mar 2015 00:41:57 +0000 (00:41 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@233341 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Sema/Lookup.h
include/clang/Sema/Sema.h
lib/Sema/SemaDecl.cpp
lib/Sema/SemaLookup.cpp
lib/Sema/SemaTemplate.cpp
test/Modules/Inputs/submodules-merge-defs/defs.h
test/Modules/submodules-merge-defs.cpp

index 8ba78bea594adbf76318a29b9bef4704332b5db0..5bfee8b0d037cb52ca1dbaa9721666556510eeb1 100644 (file)
@@ -291,9 +291,6 @@ public:
     if (!D->isHidden())
       return true;
 
-    if (SemaRef.ActiveTemplateInstantiations.empty())
-      return false;
-
     // During template instantiation, we can refer to hidden declarations, if
     // they were visible in any module along the path of instantiation.
     return isVisibleSlow(SemaRef, D);
index 21fe2e493c2942b0c6da92cc11cd2877dd3e0744..6cf86e29dae00a3759bd7c92913330c0bff95965 100644 (file)
@@ -5344,7 +5344,8 @@ public:
                                 SourceLocation ModulePrivateLoc,
                                 SourceLocation FriendLoc,
                                 unsigned NumOuterTemplateParamLists,
-                            TemplateParameterList **OuterTemplateParamLists);
+                            TemplateParameterList **OuterTemplateParamLists,
+                                bool *SkipBody = nullptr);
 
   void translateTemplateArguments(const ASTTemplateArgsPtr &In,
                                   TemplateArgumentListInfo &Out);
index ffd22390ee3596f8e21f8f884956cea2948f86d0..e9c40aa2e5d34d92d3f28773faa4cf3250d64035 100644 (file)
@@ -11297,7 +11297,8 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
                                                ModulePrivateLoc,
                                                /*FriendLoc*/SourceLocation(),
                                                TemplateParameterLists.size()-1,
-                                               TemplateParameterLists.data());
+                                               TemplateParameterLists.data(),
+                                               SkipBody);
         return Result.get();
       } else {
         // The "template<>" header is extraneous.
@@ -11696,8 +11697,9 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
                     TSK_ExplicitSpecialization;
               }
 
+              NamedDecl *Hidden = nullptr;
               if (SkipBody && getLangOpts().CPlusPlus &&
-                  !hasVisibleDefinition(Def, &Def)) {
+                  !hasVisibleDefinition(Def, &Hidden)) {
                 // There is a definition of this tag, but it is not visible. We
                 // explicitly make use of C++'s one definition rule here, and
                 // assume that this definition is identical to the hidden one
@@ -11705,8 +11707,8 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
                 // use it in place of this one.
                 *SkipBody = true;
                 if (auto *Listener = getASTMutationListener())
-                  Listener->RedefinedHiddenDefinition(Def, KWLoc);
-                Def->setHidden(false);
+                  Listener->RedefinedHiddenDefinition(Hidden, KWLoc);
+                Hidden->setHidden(false);
                 return Def;
               } else if (!IsExplicitSpecializationAfterInstantiation) {
                 // A redeclaration in function prototype scope in C isn't
index 0b406184058202a4eddb325123310b555b95a213..ac7376efbc4105694cc40de217db07caa5bfc663 100644 (file)
@@ -1217,11 +1217,27 @@ llvm::DenseSet<Module*> &Sema::getLookupModules() {
 /// path (by instantiating a template, you allow it to see the declarations that
 /// your module can see, including those later on in your module).
 bool LookupResult::isVisibleSlow(Sema &SemaRef, NamedDecl *D) {
-  assert(D->isHidden() && !SemaRef.ActiveTemplateInstantiations.empty() &&
-         "should not call this: not in slow case");
+  assert(D->isHidden() && "should not call this: not in slow case");
   Module *DeclModule = D->getOwningModule();
   assert(DeclModule && "hidden decl not from a module");
 
+  // If this declaration is not at namespace scope nor module-private,
+  // then it is visible if its lexical parent has a visible definition.
+  DeclContext *DC = D->getLexicalDeclContext();
+  if (!D->isModulePrivate() &&
+      DC && !DC->isFileContext() && !isa<LinkageSpecDecl>(DC)) {
+    NamedDecl *Hidden;
+    if (SemaRef.hasVisibleDefinition(cast<NamedDecl>(DC), &Hidden)) {
+      if (SemaRef.ActiveTemplateInstantiations.empty()) {
+        // Cache the fact that this declaration is implicitly visible because
+        // its parent has a visible definition.
+        D->setHidden(false);
+      }
+      return true;
+    }
+    return false;
+  }
+
   // Find the extra places where we need to look.
   llvm::DenseSet<Module*> &LookupModules = SemaRef.getLookupModules();
   if (LookupModules.empty())
index 805709dab804665fa66b9dd7f076e5a44e81d141..c642c0599b5603bc73cfb73f414bffaee0d17333 100644 (file)
@@ -12,6 +12,7 @@
 #include "TreeTransform.h"
 #include "clang/AST/ASTConsumer.h"
 #include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTMutationListener.h"
 #include "clang/AST/DeclFriend.h"
 #include "clang/AST/DeclTemplate.h"
 #include "clang/AST/Expr.h"
@@ -836,7 +837,8 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
                          AccessSpecifier AS, SourceLocation ModulePrivateLoc,
                          SourceLocation FriendLoc,
                          unsigned NumOuterTemplateParamLists,
-                         TemplateParameterList** OuterTemplateParamLists) {
+                         TemplateParameterList** OuterTemplateParamLists,
+                         bool *SkipBody) {
   assert(TemplateParams && TemplateParams->size() > 0 &&
          "No template parameters");
   assert(TUK != TUK_Reference && "Can only declare or define class templates");
@@ -993,6 +995,23 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
     // Check for redefinition of this class template.
     if (TUK == TUK_Definition) {
       if (TagDecl *Def = PrevRecordDecl->getDefinition()) {
+        // If we have a prior definition that is not visible, treat this as
+        // simply making that previous definition visible.
+        NamedDecl *Hidden = nullptr;
+        if (SkipBody && !hasVisibleDefinition(Def, &Hidden)) {
+          *SkipBody = true;
+          auto *Tmpl = cast<CXXRecordDecl>(Hidden)->getDescribedClassTemplate();
+          assert(Tmpl && "original definition of a class template is not a "
+                         "class template?");
+          if (auto *Listener = getASTMutationListener()) {
+            Listener->RedefinedHiddenDefinition(Hidden, KWLoc);
+            Listener->RedefinedHiddenDefinition(Tmpl, KWLoc);
+          }
+          Hidden->setHidden(false);
+          Tmpl->setHidden(false);
+          return Def;
+        }
+
         Diag(NameLoc, diag::err_redefinition) << Name;
         Diag(Def->getLocation(), diag::note_previous_definition);
         // FIXME: Would it make sense to try to "forget" the previous
index 1c866b55aad34d277a0ed330c162ecb4d5ca7b10..dfb58adcbcd05b0d31613841c510e4ea5516673b 100644 (file)
@@ -1,6 +1,16 @@
-struct A {};
+struct A { int a_member; };
+namespace { inline int use_a(A a) { return a.a_member; } }
+
 class B {
   struct Inner1 {};
+public:
   struct Inner2;
 };
+// Check that lookup and access checks are performed in the right context.
 struct B::Inner2 : Inner1 {};
+
+// Check that base-specifiers are correctly disambiguated.
+template<int N> struct C_Base { struct D { constexpr operator int() const { return 0; } }; };
+const int C_Const = 0;
+struct C1 : C_Base<C_Base<0>::D{}> {} extern c1;
+struct C2 : C_Base<C_Const<0>::D{} extern c2;
index 48d4feb7cfe884f2e5889d670c36f5ec76d50e32..9b5b13d63fc1d4f18cc7a1e75d5c6b3e499d2eeb 100644 (file)
@@ -1,5 +1,5 @@
 // RUN: rm -rf %t
-// RUN: %clang_cc1 -x c++ -fmodules-cache-path=%t -fmodules -I %S/Inputs/submodules-merge-defs %s -verify -fno-modules-error-recovery
+// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules-cache-path=%t -fmodules -I %S/Inputs/submodules-merge-defs %s -verify -fno-modules-error-recovery
 
 // Trigger import of definitions, but don't make them visible.
 #include "empty.h"
@@ -7,7 +7,22 @@
 A pre_a; // expected-error {{must be imported}} expected-error {{must use 'struct'}}
 // expected-note@defs.h:1 {{here}}
 
+B::Inner2 pre_bi; // expected-error +{{must be imported}}
+// expected-note@defs.h:4 +{{here}}
+// expected-note@defs.h:10 +{{here}}
+
+C_Base<1> pre_cb1; // expected-error +{{must be imported}}
+// expected-note@defs.h:13 +{{here}}
+C1 pre_c1; // expected-error +{{must be imported}} expected-error {{must use 'struct'}}
+// expected-note@defs.h:15 +{{here}}
+C2 pre_c2; // expected-error +{{must be imported}} expected-error {{must use 'struct'}}
+// expected-note@defs.h:16 +{{here}}
+
 // Make definitions from second module visible.
 #include "import-and-redefine.h"
 
 A post_a;
+B::Inner2 post_bi;
+C_Base<1> post_cb1;
+C1 c1;
+C2 c2;