Skip to content

Commit b65f0c1

Browse files
committed
Reapply "[Clang] Implement resolution for CWG1835 (llvm#92957)"
Reapplies llvm#92957.
1 parent d9c95ef commit b65f0c1

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
@@ -246,6 +246,9 @@ Resolutions to C++ Defect Reports
246246
by default.
247247
(`CWG2521: User-defined literals and reserved identifiers <https://cplusplus.github.io/CWG/issues/2521.html>`_).
248248

249+
- Clang now correctly implements lookup for the terminal name of a member-qualified nested-name-specifier.
250+
(`CWG1835: Dependent member lookup before < <https://cplusplus.github.io/CWG/issues/1835.html>`_).
251+
249252
C Language Changes
250253
------------------
251254

clang/include/clang/AST/ExprCXX.h

Lines changed: 49 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -3678,9 +3678,9 @@ class CXXUnresolvedConstructExpr final
36783678
/// an implicit access if a qualifier is provided.
36793679
class CXXDependentScopeMemberExpr final
36803680
: public Expr,
3681-
private llvm::TrailingObjects<CXXDependentScopeMemberExpr,
3682-
ASTTemplateKWAndArgsInfo,
3683-
TemplateArgumentLoc, NamedDecl *> {
3681+
private llvm::TrailingObjects<
3682+
CXXDependentScopeMemberExpr, NestedNameSpecifierLoc, DeclAccessPair,
3683+
ASTTemplateKWAndArgsInfo, TemplateArgumentLoc> {
36843684
friend class ASTStmtReader;
36853685
friend class ASTStmtWriter;
36863686
friend TrailingObjects;
@@ -3693,17 +3693,15 @@ class CXXDependentScopeMemberExpr final
36933693
/// implicit accesses.
36943694
QualType BaseType;
36953695

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

3702+
/// The location of the '->' or '.' operator.
3703+
SourceLocation OperatorLoc;
3704+
37073705
// CXXDependentScopeMemberExpr is followed by several trailing objects,
37083706
// some of which optional. They are in order:
37093707
//
@@ -3723,8 +3721,16 @@ class CXXDependentScopeMemberExpr final
37233721
return CXXDependentScopeMemberExprBits.HasTemplateKWAndArgsInfo;
37243722
}
37253723

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

37303736
unsigned numTrailingObjects(OverloadToken<ASTTemplateKWAndArgsInfo>) const {
@@ -3735,33 +3741,32 @@ class CXXDependentScopeMemberExpr final
37353741
return getNumTemplateArgs();
37363742
}
37373743

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

3751-
CXXDependentScopeMemberExpr(EmptyShell Empty, bool HasTemplateKWAndArgsInfo,
3752-
bool HasFirstQualifierFoundInScope);
3753+
CXXDependentScopeMemberExpr(EmptyShell Empty, bool HasQualifier,
3754+
unsigned NumUnqualifiedLookups,
3755+
bool HasTemplateKWAndArgsInfo);
37533756

37543757
public:
37553758
static CXXDependentScopeMemberExpr *
37563759
Create(const ASTContext &Ctx, Expr *Base, QualType BaseType, bool IsArrow,
37573760
SourceLocation OperatorLoc, NestedNameSpecifierLoc QualifierLoc,
3758-
SourceLocation TemplateKWLoc, NamedDecl *FirstQualifierFoundInScope,
3761+
SourceLocation TemplateKWLoc,
3762+
ArrayRef<DeclAccessPair> UnqualifiedLookups,
37593763
DeclarationNameInfo MemberNameInfo,
37603764
const TemplateArgumentListInfo *TemplateArgs);
37613765

37623766
static CXXDependentScopeMemberExpr *
3763-
CreateEmpty(const ASTContext &Ctx, bool HasTemplateKWAndArgsInfo,
3764-
unsigned NumTemplateArgs, bool HasFirstQualifierFoundInScope);
3767+
CreateEmpty(const ASTContext &Ctx, bool HasQualifier,
3768+
unsigned NumUnqualifiedLookups, bool HasTemplateKWAndArgsInfo,
3769+
unsigned NumTemplateArgs);
37653770

37663771
/// True if this is an implicit access, i.e. one in which the
37673772
/// member being accessed was not written in the source. The source
@@ -3786,34 +3791,35 @@ class CXXDependentScopeMemberExpr final
37863791
bool isArrow() const { return CXXDependentScopeMemberExprBits.IsArrow; }
37873792

37883793
/// Retrieve the location of the '->' or '.' operator.
3789-
SourceLocation getOperatorLoc() const {
3790-
return CXXDependentScopeMemberExprBits.OperatorLoc;
3794+
SourceLocation getOperatorLoc() const { return OperatorLoc; }
3795+
3796+
/// Determines whether this member expression had a nested-name-specifier
3797+
/// prior to the name of the member, e.g., x->Base::foo.
3798+
bool hasQualifier() const {
3799+
return CXXDependentScopeMemberExprBits.HasQualifier;
37913800
}
37923801

3793-
/// Retrieve the nested-name-specifier that qualifies the member name.
3794-
NestedNameSpecifier *getQualifier() const {
3795-
return QualifierLoc.getNestedNameSpecifier();
3802+
/// If the member name was qualified, retrieves the nested-name-specifier
3803+
/// that precedes the member name, with source-location information.
3804+
NestedNameSpecifierLoc getQualifierLoc() const {
3805+
if (!hasQualifier())
3806+
return NestedNameSpecifierLoc();
3807+
return *getTrailingObjects<NestedNameSpecifierLoc>();
37963808
}
37973809

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

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

38193825
/// 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
@@ -1040,18 +1040,19 @@ class alignas(void *) Stmt {
10401040
LLVM_PREFERRED_TYPE(bool)
10411041
unsigned IsArrow : 1;
10421042

1043+
/// True if this member expression used a nested-name-specifier to
1044+
/// refer to the member, e.g., "x->Base::f".
1045+
LLVM_PREFERRED_TYPE(bool)
1046+
unsigned HasQualifier : 1;
1047+
10431048
/// Whether this member expression has info for explicit template
10441049
/// keyword and arguments.
10451050
LLVM_PREFERRED_TYPE(bool)
10461051
unsigned HasTemplateKWAndArgsInfo : 1;
10471052

1048-
/// See getFirstQualifierFoundInScope() and the comment listing
1049-
/// the trailing objects.
1050-
LLVM_PREFERRED_TYPE(bool)
1051-
unsigned HasFirstQualifierFoundInScope : 1;
1052-
1053-
/// The location of the '->' or '.' operator.
1054-
SourceLocation OperatorLoc;
1053+
/// Number of declarations found by unqualified lookup for the
1054+
/// first component name of the nested-name-specifier.
1055+
unsigned NumUnqualifiedLookups;
10551056
};
10561057

10571058
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
@@ -907,9 +907,7 @@ def missing_template_arg_list_after_template_kw : Extension<
907907
"keyword">, InGroup<DiagGroup<"missing-template-arg-list-after-template-kw">>,
908908
DefaultError;
909909

910-
def err_missing_dependent_template_keyword : Error<
911-
"use 'template' keyword to treat '%0' as a dependent template name">;
912-
def warn_missing_dependent_template_keyword : ExtWarn<
910+
def ext_missing_dependent_template_keyword : ExtWarn<
913911
"use 'template' keyword to treat '%0' as a dependent template name">;
914912

915913
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
@@ -3382,15 +3382,11 @@ class Parser : public CodeCompletionHandler {
33823382
BaseResult ParseBaseSpecifier(Decl *ClassDecl);
33833383
AccessSpecifier getAccessSpecifierIfPresent() const;
33843384

3385-
bool ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
3386-
ParsedType ObjectType,
3387-
bool ObjectHadErrors,
3388-
SourceLocation TemplateKWLoc,
3389-
IdentifierInfo *Name,
3390-
SourceLocation NameLoc,
3391-
bool EnteringContext,
3392-
UnqualifiedId &Id,
3393-
bool AssumeTemplateId);
3385+
bool ParseUnqualifiedIdTemplateId(
3386+
CXXScopeSpec &SS, ParsedType ObjectType, bool ObjectHadErrors,
3387+
SourceLocation TemplateKWLoc, SourceLocation TildeLoc,
3388+
IdentifierInfo *Name, SourceLocation NameLoc, bool EnteringContext,
3389+
UnqualifiedId &Id, bool AssumeTemplateId);
33943390
bool ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
33953391
ParsedType ObjectType,
33963392
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
@@ -2771,7 +2771,8 @@ class Sema final : public SemaBase {
27712771
/// (e.g., Base::), perform name lookup for that identifier as a
27722772
/// nested-name-specifier within the given scope, and return the result of
27732773
/// that name lookup.
2774-
NamedDecl *FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS);
2774+
bool LookupFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS,
2775+
UnresolvedSetImpl &R);
27752776

27762777
/// Keeps information about an identifier in a nested-name-spec.
27772778
///
@@ -2811,9 +2812,6 @@ class Sema final : public SemaBase {
28112812
/// \param EnteringContext If true, enter the context specified by the
28122813
/// nested-name-specifier.
28132814
/// \param SS Optional nested name specifier preceding the identifier.
2814-
/// \param ScopeLookupResult Provides the result of name lookup within the
2815-
/// scope of the nested-name-specifier that was computed at template
2816-
/// definition time.
28172815
/// \param ErrorRecoveryLookup Specifies if the method is called to improve
28182816
/// error recovery and what kind of recovery is performed.
28192817
/// \param IsCorrectedToColon If not null, suggestion of replace '::' -> ':'
@@ -2822,11 +2820,6 @@ class Sema final : public SemaBase {
28222820
/// not '::'.
28232821
/// \param OnlyNamespace If true, only considers namespaces in lookup.
28242822
///
2825-
/// This routine differs only slightly from ActOnCXXNestedNameSpecifier, in
2826-
/// that it contains an extra parameter \p ScopeLookupResult, which provides
2827-
/// the result of name lookup within the scope of the nested-name-specifier
2828-
/// that was computed at template definition time.
2829-
///
28302823
/// If ErrorRecoveryLookup is true, then this call is used to improve error
28312824
/// recovery. This means that it should not emit diagnostics, it should
28322825
/// just return true on failure. It also means it should only return a valid
@@ -2835,7 +2828,6 @@ class Sema final : public SemaBase {
28352828
/// specifier.
28362829
bool BuildCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo,
28372830
bool EnteringContext, CXXScopeSpec &SS,
2838-
NamedDecl *ScopeLookupResult,
28392831
bool ErrorRecoveryLookup,
28402832
bool *IsCorrectedToColon = nullptr,
28412833
bool OnlyNamespace = false);
@@ -8527,11 +8519,12 @@ class Sema final : public SemaBase {
85278519
const TemplateArgumentListInfo *TemplateArgs,
85288520
bool IsDefiniteInstance, const Scope *S);
85298521

8530-
ExprResult ActOnDependentMemberExpr(
8531-
Expr *Base, QualType BaseType, bool IsArrow, SourceLocation OpLoc,
8532-
const CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
8533-
NamedDecl *FirstQualifierInScope, const DeclarationNameInfo &NameInfo,
8534-
const TemplateArgumentListInfo *TemplateArgs);
8522+
ExprResult
8523+
ActOnDependentMemberExpr(Expr *Base, QualType BaseType, bool IsArrow,
8524+
SourceLocation OpLoc, const CXXScopeSpec &SS,
8525+
SourceLocation TemplateKWLoc,
8526+
const DeclarationNameInfo &NameInfo,
8527+
const TemplateArgumentListInfo *TemplateArgs);
85358528

85368529
/// The main callback when the parser finds something like
85378530
/// expression . [nested-name-specifier] identifier
@@ -8587,15 +8580,14 @@ class Sema final : public SemaBase {
85878580
ExprResult BuildMemberReferenceExpr(
85888581
Expr *Base, QualType BaseType, SourceLocation OpLoc, bool IsArrow,
85898582
CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
8590-
NamedDecl *FirstQualifierInScope, const DeclarationNameInfo &NameInfo,
8583+
const DeclarationNameInfo &NameInfo,
85918584
const TemplateArgumentListInfo *TemplateArgs, const Scope *S,
85928585
ActOnMemberAccessExtraArgs *ExtraArgs = nullptr);
85938586

85948587
ExprResult
85958588
BuildMemberReferenceExpr(Expr *Base, QualType BaseType, SourceLocation OpLoc,
85968589
bool IsArrow, const CXXScopeSpec &SS,
8597-
SourceLocation TemplateKWLoc,
8598-
NamedDecl *FirstQualifierInScope, LookupResult &R,
8590+
SourceLocation TemplateKWLoc, LookupResult &R,
85998591
const TemplateArgumentListInfo *TemplateArgs,
86008592
const Scope *S, bool SuppressQualifierCheck = false,
86018593
ActOnMemberAccessExtraArgs *ExtraArgs = nullptr);
@@ -11083,15 +11075,14 @@ class Sema final : public SemaBase {
1108311075
QualType ObjectType, bool EnteringContext,
1108411076
RequiredTemplateKind RequiredTemplate = SourceLocation(),
1108511077
AssumedTemplateKind *ATK = nullptr,
11086-
bool AllowTypoCorrection = true);
11078+
bool AllowTypoCorrection = true, bool MayBeNNS = false);
1108711079

11088-
TemplateNameKind isTemplateName(Scope *S, CXXScopeSpec &SS,
11089-
bool hasTemplateKeyword,
11090-
const UnqualifiedId &Name,
11091-
ParsedType ObjectType, bool EnteringContext,
11092-
TemplateTy &Template,
11093-
bool &MemberOfUnknownSpecialization,
11094-
bool Disambiguation = false);
11080+
TemplateNameKind
11081+
isTemplateName(Scope *S, CXXScopeSpec &SS, bool hasTemplateKeyword,
11082+
const UnqualifiedId &Name, ParsedType ObjectType,
11083+
bool EnteringContext, TemplateTy &Template,
11084+
bool &MemberOfUnknownSpecialization,
11085+
bool Disambiguation = false, bool MayBeNNS = false);
1109511086

1109611087
/// Try to resolve an undeclared template name as a type template.
1109711088
///
@@ -11426,12 +11417,11 @@ class Sema final : public SemaBase {
1142611417
/// For example, given "x.MetaFun::template apply", the scope specifier
1142711418
/// \p SS will be "MetaFun::", \p TemplateKWLoc contains the location
1142811419
/// of the "template" keyword, and "apply" is the \p Name.
11429-
TemplateNameKind ActOnTemplateName(Scope *S, CXXScopeSpec &SS,
11430-
SourceLocation TemplateKWLoc,
11431-
const UnqualifiedId &Name,
11432-
ParsedType ObjectType,
11433-
bool EnteringContext, TemplateTy &Template,
11434-
bool AllowInjectedClassName = false);
11420+
TemplateNameKind
11421+
ActOnTemplateName(Scope *S, CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
11422+
const UnqualifiedId &Name, ParsedType ObjectType,
11423+
bool EnteringContext, TemplateTy &Template,
11424+
bool AllowInjectedClassName = false, bool MayBeNNS = false);
1143511425

1143611426
DeclResult ActOnClassTemplateSpecialization(
1143711427
Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc,

0 commit comments

Comments
 (0)