diff options
-rw-r--r-- | clang/lib/Sema/SemaLookup.cpp | 55 | ||||
-rw-r--r-- | clang/test/CXX/drs/dr4xx.cpp | 18 | ||||
-rw-r--r-- | clang/www/cxx_dr_status.html | 2 |
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> |