summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/lib/Sema/SemaLookup.cpp55
-rw-r--r--clang/test/CXX/drs/dr4xx.cpp18
-rw-r--r--clang/www/cxx_dr_status.html2
3 files changed, 48 insertions, 27 deletions
diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp
index a020dcf14d6..7236e99942b 100644
--- a/clang/lib/Sema/SemaLookup.cpp
+++ b/clang/lib/Sema/SemaLookup.cpp
@@ -368,13 +368,17 @@ static bool isPreferredLookupResult(Sema &S, Sema::LookupNameKind Kind,
auto *DUnderlying = D->getUnderlyingDecl();
auto *EUnderlying = Existing->getUnderlyingDecl();
- // If they have different underlying declarations, pick one arbitrarily
- // (this happens when two type declarations denote the same type).
- // FIXME: Should we prefer a struct declaration over a typedef or vice versa?
- // If a name could be a typedef-name or a class-name, which is it?
+ // If they have different underlying declarations, prefer a typedef over the
+ // original type (this happens when two type declarations denote the same
+ // type), per a generous reading of C++ [dcl.typedef]p3 and p4. The typedef
+ // might carry additional semantic information, such as an alignment override.
+ // However, per C++ [dcl.typedef]p5, when looking up a tag name, prefer a tag
+ // declaration over a typedef.
if (DUnderlying->getCanonicalDecl() != EUnderlying->getCanonicalDecl()) {
assert(isa<TypeDecl>(DUnderlying) && isa<TypeDecl>(EUnderlying));
- return false;
+ bool HaveTag = isa<TagDecl>(EUnderlying);
+ bool WantTag = Kind == Sema::LookupTagName;
+ return HaveTag != WantTag;
}
// Pick the function with more default arguments.
@@ -434,6 +438,23 @@ static bool isPreferredLookupResult(Sema &S, Sema::LookupNameKind Kind,
return !S.isVisible(Existing);
}
+/// Determine whether \p D can hide a tag declaration.
+static bool canHideTag(NamedDecl *D) {
+ // C++ [basic.scope.declarative]p4:
+ // Given a set of declarations in a single declarative region [...]
+ // exactly one declaration shall declare a class name or enumeration name
+ // that is not a typedef name and the other declarations shall all refer to
+ // the same variable or enumerator, or all refer to functions and function
+ // templates; in this case the class name or enumeration name is hidden.
+ // C++ [basic.scope.hiding]p2:
+ // A class name or enumeration name can be hidden by the name of a
+ // variable, data member, function, or enumerator declared in the same
+ // scope.
+ D = D->getUnderlyingDecl();
+ return isa<VarDecl>(D) || isa<EnumConstantDecl>(D) || isa<FunctionDecl>(D) ||
+ isa<FunctionTemplateDecl>(D) || isa<FieldDecl>(D);
+}
+
/// Resolves the result kind of this lookup.
void LookupResult::resolveKind() {
unsigned N = Decls.size();
@@ -489,15 +510,12 @@ void LookupResult::resolveKind() {
// no ambiguity if they all refer to the same type, so unique based on the
// canonical type.
if (TypeDecl *TD = dyn_cast<TypeDecl>(D)) {
- // FIXME: Why are nested type declarations treated differently?
- if (!TD->getDeclContext()->isRecord()) {
- QualType T = getSema().Context.getTypeDeclType(TD);
- auto UniqueResult = UniqueTypes.insert(
- std::make_pair(getSema().Context.getCanonicalType(T), I));
- if (!UniqueResult.second) {
- // The type is not unique.
- ExistingI = UniqueResult.first->second;
- }
+ QualType T = getSema().Context.getTypeDeclType(TD);
+ auto UniqueResult = UniqueTypes.insert(
+ std::make_pair(getSema().Context.getCanonicalType(T), I));
+ if (!UniqueResult.second) {
+ // The type is not unique.
+ ExistingI = UniqueResult.first->second;
}
}
@@ -564,10 +582,13 @@ void LookupResult::resolveKind() {
// wherever the object, function, or enumerator name is visible.
// But it's still an error if there are distinct tag types found,
// even if they're not visible. (ref?)
- if (HideTags && HasTag && !Ambiguous &&
+ if (N > 1 && HideTags && HasTag && !Ambiguous &&
(HasFunction || HasNonFunction || HasUnresolved)) {
- if (getContextForScopeMatching(Decls[UniqueTagIndex])->Equals(
- getContextForScopeMatching(Decls[UniqueTagIndex ? 0 : N - 1])))
+ NamedDecl *OtherDecl = Decls[UniqueTagIndex ? 0 : N - 1];
+ if (isa<TagDecl>(Decls[UniqueTagIndex]->getUnderlyingDecl()) &&
+ getContextForScopeMatching(Decls[UniqueTagIndex])->Equals(
+ getContextForScopeMatching(OtherDecl)) &&
+ canHideTag(OtherDecl))
Decls[UniqueTagIndex] = Decls[--N];
else
Ambiguous = true;
diff --git a/clang/test/CXX/drs/dr4xx.cpp b/clang/test/CXX/drs/dr4xx.cpp
index 2a548e2eaba..bceea793faf 100644
--- a/clang/test/CXX/drs/dr4xx.cpp
+++ b/clang/test/CXX/drs/dr4xx.cpp
@@ -83,7 +83,7 @@ namespace dr406 { // dr406: yes
} A;
}
-namespace dr407 { // dr407: no
+namespace dr407 { // dr407: 3.8
struct S;
typedef struct S S;
void f() {
@@ -108,22 +108,22 @@ namespace dr407 { // dr407: no
struct S s; // expected-error {{ambiguous}}
}
namespace D {
- // FIXME: This is valid.
using A::S;
- typedef struct S S; // expected-note {{here}}
- struct S s; // expected-error {{refers to a typedef}}
+ typedef struct S S;
+ struct S s;
}
namespace E {
- // FIXME: The standard doesn't say whether this is valid.
+ // The standard doesn't say whether this is valid. We interpret
+ // DR407 as meaning "if lookup finds both a tag and a typedef with the
+ // same type, then it's OK in an elaborated-type-specifier".
typedef A::S S;
using A::S;
struct S s;
}
namespace F {
- typedef A::S S; // expected-note {{here}}
+ typedef A::S S;
}
- // FIXME: The standard doesn't say what to do in these cases, but
- // our behavior should not depend on the order of the using-directives.
+ // The standard doesn't say what to do in these cases either.
namespace G {
using namespace A;
using namespace F;
@@ -132,7 +132,7 @@ namespace dr407 { // dr407: no
namespace H {
using namespace F;
using namespace A;
- struct S s; // expected-error {{refers to a typedef}}
+ struct S s;
}
}
}
diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html
index 0c5339176a6..6b63fb21cf9 100644
--- a/clang/www/cxx_dr_status.html
+++ b/clang/www/cxx_dr_status.html
@@ -2483,7 +2483,7 @@ of class templates</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#407">407</a></td>
<td>C++11</td>
<td>Named class with associated typedef: two names or one?</td>
- <td class="none" align="center">No</td>
+ <td class="svn" align="center">SVN</td>
</tr>
<tr id="408">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#408">408</a></td>
OpenPOWER on IntegriCloud