Author: rsmith
Date: Sat Jan  9 00:58:48 2016
New Revision: 257251

URL: http://llvm.org/viewvc/llvm-project?rev=257251&view=rev
Log:
[modules] If we're treating an elaborated-type-specifier as if it introduces a
tag (because the previous declaration was found in a different module), inject
the tag into the appropriate scope (that is, the enclosing scope if we're in a
function prototype scope in C++).

Modified:
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/test/Modules/tag-injection.cpp

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=257251&r1=257250&r2=257251&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Sat Jan  9 00:58:48 2016
@@ -11798,6 +11798,28 @@ static bool isAcceptableTagRedeclContext
   return false;
 }
 
+/// Find the DeclContext in which a tag is implicitly declared if we see an
+/// elaborated type specifier in the specified context, and lookup finds
+/// nothing.
+static DeclContext *getTagInjectionContext(DeclContext *DC) {
+  while (!DC->isFileContext() && !DC->isFunctionOrMethod())
+    DC = DC->getParent();
+  return DC;
+}
+
+/// Find the Scope in which a tag is implicitly declared if we see an
+/// elaborated type specifier in the specified context, and lookup finds
+/// nothing.
+static Scope *getTagInjectionScope(Scope *S, const LangOptions &LangOpts) {
+  while (S->isClassScope() ||
+         (LangOpts.CPlusPlus &&
+          S->isFunctionPrototypeScope()) ||
+         ((S->getFlags() & Scope::DeclScope) == 0) ||
+         (S->getEntity() && S->getEntity()->isTransparentContext()))
+    S = S->getParent();
+  return S;
+}
+
 /// \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
@@ -12114,16 +12136,10 @@ Decl *Sema::ActOnTag(Scope *S, unsigned
       // Find the context where we'll be declaring the tag.
       // FIXME: We would like to maintain the current DeclContext as the
       // lexical context,
-      while (!SearchDC->isFileContext() && !SearchDC->isFunctionOrMethod())
-        SearchDC = SearchDC->getParent();
+      SearchDC = getTagInjectionContext(SearchDC);
 
       // Find the scope where we'll be declaring the tag.
-      while (S->isClassScope() ||
-             (getLangOpts().CPlusPlus &&
-              S->isFunctionPrototypeScope()) ||
-             ((S->getFlags() & Scope::DeclScope) == 0) ||
-             (S->getEntity() && S->getEntity()->isTransparentContext()))
-        S = S->getParent();
+      S = getTagInjectionScope(S, getLangOpts());
     } else {
       assert(TUK == TUK_Friend);
       // C++ [namespace.memdef]p3:
@@ -12293,14 +12309,13 @@ Decl *Sema::ActOnTag(Scope *S, unsigned
               // the declaration would have meant the same thing if no prior
               // declaration were found, that is, if it was found in the same
               // scope where we would have injected a declaration.
-              DeclContext *InjectedDC = CurContext;
-              while (!InjectedDC->isFileContext() &&
-                     !InjectedDC->isFunctionOrMethod())
-                InjectedDC = InjectedDC->getParent();
-              if (!InjectedDC->getRedeclContext()->Equals(
-                  PrevDecl->getDeclContext()->getRedeclContext()))
+              if (!getTagInjectionContext(CurContext)
+                       ->getRedeclContext()
+                       
->Equals(PrevDecl->getDeclContext()->getRedeclContext()))
                 return PrevTagDecl;
-              // This is in the injected scope, create a new declaration.
+              // This is in the injected scope, create a new declaration in
+              // that scope.
+              S = getTagInjectionScope(S, getLangOpts());
             } else {
               return PrevTagDecl;
             }

Modified: cfe/trunk/test/Modules/tag-injection.cpp
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/tag-injection.cpp?rev=257251&r1=257250&r2=257251&view=diff
==============================================================================
--- cfe/trunk/test/Modules/tag-injection.cpp (original)
+++ cfe/trunk/test/Modules/tag-injection.cpp Sat Jan  9 00:58:48 2016
@@ -1,12 +1,15 @@
 // RUN: rm -rf %t
 // RUN: mkdir %t
-// RUN: touch %t/a.h
-// RUN: echo 'struct X {};' > %t/b.h
+// RUN: echo 'struct tm;' > %t/a.h
+// RUN: echo 'struct X {}; void foo(struct tm*);' > %t/b.h
 // RUN: echo 'module X { module a { header "a.h" } module b { header "b.h" } 
}' > %t/x.modulemap
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -x c++ 
-fmodule-map-file=%t/x.modulemap %s -I%t -verify -std=c++11
 // RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -x c++ 
-fmodule-map-file=%t/x.modulemap %s -I%t -verify 
-fmodules-local-submodule-visibility -std=c++11
 
 #include "a.h"
 
+using ::tm;
+
 struct A {
   // This use of 'struct X' makes the declaration (but not definition) of X 
visible.
   virtual void f(struct X *p);


_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to