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:
parent
049f4ffab1
commit
cdf87024ed
|
@ -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.
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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'?}}
|
||||
|
|
|
@ -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'}}
|
||||
|
||||
|
|
Loading…
Reference in New Issue