From: Douglas Gregor Date: Tue, 29 Jun 2010 17:53:46 +0000 (+0000) Subject: Allow a using directive to refer to the implicitly-defined namespace X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=6699220f73f11e471b5e5aa42eaf064afeaa079e;p=clang Allow a using directive to refer to the implicitly-defined namespace "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 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index e5c16fbe43..8fd2634fe8 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -459,6 +459,9 @@ def warn_weak_vtable : Warning< "emitted in every translation unit">, InGroup>, 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. diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index fcf5e94149..325add7671 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -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, diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index c6f149e8fe..66d0bf5bd4 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -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(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() || + R.getAsSingle()) { + 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(Named) || isa(Named)) diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 97300f7d63..1801565ff0 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -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); diff --git a/test/FixIt/typo.cpp b/test/FixIt/typo.cpp index 5b9e68bbfd..9789a5807a 100644 --- a/test/FixIt/typo.cpp +++ b/test/FixIt/typo.cpp @@ -12,7 +12,8 @@ namespace std { typedef basic_string 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 b1; // expected-error{{no template named 'basc_string'; did you mean 'basic_string'?}} std::basic_sting b2; // expected-error{{no template named 'basic_sting' in namespace 'std'; did you mean 'basic_string'?}} diff --git a/test/SemaCXX/using-directive.cpp b/test/SemaCXX/using-directive.cpp index 0d5c8400ab..162f7fa07a 100644 --- a/test/SemaCXX/using-directive.cpp +++ b/test/SemaCXX/using-directive.cpp @@ -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'}} +