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
This commit is contained in:
parent
6484655f9d
commit
59e56eeb1d
@ -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
|
||||
------------------
|
||||
|
||||
|
@ -3676,9 +3676,9 @@ public:
|
||||
/// 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 @@ public:
|
||||
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;
|
||||
SourceLocation getOperatorLoc() const {
|
||||
return CXXDependentScopeMemberExprBits.OperatorLoc;
|
||||
}
|
||||
|
||||
/// 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>();
|
||||
}
|
||||
|
||||
/// 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.
|
||||
|
@ -1020,19 +1020,18 @@ protected:
|
||||
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 {
|
||||
|
@ -97,10 +97,6 @@ public:
|
||||
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
|
||||
|
@ -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>;
|
||||
|
@ -3372,11 +3372,15 @@ private:
|
||||
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);
|
||||
|
@ -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 @@ public:
|
||||
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();
|
||||
|
@ -483,15 +483,11 @@ public:
|
||||
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
|
||||
|
@ -2803,8 +2803,7 @@ public:
|
||||
/// (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 @@ public:
|
||||
/// \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 @@ public:
|
||||
/// not '::'.
|
||||
/// \param OnlyNamespace If true, only considers namespaces in lookup.
|
||||
///
|
||||
/// This routine differs 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 @@ public:
|
||||
/// 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 @@ public:
|
||||
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 @@ public:
|
||||
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 @@ public:
|
||||
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 @@ public:
|
||||
/// 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,
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -594,10 +594,11 @@ private:
|
||||
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 @@ recurse:
|
||||
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 @@ recurse:
|
||||
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 @@ recurse:
|
||||
= 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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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 @@ public:
|
||||
|
||||
bool Sema::BuildCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo,
|
||||
bool EnteringContext, CXXScopeSpec &SS,
|
||||
NamedDecl *ScopeLookupResult,
|
||||
bool ErrorRecoveryLookup,
|
||||
bool *IsCorrectedToColon,
|
||||
bool OnlyNamespace) {
|
||||
if (IdInfo.Identifier->isEditorPlaceholder())
|
||||
return true;
|
||||
if (IsCorrectedToColon)
|
||||
*IsCorrectedToColon = false;
|
||||
|
||||
QualType ObjectType = GetTypeFromParser(IdInfo.ObjectType);
|
||||
LookupResult Found(*this, IdInfo.Identifier, IdInfo.IdentifierLoc,
|
||||
OnlyNamespace ? LookupNamespaceName
|
||||
: LookupNestedNameSpecifierName);
|
||||
QualType ObjectType = GetTypeFromParser(IdInfo.ObjectType);
|
||||
|
||||
// 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.
|
||||
|
||||
// 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();
|
||||
// The declaration context must be complete.
|
||||
if (!LookupCtx->isDependentContext() &&
|
||||
RequireCompleteDeclContext(SS, LookupCtx))
|
||||
return true;
|
||||
|
||||
LookupQualifiedName(Found, LookupCtx);
|
||||
|
||||
if (!ObjectType.isNull() && Found.empty()) {
|
||||
// C++ [basic.lookup.classref]p4:
|
||||
// If the id-expression in a class member access is a qualified-id of
|
||||
// the form
|
||||
//
|
||||
// class-name-or-namespace-name::...
|
||||
//
|
||||
// the class-name-or-namespace-name following the . or -> operator is
|
||||
// looked up both in the context of the entire postfix-expression and in
|
||||
// the scope of the class of the object expression. If the name is found
|
||||
// only in the scope of the class of the object expression, the name
|
||||
// shall refer to a class-name. If the name is found only in the
|
||||
// context of the entire postfix-expression, the name shall refer to a
|
||||
// class-name or namespace-name. [...]
|
||||
//
|
||||
// Qualified name lookup into a class will not find a namespace-name,
|
||||
// so we do not need to diagnose that case specifically. However,
|
||||
// this qualified name lookup may find nothing. In that case, perform
|
||||
// unqualified name lookup in the given scope (if available) or
|
||||
// reconstruct the result from when name lookup was performed at template
|
||||
// definition time.
|
||||
if (S)
|
||||
LookupName(Found, S);
|
||||
else if (ScopeLookupResult)
|
||||
Found.addDecl(ScopeLookupResult);
|
||||
|
||||
ObjectTypeSearchedInScope = true;
|
||||
}
|
||||
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
|
||||
// different 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,
|
||||
|
@ -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();
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
// Determine where to perform name lookup
|
||||
DeclContext *LookupCtx = nullptr;
|
||||
bool IsDependent = false;
|
||||
if (!ObjectType.isNull()) {
|
||||
// This nested-name-specifier occurs in a member access expression, e.g.,
|
||||
// x->B::f, and we are looking into the type of the object.
|
||||
assert(SS.isEmpty() && "ObjectType and scope specifier cannot coexist");
|
||||
LookupCtx = computeDeclContext(ObjectType);
|
||||
IsDependent = !LookupCtx && ObjectType->isDependentType();
|
||||
assert((IsDependent || !ObjectType->isIncompleteType() ||
|
||||
!ObjectType->getAs<TagType>() ||
|
||||
ObjectType->castAs<TagType>()->isBeingDefined()) &&
|
||||
"Caller should have completed object type");
|
||||
|
||||
// Template names cannot appear inside an Objective-C class or object type
|
||||
// or a vector type.
|
||||
//
|
||||
// FIXME: This is wrong. For example:
|
||||
//
|
||||
// template<typename T> using Vec = T __attribute__((ext_vector_type(4)));
|
||||
// Vec<int> vi;
|
||||
// vi.Vec<int>::~Vec<int>();
|
||||
//
|
||||
// ... should be accepted but we will not treat 'Vec' as a template name
|
||||
// here. The right thing to do would be to check if the name is a valid
|
||||
// vector component name, and look up a template name if not. And similarly
|
||||
// for lookups into Objective-C class and object types, where the same
|
||||
// problem can arise.
|
||||
if (ObjectType->isObjCObjectOrInterfaceType() ||
|
||||
ObjectType->isVectorType()) {
|
||||
Found.clear();
|
||||
return false;
|
||||
}
|
||||
} else if (SS.isNotEmpty()) {
|
||||
// This nested-name-specifier occurs after another nested-name-specifier,
|
||||
// so long into the context associated with the prior nested-name-specifier.
|
||||
LookupCtx = computeDeclContext(SS, EnteringContext);
|
||||
IsDependent = !LookupCtx && isDependentScopeSpecifier(SS);
|
||||
|
||||
// The declaration context must be complete.
|
||||
if (LookupCtx && RequireCompleteDeclContext(SS, LookupCtx))
|
||||
return true;
|
||||
}
|
||||
|
||||
LookupParsedName(Found, S, &SS, ObjectType,
|
||||
/*AllowBuiltinCreation=*/false, EnteringContext);
|
||||
|
||||
// C++ [basic.lookup.qual.general]p3:
|
||||
// [...] Unless otherwise specified, a qualified name undergoes qualified
|
||||
// name lookup in its lookup context from the point where it appears unless
|
||||
// the lookup context either is dependent and is not the current
|
||||
// instantiation or is not a class or class template.
|
||||
//
|
||||
// The lookup context is dependent and either:
|
||||
// - it is not the current instantiation, or
|
||||
// - it is the current instantiation, it has at least one dependent base
|
||||
// class, and qualified lookup found nothing.
|
||||
//
|
||||
// If this is a member-qualified name that is the terminal name of a
|
||||
// nested-name-specifier, we perform unqualified lookup and store the results
|
||||
// so we can replicate the lookup during instantiation. The results of the
|
||||
// unqualified loookup are *not* used to determine whether '<' is interpreted
|
||||
// as the delimiter of a template-argument-list.
|
||||
//
|
||||
// For example:
|
||||
//
|
||||
// template<typename T>
|
||||
// struct A {
|
||||
// int x;
|
||||
// };
|
||||
//
|
||||
// template<typename T>
|
||||
// using B = A<T>;
|
||||
//
|
||||
// template<typename T>
|
||||
// void f(A<T> a, A<int> b) {
|
||||
// a.B<T>::x; // error: missing 'template' before 'B'
|
||||
// b.B<int>::x; // ok, lookup context is not dependent
|
||||
// }
|
||||
if (Found.wasNotFoundInCurrentInstantiation())
|
||||
return false;
|
||||
|
||||
bool ObjectTypeSearchedInScope = false;
|
||||
bool AllowFunctionTemplatesInLookup = true;
|
||||
if (LookupCtx) {
|
||||
// Perform "qualified" name lookup into the declaration context we
|
||||
// computed, which is either the type of the base of a member access
|
||||
// expression or the declaration context associated with a prior
|
||||
// nested-name-specifier.
|
||||
LookupQualifiedName(Found, LookupCtx);
|
||||
|
||||
// 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) {
|
||||
// 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)
|
||||
|
@ -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
|
||||
|
@ -541,9 +541,10 @@ public:
|
||||
/// By default, transforms all of the types and declarations within the
|
||||
/// nested-name-specifier. Subclasses may override this function to provide
|
||||
/// alternate behavior.
|
||||
NestedNameSpecifierLoc TransformNestedNameSpecifierLoc(
|
||||
NestedNameSpecifierLoc NNS, QualType ObjectType = QualType(),
|
||||
ArrayRef<DeclAccessPair> UnqualifiedLookups = std::nullopt);
|
||||
NestedNameSpecifierLoc
|
||||
TransformNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS,
|
||||
QualType ObjectType = QualType(),
|
||||
NamedDecl *FirstQualifierInScope = nullptr);
|
||||
|
||||
/// Transform the given declaration name.
|
||||
///
|
||||
@ -584,11 +585,12 @@ public:
|
||||
/// By default, transforms the template name by transforming the declarations
|
||||
/// and nested-name-specifiers that occur within the template name.
|
||||
/// Subclasses may override this function to provide alternate behavior.
|
||||
TemplateName TransformTemplateName(CXXScopeSpec &SS, TemplateName Name,
|
||||
SourceLocation NameLoc,
|
||||
QualType ObjectType = QualType(),
|
||||
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 @@ public:
|
||||
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 @@ public:
|
||||
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 @@ public:
|
||||
///
|
||||
/// By default, performs semantic analysis to build the new expression.
|
||||
/// Subclasses may override this routine to provide different behavior.
|
||||
ExprResult
|
||||
RebuildMemberExpr(Expr *Base, SourceLocation OpLoc, bool isArrow,
|
||||
NestedNameSpecifierLoc QualifierLoc,
|
||||
SourceLocation TemplateKWLoc,
|
||||
const DeclarationNameInfo &MemberNameInfo,
|
||||
ValueDecl *Member, NamedDecl *FoundDecl,
|
||||
const TemplateArgumentListInfo *ExplicitTemplateArgs,
|
||||
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 @@ public:
|
||||
|
||||
CXXScopeSpec SS;
|
||||
SS.Adopt(QualifierLoc);
|
||||
SS.setUnqualifiedLookups(UnqualifiedLookups);
|
||||
|
||||
Base = BaseResult.get();
|
||||
if (Base->containsErrors())
|
||||
@ -2923,9 +2926,10 @@ public:
|
||||
}
|
||||
|
||||
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 @@ public:
|
||||
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 @@ public:
|
||||
///
|
||||
/// By default, performs semantic analysis to build the new expression.
|
||||
/// Subclasses may override this routine to provide different behavior.
|
||||
ExprResult RebuildCXXDependentScopeMemberExpr(
|
||||
Expr *BaseE, QualType BaseType, bool IsArrow, SourceLocation OperatorLoc,
|
||||
NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc,
|
||||
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 different 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 @@ public:
|
||||
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 @@ public:
|
||||
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 @@ public:
|
||||
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 @@ public:
|
||||
}
|
||||
|
||||
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 @@ TreeTransform<Derived>
|
||||
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>
|
||||
|
@ -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->CXXDependentScopeMemberExprBits.OperatorLoc = readSourceLocation();
|
||||
|
||||
if (HasFirstQualifierFoundInScope)
|
||||
*E->getTrailingObjects<NamedDecl *>() = readDeclAs<NamedDecl>();
|
||||
|
||||
E->MemberNameInfo = Record.readDeclarationNameInfo();
|
||||
|
||||
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 (HasTemplateInfo)
|
||||
ReadTemplateKWAndArgsInfo(
|
||||
*E->getTrailingObjects<ASTTemplateKWAndArgsInfo>(),
|
||||
E->getTrailingObjects<TemplateArgumentLoc>(), NumTemplateArgs);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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>());
|
||||
}
|
||||
|
||||
CurrentPackingBits.addBit(E->isArrow());
|
||||
|
||||
Record.AddTypeRef(E->getBaseType());
|
||||
CurrentPackingBits.addBit(E->isArrow());
|
||||
Record.AddNestedNameSpecifierLoc(E->getQualifierLoc());
|
||||
CurrentPackingBits.addBit(!E->isImplicitAccess());
|
||||
if (!E->isImplicitAccess())
|
||||
Record.AddStmt(E->getBase());
|
||||
|
||||
Record.AddSourceLocation(E->getOperatorLoc());
|
||||
|
||||
if (E->hasFirstQualifierFoundInScope())
|
||||
Record.AddDeclRef(E->getFirstQualifierFoundInScope());
|
||||
|
||||
Record.AddDeclarationNameInfo(E->MemberNameInfo);
|
||||
|
||||
if (HasQualifier)
|
||||
Record.AddNestedNameSpecifierLoc(E->getQualifierLoc());
|
||||
|
||||
for (DeclAccessPair D : E->unqualified_lookups()) {
|
||||
Record.AddDeclRef(D.getDecl());
|
||||
Record.push_back(D.getAccess());
|
||||
}
|
||||
|
||||
if (HasTemplateInfo)
|
||||
AddTemplateKWAndArgsInfo(*E->getTrailingObjects<ASTTemplateKWAndArgsInfo>(),
|
||||
E->getTrailingObjects<TemplateArgumentLoc>());
|
||||
|
||||
Code = serialization::EXPR_CXX_DEPENDENT_SCOPE_MEMBER;
|
||||
}
|
||||
|
||||
|
@ -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'}}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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'}}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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}}
|
@ -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
|
@ -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>'}}
|
||||
}
|
||||
|
||||
|
@ -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@-1 {{no member named 'f' in 'cwg141::B'}}
|
||||
// expected-error@-2 +{{}}
|
||||
(void)b.S<int>::n;
|
||||
}
|
||||
template<typename T> struct C {
|
||||
@ -626,12 +628,10 @@ namespace cwg141 { // cwg141: 3.1
|
||||
// expected-error@-1 {{use 'template' keyword to treat 'f' as a dependent template name}}
|
||||
}
|
||||
void h() {
|
||||
(void)t.S<int>::n;
|
||||
// expected-error@-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@-1 {{use 'template' keyword to treat 'S' as a dependent template name}}
|
||||
(void)t.S<int>(); // ok!
|
||||
}
|
||||
};
|
||||
void h() { C<B>().h(); } // ok
|
||||
|
@ -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@-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@-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@-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@-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@-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@-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@-1 {{expected ';' after expression}}
|
||||
|
||||
|
||||
this->f1<0; // expected-error {{expected '>'}}
|
||||
// expected-note@-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@-1 {{expected ';' after expression}}
|
||||
|
||||
this->A1<0; // expected-error {{expected '>'}}
|
||||
// expected-note@-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@-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@-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@-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@-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@-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@-1 {{reference to 'f0' is ambiguous}}
|
||||
this->f0<0>; // expected-error {{no member named 'f0' in 'B<T>'}}
|
||||
// expected-error@-1 {{reference to 'f0' is ambiguous}}
|
||||
this->f0<0>1; // expected-error {{no member named 'f0' in 'B<T>'}}
|
||||
// expected-error@-1 {{expected ';' after expression}}
|
||||
// expected-error@-2 {{reference to 'f0' is ambiguous}}
|
||||
|
||||
this->A0<0; // expected-error {{no member named 'A0' in 'B<T>'}}
|
||||
// expected-error@-1 {{reference to 'A0' is ambiguous}}
|
||||
this->A0<0>; // expected-error {{no member named 'A0' in 'B<T>'}}
|
||||
// expected-error@-1 {{reference to 'A0' is ambiguous}}
|
||||
this->A0<0>1; // expected-error {{no member named 'A0' in 'B<T>'}}
|
||||
// expected-error@-1 {{expected ';' after expression}}
|
||||
// expected-error@-2 {{reference to 'A0' is ambiguous}}
|
||||
|
||||
this->f1<0; // expected-error {{expected '>'}}
|
||||
// expected-note@-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@-1 {{expected ';' after expression}}
|
||||
|
||||
this->A1<0; // expected-error {{expected '>'}}
|
||||
// expected-note@-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@-1 {{expected ';' after expression}}
|
||||
}
|
||||
};
|
||||
} // namespace FoundAmbiguousTemplate
|
@ -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'}}
|
||||
};
|
||||
|
@ -158,12 +158,12 @@ public:
|
||||
|
||||
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
|
||||
|
@ -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
|
||||
|
@ -78,7 +78,7 @@ bool r22 = requires { typename s::~s; };
|
||||
|
||||
template<typename T>
|
||||
bool r23 = requires { typename identity<T>::temp<T>; };
|
||||
// expected-warning@-1 {{use 'template' keyword to treat 'temp' as a dependent template name}}
|
||||
// expected-error@-1 {{use 'template' keyword to treat 'temp' as a dependent template name}}
|
||||
|
||||
template<typename T>
|
||||
bool r24 = requires {
|
||||
|
@ -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@-1 {{use 'template' keyword to treat 'f' as a dependent template name}}
|
||||
// expected-error@-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@-1 {{use 'template' keyword to treat 'f' as a dependent template name}}
|
||||
// expected-error@-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@-1 {{use 'template' keyword to treat 'f' as a dependent template name}}
|
||||
// expected-error@-1 {{use 'template' keyword to treat 'f' as a dependent template name}}
|
||||
}
|
||||
template<typename T>
|
||||
void f4() {
|
||||
|
@ -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 {
|
||||
|
@ -96,7 +96,7 @@ void foo6() {
|
||||
// expected-error@-1{{static assertion failed due to requirement 'static_cast<const X<int> *>(nullptr)'}}
|
||||
static_assert((const X<typename T::T>[]){} == nullptr);
|
||||
// expected-error@-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@-1{{static assertion failed due to requirement 'sizeof(X<void>) == 0'}} \
|
||||
// expected-note@-1 {{evaluates to '8 == 0'}}
|
||||
static_assert(constexpr_return_false<typename T::T, typename T::U>());
|
||||
|
@ -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;
|
||||
|
@ -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'}}
|
||||
|
@ -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 {
|
||||
|
@ -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@+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 {
|
||||
|
@ -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}}
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user