r233250 - [modules] If we reach a definition of a class for which we already have a

Richard Smith richard-llvm at metafoo.co.uk
Wed Mar 25 21:09:53 PDT 2015


Author: rsmith
Date: Wed Mar 25 23:09:53 2015
New Revision: 233250

URL: http://llvm.org/viewvc/llvm-project?rev=233250&view=rev
Log:
[modules] If we reach a definition of a class for which we already have a
non-visible definition, skip the new definition and make the old one visible
instead of trying to parse it again and failing horribly. C++'s ODR allows
us to assume that the two definitions are identical.

Added:
    cfe/trunk/test/Modules/Inputs/submodules-merge-defs/
    cfe/trunk/test/Modules/Inputs/submodules-merge-defs/defs.h
    cfe/trunk/test/Modules/Inputs/submodules-merge-defs/empty.h
    cfe/trunk/test/Modules/Inputs/submodules-merge-defs/import-and-redefine.h
    cfe/trunk/test/Modules/Inputs/submodules-merge-defs/module.modulemap
    cfe/trunk/test/Modules/Inputs/submodules-merge-defs/use-defs.h
    cfe/trunk/test/Modules/submodules-merge-defs.cpp
Modified:
    cfe/trunk/include/clang/AST/ASTMutationListener.h
    cfe/trunk/include/clang/Parse/Parser.h
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/include/clang/Serialization/ASTWriter.h
    cfe/trunk/lib/Frontend/MultiplexConsumer.cpp
    cfe/trunk/lib/Parse/ParseDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaType.cpp
    cfe/trunk/lib/Serialization/ASTCommon.h
    cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
    cfe/trunk/lib/Serialization/ASTWriter.cpp

Modified: cfe/trunk/include/clang/AST/ASTMutationListener.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTMutationListener.h?rev=233250&r1=233249&r2=233250&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ASTMutationListener.h (original)
+++ cfe/trunk/include/clang/AST/ASTMutationListener.h Wed Mar 25 23:09:53 2015
@@ -24,6 +24,7 @@ namespace clang {
   class DeclContext;
   class FunctionDecl;
   class FunctionTemplateDecl;
+  class NamedDecl;
   class ObjCCategoryDecl;
   class ObjCContainerDecl;
   class ObjCInterfaceDecl;
@@ -113,6 +114,12 @@ public:
   /// \param D the declaration marked OpenMP threadprivate.
   virtual void DeclarationMarkedOpenMPThreadPrivate(const Decl *D) {}
 
+  /// \brief A definition has been made visible by being redefined locally.
+  ///
+  /// \param D The definition that was previously not visible.
+  virtual void RedefinedHiddenDefinition(const NamedDecl *D,
+                                         SourceLocation Loc) {}
+
   // NOTE: If new methods are added they should also be added to
   // MultiplexASTMutationListener.
 };

Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=233250&r1=233249&r2=233250&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Wed Mar 25 23:09:53 2015
@@ -2284,6 +2284,10 @@ private:
                            AccessSpecifier AS, bool EnteringContext,
                            DeclSpecContext DSC, 
                            ParsedAttributesWithRange &Attributes);
+  void SkipCXXMemberSpecification(SourceLocation StartLoc,
+                                  SourceLocation AttrFixitLoc,
+                                  unsigned TagType,
+                                  Decl *TagDecl);
   void ParseCXXMemberSpecification(SourceLocation StartLoc,
                                    SourceLocation AttrFixitLoc,
                                    ParsedAttributesWithRange &Attrs,

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=233250&r1=233249&r2=233250&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Wed Mar 25 23:09:53 2015
@@ -1279,6 +1279,10 @@ private:
   bool RequireCompleteTypeImpl(SourceLocation Loc, QualType T,
                            TypeDiagnoser &Diagnoser);
 public:
+  /// Determine if \p D has a visible definition. If not, suggest a declaration
+  /// that should be made visible to expose the definition.
+  bool hasVisibleDefinition(NamedDecl *D, NamedDecl **Suggested);
+
   bool RequireCompleteType(SourceLocation Loc, QualType T,
                            TypeDiagnoser &Diagnoser);
   bool RequireCompleteType(SourceLocation Loc, QualType T,
@@ -1725,7 +1729,7 @@ public:
                  bool &OwnedDecl, bool &IsDependent,
                  SourceLocation ScopedEnumKWLoc,
                  bool ScopedEnumUsesClassTag, TypeResult UnderlyingType,
-                 bool IsTypeSpecifier);
+                 bool IsTypeSpecifier, bool *SkipBody = nullptr);
 
   Decl *ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
                                 unsigned TagSpec, SourceLocation TagLoc,
@@ -1790,6 +1794,11 @@ public:
   /// struct, or union).
   void ActOnTagStartDefinition(Scope *S, Decl *TagDecl);
 
+  /// \brief Invoked when we enter a tag definition that we're skipping.
+  void ActOnTagStartSkippedDefinition(Scope *S, Decl *TD) {
+    PushDeclContext(S, cast<DeclContext>(TD));
+  }
+
   Decl *ActOnObjCContainerStartDefinition(Decl *IDecl);
 
   /// ActOnStartCXXMemberDeclarations - Invoked when we have parsed a
@@ -1805,6 +1814,10 @@ public:
   void ActOnTagFinishDefinition(Scope *S, Decl *TagDecl,
                                 SourceLocation RBraceLoc);
 
+  void ActOnTagFinishSkippedDefinition() {
+    PopDeclContext();
+  }
+
   void ActOnObjCContainerFinishDefinition();
 
   /// \brief Invoked when we must temporarily exit the objective-c container

Modified: cfe/trunk/include/clang/Serialization/ASTWriter.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTWriter.h?rev=233250&r1=233249&r2=233250&view=diff
==============================================================================
--- cfe/trunk/include/clang/Serialization/ASTWriter.h (original)
+++ cfe/trunk/include/clang/Serialization/ASTWriter.h Wed Mar 25 23:09:53 2015
@@ -861,6 +861,8 @@ public:
                                     const ObjCCategoryDecl *ClassExt) override;
   void DeclarationMarkedUsed(const Decl *D) override;
   void DeclarationMarkedOpenMPThreadPrivate(const Decl *D) override;
+  void RedefinedHiddenDefinition(const NamedDecl *D,
+                                 SourceLocation Loc) override;
 };
 
 /// \brief AST and semantic-analysis consumer that generates a

Modified: cfe/trunk/lib/Frontend/MultiplexConsumer.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/MultiplexConsumer.cpp?rev=233250&r1=233249&r2=233250&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/MultiplexConsumer.cpp (original)
+++ cfe/trunk/lib/Frontend/MultiplexConsumer.cpp Wed Mar 25 23:09:53 2015
@@ -110,6 +110,8 @@ public:
                                     const ObjCCategoryDecl *ClassExt) override;
   void DeclarationMarkedUsed(const Decl *D) override;
   void DeclarationMarkedOpenMPThreadPrivate(const Decl *D) override;
+  void RedefinedHiddenDefinition(const NamedDecl *D,
+                                 SourceLocation Loc) override;
 
 private:
   std::vector<ASTMutationListener*> Listeners;
@@ -193,6 +195,11 @@ void MultiplexASTMutationListener::Decla
   for (size_t i = 0, e = Listeners.size(); i != e; ++i)
     Listeners[i]->DeclarationMarkedOpenMPThreadPrivate(D);
 }
+void MultiplexASTMutationListener::RedefinedHiddenDefinition(
+    const NamedDecl *D, SourceLocation Loc) {
+  for (auto *L : Listeners)
+    L->RedefinedHiddenDefinition(D, Loc);
+}
 
 }  // end namespace clang
 

Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=233250&r1=233249&r2=233250&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Wed Mar 25 23:09:53 2015
@@ -1550,6 +1550,7 @@ void Parser::ParseClassSpecifier(tok::To
   TypeResult TypeResult = true; // invalid
 
   bool Owned = false;
+  bool SkipBody = false;
   if (TemplateId) {
     // Explicit specialization, class template partial specialization,
     // or explicit instantiation.
@@ -1695,7 +1696,8 @@ void Parser::ParseClassSpecifier(tok::To
                                        TParams, Owned, IsDependent,
                                        SourceLocation(), false,
                                        clang::TypeResult(),
-                                       DSC == DSC_type_specifier);
+                                       DSC == DSC_type_specifier,
+                                       &SkipBody);
 
     // If ActOnTag said the type was dependent, try again with the
     // less common call.
@@ -1711,7 +1713,10 @@ void Parser::ParseClassSpecifier(tok::To
     assert(Tok.is(tok::l_brace) ||
            (getLangOpts().CPlusPlus && Tok.is(tok::colon)) ||
            isCXX11FinalKeyword());
-    if (getLangOpts().CPlusPlus)
+    if (SkipBody)
+      SkipCXXMemberSpecification(StartLoc, AttrFixitLoc, TagType,
+                                 TagOrTempResult.get());
+    else if (getLangOpts().CPlusPlus)
       ParseCXXMemberSpecification(StartLoc, AttrFixitLoc, attrs, TagType,
                                   TagOrTempResult.get());
     else
@@ -2688,6 +2693,55 @@ ExprResult Parser::ParseCXXMemberInitial
   return ParseInitializer();
 }
 
+void Parser::SkipCXXMemberSpecification(SourceLocation RecordLoc,
+                                        SourceLocation AttrFixitLoc,
+                                        unsigned TagType, Decl *TagDecl) {
+  // Skip the optional 'final' keyword.
+  if (getLangOpts().CPlusPlus && Tok.is(tok::identifier)) {
+    assert(isCXX11FinalKeyword() && "not a class definition");
+    ConsumeToken();
+
+    // Diagnose any C++11 attributes after 'final' keyword.
+    // We deliberately discard these attributes.
+    ParsedAttributesWithRange Attrs(AttrFactory);
+    CheckMisplacedCXX11Attribute(Attrs, AttrFixitLoc);
+
+    // This can only happen if we had malformed misplaced attributes;
+    // we only get called if there is a colon or left-brace after the
+    // attributes.
+    if (Tok.isNot(tok::colon) && Tok.isNot(tok::l_brace))
+      return;
+  }
+
+  // Skip the base clauses. This requires actually parsing them, because
+  // otherwise we can't be sure where they end (a left brace may appear
+  // within a template argument).
+  if (Tok.is(tok::colon)) {
+    // Enter the scope of the class so that we can correctly parse its bases.
+    ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope);
+    ParsingClassDefinition ParsingDef(*this, TagDecl, /*NonNestedClass*/ true,
+                                      TagType == DeclSpec::TST_interface);
+    Actions.ActOnTagStartSkippedDefinition(getCurScope(), TagDecl);
+
+    // Parse the bases but don't attach them to the class.
+    ParseBaseClause(nullptr);
+
+    Actions.ActOnTagFinishSkippedDefinition();
+
+    if (!Tok.is(tok::l_brace)) {
+      Diag(PP.getLocForEndOfToken(PrevTokLocation),
+           diag::err_expected_lbrace_after_base_specifiers);
+      return;
+    }
+  }
+
+  // Skip the body.
+  assert(Tok.is(tok::l_brace));
+  BalancedDelimiterTracker T(*this, tok::l_brace);
+  T.consumeOpen();
+  T.skipToEnd();
+}
+
 /// ParseCXXMemberSpecification - Parse the class definition.
 ///
 ///       member-specification:

Modified: cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp?rev=233250&r1=233249&r2=233250&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp (original)
+++ cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp Wed Mar 25 23:09:53 2015
@@ -218,6 +218,7 @@ bool Sema::RequireCompleteDeclContext(CX
   // Fixed enum types are complete, but they aren't valid as scopes
   // until we see a definition, so awkwardly pull out this special
   // case.
+  // FIXME: The definition might not be visible; complain if it is not.
   const EnumType *enumType = dyn_cast_or_null<EnumType>(tagType);
   if (!enumType || enumType->getDecl()->isCompleteDefinition())
     return false;

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=233250&r1=233249&r2=233250&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Wed Mar 25 23:09:53 2015
@@ -16,6 +16,7 @@
 #include "clang/AST/ASTConsumer.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/ASTLambda.h"
+#include "clang/AST/ASTMutationListener.h"
 #include "clang/AST/CXXInheritance.h"
 #include "clang/AST/CharUnits.h"
 #include "clang/AST/CommentDiagnostic.h"
@@ -11233,13 +11234,16 @@ static FixItHint createFriendTagNNSFixIt
   return FixItHint::CreateInsertion(NameLoc, Insertion);
 }
 
-/// ActOnTag - This is invoked when we see 'struct foo' or 'struct {'.  In the
+/// \brief This is invoked when we see 'struct foo' or 'struct {'.  In the
 /// former case, Name will be non-null.  In the later case, Name will be null.
 /// TagSpec indicates what kind of tag this is. TUK indicates whether this is a
 /// reference/declaration/definition of a tag.
 ///
-/// IsTypeSpecifier is true if this is a type-specifier (or
+/// \param IsTypeSpecifier \c true if this is a type-specifier (or
 /// trailing-type-specifier) other than one in an alias-declaration.
+///
+/// \param SkipBody If non-null, will be set to true if the caller should skip
+/// the definition of this tag, and treat it as if it were a declaration.
 Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
                      SourceLocation KWLoc, CXXScopeSpec &SS,
                      IdentifierInfo *Name, SourceLocation NameLoc,
@@ -11250,7 +11254,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned
                      SourceLocation ScopedEnumKWLoc,
                      bool ScopedEnumUsesClassTag,
                      TypeResult UnderlyingType,
-                     bool IsTypeSpecifier) {
+                     bool IsTypeSpecifier, bool *SkipBody) {
   // If this is not a definition, it must have a name.
   IdentifierInfo *OrigName = Name;
   assert((Name != nullptr || TUK == TUK_Definition) &&
@@ -11676,7 +11680,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned
 
           // Diagnose attempts to redefine a tag.
           if (TUK == TUK_Definition) {
-            if (TagDecl *Def = PrevTagDecl->getDefinition()) {
+            if (NamedDecl *Def = PrevTagDecl->getDefinition()) {
               // If we're defining a specialization and the previous definition
               // is from an implicit instantiation, don't emit an error
               // here; we'll catch this in the general case below.
@@ -11692,7 +11696,19 @@ Decl *Sema::ActOnTag(Scope *S, unsigned
                     TSK_ExplicitSpecialization;
               }
 
-              if (!IsExplicitSpecializationAfterInstantiation) {
+              if (SkipBody && getLangOpts().CPlusPlus &&
+                  !hasVisibleDefinition(Def, &Def)) {
+                // 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
+                // we already have. Make the existing definition visible and
+                // use it in place of this one.
+                *SkipBody = true;
+                if (auto *Listener = getASTMutationListener())
+                  Listener->RedefinedHiddenDefinition(Def, KWLoc);
+                Def->setHidden(false);
+                return Def;
+              } else if (!IsExplicitSpecializationAfterInstantiation) {
                 // A redeclaration in function prototype scope in C isn't
                 // visible elsewhere, so merely issue a warning.
                 if (!getLangOpts().CPlusPlus && S->containedInPrototypeScope())

Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=233250&r1=233249&r2=233250&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Wed Mar 25 23:09:53 2015
@@ -5126,9 +5126,9 @@ bool Sema::RequireCompleteType(SourceLoc
 /// \param D The definition of the entity.
 /// \param Suggested Filled in with the declaration that should be made visible
 ///        in order to provide a definition of this entity.
-static bool hasVisibleDefinition(Sema &S, NamedDecl *D, NamedDecl **Suggested) {
+bool Sema::hasVisibleDefinition(NamedDecl *D, NamedDecl **Suggested) {
   // Easy case: if we don't have modules, all declarations are visible.
-  if (!S.getLangOpts().Modules)
+  if (!getLangOpts().Modules)
     return true;
 
   // If this definition was instantiated from a template, map back to the
@@ -5144,7 +5144,7 @@ static bool hasVisibleDefinition(Sema &S
       // If the enum has a fixed underlying type, any declaration of it will do.
       *Suggested = nullptr;
       for (auto *Redecl : ED->redecls()) {
-        if (LookupResult::isVisible(S, Redecl))
+        if (LookupResult::isVisible(*this, Redecl))
           return true;
         if (Redecl->isThisDeclarationADefinition() ||
             (Redecl->isCanonicalDecl() && !*Suggested))
@@ -5159,7 +5159,7 @@ static bool hasVisibleDefinition(Sema &S
   // FIXME: If we merged any other decl into D, and that declaration is visible,
   // then we should consider a definition to be visible.
   *Suggested = D;
-  return LookupResult::isVisible(S, D);
+  return LookupResult::isVisible(*this, D);
 }
 
 /// Locks in the inheritance model for the given class and all of its bases.
@@ -5210,7 +5210,7 @@ bool Sema::RequireCompleteTypeImpl(Sourc
     // If we know about the definition but it is not visible, complain.
     NamedDecl *SuggestedDef = nullptr;
     if (!Diagnoser.Suppressed && Def &&
-        !hasVisibleDefinition(*this, Def, &SuggestedDef)) {
+        !hasVisibleDefinition(Def, &SuggestedDef)) {
       // Suppress this error outside of a SFINAE context if we've already
       // emitted the error once for this type. There's no usefulness in
       // repeating the diagnostic.

Modified: cfe/trunk/lib/Serialization/ASTCommon.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTCommon.h?rev=233250&r1=233249&r2=233250&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTCommon.h (original)
+++ cfe/trunk/lib/Serialization/ASTCommon.h Wed Mar 25 23:09:53 2015
@@ -35,7 +35,8 @@ enum DeclUpdateKind {
   UPD_DECL_MARKED_USED,
   UPD_MANGLING_NUMBER,
   UPD_STATIC_LOCAL_NUMBER,
-  UPD_DECL_MARKED_OPENMP_THREADPRIVATE
+  UPD_DECL_MARKED_OPENMP_THREADPRIVATE,
+  UPD_DECL_EXPORTED
 };
 
 TypeIdx TypeIdxFromBuiltin(const BuiltinType *BT);

Modified: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=233250&r1=233249&r2=233250&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Wed Mar 25 23:09:53 2015
@@ -3793,10 +3793,24 @@ void ASTDeclReader::UpdateDecl(Decl *D,
     case UPD_STATIC_LOCAL_NUMBER:
       Reader.Context.setStaticLocalNumber(cast<VarDecl>(D), Record[Idx++]);
       break;
+
     case UPD_DECL_MARKED_OPENMP_THREADPRIVATE:
       D->addAttr(OMPThreadPrivateDeclAttr::CreateImplicit(
           Reader.Context, ReadSourceRange(Record, Idx)));
       break;
+
+    case UPD_DECL_EXPORTED:
+      unsigned SubmoduleID = readSubmoduleID(Record, Idx);
+      Module *Owner = SubmoduleID ? Reader.getSubmodule(SubmoduleID) : nullptr;
+      if (Owner && Owner->NameVisibility != Module::AllVisible) {
+        // If Owner is made visible at some later point, make this declaration
+        // visible too.
+        Reader.HiddenNamesMap[Owner].HiddenDecls.push_back(D);
+      } else {
+        // The declaration is now visible.
+        D->Hidden = false;
+      }
+      break;
     }
   }
 }

Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=233250&r1=233249&r2=233250&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriter.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriter.cpp Wed Mar 25 23:09:53 2015
@@ -4927,10 +4927,15 @@ void ASTWriter::WriteDeclUpdatesBlocks(R
       case UPD_STATIC_LOCAL_NUMBER:
         Record.push_back(Update.getNumber());
         break;
+
       case UPD_DECL_MARKED_OPENMP_THREADPRIVATE:
         AddSourceRange(D->getAttr<OMPThreadPrivateDeclAttr>()->getRange(),
                        Record);
         break;
+
+      case UPD_DECL_EXPORTED:
+        Record.push_back(inferSubmoduleIDFromLocation(Update.getLoc()));
+        break;
       }
     }
 
@@ -6074,3 +6079,11 @@ void ASTWriter::DeclarationMarkedOpenMPT
 
   DeclUpdates[D].push_back(DeclUpdate(UPD_DECL_MARKED_OPENMP_THREADPRIVATE));
 }
+
+void ASTWriter::RedefinedHiddenDefinition(const NamedDecl *D,
+                                          SourceLocation Loc) {
+  assert(!WritingAST && "Already writing the AST!");
+  assert(D->isHidden() && "expected a hidden declaration");
+  assert(D->isFromASTFile() && "hidden decl not from AST file");
+  DeclUpdates[D].push_back(DeclUpdate(UPD_DECL_EXPORTED, Loc));
+}

Added: cfe/trunk/test/Modules/Inputs/submodules-merge-defs/defs.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/submodules-merge-defs/defs.h?rev=233250&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/submodules-merge-defs/defs.h (added)
+++ cfe/trunk/test/Modules/Inputs/submodules-merge-defs/defs.h Wed Mar 25 23:09:53 2015
@@ -0,0 +1,6 @@
+struct A {};
+class B {
+  struct Inner1 {};
+  struct Inner2;
+};
+struct B::Inner2 : Inner1 {};

Added: cfe/trunk/test/Modules/Inputs/submodules-merge-defs/empty.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/submodules-merge-defs/empty.h?rev=233250&view=auto
==============================================================================
    (empty)

Added: cfe/trunk/test/Modules/Inputs/submodules-merge-defs/import-and-redefine.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/submodules-merge-defs/import-and-redefine.h?rev=233250&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/submodules-merge-defs/import-and-redefine.h (added)
+++ cfe/trunk/test/Modules/Inputs/submodules-merge-defs/import-and-redefine.h Wed Mar 25 23:09:53 2015
@@ -0,0 +1,5 @@
+// Trigger import of definitions, but don't make them visible.
+#include "empty.h"
+
+// Now parse the definitions again.
+#include "defs.h"

Added: cfe/trunk/test/Modules/Inputs/submodules-merge-defs/module.modulemap
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/submodules-merge-defs/module.modulemap?rev=233250&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/submodules-merge-defs/module.modulemap (added)
+++ cfe/trunk/test/Modules/Inputs/submodules-merge-defs/module.modulemap Wed Mar 25 23:09:53 2015
@@ -0,0 +1,11 @@
+module "stuff" {
+  textual header "defs.h"
+  module "empty" { header "empty.h" }
+  module "use" { header "use-defs.h" }
+}
+
+module "redef" {
+  header "import-and-redefine.h"
+  // Do not re-export stuff.use
+  use "stuff"
+}

Added: cfe/trunk/test/Modules/Inputs/submodules-merge-defs/use-defs.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/submodules-merge-defs/use-defs.h?rev=233250&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/submodules-merge-defs/use-defs.h (added)
+++ cfe/trunk/test/Modules/Inputs/submodules-merge-defs/use-defs.h Wed Mar 25 23:09:53 2015
@@ -0,0 +1 @@
+#include "defs.h"

Added: cfe/trunk/test/Modules/submodules-merge-defs.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/submodules-merge-defs.cpp?rev=233250&view=auto
==============================================================================
--- cfe/trunk/test/Modules/submodules-merge-defs.cpp (added)
+++ cfe/trunk/test/Modules/submodules-merge-defs.cpp Wed Mar 25 23:09:53 2015
@@ -0,0 +1,13 @@
+// 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
+
+// Trigger import of definitions, but don't make them visible.
+#include "empty.h"
+
+A pre_a; // expected-error {{must be imported}} expected-error {{must use 'struct'}}
+// expected-note at defs.h:1 {{here}}
+
+// Make definitions from second module visible.
+#include "import-and-redefine.h"
+
+A post_a;





More information about the cfe-commits mailing list