Skip to content

Commit 01c3db0

Browse files
committed
Reapply "[Clang] Implement resolution for CWG1835 (llvm#92957)"
Reapplies llvm#92957.
1 parent 842a332 commit 01c3db0

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+1109
-805
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,9 @@ C++2c Feature Support
8787
Resolutions to C++ Defect Reports
8888
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
8989

90+
- Clang now correctly implements lookup for the terminal name of a member-qualified nested-name-specifier.
91+
(`CWG1835: Dependent member lookup before < <https://cplusplus.github.io/CWG/issues/1835.html>`_).
92+
9093
C Language Changes
9194
------------------
9295

clang/include/clang/AST/ExprCXX.h

Lines changed: 49 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -3676,9 +3676,9 @@ class CXXUnresolvedConstructExpr final
36763676
/// an implicit access if a qualifier is provided.
36773677
class CXXDependentScopeMemberExpr final
36783678
: public Expr,
3679-
private llvm::TrailingObjects<CXXDependentScopeMemberExpr,
3680-
ASTTemplateKWAndArgsInfo,
3681-
TemplateArgumentLoc, NamedDecl *> {
3679+
private llvm::TrailingObjects<
3680+
CXXDependentScopeMemberExpr, NestedNameSpecifierLoc, DeclAccessPair,
3681+
ASTTemplateKWAndArgsInfo, TemplateArgumentLoc> {
36823682
friend class ASTStmtReader;
36833683
friend class ASTStmtWriter;
36843684
friend TrailingObjects;
@@ -3691,17 +3691,15 @@ class CXXDependentScopeMemberExpr final
36913691
/// implicit accesses.
36923692
QualType BaseType;
36933693

3694-
/// The nested-name-specifier that precedes the member name, if any.
3695-
/// FIXME: This could be in principle store as a trailing object.
3696-
/// However the performance impact of doing so should be investigated first.
3697-
NestedNameSpecifierLoc QualifierLoc;
3698-
36993694
/// The member to which this member expression refers, which
37003695
/// can be name, overloaded operator, or destructor.
37013696
///
37023697
/// FIXME: could also be a template-id
37033698
DeclarationNameInfo MemberNameInfo;
37043699

3700+
/// The location of the '->' or '.' operator.
3701+
SourceLocation OperatorLoc;
3702+
37053703
// CXXDependentScopeMemberExpr is followed by several trailing objects,
37063704
// some of which optional. They are in order:
37073705
//
@@ -3721,8 +3719,16 @@ class CXXDependentScopeMemberExpr final
37213719
return CXXDependentScopeMemberExprBits.HasTemplateKWAndArgsInfo;
37223720
}
37233721

3724-
bool hasFirstQualifierFoundInScope() const {
3725-
return CXXDependentScopeMemberExprBits.HasFirstQualifierFoundInScope;
3722+
unsigned getNumUnqualifiedLookups() const {
3723+
return CXXDependentScopeMemberExprBits.NumUnqualifiedLookups;
3724+
}
3725+
3726+
unsigned numTrailingObjects(OverloadToken<NestedNameSpecifierLoc>) const {
3727+
return hasQualifier();
3728+
}
3729+
3730+
unsigned numTrailingObjects(OverloadToken<DeclAccessPair>) const {
3731+
return getNumUnqualifiedLookups();
37263732
}
37273733

37283734
unsigned numTrailingObjects(OverloadToken<ASTTemplateKWAndArgsInfo>) const {
@@ -3733,33 +3739,32 @@ class CXXDependentScopeMemberExpr final
37333739
return getNumTemplateArgs();
37343740
}
37353741

3736-
unsigned numTrailingObjects(OverloadToken<NamedDecl *>) const {
3737-
return hasFirstQualifierFoundInScope();
3738-
}
3739-
37403742
CXXDependentScopeMemberExpr(const ASTContext &Ctx, Expr *Base,
37413743
QualType BaseType, bool IsArrow,
37423744
SourceLocation OperatorLoc,
37433745
NestedNameSpecifierLoc QualifierLoc,
37443746
SourceLocation TemplateKWLoc,
3745-
NamedDecl *FirstQualifierFoundInScope,
3747+
ArrayRef<DeclAccessPair> UnqualifiedLookups,
37463748
DeclarationNameInfo MemberNameInfo,
37473749
const TemplateArgumentListInfo *TemplateArgs);
37483750

3749-
CXXDependentScopeMemberExpr(EmptyShell Empty, bool HasTemplateKWAndArgsInfo,
3750-
bool HasFirstQualifierFoundInScope);
3751+
CXXDependentScopeMemberExpr(EmptyShell Empty, bool HasQualifier,
3752+
unsigned NumUnqualifiedLookups,
3753+
bool HasTemplateKWAndArgsInfo);
37513754

37523755
public:
37533756
static CXXDependentScopeMemberExpr *
37543757
Create(const ASTContext &Ctx, Expr *Base, QualType BaseType, bool IsArrow,
37553758
SourceLocation OperatorLoc, NestedNameSpecifierLoc QualifierLoc,
3756-
SourceLocation TemplateKWLoc, NamedDecl *FirstQualifierFoundInScope,
3759+
SourceLocation TemplateKWLoc,
3760+
ArrayRef<DeclAccessPair> UnqualifiedLookups,
37573761
DeclarationNameInfo MemberNameInfo,
37583762
const TemplateArgumentListInfo *TemplateArgs);
37593763

37603764
static CXXDependentScopeMemberExpr *
3761-
CreateEmpty(const ASTContext &Ctx, bool HasTemplateKWAndArgsInfo,
3762-
unsigned NumTemplateArgs, bool HasFirstQualifierFoundInScope);
3765+
CreateEmpty(const ASTContext &Ctx, bool HasQualifier,
3766+
unsigned NumUnqualifiedLookups, bool HasTemplateKWAndArgsInfo,
3767+
unsigned NumTemplateArgs);
37633768

37643769
/// True if this is an implicit access, i.e. one in which the
37653770
/// member being accessed was not written in the source. The source
@@ -3784,34 +3789,35 @@ class CXXDependentScopeMemberExpr final
37843789
bool isArrow() const { return CXXDependentScopeMemberExprBits.IsArrow; }
37853790

37863791
/// Retrieve the location of the '->' or '.' operator.
3787-
SourceLocation getOperatorLoc() const {
3788-
return CXXDependentScopeMemberExprBits.OperatorLoc;
3792+
SourceLocation getOperatorLoc() const { return OperatorLoc; }
3793+
3794+
/// Determines whether this member expression had a nested-name-specifier
3795+
/// prior to the name of the member, e.g., x->Base::foo.
3796+
bool hasQualifier() const {
3797+
return CXXDependentScopeMemberExprBits.HasQualifier;
37893798
}
37903799

3791-
/// Retrieve the nested-name-specifier that qualifies the member name.
3792-
NestedNameSpecifier *getQualifier() const {
3793-
return QualifierLoc.getNestedNameSpecifier();
3800+
/// If the member name was qualified, retrieves the nested-name-specifier
3801+
/// that precedes the member name, with source-location information.
3802+
NestedNameSpecifierLoc getQualifierLoc() const {
3803+
if (!hasQualifier())
3804+
return NestedNameSpecifierLoc();
3805+
return *getTrailingObjects<NestedNameSpecifierLoc>();
37943806
}
37953807

3796-
/// Retrieve the nested-name-specifier that qualifies the member
3797-
/// name, with source location information.
3798-
NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; }
3808+
/// If the member name was qualified, retrieves the
3809+
/// nested-name-specifier that precedes the member name. Otherwise, returns
3810+
/// NULL.
3811+
NestedNameSpecifier *getQualifier() const {
3812+
return getQualifierLoc().getNestedNameSpecifier();
3813+
}
37993814

3800-
/// Retrieve the first part of the nested-name-specifier that was
3801-
/// found in the scope of the member access expression when the member access
3802-
/// was initially parsed.
3803-
///
3804-
/// This function only returns a useful result when member access expression
3805-
/// uses a qualified member name, e.g., "x.Base::f". Here, the declaration
3806-
/// returned by this function describes what was found by unqualified name
3807-
/// lookup for the identifier "Base" within the scope of the member access
3808-
/// expression itself. At template instantiation time, this information is
3809-
/// combined with the results of name lookup into the type of the object
3810-
/// expression itself (the class type of x).
3811-
NamedDecl *getFirstQualifierFoundInScope() const {
3812-
if (!hasFirstQualifierFoundInScope())
3813-
return nullptr;
3814-
return *getTrailingObjects<NamedDecl *>();
3815+
/// Retrieve the declarations found by unqualified lookup for the first
3816+
/// component name of the nested-name-specifier, if any.
3817+
ArrayRef<DeclAccessPair> unqualified_lookups() const {
3818+
if (!getNumUnqualifiedLookups())
3819+
return std::nullopt;
3820+
return {getTrailingObjects<DeclAccessPair>(), getNumUnqualifiedLookups()};
38153821
}
38163822

38173823
/// Retrieve the name of the member that this expression refers to.

clang/include/clang/AST/Stmt.h

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1020,18 +1020,19 @@ class alignas(void *) Stmt {
10201020
LLVM_PREFERRED_TYPE(bool)
10211021
unsigned IsArrow : 1;
10221022

1023+
/// True if this member expression used a nested-name-specifier to
1024+
/// refer to the member, e.g., "x->Base::f".
1025+
LLVM_PREFERRED_TYPE(bool)
1026+
unsigned HasQualifier : 1;
1027+
10231028
/// Whether this member expression has info for explicit template
10241029
/// keyword and arguments.
10251030
LLVM_PREFERRED_TYPE(bool)
10261031
unsigned HasTemplateKWAndArgsInfo : 1;
10271032

1028-
/// See getFirstQualifierFoundInScope() and the comment listing
1029-
/// the trailing objects.
1030-
LLVM_PREFERRED_TYPE(bool)
1031-
unsigned HasFirstQualifierFoundInScope : 1;
1032-
1033-
/// The location of the '->' or '.' operator.
1034-
SourceLocation OperatorLoc;
1033+
/// Number of declarations found by unqualified lookup for the
1034+
/// first component name of the nested-name-specifier.
1035+
unsigned NumUnqualifiedLookups;
10351036
};
10361037

10371038
class OverloadExprBitfields {

clang/include/clang/AST/UnresolvedSet.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,10 @@ class UnresolvedSetImpl {
9797
decls().push_back(DeclAccessPair::make(D, AS));
9898
}
9999

100+
void addAllDecls(ArrayRef<DeclAccessPair> Other) {
101+
append(iterator(Other.begin()), iterator(Other.end()));
102+
}
103+
100104
/// Replaces the given declaration with the new one, once.
101105
///
102106
/// \return true if the set changed

clang/include/clang/Basic/DiagnosticParseKinds.td

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -895,9 +895,7 @@ def missing_template_arg_list_after_template_kw : Extension<
895895
"keyword">, InGroup<DiagGroup<"missing-template-arg-list-after-template-kw">>,
896896
DefaultError;
897897

898-
def err_missing_dependent_template_keyword : Error<
899-
"use 'template' keyword to treat '%0' as a dependent template name">;
900-
def warn_missing_dependent_template_keyword : ExtWarn<
898+
def ext_missing_dependent_template_keyword : ExtWarn<
901899
"use 'template' keyword to treat '%0' as a dependent template name">;
902900

903901
def ext_extern_template : Extension<

clang/include/clang/Parse/Parser.h

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3374,15 +3374,11 @@ class Parser : public CodeCompletionHandler {
33743374
BaseResult ParseBaseSpecifier(Decl *ClassDecl);
33753375
AccessSpecifier getAccessSpecifierIfPresent() const;
33763376

3377-
bool ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
3378-
ParsedType ObjectType,
3379-
bool ObjectHadErrors,
3380-
SourceLocation TemplateKWLoc,
3381-
IdentifierInfo *Name,
3382-
SourceLocation NameLoc,
3383-
bool EnteringContext,
3384-
UnqualifiedId &Id,
3385-
bool AssumeTemplateId);
3377+
bool ParseUnqualifiedIdTemplateId(
3378+
CXXScopeSpec &SS, ParsedType ObjectType, bool ObjectHadErrors,
3379+
SourceLocation TemplateKWLoc, SourceLocation TildeLoc,
3380+
IdentifierInfo *Name, SourceLocation NameLoc, bool EnteringContext,
3381+
UnqualifiedId &Id, bool AssumeTemplateId);
33863382
bool ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
33873383
ParsedType ObjectType,
33883384
UnqualifiedId &Result);

clang/include/clang/Sema/DeclSpec.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ class CXXScopeSpec {
7575
SourceRange Range;
7676
NestedNameSpecifierLocBuilder Builder;
7777
ArrayRef<TemplateParameterList *> TemplateParamLists;
78+
ArrayRef<DeclAccessPair> UnqualifiedLookups;
7879

7980
public:
8081
SourceRange getRange() const { return Range; }
@@ -91,6 +92,13 @@ class CXXScopeSpec {
9192
return TemplateParamLists;
9293
}
9394

95+
void setUnqualifiedLookups(ArrayRef<DeclAccessPair> Found) {
96+
UnqualifiedLookups = Found;
97+
}
98+
ArrayRef<DeclAccessPair> getUnqualifiedLookups() const {
99+
return UnqualifiedLookups;
100+
}
101+
94102
/// Retrieve the representation of the nested-name-specifier.
95103
NestedNameSpecifier *getScopeRep() const {
96104
return Builder.getRepresentation();

clang/include/clang/Sema/Lookup.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -483,11 +483,15 @@ class LookupResult {
483483
ResultKind = Found;
484484
}
485485

486+
void addAllDecls(ArrayRef<DeclAccessPair> Other) {
487+
Decls.addAllDecls(Other);
488+
ResultKind = Found;
489+
}
490+
486491
/// Add all the declarations from another set of lookup
487492
/// results.
488493
void addAllDecls(const LookupResult &Other) {
489-
Decls.append(Other.Decls.begin(), Other.Decls.end());
490-
ResultKind = Found;
494+
addAllDecls(Other.Decls.pairs());
491495
}
492496

493497
/// Determine whether no result was found because we could not

clang/include/clang/Sema/Sema.h

Lines changed: 22 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2804,7 +2804,8 @@ class Sema final : public SemaBase {
28042804
/// (e.g., Base::), perform name lookup for that identifier as a
28052805
/// nested-name-specifier within the given scope, and return the result of
28062806
/// that name lookup.
2807-
NamedDecl *FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS);
2807+
bool LookupFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS,
2808+
UnresolvedSetImpl &R);
28082809

28092810
/// Keeps information about an identifier in a nested-name-spec.
28102811
///
@@ -2844,9 +2845,6 @@ class Sema final : public SemaBase {
28442845
/// \param EnteringContext If true, enter the context specified by the
28452846
/// nested-name-specifier.
28462847
/// \param SS Optional nested name specifier preceding the identifier.
2847-
/// \param ScopeLookupResult Provides the result of name lookup within the
2848-
/// scope of the nested-name-specifier that was computed at template
2849-
/// definition time.
28502848
/// \param ErrorRecoveryLookup Specifies if the method is called to improve
28512849
/// error recovery and what kind of recovery is performed.
28522850
/// \param IsCorrectedToColon If not null, suggestion of replace '::' -> ':'
@@ -2855,11 +2853,6 @@ class Sema final : public SemaBase {
28552853
/// not '::'.
28562854
/// \param OnlyNamespace If true, only considers namespaces in lookup.
28572855
///
2858-
/// This routine differs only slightly from ActOnCXXNestedNameSpecifier, in
2859-
/// that it contains an extra parameter \p ScopeLookupResult, which provides
2860-
/// the result of name lookup within the scope of the nested-name-specifier
2861-
/// that was computed at template definition time.
2862-
///
28632856
/// If ErrorRecoveryLookup is true, then this call is used to improve error
28642857
/// recovery. This means that it should not emit diagnostics, it should
28652858
/// just return true on failure. It also means it should only return a valid
@@ -2868,7 +2861,6 @@ class Sema final : public SemaBase {
28682861
/// specifier.
28692862
bool BuildCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo,
28702863
bool EnteringContext, CXXScopeSpec &SS,
2871-
NamedDecl *ScopeLookupResult,
28722864
bool ErrorRecoveryLookup,
28732865
bool *IsCorrectedToColon = nullptr,
28742866
bool OnlyNamespace = false);
@@ -8570,11 +8562,12 @@ class Sema final : public SemaBase {
85708562
const TemplateArgumentListInfo *TemplateArgs,
85718563
bool IsDefiniteInstance, const Scope *S);
85728564

8573-
ExprResult ActOnDependentMemberExpr(
8574-
Expr *Base, QualType BaseType, bool IsArrow, SourceLocation OpLoc,
8575-
const CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
8576-
NamedDecl *FirstQualifierInScope, const DeclarationNameInfo &NameInfo,
8577-
const TemplateArgumentListInfo *TemplateArgs);
8565+
ExprResult
8566+
ActOnDependentMemberExpr(Expr *Base, QualType BaseType, bool IsArrow,
8567+
SourceLocation OpLoc, const CXXScopeSpec &SS,
8568+
SourceLocation TemplateKWLoc,
8569+
const DeclarationNameInfo &NameInfo,
8570+
const TemplateArgumentListInfo *TemplateArgs);
85788571

85798572
/// The main callback when the parser finds something like
85808573
/// expression . [nested-name-specifier] identifier
@@ -8630,15 +8623,14 @@ class Sema final : public SemaBase {
86308623
ExprResult BuildMemberReferenceExpr(
86318624
Expr *Base, QualType BaseType, SourceLocation OpLoc, bool IsArrow,
86328625
CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
8633-
NamedDecl *FirstQualifierInScope, const DeclarationNameInfo &NameInfo,
8626+
const DeclarationNameInfo &NameInfo,
86348627
const TemplateArgumentListInfo *TemplateArgs, const Scope *S,
86358628
ActOnMemberAccessExtraArgs *ExtraArgs = nullptr);
86368629

86378630
ExprResult
86388631
BuildMemberReferenceExpr(Expr *Base, QualType BaseType, SourceLocation OpLoc,
86398632
bool IsArrow, const CXXScopeSpec &SS,
8640-
SourceLocation TemplateKWLoc,
8641-
NamedDecl *FirstQualifierInScope, LookupResult &R,
8633+
SourceLocation TemplateKWLoc, LookupResult &R,
86428634
const TemplateArgumentListInfo *TemplateArgs,
86438635
const Scope *S, bool SuppressQualifierCheck = false,
86448636
ActOnMemberAccessExtraArgs *ExtraArgs = nullptr);
@@ -11126,15 +11118,14 @@ class Sema final : public SemaBase {
1112611118
QualType ObjectType, bool EnteringContext,
1112711119
RequiredTemplateKind RequiredTemplate = SourceLocation(),
1112811120
AssumedTemplateKind *ATK = nullptr,
11129-
bool AllowTypoCorrection = true);
11121+
bool AllowTypoCorrection = true, bool MayBeNNS = false);
1113011122

11131-
TemplateNameKind isTemplateName(Scope *S, CXXScopeSpec &SS,
11132-
bool hasTemplateKeyword,
11133-
const UnqualifiedId &Name,
11134-
ParsedType ObjectType, bool EnteringContext,
11135-
TemplateTy &Template,
11136-
bool &MemberOfUnknownSpecialization,
11137-
bool Disambiguation = false);
11123+
TemplateNameKind
11124+
isTemplateName(Scope *S, CXXScopeSpec &SS, bool hasTemplateKeyword,
11125+
const UnqualifiedId &Name, ParsedType ObjectType,
11126+
bool EnteringContext, TemplateTy &Template,
11127+
bool &MemberOfUnknownSpecialization,
11128+
bool Disambiguation = false, bool MayBeNNS = false);
1113811129

1113911130
/// Try to resolve an undeclared template name as a type template.
1114011131
///
@@ -11467,12 +11458,11 @@ class Sema final : public SemaBase {
1146711458
/// For example, given "x.MetaFun::template apply", the scope specifier
1146811459
/// \p SS will be "MetaFun::", \p TemplateKWLoc contains the location
1146911460
/// of the "template" keyword, and "apply" is the \p Name.
11470-
TemplateNameKind ActOnTemplateName(Scope *S, CXXScopeSpec &SS,
11471-
SourceLocation TemplateKWLoc,
11472-
const UnqualifiedId &Name,
11473-
ParsedType ObjectType,
11474-
bool EnteringContext, TemplateTy &Template,
11475-
bool AllowInjectedClassName = false);
11461+
TemplateNameKind
11462+
ActOnTemplateName(Scope *S, CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
11463+
const UnqualifiedId &Name, ParsedType ObjectType,
11464+
bool EnteringContext, TemplateTy &Template,
11465+
bool AllowInjectedClassName = false, bool MayBeNNS = false);
1147611466

1147711467
DeclResult ActOnClassTemplateSpecialization(
1147811468
Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc,

0 commit comments

Comments
 (0)