]> granicus.if.org Git - clang/commitdiff
Provide Decl::getOwningModule(), which determines the (sub)module in
authorDouglas Gregor <dgregor@apple.com>
Sat, 12 Jan 2013 01:29:50 +0000 (01:29 +0000)
committerDouglas Gregor <dgregor@apple.com>
Sat, 12 Jan 2013 01:29:50 +0000 (01:29 +0000)
which a particular declaration resides. Use this information to
customize the "definition of 'blah' must be imported from another
module" diagnostic with the module the user actually has to
import. Additionally, recover by importing that module, so we don't
complain about other names in that module.

Still TODO: coming up with decent Fix-Its for these cases, and expand
this recovery approach for other name lookup failures.

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

15 files changed:
include/clang/AST/DeclBase.h
include/clang/AST/ExternalASTSource.h
include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Frontend/ASTUnit.h
include/clang/Frontend/CompilerInstance.h
include/clang/Lex/ModuleLoader.h
include/clang/Sema/Lookup.h
include/clang/Sema/Sema.h
include/clang/Serialization/ASTReader.h
lib/AST/DeclBase.cpp
lib/Frontend/CompilerInstance.cpp
lib/Sema/SemaDecl.cpp
lib/Sema/SemaType.cpp
lib/Serialization/ASTReader.cpp
test/Modules/decldef.mm

index 823340aeaf0ea5c67e701f42f18b832625cede68..c91284d54a000a9689b1895027714b3d31bed25b 100644 (file)
@@ -32,6 +32,7 @@ class DependentDiagnostic;
 class EnumDecl;
 class FunctionDecl;
 class LinkageSpecDecl;
+class Module;
 class NamedDecl;
 class NamespaceDecl;
 class ObjCCategoryDecl;
@@ -593,7 +594,18 @@ public:
     
     return 0;
   }
-  
+
+private:
+  Module *getOwningModuleSlow() const;
+
+public:
+  Module *getOwningModule() const {
+    if (!isFromASTFile())
+      return 0;
+
+    return getOwningModuleSlow();
+  }
+
   unsigned getIdentifierNamespace() const {
     return IdentifierNamespace;
   }
index 871912ac09dfcdde07bcb3c4520e8446fc7228b2..501f8a796dfc779429f1d2a224cce17570162d34 100644 (file)
@@ -25,6 +25,7 @@ class CXXBaseSpecifier;
 class DeclarationName;
 class ExternalSemaSource; // layering violation required for downcasting
 class FieldDecl;
+class Module;
 class NamedDecl;
 class RecordDecl;
 class Selector;
@@ -131,9 +132,12 @@ public:
   /// \brief Ensures that the table of all visible declarations inside this
   /// context is up to date.
   ///
-  /// The default implementation of this functino is a no-op.
+  /// The default implementation of this function is a no-op.
   virtual void completeVisibleDeclsMap(const DeclContext *DC);
 
+  /// \brief Retrieve the module that corresponds to the given module ID.
+  virtual Module *getModule(unsigned ID) { return 0; }
+
   /// \brief Finds all declarations lexically contained within the given
   /// DeclContext, after applying an optional filter predicate.
   ///
index 0b1917a46d28d5ae4ff483ecc95e5282c1ac2271..7d6fc992644bf716a428ab27f41acaa6de8deb4e 100644 (file)
@@ -6082,7 +6082,7 @@ def err_module_private_local_class : Error<
   "local %select{struct|interface|union|class|enum}0 cannot be declared "
   "__module_private__">;
 def err_module_private_definition : Error<
-  "definition of %0 must be imported before it is required">;
+  "definition of %0 must be imported from module '%1' before it is required">;
 }
 
 let CategoryName = "Documentation Issue" in {
index 2e929d98ce5983aa14c2047954d6ebcc65868de0..3701cdc2e44f8ab16541125eff2438da40be8032 100644 (file)
@@ -837,6 +837,10 @@ public:
     // ASTUnit doesn't know how to load modules (not that this matters).
     return ModuleLoadResult();
   }
+
+  virtual void makeModuleVisible(Module *Mod,
+                                 Module::NameVisibilityKind Visibility) { }
+
 };
 
 } // namespace clang
index ec2fead280ac09bf26401d8e8463284a2c813f29..2d6a8702dc646436dc5eac6689a91d71680c80b1 100644 (file)
@@ -649,6 +649,10 @@ public:
                                       ModuleIdPath Path,
                                       Module::NameVisibilityKind Visibility,
                                       bool IsInclusionDirective);
+
+  virtual void makeModuleVisible(Module *Mod,
+                                 Module::NameVisibilityKind Visibility);
+
 };
 
 } // end namespace clang
index 3a5f41d510b1964f697d16954d5659b03d12d846..f086c082f9d2ce5a3532bc6a65e2d00ee8891731 100644 (file)
@@ -80,6 +80,10 @@ public:
                                       ModuleIdPath Path,
                                       Module::NameVisibilityKind Visibility,
                                       bool IsInclusionDirective) = 0;
+
+  /// \brief Make the given module visible.
+  virtual void makeModuleVisible(Module *Mod,
+                                 Module::NameVisibilityKind Visibility) = 0;
 };
   
 }
index 7dab0ef170f2b1f180efd75ee906035c7788bbd8..68b36e7d3cab166e490689f26ac037591d4a8604 100644 (file)
@@ -138,7 +138,8 @@ public:
       IDNS(0),
       Redecl(Redecl != Sema::NotForRedeclaration),
       HideTags(true),
-      Diagnose(Redecl == Sema::NotForRedeclaration)
+      Diagnose(Redecl == Sema::NotForRedeclaration),
+      AllowHidden(Redecl == Sema::ForRedeclaration)
   {
     configure();
   }
@@ -158,7 +159,8 @@ public:
       IDNS(0),
       Redecl(Redecl != Sema::NotForRedeclaration),
       HideTags(true),
-      Diagnose(Redecl == Sema::NotForRedeclaration)
+      Diagnose(Redecl == Sema::NotForRedeclaration),
+      AllowHidden(Redecl == Sema::ForRedeclaration)
   {
     configure();
   }
@@ -176,7 +178,8 @@ public:
       IDNS(Other.IDNS),
       Redecl(Other.Redecl),
       HideTags(Other.HideTags),
-      Diagnose(false)
+      Diagnose(false),
+      AllowHidden(Other.AllowHidden)
   {}
 
   ~LookupResult() {
@@ -214,10 +217,16 @@ public:
     return Redecl;
   }
 
+  /// \brief Specify whether hidden declarations are visible, e.g.,
+  /// for recovery reasons.
+  void setAllowHidden(bool AH) {
+    AllowHidden = AH;
+  }
+
   /// \brief Determine whether this lookup is permitted to see hidden
   /// declarations, such as those in modules that have not yet been imported.
   bool isHiddenDeclarationVisible() const {
-    return Redecl || LookupKind == Sema::LookupTagName;
+    return AllowHidden || LookupKind == Sema::LookupTagName;
   }
   
   /// Sets whether tag declarations should be hidden by non-tag
@@ -483,6 +492,7 @@ public:
   /// \brief Change this lookup's redeclaration kind.
   void setRedeclarationKind(Sema::RedeclarationKind RK) {
     Redecl = RK;
+    AllowHidden = (RK == Sema::ForRedeclaration);
     configure();
   }
 
@@ -644,6 +654,9 @@ private:
   bool HideTags;
 
   bool Diagnose;
+
+  /// \brief True if we should allow hidden declarations to be 'visible'.
+  bool AllowHidden;
 };
 
   /// \brief Consumes visible declarations found when searching for
index 5971ff57884778326043968894dbc2e2291dc9ed..1f56acee64f2bb4c5d570911e0bef9fb3693a3cf 100644 (file)
@@ -275,12 +275,6 @@ public:
   /// This is only necessary for issuing pretty diagnostics.
   ExtVectorDeclsType ExtVectorDecls;
 
-  /// \brief The set of types for which we have already complained about the
-  /// definitions being hidden.
-  ///
-  /// This set is used to suppress redundant diagnostics.
-  llvm::SmallPtrSet<NamedDecl *, 4> HiddenDefinitions;
-
   /// FieldCollector - Collects CXXFieldDecls during parsing of C++ classes.
   OwningPtr<CXXFieldCollector> FieldCollector;
 
@@ -1456,6 +1450,14 @@ public:
   DeclResult ActOnModuleImport(SourceLocation AtLoc, SourceLocation ImportLoc,
                                ModuleIdPath Path);
 
+  /// \brief Create an implicit import of the given module at the given
+  /// source location.
+  ///
+  /// This routine is typically used for error recovery, when the entity found
+  /// by name lookup is actually hidden within a module that we know about but
+  /// the user has forgotten to import.
+  void createImplicitModuleImport(SourceLocation Loc, Module *Mod);
+
   /// \brief Retrieve a suitable printing policy.
   PrintingPolicy getPrintingPolicy() const {
     return getPrintingPolicy(Context, PP);
index 816dfef024f3a3f4ced74c9f5518dd587be451fe..61d77b0a75112a686db1aaaa01e463f36fc1bd8b 100644 (file)
@@ -1558,7 +1558,12 @@ public:
   /// \brief Retrieve the submodule that corresponds to a global submodule ID.
   ///
   Module *getSubmodule(serialization::SubmoduleID GlobalID);
-  
+
+  /// \brief Retrieve the module that corresponds to the given module ID.
+  ///
+  /// Note: overrides method in ExternalASTSource
+  virtual Module *getModule(unsigned ID);
+
   /// \brief Retrieve a selector from the given module with its local ID
   /// number.
   Selector getLocalSelector(ModuleFile &M, unsigned LocalID);
index 5dccaac0205de7d8489e98a4c849e6d637cbe1ba..d8b63611fd1041ccfe16a0f3fc5ade661b488c72 100644 (file)
@@ -59,6 +59,11 @@ void *Decl::AllocateDeserializedDecl(const ASTContext &Context,
   return Result;
 }
 
+Module *Decl::getOwningModuleSlow() const {
+  assert(isFromASTFile() && "Not from AST file?");
+  return getASTContext().getExternalSource()->getModule(getOwningModuleID());
+}
+
 const char *Decl::getDeclKindName() const {
   switch (DeclKind) {
   default: llvm_unreachable("Declaration not in DeclNodes.inc!");
index f31301c6e9f1884363c45307405eff79e1856cbd..5b2be9196776ddf4852630af7186e02a8bb09cf4 100644 (file)
@@ -1201,3 +1201,9 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
   LastModuleImportResult = ModuleLoadResult(Module, false);
   return LastModuleImportResult;
 }
+
+void CompilerInstance::makeModuleVisible(Module *Mod,
+                                         Module::NameVisibilityKind Visibility){
+  ModuleManager->makeModuleVisible(Mod, Visibility);
+}
+
index 0cf1238220789487e6fc52a4a158ce6d1369b730..c3a2ad11230fe7d325c7bda489d33809ea754964 100644 (file)
@@ -11173,6 +11173,18 @@ DeclResult Sema::ActOnModuleImport(SourceLocation AtLoc,
   return Import;
 }
 
+void Sema::createImplicitModuleImport(SourceLocation Loc, Module *Mod) {
+  // Create the implicit import declaration.
+  TranslationUnitDecl *TU = getASTContext().getTranslationUnitDecl();
+  ImportDecl *ImportD = ImportDecl::CreateImplicit(getASTContext(), TU,
+                                                   Loc, Mod, Loc);
+  TU->addDecl(ImportD);
+  Consumer.HandleImplicitImportDecl(ImportD);
+
+  // Make the module visible.
+  PP.getModuleLoader().makeModuleVisible(Mod, Module::AllVisible);
+}
+
 void Sema::ActOnPragmaRedefineExtname(IdentifierInfo* Name,
                                       IdentifierInfo* AliasName,
                                       SourceLocation PragmaLoc,
index 60db55aff33c19eed289e8fab4c87fa959858662..59c1dea8ff57e67b29c0cef28c5b185ce3adb54d 100644 (file)
@@ -4392,9 +4392,14 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
       // repeating the diagnostic.
       // FIXME: Add a Fix-It that imports the corresponding module or includes
       // the header.
-      if (isSFINAEContext() || HiddenDefinitions.insert(Def)) {
-        Diag(Loc, diag::err_module_private_definition) << T;
-        Diag(Def->getLocation(), diag::note_previous_definition);
+      Module *Owner = Def->getOwningModule();
+      Diag(Loc, diag::err_module_private_definition)
+        << T << Owner->getFullModuleName();
+      Diag(Def->getLocation(), diag::note_previous_definition);
+
+      if (!isSFINAEContext()) {
+        // Recover by implicitly importing this module.
+        createImplicitModuleImport(Loc, Owner);
       }
     }
 
index a4436d16716a153e612c1ba9ce17d5152814542f..986eee1c95154c1c84410a4db992e68d596bbaeb 100644 (file)
@@ -6200,7 +6200,11 @@ Module *ASTReader::getSubmodule(SubmoduleID GlobalID) {
   
   return SubmodulesLoaded[GlobalID - NUM_PREDEF_SUBMODULE_IDS];
 }
-                               
+
+Module *ASTReader::getModule(unsigned ID) {
+  return getSubmodule(ID);
+}
+
 Selector ASTReader::getLocalSelector(ModuleFile &M, unsigned LocalID) {
   return DecodeSelector(getGlobalSelectorID(M, LocalID));
 }
index c99fdea0d84ee0f646313beaa716f9a5660a4e9b..e164aa7e08049e2517929a743e92332493921485 100644 (file)
@@ -2,13 +2,7 @@
 // RUN: %clang_cc1 -fmodules -I %S/Inputs -fmodule-cache-path %t %s -verify
 
 
-// in other file: expected-note{{previous definition is here}}
-
-
-
-
-
-// in other file: expected-note{{previous definition is here}}
+// In other file: expected-note {{previous definition is here}}
 
 @import decldef;
 A *a1; // expected-error{{unknown type name 'A'}}
@@ -19,10 +13,9 @@ A *a2;
 B *b;
 
 void testA(A *a) {
-  a->ivar = 17; // expected-error{{definition of 'A' must be imported before it is required}}
+  a->ivar = 17; // expected-error{{definition of 'A' must be imported from module 'decldef.Def' before it is required}}
 }
 
 void testB() {
-  B b; // expected-error{{definition of 'B' must be imported before it is required}}
-  B b2; // Note: the reundant error was silenced.
+  B b; // Note: redundant error silenced
 }