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.

llvm-svn: 107172
This commit is contained in:
Douglas Gregor 2010-06-29 17:53:46 +00:00
parent 049f4ffab1
commit cdf87024ed
6 changed files with 70 additions and 12 deletions

View 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.

View 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,

View 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))

View 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);

View 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'?}}

View 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'}}