[libcxx-commits] [libcxx] 59e56ee - Revert "Reapply "[Clang] Implement resolution for CWG1835 (#92957)" (#98547)"
Haojian Wu via libcxx-commits
libcxx-commits at lists.llvm.org
Mon Jul 15 04:22:56 PDT 2024
Author: Haojian Wu
Date: 2024-07-15T13:22:40+02:00
New Revision: 59e56eeb1d9c0d25a522ae09f501a350981a31de
URL: https://github.com/llvm/llvm-project/commit/59e56eeb1d9c0d25a522ae09f501a350981a31de
DIFF: https://github.com/llvm/llvm-project/commit/59e56eeb1d9c0d25a522ae09f501a350981a31de.diff
LOG: Revert "Reapply "[Clang] Implement resolution for CWG1835 (#92957)" (#98547)"
This reverts commit ce4aada6e2135e29839f672a6599db628b53295d and a
follow-up patch 8ef26f1289bf069ccc0d6383f2f4c0116a1206c1.
This new warning can not be fully suppressed by the
`-Wno-missing-dependent-template-keyword` flag, this gives developer no
time to do the cleanup in a large codebase, see https://github.com/llvm/llvm-project/pull/98547#issuecomment-2228250884
Added:
Modified:
clang/docs/ReleaseNotes.rst
clang/include/clang/AST/ExprCXX.h
clang/include/clang/AST/Stmt.h
clang/include/clang/AST/UnresolvedSet.h
clang/include/clang/Basic/DiagnosticParseKinds.td
clang/include/clang/Parse/Parser.h
clang/include/clang/Sema/DeclSpec.h
clang/include/clang/Sema/Lookup.h
clang/include/clang/Sema/Sema.h
clang/lib/AST/ASTImporter.cpp
clang/lib/AST/ExprCXX.cpp
clang/lib/AST/ItaniumMangle.cpp
clang/lib/Parse/ParseExpr.cpp
clang/lib/Parse/ParseExprCXX.cpp
clang/lib/Sema/SemaCXXScopeSpec.cpp
clang/lib/Sema/SemaCoroutine.cpp
clang/lib/Sema/SemaDeclCXX.cpp
clang/lib/Sema/SemaExpr.cpp
clang/lib/Sema/SemaExprMember.cpp
clang/lib/Sema/SemaOverload.cpp
clang/lib/Sema/SemaStmtAsm.cpp
clang/lib/Sema/SemaTemplate.cpp
clang/lib/Sema/SemaTemplateInstantiate.cpp
clang/lib/Sema/TreeTransform.h
clang/lib/Serialization/ASTReaderStmt.cpp
clang/lib/Serialization/ASTWriterStmt.cpp
clang/test/CXX/basic/basic.lookup/basic.lookup.classref/p1-cxx11.cpp
clang/test/CXX/basic/basic.lookup/basic.lookup.classref/p1.cpp
clang/test/CXX/class.derived/class.member.lookup/p8.cpp
clang/test/CXX/drs/cwg1xx.cpp
clang/test/CXX/temp/temp.res/p3.cpp
clang/test/FixIt/fixit.cpp
clang/test/Misc/warning-flags.c
clang/test/Parser/cxx2a-concepts-requires-expr.cpp
clang/test/SemaCXX/cxx0x-noexcept-expression.cpp
clang/test/SemaCXX/pseudo-destructors.cpp
clang/test/SemaCXX/static-assert-cxx17.cpp
clang/test/SemaTemplate/dependent-base-classes.cpp
clang/test/SemaTemplate/dependent-template-recover.cpp
clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp
clang/test/SemaTemplate/template-id-expr.cpp
clang/test/SemaTemplate/typename-specifier-3.cpp
libcxx/include/regex
llvm/include/llvm/ADT/ArrayRef.h
Removed:
clang/test/CXX/basic/basic.lookup/basic.lookup.qual/basic.lookup.qual.general/p3-example3.cpp
clang/test/CXX/basic/basic.lookup/basic.lookup.qual/basic.lookup.qual.general/p3.cpp
clang/test/CXX/temp/temp.names/p3-23.cpp
################################################################################
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 83a1353f3c400..882277efb2114 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -313,10 +313,6 @@ Resolutions to C++ Defect Reports
- Clang now considers ``noexcept(typeid(expr))`` more carefully, instead of always assuming that ``std::bad_typeid`` can be thrown.
(`CWG2191: Incorrect result for noexcept(typeid(v)) <https://cplusplus.github.io/CWG/issues/2191.html>`_).
-- Clang now correctly implements lookup for the terminal name of a member-qualified nested-name-specifier.
- (`CWG1835: Dependent member lookup before < <https://cplusplus.github.io/CWG/issues/1835.html>`_).
- The warning can be disabled via `-Wno-missing-dependent-template-keyword`.
-
C Language Changes
------------------
diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h
index edaea6fe27cc3..c2feac525c1ea 100644
--- a/clang/include/clang/AST/ExprCXX.h
+++ b/clang/include/clang/AST/ExprCXX.h
@@ -3676,9 +3676,9 @@ class CXXUnresolvedConstructExpr final
/// an implicit access if a qualifier is provided.
class CXXDependentScopeMemberExpr final
: public Expr,
- private llvm::TrailingObjects<
- CXXDependentScopeMemberExpr, NestedNameSpecifierLoc, DeclAccessPair,
- ASTTemplateKWAndArgsInfo, TemplateArgumentLoc> {
+ private llvm::TrailingObjects<CXXDependentScopeMemberExpr,
+ ASTTemplateKWAndArgsInfo,
+ TemplateArgumentLoc, NamedDecl *> {
friend class ASTStmtReader;
friend class ASTStmtWriter;
friend TrailingObjects;
@@ -3691,15 +3691,17 @@ class CXXDependentScopeMemberExpr final
/// implicit accesses.
QualType BaseType;
+ /// The nested-name-specifier that precedes the member name, if any.
+ /// FIXME: This could be in principle store as a trailing object.
+ /// However the performance impact of doing so should be investigated first.
+ NestedNameSpecifierLoc QualifierLoc;
+
/// The member to which this member expression refers, which
/// can be name, overloaded operator, or destructor.
///
/// FIXME: could also be a template-id
DeclarationNameInfo MemberNameInfo;
- /// The location of the '->' or '.' operator.
- SourceLocation OperatorLoc;
-
// CXXDependentScopeMemberExpr is followed by several trailing objects,
// some of which optional. They are in order:
//
@@ -3719,16 +3721,8 @@ class CXXDependentScopeMemberExpr final
return CXXDependentScopeMemberExprBits.HasTemplateKWAndArgsInfo;
}
- unsigned getNumUnqualifiedLookups() const {
- return CXXDependentScopeMemberExprBits.NumUnqualifiedLookups;
- }
-
- unsigned numTrailingObjects(OverloadToken<NestedNameSpecifierLoc>) const {
- return hasQualifier();
- }
-
- unsigned numTrailingObjects(OverloadToken<DeclAccessPair>) const {
- return getNumUnqualifiedLookups();
+ bool hasFirstQualifierFoundInScope() const {
+ return CXXDependentScopeMemberExprBits.HasFirstQualifierFoundInScope;
}
unsigned numTrailingObjects(OverloadToken<ASTTemplateKWAndArgsInfo>) const {
@@ -3739,32 +3733,33 @@ class CXXDependentScopeMemberExpr final
return getNumTemplateArgs();
}
+ unsigned numTrailingObjects(OverloadToken<NamedDecl *>) const {
+ return hasFirstQualifierFoundInScope();
+ }
+
CXXDependentScopeMemberExpr(const ASTContext &Ctx, Expr *Base,
QualType BaseType, bool IsArrow,
SourceLocation OperatorLoc,
NestedNameSpecifierLoc QualifierLoc,
SourceLocation TemplateKWLoc,
- ArrayRef<DeclAccessPair> UnqualifiedLookups,
+ NamedDecl *FirstQualifierFoundInScope,
DeclarationNameInfo MemberNameInfo,
const TemplateArgumentListInfo *TemplateArgs);
- CXXDependentScopeMemberExpr(EmptyShell Empty, bool HasQualifier,
- unsigned NumUnqualifiedLookups,
- bool HasTemplateKWAndArgsInfo);
+ CXXDependentScopeMemberExpr(EmptyShell Empty, bool HasTemplateKWAndArgsInfo,
+ bool HasFirstQualifierFoundInScope);
public:
static CXXDependentScopeMemberExpr *
Create(const ASTContext &Ctx, Expr *Base, QualType BaseType, bool IsArrow,
SourceLocation OperatorLoc, NestedNameSpecifierLoc QualifierLoc,
- SourceLocation TemplateKWLoc,
- ArrayRef<DeclAccessPair> UnqualifiedLookups,
+ SourceLocation TemplateKWLoc, NamedDecl *FirstQualifierFoundInScope,
DeclarationNameInfo MemberNameInfo,
const TemplateArgumentListInfo *TemplateArgs);
static CXXDependentScopeMemberExpr *
- CreateEmpty(const ASTContext &Ctx, bool HasQualifier,
- unsigned NumUnqualifiedLookups, bool HasTemplateKWAndArgsInfo,
- unsigned NumTemplateArgs);
+ CreateEmpty(const ASTContext &Ctx, bool HasTemplateKWAndArgsInfo,
+ unsigned NumTemplateArgs, bool HasFirstQualifierFoundInScope);
/// True if this is an implicit access, i.e. one in which the
/// member being accessed was not written in the source. The source
@@ -3789,35 +3784,34 @@ class CXXDependentScopeMemberExpr final
bool isArrow() const { return CXXDependentScopeMemberExprBits.IsArrow; }
/// Retrieve the location of the '->' or '.' operator.
- SourceLocation getOperatorLoc() const { return OperatorLoc; }
-
- /// Determines whether this member expression had a nested-name-specifier
- /// prior to the name of the member, e.g., x->Base::foo.
- bool hasQualifier() const {
- return CXXDependentScopeMemberExprBits.HasQualifier;
- }
-
- /// If the member name was qualified, retrieves the nested-name-specifier
- /// that precedes the member name, with source-location information.
- NestedNameSpecifierLoc getQualifierLoc() const {
- if (!hasQualifier())
- return NestedNameSpecifierLoc();
- return *getTrailingObjects<NestedNameSpecifierLoc>();
+ SourceLocation getOperatorLoc() const {
+ return CXXDependentScopeMemberExprBits.OperatorLoc;
}
- /// If the member name was qualified, retrieves the
- /// nested-name-specifier that precedes the member name. Otherwise, returns
- /// NULL.
+ /// Retrieve the nested-name-specifier that qualifies the member name.
NestedNameSpecifier *getQualifier() const {
- return getQualifierLoc().getNestedNameSpecifier();
+ return QualifierLoc.getNestedNameSpecifier();
}
- /// Retrieve the declarations found by unqualified lookup for the first
- /// component name of the nested-name-specifier, if any.
- ArrayRef<DeclAccessPair> unqualified_lookups() const {
- if (!getNumUnqualifiedLookups())
- return std::nullopt;
- return {getTrailingObjects<DeclAccessPair>(), getNumUnqualifiedLookups()};
+ /// Retrieve the nested-name-specifier that qualifies the member
+ /// name, with source location information.
+ NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; }
+
+ /// Retrieve the first part of the nested-name-specifier that was
+ /// found in the scope of the member access expression when the member access
+ /// was initially parsed.
+ ///
+ /// This function only returns a useful result when member access expression
+ /// uses a qualified member name, e.g., "x.Base::f". Here, the declaration
+ /// returned by this function describes what was found by unqualified name
+ /// lookup for the identifier "Base" within the scope of the member access
+ /// expression itself. At template instantiation time, this information is
+ /// combined with the results of name lookup into the type of the object
+ /// expression itself (the class type of x).
+ NamedDecl *getFirstQualifierFoundInScope() const {
+ if (!hasFirstQualifierFoundInScope())
+ return nullptr;
+ return *getTrailingObjects<NamedDecl *>();
}
/// Retrieve the name of the member that this expression refers to.
diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h
index 257a61c97c9c6..9cd7a364cd3f1 100644
--- a/clang/include/clang/AST/Stmt.h
+++ b/clang/include/clang/AST/Stmt.h
@@ -1020,19 +1020,18 @@ class alignas(void *) Stmt {
LLVM_PREFERRED_TYPE(bool)
unsigned IsArrow : 1;
- /// True if this member expression used a nested-name-specifier to
- /// refer to the member, e.g., "x->Base::f".
- LLVM_PREFERRED_TYPE(bool)
- unsigned HasQualifier : 1;
-
/// Whether this member expression has info for explicit template
/// keyword and arguments.
LLVM_PREFERRED_TYPE(bool)
unsigned HasTemplateKWAndArgsInfo : 1;
- /// Number of declarations found by unqualified lookup for the
- /// first component name of the nested-name-specifier.
- unsigned NumUnqualifiedLookups;
+ /// See getFirstQualifierFoundInScope() and the comment listing
+ /// the trailing objects.
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned HasFirstQualifierFoundInScope : 1;
+
+ /// The location of the '->' or '.' operator.
+ SourceLocation OperatorLoc;
};
class OverloadExprBitfields {
diff --git a/clang/include/clang/AST/UnresolvedSet.h b/clang/include/clang/AST/UnresolvedSet.h
index ef44499ce5926..1369725ab4e96 100644
--- a/clang/include/clang/AST/UnresolvedSet.h
+++ b/clang/include/clang/AST/UnresolvedSet.h
@@ -97,10 +97,6 @@ class UnresolvedSetImpl {
decls().push_back(DeclAccessPair::make(D, AS));
}
- void addAllDecls(ArrayRef<DeclAccessPair> Other) {
- append(iterator(Other.begin()), iterator(Other.end()));
- }
-
/// Replaces the given declaration with the new one, once.
///
/// \return true if the set changed
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td
index e00cd47411cb3..12aab09f28556 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -895,9 +895,10 @@ def missing_template_arg_list_after_template_kw : Extension<
"keyword">, InGroup<DiagGroup<"missing-template-arg-list-after-template-kw">>,
DefaultError;
-def ext_missing_dependent_template_keyword : ExtWarn<
- "use 'template' keyword to treat '%0' as a dependent template name">,
- InGroup<DiagGroup<"missing-dependent-template-keyword">>;
+def err_missing_dependent_template_keyword : Error<
+ "use 'template' keyword to treat '%0' as a dependent template name">;
+def warn_missing_dependent_template_keyword : ExtWarn<
+ "use 'template' keyword to treat '%0' as a dependent template name">;
def ext_extern_template : Extension<
"extern templates are a C++11 extension">, InGroup<CXX11>;
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index bb3f08aef0378..126fea0aef2a7 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -3372,11 +3372,15 @@ class Parser : public CodeCompletionHandler {
BaseResult ParseBaseSpecifier(Decl *ClassDecl);
AccessSpecifier getAccessSpecifierIfPresent() const;
- bool ParseUnqualifiedIdTemplateId(
- CXXScopeSpec &SS, ParsedType ObjectType, bool ObjectHadErrors,
- SourceLocation TemplateKWLoc, SourceLocation TildeLoc,
- IdentifierInfo *Name, SourceLocation NameLoc, bool EnteringContext,
- UnqualifiedId &Id, bool AssumeTemplateId);
+ bool ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
+ ParsedType ObjectType,
+ bool ObjectHadErrors,
+ SourceLocation TemplateKWLoc,
+ IdentifierInfo *Name,
+ SourceLocation NameLoc,
+ bool EnteringContext,
+ UnqualifiedId &Id,
+ bool AssumeTemplateId);
bool ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
ParsedType ObjectType,
UnqualifiedId &Result);
diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h
index 9c22c35535ede..425b6e2a0b30c 100644
--- a/clang/include/clang/Sema/DeclSpec.h
+++ b/clang/include/clang/Sema/DeclSpec.h
@@ -75,7 +75,6 @@ class CXXScopeSpec {
SourceRange Range;
NestedNameSpecifierLocBuilder Builder;
ArrayRef<TemplateParameterList *> TemplateParamLists;
- ArrayRef<DeclAccessPair> UnqualifiedLookups;
public:
SourceRange getRange() const { return Range; }
@@ -92,13 +91,6 @@ class CXXScopeSpec {
return TemplateParamLists;
}
- void setUnqualifiedLookups(ArrayRef<DeclAccessPair> Found) {
- UnqualifiedLookups = Found;
- }
- ArrayRef<DeclAccessPair> getUnqualifiedLookups() const {
- return UnqualifiedLookups;
- }
-
/// Retrieve the representation of the nested-name-specifier.
NestedNameSpecifier *getScopeRep() const {
return Builder.getRepresentation();
diff --git a/clang/include/clang/Sema/Lookup.h b/clang/include/clang/Sema/Lookup.h
index 6b765ef3c980f..b0a08a05ac6a0 100644
--- a/clang/include/clang/Sema/Lookup.h
+++ b/clang/include/clang/Sema/Lookup.h
@@ -483,15 +483,11 @@ class LookupResult {
ResultKind = Found;
}
- void addAllDecls(ArrayRef<DeclAccessPair> Other) {
- Decls.addAllDecls(Other);
- ResultKind = Found;
- }
-
/// Add all the declarations from another set of lookup
/// results.
void addAllDecls(const LookupResult &Other) {
- addAllDecls(Other.Decls.pairs());
+ Decls.append(Other.Decls.begin(), Other.Decls.end());
+ ResultKind = Found;
}
/// Determine whether no result was found because we could not
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index a0821d5298bc4..48dff1b76cc57 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -2803,8 +2803,7 @@ class Sema final : public SemaBase {
/// (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 LookupFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS,
- UnresolvedSetImpl &R);
+ NamedDecl *FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS);
/// Keeps information about an identifier in a nested-name-spec.
///
@@ -2844,6 +2843,9 @@ class Sema final : public SemaBase {
/// \param EnteringContext If true, enter the context specified by the
/// nested-name-specifier.
/// \param SS Optional nested name specifier preceding the identifier.
+ /// \param ScopeLookupResult Provides the result of name lookup within the
+ /// scope of the nested-name-specifier that was computed at template
+ /// definition time.
/// \param ErrorRecoveryLookup Specifies if the method is called to improve
/// error recovery and what kind of recovery is performed.
/// \param IsCorrectedToColon If not null, suggestion of replace '::' -> ':'
@@ -2852,6 +2854,11 @@ class Sema final : public SemaBase {
/// not '::'.
/// \param OnlyNamespace If true, only considers namespaces in lookup.
///
+ /// This routine
diff ers only slightly from ActOnCXXNestedNameSpecifier, in
+ /// that it contains an extra parameter \p ScopeLookupResult, which provides
+ /// the result of name lookup within the scope of the nested-name-specifier
+ /// that was computed at template definition time.
+ ///
/// If ErrorRecoveryLookup is true, then this call is used to improve error
/// recovery. This means that it should not emit diagnostics, it should
/// just return true on failure. It also means it should only return a valid
@@ -2860,6 +2867,7 @@ class Sema final : public SemaBase {
/// specifier.
bool BuildCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo,
bool EnteringContext, CXXScopeSpec &SS,
+ NamedDecl *ScopeLookupResult,
bool ErrorRecoveryLookup,
bool *IsCorrectedToColon = nullptr,
bool OnlyNamespace = false);
@@ -8559,12 +8567,11 @@ class Sema final : public SemaBase {
const TemplateArgumentListInfo *TemplateArgs,
bool IsDefiniteInstance, const Scope *S);
- ExprResult
- ActOnDependentMemberExpr(Expr *Base, QualType BaseType, bool IsArrow,
- SourceLocation OpLoc, const CXXScopeSpec &SS,
- SourceLocation TemplateKWLoc,
- const DeclarationNameInfo &NameInfo,
- const TemplateArgumentListInfo *TemplateArgs);
+ ExprResult ActOnDependentMemberExpr(
+ Expr *Base, QualType BaseType, bool IsArrow, SourceLocation OpLoc,
+ const CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
+ NamedDecl *FirstQualifierInScope, const DeclarationNameInfo &NameInfo,
+ const TemplateArgumentListInfo *TemplateArgs);
/// The main callback when the parser finds something like
/// expression . [nested-name-specifier] identifier
@@ -8620,14 +8627,15 @@ class Sema final : public SemaBase {
ExprResult BuildMemberReferenceExpr(
Expr *Base, QualType BaseType, SourceLocation OpLoc, bool IsArrow,
CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
- const DeclarationNameInfo &NameInfo,
+ NamedDecl *FirstQualifierInScope, const DeclarationNameInfo &NameInfo,
const TemplateArgumentListInfo *TemplateArgs, const Scope *S,
ActOnMemberAccessExtraArgs *ExtraArgs = nullptr);
ExprResult
BuildMemberReferenceExpr(Expr *Base, QualType BaseType, SourceLocation OpLoc,
bool IsArrow, const CXXScopeSpec &SS,
- SourceLocation TemplateKWLoc, LookupResult &R,
+ SourceLocation TemplateKWLoc,
+ NamedDecl *FirstQualifierInScope, LookupResult &R,
const TemplateArgumentListInfo *TemplateArgs,
const Scope *S, bool SuppressQualifierCheck = false,
ActOnMemberAccessExtraArgs *ExtraArgs = nullptr);
@@ -11115,14 +11123,15 @@ class Sema final : public SemaBase {
QualType ObjectType, bool EnteringContext,
RequiredTemplateKind RequiredTemplate = SourceLocation(),
AssumedTemplateKind *ATK = nullptr,
- bool AllowTypoCorrection = true, bool MayBeNNS = false);
+ bool AllowTypoCorrection = true);
- TemplateNameKind
- isTemplateName(Scope *S, CXXScopeSpec &SS, bool hasTemplateKeyword,
- const UnqualifiedId &Name, ParsedType ObjectType,
- bool EnteringContext, TemplateTy &Template,
- bool &MemberOfUnknownSpecialization,
- bool Disambiguation = false, bool MayBeNNS = false);
+ TemplateNameKind isTemplateName(Scope *S, CXXScopeSpec &SS,
+ bool hasTemplateKeyword,
+ const UnqualifiedId &Name,
+ ParsedType ObjectType, bool EnteringContext,
+ TemplateTy &Template,
+ bool &MemberOfUnknownSpecialization,
+ bool Disambiguation = false);
/// Try to resolve an undeclared template name as a type template.
///
@@ -11455,11 +11464,12 @@ class Sema final : public SemaBase {
/// For example, given "x.MetaFun::template apply", the scope specifier
/// \p SS will be "MetaFun::", \p TemplateKWLoc contains the location
/// of the "template" keyword, and "apply" is the \p Name.
- TemplateNameKind
- ActOnTemplateName(Scope *S, CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
- const UnqualifiedId &Name, ParsedType ObjectType,
- bool EnteringContext, TemplateTy &Template,
- bool AllowInjectedClassName = false, bool MayBeNNS = false);
+ TemplateNameKind ActOnTemplateName(Scope *S, CXXScopeSpec &SS,
+ SourceLocation TemplateKWLoc,
+ const UnqualifiedId &Name,
+ ParsedType ObjectType,
+ bool EnteringContext, TemplateTy &Template,
+ bool AllowInjectedClassName = false);
DeclResult ActOnClassTemplateSpecialization(
Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc,
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index 9bb035c07b8ae..4e1b3a5a94de7 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -8439,14 +8439,8 @@ ExpectedStmt ASTNodeImporter::VisitCXXDependentScopeMemberExpr(
auto ToOperatorLoc = importChecked(Err, E->getOperatorLoc());
auto ToQualifierLoc = importChecked(Err, E->getQualifierLoc());
auto ToTemplateKeywordLoc = importChecked(Err, E->getTemplateKeywordLoc());
-
- UnresolvedSet<8> ToUnqualifiedLookups;
- for (auto D : E->unqualified_lookups())
- if (auto ToDOrErr = import(D.getDecl()))
- ToUnqualifiedLookups.addDecl(*ToDOrErr);
- else
- return ToDOrErr.takeError();
-
+ auto ToFirstQualifierFoundInScope =
+ importChecked(Err, E->getFirstQualifierFoundInScope());
if (Err)
return std::move(Err);
@@ -8480,7 +8474,7 @@ ExpectedStmt ASTNodeImporter::VisitCXXDependentScopeMemberExpr(
return CXXDependentScopeMemberExpr::Create(
Importer.getToContext(), ToBase, ToType, E->isArrow(), ToOperatorLoc,
- ToQualifierLoc, ToTemplateKeywordLoc, ToUnqualifiedLookups.pairs(),
+ ToQualifierLoc, ToTemplateKeywordLoc, ToFirstQualifierFoundInScope,
ToMemberNameInfo, ResInfo);
}
diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp
index 9d2883a8debb7..8d2a1b5611ccc 100644
--- a/clang/lib/AST/ExprCXX.cpp
+++ b/clang/lib/AST/ExprCXX.cpp
@@ -1489,27 +1489,19 @@ SourceLocation CXXUnresolvedConstructExpr::getBeginLoc() const {
CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(
const ASTContext &Ctx, Expr *Base, QualType BaseType, bool IsArrow,
SourceLocation OperatorLoc, NestedNameSpecifierLoc QualifierLoc,
- SourceLocation TemplateKWLoc, ArrayRef<DeclAccessPair> UnqualifiedLookups,
+ SourceLocation TemplateKWLoc, NamedDecl *FirstQualifierFoundInScope,
DeclarationNameInfo MemberNameInfo,
const TemplateArgumentListInfo *TemplateArgs)
: Expr(CXXDependentScopeMemberExprClass, Ctx.DependentTy, VK_LValue,
OK_Ordinary),
- Base(Base), BaseType(BaseType), MemberNameInfo(MemberNameInfo),
- OperatorLoc(OperatorLoc) {
+ Base(Base), BaseType(BaseType), QualifierLoc(QualifierLoc),
+ MemberNameInfo(MemberNameInfo) {
CXXDependentScopeMemberExprBits.IsArrow = IsArrow;
- CXXDependentScopeMemberExprBits.HasQualifier = QualifierLoc.hasQualifier();
- CXXDependentScopeMemberExprBits.NumUnqualifiedLookups =
- UnqualifiedLookups.size();
CXXDependentScopeMemberExprBits.HasTemplateKWAndArgsInfo =
(TemplateArgs != nullptr) || TemplateKWLoc.isValid();
-
- if (hasQualifier())
- new (getTrailingObjects<NestedNameSpecifierLoc>())
- NestedNameSpecifierLoc(QualifierLoc);
-
- std::uninitialized_copy_n(UnqualifiedLookups.data(),
- UnqualifiedLookups.size(),
- getTrailingObjects<DeclAccessPair>());
+ CXXDependentScopeMemberExprBits.HasFirstQualifierFoundInScope =
+ FirstQualifierFoundInScope != nullptr;
+ CXXDependentScopeMemberExprBits.OperatorLoc = OperatorLoc;
if (TemplateArgs) {
auto Deps = TemplateArgumentDependence::None;
@@ -1521,59 +1513,54 @@ CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(
TemplateKWLoc);
}
+ if (hasFirstQualifierFoundInScope())
+ *getTrailingObjects<NamedDecl *>() = FirstQualifierFoundInScope;
setDependence(computeDependence(this));
}
CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(
- EmptyShell Empty, bool HasQualifier, unsigned NumUnqualifiedLookups,
- bool HasTemplateKWAndArgsInfo)
+ EmptyShell Empty, bool HasTemplateKWAndArgsInfo,
+ bool HasFirstQualifierFoundInScope)
: 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, ArrayRef<DeclAccessPair> UnqualifiedLookups,
+ SourceLocation TemplateKWLoc, NamedDecl *FirstQualifierFoundInScope,
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;
- unsigned Size =
- totalSizeToAlloc<NestedNameSpecifierLoc, DeclAccessPair,
- ASTTemplateKWAndArgsInfo, TemplateArgumentLoc>(
- HasQualifier, NumUnqualifiedLookups, HasTemplateKWAndArgsInfo,
- NumTemplateArgs);
+ bool HasFirstQualifierFoundInScope = FirstQualifierFoundInScope != nullptr;
+
+ unsigned Size = totalSizeToAlloc<ASTTemplateKWAndArgsInfo,
+ TemplateArgumentLoc, NamedDecl *>(
+ HasTemplateKWAndArgsInfo, NumTemplateArgs, HasFirstQualifierFoundInScope);
void *Mem = Ctx.Allocate(Size, alignof(CXXDependentScopeMemberExpr));
return new (Mem) CXXDependentScopeMemberExpr(
Ctx, Base, BaseType, IsArrow, OperatorLoc, QualifierLoc, TemplateKWLoc,
- UnqualifiedLookups, MemberNameInfo, TemplateArgs);
+ FirstQualifierFoundInScope, MemberNameInfo, TemplateArgs);
}
CXXDependentScopeMemberExpr *CXXDependentScopeMemberExpr::CreateEmpty(
- const ASTContext &Ctx, bool HasQualifier, unsigned NumUnqualifiedLookups,
- bool HasTemplateKWAndArgsInfo, unsigned NumTemplateArgs) {
- assert(!NumTemplateArgs || HasTemplateKWAndArgsInfo);
- assert(!NumUnqualifiedLookups || HasQualifier);
+ const ASTContext &Ctx, bool HasTemplateKWAndArgsInfo,
+ unsigned NumTemplateArgs, bool HasFirstQualifierFoundInScope) {
+ assert(NumTemplateArgs == 0 || HasTemplateKWAndArgsInfo);
- unsigned Size =
- totalSizeToAlloc<NestedNameSpecifierLoc, DeclAccessPair,
- ASTTemplateKWAndArgsInfo, TemplateArgumentLoc>(
- HasQualifier, NumUnqualifiedLookups, HasTemplateKWAndArgsInfo,
- NumTemplateArgs);
+ unsigned Size = totalSizeToAlloc<ASTTemplateKWAndArgsInfo,
+ TemplateArgumentLoc, NamedDecl *>(
+ HasTemplateKWAndArgsInfo, NumTemplateArgs, HasFirstQualifierFoundInScope);
void *Mem = Ctx.Allocate(Size, alignof(CXXDependentScopeMemberExpr));
- return new (Mem) CXXDependentScopeMemberExpr(EmptyShell(), HasQualifier,
- NumUnqualifiedLookups,
- HasTemplateKWAndArgsInfo);
+ return new (Mem) CXXDependentScopeMemberExpr(
+ EmptyShell(), HasTemplateKWAndArgsInfo, HasFirstQualifierFoundInScope);
}
CXXThisExpr *CXXThisExpr::Create(const ASTContext &Ctx, SourceLocation L,
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index f14c4762bee6f..5444dcf027fe2 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -594,10 +594,11 @@ class CXXNameMangler {
void mangleMemberExprBase(const Expr *base, bool isArrow);
void mangleMemberExpr(const Expr *base, bool isArrow,
NestedNameSpecifier *qualifier,
- ArrayRef<DeclAccessPair> UnqualifiedLookups,
+ NamedDecl *firstQualifierLookup,
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,
@@ -4495,11 +4496,14 @@ void CXXNameMangler::mangleMemberExprBase(const Expr *Base, bool IsArrow) {
}
/// Mangles a member expression.
-void CXXNameMangler::mangleMemberExpr(
- const Expr *base, bool isArrow, NestedNameSpecifier *qualifier,
- ArrayRef<DeclAccessPair> UnqualifiedLookups, DeclarationName member,
- const TemplateArgumentLoc *TemplateArgs, unsigned NumTemplateArgs,
- unsigned arity) {
+void CXXNameMangler::mangleMemberExpr(const Expr *base,
+ bool isArrow,
+ NestedNameSpecifier *qualifier,
+ NamedDecl *firstQualifierLookup,
+ DeclarationName member,
+ const TemplateArgumentLoc *TemplateArgs,
+ unsigned NumTemplateArgs,
+ unsigned arity) {
// <expression> ::= dt <expression> <unresolved-name>
// ::= pt <expression> <unresolved-name>
if (base)
@@ -4981,9 +4985,11 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity,
case Expr::MemberExprClass: {
NotPrimaryExpr();
const MemberExpr *ME = cast<MemberExpr>(E);
- mangleMemberExpr(ME->getBase(), ME->isArrow(), ME->getQualifier(),
- std::nullopt, ME->getMemberDecl()->getDeclName(),
- ME->getTemplateArgs(), ME->getNumTemplateArgs(), Arity);
+ mangleMemberExpr(ME->getBase(), ME->isArrow(),
+ ME->getQualifier(), nullptr,
+ ME->getMemberDecl()->getDeclName(),
+ ME->getTemplateArgs(), ME->getNumTemplateArgs(),
+ Arity);
break;
}
@@ -4991,9 +4997,10 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity,
NotPrimaryExpr();
const UnresolvedMemberExpr *ME = cast<UnresolvedMemberExpr>(E);
mangleMemberExpr(ME->isImplicitAccess() ? nullptr : ME->getBase(),
- ME->isArrow(), ME->getQualifier(), std::nullopt,
- ME->getMemberName(), ME->getTemplateArgs(),
- ME->getNumTemplateArgs(), Arity);
+ ME->isArrow(), ME->getQualifier(), nullptr,
+ ME->getMemberName(),
+ ME->getTemplateArgs(), ME->getNumTemplateArgs(),
+ Arity);
break;
}
@@ -5003,8 +5010,10 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity,
= cast<CXXDependentScopeMemberExpr>(E);
mangleMemberExpr(ME->isImplicitAccess() ? nullptr : ME->getBase(),
ME->isArrow(), ME->getQualifier(),
- ME->unqualified_lookups(), ME->getMember(),
- ME->getTemplateArgs(), ME->getNumTemplateArgs(), Arity);
+ ME->getFirstQualifierFoundInScope(),
+ ME->getMember(),
+ ME->getTemplateArgs(), ME->getNumTemplateArgs(),
+ Arity);
break;
}
diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp
index 310a38b2cd786..259bfa1d77cdb 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/lib/Parse/ParseExpr.cpp
@@ -2348,9 +2348,10 @@ 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 17be090dea3fd..1d364f77a8146 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -100,8 +100,7 @@ void Parser::CheckForTemplateAndDigraph(Token &Next, ParsedType ObjectType,
bool MemberOfUnknownSpecialization;
if (!Actions.isTemplateName(getCurScope(), SS, /*hasTemplateKeyword=*/false,
TemplateName, ObjectType, EnteringContext,
- Template, MemberOfUnknownSpecialization,
- /*Disambiguation=*/false, /*MayBeNNS=*/true))
+ Template, MemberOfUnknownSpecialization))
return;
FixDigraph(*this, PP, Next, SecondToken, tok::unknown,
@@ -354,8 +353,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(
TemplateTy Template;
TemplateNameKind TNK = Actions.ActOnTemplateName(
getCurScope(), SS, TemplateKWLoc, TemplateName, ObjectType,
- EnteringContext, Template, /*AllowInjectedClassName*/ true,
- /*MayBeNNS=*/true);
+ EnteringContext, Template, /*AllowInjectedClassName*/ true);
if (AnnotateTemplateIdToken(Template, TNK, SS, TemplateKWLoc,
TemplateName, false))
return true;
@@ -407,6 +405,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(
: TemplateId->TemplateNameLoc;
SS.SetInvalid(SourceRange(StartLoc, CCLoc));
}
+
continue;
}
@@ -529,19 +528,18 @@ 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,
- /*Disambiguation=*/false,
- /*MayBeNNS=*/true)) {
+ if (TemplateNameKind TNK = Actions.isTemplateName(getCurScope(), SS,
+ /*hasTemplateKeyword=*/false,
+ TemplateName,
+ ObjectType,
+ EnteringContext,
+ Template,
+ MemberOfUnknownSpecialization)) {
// 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 ||
- (!HasScopeSpecifier && ObjectType)) &&
+ if (!IsTypename && TNK == TNK_Undeclared_template &&
isTemplateArgumentList(1) == TPResult::False)
break;
@@ -568,7 +566,11 @@ 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.
- Diag(Tok.getLocation(), diag::ext_missing_dependent_template_keyword)
+ unsigned DiagID = diag::err_missing_dependent_template_keyword;
+ if (getLangOpts().MicrosoftExt)
+ DiagID = diag::warn_missing_dependent_template_keyword;
+
+ Diag(Tok.getLocation(), DiagID)
<< II.getName()
<< FixItHint::CreateInsertion(Tok.getLocation(), "template ");
}
@@ -1918,12 +1920,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(),
- /*TemplateKWLoc=*/SourceLocation(), TildeLoc,
- Name, NameLoc, false, SecondTypeName,
- /*AssumeTemplateId=*/true))
+ // example, so we accept it anyway.
+ if (Tok.is(tok::less) &&
+ ParseUnqualifiedIdTemplateId(
+ SS, ObjectType, Base && Base->containsErrors(), SourceLocation(),
+ Name, NameLoc, false, SecondTypeName,
+ /*AssumeTemplateId=*/true))
return ExprError();
return Actions.ActOnPseudoDestructorExpr(getCurScope(), Base, OpLoc, OpKind,
@@ -2530,9 +2532,8 @@ 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, SourceLocation TildeLoc, IdentifierInfo *Name,
- SourceLocation NameLoc, bool EnteringContext, UnqualifiedId &Id,
- bool AssumeTemplateId) {
+ SourceLocation TemplateKWLoc, IdentifierInfo *Name, SourceLocation NameLoc,
+ bool EnteringContext, UnqualifiedId &Id, bool AssumeTemplateId) {
assert(Tok.is(tok::less) && "Expected '<' to finish parsing a template-id");
TemplateTy Template;
@@ -2546,14 +2547,13 @@ 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,
- TildeLoc.isValid());
+ /*AllowInjectedClassName*/ true);
} else {
bool MemberOfUnknownSpecialization;
- TNK = Actions.isTemplateName(
- getCurScope(), SS, TemplateKWLoc.isValid(), Id, ObjectType,
- EnteringContext, Template, MemberOfUnknownSpecialization,
- /*Disambiguation=*/false, TildeLoc.isValid());
+ TNK = Actions.isTemplateName(getCurScope(), SS,
+ TemplateKWLoc.isValid(), Id,
+ ObjectType, EnteringContext, Template,
+ MemberOfUnknownSpecialization);
// 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::ext_missing_dependent_template_keyword)
+ Diag(Id.StartLocation, diag::err_missing_dependent_template_keyword)
<< Name
<< FixItHint::CreateInsertion(Id.StartLocation, "template ");
}
TNK = Actions.ActOnTemplateName(
getCurScope(), SS, TemplateKWLoc, Id, ObjectType, EnteringContext,
- Template, /*AllowInjectedClassName=*/true, TildeLoc.isValid());
+ Template, /*AllowInjectedClassName*/ true);
} else if (TNK == TNK_Non_template) {
return false;
}
@@ -2611,16 +2611,14 @@ bool Parser::ParseUnqualifiedIdTemplateId(
bool MemberOfUnknownSpecialization;
TemplateName.setIdentifier(Name, NameLoc);
if (ObjectType) {
- TNK = Actions.ActOnTemplateName(getCurScope(), SS, TemplateKWLoc,
- TemplateName, ObjectType, EnteringContext,
- Template, /*AllowInjectedClassName=*/true,
- /*MayBeNNS=*/true);
+ TNK = Actions.ActOnTemplateName(
+ getCurScope(), SS, TemplateKWLoc, TemplateName, ObjectType,
+ EnteringContext, Template, /*AllowInjectedClassName*/ true);
} else {
TNK = Actions.isTemplateName(getCurScope(), SS, TemplateKWLoc.isValid(),
- TemplateName, ObjectType, EnteringContext,
- Template, MemberOfUnknownSpecialization,
- /*Disambiguation=*/false,
- /*MayBeNNS=*/true);
+ TemplateName, ObjectType,
+ EnteringContext, Template,
+ MemberOfUnknownSpecialization);
if (TNK == TNK_Non_template && !Id.DestructorName.get()) {
Diag(NameLoc, diag::err_destructor_template_id)
@@ -2682,7 +2680,7 @@ bool Parser::ParseUnqualifiedIdTemplateId(
if (Id.getKind() == UnqualifiedIdKind::IK_ConstructorName)
Id.setConstructorName(Type.get(), NameLoc, RAngleLoc);
else
- Id.setDestructorName(TildeLoc, Type.get(), RAngleLoc);
+ Id.setDestructorName(Id.StartLocation, Type.get(), RAngleLoc);
return false;
}
@@ -3030,9 +3028,8 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, ParsedType ObjectType,
if (Tok.is(tok::less))
return ParseUnqualifiedIdTemplateId(
SS, ObjectType, ObjectHadErrors,
- TemplateKWLoc ? *TemplateKWLoc : SourceLocation(),
- /*TildeLoc=*/SourceLocation(), Id, IdLoc, EnteringContext, Result,
- TemplateSpecified);
+ TemplateKWLoc ? *TemplateKWLoc : SourceLocation(), Id, IdLoc,
+ EnteringContext, Result, TemplateSpecified);
if (TemplateSpecified) {
TemplateNameKind TNK =
@@ -3127,15 +3124,13 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, ParsedType ObjectType,
Tok.is(tok::less))
return ParseUnqualifiedIdTemplateId(
SS, ObjectType, ObjectHadErrors,
- TemplateKWLoc ? *TemplateKWLoc : SourceLocation(),
- /*TildeLoc=*/SourceLocation(), /*Name=*/nullptr,
- /*NameLoc=*/SourceLocation(), EnteringContext, Result,
- TemplateSpecified);
+ TemplateKWLoc ? *TemplateKWLoc : SourceLocation(), nullptr,
+ 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;
@@ -3225,8 +3220,8 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, ParsedType ObjectType,
Result.setDestructorName(TildeLoc, nullptr, ClassNameLoc);
return ParseUnqualifiedIdTemplateId(
SS, ObjectType, ObjectHadErrors,
- TemplateKWLoc ? *TemplateKWLoc : SourceLocation(), TildeLoc,
- ClassName, ClassNameLoc, EnteringContext, Result, TemplateSpecified);
+ TemplateKWLoc ? *TemplateKWLoc : SourceLocation(), 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 dd61bb22e3dfa..5b2d65247e72e 100644
--- a/clang/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp
@@ -356,41 +356,29 @@ bool Sema::isAcceptableNestedNameSpecifier(const NamedDecl *SD,
return false;
}
-/// 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;
+NamedDecl *Sema::FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS) {
+ if (!S || !NNS)
+ return nullptr;
while (NNS->getPrefix())
NNS = NNS->getPrefix();
- // 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);
+ if (NNS->getKind() != NestedNameSpecifier::Identifier)
+ return nullptr;
+
+ LookupResult Found(*this, NNS->getAsIdentifier(), SourceLocation(),
+ LookupNestedNameSpecifierName);
LookupName(Found, S);
+ assert(!Found.isAmbiguous() && "Cannot handle ambiguities here yet");
- if (Found.empty())
- return false;
+ if (!Found.isSingleResult())
+ return nullptr;
- R.addAllDecls(Found.asUnresolvedSet().pairs());
- Found.suppressDiagnostics();
- return true;
+ NamedDecl *Result = Found.getFoundDecl();
+ if (isAcceptableNestedNameSpecifier(Result))
+ return Result;
+
+ return nullptr;
}
namespace {
@@ -419,82 +407,112 @@ class NestedNameSpecifierValidatorCCC final
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);
- // 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;
+ // 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());
}
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;
- // 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();
+ 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;
}
- ObjectTypeSearchedInScope = true;
+ } else if (!isDependent) {
+ // Perform unqualified name lookup in the current scope.
+ LookupName(Found, S);
}
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);
- LookupParsedName(R, S, &SS, ObjectType,
- /*AllowBuiltinCreation=*/false, EnteringContext);
-
+ if (LookupCtx)
+ LookupQualifiedName(R, LookupCtx);
+ else if (S && !isDependent)
+ LookupName(R, S);
if (!R.empty()) {
// Don't diagnose problems with this speculative lookup.
R.suppressDiagnostics();
@@ -521,11 +539,6 @@ 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
//
diff erent kind of error, so look for typos.
@@ -581,14 +594,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 = nullptr;
+ NamedDecl *OuterDecl;
if (S) {
LookupResult FoundOuter(*this, IdInfo.Identifier, IdInfo.IdentifierLoc,
LookupNestedNameSpecifierName);
LookupName(FoundOuter, S);
OuterDecl = FoundOuter.getAsSingle<NamedDecl>();
- } else if (!SS.getUnqualifiedLookups().empty())
- OuterDecl = SS.getUnqualifiedLookups().front().getDecl();
+ } else
+ OuterDecl = ScopeLookupResult;
if (isAcceptableNestedNameSpecifier(OuterDecl) &&
OuterDecl->getCanonicalDecl() != SD->getCanonicalDecl() &&
@@ -766,7 +779,7 @@ bool Sema::ActOnCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo,
return true;
return BuildCXXNestedNameSpecifier(S, IdInfo, EnteringContext, SS,
- /*ErrorRecoveryLookup=*/false,
+ /*ScopeLookupResult=*/nullptr, false,
IsCorrectedToColon, OnlyNamespace);
}
@@ -827,7 +840,7 @@ bool Sema::IsInvalidUnlessNestedName(Scope *S, CXXScopeSpec &SS,
return false;
return !BuildCXXNestedNameSpecifier(S, IdInfo, EnteringContext, SS,
- /*ErrorRecoveryLookup=*/true);
+ /*ScopeLookupResult=*/nullptr, true);
}
bool Sema::ActOnCXXNestedNameSpecifier(Scope *S,
diff --git a/clang/lib/Sema/SemaCoroutine.cpp b/clang/lib/Sema/SemaCoroutine.cpp
index fa0eb1d2afbee..81334c817b2af 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(),
- NameInfo, /*TemplateArgs=*/nullptr,
+ Base, Base->getType(), Loc, /*IsPtr=*/false, SS,
+ SourceLocation(), nullptr, 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 76db539b5726b..17c4ba99c03f5 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -1275,11 +1275,9 @@ 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,
- /*IsArrow=*/false,
- /*SS=*/CXXScopeSpec(),
- /*TemplateKWLoc=*/SourceLocation(),
- MemberGet, &Args, /*S=*/nullptr);
+ E = S.BuildMemberReferenceExpr(E.get(), DecompType, Loc, false,
+ CXXScopeSpec(), SourceLocation(), nullptr,
+ MemberGet, &Args, nullptr);
if (E.isInvalid())
return true;
@@ -4903,12 +4901,16 @@ 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(), MemberLookup,
- /*TemplateArgs=*/nullptr,
- /*S=*/nullptr);
+ ExprResult CtorArg
+ = SemaRef.BuildMemberReferenceExpr(MemberExprBase,
+ ParamType, Loc,
+ /*IsArrow=*/false,
+ SS,
+ /*TemplateKWLoc=*/SourceLocation(),
+ /*FirstQualifierInScope=*/nullptr,
+ MemberLookup,
+ /*TemplateArgs=*/nullptr,
+ /*S*/nullptr);
if (CtorArg.isInvalid())
return true;
@@ -14337,10 +14339,8 @@ 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,
- /*TemplateKwLoc=*/SourceLocation(), MemberLookup,
- /*TemplateArgs=*/nullptr, /*S=*/nullptr)
- .get());
+ Builder.build(S, Loc), Type, Loc, IsArrow, SS, SourceLocation(),
+ nullptr, MemberLookup, nullptr, nullptr).get());
}
MemberBuilder(const ExprBuilder &Builder, QualType Type, bool IsArrow,
@@ -14546,11 +14546,13 @@ 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(), OpLookup,
- /*TemplateArgs=*/nullptr, /*S*/ nullptr,
- /*SuppressQualifierCheck=*/true);
+ ExprResult OpEqualRef
+ = S.BuildMemberReferenceExpr(To.build(S, Loc), T, Loc, /*IsArrow=*/false,
+ SS, /*TemplateKWLoc=*/SourceLocation(),
+ /*FirstQualifierInScope=*/nullptr,
+ OpLookup,
+ /*TemplateArgs=*/nullptr, /*S*/nullptr,
+ /*SuppressQualifierCheck=*/true);
if (OpEqualRef.isInvalid())
return StmtError();
@@ -17156,9 +17158,8 @@ bool Sema::EvaluateStaticAssertMessageAsString(Expr *Message,
auto BuildExpr = [&](LookupResult &LR) {
ExprResult Res = BuildMemberReferenceExpr(
- Message, Message->getType(), Message->getBeginLoc(), /*IsArrow=*/false,
- /*SS=*/CXXScopeSpec(), /*TemplateKWLoc=*/SourceLocation(), LR,
- /*TemplateArgs=*/nullptr, /*S=*/nullptr);
+ Message, Message->getType(), Message->getBeginLoc(), false,
+ CXXScopeSpec(), SourceLocation(), nullptr, LR, nullptr, 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 9940f8cb62955..d6b85cbcaf56b 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,
- /*UnqualifiedLookups=*/std::nullopt, NameInfo, TemplateArgs);
+ /*FirstQualifierFoundInScope=*/nullptr, 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 8519618bacfee..2070f3b7bb3a2 100644
--- a/clang/lib/Sema/SemaExprMember.cpp
+++ b/clang/lib/Sema/SemaExprMember.cpp
@@ -552,9 +552,11 @@ 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
@@ -588,8 +590,8 @@ Sema::ActOnDependentMemberExpr(Expr *BaseExpr, QualType BaseType, bool IsArrow,
// must have pointer type, and the accessed type is the pointee.
return CXXDependentScopeMemberExpr::Create(
Context, BaseExpr, BaseType, IsArrow, OpLoc,
- SS.getWithLocInContext(Context), TemplateKWLoc,
- SS.getUnqualifiedLookups(), NameInfo, TemplateArgs);
+ SS.getWithLocInContext(Context), TemplateKWLoc, FirstQualifierInScope,
+ NameInfo, TemplateArgs);
}
/// We know that the given qualified member reference points only to
@@ -765,9 +767,8 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
R.addDecl(ND);
R.resolveKind();
return SemaRef.BuildMemberReferenceExpr(
- BaseExpr, BaseExpr->getType(), OpLoc, IsArrow, SS,
- /*TemplateKWLoc=*/SourceLocation(), R, /*TemplateArgs=*/nullptr,
- /*S=*/nullptr);
+ BaseExpr, BaseExpr->getType(), OpLoc, IsArrow, SS, SourceLocation(),
+ nullptr, R, nullptr, nullptr);
},
Sema::CTK_ErrorRecovery, DC);
@@ -783,7 +784,7 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
ExprResult Sema::BuildMemberReferenceExpr(
Expr *Base, QualType BaseType, SourceLocation OpLoc, bool IsArrow,
CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
- const DeclarationNameInfo &NameInfo,
+ NamedDecl *FirstQualifierInScope, const DeclarationNameInfo &NameInfo,
const TemplateArgumentListInfo *TemplateArgs, const Scope *S,
ActOnMemberAccessExtraArgs *ExtraArgs) {
LookupResult R(*this, NameInfo, LookupMemberName);
@@ -827,9 +828,10 @@ ExprResult Sema::BuildMemberReferenceExpr(
if (SS.isInvalid())
return ExprError();
- return BuildMemberReferenceExpr(Base, BaseType, OpLoc, IsArrow, SS,
- TemplateKWLoc, R, TemplateArgs, S,
- /*SuppressQualifierCheck=*/false, ExtraArgs);
+ return BuildMemberReferenceExpr(Base, BaseType,
+ OpLoc, IsArrow, SS, TemplateKWLoc,
+ FirstQualifierInScope, R, TemplateArgs, S,
+ false, ExtraArgs);
}
ExprResult
@@ -967,11 +969,17 @@ static bool IsInFnTryBlockHandler(const Scope *S) {
return false;
}
-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) {
+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) {
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,
@@ -981,8 +989,8 @@ ExprResult Sema::BuildMemberReferenceExpr(
(SS.isSet() ? SS.getScopeRep()->isDependent()
: BaseExprType->isDependentType())))
return ActOnDependentMemberExpr(BaseExpr, BaseExprType, IsArrow, OpLoc, SS,
- TemplateKWLoc, R.getLookupNameInfo(),
- TemplateArgs);
+ TemplateKWLoc, FirstQualifierInScope,
+ R.getLookupNameInfo(), TemplateArgs);
QualType BaseType = BaseExprType;
if (IsArrow) {
@@ -1187,9 +1195,9 @@ ExprResult Sema::BuildMemberReferenceExpr(
// Non-dependent member, but dependent template arguments.
if (!VDecl.get())
- return ActOnDependentMemberExpr(BaseExpr, BaseExpr->getType(), IsArrow,
- OpLoc, SS, TemplateKWLoc, MemberNameInfo,
- TemplateArgs);
+ return ActOnDependentMemberExpr(
+ BaseExpr, BaseExpr->getType(), IsArrow, OpLoc, SS, TemplateKWLoc,
+ FirstQualifierInScope, MemberNameInfo, TemplateArgs);
VarDecl *Var = cast<VarDecl>(VDecl.get());
if (!Var->getTemplateSpecializationKind())
@@ -1755,16 +1763,15 @@ 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);
- UnresolvedSet<4> UnqualifiedLookups;
- if (SS.isValid() &&
- LookupFirstQualifierInScope(S, SS.getScopeRep(), UnqualifiedLookups)) {
- SS.setUnqualifiedLookups(UnqualifiedLookups.pairs());
- }
+ NamedDecl *FirstQualifierInScope
+ = (!SS.isSet() ? nullptr : FindFirstQualifierInScope(S, SS.getScopeRep()));
+
// This is a postfix expression, so get rid of ParenListExprs.
ExprResult Result = MaybeConvertParenListExprToParenExpr(S, Base);
if (Result.isInvalid()) return ExprError();
@@ -1772,8 +1779,8 @@ ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base,
ActOnMemberAccessExtraArgs ExtraArgs = {S, Id, ObjCImpDecl};
ExprResult Res = BuildMemberReferenceExpr(
- Base, Base->getType(), OpLoc, IsArrow, SS, TemplateKWLoc, NameInfo,
- TemplateArgs, S, &ExtraArgs);
+ Base, Base->getType(), OpLoc, IsArrow, SS, TemplateKWLoc,
+ FirstQualifierInScope, NameInfo, TemplateArgs, S, &ExtraArgs);
if (!Res.isInvalid() && isa<MemberExpr>(Res.get()))
CheckMemberAccessOfNoDeref(cast<MemberExpr>(Res.get()));
@@ -1917,8 +1924,9 @@ Sema::BuildImplicitMemberExpr(const CXXScopeSpec &SS,
baseExpr = BuildCXXThisExpr(loc, ThisTy, /*IsImplicit=*/true);
}
- return BuildMemberReferenceExpr(baseExpr, ThisTy,
- /*OpLoc=*/SourceLocation(),
- /*IsArrow=*/!getLangOpts().HLSL, SS,
- TemplateKWLoc, R, TemplateArgs, S);
+ return BuildMemberReferenceExpr(
+ baseExpr, ThisTy,
+ /*OpLoc=*/SourceLocation(),
+ /*IsArrow=*/!getLangOpts().HLSL, SS, TemplateKWLoc,
+ /*FirstQualifierInScope=*/nullptr, R, TemplateArgs, S);
}
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index d4a48858ec419..074062ebbb594 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -16036,11 +16036,13 @@ Sema::BuildForRangeBeginEndCall(SourceLocation Loc,
CandidateSet->clear(OverloadCandidateSet::CSK_Normal);
if (!MemberLookup.empty()) {
- ExprResult MemberRef = BuildMemberReferenceExpr(
- Range, Range->getType(), Loc,
- /*IsPtr=*/false, /*SS=*/CXXScopeSpec(),
- /*TemplateKWLoc=*/SourceLocation(), MemberLookup,
- /*TemplateArgs=*/nullptr, S);
+ ExprResult MemberRef =
+ BuildMemberReferenceExpr(Range, Range->getType(), Loc,
+ /*IsPtr=*/false, CXXScopeSpec(),
+ /*TemplateKWLoc=*/SourceLocation(),
+ /*FirstQualifierInScope=*/nullptr,
+ 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 da2e99b6bc00c..32d42f3c3f3bb 100644
--- a/clang/lib/Sema/SemaStmtAsm.cpp
+++ b/clang/lib/Sema/SemaStmtAsm.cpp
@@ -900,8 +900,7 @@ Sema::LookupInlineAsmVarDeclField(Expr *E, StringRef Member,
return CXXDependentScopeMemberExpr::Create(
Context, E, T, /*IsArrow=*/false, AsmLoc, NestedNameSpecifierLoc(),
SourceLocation(),
- /*UnqualifiedLookups=*/std::nullopt, NameInfo,
- /*TemplateArgs=*/nullptr);
+ /*FirstQualifierFoundInScope=*/nullptr, NameInfo, /*TemplateArgs=*/nullptr);
}
const RecordType *RT = T->getAs<RecordType>();
@@ -924,9 +923,8 @@ Sema::LookupInlineAsmVarDeclField(Expr *E, StringRef Member,
// Make an Expr to thread through OpDecl.
ExprResult Result = BuildMemberReferenceExpr(
- E, E->getType(), AsmLoc, /*IsArrow=*/false, /*SS=*/CXXScopeSpec(),
- /*TemplateKWLoc*/ SourceLocation(), FieldResult,
- /*TemplateArgs=*/nullptr, /*S=*/nullptr);
+ E, E->getType(), AsmLoc, /*IsArrow=*/false, CXXScopeSpec(),
+ SourceLocation(), nullptr, FieldResult, nullptr, nullptr);
return Result;
}
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index d80e50deef697..9d96201625389 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -174,12 +174,15 @@ 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,
- bool MayBeNNS) {
+TemplateNameKind Sema::isTemplateName(Scope *S,
+ CXXScopeSpec &SS,
+ bool hasTemplateKeyword,
+ const UnqualifiedId &Name,
+ ParsedType ObjectTypePtr,
+ bool EnteringContext,
+ TemplateTy &TemplateResult,
+ bool &MemberOfUnknownSpecialization,
+ bool Disambiguation) {
assert(getLangOpts().CPlusPlus && "No template names in C!");
DeclarationName TName;
@@ -210,9 +213,8 @@ Sema::isTemplateName(Scope *S, CXXScopeSpec &SS, bool hasTemplateKeyword,
if (LookupTemplateName(R, S, SS, ObjectType, EnteringContext,
/*RequiredTemplate=*/SourceLocation(),
&AssumedTemplate,
- /*AllowTypoCorrection=*/!Disambiguation, MayBeNNS))
+ /*AllowTypoCorrection=*/!Disambiguation))
return TNK_Non_template;
-
MemberOfUnknownSpecialization = R.wasNotFoundInCurrentInstantiation();
if (AssumedTemplate != AssumedTemplateKind::None) {
@@ -378,7 +380,7 @@ bool Sema::LookupTemplateName(LookupResult &Found, Scope *S, CXXScopeSpec &SS,
QualType ObjectType, bool EnteringContext,
RequiredTemplateKind RequiredTemplate,
AssumedTemplateKind *ATK,
- bool AllowTypoCorrection, bool MayBeNNS) {
+ bool AllowTypoCorrection) {
if (ATK)
*ATK = AssumedTemplateKind::None;
@@ -387,89 +389,92 @@ bool Sema::LookupTemplateName(LookupResult &Found, Scope *S, CXXScopeSpec &SS,
Found.setTemplateNameLookup(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);
+ // 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);
- // 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;
+ // The declaration context must be complete.
+ if (LookupCtx && RequireCompleteDeclContext(SS, LookupCtx))
+ return true;
+ }
bool ObjectTypeSearchedInScope = false;
-
- // 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) {
+ 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);
- } else if (!SS.getUnqualifiedLookups().empty()) {
- Found.addAllDecls(SS.getUnqualifiedLookups());
- Found.resolveKind();
+
+ 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;
}
- ObjectTypeSearchedInScope = true;
+
+ IsDependent |= Found.wasNotFoundInCurrentInstantiation();
}
if (Found.isAmbiguous())
@@ -489,7 +494,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()) {
+ if (AllFunctions || (Found.empty() && !IsDependent)) {
// 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.
@@ -501,15 +506,11 @@ bool Sema::LookupTemplateName(LookupResult &Found, Scope *S, CXXScopeSpec &SS,
}
}
- if (Found.empty() && AllowTypoCorrection) {
+ if (Found.empty() && !IsDependent && 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,8 +543,13 @@ bool Sema::LookupTemplateName(LookupResult &Found, Scope *S, CXXScopeSpec &SS,
NamedDecl *ExampleLookupResult =
Found.empty() ? nullptr : Found.getRepresentativeDecl();
- FilterAcceptableTemplateNames(Found);
+ FilterAcceptableTemplateNames(Found, AllowFunctionTemplatesInLookup);
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) {
@@ -735,7 +741,7 @@ Sema::ActOnDependentIdExpression(const CXXScopeSpec &SS,
/*IsArrow=*/!Context.getLangOpts().HLSL,
/*OperatorLoc=*/SourceLocation(),
/*QualifierLoc=*/NestedNameSpecifierLoc(), TemplateKWLoc,
- /*UnqualifiedLookups=*/std::nullopt, NameInfo, TemplateArgs);
+ /*FirstQualifierFoundInScope=*/nullptr, NameInfo, TemplateArgs);
}
return BuildDependentDeclRefExpr(SS, TemplateKWLoc, NameInfo, TemplateArgs);
}
@@ -4470,10 +4476,14 @@ 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, bool MayBeNNS) {
+TemplateNameKind Sema::ActOnTemplateName(Scope *S,
+ CXXScopeSpec &SS,
+ SourceLocation TemplateKWLoc,
+ const UnqualifiedId &Name,
+ ParsedType ObjectType,
+ bool EnteringContext,
+ TemplateTy &Result,
+ bool AllowInjectedClassName) {
if (TemplateKWLoc.isValid() && S && !S->getTemplateParamParent())
Diag(TemplateKWLoc,
getLangOpts().CPlusPlus11 ?
@@ -4508,10 +4518,9 @@ TemplateNameKind Sema::ActOnTemplateName(
// "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,
- /*Disambiguation=*/false, MayBeNNS);
+ TemplateNameKind TNK = isTemplateName(S, SS, TemplateKWLoc.isValid(), Name,
+ ObjectType, EnteringContext, Result,
+ MemberOfUnknownSpecialization);
if (TNK != TNK_Non_template) {
// We resolved this to a (non-dependent) template name. Return it.
auto *LookupRD = dyn_cast_or_null<CXXRecordDecl>(LookupCtx);
@@ -4550,8 +4559,7 @@ TemplateNameKind Sema::ActOnTemplateName(
? RequiredTemplateKind(TemplateKWLoc)
: TemplateNameIsRequired;
if (!LookupTemplateName(R, S, SS, ObjectType.get(), EnteringContext, RTK,
- /*ATK=*/nullptr, /*AllowTypoCorrection=*/false,
- MayBeNNS) &&
+ /*ATK=*/nullptr, /*AllowTypoCorrection=*/false) &&
!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 64c5a16b2e4c3..a7bc6749c5852 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -1515,11 +1515,12 @@ namespace {
NestedNameSpecifierLoc QualifierLoc,
QualType T);
- TemplateName TransformTemplateName(CXXScopeSpec &SS, TemplateName Name,
- SourceLocation NameLoc,
- QualType ObjectType = QualType(),
- bool AllowInjectedClassName = false,
- bool MayBeNNS = false);
+ TemplateName
+ TransformTemplateName(CXXScopeSpec &SS, TemplateName Name,
+ SourceLocation NameLoc,
+ QualType ObjectType = QualType(),
+ NamedDecl *FirstQualifierInScope = nullptr,
+ bool AllowInjectedClassName = false);
const CXXAssumeAttr *TransformCXXAssumeAttr(const CXXAssumeAttr *AA);
const LoopHintAttr *TransformLoopHintAttr(const LoopHintAttr *LH);
@@ -1951,7 +1952,8 @@ TemplateInstantiator::RebuildElaboratedType(SourceLocation KeywordLoc,
TemplateName TemplateInstantiator::TransformTemplateName(
CXXScopeSpec &SS, TemplateName Name, SourceLocation NameLoc,
- QualType ObjectType, bool AllowInjectedClassName, bool MayBeNNS) {
+ QualType ObjectType, NamedDecl *FirstQualifierInScope,
+ bool AllowInjectedClassName) {
if (TemplateTemplateParmDecl *TTP
= dyn_cast_or_null<TemplateTemplateParmDecl>(Name.getAsTemplateDecl())) {
if (TTP->getDepth() < TemplateArgs.getNumLevels()) {
@@ -2023,7 +2025,8 @@ TemplateName TemplateInstantiator::TransformTemplateName(
}
return inherited::TransformTemplateName(SS, Name, NameLoc, ObjectType,
- AllowInjectedClassName, MayBeNNS);
+ FirstQualifierInScope,
+ AllowInjectedClassName);
}
ExprResult
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index f6021440cda69..655f248d11383 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -541,9 +541,10 @@ class TreeTransform {
/// 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(),
- ArrayRef<DeclAccessPair> UnqualifiedLookups = std::nullopt);
+ NestedNameSpecifierLoc
+ TransformNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS,
+ QualType ObjectType = QualType(),
+ NamedDecl *FirstQualifierInScope = nullptr);
/// Transform the given declaration name.
///
@@ -584,11 +585,12 @@ class TreeTransform {
/// 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(),
- bool AllowInjectedClassName = false,
- bool MayBeNNS = false);
+ TemplateName
+ TransformTemplateName(CXXScopeSpec &SS, TemplateName Name,
+ SourceLocation NameLoc,
+ QualType ObjectType = QualType(),
+ NamedDecl *FirstQualifierInScope = nullptr,
+ bool AllowInjectedClassName = false);
/// Transform the given template argument.
///
@@ -1138,8 +1140,8 @@ class TreeTransform {
CXXScopeSpec SS;
SS.Adopt(QualifierLoc);
TemplateName InstName = getDerived().RebuildTemplateName(
- SS, TemplateKWLoc, *Name, NameLoc, QualType(), AllowInjectedClassName,
- /*MayBeNNS=*/false);
+ SS, TemplateKWLoc, *Name, NameLoc, QualType(), nullptr,
+ AllowInjectedClassName);
if (InstName.isNull())
return QualType();
@@ -1310,7 +1312,8 @@ class TreeTransform {
SourceLocation TemplateKWLoc,
const IdentifierInfo &Name,
SourceLocation NameLoc, QualType ObjectType,
- bool AllowInjectedClassName, bool MayBeNNS);
+ NamedDecl *FirstQualifierInScope,
+ bool AllowInjectedClassName);
/// Build a new template name given a nested name specifier and the
/// overloaded operator name that is referred to as a template.
@@ -2846,14 +2849,15 @@ class TreeTransform {
///
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide
diff erent behavior.
- 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 RebuildMemberExpr(Expr *Base, SourceLocation OpLoc,
+ bool isArrow,
+ NestedNameSpecifierLoc QualifierLoc,
+ SourceLocation TemplateKWLoc,
+ const DeclarationNameInfo &MemberNameInfo,
+ ValueDecl *Member,
+ NamedDecl *FoundDecl,
+ const TemplateArgumentListInfo *ExplicitTemplateArgs,
+ NamedDecl *FirstQualifierInScope) {
ExprResult BaseResult = getSema().PerformMemberExprBaseConversion(Base,
isArrow);
if (!Member->getDeclName()) {
@@ -2890,7 +2894,6 @@ class TreeTransform {
CXXScopeSpec SS;
SS.Adopt(QualifierLoc);
- SS.setUnqualifiedLookups(UnqualifiedLookups);
Base = BaseResult.get();
if (Base->containsErrors())
@@ -2923,9 +2926,10 @@ class TreeTransform {
}
return getSema().BuildMemberReferenceExpr(Base, BaseType, OpLoc, isArrow,
- SS, TemplateKWLoc, R,
- ExplicitTemplateArgs,
- /*S=*/nullptr);
+ SS, TemplateKWLoc,
+ FirstQualifierInScope,
+ R, ExplicitTemplateArgs,
+ /*S*/nullptr);
}
/// Build a new binary operator expression.
@@ -2998,9 +3002,10 @@ class TreeTransform {
CXXScopeSpec SS;
DeclarationNameInfo NameInfo(&Accessor, AccessorLoc);
return getSema().BuildMemberReferenceExpr(
- Base, Base->getType(), OpLoc, IsArrow, SS,
- /*TemplateKWLoc=*/SourceLocation(), NameInfo,
- /*TemplateArgs=*/nullptr, /*S=*/nullptr);
+ Base, Base->getType(), OpLoc, IsArrow, SS, SourceLocation(),
+ /*FirstQualifierInScope*/ nullptr, NameInfo,
+ /* TemplateArgs */ nullptr,
+ /*S*/ nullptr);
}
/// Build a new initializer list expression.
@@ -3568,37 +3573,46 @@ class TreeTransform {
///
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide
diff erent behavior.
- ExprResult RebuildCXXDependentScopeMemberExpr(
- Expr *BaseE, QualType BaseType, bool IsArrow, SourceLocation OperatorLoc,
- NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc,
- ArrayRef<DeclAccessPair> UnqualifiedLookups,
- const DeclarationNameInfo &MemberNameInfo,
- const TemplateArgumentListInfo *TemplateArgs) {
+ ExprResult RebuildCXXDependentScopeMemberExpr(Expr *BaseE,
+ QualType BaseType,
+ bool IsArrow,
+ SourceLocation OperatorLoc,
+ NestedNameSpecifierLoc QualifierLoc,
+ SourceLocation TemplateKWLoc,
+ NamedDecl *FirstQualifierInScope,
+ const DeclarationNameInfo &MemberNameInfo,
+ const TemplateArgumentListInfo *TemplateArgs) {
CXXScopeSpec SS;
SS.Adopt(QualifierLoc);
- SS.setUnqualifiedLookups(UnqualifiedLookups);
- return SemaRef.BuildMemberReferenceExpr(
- BaseE, BaseType, OperatorLoc, IsArrow, SS, TemplateKWLoc,
- MemberNameInfo, TemplateArgs, /*S=*/nullptr);
+ return SemaRef.BuildMemberReferenceExpr(BaseE, BaseType,
+ OperatorLoc, IsArrow,
+ SS, TemplateKWLoc,
+ FirstQualifierInScope,
+ 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
diff erent behavior.
- ExprResult RebuildUnresolvedMemberExpr(
- Expr *BaseE, QualType BaseType, SourceLocation OperatorLoc, bool IsArrow,
- NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc,
- ArrayRef<DeclAccessPair> UnqualifiedLookups, LookupResult &R,
- const TemplateArgumentListInfo *TemplateArgs) {
+ ExprResult RebuildUnresolvedMemberExpr(Expr *BaseE, QualType BaseType,
+ SourceLocation OperatorLoc,
+ bool IsArrow,
+ NestedNameSpecifierLoc QualifierLoc,
+ SourceLocation TemplateKWLoc,
+ NamedDecl *FirstQualifierInScope,
+ LookupResult &R,
+ const TemplateArgumentListInfo *TemplateArgs) {
CXXScopeSpec SS;
SS.Adopt(QualifierLoc);
- SS.setUnqualifiedLookups(UnqualifiedLookups);
- return SemaRef.BuildMemberReferenceExpr(BaseE, BaseType, OperatorLoc,
- IsArrow, SS, TemplateKWLoc, R,
- TemplateArgs, /*S=*/nullptr);
+ return SemaRef.BuildMemberReferenceExpr(BaseE, BaseType,
+ OperatorLoc, IsArrow,
+ SS, TemplateKWLoc,
+ FirstQualifierInScope,
+ R, TemplateArgs, /*S*/nullptr);
}
/// Build a new noexcept expression.
@@ -3817,8 +3831,10 @@ class TreeTransform {
DeclarationNameInfo NameInfo(Ivar->getDeclName(), IvarLoc);
ExprResult Result = getSema().BuildMemberReferenceExpr(
BaseArg, BaseArg->getType(),
- /*FIXME:*/ IvarLoc, IsArrow, SS, /*TemplateKWLoc=*/SourceLocation(),
- NameInfo, /*TemplateArgs=*/nullptr, /*S=*/nullptr);
+ /*FIXME:*/ IvarLoc, IsArrow, SS, SourceLocation(),
+ /*FirstQualifierInScope=*/nullptr, NameInfo,
+ /*TemplateArgs=*/nullptr,
+ /*S=*/nullptr);
if (IsFreeIvar && Result.isUsable())
cast<ObjCIvarRefExpr>(Result.get())->setIsFreeIvar(IsFreeIvar);
return Result;
@@ -3833,12 +3849,14 @@ class TreeTransform {
SourceLocation PropertyLoc) {
CXXScopeSpec SS;
DeclarationNameInfo NameInfo(Property->getDeclName(), PropertyLoc);
- return getSema().BuildMemberReferenceExpr(
- BaseArg, BaseArg->getType(),
- /*FIXME:*/ PropertyLoc,
- /*IsArrow=*/false, SS, /*TemplateKWLoc=*/SourceLocation(), NameInfo,
- /*TemplateArgs=*/nullptr,
- /*S=*/nullptr);
+ return getSema().BuildMemberReferenceExpr(BaseArg, BaseArg->getType(),
+ /*FIXME:*/PropertyLoc,
+ /*IsArrow=*/false,
+ SS, SourceLocation(),
+ /*FirstQualifierInScope=*/nullptr,
+ NameInfo,
+ /*TemplateArgs=*/nullptr,
+ /*S=*/nullptr);
}
/// Build a new Objective-C property reference expression.
@@ -3865,11 +3883,13 @@ class TreeTransform {
SourceLocation OpLoc, bool IsArrow) {
CXXScopeSpec SS;
DeclarationNameInfo NameInfo(&getSema().Context.Idents.get("isa"), IsaLoc);
- return getSema().BuildMemberReferenceExpr(
- BaseArg, BaseArg->getType(), OpLoc, IsArrow, SS,
- /*TemplateKWLoc=*/SourceLocation(), NameInfo,
- /*TemplateArgs=*/nullptr,
- /*S=*/nullptr);
+ return getSema().BuildMemberReferenceExpr(BaseArg, BaseArg->getType(),
+ OpLoc, IsArrow,
+ SS, SourceLocation(),
+ /*FirstQualifierInScope=*/nullptr,
+ NameInfo,
+ /*TemplateArgs=*/nullptr,
+ /*S=*/nullptr);
}
/// Build a new shuffle vector expression.
@@ -4034,14 +4054,18 @@ class TreeTransform {
}
private:
- TypeLoc TransformTypeInObjectScope(TypeLoc TL, QualType ObjectType,
+ TypeLoc TransformTypeInObjectScope(TypeLoc TL,
+ QualType ObjectType,
+ NamedDecl *FirstQualifierInScope,
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,
@@ -4360,7 +4384,7 @@ Sema::ConditionResult TreeTransform<Derived>::TransformCondition(
template <typename Derived>
NestedNameSpecifierLoc TreeTransform<Derived>::TransformNestedNameSpecifierLoc(
NestedNameSpecifierLoc NNS, QualType ObjectType,
- ArrayRef<DeclAccessPair> UnqualifiedLookups) {
+ NamedDecl *FirstQualifierInScope) {
SmallVector<NestedNameSpecifierLoc, 4> Qualifiers;
auto insertNNS = [&Qualifiers](NestedNameSpecifierLoc NNS) {
@@ -4371,8 +4395,6 @@ NestedNameSpecifierLoc TreeTransform<Derived>::TransformNestedNameSpecifierLoc(
insertNNS(NNS);
CXXScopeSpec SS;
- SS.setUnqualifiedLookups(UnqualifiedLookups);
-
while (!Qualifiers.empty()) {
NestedNameSpecifierLoc Q = Qualifiers.pop_back_val();
NestedNameSpecifier *QNNS = Q.getNestedNameSpecifier();
@@ -4382,9 +4404,8 @@ NestedNameSpecifierLoc TreeTransform<Derived>::TransformNestedNameSpecifierLoc(
Sema::NestedNameSpecInfo IdInfo(QNNS->getAsIdentifier(),
Q.getLocalBeginLoc(), Q.getLocalEndLoc(),
ObjectType);
- if (SemaRef.BuildCXXNestedNameSpecifier(/*Scope=*/nullptr, IdInfo,
- /*EnteringContext=*/false, SS,
- /*ErrorRecoveryLookup=*/false))
+ if (SemaRef.BuildCXXNestedNameSpecifier(/*Scope=*/nullptr, IdInfo, false,
+ SS, FirstQualifierInScope, false))
return NestedNameSpecifierLoc();
break;
}
@@ -4422,7 +4443,8 @@ NestedNameSpecifierLoc TreeTransform<Derived>::TransformNestedNameSpecifierLoc(
case NestedNameSpecifier::TypeSpecWithTemplate:
case NestedNameSpecifier::TypeSpec: {
- TypeLoc TL = TransformTypeInObjectScope(Q.getTypeLoc(), ObjectType, SS);
+ TypeLoc TL = TransformTypeInObjectScope(Q.getTypeLoc(), ObjectType,
+ FirstQualifierInScope, SS);
if (!TL)
return NestedNameSpecifierLoc();
@@ -4455,7 +4477,7 @@ NestedNameSpecifierLoc TreeTransform<Derived>::TransformNestedNameSpecifierLoc(
}
// The qualifier-in-scope and object type only apply to the leftmost entity.
- SS.setUnqualifiedLookups(std::nullopt);
+ FirstQualifierInScope = nullptr;
ObjectType = QualType();
}
@@ -4538,10 +4560,14 @@ ::TransformDeclarationNameInfo(const DeclarationNameInfo &NameInfo) {
llvm_unreachable("Unknown name kind.");
}
-template <typename Derived>
-TemplateName TreeTransform<Derived>::TransformTemplateName(
- CXXScopeSpec &SS, TemplateName Name, SourceLocation NameLoc,
- QualType ObjectType, bool AllowInjectedClassName, bool MayBeNNS) {
+template<typename Derived>
+TemplateName
+TreeTransform<Derived>::TransformTemplateName(CXXScopeSpec &SS,
+ TemplateName Name,
+ SourceLocation NameLoc,
+ QualType ObjectType,
+ NamedDecl *FirstQualifierInScope,
+ bool AllowInjectedClassName) {
if (QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName()) {
TemplateDecl *Template = QTN->getUnderlyingTemplate().getAsTemplateDecl();
assert(Template && "qualified template name must refer to a template");
@@ -4565,7 +4591,7 @@ TemplateName TreeTransform<Derived>::TransformTemplateName(
if (SS.getScopeRep()) {
// These apply to the scope specifier, not the template.
ObjectType = QualType();
- SS.setUnqualifiedLookups(std::nullopt);
+ FirstQualifierInScope = nullptr;
}
if (!getDerived().AlwaysRebuild() &&
@@ -4577,9 +4603,13 @@ TemplateName TreeTransform<Derived>::TransformTemplateName(
SourceLocation TemplateKWLoc = NameLoc;
if (DTN->isIdentifier()) {
- return getDerived().RebuildTemplateName(
- SS, TemplateKWLoc, *DTN->getIdentifier(), NameLoc, ObjectType,
- AllowInjectedClassName, MayBeNNS);
+ return getDerived().RebuildTemplateName(SS,
+ TemplateKWLoc,
+ *DTN->getIdentifier(),
+ NameLoc,
+ ObjectType,
+ FirstQualifierInScope,
+ AllowInjectedClassName);
}
return getDerived().RebuildTemplateName(SS, TemplateKWLoc,
@@ -5123,31 +5153,39 @@ QualType TreeTransform<Derived>::RebuildQualifiedType(QualType T,
return SemaRef.BuildQualifiedType(T, Loc, Quals);
}
-template <typename Derived>
-TypeLoc TreeTransform<Derived>::TransformTypeInObjectScope(TypeLoc TL,
- QualType ObjectType,
- CXXScopeSpec &SS) {
+template<typename Derived>
+TypeLoc
+TreeTransform<Derived>::TransformTypeInObjectScope(TypeLoc TL,
+ QualType ObjectType,
+ NamedDecl *UnqualLookup,
+ CXXScopeSpec &SS) {
if (getDerived().AlreadyTransformed(TL.getType()))
return TL;
- TypeSourceInfo *TSI = TransformTSIInObjectScope(TL, ObjectType, SS);
+ TypeSourceInfo *TSI =
+ TransformTSIInObjectScope(TL, ObjectType, UnqualLookup, SS);
if (TSI)
return TSI->getTypeLoc();
return TypeLoc();
}
-template <typename Derived>
-TypeSourceInfo *TreeTransform<Derived>::TransformTypeInObjectScope(
- TypeSourceInfo *TSInfo, QualType ObjectType, CXXScopeSpec &SS) {
+template<typename Derived>
+TypeSourceInfo *
+TreeTransform<Derived>::TransformTypeInObjectScope(TypeSourceInfo *TSInfo,
+ QualType ObjectType,
+ NamedDecl *UnqualLookup,
+ CXXScopeSpec &SS) {
if (getDerived().AlreadyTransformed(TSInfo->getType()))
return TSInfo;
- return TransformTSIInObjectScope(TSInfo->getTypeLoc(), ObjectType, SS);
+ return TransformTSIInObjectScope(TSInfo->getTypeLoc(), ObjectType,
+ UnqualLookup, SS);
}
template <typename Derived>
TypeSourceInfo *TreeTransform<Derived>::TransformTSIInObjectScope(
- TypeLoc TL, QualType ObjectType, CXXScopeSpec &SS) {
+ TypeLoc TL, QualType ObjectType, NamedDecl *UnqualLookup,
+ CXXScopeSpec &SS) {
QualType T = TL.getType();
assert(!getDerived().AlreadyTransformed(T));
@@ -5160,7 +5198,7 @@ TypeSourceInfo *TreeTransform<Derived>::TransformTSIInObjectScope(
TemplateName Template = getDerived().TransformTemplateName(
SS, SpecTL.getTypePtr()->getTemplateName(), SpecTL.getTemplateNameLoc(),
- ObjectType, /*AllowInjectedClassName=*/true, /*MayBeNNS=*/true);
+ ObjectType, UnqualLookup, /*AllowInjectedClassName*/true);
if (Template.isNull())
return nullptr;
@@ -5170,11 +5208,13 @@ TypeSourceInfo *TreeTransform<Derived>::TransformTSIInObjectScope(
DependentTemplateSpecializationTypeLoc SpecTL =
TL.castAs<DependentTemplateSpecializationTypeLoc>();
- TemplateName Template = getDerived().RebuildTemplateName(
- SS, SpecTL.getTemplateKeywordLoc(),
- *SpecTL.getTypePtr()->getIdentifier(), SpecTL.getTemplateNameLoc(),
- ObjectType,
- /*AllowInjectedClassName=*/true, /*MayBeNNS=*/true);
+ TemplateName Template
+ = getDerived().RebuildTemplateName(SS,
+ SpecTL.getTemplateKeywordLoc(),
+ *SpecTL.getTypePtr()->getIdentifier(),
+ SpecTL.getTemplateNameLoc(),
+ ObjectType, UnqualLookup,
+ /*AllowInjectedClassName*/true);
if (Template.isNull())
return nullptr;
@@ -12318,8 +12358,7 @@ 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).
- ArrayRef<DeclAccessPair> UnqualifiedLookups;
-
+ NamedDecl *FirstQualifierInScope = nullptr;
DeclarationNameInfo MemberNameInfo = E->getMemberNameInfo();
if (MemberNameInfo.getName()) {
MemberNameInfo = getDerived().TransformDeclarationNameInfo(MemberNameInfo);
@@ -12327,11 +12366,16 @@ TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E) {
return ExprError();
}
- return getDerived().RebuildMemberExpr(
- Base.get(), FakeOperatorLoc, E->isArrow(), QualifierLoc, TemplateKWLoc,
- MemberNameInfo, Member, FoundDecl,
- (E->hasExplicitTemplateArgs() ? &TransArgs : nullptr),
- UnqualifiedLookups);
+ return getDerived().RebuildMemberExpr(Base.get(), FakeOperatorLoc,
+ E->isArrow(),
+ QualifierLoc,
+ TemplateKWLoc,
+ MemberNameInfo,
+ Member,
+ FoundDecl,
+ (E->hasExplicitTemplateArgs()
+ ? &TransArgs : nullptr),
+ FirstQualifierInScope);
}
template<typename Derived>
@@ -13458,8 +13502,9 @@ TreeTransform<Derived>::TransformCXXPseudoDestructorExpr(
PseudoDestructorTypeStorage Destroyed;
if (E->getDestroyedTypeInfo()) {
- TypeSourceInfo *DestroyedTypeInfo = getDerived().TransformTypeInObjectScope(
- E->getDestroyedTypeInfo(), ObjectType, SS);
+ TypeSourceInfo *DestroyedTypeInfo
+ = getDerived().TransformTypeInObjectScope(E->getDestroyedTypeInfo(),
+ ObjectType, nullptr, SS);
if (!DestroyedTypeInfo)
return ExprError();
Destroyed = DestroyedTypeInfo;
@@ -13485,7 +13530,7 @@ TreeTransform<Derived>::TransformCXXPseudoDestructorExpr(
if (E->getScopeTypeInfo()) {
CXXScopeSpec EmptySS;
ScopeTypeInfo = getDerived().TransformTypeInObjectScope(
- E->getScopeTypeInfo(), ObjectType, EmptySS);
+ E->getScopeTypeInfo(), ObjectType, nullptr, EmptySS);
if (!ScopeTypeInfo)
return ExprError();
}
@@ -14746,17 +14791,19 @@ TreeTransform<Derived>::TransformCXXDependentScopeMemberExpr(
ObjectType = BaseType->castAs<PointerType>()->getPointeeType();
}
- UnresolvedSet<4> UnqualifiedLookups;
- for (auto D : E->unqualified_lookups()) {
- if (NamedDecl *InstD = getDerived().TransformFirstQualifierInScope(
- D.getDecl(), E->getQualifierLoc().getBeginLoc()))
- UnqualifiedLookups.addDecl(InstD);
- }
+ // Transform the first part of the nested-name-specifier that qualifies
+ // the member name.
+ NamedDecl *FirstQualifierInScope
+ = getDerived().TransformFirstQualifierInScope(
+ E->getFirstQualifierFoundInScope(),
+ E->getQualifierLoc().getBeginLoc());
NestedNameSpecifierLoc QualifierLoc;
if (E->getQualifier()) {
- QualifierLoc = getDerived().TransformNestedNameSpecifierLoc(
- E->getQualifierLoc(), ObjectType, UnqualifiedLookups.pairs());
+ QualifierLoc
+ = getDerived().TransformNestedNameSpecifierLoc(E->getQualifierLoc(),
+ ObjectType,
+ FirstQualifierInScope);
if (!QualifierLoc)
return ExprError();
}
@@ -14775,16 +14822,23 @@ 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() &&
- UnqualifiedLookups.pairs() == E->unqualified_lookups())
+ FirstQualifierInScope == E->getFirstQualifierFoundInScope())
return E;
- return getDerived().RebuildCXXDependentScopeMemberExpr(
- Base.get(), BaseType, E->isArrow(), E->getOperatorLoc(), QualifierLoc,
- TemplateKWLoc, UnqualifiedLookups.pairs(), NameInfo,
- /*TemplateArgs*/ nullptr);
+ return getDerived().RebuildCXXDependentScopeMemberExpr(Base.get(),
+ BaseType,
+ E->isArrow(),
+ E->getOperatorLoc(),
+ QualifierLoc,
+ TemplateKWLoc,
+ FirstQualifierInScope,
+ NameInfo,
+ /*TemplateArgs*/nullptr);
}
TemplateArgumentListInfo TransArgs(E->getLAngleLoc(), E->getRAngleLoc());
@@ -14793,9 +14847,15 @@ TreeTransform<Derived>::TransformCXXDependentScopeMemberExpr(
TransArgs))
return ExprError();
- return getDerived().RebuildCXXDependentScopeMemberExpr(
- Base.get(), BaseType, E->isArrow(), E->getOperatorLoc(), QualifierLoc,
- TemplateKWLoc, UnqualifiedLookups.pairs(), NameInfo, &TransArgs);
+ return getDerived().RebuildCXXDependentScopeMemberExpr(Base.get(),
+ BaseType,
+ E->isArrow(),
+ E->getOperatorLoc(),
+ QualifierLoc,
+ TemplateKWLoc,
+ FirstQualifierInScope,
+ NameInfo,
+ &TransArgs);
}
template <typename Derived>
@@ -14856,11 +14916,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).
- ArrayRef<DeclAccessPair> UnqualifiedLookups;
+ NamedDecl *FirstQualifierInScope = nullptr;
return getDerived().RebuildUnresolvedMemberExpr(
Base.get(), BaseType, Old->getOperatorLoc(), Old->isArrow(), QualifierLoc,
- TemplateKWLoc, UnqualifiedLookups, R,
+ TemplateKWLoc, FirstQualifierInScope, R,
(Old->hasExplicitTemplateArgs() ? &TransArgs : nullptr));
}
@@ -16217,18 +16277,22 @@ 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, bool AllowInjectedClassName,
- bool MayBeNNS) {
+template<typename Derived>
+TemplateName
+TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS,
+ SourceLocation TemplateKWLoc,
+ const IdentifierInfo &Name,
+ SourceLocation NameLoc,
+ QualType ObjectType,
+ NamedDecl *FirstQualifierInScope,
+ bool AllowInjectedClassName) {
UnqualifiedId TemplateName;
TemplateName.setIdentifier(&Name, NameLoc);
Sema::TemplateTy Template;
getSema().ActOnTemplateName(/*Scope=*/nullptr, SS, TemplateKWLoc,
TemplateName, ParsedType::make(ObjectType),
/*EnteringContext=*/false, Template,
- AllowInjectedClassName, MayBeNNS);
+ AllowInjectedClassName);
return Template.get();
}
@@ -16376,10 +16440,13 @@ TreeTransform<Derived>::RebuildCXXPseudoDestructorExpr(Expr *Base,
}
SourceLocation TemplateKWLoc; // FIXME: retrieve it from caller.
- return getSema().BuildMemberReferenceExpr(
- Base, BaseType, OperatorLoc, isArrow, SS, TemplateKWLoc, NameInfo,
- /*TemplateArgs=*/nullptr,
- /*S=*/nullptr);
+ return getSema().BuildMemberReferenceExpr(Base, BaseType,
+ OperatorLoc, isArrow,
+ SS, TemplateKWLoc,
+ /*FIXME: FirstQualifier*/ nullptr,
+ NameInfo,
+ /*TemplateArgs*/ nullptr,
+ /*S*/nullptr);
}
template<typename Derived>
diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp
index 6ccb4b01a036a..37f5c7f2bf20b 100644
--- a/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -1992,43 +1992,42 @@ void ASTStmtReader::VisitCXXDependentScopeMemberExpr(
CXXDependentScopeMemberExpr *E) {
VisitExpr(E);
- CurrentUnpackingBits.emplace(Record.readInt());
- 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;
+ 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!");
- 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->OperatorLoc = Record.readSourceLocation();
- E->MemberNameInfo = Record.readDeclarationNameInfo();
+ E->CXXDependentScopeMemberExprBits.OperatorLoc = readSourceLocation();
- if (HasQualifier)
- new (E->getTrailingObjects<NestedNameSpecifierLoc>())
- NestedNameSpecifierLoc(Record.readNestedNameSpecifierLoc());
-
- 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 (HasFirstQualifierFoundInScope)
+ *E->getTrailingObjects<NamedDecl *>() = readDeclAs<NamedDecl>();
- if (HasTemplateInfo)
- ReadTemplateKWAndArgsInfo(
- *E->getTrailingObjects<ASTTemplateKWAndArgsInfo>(),
- E->getTrailingObjects<TemplateArgumentLoc>(), NumTemplateArgs);
+ E->MemberNameInfo = Record.readDeclarationNameInfo();
}
void
@@ -4075,16 +4074,16 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
break;
case EXPR_CXX_DEPENDENT_SCOPE_MEMBER: {
+ unsigned NumTemplateArgs = Record[ASTStmtReader::NumExprFields];
BitsUnpacker DependentScopeMemberBits(
- Record[ASTStmtReader::NumExprFields]);
- bool HasQualifier = DependentScopeMemberBits.getNextBit();
- bool HasTemplateInfo = DependentScopeMemberBits.getNextBit();
- unsigned NumUnqualifiedLookups = Record[ASTStmtReader::NumExprFields + 1];
- unsigned NumTemplateArgs = Record[ASTStmtReader::NumExprFields + 2];
+ Record[ASTStmtReader::NumExprFields + 1]);
+ bool HasTemplateKWAndArgsInfo = DependentScopeMemberBits.getNextBit();
+ bool HasFirstQualifierFoundInScope =
+ DependentScopeMemberBits.getNextBit();
S = CXXDependentScopeMemberExpr::CreateEmpty(
- Context, HasQualifier, NumUnqualifiedLookups, HasTemplateInfo,
- NumTemplateArgs);
+ Context, HasTemplateKWAndArgsInfo, NumTemplateArgs,
+ HasFirstQualifierFoundInScope);
break;
}
diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp
index 98606bbf8c4a0..d36f43fdaf262 100644
--- a/clang/lib/Serialization/ASTWriterStmt.cpp
+++ b/clang/lib/Serialization/ASTWriterStmt.cpp
@@ -1986,41 +1986,34 @@ void ASTStmtWriter::VisitCXXDependentScopeMemberExpr(
CXXDependentScopeMemberExpr *E) {
VisitExpr(E);
- bool HasQualifier = E->hasQualifier();
- unsigned NumUnqualifiedLookups = E->getNumUnqualifiedLookups();
- bool HasTemplateInfo = E->hasTemplateKWAndArgsInfo();
- unsigned NumTemplateArgs = E->getNumTemplateArgs();
-
- // Write these first for easy access when deserializing, as they affect the
- // size of the CXXDependentScopeMemberExpr.
+ // 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(HasQualifier);
- CurrentPackingBits.addBit(HasTemplateInfo);
- Record.push_back(NumUnqualifiedLookups);
- Record.push_back(NumTemplateArgs);
+ CurrentPackingBits.addBit(E->hasTemplateKWAndArgsInfo());
+ CurrentPackingBits.addBit(E->hasFirstQualifierFoundInScope());
+
+ if (E->hasTemplateKWAndArgsInfo()) {
+ const ASTTemplateKWAndArgsInfo &ArgInfo =
+ *E->getTrailingObjects<ASTTemplateKWAndArgsInfo>();
+ AddTemplateKWAndArgsInfo(ArgInfo,
+ E->getTrailingObjects<TemplateArgumentLoc>());
+ }
- Record.AddTypeRef(E->getBaseType());
CurrentPackingBits.addBit(E->isArrow());
+
+ Record.AddTypeRef(E->getBaseType());
+ Record.AddNestedNameSpecifierLoc(E->getQualifierLoc());
CurrentPackingBits.addBit(!E->isImplicitAccess());
if (!E->isImplicitAccess())
Record.AddStmt(E->getBase());
Record.AddSourceLocation(E->getOperatorLoc());
- 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>());
+ if (E->hasFirstQualifierFoundInScope())
+ Record.AddDeclRef(E->getFirstQualifierFoundInScope());
+ Record.AddDeclarationNameInfo(E->MemberNameInfo);
Code = serialization::EXPR_CXX_DEPENDENT_SCOPE_MEMBER;
}
diff --git a/clang/test/CXX/basic/basic.lookup/basic.lookup.classref/p1-cxx11.cpp b/clang/test/CXX/basic/basic.lookup/basic.lookup.classref/p1-cxx11.cpp
index 11eb67fb4f159..1afea99e8895c 100644
--- a/clang/test/CXX/basic/basic.lookup/basic.lookup.classref/p1-cxx11.cpp
+++ b/clang/test/CXX/basic/basic.lookup/basic.lookup.classref/p1-cxx11.cpp
@@ -55,19 +55,15 @@ namespace PR11856 {
template<typename T> T *end(T*);
- struct X { };
- struct Y {
- int end;
- };
+ class X { };
template <typename T>
void Foo2() {
T it1;
- if (it1->end < it1->end) { }
+ if (it1->end < it1->end) {
+ }
X *x;
- if (x->end < 7) { } // expected-error{{no member named 'end' in 'PR11856::X'}}
-
- Y *y;
- if (y->end < 7) { }
+ if (x->end < 7) { // expected-error{{no member named 'end' in 'PR11856::X'}}
+ }
}
}
diff --git a/clang/test/CXX/basic/basic.lookup/basic.lookup.classref/p1.cpp b/clang/test/CXX/basic/basic.lookup/basic.lookup.classref/p1.cpp
index 5221b883f046c..e3599db18350b 100644
--- a/clang/test/CXX/basic/basic.lookup/basic.lookup.classref/p1.cpp
+++ b/clang/test/CXX/basic/basic.lookup/basic.lookup.classref/p1.cpp
@@ -86,19 +86,15 @@ namespace PR11856 {
template<typename T> T *end(T*);
- struct X { };
- struct Y {
- int end;
- };
+ class X { };
template <typename T>
void Foo2() {
T it1;
- if (it1->end < it1->end) { }
+ if (it1->end < it1->end) {
+ }
X *x;
- if (x->end < 7) { } // expected-error{{no member named 'end' in 'PR11856::X'}}
-
- Y *y;
- if (y->end < 7) { }
+ if (x->end < 7) { // expected-error{{no member named 'end' in 'PR11856::X'}}
+ }
}
}
diff --git a/clang/test/CXX/basic/basic.lookup/basic.lookup.qual/basic.lookup.qual.general/p3-example3.cpp b/clang/test/CXX/basic/basic.lookup/basic.lookup.qual/basic.lookup.qual.general/p3-example3.cpp
deleted file mode 100644
index 423eacd21d441..0000000000000
--- a/clang/test/CXX/basic/basic.lookup/basic.lookup.qual/basic.lookup.qual.general/p3-example3.cpp
+++ /dev/null
@@ -1,27 +0,0 @@
-// RUN: %clang_cc1 -std=c++23 %s -verify
-
-int f();
-
-struct A {
- int B, C; // expected-note {{declared as a non-template here}}
- template<int> using D = void;
- using T = void;
- void f();
-};
-
-using B = A;
-template<int> using C = A;
-template<int> using D = A;
-template<int> using X = A;
-
-template<class T>
-void g(T *p) {
- p->X<0>::f(); // expected-error {{no member named 'X' in 'A'}}
- p->template X<0>::f();
- p->B::f();
- p->template C<0>::f(); // expected-error {{'C' following the 'template' keyword does not refer to a template}}
- p->template D<0>::f(); // expected-error {{type 'template D<0>' (aka 'void') cannot be used prior to '::' because it has no members}}
- p->T::f(); // expected-error {{'A::T' (aka 'void') is not a class, namespace, or enumeration}}
-}
-
-template void g(A*); // expected-note {{in instantiation of}}
diff --git a/clang/test/CXX/basic/basic.lookup/basic.lookup.qual/basic.lookup.qual.general/p3.cpp b/clang/test/CXX/basic/basic.lookup/basic.lookup.qual/basic.lookup.qual.general/p3.cpp
deleted file mode 100644
index 7d843649c3f30..0000000000000
--- a/clang/test/CXX/basic/basic.lookup/basic.lookup.qual/basic.lookup.qual.general/p3.cpp
+++ /dev/null
@@ -1,98 +0,0 @@
-// RUN: %clang_cc1 -std=c++23 -Wno-unused %s -verify
-
-namespace Unambiguous {
- struct A {
- int x;
-
- template<typename T>
- using C = A;
- };
-
- using B = A;
-
- template<typename T>
- using D = A;
-
- using E = void;
-
- struct F : A {
- void non_template() {
- this->x;
- this->A::x;
- this->B::x;
- this->C<int>::x;
- this->D<int>::x;
- this->E::x; // expected-error {{'Unambiguous::E' (aka 'void') is not a class, namespace, or enumeration}}
- }
- };
-
- template<typename T>
- void not_instantiated(T t) {
- t.x;
- t.A::x;
- t.B::x;
- t.C<int>::x; // expected-warning {{use 'template' keyword to treat 'C' as a dependent template name}}
- t.template C<int>::x;
- t.D<int>::x; // expected-warning {{use 'template' keyword to treat 'D' as a dependent template name}}
- t.template D<int>::x;
- t.E::x;
- }
-
- template<typename T>
- void instantiated_valid(T t) {
- t.x;
- t.A::x;
- t.B::x;
- t.template C<int>::x;
- t.template D<int>::x;
- t.E::x;
- }
-
- template<typename T>
- void instantiated_invalid(T t) {
- t.x;
- t.A::x;
- t.B::x; // expected-error {{'Unambiguous::Invalid::B' (aka 'void') is not a class, namespace, or enumeration}}
- t.template C<int>::x;
- t.template D<int>::x; // expected-error {{'D' following the 'template' keyword does not refer to a template}}
- t.E::x; // expected-error {{'Unambiguous::E' (aka 'void') is not a class, namespace, or enumeration}}
- }
-
- struct Valid : A {
- using E = A;
- };
-
- template void instantiated_valid(Valid);
-
- struct Invalid : A {
- using B = void;
- using D = A; // expected-note {{declared as a non-template here}}
- };
-
- template void instantiated_invalid(Invalid); // expected-note {{in instantiation of}}
-} // namespace Unambiguous
-
-namespace Ambiguous {
- inline namespace N {
- struct A { }; // expected-note {{candidate found by name lookup is 'Ambiguous::N::A'}}
- }
-
- struct A { }; // expected-note {{candidate found by name lookup is 'Ambiguous::A'}}
-
- template<typename T>
- void f(T t) {
- t.A::x; // expected-error {{reference to 'A' is ambiguous}}
- }
-
- struct B {
- using A = B;
-
- int x;
- };
-
- struct C { };
-
- template void f(B);
- template void f(C); // expected-note {{in instantiation of}}
-
-} // namespace Ambiguous
diff --git a/clang/test/CXX/class.derived/class.member.lookup/p8.cpp b/clang/test/CXX/class.derived/class.member.lookup/p8.cpp
index 97d3587881bbc..78e83c0ab4566 100644
--- a/clang/test/CXX/class.derived/class.member.lookup/p8.cpp
+++ b/clang/test/CXX/class.derived/class.member.lookup/p8.cpp
@@ -47,8 +47,8 @@ template<typename T>
void DerivedT<T>::Inner() {
Derived1T<T>::Foo();
Derived2T<T>::Member = 42;
- this->Derived1T<T>::Foo(); // expected-warning{{use 'template' keyword to treat 'Derived1T' as a dependent template name}}
- this->Derived2T<T>::Member = 42; // expected-warning{{use 'template' keyword to treat 'Derived2T' as a dependent template name}}
+ this->Derived1T<T>::Foo();
+ this->Derived2T<T>::Member = 42;
this->Foo(); // expected-error{{non-static member 'Foo' found in multiple base-class subobjects of type 'BaseT<int>'}}
}
diff --git a/clang/test/CXX/drs/cwg1xx.cpp b/clang/test/CXX/drs/cwg1xx.cpp
index 6bca460818425..e7dddd1ea9278 100644
--- a/clang/test/CXX/drs/cwg1xx.cpp
+++ b/clang/test/CXX/drs/cwg1xx.cpp
@@ -615,8 +615,10 @@ namespace cwg141 { // cwg141: 3.1
// cxx98-note@#cwg141-S {{lookup from the current scope refers here}}
// expected-error@#cwg141-a {{no member named 'n' in 'cwg141::A::S<int>'; did you mean '::cwg141::S<int>::n'?}}
// expected-note@#cwg141-S {{'::cwg141::S<int>::n' declared here}}
+ // FIXME: we issue a useful diagnostic first, then some bogus ones.
b.f<int>();
// expected-error at -1 {{no member named 'f' in 'cwg141::B'}}
+ // expected-error at -2 +{{}}
(void)b.S<int>::n;
}
template<typename T> struct C {
@@ -626,12 +628,10 @@ namespace cwg141 { // cwg141: 3.1
// expected-error at -1 {{use 'template' keyword to treat 'f' as a dependent template name}}
}
void h() {
- (void)t.S<int>::n;
- // expected-error at -1 {{use 'template' keyword to treat 'S' as a dependent template name}}
+ (void)t.S<int>::n; // ok
}
void i() {
- (void)t.S<int>();
- // expected-error at -1 {{use 'template' keyword to treat 'S' as a dependent template name}}
+ (void)t.S<int>(); // ok!
}
};
void h() { C<B>().h(); } // ok
diff --git a/clang/test/CXX/temp/temp.names/p3-23.cpp b/clang/test/CXX/temp/temp.names/p3-23.cpp
deleted file mode 100644
index 27c24e1d61706..0000000000000
--- a/clang/test/CXX/temp/temp.names/p3-23.cpp
+++ /dev/null
@@ -1,237 +0,0 @@
-// RUN: %clang_cc1 -std=c++23 -Wno-unused %s -verify
-
-namespace FoundNothing {
- template<typename T>
- void f0(T &t) {
- t.x<0;
- t.x<0>; // expected-error {{expected expression}}
- t.x<0>1;
- }
-
- template<typename T>
- struct A {
- void f1() {
- this->x<0; // expected-error {{no member named 'x' in 'A<T>'}}
- this->x<0>; // expected-error {{no member named 'x' in 'A<T>'}}
- // expected-error at -1 {{expected expression}}
- this->x<0>1; // expected-error {{no member named 'x' in 'A<T>'}}
- }
- };
-} // namespace FoundNothing
-
-namespace FoundSingleNonTemplate {
- void f0();
-
- struct A0;
-
- template<typename T>
- void g0(T &t) {
- t.f0<0;
- t.f0<0>; // expected-error {{expected expression}}
- t.f0<0>1;
-
- t.A0<0;
- t.A0<0>; // expected-error {{expected expression}}
- t.A0<0>1;
- }
-
- template<typename T>
- struct B {
- void f1();
-
- struct A1; // expected-note 3{{member 'A1' declared here}}
-
- void g1() {
- this->f0<0; // expected-error {{no member named 'f0' in 'B<T>'}}
- this->f0<0>; // expected-error {{no member named 'f0' in 'B<T>'}}
- // expected-error at -1 {{expected expression}}
- this->f0<0>1; // expected-error {{no member named 'f0' in 'B<T>'}}
-
- this->A0<0; // expected-error {{no member named 'A0' in 'B<T>'}}
- this->A0<0>; // expected-error {{no member named 'A0' in 'B<T>'}}
- // expected-error at -1 {{expected expression}}
- this->A0<0>1; // expected-error {{no member named 'A0' in 'B<T>'}}
-
- this->f1<0; // expected-error {{reference to non-static member function must be called}}
- this->f1<0>; // expected-error {{reference to non-static member function must be called}}
- // expected-error at -1 {{expected expression}}
- this->f1<0>1; // expected-error {{reference to non-static member function must be called}}
-
- this->A1<0; // expected-error {{cannot refer to type member 'A1' in 'B<T>' with '->'}}
- this->A1<0>; // expected-error {{cannot refer to type member 'A1' in 'B<T>' with '->'}}
- // expected-error at -1 {{expected expression}}
- this->A1<0>1; // expected-error {{cannot refer to type member 'A1' in 'B<T>' with '->'}}
- }
- };
-} // namespace FoundSingleNonTemplate
-
-namespace FoundSingleTemplate {
- template<int I>
- void f0();
-
- template<int I>
- struct A0;
-
- template<typename T>
- void g0(T &t) {
- t.f0<0;
- t.f0<0>; // expected-error {{expected expression}}
- t.f0<0>1;
-
- t.A0<0;
- t.A0<0>; // expected-error {{expected expression}}
- t.A0<0>1;
- }
-
- template<typename T>
- struct B {
- template<int I>
- void f1(); // expected-note 2{{possible target for call}}
-
- template<int I>
- struct A1; // expected-note 2{{member 'A1' declared here}}
-
- void g1() {
- this->f0<0; // expected-error {{no member named 'f0' in 'B<T>'}}
- this->f0<0>; // expected-error {{no member named 'f0' in 'B<T>'}}
- this->f0<0>1; // expected-error {{no member named 'f0' in 'B<T>'}}
- // expected-error at -1 {{expected ';' after expression}}
-
- this->A0<0; // expected-error {{no member named 'A0' in 'B<T>'}}
- this->A0<0>; // expected-error {{no member named 'A0' in 'B<T>'}}
- this->A0<0>1; // expected-error {{no member named 'A0' in 'B<T>'}}
- // expected-error at -1 {{expected ';' after expression}}
-
-
- this->f1<0; // expected-error {{expected '>'}}
- // expected-note at -1 {{to match this '<'}}
- this->f1<0>; // expected-error {{reference to non-static member function must be called}}
- this->f1<0>1; // expected-error {{reference to non-static member function must be called}}
- // expected-error at -1 {{expected ';' after expression}}
-
- this->A1<0; // expected-error {{expected '>'}}
- // expected-note at -1 {{to match this '<'}}
- this->A1<0>; // expected-error {{cannot refer to member 'A1' in 'B<T>' with '->'}}
- this->A1<0>1; // expected-error {{cannot refer to member 'A1' in 'B<T>' with '->'}}
- // expected-error at -1 {{expected ';' after expression}}
- }
- };
-} // namespace FoundSingleTemplate
-
-namespace FoundAmbiguousNonTemplate {
- inline namespace N {
- int f0;
-
- struct A0;
- } // namespace N
-
- void f0();
-
- struct A0;
-
- template<typename T>
- void g0(T &t) {
- t.f0<0;
- t.f0<0>; // expected-error {{expected expression}}
- t.f0<0>1;
-
- t.A0<0;
- t.A0<0>; // expected-error {{expected expression}}
- t.A0<0>1;
- }
-
- template<typename T>
- struct B {
- void f1();
-
- struct A1; // expected-note 3{{member 'A1' declared here}}
-
- void g1() {
- this->f0<0; // expected-error {{no member named 'f0' in 'B<T>'}}
- this->f0<0>; // expected-error {{no member named 'f0' in 'B<T>'}}
- // expected-error at -1 {{expected expression}}
- this->f0<0>1; // expected-error {{no member named 'f0' in 'B<T>'}}
-
- this->A0<0; // expected-error {{no member named 'A0' in 'B<T>'}}
- this->A0<0>; // expected-error {{no member named 'A0' in 'B<T>'}}
- // expected-error at -1 {{expected expression}}
- this->A0<0>1; // expected-error {{no member named 'A0' in 'B<T>'}}
-
- this->f1<0; // expected-error {{reference to non-static member function must be called}}
- this->f1<0>; // expected-error {{reference to non-static member function must be called}}
- // expected-error at -1 {{expected expression}}
- this->f1<0>1; // expected-error {{reference to non-static member function must be called}}
-
- this->A1<0; // expected-error {{cannot refer to type member 'A1' in 'B<T>' with '->'}}
- this->A1<0>; // expected-error {{cannot refer to type member 'A1' in 'B<T>' with '->'}}
- // expected-error at -1 {{expected expression}}
- this->A1<0>1; // expected-error {{cannot refer to type member 'A1' in 'B<T>' with '->'}}
- }
- };
-} // namespace FoundAmbiguousNonTemplates
-
-namespace FoundAmbiguousTemplate {
- inline namespace N {
- template<int I>
- int f0; // expected-note 3{{candidate found by name lookup is 'FoundAmbiguousTemplate::N::f0'}}
-
- template<int I>
- struct A0; // expected-note 3{{candidate found by name lookup is 'FoundAmbiguousTemplate::N::A0'}}
- } // namespace N
-
- template<int I>
- void f0(); // expected-note 3{{candidate found by name lookup is 'FoundAmbiguousTemplate::f0'}}
-
- template<int I>
- struct A0; // expected-note 3{{candidate found by name lookup is 'FoundAmbiguousTemplate::A0'}}
-
- template<typename T>
- void g0(T &t) {
- t.f0<0;
- t.f0<0>; // expected-error {{expected expression}}
- t.f0<0>1;
-
- t.A0<0;
- t.A0<0>; // expected-error {{expected expression}}
- t.A0<0>1;
- }
-
- template<typename T>
- struct B {
- template<int I>
- void f1(); // expected-note 2{{possible target for call}}
-
- template<int I>
- struct A1; // expected-note 2{{member 'A1' declared here}}
-
- void g1() {
- this->f0<0; // expected-error {{no member named 'f0' in 'B<T>'}}
- // expected-error at -1 {{reference to 'f0' is ambiguous}}
- this->f0<0>; // expected-error {{no member named 'f0' in 'B<T>'}}
- // expected-error at -1 {{reference to 'f0' is ambiguous}}
- this->f0<0>1; // expected-error {{no member named 'f0' in 'B<T>'}}
- // expected-error at -1 {{expected ';' after expression}}
- // expected-error at -2 {{reference to 'f0' is ambiguous}}
-
- this->A0<0; // expected-error {{no member named 'A0' in 'B<T>'}}
- // expected-error at -1 {{reference to 'A0' is ambiguous}}
- this->A0<0>; // expected-error {{no member named 'A0' in 'B<T>'}}
- // expected-error at -1 {{reference to 'A0' is ambiguous}}
- this->A0<0>1; // expected-error {{no member named 'A0' in 'B<T>'}}
- // expected-error at -1 {{expected ';' after expression}}
- // expected-error at -2 {{reference to 'A0' is ambiguous}}
-
- this->f1<0; // expected-error {{expected '>'}}
- // expected-note at -1 {{to match this '<'}}
- this->f1<0>; // expected-error {{reference to non-static member function must be called}}
- this->f1<0>1; // expected-error {{reference to non-static member function must be called}}
- // expected-error at -1 {{expected ';' after expression}}
-
- this->A1<0; // expected-error {{expected '>'}}
- // expected-note at -1 {{to match this '<'}}
- this->A1<0>; // expected-error {{cannot refer to member 'A1' in 'B<T>' with '->'}}
- this->A1<0>1; // expected-error {{cannot refer to member 'A1' in 'B<T>' with '->'}}
- // expected-error at -1 {{expected ';' after expression}}
- }
- };
-} // namespace FoundAmbiguousTemplate
diff --git a/clang/test/CXX/temp/temp.res/p3.cpp b/clang/test/CXX/temp/temp.res/p3.cpp
index a4d735e05e9b8..37ab93559e369 100644
--- a/clang/test/CXX/temp/temp.res/p3.cpp
+++ b/clang/test/CXX/temp/temp.res/p3.cpp
@@ -30,6 +30,6 @@ template<typename T> int A<T>::template C<int>::*f5() {} // expected-error {{has
template<typename T> template<typename U> struct A<T>::B {
friend A<T>::C<T> f6(); // ok, same as 'friend T f6();'
- friend A<U>::C<T> f7(); // expected-warning {{use 'template' keyword to treat 'C' as a dependent template name}} expected-warning {{missing 'typename'}}
+ friend A<U>::C<T> f7(); // expected-error {{use 'template' keyword to treat 'C' as a dependent template name}} expected-warning {{missing 'typename'}}
friend A<U>::template C<T> f8(); // expected-warning {{missing 'typename'}}
};
diff --git a/clang/test/FixIt/fixit.cpp b/clang/test/FixIt/fixit.cpp
index 144eefb3ae4bd..605c2d0bd0235 100644
--- a/clang/test/FixIt/fixit.cpp
+++ b/clang/test/FixIt/fixit.cpp
@@ -158,12 +158,12 @@ class F1 {
template<class T>
class F2 {
- typename F1<T>:: /*template*/ Iterator<0> Mypos; // expected-warning {{use 'template' keyword to treat 'Iterator' as a dependent template name}}
+ typename F1<T>:: /*template*/ Iterator<0> Mypos; // expected-error {{use 'template' keyword to treat 'Iterator' as a dependent template name}}
};
template <class T>
void f(){
- typename F1<T>:: /*template*/ Iterator<0> Mypos; // expected-warning {{use 'template' keyword to treat 'Iterator' as a dependent template name}}
+ typename F1<T>:: /*template*/ Iterator<0> Mypos; // expected-error {{use 'template' keyword to treat 'Iterator' as a dependent template name}}
}
// Tests for &/* fixits
diff --git a/clang/test/Misc/warning-flags.c b/clang/test/Misc/warning-flags.c
index 7b993f6849363..cdbe1e95cba96 100644
--- a/clang/test/Misc/warning-flags.c
+++ b/clang/test/Misc/warning-flags.c
@@ -18,7 +18,7 @@ This test serves two purposes:
The list of warnings below should NEVER grow. It should gradually shrink to 0.
-CHECK: Warnings without flags (64):
+CHECK: Warnings without flags (65):
CHECK-NEXT: ext_expected_semi_decl_list
CHECK-NEXT: ext_missing_whitespace_after_macro_name
@@ -61,6 +61,7 @@ CHECK-NEXT: warn_invalid_cpu_supports
CHECK-NEXT: warn_maynot_respond
CHECK-NEXT: warn_method_param_redefinition
CHECK-NEXT: warn_missing_case_for_condition
+CHECK-NEXT: warn_missing_dependent_template_keyword
CHECK-NEXT: warn_missing_whitespace_after_macro_name
CHECK-NEXT: warn_mt_message
CHECK-NEXT: warn_no_constructor_for_refconst
diff --git a/clang/test/Parser/cxx2a-concepts-requires-expr.cpp b/clang/test/Parser/cxx2a-concepts-requires-expr.cpp
index 0c7f453b5c48d..5755844a323d2 100644
--- a/clang/test/Parser/cxx2a-concepts-requires-expr.cpp
+++ b/clang/test/Parser/cxx2a-concepts-requires-expr.cpp
@@ -78,7 +78,7 @@ bool r22 = requires { typename s::~s; };
template<typename T>
bool r23 = requires { typename identity<T>::temp<T>; };
-// expected-warning at -1 {{use 'template' keyword to treat 'temp' as a dependent template name}}
+// expected-error at -1 {{use 'template' keyword to treat 'temp' as a dependent template name}}
template<typename T>
bool r24 = requires {
diff --git a/clang/test/SemaCXX/cxx0x-noexcept-expression.cpp b/clang/test/SemaCXX/cxx0x-noexcept-expression.cpp
index a01edc77e02af..b3c102830f359 100644
--- a/clang/test/SemaCXX/cxx0x-noexcept-expression.cpp
+++ b/clang/test/SemaCXX/cxx0x-noexcept-expression.cpp
@@ -127,7 +127,7 @@ void f1() {
// `dependent` should be type-dependent because the noexcept-expression should be value-dependent
// (it is true if T is int*, false if T is Polymorphic<false, false>* for example)
dependent.f<void>(); // This should need to be `.template f` to parse as a template
- // expected-warning at -1 {{use 'template' keyword to treat 'f' as a dependent template name}}
+ // expected-error at -1 {{use 'template' keyword to treat 'f' as a dependent template name}}
}
template<typename... T>
void f2() {
@@ -135,14 +135,14 @@ void f2() {
// X<true> when T...[0] is a type with some operator&& which returns int*
// X<false> when sizeof...(T) == 0
dependent.f<void>();
- // expected-warning at -1 {{use 'template' keyword to treat 'f' as a dependent template name}}
+ // expected-error at -1 {{use 'template' keyword to treat 'f' as a dependent template name}}
}
template<typename T>
void f3() {
X<noexcept(typeid(*static_cast<T*>(nullptr)))> dependent;
// X<true> when T is int, X<false> when T is Polymorphic<false, false>
dependent.f<void>();
- // expected-warning at -1 {{use 'template' keyword to treat 'f' as a dependent template name}}
+ // expected-error at -1 {{use 'template' keyword to treat 'f' as a dependent template name}}
}
template<typename T>
void f4() {
diff --git a/clang/test/SemaCXX/pseudo-destructors.cpp b/clang/test/SemaCXX/pseudo-destructors.cpp
index 44dc9ce8b1520..55a96002be2ab 100644
--- a/clang/test/SemaCXX/pseudo-destructors.cpp
+++ b/clang/test/SemaCXX/pseudo-destructors.cpp
@@ -22,21 +22,21 @@ void cv_test(const volatile T* cvt) {
void f(A* a, Foo *f, int *i, double *d, int ii) {
a->~A();
a->A::~A();
-
+
a->~foo(); // expected-error{{undeclared identifier 'foo' in destructor name}}
-
+
a->~Bar(); // expected-error{{destructor type 'Bar' (aka 'Foo') in object destruction expression does not match the type 'A' of the object being destroyed}}
-
+
f->~Bar();
f->~Foo();
i->~Bar(); // expected-error{{does not match}}
-
+
g().~Bar(); // expected-error{{non-scalar}}
-
+
f->::~Bar(); // expected-error {{not a structure or union}}
f->::Bar::~Bar();
f->N::~Wibble(); // expected-error{{'N' does not refer to a type}} expected-error{{'Wibble' does not refer to a type}}
-
+
f->Bar::~Bar(17, 42); // expected-error{{cannot have any arguments}}
i->~Integer();
@@ -148,12 +148,12 @@ namespace TwoPhaseLookup {
namespace Template {
template<typename T> struct Y {};
template<class U> using G = Y<U>;
- template<typename T> void f(T *p) { p->~G<int>(); } // expected-error {{no member named 'G'}}
+ template<typename T> void f(T *p) { p->~G<int>(); } // expected-error {{no member named '~Y'}}
void h1(Y<int> *p) { p->~G<int>(); }
- void h2(Y<int> *p) { f(p); } // expected-note {{instantiation of}}
+ void h2(Y<int> *p) { f(p); }
namespace N { template<typename T> struct G {}; }
void h3(N::G<int> *p) { p->~G<int>(); }
- void h4(N::G<int> *p) { f(p); }
+ void h4(N::G<int> *p) { f(p); } // expected-note {{instantiation of}}
}
namespace TemplateUndeclared {
diff --git a/clang/test/SemaCXX/static-assert-cxx17.cpp b/clang/test/SemaCXX/static-assert-cxx17.cpp
index 754f4ae5f1d38..41a7b025d0eb7 100644
--- a/clang/test/SemaCXX/static-assert-cxx17.cpp
+++ b/clang/test/SemaCXX/static-assert-cxx17.cpp
@@ -96,7 +96,7 @@ void foo6() {
// expected-error at -1{{static assertion failed due to requirement 'static_cast<const X<int> *>(nullptr)'}}
static_assert((const X<typename T::T>[]){} == nullptr);
// expected-error at -1{{static assertion failed due to requirement '(const X<int>[0]){} == nullptr'}}
- static_assert(sizeof(X<decltype(X<typename T::T>().template X<typename T::T>::~X())>) == 0);
+ static_assert(sizeof(X<decltype(X<typename T::T>().X<typename T::T>::~X())>) == 0);
// expected-error at -1{{static assertion failed due to requirement 'sizeof(X<void>) == 0'}} \
// expected-note at -1 {{evaluates to '8 == 0'}}
static_assert(constexpr_return_false<typename T::T, typename T::U>());
diff --git a/clang/test/SemaTemplate/dependent-base-classes.cpp b/clang/test/SemaTemplate/dependent-base-classes.cpp
index 4cb88a5b4070a..92a37efaa7e73 100644
--- a/clang/test/SemaTemplate/dependent-base-classes.cpp
+++ b/clang/test/SemaTemplate/dependent-base-classes.cpp
@@ -1,12 +1,12 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
template<typename T, typename U>
-struct X0 : T::template apply<U> {
+struct X0 : T::template apply<U> {
X0(U u) : T::template apply<U>(u) { }
};
template<typename T, typename U>
-struct X1 : T::apply<U> { }; // expected-warning{{use 'template' keyword to treat 'apply' as a dependent template name}}
+struct X1 : T::apply<U> { }; // expected-error{{use 'template' keyword to treat 'apply' as a dependent template name}}
template<typename T>
struct X2 : vector<T> { }; // expected-error{{no template named 'vector'}}
@@ -85,7 +85,7 @@ namespace PR6081 {
struct A { };
template<typename T>
- class B : public A<T>
+ class B : public A<T>
{
public:
template< class X >
@@ -109,9 +109,9 @@ namespace PR6081 {
namespace PR6413 {
template <typename T> class Base_A { };
-
+
class Base_B { };
-
+
template <typename T>
class Derived
: public virtual Base_A<T>
@@ -120,12 +120,12 @@ namespace PR6413 {
}
namespace PR5812 {
- template <class T> struct Base {
- Base* p;
- };
+ template <class T> struct Base {
+ Base* p;
+ };
- template <class T> struct Derived: public Base<T> {
- typename Derived::Base* p; // meaning Derived::Base<T>
+ template <class T> struct Derived: public Base<T> {
+ typename Derived::Base* p; // meaning Derived::Base<T>
};
Derived<int> di;
diff --git a/clang/test/SemaTemplate/dependent-template-recover.cpp b/clang/test/SemaTemplate/dependent-template-recover.cpp
index c763989e6dadb..c7e27e8da25f1 100644
--- a/clang/test/SemaTemplate/dependent-template-recover.cpp
+++ b/clang/test/SemaTemplate/dependent-template-recover.cpp
@@ -2,15 +2,15 @@
template<typename T, typename U, int N>
struct X {
void f(T* t) {
- t->f0<U>(); // expected-warning{{use 'template' keyword to treat 'f0' as a dependent template name}}
- t->f0<int>(); // expected-warning{{use 'template' keyword to treat 'f0' as a dependent template name}}
+ t->f0<U>(); // expected-error{{use 'template' keyword to treat 'f0' as a dependent template name}}
+ t->f0<int>(); // expected-error{{use 'template' keyword to treat 'f0' as a dependent template name}}
- t->operator+<U const, 1>(1); // expected-warning{{use 'template' keyword to treat 'operator +' as a dependent template name}}
- t->f1<int const, 2>(1); // expected-warning{{use 'template' keyword to treat 'f1' as a dependent template name}}
+ t->operator+<U const, 1>(1); // expected-error{{use 'template' keyword to treat 'operator +' as a dependent template name}}
+ t->f1<int const, 2>(1); // expected-error{{use 'template' keyword to treat 'f1' as a dependent template name}}
t->f1<3, int const>(1); // expected-error{{missing 'template' keyword prior to dependent template name 'f1'}}
- T::getAs<U>(); // expected-warning{{use 'template' keyword to treat 'getAs' as a dependent template name}}
- t->T::getAs<U>(); // expected-warning{{use 'template' keyword to treat 'getAs' as a dependent template name}}
+ T::getAs<U>(); // expected-error{{use 'template' keyword to treat 'getAs' as a dependent template name}}
+ t->T::getAs<U>(); // expected-error{{use 'template' keyword to treat 'getAs' as a dependent template name}}
(*t).f2<N>(); // expected-error{{missing 'template' keyword prior to dependent template name 'f2'}}
(*t).f2<0>(); // expected-error{{missing 'template' keyword prior to dependent template name 'f2'}}
diff --git a/clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp b/clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp
index 7768d2f03ac5b..ad73daa8e214c 100644
--- a/clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp
+++ b/clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp
@@ -115,7 +115,7 @@ namespace CopyCounting {
static_assert(f(X<A{}>()) == 0);
template<A a> struct Y { void f(); };
- template<A a> void g(Y<a> y) { y.template Y<a>::f(); }
+ template<A a> void g(Y<a> y) { y.Y<a>::f(); }
void h() { constexpr A a; g<a>(Y<a>{}); }
template<A a> struct Z {
diff --git a/clang/test/SemaTemplate/template-id-expr.cpp b/clang/test/SemaTemplate/template-id-expr.cpp
index 760d6c5852403..dc12823ae307f 100644
--- a/clang/test/SemaTemplate/template-id-expr.cpp
+++ b/clang/test/SemaTemplate/template-id-expr.cpp
@@ -19,7 +19,7 @@ template<typename T>
struct X0 {
template<typename U>
void f1();
-
+
template<typename U>
void f2(U) {
f1<U>();
@@ -39,9 +39,9 @@ struct Y {
template<int I>
struct X {
X(int, int);
- void f() {
- Y<X<I> >(X<I>(0, 0));
- Y<X<I> >(::X<I>(0, 0));
+ void f() {
+ Y<X<I> >(X<I>(0, 0));
+ Y<X<I> >(::X<I>(0, 0));
}
};
@@ -149,11 +149,11 @@ struct Y2 : Y1<T> {
int x;
x = Y1::f4(0);
- x = Y1::f4<int>(0); // expected-warning {{use 'template'}} expected-error {{assigning to 'int' from incompatible type 'void'}}
+ x = Y1::f4<int>(0); // expected-error {{use 'template'}} expected-error {{assigning to 'int' from incompatible type 'void'}}
x = Y1::template f4(0); // expected-error {{assigning to 'int' from incompatible type 'void'}} expected-error {{a template argument list is expected after a name prefixed by the template keyword}}
x = p->f4(0);
- x = p->f4<int>(0); // expected-error {{assigning to 'int' from incompatible type 'void'}} expected-warning {{use 'template'}}
+ x = p->f4<int>(0); // expected-error {{assigning to 'int' from incompatible type 'void'}} expected-error {{use 'template'}}
x = p->template f4(0); // expected-error {{assigning to 'int' from incompatible type 'void'}} expected-error {{a template argument list is expected after a name prefixed by the template keyword}}
}
};
@@ -184,7 +184,7 @@ class E {
#if __cplusplus <= 199711L
// expected-warning at +2 {{extension}}
#endif
-template<typename T> using D = int; // expected-note {{declared here}}
+template<typename T> using D = int; // expected-note {{declared here}}
E<D> ed; // expected-note {{instantiation of}}
namespace non_functions {
diff --git a/clang/test/SemaTemplate/typename-specifier-3.cpp b/clang/test/SemaTemplate/typename-specifier-3.cpp
index a9010969322e5..714830f0032d2 100644
--- a/clang/test/SemaTemplate/typename-specifier-3.cpp
+++ b/clang/test/SemaTemplate/typename-specifier-3.cpp
@@ -46,7 +46,7 @@ namespace PR12884_half_fixed {
typedef int arg;
};
struct C {
- typedef typename B::X<typename B::arg> x; // expected-warning {{use 'template'}} expected-error {{refers to non-type}}
+ typedef typename B::X<typename B::arg> x; // expected-error {{use 'template'}} expected-error {{refers to non-type}}
};
};
diff --git a/libcxx/include/regex b/libcxx/include/regex
index 17ad0cf5b2aea..b814135121321 100644
--- a/libcxx/include/regex
+++ b/libcxx/include/regex
@@ -4214,7 +4214,7 @@ public:
_LIBCPP_HIDE_FROM_ABI int compare(const value_type* __s) const { return str().compare(__s); }
_LIBCPP_HIDE_FROM_ABI void swap(sub_match& __s) _NOEXCEPT_(__is_nothrow_swappable_v<_BidirectionalIterator>) {
- this->template pair<_BidirectionalIterator, _BidirectionalIterator>::swap(__s);
+ this->pair<_BidirectionalIterator, _BidirectionalIterator>::swap(__s);
std::swap(matched, __s.matched);
}
};
diff --git a/llvm/include/llvm/ADT/ArrayRef.h b/llvm/include/llvm/ADT/ArrayRef.h
index 1c6799f1c56ed..ac40ec4a6b240 100644
--- a/llvm/include/llvm/ADT/ArrayRef.h
+++ b/llvm/include/llvm/ADT/ArrayRef.h
@@ -460,11 +460,8 @@ namespace llvm {
OwningArrayRef &operator=(OwningArrayRef &&Other) {
delete[] this->data();
- using Base = MutableArrayRef<T>;
- // GCC versions prior to 11.1 incorrectly reject if the 'template' keyword
- // is used prior to the nested-name-specifier here.
- this->Base::operator=(Other);
- Other.Base::operator=(Base());
+ this->MutableArrayRef<T>::operator=(Other);
+ Other.MutableArrayRef<T>::operator=(MutableArrayRef<T>());
return *this;
}
More information about the libcxx-commits
mailing list