summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2015-12-29 23:34:32 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2015-12-29 23:34:32 +0000
commitf2005d3de64f9230c6b43b4f4da1866d999446c8 (patch)
treefbeca65132ed366aae5a8e69cfac59bd1061bf2a
parent0315920629da8a51b717cbaff05dcd2af42ea5d5 (diff)
downloadbcm5719-llvm-f2005d3de64f9230c6b43b4f4da1866d999446c8.tar.gz
bcm5719-llvm-f2005d3de64f9230c6b43b4f4da1866d999446c8.zip
Model NamespaceAliasDecls as having their nominated namespace as an underlying
declaration. This fixes an issue where we would reject (due to a claimed ambiguity) a case where lookup finds multiple NamespaceAliasDecls from different scopes that nominate the same namespace. The C++ standard doesn't make it clear that such a case is in fact valid (which I'm working on fixing), but there are no relevant rules that distinguish using declarations and namespace alias declarations here, so it makes sense to treat them the same way. llvm-svn: 256601
-rw-r--r--clang/include/clang/AST/Decl.h3
-rw-r--r--clang/lib/AST/Decl.cpp3
-rw-r--r--clang/lib/Sema/SemaCXXScopeSpec.cpp15
-rw-r--r--clang/lib/Sema/SemaCodeComplete.cpp17
-rw-r--r--clang/lib/Sema/SemaDeclCXX.cpp17
-rw-r--r--clang/test/SemaCXX/namespace-alias.cpp24
-rw-r--r--clang/test/SemaCXX/using-decl-1.cpp4
7 files changed, 54 insertions, 29 deletions
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index 6e588a6f84b..a006f424b7c 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -319,7 +319,8 @@ public:
NamedDecl *getUnderlyingDecl() {
// Fast-path the common case.
if (this->getKind() != UsingShadow &&
- this->getKind() != ObjCCompatibleAlias)
+ this->getKind() != ObjCCompatibleAlias &&
+ this->getKind() != NamespaceAlias)
return this;
return getUnderlyingDeclImpl();
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 243d4055840..9b43977b0bc 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -1607,6 +1607,9 @@ NamedDecl *NamedDecl::getUnderlyingDeclImpl() {
if (auto *AD = dyn_cast<ObjCCompatibleAliasDecl>(ND))
return AD->getClassInterface();
+ if (auto *AD = dyn_cast<NamespaceAliasDecl>(ND))
+ return AD->getNamespace();
+
return ND;
}
diff --git a/clang/lib/Sema/SemaCXXScopeSpec.cpp b/clang/lib/Sema/SemaCXXScopeSpec.cpp
index f943a10deb4..f7aace625a9 100644
--- a/clang/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp
@@ -291,8 +291,10 @@ bool Sema::isAcceptableNestedNameSpecifier(const NamedDecl *SD,
if (!SD)
return false;
+ SD = SD->getUnderlyingDecl();
+
// Namespace and namespace aliases are fine.
- if (isa<NamespaceDecl>(SD) || isa<NamespaceAliasDecl>(SD))
+ if (isa<NamespaceDecl>(SD))
return true;
if (!isa<TypeDecl>(SD))
@@ -396,10 +398,7 @@ bool Sema::isNonTypeNestedNameSpecifier(Scope *S, CXXScopeSpec &SS,
}
Found.suppressDiagnostics();
- if (NamedDecl *ND = Found.getAsSingle<NamedDecl>())
- return isa<NamespaceDecl>(ND) || isa<NamespaceAliasDecl>(ND);
-
- return false;
+ return Found.getAsSingle<NamespaceDecl>();
}
namespace {
@@ -615,7 +614,8 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S,
}
}
- NamedDecl *SD = Found.getAsSingle<NamedDecl>();
+ NamedDecl *SD =
+ Found.isSingleResult() ? Found.getRepresentativeDecl() : nullptr;
bool IsExtension = false;
bool AcceptSpec = isAcceptableNestedNameSpecifier(SD, &IsExtension);
if (!AcceptSpec && IsExtension) {
@@ -687,7 +687,8 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S,
return false;
}
- QualType T = Context.getTypeDeclType(cast<TypeDecl>(SD));
+ QualType T =
+ Context.getTypeDeclType(cast<TypeDecl>(SD->getUnderlyingDecl()));
TypeLocBuilder TLB;
if (isa<InjectedClassNameType>(T)) {
InjectedClassNameTypeLoc InjectedTL
diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp
index 5aa5fc5ebde..21cf6258514 100644
--- a/clang/lib/Sema/SemaCodeComplete.cpp
+++ b/clang/lib/Sema/SemaCodeComplete.cpp
@@ -494,6 +494,7 @@ bool ResultBuilder::isInterestingDecl(const NamedDecl *ND,
bool &AsNestedNameSpecifier) const {
AsNestedNameSpecifier = false;
+ auto *Named = ND;
ND = ND->getUnderlyingDecl();
// Skip unnamed entities.
@@ -526,14 +527,14 @@ bool ResultBuilder::isInterestingDecl(const NamedDecl *ND,
return false;
if (Filter == &ResultBuilder::IsNestedNameSpecifier ||
- ((isa<NamespaceDecl>(ND) || isa<NamespaceAliasDecl>(ND)) &&
+ (isa<NamespaceDecl>(ND) &&
Filter != &ResultBuilder::IsNamespace &&
Filter != &ResultBuilder::IsNamespaceOrAlias &&
Filter != nullptr))
AsNestedNameSpecifier = true;
// Filter out any unwanted results.
- if (Filter && !(this->*Filter)(ND)) {
+ if (Filter && !(this->*Filter)(Named)) {
// Check whether it is interesting as a nested-name-specifier.
if (AllowNestedNameSpecifiers && SemaRef.getLangOpts().CPlusPlus &&
IsNestedNameSpecifier(ND) &&
@@ -1142,14 +1143,12 @@ bool ResultBuilder::IsNamespace(const NamedDecl *ND) const {
/// \brief Determines whether the given declaration is a namespace or
/// namespace alias.
bool ResultBuilder::IsNamespaceOrAlias(const NamedDecl *ND) const {
- return isa<NamespaceDecl>(ND) || isa<NamespaceAliasDecl>(ND);
+ return isa<NamespaceDecl>(ND->getUnderlyingDecl());
}
/// \brief Determines whether the given declaration is a type.
bool ResultBuilder::IsType(const NamedDecl *ND) const {
- if (const UsingShadowDecl *Using = dyn_cast<UsingShadowDecl>(ND))
- ND = Using->getTargetDecl();
-
+ ND = ND->getUnderlyingDecl();
return isa<TypeDecl>(ND) || isa<ObjCInterfaceDecl>(ND);
}
@@ -1157,11 +1156,9 @@ bool ResultBuilder::IsType(const NamedDecl *ND) const {
/// "." or "->". Only value declarations, nested name specifiers, and
/// using declarations thereof should show up.
bool ResultBuilder::IsMember(const NamedDecl *ND) const {
- if (const UsingShadowDecl *Using = dyn_cast<UsingShadowDecl>(ND))
- ND = Using->getTargetDecl();
-
+ ND = ND->getUnderlyingDecl();
return isa<ValueDecl>(ND) || isa<FunctionTemplateDecl>(ND) ||
- isa<ObjCPropertyDecl>(ND);
+ isa<ObjCPropertyDecl>(ND);
}
static bool isObjCReceiverType(ASTContext &C, QualType T) {
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 634e699056e..b4d6175622d 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -7198,7 +7198,8 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
// as if by qualified name lookup.
LookupResult R(*this, II, IdentLoc, LookupOrdinaryName, ForRedeclaration);
LookupQualifiedName(R, CurContext->getRedeclContext());
- NamedDecl *PrevDecl = R.getAsSingle<NamedDecl>();
+ NamedDecl *PrevDecl =
+ R.isSingleResult() ? R.getRepresentativeDecl() : nullptr;
PrevNS = dyn_cast_or_null<NamespaceDecl>(PrevDecl);
if (PrevNS) {
@@ -7579,9 +7580,9 @@ Decl *Sema::ActOnUsingDirective(Scope *S,
}
if (!R.empty()) {
- NamedDecl *Named = R.getFoundDecl();
- assert((isa<NamespaceDecl>(Named) || isa<NamespaceAliasDecl>(Named))
- && "expected namespace decl");
+ NamedDecl *Named = R.getRepresentativeDecl();
+ NamespaceDecl *NS = R.getAsSingle<NamespaceDecl>();
+ assert(NS && "expected namespace decl");
// The use of a nested name specifier may trigger deprecation warnings.
DiagnoseUseOfDecl(Named, IdentLoc);
@@ -7598,7 +7599,6 @@ Decl *Sema::ActOnUsingDirective(Scope *S,
// Find enclosing context containing both using-directive and
// nominated namespace.
- NamespaceDecl *NS = getNamespaceDecl(Named);
DeclContext *CommonAncestor = cast<DeclContext>(NS);
while (CommonAncestor && !CommonAncestor->Encloses(CurContext))
CommonAncestor = CommonAncestor->getParent();
@@ -8669,7 +8669,7 @@ Decl *Sema::ActOnNamespaceAliasDef(Scope *S, SourceLocation NamespaceLoc,
}
}
assert(!R.isAmbiguous() && !R.empty());
- NamedDecl *ND = R.getFoundDecl();
+ NamedDecl *ND = R.getRepresentativeDecl();
// Check if we have a previous declaration with the same name.
LookupResult PrevR(*this, Alias, AliasLoc, LookupOrdinaryName,
@@ -8689,7 +8689,8 @@ Decl *Sema::ActOnNamespaceAliasDef(Scope *S, SourceLocation NamespaceLoc,
// Find the previous declaration and check that we can redeclare it.
NamespaceAliasDecl *Prev = nullptr;
if (NamedDecl *PrevDecl = PrevR.getAsSingle<NamedDecl>()) {
- if (NamespaceAliasDecl *AD = dyn_cast<NamespaceAliasDecl>(PrevDecl)) {
+ if (NamespaceAliasDecl *AD =
+ dyn_cast<NamespaceAliasDecl>(PrevR.getRepresentativeDecl())) {
// We already have an alias with the same name that points to the same
// namespace; check that it matches.
if (AD->getNamespace()->Equals(getNamespaceDecl(ND))) {
@@ -8697,7 +8698,7 @@ Decl *Sema::ActOnNamespaceAliasDef(Scope *S, SourceLocation NamespaceLoc,
} else if (isVisible(PrevDecl)) {
Diag(AliasLoc, diag::err_redefinition_different_namespace_alias)
<< Alias;
- Diag(PrevDecl->getLocation(), diag::note_previous_namespace_alias)
+ Diag(AD->getLocation(), diag::note_previous_namespace_alias)
<< AD->getNamespace();
return nullptr;
}
diff --git a/clang/test/SemaCXX/namespace-alias.cpp b/clang/test/SemaCXX/namespace-alias.cpp
index 1cf820e3e38..2ba771ed018 100644
--- a/clang/test/SemaCXX/namespace-alias.cpp
+++ b/clang/test/SemaCXX/namespace-alias.cpp
@@ -133,3 +133,27 @@ namespace PR25731 {
X::f();
}
}
+
+namespace MultipleUnambiguousLookupResults {
+ namespace A { int y; }
+ namespace B {
+ namespace X { int x; }
+ namespace Y = A;
+ namespace Z = A; // expected-note {{candidate}}
+ }
+ namespace C {
+ namespace X = B::X;
+ namespace Y = A;
+ namespace Z = X; // expected-note {{candidate}}
+ }
+ using namespace B;
+ using namespace C;
+ int x1 = X::x; // ok, unambiguous
+ int y1 = Y::y; // ok, unambiguous
+ int z1 = Z::x; // expected-error {{ambiguous}}
+
+ namespace X = C::X;
+ namespace Y = A;
+ int x2 = X::x; // ok, unambiguous
+ int y2 = Y::y; // ok, unambiguous
+}
diff --git a/clang/test/SemaCXX/using-decl-1.cpp b/clang/test/SemaCXX/using-decl-1.cpp
index 5afd15f8b50..ec45b3109a0 100644
--- a/clang/test/SemaCXX/using-decl-1.cpp
+++ b/clang/test/SemaCXX/using-decl-1.cpp
@@ -30,9 +30,7 @@ struct X0 {
};
struct X1 : X0 {
- // FIXME: give this operator() a 'float' parameter to test overloading
- // behavior. It currently fails.
- void operator()();
+ void operator()(float&);
using X0::operator();
void test() {
OpenPOWER on IntegriCloud