diff options
author | Krystian Stasiowski <sdkrystian@gmail.com> | 2024-07-09 19:00:19 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-07-09 19:00:19 -0400 |
commit | 7bfb98c34687d9784f36937c3ff3e735698b498a (patch) | |
tree | 4fd464b55299ec427dc54c2e21e4a1bb354790a5 /clang/lib | |
parent | afbd7d1e7c7155b07561e46275a451fec917c34c (diff) | |
download | llvm-7bfb98c34687d9784f36937c3ff3e735698b498a.zip llvm-7bfb98c34687d9784f36937c3ff3e735698b498a.tar.gz llvm-7bfb98c34687d9784f36937c3ff3e735698b498a.tar.bz2 |
[Clang] Implement resolution for CWG1835 (#92957)
CWG1835 was one of the many core issues resolved by P1787R6: "Declarations and where to
find them" (http://wg21.link/p1787r6). Its resolution changes how
member-qualified names (as defined by [basic.lookup.qual.general] p2) are looked
up. This patch implementation that resolution.
Previously, an _identifier_ following `.` or `->` would be first looked
up in the type of the object expression (i.e. qualified lookup), and
then in the context of the _postfix-expression_ (i.e. unqualified
lookup) if nothing was found; the result of the second lookup was
required to name a class template. Notably, this second lookup would
occur even when the object expression was dependent, and its result
would be used to determine whether a `<` token is the start of a
_template-argument_list_.
The new wording in [basic.lookup.qual.general] p2 states:
> A member-qualified name is the (unique) component name, if any, of
> - an _unqualified-id_ or
> - a _nested-name-specifier_ of the form _`type-name ::`_ or
_`namespace-name ::`​_
>
> in the id-expression of a class member access expression. A
***qualified name*** is
> - a member-qualified name or
> - the terminal name of
> - a _qualified-id_,
> - a _using-declarator_,
> - a _typename-specifier_,
> - a _qualified-namespace-specifier_, or
> - a _nested-name-specifier_, _elaborated-type-specifier_, or
_class-or-decltype_ that has a _nested-name-specifier_.
>
> The _lookup context_ of a member-qualified name is the type of its
associated object expression (considered dependent if the object
expression is type-dependent). The lookup context of any other qualified
name is the type, template, or namespace nominated by the preceding
_nested-name-specifier_.
And [basic.lookup.qual.general] p3 now states:
> _Qualified name lookup_ in a class, namespace, or enumeration performs
a search of the scope associated with it except as specified below.
Unless otherwise specified, a qualified name undergoes qualified name
lookup in its lookup context from the point where it appears unless the
lookup context either is dependent and is not the current instantiation
or is not a class or class template. If nothing is found by qualified
lookup for a member-qualified name that is the terminal name of a
_nested-name-specifier_ and is not dependent, it undergoes unqualified
lookup.
In non-standardese terms, these two paragraphs essentially state the
following:
- A name that immediately follows `.` or `->` in a class member access
expression is a member-qualified name
- A member-qualified name will be first looked up in the type of the
object expression `T` unless `T` is a dependent type that is _not_ the
current instantiation, e.g.
```
template<typename T>
struct A
{
void f(T* t)
{
this->x; // type of the object expression is 'A<T>'. although 'A<T>' is dependent, it is the
// current instantiation so we look up 'x' in the template definition context.
t->y; // type of the object expression is 'T' ('->' is transformed to '.' per [expr.ref]).
// 'T' is dependent and is *not* the current instantiation, so we lookup 'y' in the
// template instantiation context.
}
};
```
- If the first lookup finds nothing and:
- the member-qualified name is the first component of a
_nested-name-specifier_ (which could be an _identifier_ or a
_simple-template-id_), and either:
- the type of the object expression is the current instantiation and it
has no dependent base classes, or
- the type of the object expression is not dependent
then we lookup the name again, this time via unqualified lookup.
Although the second (unqualified) lookup is stated not to occur when the
member-qualified name is dependent, a dependent name will _not_ be
dependent once the template is instantiated, so the second lookup must
"occur" during instantiation if qualified lookup does not find anything.
This means that we must perform the second (unqualified) lookup during
parsing even when the type of the object expression is dependent, but
those results are _not_ used to determine whether a `<` token is the
start of a _template-argument_list_; they are stored so we can replicate
the second lookup during instantiation.
In even simpler terms (paraphrasing the meeting minutes from the review of P1787; see https://wiki.edg.com/bin/view/Wg21summer2020/P1787%28Lookup%29Review2020-06-15Through2020-06-18):
- Unqualified lookup always happens for the first name in a
_nested-name-specifier_ that follows `.` or `->`
- The result of that lookup is only used to determine whether `<` is the
start of a _template-argument-list_ if the first (qualified) lookup
found nothing and the lookup context:
- is not dependent, or
- is the current instantiation and has no dependent base classes.
An example:
```
struct A
{
void f();
};
template<typename T>
using B = A;
template<typename T>
struct C : A
{
template<typename U>
void g();
void h(T* t)
{
this->g<int>(); // ok, '<' is the start of a template-argument-list ('g' was found via qualified lookup in the current instantiation)
this->B<void>::f(); // ok, '<' is the start of a template-argument-list (current instantiation has no dependent bases, 'B' was found via unqualified lookup)
t->g<int>(); // error: '<' means less than (unqualified lookup does not occur for a member-qualified name that isn't the first component of a nested-name-specifier)
t->B<void>::f(); // error: '<' means less than (unqualified lookup does not occur if the name is dependent)
t->template B<void>::f(); // ok: '<' is the start of a template-argument-list ('template' keyword used)
}
};
```
Some additional notes:
- Per [basic.lookup.qual.general] p1, lookup for a
member-qualified name only considers namespaces, types, and templates
whose specializations are types if it's an _identifier_ followed by
`::`; lookup for the component name of a _simple-template-id_ followed
by `::` is _not_ subject to this rule.
- The wording which specifies when the second unqualified lookup occurs
appears to be paradoxical. We are supposed to do it only for the first
component name of a _nested-name-specifier_ that follows `.` or `->`
when qualified lookup finds nothing. However, when that name is followed
by `<` (potentially starting a _simple-template-id_) we don't _know_
whether it will be the start of a _nested-name-specifier_ until we do
the lookup -- but we aren't supposed to do the lookup until we know it's
part of a _nested-name-specifier_! ***However***, since we only do the
second lookup when the first lookup finds nothing (and the name isn't
dependent), ***and*** since neither lookup is type-only, the only valid
option is for the name to be the _template-name_ in a
_simple-template-id_ that is followed by `::` (it can't be an
_unqualified-id_ naming a member because we already determined that the
lookup context doesn't have a member with that name). Thus, we can lock
into the _nested-name-specifier_ interpretation and do the second lookup
without having to know whether the _simple-template-id_ will be followed
by `::` yet.
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/AST/ASTImporter.cpp | 12 | ||||
-rw-r--r-- | clang/lib/AST/ExprCXX.cpp | 67 | ||||
-rw-r--r-- | clang/lib/AST/ItaniumMangle.cpp | 39 | ||||
-rw-r--r-- | clang/lib/Parse/ParseExpr.cpp | 7 | ||||
-rw-r--r-- | clang/lib/Parse/ParseExprCXX.cpp | 95 | ||||
-rw-r--r-- | clang/lib/Sema/SemaCXXScopeSpec.cpp | 195 | ||||
-rw-r--r-- | clang/lib/Sema/SemaCoroutine.cpp | 4 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 47 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExprMember.cpp | 74 | ||||
-rw-r--r-- | clang/lib/Sema/SemaOverload.cpp | 12 | ||||
-rw-r--r-- | clang/lib/Sema/SemaStmtAsm.cpp | 8 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplate.cpp | 218 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiate.cpp | 17 | ||||
-rw-r--r-- | clang/lib/Sema/TreeTransform.h | 329 | ||||
-rw-r--r-- | clang/lib/Serialization/ASTReaderStmt.cpp | 63 | ||||
-rw-r--r-- | clang/lib/Serialization/ASTWriterStmt.cpp | 43 |
17 files changed, 577 insertions, 655 deletions
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 4e1b3a5..9bb035c 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -8439,8 +8439,14 @@ ExpectedStmt ASTNodeImporter::VisitCXXDependentScopeMemberExpr( auto ToOperatorLoc = importChecked(Err, E->getOperatorLoc()); auto ToQualifierLoc = importChecked(Err, E->getQualifierLoc()); auto ToTemplateKeywordLoc = importChecked(Err, E->getTemplateKeywordLoc()); - auto ToFirstQualifierFoundInScope = - importChecked(Err, E->getFirstQualifierFoundInScope()); + + UnresolvedSet<8> ToUnqualifiedLookups; + for (auto D : E->unqualified_lookups()) + if (auto ToDOrErr = import(D.getDecl())) + ToUnqualifiedLookups.addDecl(*ToDOrErr); + else + return ToDOrErr.takeError(); + if (Err) return std::move(Err); @@ -8474,7 +8480,7 @@ ExpectedStmt ASTNodeImporter::VisitCXXDependentScopeMemberExpr( return CXXDependentScopeMemberExpr::Create( Importer.getToContext(), ToBase, ToType, E->isArrow(), ToOperatorLoc, - ToQualifierLoc, ToTemplateKeywordLoc, ToFirstQualifierFoundInScope, + ToQualifierLoc, ToTemplateKeywordLoc, ToUnqualifiedLookups.pairs(), ToMemberNameInfo, ResInfo); } diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp index 8d2a1b5..9d2883a 100644 --- a/clang/lib/AST/ExprCXX.cpp +++ b/clang/lib/AST/ExprCXX.cpp @@ -1489,19 +1489,27 @@ SourceLocation CXXUnresolvedConstructExpr::getBeginLoc() const { CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr( const ASTContext &Ctx, Expr *Base, QualType BaseType, bool IsArrow, SourceLocation OperatorLoc, NestedNameSpecifierLoc QualifierLoc, - SourceLocation TemplateKWLoc, NamedDecl *FirstQualifierFoundInScope, + SourceLocation TemplateKWLoc, ArrayRef<DeclAccessPair> UnqualifiedLookups, DeclarationNameInfo MemberNameInfo, const TemplateArgumentListInfo *TemplateArgs) : Expr(CXXDependentScopeMemberExprClass, Ctx.DependentTy, VK_LValue, OK_Ordinary), - Base(Base), BaseType(BaseType), QualifierLoc(QualifierLoc), - MemberNameInfo(MemberNameInfo) { + Base(Base), BaseType(BaseType), MemberNameInfo(MemberNameInfo), + OperatorLoc(OperatorLoc) { CXXDependentScopeMemberExprBits.IsArrow = IsArrow; + CXXDependentScopeMemberExprBits.HasQualifier = QualifierLoc.hasQualifier(); + CXXDependentScopeMemberExprBits.NumUnqualifiedLookups = + UnqualifiedLookups.size(); CXXDependentScopeMemberExprBits.HasTemplateKWAndArgsInfo = (TemplateArgs != nullptr) || TemplateKWLoc.isValid(); - CXXDependentScopeMemberExprBits.HasFirstQualifierFoundInScope = - FirstQualifierFoundInScope != nullptr; - CXXDependentScopeMemberExprBits.OperatorLoc = OperatorLoc; + + if (hasQualifier()) + new (getTrailingObjects<NestedNameSpecifierLoc>()) + NestedNameSpecifierLoc(QualifierLoc); + + std::uninitialized_copy_n(UnqualifiedLookups.data(), + UnqualifiedLookups.size(), + getTrailingObjects<DeclAccessPair>()); if (TemplateArgs) { auto Deps = TemplateArgumentDependence::None; @@ -1513,54 +1521,59 @@ CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr( TemplateKWLoc); } - if (hasFirstQualifierFoundInScope()) - *getTrailingObjects<NamedDecl *>() = FirstQualifierFoundInScope; setDependence(computeDependence(this)); } CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr( - EmptyShell Empty, bool HasTemplateKWAndArgsInfo, - bool HasFirstQualifierFoundInScope) + EmptyShell Empty, bool HasQualifier, unsigned NumUnqualifiedLookups, + bool HasTemplateKWAndArgsInfo) : Expr(CXXDependentScopeMemberExprClass, Empty) { + CXXDependentScopeMemberExprBits.HasQualifier = HasQualifier; + CXXDependentScopeMemberExprBits.NumUnqualifiedLookups = NumUnqualifiedLookups; CXXDependentScopeMemberExprBits.HasTemplateKWAndArgsInfo = HasTemplateKWAndArgsInfo; - CXXDependentScopeMemberExprBits.HasFirstQualifierFoundInScope = - HasFirstQualifierFoundInScope; } CXXDependentScopeMemberExpr *CXXDependentScopeMemberExpr::Create( const ASTContext &Ctx, Expr *Base, QualType BaseType, bool IsArrow, SourceLocation OperatorLoc, NestedNameSpecifierLoc QualifierLoc, - SourceLocation TemplateKWLoc, NamedDecl *FirstQualifierFoundInScope, + SourceLocation TemplateKWLoc, ArrayRef<DeclAccessPair> UnqualifiedLookups, DeclarationNameInfo MemberNameInfo, const TemplateArgumentListInfo *TemplateArgs) { + bool HasQualifier = QualifierLoc.hasQualifier(); + unsigned NumUnqualifiedLookups = UnqualifiedLookups.size(); + assert(!NumUnqualifiedLookups || HasQualifier); bool HasTemplateKWAndArgsInfo = (TemplateArgs != nullptr) || TemplateKWLoc.isValid(); unsigned NumTemplateArgs = TemplateArgs ? TemplateArgs->size() : 0; - bool HasFirstQualifierFoundInScope = FirstQualifierFoundInScope != nullptr; - - unsigned Size = totalSizeToAlloc<ASTTemplateKWAndArgsInfo, - TemplateArgumentLoc, NamedDecl *>( - HasTemplateKWAndArgsInfo, NumTemplateArgs, HasFirstQualifierFoundInScope); + unsigned Size = + totalSizeToAlloc<NestedNameSpecifierLoc, DeclAccessPair, + ASTTemplateKWAndArgsInfo, TemplateArgumentLoc>( + HasQualifier, NumUnqualifiedLookups, HasTemplateKWAndArgsInfo, + NumTemplateArgs); void *Mem = Ctx.Allocate(Size, alignof(CXXDependentScopeMemberExpr)); return new (Mem) CXXDependentScopeMemberExpr( Ctx, Base, BaseType, IsArrow, OperatorLoc, QualifierLoc, TemplateKWLoc, - FirstQualifierFoundInScope, MemberNameInfo, TemplateArgs); + UnqualifiedLookups, MemberNameInfo, TemplateArgs); } CXXDependentScopeMemberExpr *CXXDependentScopeMemberExpr::CreateEmpty( - const ASTContext &Ctx, bool HasTemplateKWAndArgsInfo, - unsigned NumTemplateArgs, bool HasFirstQualifierFoundInScope) { - assert(NumTemplateArgs == 0 || HasTemplateKWAndArgsInfo); + const ASTContext &Ctx, bool HasQualifier, unsigned NumUnqualifiedLookups, + bool HasTemplateKWAndArgsInfo, unsigned NumTemplateArgs) { + assert(!NumTemplateArgs || HasTemplateKWAndArgsInfo); + assert(!NumUnqualifiedLookups || HasQualifier); - unsigned Size = totalSizeToAlloc<ASTTemplateKWAndArgsInfo, - TemplateArgumentLoc, NamedDecl *>( - HasTemplateKWAndArgsInfo, NumTemplateArgs, HasFirstQualifierFoundInScope); + unsigned Size = + totalSizeToAlloc<NestedNameSpecifierLoc, DeclAccessPair, + ASTTemplateKWAndArgsInfo, TemplateArgumentLoc>( + HasQualifier, NumUnqualifiedLookups, HasTemplateKWAndArgsInfo, + NumTemplateArgs); void *Mem = Ctx.Allocate(Size, alignof(CXXDependentScopeMemberExpr)); - return new (Mem) CXXDependentScopeMemberExpr( - EmptyShell(), HasTemplateKWAndArgsInfo, HasFirstQualifierFoundInScope); + return new (Mem) CXXDependentScopeMemberExpr(EmptyShell(), HasQualifier, + NumUnqualifiedLookups, + HasTemplateKWAndArgsInfo); } CXXThisExpr *CXXThisExpr::Create(const ASTContext &Ctx, SourceLocation L, diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 5444dcf..f14c476 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -594,11 +594,10 @@ private: void mangleMemberExprBase(const Expr *base, bool isArrow); void mangleMemberExpr(const Expr *base, bool isArrow, NestedNameSpecifier *qualifier, - NamedDecl *firstQualifierLookup, + ArrayRef<DeclAccessPair> UnqualifiedLookups, DeclarationName name, const TemplateArgumentLoc *TemplateArgs, - unsigned NumTemplateArgs, - unsigned knownArity); + unsigned NumTemplateArgs, unsigned knownArity); void mangleCastExpression(const Expr *E, StringRef CastEncoding); void mangleInitListElements(const InitListExpr *InitList); void mangleRequirement(SourceLocation RequiresExprLoc, @@ -4496,14 +4495,11 @@ void CXXNameMangler::mangleMemberExprBase(const Expr *Base, bool IsArrow) { } /// Mangles a member expression. -void CXXNameMangler::mangleMemberExpr(const Expr *base, - bool isArrow, - NestedNameSpecifier *qualifier, - NamedDecl *firstQualifierLookup, - DeclarationName member, - const TemplateArgumentLoc *TemplateArgs, - unsigned NumTemplateArgs, - unsigned arity) { +void CXXNameMangler::mangleMemberExpr( + const Expr *base, bool isArrow, NestedNameSpecifier *qualifier, + ArrayRef<DeclAccessPair> UnqualifiedLookups, DeclarationName member, + const TemplateArgumentLoc *TemplateArgs, unsigned NumTemplateArgs, + unsigned arity) { // <expression> ::= dt <expression> <unresolved-name> // ::= pt <expression> <unresolved-name> if (base) @@ -4985,11 +4981,9 @@ recurse: case Expr::MemberExprClass: { NotPrimaryExpr(); const MemberExpr *ME = cast<MemberExpr>(E); - mangleMemberExpr(ME->getBase(), ME->isArrow(), - ME->getQualifier(), nullptr, - ME->getMemberDecl()->getDeclName(), - ME->getTemplateArgs(), ME->getNumTemplateArgs(), - Arity); + mangleMemberExpr(ME->getBase(), ME->isArrow(), ME->getQualifier(), + std::nullopt, ME->getMemberDecl()->getDeclName(), + ME->getTemplateArgs(), ME->getNumTemplateArgs(), Arity); break; } @@ -4997,10 +4991,9 @@ recurse: NotPrimaryExpr(); const UnresolvedMemberExpr *ME = cast<UnresolvedMemberExpr>(E); mangleMemberExpr(ME->isImplicitAccess() ? nullptr : ME->getBase(), - ME->isArrow(), ME->getQualifier(), nullptr, - ME->getMemberName(), - ME->getTemplateArgs(), ME->getNumTemplateArgs(), - Arity); + ME->isArrow(), ME->getQualifier(), std::nullopt, + ME->getMemberName(), ME->getTemplateArgs(), + ME->getNumTemplateArgs(), Arity); break; } @@ -5010,10 +5003,8 @@ recurse: = cast<CXXDependentScopeMemberExpr>(E); mangleMemberExpr(ME->isImplicitAccess() ? nullptr : ME->getBase(), ME->isArrow(), ME->getQualifier(), - ME->getFirstQualifierFoundInScope(), - ME->getMember(), - ME->getTemplateArgs(), ME->getNumTemplateArgs(), - Arity); + ME->unqualified_lookups(), ME->getMember(), + ME->getTemplateArgs(), ME->getNumTemplateArgs(), Arity); break; } diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index 2dd2e1b..b98eb70 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -2343,10 +2343,9 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { } if (!LHS.isInvalid()) - LHS = Actions.ActOnMemberAccessExpr(getCurScope(), LHS.get(), OpLoc, - OpKind, SS, TemplateKWLoc, Name, - CurParsedObjCImpl ? CurParsedObjCImpl->Dcl - : nullptr); + LHS = Actions.ActOnMemberAccessExpr( + getCurScope(), LHS.get(), OpLoc, OpKind, SS, TemplateKWLoc, Name, + CurParsedObjCImpl ? CurParsedObjCImpl->Dcl : nullptr); if (!LHS.isInvalid()) { if (Tok.is(tok::less)) checkPotentialAngleBracket(LHS); diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index 1d364f7..17be090 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -100,7 +100,8 @@ void Parser::CheckForTemplateAndDigraph(Token &Next, ParsedType ObjectType, bool MemberOfUnknownSpecialization; if (!Actions.isTemplateName(getCurScope(), SS, /*hasTemplateKeyword=*/false, TemplateName, ObjectType, EnteringContext, - Template, MemberOfUnknownSpecialization)) + Template, MemberOfUnknownSpecialization, + /*Disambiguation=*/false, /*MayBeNNS=*/true)) return; FixDigraph(*this, PP, Next, SecondToken, tok::unknown, @@ -353,7 +354,8 @@ bool Parser::ParseOptionalCXXScopeSpecifier( TemplateTy Template; TemplateNameKind TNK = Actions.ActOnTemplateName( getCurScope(), SS, TemplateKWLoc, TemplateName, ObjectType, - EnteringContext, Template, /*AllowInjectedClassName*/ true); + EnteringContext, Template, /*AllowInjectedClassName*/ true, + /*MayBeNNS=*/true); if (AnnotateTemplateIdToken(Template, TNK, SS, TemplateKWLoc, TemplateName, false)) return true; @@ -405,7 +407,6 @@ bool Parser::ParseOptionalCXXScopeSpecifier( : TemplateId->TemplateNameLoc; SS.SetInvalid(SourceRange(StartLoc, CCLoc)); } - continue; } @@ -528,18 +529,19 @@ bool Parser::ParseOptionalCXXScopeSpecifier( UnqualifiedId TemplateName; TemplateName.setIdentifier(&II, Tok.getLocation()); bool MemberOfUnknownSpecialization; - if (TemplateNameKind TNK = Actions.isTemplateName(getCurScope(), SS, - /*hasTemplateKeyword=*/false, - TemplateName, - ObjectType, - EnteringContext, - Template, - MemberOfUnknownSpecialization)) { + if (TemplateNameKind TNK = Actions.isTemplateName( + getCurScope(), SS, + /*hasTemplateKeyword=*/false, TemplateName, ObjectType, + EnteringContext, Template, MemberOfUnknownSpecialization, + /*Disambiguation=*/false, + /*MayBeNNS=*/true)) { // If lookup didn't find anything, we treat the name as a template-name // anyway. C++20 requires this, and in prior language modes it improves // error recovery. But before we commit to this, check that we actually // have something that looks like a template-argument-list next. - if (!IsTypename && TNK == TNK_Undeclared_template && + if (!IsTypename && + (TNK == TNK_Undeclared_template || + (!HasScopeSpecifier && ObjectType)) && isTemplateArgumentList(1) == TPResult::False) break; @@ -566,11 +568,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier( // member of an unknown specialization. However, this will only // parse correctly as a template, so suggest the keyword 'template' // before 'getAs' and treat this as a dependent template name. - unsigned DiagID = diag::err_missing_dependent_template_keyword; - if (getLangOpts().MicrosoftExt) - DiagID = diag::warn_missing_dependent_template_keyword; - - Diag(Tok.getLocation(), DiagID) + Diag(Tok.getLocation(), diag::ext_missing_dependent_template_keyword) << II.getName() << FixItHint::CreateInsertion(Tok.getLocation(), "template "); } @@ -1920,12 +1918,12 @@ Parser::ParseCXXPseudoDestructor(Expr *Base, SourceLocation OpLoc, // argument list. This affects examples such as // void f(auto *p) { p->~X<int>(); } // ... but there's no ambiguity, and nowhere to write 'template' in such an - // example, so we accept it anyway. - if (Tok.is(tok::less) && - ParseUnqualifiedIdTemplateId( - SS, ObjectType, Base && Base->containsErrors(), SourceLocation(), - Name, NameLoc, false, SecondTypeName, - /*AssumeTemplateId=*/true)) + // example, so we accept it anyway + if (Tok.is(tok::less) && ParseUnqualifiedIdTemplateId( + SS, ObjectType, Base && Base->containsErrors(), + /*TemplateKWLoc=*/SourceLocation(), TildeLoc, + Name, NameLoc, false, SecondTypeName, + /*AssumeTemplateId=*/true)) return ExprError(); return Actions.ActOnPseudoDestructorExpr(getCurScope(), Base, OpLoc, OpKind, @@ -2532,8 +2530,9 @@ bool Parser::ParseCXXTypeSpecifierSeq(DeclSpec &DS, DeclaratorContext Context) { /// \returns true if a parse error occurred, false otherwise. bool Parser::ParseUnqualifiedIdTemplateId( CXXScopeSpec &SS, ParsedType ObjectType, bool ObjectHadErrors, - SourceLocation TemplateKWLoc, IdentifierInfo *Name, SourceLocation NameLoc, - bool EnteringContext, UnqualifiedId &Id, bool AssumeTemplateId) { + SourceLocation TemplateKWLoc, SourceLocation TildeLoc, IdentifierInfo *Name, + SourceLocation NameLoc, bool EnteringContext, UnqualifiedId &Id, + bool AssumeTemplateId) { assert(Tok.is(tok::less) && "Expected '<' to finish parsing a template-id"); TemplateTy Template; @@ -2547,13 +2546,14 @@ bool Parser::ParseUnqualifiedIdTemplateId( // this template-id is used to form a nested-name-specifier or not. TNK = Actions.ActOnTemplateName(getCurScope(), SS, TemplateKWLoc, Id, ObjectType, EnteringContext, Template, - /*AllowInjectedClassName*/ true); + /*AllowInjectedClassName=*/true, + TildeLoc.isValid()); } else { bool MemberOfUnknownSpecialization; - TNK = Actions.isTemplateName(getCurScope(), SS, - TemplateKWLoc.isValid(), Id, - ObjectType, EnteringContext, Template, - MemberOfUnknownSpecialization); + TNK = Actions.isTemplateName( + getCurScope(), SS, TemplateKWLoc.isValid(), Id, ObjectType, + EnteringContext, Template, MemberOfUnknownSpecialization, + /*Disambiguation=*/false, TildeLoc.isValid()); // If lookup found nothing but we're assuming that this is a template // name, double-check that makes sense syntactically before committing // to it. @@ -2580,13 +2580,13 @@ bool Parser::ParseUnqualifiedIdTemplateId( else Name += Id.Identifier->getName(); } - Diag(Id.StartLocation, diag::err_missing_dependent_template_keyword) + Diag(Id.StartLocation, diag::ext_missing_dependent_template_keyword) << Name << FixItHint::CreateInsertion(Id.StartLocation, "template "); } TNK = Actions.ActOnTemplateName( getCurScope(), SS, TemplateKWLoc, Id, ObjectType, EnteringContext, - Template, /*AllowInjectedClassName*/ true); + Template, /*AllowInjectedClassName=*/true, TildeLoc.isValid()); } else if (TNK == TNK_Non_template) { return false; } @@ -2611,14 +2611,16 @@ bool Parser::ParseUnqualifiedIdTemplateId( bool MemberOfUnknownSpecialization; TemplateName.setIdentifier(Name, NameLoc); if (ObjectType) { - TNK = Actions.ActOnTemplateName( - getCurScope(), SS, TemplateKWLoc, TemplateName, ObjectType, - EnteringContext, Template, /*AllowInjectedClassName*/ true); + TNK = Actions.ActOnTemplateName(getCurScope(), SS, TemplateKWLoc, + TemplateName, ObjectType, EnteringContext, + Template, /*AllowInjectedClassName=*/true, + /*MayBeNNS=*/true); } else { TNK = Actions.isTemplateName(getCurScope(), SS, TemplateKWLoc.isValid(), - TemplateName, ObjectType, - EnteringContext, Template, - MemberOfUnknownSpecialization); + TemplateName, ObjectType, EnteringContext, + Template, MemberOfUnknownSpecialization, + /*Disambiguation=*/false, + /*MayBeNNS=*/true); if (TNK == TNK_Non_template && !Id.DestructorName.get()) { Diag(NameLoc, diag::err_destructor_template_id) @@ -2680,7 +2682,7 @@ bool Parser::ParseUnqualifiedIdTemplateId( if (Id.getKind() == UnqualifiedIdKind::IK_ConstructorName) Id.setConstructorName(Type.get(), NameLoc, RAngleLoc); else - Id.setDestructorName(Id.StartLocation, Type.get(), RAngleLoc); + Id.setDestructorName(TildeLoc, Type.get(), RAngleLoc); return false; } @@ -3028,8 +3030,9 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, ParsedType ObjectType, if (Tok.is(tok::less)) return ParseUnqualifiedIdTemplateId( SS, ObjectType, ObjectHadErrors, - TemplateKWLoc ? *TemplateKWLoc : SourceLocation(), Id, IdLoc, - EnteringContext, Result, TemplateSpecified); + TemplateKWLoc ? *TemplateKWLoc : SourceLocation(), + /*TildeLoc=*/SourceLocation(), Id, IdLoc, EnteringContext, Result, + TemplateSpecified); if (TemplateSpecified) { TemplateNameKind TNK = @@ -3124,13 +3127,15 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, ParsedType ObjectType, Tok.is(tok::less)) return ParseUnqualifiedIdTemplateId( SS, ObjectType, ObjectHadErrors, - TemplateKWLoc ? *TemplateKWLoc : SourceLocation(), nullptr, - SourceLocation(), EnteringContext, Result, TemplateSpecified); + TemplateKWLoc ? *TemplateKWLoc : SourceLocation(), + /*TildeLoc=*/SourceLocation(), /*Name=*/nullptr, + /*NameLoc=*/SourceLocation(), EnteringContext, Result, + TemplateSpecified); else if (TemplateSpecified && Actions.ActOnTemplateName( getCurScope(), SS, *TemplateKWLoc, Result, ObjectType, EnteringContext, Template, - /*AllowInjectedClassName*/ true) == TNK_Non_template) + /*AllowInjectedClassName=*/true) == TNK_Non_template) return true; return false; @@ -3220,8 +3225,8 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, ParsedType ObjectType, Result.setDestructorName(TildeLoc, nullptr, ClassNameLoc); return ParseUnqualifiedIdTemplateId( SS, ObjectType, ObjectHadErrors, - TemplateKWLoc ? *TemplateKWLoc : SourceLocation(), ClassName, - ClassNameLoc, EnteringContext, Result, TemplateSpecified); + TemplateKWLoc ? *TemplateKWLoc : SourceLocation(), TildeLoc, + ClassName, ClassNameLoc, EnteringContext, Result, TemplateSpecified); } // Note that this is a destructor name. diff --git a/clang/lib/Sema/SemaCXXScopeSpec.cpp b/clang/lib/Sema/SemaCXXScopeSpec.cpp index 5b2d652..dd61bb22 100644 --- a/clang/lib/Sema/SemaCXXScopeSpec.cpp +++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp @@ -356,29 +356,41 @@ bool Sema::isAcceptableNestedNameSpecifier(const NamedDecl *SD, return false; } -NamedDecl *Sema::FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS) { - if (!S || !NNS) - return nullptr; +/// If the given nested-name-specifier begins with a bare identifier +/// (e.g., Base::), perform name lookup for that identifier as a +/// nested-name-specifier within the given scope, and return the result of that +/// name lookup. +bool Sema::LookupFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS, + UnresolvedSetImpl &R) { + if (!S) + return false; while (NNS->getPrefix()) NNS = NNS->getPrefix(); - if (NNS->getKind() != NestedNameSpecifier::Identifier) - return nullptr; - - LookupResult Found(*this, NNS->getAsIdentifier(), SourceLocation(), - LookupNestedNameSpecifierName); + // FIXME: This is a rather nasty hack! Ideally we should get the results + // from LookupTemplateName/BuildCXXNestedNameSpecifier. + const IdentifierInfo *II = NNS->getAsIdentifier(); + if (!II) { + if (const auto *DTST = + dyn_cast_if_present<DependentTemplateSpecializationType>( + NNS->getAsType())) + II = DTST->getIdentifier(); + else + return false; + } + assert(II && "Missing first qualifier in scope"); + LookupResult Found(*this, II, SourceLocation(), + NNS->getAsIdentifier() ? LookupNestedNameSpecifierName + : LookupOrdinaryName); LookupName(Found, S); - assert(!Found.isAmbiguous() && "Cannot handle ambiguities here yet"); - if (!Found.isSingleResult()) - return nullptr; - - NamedDecl *Result = Found.getFoundDecl(); - if (isAcceptableNestedNameSpecifier(Result)) - return Result; + if (Found.empty()) + return false; - return nullptr; + R.addAllDecls(Found.asUnresolvedSet().pairs()); + Found.suppressDiagnostics(); + return true; } namespace { @@ -407,112 +419,82 @@ public: bool Sema::BuildCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo, bool EnteringContext, CXXScopeSpec &SS, - NamedDecl *ScopeLookupResult, bool ErrorRecoveryLookup, bool *IsCorrectedToColon, bool OnlyNamespace) { if (IdInfo.Identifier->isEditorPlaceholder()) return true; + if (IsCorrectedToColon) + *IsCorrectedToColon = false; + + QualType ObjectType = GetTypeFromParser(IdInfo.ObjectType); LookupResult Found(*this, IdInfo.Identifier, IdInfo.IdentifierLoc, OnlyNamespace ? LookupNamespaceName : LookupNestedNameSpecifierName); - QualType ObjectType = GetTypeFromParser(IdInfo.ObjectType); - // Determine where to perform name lookup - DeclContext *LookupCtx = nullptr; - bool isDependent = false; - if (IsCorrectedToColon) - *IsCorrectedToColon = false; - if (!ObjectType.isNull()) { - // This nested-name-specifier occurs in a member access expression, e.g., - // x->B::f, and we are looking into the type of the object. - assert(!SS.isSet() && "ObjectType and scope specifier cannot coexist"); - LookupCtx = computeDeclContext(ObjectType); - isDependent = ObjectType->isDependentType(); - } else if (SS.isSet()) { - // This nested-name-specifier occurs after another nested-name-specifier, - // so look into the context associated with the prior nested-name-specifier. - LookupCtx = computeDeclContext(SS, EnteringContext); - isDependent = isDependentScopeSpecifier(SS); - Found.setContextRange(SS.getRange()); + // C++ [basic.lookup.qual.general]p3: + // Qualified name lookup in a class, namespace, or enumeration performs a + // search of the scope associated with it except as specified below. + LookupParsedName(Found, S, &SS, ObjectType, + /*AllowBuiltinCreation=*/false, EnteringContext); + + // C++ [basic.lookup.qual.general]p3: + // [...] Unless otherwise specified, a qualified name undergoes qualified + // name lookup in its lookup context from the point where it appears unless + // the lookup context either is dependent and is not the current + // instantiation or is not a class or class template. + if (Found.wasNotFoundInCurrentInstantiation()) { + // Don't speculate if we're just trying to improve error recovery. + if (ErrorRecoveryLookup) + return true; + + // The lookup context is dependent and either: + // - it is not the current instantiation, or + // - it is the current instantiation, it has at least one dependent base + // class, and qualified lookup found nothing. + // Build a dependent nested-name-specifier. We will lookup the name again + // during instantiation. + SS.Extend(Context, IdInfo.Identifier, IdInfo.IdentifierLoc, IdInfo.CCLoc); + return false; } bool ObjectTypeSearchedInScope = false; - if (LookupCtx) { - // Perform "qualified" name lookup into the declaration context we - // computed, which is either the type of the base of a member access - // expression or the declaration context associated with a prior - // nested-name-specifier. - - // The declaration context must be complete. - if (!LookupCtx->isDependentContext() && - RequireCompleteDeclContext(SS, LookupCtx)) - return true; - LookupQualifiedName(Found, LookupCtx); - - if (!ObjectType.isNull() && Found.empty()) { - // C++ [basic.lookup.classref]p4: - // If the id-expression in a class member access is a qualified-id of - // the form - // - // class-name-or-namespace-name::... - // - // the class-name-or-namespace-name following the . or -> operator is - // looked up both in the context of the entire postfix-expression and in - // the scope of the class of the object expression. If the name is found - // only in the scope of the class of the object expression, the name - // shall refer to a class-name. If the name is found only in the - // context of the entire postfix-expression, the name shall refer to a - // class-name or namespace-name. [...] - // - // Qualified name lookup into a class will not find a namespace-name, - // so we do not need to diagnose that case specifically. However, - // this qualified name lookup may find nothing. In that case, perform - // unqualified name lookup in the given scope (if available) or - // reconstruct the result from when name lookup was performed at template - // definition time. - if (S) - LookupName(Found, S); - else if (ScopeLookupResult) - Found.addDecl(ScopeLookupResult); - - ObjectTypeSearchedInScope = true; + // C++ [basic.lookup.qual.general]p2: + // A member-qualified name is the (unique) component name, if any, of + // - an unqualified-id or + // - a nested-name-specifier of the form type-name :: or namespace-name :: + // in the id-expression of a class member access expression. + // + // C++ [basic.lookup.qual.general]p3: + // [...] If nothing is found by qualified lookup for a member-qualified + // name that is the terminal name of a nested-name-specifier and is not + // dependent, it undergoes unqualified lookup. + // + // In 'x.A::B::y', 'A' will undergo unqualified lookup if qualified lookup + // in the type of 'x' finds nothing. If the lookup context is dependent, + // we perform the unqualified lookup in the template definition context + // and store the results so we can replicate the lookup during instantiation. + if (Found.empty() && !ObjectType.isNull()) { + if (S) { + LookupName(Found, S); + } else if (!SS.getUnqualifiedLookups().empty()) { + Found.addAllDecls(SS.getUnqualifiedLookups()); + Found.resolveKind(); } - } else if (!isDependent) { - // Perform unqualified name lookup in the current scope. - LookupName(Found, S); + ObjectTypeSearchedInScope = true; } if (Found.isAmbiguous()) return true; - // If we performed lookup into a dependent context and did not find anything, - // that's fine: just build a dependent nested-name-specifier. - if (Found.empty() && isDependent && - !(LookupCtx && LookupCtx->isRecord() && - (!cast<CXXRecordDecl>(LookupCtx)->hasDefinition() || - !cast<CXXRecordDecl>(LookupCtx)->hasAnyDependentBases()))) { - // Don't speculate if we're just trying to improve error recovery. - if (ErrorRecoveryLookup) - return true; - - // We were not able to compute the declaration context for a dependent - // base object type or prior nested-name-specifier, so this - // nested-name-specifier refers to an unknown specialization. Just build - // a dependent nested-name-specifier. - SS.Extend(Context, IdInfo.Identifier, IdInfo.IdentifierLoc, IdInfo.CCLoc); - return false; - } - if (Found.empty() && !ErrorRecoveryLookup) { // If identifier is not found as class-name-or-namespace-name, but is found // as other entity, don't look for typos. LookupResult R(*this, Found.getLookupNameInfo(), LookupOrdinaryName); - if (LookupCtx) - LookupQualifiedName(R, LookupCtx); - else if (S && !isDependent) - LookupName(R, S); + LookupParsedName(R, S, &SS, ObjectType, + /*AllowBuiltinCreation=*/false, EnteringContext); + if (!R.empty()) { // Don't diagnose problems with this speculative lookup. R.suppressDiagnostics(); @@ -539,6 +521,11 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo, } } + DeclContext *LookupCtx = + SS.isSet() + ? computeDeclContext(SS, EnteringContext) + : (!ObjectType.isNull() ? computeDeclContext(ObjectType) : nullptr); + if (Found.empty() && !ErrorRecoveryLookup && !getLangOpts().MSVCCompat) { // We haven't found anything, and we're not recovering from a // different kind of error, so look for typos. @@ -594,14 +581,14 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo, // scope, reconstruct the result from the template instantiation itself. // // Note that C++11 does *not* perform this redundant lookup. - NamedDecl *OuterDecl; + NamedDecl *OuterDecl = nullptr; if (S) { LookupResult FoundOuter(*this, IdInfo.Identifier, IdInfo.IdentifierLoc, LookupNestedNameSpecifierName); LookupName(FoundOuter, S); OuterDecl = FoundOuter.getAsSingle<NamedDecl>(); - } else - OuterDecl = ScopeLookupResult; + } else if (!SS.getUnqualifiedLookups().empty()) + OuterDecl = SS.getUnqualifiedLookups().front().getDecl(); if (isAcceptableNestedNameSpecifier(OuterDecl) && OuterDecl->getCanonicalDecl() != SD->getCanonicalDecl() && @@ -779,7 +766,7 @@ bool Sema::ActOnCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo, return true; return BuildCXXNestedNameSpecifier(S, IdInfo, EnteringContext, SS, - /*ScopeLookupResult=*/nullptr, false, + /*ErrorRecoveryLookup=*/false, IsCorrectedToColon, OnlyNamespace); } @@ -840,7 +827,7 @@ bool Sema::IsInvalidUnlessNestedName(Scope *S, CXXScopeSpec &SS, return false; return !BuildCXXNestedNameSpecifier(S, IdInfo, EnteringContext, SS, - /*ScopeLookupResult=*/nullptr, true); + /*ErrorRecoveryLookup=*/true); } bool Sema::ActOnCXXNestedNameSpecifier(Scope *S, diff --git a/clang/lib/Sema/SemaCoroutine.cpp b/clang/lib/Sema/SemaCoroutine.cpp index 81334c8..fa0eb1d 100644 --- a/clang/lib/Sema/SemaCoroutine.cpp +++ b/clang/lib/Sema/SemaCoroutine.cpp @@ -306,8 +306,8 @@ static ExprResult buildMemberCall(Sema &S, Expr *Base, SourceLocation Loc, // FIXME: Fix BuildMemberReferenceExpr to take a const CXXScopeSpec&. CXXScopeSpec SS; ExprResult Result = S.BuildMemberReferenceExpr( - Base, Base->getType(), Loc, /*IsPtr=*/false, SS, - SourceLocation(), nullptr, NameInfo, /*TemplateArgs=*/nullptr, + Base, Base->getType(), Loc, /*IsPtr=*/false, SS, SourceLocation(), + NameInfo, /*TemplateArgs=*/nullptr, /*Scope=*/nullptr); if (Result.isInvalid()) return ExprError(); diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 59487bf..490cd6e 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -1275,9 +1275,11 @@ static bool checkTupleLikeDecomposition(Sema &S, if (UseMemberGet) { // if [lookup of member get] finds at least one declaration, the // initializer is e.get<i-1>(). - E = S.BuildMemberReferenceExpr(E.get(), DecompType, Loc, false, - CXXScopeSpec(), SourceLocation(), nullptr, - MemberGet, &Args, nullptr); + E = S.BuildMemberReferenceExpr(E.get(), DecompType, Loc, + /*IsArrow=*/false, + /*SS=*/CXXScopeSpec(), + /*TemplateKWLoc=*/SourceLocation(), + MemberGet, &Args, /*S=*/nullptr); if (E.isInvalid()) return true; @@ -4901,16 +4903,12 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, MemberLookup.addDecl(Indirect ? cast<ValueDecl>(Indirect) : cast<ValueDecl>(Field), AS_public); MemberLookup.resolveKind(); - ExprResult CtorArg - = SemaRef.BuildMemberReferenceExpr(MemberExprBase, - ParamType, Loc, - /*IsArrow=*/false, - SS, - /*TemplateKWLoc=*/SourceLocation(), - /*FirstQualifierInScope=*/nullptr, - MemberLookup, - /*TemplateArgs=*/nullptr, - /*S*/nullptr); + ExprResult CtorArg = SemaRef.BuildMemberReferenceExpr( + MemberExprBase, ParamType, Loc, + /*IsArrow=*/false, SS, + /*TemplateKWLoc=*/SourceLocation(), MemberLookup, + /*TemplateArgs=*/nullptr, + /*S=*/nullptr); if (CtorArg.isInvalid()) return true; @@ -14336,8 +14334,10 @@ class MemberBuilder: public ExprBuilder { public: Expr *build(Sema &S, SourceLocation Loc) const override { return assertNotNull(S.BuildMemberReferenceExpr( - Builder.build(S, Loc), Type, Loc, IsArrow, SS, SourceLocation(), - nullptr, MemberLookup, nullptr, nullptr).get()); + Builder.build(S, Loc), Type, Loc, IsArrow, SS, + /*TemplateKwLoc=*/SourceLocation(), MemberLookup, + /*TemplateArgs=*/nullptr, /*S=*/nullptr) + .get()); } MemberBuilder(const ExprBuilder &Builder, QualType Type, bool IsArrow, @@ -14543,13 +14543,11 @@ buildSingleCopyAssignRecursively(Sema &S, SourceLocation Loc, QualType T, Loc); // Create the reference to operator=. - ExprResult OpEqualRef - = S.BuildMemberReferenceExpr(To.build(S, Loc), T, Loc, /*IsArrow=*/false, - SS, /*TemplateKWLoc=*/SourceLocation(), - /*FirstQualifierInScope=*/nullptr, - OpLookup, - /*TemplateArgs=*/nullptr, /*S*/nullptr, - /*SuppressQualifierCheck=*/true); + ExprResult OpEqualRef = S.BuildMemberReferenceExpr( + To.build(S, Loc), T, Loc, /*IsArrow=*/false, SS, + /*TemplateKWLoc=*/SourceLocation(), OpLookup, + /*TemplateArgs=*/nullptr, /*S*/ nullptr, + /*SuppressQualifierCheck=*/true); if (OpEqualRef.isInvalid()) return StmtError(); @@ -17155,8 +17153,9 @@ bool Sema::EvaluateStaticAssertMessageAsString(Expr *Message, auto BuildExpr = [&](LookupResult &LR) { ExprResult Res = BuildMemberReferenceExpr( - Message, Message->getType(), Message->getBeginLoc(), false, - CXXScopeSpec(), SourceLocation(), nullptr, LR, nullptr, nullptr); + Message, Message->getType(), Message->getBeginLoc(), /*IsArrow=*/false, + /*SS=*/CXXScopeSpec(), /*TemplateKWLoc=*/SourceLocation(), LR, + /*TemplateArgs=*/nullptr, /*S=*/nullptr); if (Res.isInvalid()) return ExprError(); Res = BuildCallExpr(nullptr, Res.get(), Loc, std::nullopt, Loc, nullptr, diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 45991e6..376eed6 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -2624,7 +2624,7 @@ recoverFromMSUnqualifiedLookup(Sema &S, ASTContext &Context, return CXXDependentScopeMemberExpr::Create( Context, /*This=*/nullptr, ThisType, /*IsArrow=*/true, /*Op=*/SourceLocation(), NestedNameSpecifierLoc(), TemplateKWLoc, - /*FirstQualifierFoundInScope=*/nullptr, NameInfo, TemplateArgs); + /*UnqualifiedLookups=*/std::nullopt, NameInfo, TemplateArgs); } // Synthesize a fake NNS that points to the derived class. This will diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp index 2070f3b..8519618 100644 --- a/clang/lib/Sema/SemaExprMember.cpp +++ b/clang/lib/Sema/SemaExprMember.cpp @@ -552,11 +552,9 @@ static Decl *FindGetterSetterNameDecl(const ObjCObjectPointerType *QIdTy, } ExprResult -Sema::ActOnDependentMemberExpr(Expr *BaseExpr, QualType BaseType, - bool IsArrow, SourceLocation OpLoc, - const CXXScopeSpec &SS, +Sema::ActOnDependentMemberExpr(Expr *BaseExpr, QualType BaseType, bool IsArrow, + SourceLocation OpLoc, const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, - NamedDecl *FirstQualifierInScope, const DeclarationNameInfo &NameInfo, const TemplateArgumentListInfo *TemplateArgs) { // Even in dependent contexts, try to diagnose base expressions with @@ -590,8 +588,8 @@ Sema::ActOnDependentMemberExpr(Expr *BaseExpr, QualType BaseType, // must have pointer type, and the accessed type is the pointee. return CXXDependentScopeMemberExpr::Create( Context, BaseExpr, BaseType, IsArrow, OpLoc, - SS.getWithLocInContext(Context), TemplateKWLoc, FirstQualifierInScope, - NameInfo, TemplateArgs); + SS.getWithLocInContext(Context), TemplateKWLoc, + SS.getUnqualifiedLookups(), NameInfo, TemplateArgs); } /// We know that the given qualified member reference points only to @@ -767,8 +765,9 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, R.addDecl(ND); R.resolveKind(); return SemaRef.BuildMemberReferenceExpr( - BaseExpr, BaseExpr->getType(), OpLoc, IsArrow, SS, SourceLocation(), - nullptr, R, nullptr, nullptr); + BaseExpr, BaseExpr->getType(), OpLoc, IsArrow, SS, + /*TemplateKWLoc=*/SourceLocation(), R, /*TemplateArgs=*/nullptr, + /*S=*/nullptr); }, Sema::CTK_ErrorRecovery, DC); @@ -784,7 +783,7 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R, ExprResult Sema::BuildMemberReferenceExpr( Expr *Base, QualType BaseType, SourceLocation OpLoc, bool IsArrow, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, - NamedDecl *FirstQualifierInScope, const DeclarationNameInfo &NameInfo, + const DeclarationNameInfo &NameInfo, const TemplateArgumentListInfo *TemplateArgs, const Scope *S, ActOnMemberAccessExtraArgs *ExtraArgs) { LookupResult R(*this, NameInfo, LookupMemberName); @@ -828,10 +827,9 @@ ExprResult Sema::BuildMemberReferenceExpr( if (SS.isInvalid()) return ExprError(); - return BuildMemberReferenceExpr(Base, BaseType, - OpLoc, IsArrow, SS, TemplateKWLoc, - FirstQualifierInScope, R, TemplateArgs, S, - false, ExtraArgs); + return BuildMemberReferenceExpr(Base, BaseType, OpLoc, IsArrow, SS, + TemplateKWLoc, R, TemplateArgs, S, + /*SuppressQualifierCheck=*/false, ExtraArgs); } ExprResult @@ -969,17 +967,11 @@ static bool IsInFnTryBlockHandler(const Scope *S) { return false; } -ExprResult -Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, - SourceLocation OpLoc, bool IsArrow, - const CXXScopeSpec &SS, - SourceLocation TemplateKWLoc, - NamedDecl *FirstQualifierInScope, - LookupResult &R, - const TemplateArgumentListInfo *TemplateArgs, - const Scope *S, - bool SuppressQualifierCheck, - ActOnMemberAccessExtraArgs *ExtraArgs) { +ExprResult Sema::BuildMemberReferenceExpr( + Expr *BaseExpr, QualType BaseExprType, SourceLocation OpLoc, bool IsArrow, + const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, LookupResult &R, + const TemplateArgumentListInfo *TemplateArgs, const Scope *S, + bool SuppressQualifierCheck, ActOnMemberAccessExtraArgs *ExtraArgs) { assert(!SS.isInvalid() && "nested-name-specifier cannot be invalid"); // If the member wasn't found in the current instantiation, or if the // arrow operator was used with a dependent non-pointer object expression, @@ -989,8 +981,8 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, (SS.isSet() ? SS.getScopeRep()->isDependent() : BaseExprType->isDependentType()))) return ActOnDependentMemberExpr(BaseExpr, BaseExprType, IsArrow, OpLoc, SS, - TemplateKWLoc, FirstQualifierInScope, - R.getLookupNameInfo(), TemplateArgs); + TemplateKWLoc, R.getLookupNameInfo(), + TemplateArgs); QualType BaseType = BaseExprType; if (IsArrow) { @@ -1195,9 +1187,9 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, // Non-dependent member, but dependent template arguments. if (!VDecl.get()) - return ActOnDependentMemberExpr( - BaseExpr, BaseExpr->getType(), IsArrow, OpLoc, SS, TemplateKWLoc, - FirstQualifierInScope, MemberNameInfo, TemplateArgs); + return ActOnDependentMemberExpr(BaseExpr, BaseExpr->getType(), IsArrow, + OpLoc, SS, TemplateKWLoc, MemberNameInfo, + TemplateArgs); VarDecl *Var = cast<VarDecl>(VDecl.get()); if (!Var->getTemplateSpecializationKind()) @@ -1763,15 +1755,16 @@ ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base, const TemplateArgumentListInfo *TemplateArgs; DecomposeUnqualifiedId(Id, TemplateArgsBuffer, NameInfo, TemplateArgs); - - bool IsArrow = (OpKind == tok::arrow); + bool IsArrow = OpKind == tok::arrow; if (getLangOpts().HLSL && IsArrow) return ExprError(Diag(OpLoc, diag::err_hlsl_operator_unsupported) << 2); - NamedDecl *FirstQualifierInScope - = (!SS.isSet() ? nullptr : FindFirstQualifierInScope(S, SS.getScopeRep())); - + UnresolvedSet<4> UnqualifiedLookups; + if (SS.isValid() && + LookupFirstQualifierInScope(S, SS.getScopeRep(), UnqualifiedLookups)) { + SS.setUnqualifiedLookups(UnqualifiedLookups.pairs()); + } // This is a postfix expression, so get rid of ParenListExprs. ExprResult Result = MaybeConvertParenListExprToParenExpr(S, Base); if (Result.isInvalid()) return ExprError(); @@ -1779,8 +1772,8 @@ ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base, ActOnMemberAccessExtraArgs ExtraArgs = {S, Id, ObjCImpDecl}; ExprResult Res = BuildMemberReferenceExpr( - Base, Base->getType(), OpLoc, IsArrow, SS, TemplateKWLoc, - FirstQualifierInScope, NameInfo, TemplateArgs, S, &ExtraArgs); + Base, Base->getType(), OpLoc, IsArrow, SS, TemplateKWLoc, NameInfo, + TemplateArgs, S, &ExtraArgs); if (!Res.isInvalid() && isa<MemberExpr>(Res.get())) CheckMemberAccessOfNoDeref(cast<MemberExpr>(Res.get())); @@ -1924,9 +1917,8 @@ Sema::BuildImplicitMemberExpr(const CXXScopeSpec &SS, baseExpr = BuildCXXThisExpr(loc, ThisTy, /*IsImplicit=*/true); } - return BuildMemberReferenceExpr( - baseExpr, ThisTy, - /*OpLoc=*/SourceLocation(), - /*IsArrow=*/!getLangOpts().HLSL, SS, TemplateKWLoc, - /*FirstQualifierInScope=*/nullptr, R, TemplateArgs, S); + return BuildMemberReferenceExpr(baseExpr, ThisTy, + /*OpLoc=*/SourceLocation(), + /*IsArrow=*/!getLangOpts().HLSL, SS, + TemplateKWLoc, R, TemplateArgs, S); } diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 5ea6b06..f49635a 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -16043,13 +16043,11 @@ Sema::BuildForRangeBeginEndCall(SourceLocation Loc, CandidateSet->clear(OverloadCandidateSet::CSK_Normal); if (!MemberLookup.empty()) { - ExprResult MemberRef = - BuildMemberReferenceExpr(Range, Range->getType(), Loc, - /*IsPtr=*/false, CXXScopeSpec(), - /*TemplateKWLoc=*/SourceLocation(), - /*FirstQualifierInScope=*/nullptr, - MemberLookup, - /*TemplateArgs=*/nullptr, S); + ExprResult MemberRef = BuildMemberReferenceExpr( + Range, Range->getType(), Loc, + /*IsPtr=*/false, /*SS=*/CXXScopeSpec(), + /*TemplateKWLoc=*/SourceLocation(), MemberLookup, + /*TemplateArgs=*/nullptr, S); if (MemberRef.isInvalid()) { *CallExpr = ExprError(); return FRS_DiagnosticIssued; diff --git a/clang/lib/Sema/SemaStmtAsm.cpp b/clang/lib/Sema/SemaStmtAsm.cpp index 32d42f3..da2e99b 100644 --- a/clang/lib/Sema/SemaStmtAsm.cpp +++ b/clang/lib/Sema/SemaStmtAsm.cpp @@ -900,7 +900,8 @@ Sema::LookupInlineAsmVarDeclField(Expr *E, StringRef Member, return CXXDependentScopeMemberExpr::Create( Context, E, T, /*IsArrow=*/false, AsmLoc, NestedNameSpecifierLoc(), SourceLocation(), - /*FirstQualifierFoundInScope=*/nullptr, NameInfo, /*TemplateArgs=*/nullptr); + /*UnqualifiedLookups=*/std::nullopt, NameInfo, + /*TemplateArgs=*/nullptr); } const RecordType *RT = T->getAs<RecordType>(); @@ -923,8 +924,9 @@ Sema::LookupInlineAsmVarDeclField(Expr *E, StringRef Member, // Make an Expr to thread through OpDecl. ExprResult Result = BuildMemberReferenceExpr( - E, E->getType(), AsmLoc, /*IsArrow=*/false, CXXScopeSpec(), - SourceLocation(), nullptr, FieldResult, nullptr, nullptr); + E, E->getType(), AsmLoc, /*IsArrow=*/false, /*SS=*/CXXScopeSpec(), + /*TemplateKWLoc*/ SourceLocation(), FieldResult, + /*TemplateArgs=*/nullptr, /*S=*/nullptr); return Result; } diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 07b3f79..f84e7e0 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -173,15 +173,12 @@ bool Sema::hasAnyAcceptableTemplateNames(LookupResult &R, return false; } -TemplateNameKind Sema::isTemplateName(Scope *S, - CXXScopeSpec &SS, - bool hasTemplateKeyword, - const UnqualifiedId &Name, - ParsedType ObjectTypePtr, - bool EnteringContext, - TemplateTy &TemplateResult, - bool &MemberOfUnknownSpecialization, - bool Disambiguation) { +TemplateNameKind +Sema::isTemplateName(Scope *S, CXXScopeSpec &SS, bool hasTemplateKeyword, + const UnqualifiedId &Name, ParsedType ObjectTypePtr, + bool EnteringContext, TemplateTy &TemplateResult, + bool &MemberOfUnknownSpecialization, bool Disambiguation, + bool MayBeNNS) { assert(getLangOpts().CPlusPlus && "No template names in C!"); DeclarationName TName; @@ -212,8 +209,9 @@ TemplateNameKind Sema::isTemplateName(Scope *S, if (LookupTemplateName(R, S, SS, ObjectType, EnteringContext, /*RequiredTemplate=*/SourceLocation(), &AssumedTemplate, - /*AllowTypoCorrection=*/!Disambiguation)) + /*AllowTypoCorrection=*/!Disambiguation, MayBeNNS)) return TNK_Non_template; + MemberOfUnknownSpecialization = R.wasNotFoundInCurrentInstantiation(); if (AssumedTemplate != AssumedTemplateKind::None) { @@ -379,7 +377,7 @@ bool Sema::LookupTemplateName(LookupResult &Found, Scope *S, CXXScopeSpec &SS, QualType ObjectType, bool EnteringContext, RequiredTemplateKind RequiredTemplate, AssumedTemplateKind *ATK, - bool AllowTypoCorrection) { + bool AllowTypoCorrection, bool MayBeNNS) { if (ATK) *ATK = AssumedTemplateKind::None; @@ -388,92 +386,89 @@ bool Sema::LookupTemplateName(LookupResult &Found, Scope *S, CXXScopeSpec &SS, Found.setTemplateNameLookup(true); - // Determine where to perform name lookup - DeclContext *LookupCtx = nullptr; - bool IsDependent = false; - if (!ObjectType.isNull()) { - // This nested-name-specifier occurs in a member access expression, e.g., - // x->B::f, and we are looking into the type of the object. - assert(SS.isEmpty() && "ObjectType and scope specifier cannot coexist"); - LookupCtx = computeDeclContext(ObjectType); - IsDependent = !LookupCtx && ObjectType->isDependentType(); - assert((IsDependent || !ObjectType->isIncompleteType() || - !ObjectType->getAs<TagType>() || - ObjectType->castAs<TagType>()->isBeingDefined()) && - "Caller should have completed object type"); - - // Template names cannot appear inside an Objective-C class or object type - // or a vector type. - // - // FIXME: This is wrong. For example: - // - // template<typename T> using Vec = T __attribute__((ext_vector_type(4))); - // Vec<int> vi; - // vi.Vec<int>::~Vec<int>(); - // - // ... should be accepted but we will not treat 'Vec' as a template name - // here. The right thing to do would be to check if the name is a valid - // vector component name, and look up a template name if not. And similarly - // for lookups into Objective-C class and object types, where the same - // problem can arise. - if (ObjectType->isObjCObjectOrInterfaceType() || - ObjectType->isVectorType()) { - Found.clear(); - return false; - } - } else if (SS.isNotEmpty()) { - // This nested-name-specifier occurs after another nested-name-specifier, - // so long into the context associated with the prior nested-name-specifier. - LookupCtx = computeDeclContext(SS, EnteringContext); - IsDependent = !LookupCtx && isDependentScopeSpecifier(SS); - - // The declaration context must be complete. - if (LookupCtx && RequireCompleteDeclContext(SS, LookupCtx)) - return true; + // Template names cannot appear inside an Objective-C class or object type + // or a vector type. + // + // FIXME: This is wrong. For example: + // + // template<typename T> using Vec = T __attribute__((ext_vector_type(4))); + // Vec<int> vi; + // vi.Vec<int>::~Vec<int>(); + // + // ... should be accepted but we will not treat 'Vec' as a template name + // here. The right thing to do would be to check if the name is a valid + // vector component name, and look up a template name if not. And similarly + // for lookups into Objective-C class and object types, where the same + // problem can arise. + if (!ObjectType.isNull() && (ObjectType->isVectorType() || + ObjectType->isObjCObjectOrInterfaceType())) { + Found.clear(); + return false; } + LookupParsedName(Found, S, &SS, ObjectType, + /*AllowBuiltinCreation=*/false, EnteringContext); + + // C++ [basic.lookup.qual.general]p3: + // [...] Unless otherwise specified, a qualified name undergoes qualified + // name lookup in its lookup context from the point where it appears unless + // the lookup context either is dependent and is not the current + // instantiation or is not a class or class template. + // + // The lookup context is dependent and either: + // - it is not the current instantiation, or + // - it is the current instantiation, it has at least one dependent base + // class, and qualified lookup found nothing. + // + // If this is a member-qualified name that is the terminal name of a + // nested-name-specifier, we perform unqualified lookup and store the results + // so we can replicate the lookup during instantiation. The results of the + // unqualified loookup are *not* used to determine whether '<' is interpreted + // as the delimiter of a template-argument-list. + // + // For example: + // + // template<typename T> + // struct A { + // int x; + // }; + // + // template<typename T> + // using B = A<T>; + // + // template<typename T> + // void f(A<T> a, A<int> b) { + // a.B<T>::x; // error: missing 'template' before 'B' + // b.B<int>::x; // ok, lookup context is not dependent + // } + if (Found.wasNotFoundInCurrentInstantiation()) + return false; + bool ObjectTypeSearchedInScope = false; - bool AllowFunctionTemplatesInLookup = true; - if (LookupCtx) { - // Perform "qualified" name lookup into the declaration context we - // computed, which is either the type of the base of a member access - // expression or the declaration context associated with a prior - // nested-name-specifier. - LookupQualifiedName(Found, LookupCtx); - - // FIXME: The C++ standard does not clearly specify what happens in the - // case where the object type is dependent, and implementations vary. In - // Clang, we treat a name after a . or -> as a template-name if lookup - // finds a non-dependent member or member of the current instantiation that - // is a type template, or finds no such members and lookup in the context - // of the postfix-expression finds a type template. In the latter case, the - // name is nonetheless dependent, and we may resolve it to a member of an - // unknown specialization when we come to instantiate the template. - IsDependent |= Found.wasNotFoundInCurrentInstantiation(); - } - - if (SS.isEmpty() && (ObjectType.isNull() || Found.empty())) { - // C++ [basic.lookup.classref]p1: - // In a class member access expression (5.2.5), if the . or -> token is - // immediately followed by an identifier followed by a <, the - // identifier must be looked up to determine whether the < is the - // beginning of a template argument list (14.2) or a less-than operator. - // The identifier is first looked up in the class of the object - // expression. If the identifier is not found, it is then looked up in - // the context of the entire postfix-expression and shall name a class - // template. - if (S) - LookupName(Found, S); - if (!ObjectType.isNull()) { - // FIXME: We should filter out all non-type templates here, particularly - // variable templates and concepts. But the exclusion of alias templates - // and template template parameters is a wording defect. - AllowFunctionTemplatesInLookup = false; - ObjectTypeSearchedInScope = true; + // C++ [basic.lookup.qual.general]p2: + // A member-qualified name is the (unique) component name, if any, of + // - an unqualified-id or + // - a nested-name-specifier of the form type-name :: or namespace-name :: + // in the id-expression of a class member access expression. + // + // C++ [basic.lookup.qual.general]p3: + // [...] If nothing is found by qualified lookup for a member-qualified + // name that is the terminal name of a nested-name-specifier and is not + // dependent, it undergoes unqualified lookup. + // + // In 'x.A::B::y', 'A' will undergo unqualified lookup if qualified lookup + // in the type of 'x' finds nothing. If the lookup context is dependent, + // we perform the unqualified lookup in the template definition context + // and store the results so we can replicate the lookup during instantiation. + if (MayBeNNS && Found.empty() && !ObjectType.isNull()) { + if (S) { + LookupName(Found, S); + } else if (!SS.getUnqualifiedLookups().empty()) { + Found.addAllDecls(SS.getUnqualifiedLookups()); + Found.resolveKind(); } - - IsDependent |= Found.wasNotFoundInCurrentInstantiation(); + ObjectTypeSearchedInScope = true; } if (Found.isAmbiguous()) @@ -493,7 +488,7 @@ bool Sema::LookupTemplateName(LookupResult &Found, Scope *S, CXXScopeSpec &SS, getLangOpts().CPlusPlus20 && llvm::all_of(Found, [](NamedDecl *ND) { return isa<FunctionDecl>(ND->getUnderlyingDecl()); }); - if (AllFunctions || (Found.empty() && !IsDependent)) { + if (AllFunctions || Found.empty()) { // If lookup found any functions, or if this is a name that can only be // used for a function, then strongly assume this is a function // template-id. @@ -505,11 +500,15 @@ bool Sema::LookupTemplateName(LookupResult &Found, Scope *S, CXXScopeSpec &SS, } } - if (Found.empty() && !IsDependent && AllowTypoCorrection) { + if (Found.empty() && AllowTypoCorrection) { // If we did not find any names, and this is not a disambiguation, attempt // to correct any typos. DeclarationName Name = Found.getLookupName(); Found.clear(); + DeclContext *LookupCtx = + SS.isSet() + ? computeDeclContext(SS, EnteringContext) + : (!ObjectType.isNull() ? computeDeclContext(ObjectType) : nullptr); // Simple filter callback that, for keywords, only accepts the C++ *_cast DefaultFilterCCC FilterCCC{}; FilterCCC.WantTypeSpecifiers = false; @@ -542,13 +541,8 @@ bool Sema::LookupTemplateName(LookupResult &Found, Scope *S, CXXScopeSpec &SS, NamedDecl *ExampleLookupResult = Found.empty() ? nullptr : Found.getRepresentativeDecl(); - FilterAcceptableTemplateNames(Found, AllowFunctionTemplatesInLookup); + FilterAcceptableTemplateNames(Found); if (Found.empty()) { - if (IsDependent) { - Found.setNotFoundInCurrentInstantiation(); - return false; - } - // If a 'template' keyword was used, a lookup that finds only non-template // names is an error. if (ExampleLookupResult && RequiredTemplate) { @@ -740,7 +734,7 @@ Sema::ActOnDependentIdExpression(const CXXScopeSpec &SS, /*IsArrow=*/!Context.getLangOpts().HLSL, /*OperatorLoc=*/SourceLocation(), /*QualifierLoc=*/NestedNameSpecifierLoc(), TemplateKWLoc, - /*FirstQualifierFoundInScope=*/nullptr, NameInfo, TemplateArgs); + /*UnqualifiedLookups=*/std::nullopt, NameInfo, TemplateArgs); } return BuildDependentDeclRefExpr(SS, TemplateKWLoc, NameInfo, TemplateArgs); } @@ -5693,14 +5687,10 @@ ExprResult Sema::BuildQualifiedTemplateIdExpr( return BuildTemplateIdExpr(SS, TemplateKWLoc, R, /*ADL=*/false, TemplateArgs); } -TemplateNameKind Sema::ActOnTemplateName(Scope *S, - CXXScopeSpec &SS, - SourceLocation TemplateKWLoc, - const UnqualifiedId &Name, - ParsedType ObjectType, - bool EnteringContext, - TemplateTy &Result, - bool AllowInjectedClassName) { +TemplateNameKind Sema::ActOnTemplateName( + Scope *S, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, + const UnqualifiedId &Name, ParsedType ObjectType, bool EnteringContext, + TemplateTy &Result, bool AllowInjectedClassName, bool MayBeNNS) { if (TemplateKWLoc.isValid() && S && !S->getTemplateParamParent()) Diag(TemplateKWLoc, getLangOpts().CPlusPlus11 ? @@ -5735,9 +5725,10 @@ TemplateNameKind Sema::ActOnTemplateName(Scope *S, // "template" keyword is now permitted). We follow the C++0x // rules, even in C++03 mode with a warning, retroactively applying the DR. bool MemberOfUnknownSpecialization; - TemplateNameKind TNK = isTemplateName(S, SS, TemplateKWLoc.isValid(), Name, - ObjectType, EnteringContext, Result, - MemberOfUnknownSpecialization); + TemplateNameKind TNK = + isTemplateName(S, SS, TemplateKWLoc.isValid(), Name, ObjectType, + EnteringContext, Result, MemberOfUnknownSpecialization, + /*Disambiguation=*/false, MayBeNNS); if (TNK != TNK_Non_template) { // We resolved this to a (non-dependent) template name. Return it. auto *LookupRD = dyn_cast_or_null<CXXRecordDecl>(LookupCtx); @@ -5776,7 +5767,8 @@ TemplateNameKind Sema::ActOnTemplateName(Scope *S, ? RequiredTemplateKind(TemplateKWLoc) : TemplateNameIsRequired; if (!LookupTemplateName(R, S, SS, ObjectType.get(), EnteringContext, RTK, - /*ATK=*/nullptr, /*AllowTypoCorrection=*/false) && + /*ATK=*/nullptr, /*AllowTypoCorrection=*/false, + MayBeNNS) && !R.isAmbiguous()) { if (LookupCtx) Diag(Name.getBeginLoc(), diag::err_no_member) diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index a7bc674..64c5a16 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -1515,12 +1515,11 @@ namespace { NestedNameSpecifierLoc QualifierLoc, QualType T); - TemplateName - TransformTemplateName(CXXScopeSpec &SS, TemplateName Name, - SourceLocation NameLoc, - QualType ObjectType = QualType(), - NamedDecl *FirstQualifierInScope = nullptr, - bool AllowInjectedClassName = false); + TemplateName TransformTemplateName(CXXScopeSpec &SS, TemplateName Name, + SourceLocation NameLoc, + QualType ObjectType = QualType(), + bool AllowInjectedClassName = false, + bool MayBeNNS = false); const CXXAssumeAttr *TransformCXXAssumeAttr(const CXXAssumeAttr *AA); const LoopHintAttr *TransformLoopHintAttr(const LoopHintAttr *LH); @@ -1952,8 +1951,7 @@ TemplateInstantiator::RebuildElaboratedType(SourceLocation KeywordLoc, TemplateName TemplateInstantiator::TransformTemplateName( CXXScopeSpec &SS, TemplateName Name, SourceLocation NameLoc, - QualType ObjectType, NamedDecl *FirstQualifierInScope, - bool AllowInjectedClassName) { + QualType ObjectType, bool AllowInjectedClassName, bool MayBeNNS) { if (TemplateTemplateParmDecl *TTP = dyn_cast_or_null<TemplateTemplateParmDecl>(Name.getAsTemplateDecl())) { if (TTP->getDepth() < TemplateArgs.getNumLevels()) { @@ -2025,8 +2023,7 @@ TemplateName TemplateInstantiator::TransformTemplateName( } return inherited::TransformTemplateName(SS, Name, NameLoc, ObjectType, - FirstQualifierInScope, - AllowInjectedClassName); + AllowInjectedClassName, MayBeNNS); } ExprResult diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 655f248..f602144 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -541,10 +541,9 @@ public: /// By default, transforms all of the types and declarations within the /// nested-name-specifier. Subclasses may override this function to provide /// alternate behavior. - NestedNameSpecifierLoc - TransformNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS, - QualType ObjectType = QualType(), - NamedDecl *FirstQualifierInScope = nullptr); + NestedNameSpecifierLoc TransformNestedNameSpecifierLoc( + NestedNameSpecifierLoc NNS, QualType ObjectType = QualType(), + ArrayRef<DeclAccessPair> UnqualifiedLookups = std::nullopt); /// Transform the given declaration name. /// @@ -585,12 +584,11 @@ public: /// By default, transforms the template name by transforming the declarations /// and nested-name-specifiers that occur within the template name. /// Subclasses may override this function to provide alternate behavior. - TemplateName - TransformTemplateName(CXXScopeSpec &SS, TemplateName Name, - SourceLocation NameLoc, - QualType ObjectType = QualType(), - NamedDecl *FirstQualifierInScope = nullptr, - bool AllowInjectedClassName = false); + TemplateName TransformTemplateName(CXXScopeSpec &SS, TemplateName Name, + SourceLocation NameLoc, + QualType ObjectType = QualType(), + bool AllowInjectedClassName = false, + bool MayBeNNS = false); /// Transform the given template argument. /// @@ -1140,8 +1138,8 @@ public: CXXScopeSpec SS; SS.Adopt(QualifierLoc); TemplateName InstName = getDerived().RebuildTemplateName( - SS, TemplateKWLoc, *Name, NameLoc, QualType(), nullptr, - AllowInjectedClassName); + SS, TemplateKWLoc, *Name, NameLoc, QualType(), AllowInjectedClassName, + /*MayBeNNS=*/false); if (InstName.isNull()) return QualType(); @@ -1312,8 +1310,7 @@ public: SourceLocation TemplateKWLoc, const IdentifierInfo &Name, SourceLocation NameLoc, QualType ObjectType, - NamedDecl *FirstQualifierInScope, - bool AllowInjectedClassName); + bool AllowInjectedClassName, bool MayBeNNS); /// Build a new template name given a nested name specifier and the /// overloaded operator name that is referred to as a template. @@ -2849,15 +2846,14 @@ public: /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. - ExprResult RebuildMemberExpr(Expr *Base, SourceLocation OpLoc, - bool isArrow, - NestedNameSpecifierLoc QualifierLoc, - SourceLocation TemplateKWLoc, - const DeclarationNameInfo &MemberNameInfo, - ValueDecl *Member, - NamedDecl *FoundDecl, - const TemplateArgumentListInfo *ExplicitTemplateArgs, - NamedDecl *FirstQualifierInScope) { + ExprResult + RebuildMemberExpr(Expr *Base, SourceLocation OpLoc, bool isArrow, + NestedNameSpecifierLoc QualifierLoc, + SourceLocation TemplateKWLoc, + const DeclarationNameInfo &MemberNameInfo, + ValueDecl *Member, NamedDecl *FoundDecl, + const TemplateArgumentListInfo *ExplicitTemplateArgs, + ArrayRef<DeclAccessPair> UnqualifiedLookups) { ExprResult BaseResult = getSema().PerformMemberExprBaseConversion(Base, isArrow); if (!Member->getDeclName()) { @@ -2894,6 +2890,7 @@ public: CXXScopeSpec SS; SS.Adopt(QualifierLoc); + SS.setUnqualifiedLookups(UnqualifiedLookups); Base = BaseResult.get(); if (Base->containsErrors()) @@ -2926,10 +2923,9 @@ public: } return getSema().BuildMemberReferenceExpr(Base, BaseType, OpLoc, isArrow, - SS, TemplateKWLoc, - FirstQualifierInScope, - R, ExplicitTemplateArgs, - /*S*/nullptr); + SS, TemplateKWLoc, R, + ExplicitTemplateArgs, + /*S=*/nullptr); } /// Build a new binary operator expression. @@ -3002,10 +2998,9 @@ public: CXXScopeSpec SS; DeclarationNameInfo NameInfo(&Accessor, AccessorLoc); return getSema().BuildMemberReferenceExpr( - Base, Base->getType(), OpLoc, IsArrow, SS, SourceLocation(), - /*FirstQualifierInScope*/ nullptr, NameInfo, - /* TemplateArgs */ nullptr, - /*S*/ nullptr); + Base, Base->getType(), OpLoc, IsArrow, SS, + /*TemplateKWLoc=*/SourceLocation(), NameInfo, + /*TemplateArgs=*/nullptr, /*S=*/nullptr); } /// Build a new initializer list expression. @@ -3573,46 +3568,37 @@ public: /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. - ExprResult RebuildCXXDependentScopeMemberExpr(Expr *BaseE, - QualType BaseType, - bool IsArrow, - SourceLocation OperatorLoc, - NestedNameSpecifierLoc QualifierLoc, - SourceLocation TemplateKWLoc, - NamedDecl *FirstQualifierInScope, - const DeclarationNameInfo &MemberNameInfo, - const TemplateArgumentListInfo *TemplateArgs) { + ExprResult RebuildCXXDependentScopeMemberExpr( + Expr *BaseE, QualType BaseType, bool IsArrow, SourceLocation OperatorLoc, + NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, + ArrayRef<DeclAccessPair> UnqualifiedLookups, + const DeclarationNameInfo &MemberNameInfo, + const TemplateArgumentListInfo *TemplateArgs) { CXXScopeSpec SS; SS.Adopt(QualifierLoc); + SS.setUnqualifiedLookups(UnqualifiedLookups); - return SemaRef.BuildMemberReferenceExpr(BaseE, BaseType, - OperatorLoc, IsArrow, - SS, TemplateKWLoc, - FirstQualifierInScope, - MemberNameInfo, - TemplateArgs, /*S*/nullptr); + return SemaRef.BuildMemberReferenceExpr( + BaseE, BaseType, OperatorLoc, IsArrow, SS, TemplateKWLoc, + MemberNameInfo, TemplateArgs, /*S=*/nullptr); } /// Build a new member reference expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. - ExprResult RebuildUnresolvedMemberExpr(Expr *BaseE, QualType BaseType, - SourceLocation OperatorLoc, - bool IsArrow, - NestedNameSpecifierLoc QualifierLoc, - SourceLocation TemplateKWLoc, - NamedDecl *FirstQualifierInScope, - LookupResult &R, - const TemplateArgumentListInfo *TemplateArgs) { + ExprResult RebuildUnresolvedMemberExpr( + Expr *BaseE, QualType BaseType, SourceLocation OperatorLoc, bool IsArrow, + NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, + ArrayRef<DeclAccessPair> UnqualifiedLookups, LookupResult &R, + const TemplateArgumentListInfo *TemplateArgs) { CXXScopeSpec SS; SS.Adopt(QualifierLoc); + SS.setUnqualifiedLookups(UnqualifiedLookups); - return SemaRef.BuildMemberReferenceExpr(BaseE, BaseType, - OperatorLoc, IsArrow, - SS, TemplateKWLoc, - FirstQualifierInScope, - R, TemplateArgs, /*S*/nullptr); + return SemaRef.BuildMemberReferenceExpr(BaseE, BaseType, OperatorLoc, + IsArrow, SS, TemplateKWLoc, R, + TemplateArgs, /*S=*/nullptr); } /// Build a new noexcept expression. @@ -3831,10 +3817,8 @@ public: DeclarationNameInfo NameInfo(Ivar->getDeclName(), IvarLoc); ExprResult Result = getSema().BuildMemberReferenceExpr( BaseArg, BaseArg->getType(), - /*FIXME:*/ IvarLoc, IsArrow, SS, SourceLocation(), - /*FirstQualifierInScope=*/nullptr, NameInfo, - /*TemplateArgs=*/nullptr, - /*S=*/nullptr); + /*FIXME:*/ IvarLoc, IsArrow, SS, /*TemplateKWLoc=*/SourceLocation(), + NameInfo, /*TemplateArgs=*/nullptr, /*S=*/nullptr); if (IsFreeIvar && Result.isUsable()) cast<ObjCIvarRefExpr>(Result.get())->setIsFreeIvar(IsFreeIvar); return Result; @@ -3849,14 +3833,12 @@ public: SourceLocation PropertyLoc) { CXXScopeSpec SS; DeclarationNameInfo NameInfo(Property->getDeclName(), PropertyLoc); - return getSema().BuildMemberReferenceExpr(BaseArg, BaseArg->getType(), - /*FIXME:*/PropertyLoc, - /*IsArrow=*/false, - SS, SourceLocation(), - /*FirstQualifierInScope=*/nullptr, - NameInfo, - /*TemplateArgs=*/nullptr, - /*S=*/nullptr); + return getSema().BuildMemberReferenceExpr( + BaseArg, BaseArg->getType(), + /*FIXME:*/ PropertyLoc, + /*IsArrow=*/false, SS, /*TemplateKWLoc=*/SourceLocation(), NameInfo, + /*TemplateArgs=*/nullptr, + /*S=*/nullptr); } /// Build a new Objective-C property reference expression. @@ -3883,13 +3865,11 @@ public: SourceLocation OpLoc, bool IsArrow) { CXXScopeSpec SS; DeclarationNameInfo NameInfo(&getSema().Context.Idents.get("isa"), IsaLoc); - return getSema().BuildMemberReferenceExpr(BaseArg, BaseArg->getType(), - OpLoc, IsArrow, - SS, SourceLocation(), - /*FirstQualifierInScope=*/nullptr, - NameInfo, - /*TemplateArgs=*/nullptr, - /*S=*/nullptr); + return getSema().BuildMemberReferenceExpr( + BaseArg, BaseArg->getType(), OpLoc, IsArrow, SS, + /*TemplateKWLoc=*/SourceLocation(), NameInfo, + /*TemplateArgs=*/nullptr, + /*S=*/nullptr); } /// Build a new shuffle vector expression. @@ -4054,18 +4034,14 @@ public: } private: - TypeLoc TransformTypeInObjectScope(TypeLoc TL, - QualType ObjectType, - NamedDecl *FirstQualifierInScope, + TypeLoc TransformTypeInObjectScope(TypeLoc TL, QualType ObjectType, CXXScopeSpec &SS); TypeSourceInfo *TransformTypeInObjectScope(TypeSourceInfo *TSInfo, QualType ObjectType, - NamedDecl *FirstQualifierInScope, CXXScopeSpec &SS); TypeSourceInfo *TransformTSIInObjectScope(TypeLoc TL, QualType ObjectType, - NamedDecl *FirstQualifierInScope, CXXScopeSpec &SS); QualType TransformDependentNameType(TypeLocBuilder &TLB, @@ -4384,7 +4360,7 @@ Sema::ConditionResult TreeTransform<Derived>::TransformCondition( template <typename Derived> NestedNameSpecifierLoc TreeTransform<Derived>::TransformNestedNameSpecifierLoc( NestedNameSpecifierLoc NNS, QualType ObjectType, - NamedDecl *FirstQualifierInScope) { + ArrayRef<DeclAccessPair> UnqualifiedLookups) { SmallVector<NestedNameSpecifierLoc, 4> Qualifiers; auto insertNNS = [&Qualifiers](NestedNameSpecifierLoc NNS) { @@ -4395,6 +4371,8 @@ NestedNameSpecifierLoc TreeTransform<Derived>::TransformNestedNameSpecifierLoc( insertNNS(NNS); CXXScopeSpec SS; + SS.setUnqualifiedLookups(UnqualifiedLookups); + while (!Qualifiers.empty()) { NestedNameSpecifierLoc Q = Qualifiers.pop_back_val(); NestedNameSpecifier *QNNS = Q.getNestedNameSpecifier(); @@ -4404,8 +4382,9 @@ NestedNameSpecifierLoc TreeTransform<Derived>::TransformNestedNameSpecifierLoc( Sema::NestedNameSpecInfo IdInfo(QNNS->getAsIdentifier(), Q.getLocalBeginLoc(), Q.getLocalEndLoc(), ObjectType); - if (SemaRef.BuildCXXNestedNameSpecifier(/*Scope=*/nullptr, IdInfo, false, - SS, FirstQualifierInScope, false)) + if (SemaRef.BuildCXXNestedNameSpecifier(/*Scope=*/nullptr, IdInfo, + /*EnteringContext=*/false, SS, + /*ErrorRecoveryLookup=*/false)) return NestedNameSpecifierLoc(); break; } @@ -4443,8 +4422,7 @@ NestedNameSpecifierLoc TreeTransform<Derived>::TransformNestedNameSpecifierLoc( case NestedNameSpecifier::TypeSpecWithTemplate: case NestedNameSpecifier::TypeSpec: { - TypeLoc TL = TransformTypeInObjectScope(Q.getTypeLoc(), ObjectType, - FirstQualifierInScope, SS); + TypeLoc TL = TransformTypeInObjectScope(Q.getTypeLoc(), ObjectType, SS); if (!TL) return NestedNameSpecifierLoc(); @@ -4477,7 +4455,7 @@ NestedNameSpecifierLoc TreeTransform<Derived>::TransformNestedNameSpecifierLoc( } // The qualifier-in-scope and object type only apply to the leftmost entity. - FirstQualifierInScope = nullptr; + SS.setUnqualifiedLookups(std::nullopt); ObjectType = QualType(); } @@ -4560,14 +4538,10 @@ TreeTransform<Derived> llvm_unreachable("Unknown name kind."); } -template<typename Derived> -TemplateName -TreeTransform<Derived>::TransformTemplateName(CXXScopeSpec &SS, - TemplateName Name, - SourceLocation NameLoc, - QualType ObjectType, - NamedDecl *FirstQualifierInScope, - bool AllowInjectedClassName) { +template <typename Derived> +TemplateName TreeTransform<Derived>::TransformTemplateName( + CXXScopeSpec &SS, TemplateName Name, SourceLocation NameLoc, + QualType ObjectType, bool AllowInjectedClassName, bool MayBeNNS) { if (QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName()) { TemplateDecl *Template = QTN->getUnderlyingTemplate().getAsTemplateDecl(); assert(Template && "qualified template name must refer to a template"); @@ -4591,7 +4565,7 @@ TreeTransform<Derived>::TransformTemplateName(CXXScopeSpec &SS, if (SS.getScopeRep()) { // These apply to the scope specifier, not the template. ObjectType = QualType(); - FirstQualifierInScope = nullptr; + SS.setUnqualifiedLookups(std::nullopt); } if (!getDerived().AlwaysRebuild() && @@ -4603,13 +4577,9 @@ TreeTransform<Derived>::TransformTemplateName(CXXScopeSpec &SS, SourceLocation TemplateKWLoc = NameLoc; if (DTN->isIdentifier()) { - return getDerived().RebuildTemplateName(SS, - TemplateKWLoc, - *DTN->getIdentifier(), - NameLoc, - ObjectType, - FirstQualifierInScope, - AllowInjectedClassName); + return getDerived().RebuildTemplateName( + SS, TemplateKWLoc, *DTN->getIdentifier(), NameLoc, ObjectType, + AllowInjectedClassName, MayBeNNS); } return getDerived().RebuildTemplateName(SS, TemplateKWLoc, @@ -5153,39 +5123,31 @@ QualType TreeTransform<Derived>::RebuildQualifiedType(QualType T, return SemaRef.BuildQualifiedType(T, Loc, Quals); } -template<typename Derived> -TypeLoc -TreeTransform<Derived>::TransformTypeInObjectScope(TypeLoc TL, - QualType ObjectType, - NamedDecl *UnqualLookup, - CXXScopeSpec &SS) { +template <typename Derived> +TypeLoc TreeTransform<Derived>::TransformTypeInObjectScope(TypeLoc TL, + QualType ObjectType, + CXXScopeSpec &SS) { if (getDerived().AlreadyTransformed(TL.getType())) return TL; - TypeSourceInfo *TSI = - TransformTSIInObjectScope(TL, ObjectType, UnqualLookup, SS); + TypeSourceInfo *TSI = TransformTSIInObjectScope(TL, ObjectType, SS); if (TSI) return TSI->getTypeLoc(); return TypeLoc(); } -template<typename Derived> -TypeSourceInfo * -TreeTransform<Derived>::TransformTypeInObjectScope(TypeSourceInfo *TSInfo, - QualType ObjectType, - NamedDecl *UnqualLookup, - CXXScopeSpec &SS) { +template <typename Derived> +TypeSourceInfo *TreeTransform<Derived>::TransformTypeInObjectScope( + TypeSourceInfo *TSInfo, QualType ObjectType, CXXScopeSpec &SS) { if (getDerived().AlreadyTransformed(TSInfo->getType())) return TSInfo; - return TransformTSIInObjectScope(TSInfo->getTypeLoc(), ObjectType, - UnqualLookup, SS); + return TransformTSIInObjectScope(TSInfo->getTypeLoc(), ObjectType, SS); } template <typename Derived> TypeSourceInfo *TreeTransform<Derived>::TransformTSIInObjectScope( - TypeLoc TL, QualType ObjectType, NamedDecl *UnqualLookup, - CXXScopeSpec &SS) { + TypeLoc TL, QualType ObjectType, CXXScopeSpec &SS) { QualType T = TL.getType(); assert(!getDerived().AlreadyTransformed(T)); @@ -5198,7 +5160,7 @@ TypeSourceInfo *TreeTransform<Derived>::TransformTSIInObjectScope( TemplateName Template = getDerived().TransformTemplateName( SS, SpecTL.getTypePtr()->getTemplateName(), SpecTL.getTemplateNameLoc(), - ObjectType, UnqualLookup, /*AllowInjectedClassName*/true); + ObjectType, /*AllowInjectedClassName=*/true, /*MayBeNNS=*/true); if (Template.isNull()) return nullptr; @@ -5208,13 +5170,11 @@ TypeSourceInfo *TreeTransform<Derived>::TransformTSIInObjectScope( DependentTemplateSpecializationTypeLoc SpecTL = TL.castAs<DependentTemplateSpecializationTypeLoc>(); - TemplateName Template - = getDerived().RebuildTemplateName(SS, - SpecTL.getTemplateKeywordLoc(), - *SpecTL.getTypePtr()->getIdentifier(), - SpecTL.getTemplateNameLoc(), - ObjectType, UnqualLookup, - /*AllowInjectedClassName*/true); + TemplateName Template = getDerived().RebuildTemplateName( + SS, SpecTL.getTemplateKeywordLoc(), + *SpecTL.getTypePtr()->getIdentifier(), SpecTL.getTemplateNameLoc(), + ObjectType, + /*AllowInjectedClassName=*/true, /*MayBeNNS=*/true); if (Template.isNull()) return nullptr; @@ -12358,7 +12318,8 @@ TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E) { // first-qualifier-in-scope here, just in case we had a dependent // base (and therefore couldn't do the check) and a // nested-name-qualifier (and therefore could do the lookup). - NamedDecl *FirstQualifierInScope = nullptr; + ArrayRef<DeclAccessPair> UnqualifiedLookups; + DeclarationNameInfo MemberNameInfo = E->getMemberNameInfo(); if (MemberNameInfo.getName()) { MemberNameInfo = getDerived().TransformDeclarationNameInfo(MemberNameInfo); @@ -12366,16 +12327,11 @@ TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E) { return ExprError(); } - return getDerived().RebuildMemberExpr(Base.get(), FakeOperatorLoc, - E->isArrow(), - QualifierLoc, - TemplateKWLoc, - MemberNameInfo, - Member, - FoundDecl, - (E->hasExplicitTemplateArgs() - ? &TransArgs : nullptr), - FirstQualifierInScope); + return getDerived().RebuildMemberExpr( + Base.get(), FakeOperatorLoc, E->isArrow(), QualifierLoc, TemplateKWLoc, + MemberNameInfo, Member, FoundDecl, + (E->hasExplicitTemplateArgs() ? &TransArgs : nullptr), + UnqualifiedLookups); } template<typename Derived> @@ -13502,9 +13458,8 @@ TreeTransform<Derived>::TransformCXXPseudoDestructorExpr( PseudoDestructorTypeStorage Destroyed; if (E->getDestroyedTypeInfo()) { - TypeSourceInfo *DestroyedTypeInfo - = getDerived().TransformTypeInObjectScope(E->getDestroyedTypeInfo(), - ObjectType, nullptr, SS); + TypeSourceInfo *DestroyedTypeInfo = getDerived().TransformTypeInObjectScope( + E->getDestroyedTypeInfo(), ObjectType, SS); if (!DestroyedTypeInfo) return ExprError(); Destroyed = DestroyedTypeInfo; @@ -13530,7 +13485,7 @@ TreeTransform<Derived>::TransformCXXPseudoDestructorExpr( if (E->getScopeTypeInfo()) { CXXScopeSpec EmptySS; ScopeTypeInfo = getDerived().TransformTypeInObjectScope( - E->getScopeTypeInfo(), ObjectType, nullptr, EmptySS); + E->getScopeTypeInfo(), ObjectType, EmptySS); if (!ScopeTypeInfo) return ExprError(); } @@ -14791,19 +14746,17 @@ TreeTransform<Derived>::TransformCXXDependentScopeMemberExpr( ObjectType = BaseType->castAs<PointerType>()->getPointeeType(); } - // Transform the first part of the nested-name-specifier that qualifies - // the member name. - NamedDecl *FirstQualifierInScope - = getDerived().TransformFirstQualifierInScope( - E->getFirstQualifierFoundInScope(), - E->getQualifierLoc().getBeginLoc()); + UnresolvedSet<4> UnqualifiedLookups; + for (auto D : E->unqualified_lookups()) { + if (NamedDecl *InstD = getDerived().TransformFirstQualifierInScope( + D.getDecl(), E->getQualifierLoc().getBeginLoc())) + UnqualifiedLookups.addDecl(InstD); + } NestedNameSpecifierLoc QualifierLoc; if (E->getQualifier()) { - QualifierLoc - = getDerived().TransformNestedNameSpecifierLoc(E->getQualifierLoc(), - ObjectType, - FirstQualifierInScope); + QualifierLoc = getDerived().TransformNestedNameSpecifierLoc( + E->getQualifierLoc(), ObjectType, UnqualifiedLookups.pairs()); if (!QualifierLoc) return ExprError(); } @@ -14822,23 +14775,16 @@ TreeTransform<Derived>::TransformCXXDependentScopeMemberExpr( if (!E->hasExplicitTemplateArgs()) { // This is a reference to a member without an explicitly-specified // template argument list. Optimize for this common case. - if (!getDerived().AlwaysRebuild() && - Base.get() == OldBase && - BaseType == E->getBaseType() && - QualifierLoc == E->getQualifierLoc() && + if (!getDerived().AlwaysRebuild() && Base.get() == OldBase && + BaseType == E->getBaseType() && QualifierLoc == E->getQualifierLoc() && NameInfo.getName() == E->getMember() && - FirstQualifierInScope == E->getFirstQualifierFoundInScope()) + UnqualifiedLookups.pairs() == E->unqualified_lookups()) return E; - return getDerived().RebuildCXXDependentScopeMemberExpr(Base.get(), - BaseType, - E->isArrow(), - E->getOperatorLoc(), - QualifierLoc, - TemplateKWLoc, - FirstQualifierInScope, - NameInfo, - /*TemplateArgs*/nullptr); + return getDerived().RebuildCXXDependentScopeMemberExpr( + Base.get(), BaseType, E->isArrow(), E->getOperatorLoc(), QualifierLoc, + TemplateKWLoc, UnqualifiedLookups.pairs(), NameInfo, + /*TemplateArgs*/ nullptr); } TemplateArgumentListInfo TransArgs(E->getLAngleLoc(), E->getRAngleLoc()); @@ -14847,15 +14793,9 @@ TreeTransform<Derived>::TransformCXXDependentScopeMemberExpr( TransArgs)) return ExprError(); - return getDerived().RebuildCXXDependentScopeMemberExpr(Base.get(), - BaseType, - E->isArrow(), - E->getOperatorLoc(), - QualifierLoc, - TemplateKWLoc, - FirstQualifierInScope, - NameInfo, - &TransArgs); + return getDerived().RebuildCXXDependentScopeMemberExpr( + Base.get(), BaseType, E->isArrow(), E->getOperatorLoc(), QualifierLoc, + TemplateKWLoc, UnqualifiedLookups.pairs(), NameInfo, &TransArgs); } template <typename Derived> @@ -14916,11 +14856,11 @@ ExprResult TreeTransform<Derived>::TransformUnresolvedMemberExpr( // first-qualifier-in-scope here, just in case we had a dependent // base (and therefore couldn't do the check) and a // nested-name-qualifier (and therefore could do the lookup). - NamedDecl *FirstQualifierInScope = nullptr; + ArrayRef<DeclAccessPair> UnqualifiedLookups; return getDerived().RebuildUnresolvedMemberExpr( Base.get(), BaseType, Old->getOperatorLoc(), Old->isArrow(), QualifierLoc, - TemplateKWLoc, FirstQualifierInScope, R, + TemplateKWLoc, UnqualifiedLookups, R, (Old->hasExplicitTemplateArgs() ? &TransArgs : nullptr)); } @@ -16277,22 +16217,18 @@ TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS, TemplateName(Template)); } -template<typename Derived> -TemplateName -TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS, - SourceLocation TemplateKWLoc, - const IdentifierInfo &Name, - SourceLocation NameLoc, - QualType ObjectType, - NamedDecl *FirstQualifierInScope, - bool AllowInjectedClassName) { +template <typename Derived> +TemplateName TreeTransform<Derived>::RebuildTemplateName( + CXXScopeSpec &SS, SourceLocation TemplateKWLoc, const IdentifierInfo &Name, + SourceLocation NameLoc, QualType ObjectType, bool AllowInjectedClassName, + bool MayBeNNS) { UnqualifiedId TemplateName; TemplateName.setIdentifier(&Name, NameLoc); Sema::TemplateTy Template; getSema().ActOnTemplateName(/*Scope=*/nullptr, SS, TemplateKWLoc, TemplateName, ParsedType::make(ObjectType), /*EnteringContext=*/false, Template, - AllowInjectedClassName); + AllowInjectedClassName, MayBeNNS); return Template.get(); } @@ -16440,13 +16376,10 @@ TreeTransform<Derived>::RebuildCXXPseudoDestructorExpr(Expr *Base, } SourceLocation TemplateKWLoc; // FIXME: retrieve it from caller. - return getSema().BuildMemberReferenceExpr(Base, BaseType, - OperatorLoc, isArrow, - SS, TemplateKWLoc, - /*FIXME: FirstQualifier*/ nullptr, - NameInfo, - /*TemplateArgs*/ nullptr, - /*S*/nullptr); + return getSema().BuildMemberReferenceExpr( + Base, BaseType, OperatorLoc, isArrow, SS, TemplateKWLoc, NameInfo, + /*TemplateArgs=*/nullptr, + /*S=*/nullptr); } template<typename Derived> diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index e23ceff..5a5d7be 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -1993,42 +1993,43 @@ void ASTStmtReader::VisitCXXDependentScopeMemberExpr( CXXDependentScopeMemberExpr *E) { VisitExpr(E); - unsigned NumTemplateArgs = Record.readInt(); CurrentUnpackingBits.emplace(Record.readInt()); - bool HasTemplateKWAndArgsInfo = CurrentUnpackingBits->getNextBit(); - bool HasFirstQualifierFoundInScope = CurrentUnpackingBits->getNextBit(); - - assert((HasTemplateKWAndArgsInfo == E->hasTemplateKWAndArgsInfo()) && - "Wrong HasTemplateKWAndArgsInfo!"); - assert( - (HasFirstQualifierFoundInScope == E->hasFirstQualifierFoundInScope()) && - "Wrong HasFirstQualifierFoundInScope!"); - - if (HasTemplateKWAndArgsInfo) - ReadTemplateKWAndArgsInfo( - *E->getTrailingObjects<ASTTemplateKWAndArgsInfo>(), - E->getTrailingObjects<TemplateArgumentLoc>(), NumTemplateArgs); - - assert((NumTemplateArgs == E->getNumTemplateArgs()) && - "Wrong NumTemplateArgs!"); + bool HasQualifier = CurrentUnpackingBits->getNextBit(); + bool HasTemplateInfo = CurrentUnpackingBits->getNextBit(); + unsigned NumUnqualifiedLookups = Record.readInt(); + unsigned NumTemplateArgs = Record.readInt(); + E->CXXDependentScopeMemberExprBits.HasQualifier = HasQualifier; + E->CXXDependentScopeMemberExprBits.NumUnqualifiedLookups = + NumUnqualifiedLookups; + E->CXXDependentScopeMemberExprBits.HasTemplateKWAndArgsInfo = HasTemplateInfo; + E->BaseType = Record.readType(); E->CXXDependentScopeMemberExprBits.IsArrow = CurrentUnpackingBits->getNextBit(); - E->BaseType = Record.readType(); - E->QualifierLoc = Record.readNestedNameSpecifierLoc(); - // not ImplicitAccess if (CurrentUnpackingBits->getNextBit()) E->Base = Record.readSubExpr(); else E->Base = nullptr; - E->CXXDependentScopeMemberExprBits.OperatorLoc = readSourceLocation(); + E->OperatorLoc = Record.readSourceLocation(); + E->MemberNameInfo = Record.readDeclarationNameInfo(); - if (HasFirstQualifierFoundInScope) - *E->getTrailingObjects<NamedDecl *>() = readDeclAs<NamedDecl>(); + if (HasQualifier) + new (E->getTrailingObjects<NestedNameSpecifierLoc>()) + NestedNameSpecifierLoc(Record.readNestedNameSpecifierLoc()); - E->MemberNameInfo = Record.readDeclarationNameInfo(); + for (unsigned I = 0; I != NumUnqualifiedLookups; ++I) { + auto *FoundD = Record.readDeclAs<NamedDecl>(); + auto AS = (AccessSpecifier)Record.readInt(); + E->getTrailingObjects<DeclAccessPair>()[I] = + DeclAccessPair::make(FoundD, AS); + } + + if (HasTemplateInfo) + ReadTemplateKWAndArgsInfo( + *E->getTrailingObjects<ASTTemplateKWAndArgsInfo>(), + E->getTrailingObjects<TemplateArgumentLoc>(), NumTemplateArgs); } void @@ -4075,16 +4076,16 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { break; case EXPR_CXX_DEPENDENT_SCOPE_MEMBER: { - unsigned NumTemplateArgs = Record[ASTStmtReader::NumExprFields]; BitsUnpacker DependentScopeMemberBits( - Record[ASTStmtReader::NumExprFields + 1]); - bool HasTemplateKWAndArgsInfo = DependentScopeMemberBits.getNextBit(); + Record[ASTStmtReader::NumExprFields]); + bool HasQualifier = DependentScopeMemberBits.getNextBit(); + bool HasTemplateInfo = DependentScopeMemberBits.getNextBit(); + unsigned NumUnqualifiedLookups = Record[ASTStmtReader::NumExprFields + 1]; + unsigned NumTemplateArgs = Record[ASTStmtReader::NumExprFields + 2]; - bool HasFirstQualifierFoundInScope = - DependentScopeMemberBits.getNextBit(); S = CXXDependentScopeMemberExpr::CreateEmpty( - Context, HasTemplateKWAndArgsInfo, NumTemplateArgs, - HasFirstQualifierFoundInScope); + Context, HasQualifier, NumUnqualifiedLookups, HasTemplateInfo, + NumTemplateArgs); break; } diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp index ea49901..30c5b1b 100644 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -1988,34 +1988,41 @@ void ASTStmtWriter::VisitCXXDependentScopeMemberExpr( CXXDependentScopeMemberExpr *E) { VisitExpr(E); - // Don't emit anything here (or if you do you will have to update - // the corresponding deserialization function). - Record.push_back(E->getNumTemplateArgs()); - CurrentPackingBits.updateBits(); - CurrentPackingBits.addBit(E->hasTemplateKWAndArgsInfo()); - CurrentPackingBits.addBit(E->hasFirstQualifierFoundInScope()); - - if (E->hasTemplateKWAndArgsInfo()) { - const ASTTemplateKWAndArgsInfo &ArgInfo = - *E->getTrailingObjects<ASTTemplateKWAndArgsInfo>(); - AddTemplateKWAndArgsInfo(ArgInfo, - E->getTrailingObjects<TemplateArgumentLoc>()); - } + bool HasQualifier = E->hasQualifier(); + unsigned NumUnqualifiedLookups = E->getNumUnqualifiedLookups(); + bool HasTemplateInfo = E->hasTemplateKWAndArgsInfo(); + unsigned NumTemplateArgs = E->getNumTemplateArgs(); - CurrentPackingBits.addBit(E->isArrow()); + // Write these first for easy access when deserializing, as they affect the + // size of the CXXDependentScopeMemberExpr. + CurrentPackingBits.updateBits(); + CurrentPackingBits.addBit(HasQualifier); + CurrentPackingBits.addBit(HasTemplateInfo); + Record.push_back(NumUnqualifiedLookups); + Record.push_back(NumTemplateArgs); Record.AddTypeRef(E->getBaseType()); - Record.AddNestedNameSpecifierLoc(E->getQualifierLoc()); + CurrentPackingBits.addBit(E->isArrow()); CurrentPackingBits.addBit(!E->isImplicitAccess()); if (!E->isImplicitAccess()) Record.AddStmt(E->getBase()); Record.AddSourceLocation(E->getOperatorLoc()); - if (E->hasFirstQualifierFoundInScope()) - Record.AddDeclRef(E->getFirstQualifierFoundInScope()); - Record.AddDeclarationNameInfo(E->MemberNameInfo); + + if (HasQualifier) + Record.AddNestedNameSpecifierLoc(E->getQualifierLoc()); + + for (DeclAccessPair D : E->unqualified_lookups()) { + Record.AddDeclRef(D.getDecl()); + Record.push_back(D.getAccess()); + } + + if (HasTemplateInfo) + AddTemplateKWAndArgsInfo(*E->getTrailingObjects<ASTTemplateKWAndArgsInfo>(), + E->getTrailingObjects<TemplateArgumentLoc>()); + Code = serialization::EXPR_CXX_DEPENDENT_SCOPE_MEMBER; } |