]> granicus.if.org Git - clang/commitdiff
Allow a using directive to refer to the implicitly-defined namespace
authorDouglas Gregor <dgregor@apple.com>
Tue, 29 Jun 2010 17:53:46 +0000 (17:53 +0000)
committerDouglas Gregor <dgregor@apple.com>
Tue, 29 Jun 2010 17:53:46 +0000 (17:53 +0000)
"std", with a warning, to improve GCC compatibility. Fixes PR7517.

As a drive-by, add typo correction for using directives.

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

include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/Sema.h
lib/Sema/SemaDeclCXX.cpp
lib/Sema/SemaExprCXX.cpp
test/FixIt/typo.cpp
test/SemaCXX/using-directive.cpp

index e5c16fbe4386191b84419d8e66f79b4efe8954fa..8fd2634fe80e7bc1c51346423c14cd4a8b12506b 100644 (file)
@@ -459,6 +459,9 @@ def warn_weak_vtable : Warning<
   "emitted in every translation unit">,
   InGroup<DiagGroup<"weak-vtables">>, DefaultIgnore;
 
+def ext_using_undefined_std : ExtWarn<
+  "using directive refers to implicitly-defined namespace 'std'">;
+  
 // C++ exception specifications
 def err_exception_spec_in_typedef : Error<
   "exception specifications are not allowed in typedefs">;
@@ -3163,6 +3166,11 @@ def err_undeclared_protocol_suggest : Error<
   "cannot find protocol declaration for %0; did you mean %1?">;
 def note_base_class_specified_here : Note<
   "base class %0 specified here">;
+def err_using_directive_suggest : Error<
+  "no namespace named %0; did you mean %1?">;
+def err_using_directive_member_suggest : Error<
+  "no namespace named %0 in %1; did you mean %2?">;
+def note_namespace_defined_here : Note<"namespace %0 defined here">;
 
 } // end of sema category
 } // end of sema component.
index fcf5e94149f52dcf81c8aff1ba2d444af2fcd3f5..325add767172ad813530af0ff09331383964ee69 100644 (file)
@@ -2120,6 +2120,7 @@ public:
                                            AttributeList *AttrList);
   virtual void ActOnFinishNamespaceDef(DeclPtrTy Dcl, SourceLocation RBrace);
 
+  NamespaceDecl *getStdNamespace();
   virtual DeclPtrTy ActOnUsingDirective(Scope *CurScope,
                                         SourceLocation UsingLoc,
                                         SourceLocation NamespcLoc,
index c6f149e8fed6f50fb44873b3892799dc99264bcf..66d0bf5bd410303532cf38dd52626ae17a49e5f2 100644 (file)
@@ -3452,6 +3452,21 @@ void Sema::ActOnFinishNamespaceDef(DeclPtrTy D, SourceLocation RBrace) {
   PopDeclContext();
 }
 
+/// \brief Retrieve the special "std" namespace, which may require us to 
+/// implicitly define the namespace.
+NamespaceDecl *Sema::getStdNamespace() {
+  if (!StdNamespace) {
+    // The "std" namespace has not yet been defined, so build one implicitly.
+    StdNamespace = NamespaceDecl::Create(Context, 
+                                         Context.getTranslationUnitDecl(),
+                                         SourceLocation(),
+                                         &PP.getIdentifierTable().get("std"));
+    StdNamespace->setImplicit(true);
+  }
+  
+  return StdNamespace;
+}
+
 Sema::DeclPtrTy Sema::ActOnUsingDirective(Scope *S,
                                           SourceLocation UsingLoc,
                                           SourceLocation NamespcLoc,
@@ -3465,13 +3480,46 @@ Sema::DeclPtrTy Sema::ActOnUsingDirective(Scope *S,
   assert(S->getFlags() & Scope::DeclScope && "Invalid Scope.");
 
   UsingDirectiveDecl *UDir = 0;
-
+  NestedNameSpecifier *Qualifier = 0;
+  if (SS.isSet())
+    Qualifier = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
+  
   // Lookup namespace name.
   LookupResult R(*this, NamespcName, IdentLoc, LookupNamespaceName);
   LookupParsedName(R, S, &SS);
   if (R.isAmbiguous())
     return DeclPtrTy();
 
+  if (R.empty()) {
+    // Allow "using namespace std;" or "using namespace ::std;" even if 
+    // "std" hasn't been defined yet, for GCC compatibility.
+    if ((!Qualifier || Qualifier->getKind() == NestedNameSpecifier::Global) &&
+        NamespcName->isStr("std")) {
+      Diag(IdentLoc, diag::ext_using_undefined_std);
+      R.addDecl(getStdNamespace());
+      R.resolveKind();
+    } 
+    // Otherwise, attempt typo correction.
+    else if (DeclarationName Corrected = CorrectTypo(R, S, &SS, 0, false, 
+                                                       CTC_NoKeywords, 0)) {
+      if (R.getAsSingle<NamespaceDecl>() || 
+          R.getAsSingle<NamespaceAliasDecl>()) {
+        if (DeclContext *DC = computeDeclContext(SS, false))
+          Diag(IdentLoc, diag::err_using_directive_member_suggest)
+            << NamespcName << DC << Corrected << SS.getRange()
+            << FixItHint::CreateReplacement(IdentLoc, Corrected.getAsString());        
+        else
+          Diag(IdentLoc, diag::err_using_directive_suggest)
+            << NamespcName << Corrected
+            << FixItHint::CreateReplacement(IdentLoc, Corrected.getAsString());
+        Diag(R.getFoundDecl()->getLocation(), diag::note_namespace_defined_here)
+          << Corrected;
+        
+        NamespcName = Corrected.getAsIdentifierInfo();
+      }
+    }
+  }
+  
   if (!R.empty()) {
     NamedDecl *Named = R.getFoundDecl();
     assert((isa<NamespaceDecl>(Named) || isa<NamespaceAliasDecl>(Named))
index 97300f7d63e152a34bd2e6419f0bd4d3abd59c97..1801565ff09593a39471a3ff090c037f9ff9bac5 100644 (file)
@@ -1207,20 +1207,11 @@ void Sema::DeclareGlobalNewDelete() {
   // "std" or "bad_alloc" as necessary to form the exception specification.
   // However, we do not make these implicit declarations visible to name
   // lookup.
-  if (!StdNamespace) {
-    // The "std" namespace has not yet been defined, so build one implicitly.
-    StdNamespace = NamespaceDecl::Create(Context, 
-                                         Context.getTranslationUnitDecl(),
-                                         SourceLocation(),
-                                         &PP.getIdentifierTable().get("std"));
-    StdNamespace->setImplicit(true);
-  }
-  
   if (!StdBadAlloc) {
     // The "std::bad_alloc" class has not yet been declared, so build it
     // implicitly.
     StdBadAlloc = CXXRecordDecl::Create(Context, TTK_Class, 
-                                        StdNamespace
+                                        getStdNamespace()
                                         SourceLocation(), 
                                       &PP.getIdentifierTable().get("bad_alloc"), 
                                         SourceLocation(), 0);
index 5b9e68bbfd3de17f388d357c33b762c98077e643..9789a5807a6926e59777d17b2ec827b1677a796b 100644 (file)
@@ -12,7 +12,8 @@ namespace std {
   typedef basic_string<char> string; // expected-note 2{{'string' declared here}}
 }
 
-namespace otherstd { // expected-note 2{{'otherstd' declared here}}
+namespace otherstd { // expected-note 2{{'otherstd' declared here}} \
+                     // expected-note{{namespace 'otherstd' defined here}}
   using namespace std;
 }
 
@@ -29,6 +30,10 @@ float area(float radius, // expected-note{{'radius' declared here}}
   return radious * pi; // expected-error{{did you mean 'radius'?}}
 }
 
+using namespace othestd; // expected-error{{no namespace named 'othestd'; did you mean 'otherstd'?}}
+namespace blargh = otherstd; // expected-note{{namespace 'blargh' defined here}}
+using namespace ::blarg; // expected-error{{no namespace named 'blarg' in the global namespace; did you mean 'blargh'?}}
+
 bool test_string(std::string s) {
   basc_string<char> b1; // expected-error{{no template named 'basc_string'; did you mean 'basic_string'?}}
   std::basic_sting<char> b2; // expected-error{{no template named 'basic_sting' in namespace 'std'; did you mean 'basic_string'?}}
index 0d5c8400ab7eee7758578158074d9c48a92fdf40..162f7fa07a36621d64955cc30d5553f0be2dc348 100644 (file)
@@ -121,3 +121,8 @@ extern "C++" {
 }
 
 void f4() { f2(1); }
+
+// PR7517
+using namespace std; // expected-warning{{using directive refers to implicitly-defined namespace 'std'}}
+using namespace ::std; // expected-warning{{using directive refers to implicitly-defined namespace 'std'}}
+