https://github.com/sdkrystian updated https://github.com/llvm/llvm-project/pull/84050
>From 67d9b107a1e5dde52769f6e7d9dc41b1d777cb60 Mon Sep 17 00:00:00 2001 From: Krystian Stasiowski <sdkryst...@gmail.com> Date: Fri, 1 Mar 2024 08:08:52 -0500 Subject: [PATCH 01/14] [Clang][Sema] Earlier resolution of class member access expressions naming member of the current instantiation --- clang/lib/AST/Expr.cpp | 2 +- clang/lib/Sema/SemaExpr.cpp | 4 +- clang/lib/Sema/SemaExprMember.cpp | 121 ++++++++++++++------ clang/lib/Sema/SemaOverload.cpp | 3 + clang/test/SemaTemplate/dependent-names.cpp | 4 +- 5 files changed, 93 insertions(+), 41 deletions(-) diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 131dace77f9c25..e60360435c32a5 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -103,7 +103,7 @@ const Expr *Expr::skipRValueSubobjectAdjustments( } } else if (const auto *ME = dyn_cast<MemberExpr>(E)) { if (!ME->isArrow()) { - assert(ME->getBase()->getType()->isRecordType()); + assert(ME->getBase()->getType()->getAsRecordDecl()); if (const auto *Field = dyn_cast<FieldDecl>(ME->getMemberDecl())) { if (!Field->isBitField() && !Field->getType()->isReferenceType()) { E = ME->getBase(); diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 8725b09f8546cf..31d902b3572413 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -666,7 +666,9 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) { // expressions of certain types in C++. if (getLangOpts().CPlusPlus && (E->getType() == Context.OverloadTy || - T->isDependentType() || + // FIXME: This is a hack! We want the lvalue-to-rvalue conversion applied + // to pointer types even if the pointee type is dependent. + (T->isDependentType() && !T->isPointerType()) || T->isRecordType())) return E; diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp index 32998ae60eafe2..fd55e6f46a1066 100644 --- a/clang/lib/Sema/SemaExprMember.cpp +++ b/clang/lib/Sema/SemaExprMember.cpp @@ -624,8 +624,8 @@ namespace { // classes, one of its base classes. class RecordMemberExprValidatorCCC final : public CorrectionCandidateCallback { public: - explicit RecordMemberExprValidatorCCC(const RecordType *RTy) - : Record(RTy->getDecl()) { + explicit RecordMemberExprValidatorCCC(QualType RTy) + : Record(RTy->getAsRecordDecl()) { // Don't add bare keywords to the consumer since they will always fail // validation by virtue of not being associated with any decls. WantTypeSpecifiers = false; @@ -671,33 +671,55 @@ class RecordMemberExprValidatorCCC final : public CorrectionCandidateCallback { static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, Expr *BaseExpr, - const RecordType *RTy, + QualType RTy, SourceLocation OpLoc, bool IsArrow, CXXScopeSpec &SS, bool HasTemplateArgs, SourceLocation TemplateKWLoc, TypoExpr *&TE) { + RecordDecl *RDecl = RTy->getAsRecordDecl(); + DeclContext *DC = SemaRef.computeDeclContext(RTy); + // If the object expression is dependent and isn't the current instantiation, + // lookup will not find anything and we must defer until instantiation. + if (!DC) { + R.setNotFoundInCurrentInstantiation(); + return false; + } + + // FIXME: Should this use Name.isDependentName()? + if (DeclarationName Name = R.getLookupName(); + Name.getNameKind() == DeclarationName::CXXConversionFunctionName && + Name.getCXXNameType()->isDependentType()) { + R.setNotFoundInCurrentInstantiation(); + return false; + } + SourceRange BaseRange = BaseExpr ? BaseExpr->getSourceRange() : SourceRange(); - RecordDecl *RDecl = RTy->getDecl(); - if (!SemaRef.isThisOutsideMemberFunctionBody(QualType(RTy, 0)) && - SemaRef.RequireCompleteType(OpLoc, QualType(RTy, 0), + if (!RTy->isDependentType() && + !SemaRef.isThisOutsideMemberFunctionBody(RTy) && + SemaRef.RequireCompleteType(OpLoc, RTy, diag::err_typecheck_incomplete_tag, BaseRange)) return true; if (HasTemplateArgs || TemplateKWLoc.isValid()) { // LookupTemplateName doesn't expect these both to exist simultaneously. - QualType ObjectType = SS.isSet() ? QualType() : QualType(RTy, 0); + QualType ObjectType = SS.isSet() ? QualType() : RTy; bool MOUS; return SemaRef.LookupTemplateName(R, nullptr, SS, ObjectType, false, MOUS, TemplateKWLoc); } - DeclContext *DC = RDecl; if (SS.isSet()) { // If the member name was a qualified-id, look into the // nested-name-specifier. DC = SemaRef.computeDeclContext(SS, false); + // We tried to look into a dependent context that is not the current + // instantiation. Defer lookup until instantiation. + if (!DC) { + R.setNotFoundInCurrentInstantiation(); + return false; + } if (SemaRef.RequireCompleteDeclContext(SS, DC)) { SemaRef.Diag(SS.getRange().getEnd(), diag::err_typecheck_incomplete_tag) @@ -717,7 +739,7 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, // The record definition is complete, now look up the member. SemaRef.LookupQualifiedName(R, DC, SS); - if (!R.empty()) + if (!R.empty() || R.wasNotFoundInCurrentInstantiation()) return false; DeclarationName Typo = R.getLookupName(); @@ -781,6 +803,7 @@ Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType, const TemplateArgumentListInfo *TemplateArgs, const Scope *S, ActOnMemberAccessExtraArgs *ExtraArgs) { + #if 0 if (BaseType->isDependentType() || (SS.isSet() && isDependentScopeSpecifier(SS)) || NameInfo.getName().isDependentName()) @@ -788,6 +811,7 @@ Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType, IsArrow, OpLoc, SS, TemplateKWLoc, FirstQualifierInScope, NameInfo, TemplateArgs); + #endif LookupResult R(*this, NameInfo, LookupMemberName); @@ -797,7 +821,7 @@ Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType, QualType RecordTy = BaseType; if (IsArrow) RecordTy = RecordTy->castAs<PointerType>()->getPointeeType(); if (LookupMemberExprInRecord( - *this, R, nullptr, RecordTy->castAs<RecordType>(), OpLoc, IsArrow, + *this, R, nullptr, RecordTy, OpLoc, IsArrow, SS, TemplateArgs != nullptr, TemplateKWLoc, TE)) return ExprError(); if (TE) @@ -990,6 +1014,14 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, const Scope *S, bool SuppressQualifierCheck, ActOnMemberAccessExtraArgs *ExtraArgs) { + + if (R.wasNotFoundInCurrentInstantiation() || (SS.isValid() && !computeDeclContext(SS, false))) { + return ActOnDependentMemberExpr(BaseExpr, BaseExprType, + IsArrow, OpLoc, + SS, TemplateKWLoc, FirstQualifierInScope, + R.getLookupNameInfo(), TemplateArgs); + } + QualType BaseType = BaseExprType; if (IsArrow) { assert(BaseType->isPointerType()); @@ -1028,11 +1060,11 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, // Rederive where we looked up. DeclContext *DC = (SS.isSet() ? computeDeclContext(SS, false) - : BaseType->castAs<RecordType>()->getDecl()); + : BaseType->getAsRecordDecl()); if (ExtraArgs) { ExprResult RetryExpr; - if (!IsArrow && BaseExpr) { + if (!IsArrow && BaseExpr && !BaseExpr->isTypeDependent()) { SFINAETrap Trap(*this, true); ParsedType ObjectType; bool MayBePseudoDestructor = false; @@ -1055,9 +1087,16 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, } } - Diag(R.getNameLoc(), diag::err_no_member) - << MemberName << DC - << (BaseExpr ? BaseExpr->getSourceRange() : SourceRange()); + if(DC) { + Diag(R.getNameLoc(), diag::err_no_member) + << MemberName << DC + << (BaseExpr ? BaseExpr->getSourceRange() : SourceRange()); + } else { + // FIXME: Is this needed? + Diag(R.getNameLoc(), diag::err_no_member) + << MemberName << BaseExprType + << (BaseExpr ? BaseExpr->getSourceRange() : SourceRange()); + } return ExprError(); } @@ -1287,7 +1326,10 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R, return ExprError(); QualType BaseType = BaseExpr.get()->getType(); + + #if 0 assert(!BaseType->isDependentType()); + #endif DeclarationName MemberName = R.getLookupName(); SourceLocation MemberLoc = R.getNameLoc(); @@ -1299,29 +1341,32 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R, if (IsArrow) { if (const PointerType *Ptr = BaseType->getAs<PointerType>()) BaseType = Ptr->getPointeeType(); - else if (const ObjCObjectPointerType *Ptr + else if (!BaseType->isDependentType()) { + if (const ObjCObjectPointerType *Ptr = BaseType->getAs<ObjCObjectPointerType>()) BaseType = Ptr->getPointeeType(); - else if (BaseType->isRecordType()) { - // Recover from arrow accesses to records, e.g.: - // struct MyRecord foo; - // foo->bar - // This is actually well-formed in C++ if MyRecord has an - // overloaded operator->, but that should have been dealt with - // by now--or a diagnostic message already issued if a problem - // was encountered while looking for the overloaded operator->. - if (!S.getLangOpts().CPlusPlus) { - S.Diag(OpLoc, diag::err_typecheck_member_reference_suggestion) - << BaseType << int(IsArrow) << BaseExpr.get()->getSourceRange() - << FixItHint::CreateReplacement(OpLoc, "."); + else if (BaseType->isRecordType()) { + // Recover from arrow accesses to records, e.g.: + // struct MyRecord foo; + // foo->bar + // This is actually well-formed in C++ if MyRecord has an + // overloaded operator->, but that should have been dealt with + // by now--or a diagnostic message already issued if a problem + // was encountered while looking for the overloaded operator->. + if (!S.getLangOpts().CPlusPlus) { + S.Diag(OpLoc, diag::err_typecheck_member_reference_suggestion) + << BaseType << int(IsArrow) << BaseExpr.get()->getSourceRange() + << FixItHint::CreateReplacement(OpLoc, "."); + } + IsArrow = false; + } else if (BaseType->isFunctionType()) { + goto fail; + } else { + S.Diag(MemberLoc, diag::err_typecheck_member_reference_arrow) + << BaseType << BaseExpr.get()->getSourceRange(); + return ExprError(); } - IsArrow = false; - } else if (BaseType->isFunctionType()) { - goto fail; - } else { - S.Diag(MemberLoc, diag::err_typecheck_member_reference_arrow) - << BaseType << BaseExpr.get()->getSourceRange(); - return ExprError(); + } } @@ -1341,9 +1386,9 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R, } // Handle field access to simple records. - if (const RecordType *RTy = BaseType->getAs<RecordType>()) { + if (BaseType->getAsRecordDecl() || BaseType->isDependentType()) { TypoExpr *TE = nullptr; - if (LookupMemberExprInRecord(S, R, BaseExpr.get(), RTy, OpLoc, IsArrow, SS, + if (LookupMemberExprInRecord(S, R, BaseExpr.get(), BaseType, OpLoc, IsArrow, SS, HasTemplateArgs, TemplateKWLoc, TE)) return ExprError(); @@ -1781,12 +1826,14 @@ ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base, if (Result.isInvalid()) return ExprError(); Base = Result.get(); + #if 0 if (Base->getType()->isDependentType() || Name.isDependentName() || isDependentScopeSpecifier(SS)) { return ActOnDependentMemberExpr(Base, Base->getType(), IsArrow, OpLoc, SS, TemplateKWLoc, FirstQualifierInScope, NameInfo, TemplateArgs); } + #endif ActOnMemberAccessExtraArgs ExtraArgs = {S, Id, ObjCImpDecl}; ExprResult Res = BuildMemberReferenceExpr( diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index f6bd85bdc64692..a41bf334990e51 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -5789,7 +5789,10 @@ static ImplicitConversionSequence TryObjectArgumentInitialization( return ICS; } + // FIXME: Should this check getAsRecordDecl instead? + #if 0 assert(FromType->isRecordType()); + #endif QualType ClassType = S.Context.getTypeDeclType(ActingContext); // C++98 [class.dtor]p2: diff --git a/clang/test/SemaTemplate/dependent-names.cpp b/clang/test/SemaTemplate/dependent-names.cpp index 641ec950054f57..a661f14af80d34 100644 --- a/clang/test/SemaTemplate/dependent-names.cpp +++ b/clang/test/SemaTemplate/dependent-names.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s typedef double A; template<typename T> class B { @@ -334,7 +334,7 @@ int arr[sizeof(Sub)]; namespace PR11421 { template < unsigned > struct X { static const unsigned dimension = 3; - template<unsigned dim=dimension> + template<unsigned dim=dimension> struct Y: Y<dim> { }; // expected-error{{circular inheritance between 'Y<dim>' and 'Y<dim>'}} }; typedef X<3> X3; >From 7ba9f076c442055d75b6abeae06b3a57b65d5a08 Mon Sep 17 00:00:00 2001 From: Krystian Stasiowski <sdkryst...@gmail.com> Date: Fri, 1 Mar 2024 11:54:23 -0500 Subject: [PATCH 02/14] [FOLD] update tests --- .../temp.res/temp.dep/temp.dep.type/p4.cpp | 110 ++++++++++++++++++ .../SemaTemplate/instantiate-function-1.cpp | 14 +-- 2 files changed, 117 insertions(+), 7 deletions(-) create mode 100644 clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p4.cpp diff --git a/clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p4.cpp b/clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p4.cpp new file mode 100644 index 00000000000000..7b36e3ad3b0131 --- /dev/null +++ b/clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p4.cpp @@ -0,0 +1,110 @@ +// RUN: %clang_cc1 -Wno-unused-value -verify %s + +namespace N0 { + template<typename T> + struct A { + int x; + void f(); + using X = int; + + void not_instantiated(A *a, A &b) { + x; + f(); + new X; + + this->x; + this->f(); + this->A::x; + this->A::f(); + + a->x; + a->f(); + a->A::x; + a->A::f(); + + (*this).x; + (*this).f(); + (*this).A::x; + (*this).A::f(); + + b.x; + b.f(); + b.A::x; + b.A::f(); + + A::x; + A::f(); + new A::X; + + y; // expected-error{{use of undeclared identifier 'y'}} + g(); // expected-error{{use of undeclared identifier 'g'}} + new Y; // expected-error{{unknown type name 'Y'}} + + this->y; // expected-error{{no member named 'y' in 'A<T>'}} + this->g(); // expected-error{{no member named 'g' in 'A<T>'}} + this->A::y; // expected-error{{no member named 'y' in 'A<T>'}} + this->A::g(); // expected-error{{no member named 'g' in 'A<T>'}} + + a->y; // expected-error{{no member named 'y' in 'A<T>'}} + a->g(); // expected-error{{no member named 'g' in 'A<T>'}} + a->A::y; // expected-error{{no member named 'y' in 'A<T>'}} + a->A::g(); // expected-error{{no member named 'g' in 'A<T>'}} + + // FIXME: An overloaded unary 'operator*' is built for these + // even though the operand is a pointer (to a dependent type). + // Type::isOverloadableType should return false for such cases. + (*this).y; + (*this).g(); + (*this).A::y; + (*this).A::g(); + + b.y; // expected-error{{no member named 'y' in 'A<T>'}} + b.g(); // expected-error{{no member named 'g' in 'A<T>'}} + b.A::y; // expected-error{{no member named 'y' in 'A<T>'}} + b.A::g(); // expected-error{{no member named 'g' in 'A<T>'}} + + A::y; // expected-error{{no member named 'y' in 'A<T>'}} + A::g(); // expected-error{{no member named 'g' in 'A<T>'}} + new A::Y; // expected-error{{no type named 'Y' in 'A<T>'}} + } + }; +} // namespace N0 + +namespace N1 { + struct A { + template<int I> + void f(); + }; + + template<typename T> + struct B { + template<int I> + void f(); + + A x; + A g(); + + void not_instantiated(B *a, B &b) { + f<0>(); + this->f<0>(); + a->f<0>(); + // FIXME: This should not require 'template'! + (*this).f<0>(); // expected-error{{missing 'template' keyword prior to dependent template name 'f'}} + b.f<0>(); + + x.f<0>(); + this->x.f<0>(); + a->x.f<0>(); + // FIXME: This should not require 'template'! + (*this).x.f<0>(); // expected-error{{missing 'template' keyword prior to dependent template name 'f'}} + b.x.f<0>(); + + // FIXME: None of these should require 'template'! + g().f<0>(); // expected-error{{missing 'template' keyword prior to dependent template name 'f'}} + this->g().f<0>(); // expected-error{{missing 'template' keyword prior to dependent template name 'f'}} + a->g().f<0>(); // expected-error{{missing 'template' keyword prior to dependent template name 'f'}} + (*this).g().f<0>(); // expected-error{{missing 'template' keyword prior to dependent template name 'f'}} + b.g().f<0>(); // expected-error{{missing 'template' keyword prior to dependent template name 'f'}} + } + }; +} // namespace N1 diff --git a/clang/test/SemaTemplate/instantiate-function-1.cpp b/clang/test/SemaTemplate/instantiate-function-1.cpp index ceef2743774805..a4967264c654b7 100644 --- a/clang/test/SemaTemplate/instantiate-function-1.cpp +++ b/clang/test/SemaTemplate/instantiate-function-1.cpp @@ -1,7 +1,7 @@ // RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify %s template<typename T, typename U> struct X0 { - void f(T x, U y) { + void f(T x, U y) { (void)(x + y); // expected-error{{invalid operands}} } }; @@ -41,7 +41,7 @@ template <typename T> struct X4 { T f() const { return; // expected-error{{non-void function 'f' should return a value}} } - + T g() const { return 1; // expected-error{{void function 'g' should not return a value}} } @@ -64,7 +64,7 @@ template<typename T, typename U, typename V> struct X6 { // IfStmt if (t > 0) return u; - else { + else { if (t < 0) return v; // expected-error{{cannot initialize return object of type}} } @@ -131,12 +131,12 @@ template<typename T> struct Member0 { t; t.f; t->f; - + T* tp; tp.f; // expected-error{{member reference base type 'T *' is not a structure or union}} tp->f; - this->f; + this->f; // expected-error{{reference to non-static member function must be called}} this.f; // expected-error{{member reference base type 'Member0<T> *' is not a structure or union}} } }; @@ -239,11 +239,11 @@ namespace PR9880 { static yes_tag check(char[sizeof(&U::luaIndex)]); enum { value = sizeof(check<T>(0)) == sizeof(yes_tag) }; }; - + class SomeClass { public: int luaIndex(lua_State* L); }; - + int i = HasIndexMetamethod<SomeClass>::value; } >From a5113ca0800257b913ff913534ab7d977c7b5b74 Mon Sep 17 00:00:00 2001 From: Krystian Stasiowski <sdkryst...@gmail.com> Date: Mon, 4 Mar 2024 06:59:58 -0500 Subject: [PATCH 03/14] [FOLD] build DependentMemberExpr for LookupResult::FoundUnresolved --- clang/lib/Sema/SemaExprMember.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp index fd55e6f46a1066..95ad16571de8d6 100644 --- a/clang/lib/Sema/SemaExprMember.cpp +++ b/clang/lib/Sema/SemaExprMember.cpp @@ -676,7 +676,6 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, CXXScopeSpec &SS, bool HasTemplateArgs, SourceLocation TemplateKWLoc, TypoExpr *&TE) { - RecordDecl *RDecl = RTy->getAsRecordDecl(); DeclContext *DC = SemaRef.computeDeclContext(RTy); // If the object expression is dependent and isn't the current instantiation, // lookup will not find anything and we must defer until instantiation. @@ -1015,7 +1014,9 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, bool SuppressQualifierCheck, ActOnMemberAccessExtraArgs *ExtraArgs) { - if (R.wasNotFoundInCurrentInstantiation() || (SS.isValid() && !computeDeclContext(SS, false))) { + if (R.wasNotFoundInCurrentInstantiation() || + (SS.isValid() && !computeDeclContext(SS, false)) || + (R.isUnresolvableResult() && R.isClassLookup() && R.getNamingClass()->isDependentContext())) { return ActOnDependentMemberExpr(BaseExpr, BaseExprType, IsArrow, OpLoc, SS, TemplateKWLoc, FirstQualifierInScope, >From a1514e1770d22f5918cb357a0f9906e25e4b27d6 Mon Sep 17 00:00:00 2001 From: Krystian Stasiowski <sdkryst...@gmail.com> Date: Tue, 5 Mar 2024 10:03:05 -0500 Subject: [PATCH 04/14] [FOLD] TransformOverloadExprDecls filters template names --- clang/lib/Sema/SemaExprMember.cpp | 3 +-- clang/lib/Sema/TreeTransform.h | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp index 95ad16571de8d6..fd3f8860d46f98 100644 --- a/clang/lib/Sema/SemaExprMember.cpp +++ b/clang/lib/Sema/SemaExprMember.cpp @@ -1015,8 +1015,7 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, ActOnMemberAccessExtraArgs *ExtraArgs) { if (R.wasNotFoundInCurrentInstantiation() || - (SS.isValid() && !computeDeclContext(SS, false)) || - (R.isUnresolvableResult() && R.isClassLookup() && R.getNamingClass()->isDependentContext())) { + (SS.isValid() && !computeDeclContext(SS, false))) { return ActOnDependentMemberExpr(BaseExpr, BaseExprType, IsArrow, OpLoc, SS, TemplateKWLoc, FirstQualifierInScope, diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 2d22692f3ab750..0a585b0de3e7d7 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -12938,6 +12938,26 @@ bool TreeTransform<Derived>::TransformOverloadExprDecls(OverloadExpr *Old, // Resolve a kind, but don't do any further analysis. If it's // ambiguous, the callee needs to deal with it. R.resolveKind(); + + if (Old->hasTemplateKeyword() && !R.empty()) { + NamedDecl *FoundDecl = R.getRepresentativeDecl()->getUnderlyingDecl(); + getSema().FilterAcceptableTemplateNames(R, + /*AllowFunctionTemplates=*/true, + /*AllowDependent=*/true); + if (R.empty()) { + // If a 'template' keyword was used, a lookup that finds only non-template + // names is an error. + getSema().Diag(R.getNameLoc(), diag::err_template_kw_refers_to_non_template) + << R.getLookupName() + << Old->getQualifierLoc().getSourceRange() + << Old->hasTemplateKeyword() + << Old->getTemplateKeywordLoc(); + getSema().Diag(FoundDecl->getLocation(), diag::note_template_kw_refers_to_non_template) + << R.getLookupName(); + return true; + } + } + return false; } >From 54d1d53d320184e32b5868476e1f798882a53226 Mon Sep 17 00:00:00 2001 From: Krystian Stasiowski <sdkryst...@gmail.com> Date: Tue, 5 Mar 2024 10:50:53 -0500 Subject: [PATCH 05/14] [FOLD] update tests --- clang/test/AST/HLSL/this-reference-template.hlsl | 2 +- clang/test/CodeGenCXX/mangle.cpp | 8 -------- clang/test/Index/annotate-nested-name-specifier.cpp | 4 ++-- clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp | 4 ++-- 4 files changed, 5 insertions(+), 13 deletions(-) diff --git a/clang/test/AST/HLSL/this-reference-template.hlsl b/clang/test/AST/HLSL/this-reference-template.hlsl index 60e057986ebf80..d427e73044b788 100644 --- a/clang/test/AST/HLSL/this-reference-template.hlsl +++ b/clang/test/AST/HLSL/this-reference-template.hlsl @@ -24,7 +24,7 @@ void main() { // CHECK: -CXXMethodDecl 0x{{[0-9A-Fa-f]+}} <line:8:3, line:10:3> line:8:5 getFirst 'K ()' implicit-inline // CHECK-NEXT:-CompoundStmt 0x{{[0-9A-Fa-f]+}} <col:16, line:10:3> // CHECK-NEXT:-ReturnStmt 0x{{[0-9A-Fa-f]+}} <line:9:4, col:16> -// CHECK-NEXT:-CXXDependentScopeMemberExpr 0x{{[0-9A-Fa-f]+}} <col:11, col:16> '<dependent type>' lvalue .First +// CHECK-NEXT:-MemberExpr 0x{{[0-9A-Fa-f]+}} <col:11, col:16> 'K' lvalue .First 0x{{[0-9A-Fa-f]+}} // CHECK-NEXT:-CXXThisExpr 0x{{[0-9A-Fa-f]+}} <col:11> 'Pair<K, V>' lvalue this // CHECK-NEXT:-CXXMethodDecl 0x{{[0-9A-Fa-f]+}} <line:12:3, line:14:3> line:12:5 getSecond 'V ()' implicit-inline // CHECK-NEXT:-CompoundStmt 0x{{[0-9A-Fa-f]+}} <col:17, line:14:3> diff --git a/clang/test/CodeGenCXX/mangle.cpp b/clang/test/CodeGenCXX/mangle.cpp index 31467d943840e0..d0800af55c87e8 100644 --- a/clang/test/CodeGenCXX/mangle.cpp +++ b/clang/test/CodeGenCXX/mangle.cpp @@ -1032,10 +1032,6 @@ namespace test51 { template <typename T> decltype(S1<T>().~S1<T>(), S1<T>().~S1<T>()) fun4() {}; template <typename T> - decltype(S1<int>().~S1<T>()) fun5(){}; - template <template <typename T> class U> - decltype(S1<int>().~U<int>()) fun6(){}; - template <typename T> decltype(E().E::~T()) fun7() {} template <template <typename> class U> decltype(X<int>::Y().U<int>::Y::~Y()) fun8() {} @@ -1047,10 +1043,6 @@ namespace test51 { // CHECK-LABEL: @_ZN6test514fun3I2S1IiEiEEDTcldtcvS1_IT0_E_EdnT_EEv template void fun4<int>(); // CHECK-LABEL: @_ZN6test514fun4IiEEDTcmcldtcv2S1IT_E_Edn2S1IS2_EEcldtcvS3__Edn2S1IS2_EEEv - template void fun5<int>(); - // CHECK-LABEL: @_ZN6test514fun5IiEEDTcldtcv2S1IiE_Edn2S1IT_EEEv - template void fun6<S1>(); - // CHECK-LABEL: @_ZN6test514fun6I2S1EEDTcldtcvS1_IiE_EdnT_IiEEEv template void fun7<E>(); // CHECK-LABEL: @_ZN6test514fun7INS_1EEEEDTcldtcvS1__Esr1EEdnT_EEv template void fun8<X>(); diff --git a/clang/test/Index/annotate-nested-name-specifier.cpp b/clang/test/Index/annotate-nested-name-specifier.cpp index a7338db6b05b77..3181497258407f 100644 --- a/clang/test/Index/annotate-nested-name-specifier.cpp +++ b/clang/test/Index/annotate-nested-name-specifier.cpp @@ -132,7 +132,7 @@ struct X8 { struct X9 : X8 { typedef X8 inherited; - void f() { + void f() { inherited::f(); } }; @@ -299,7 +299,7 @@ struct X9 : X8 { // CHECK: Identifier: "type" [77:16 - 77:20] TypeRef=X4::type:70:13 // CHECK: Punctuation: ">" [77:20 - 77:21] MemberRefExpr= // CHECK: Punctuation: "::" [77:21 - 77:23] MemberRefExpr= -// CHECK: Identifier: "g" [77:23 - 77:24] MemberRefExpr= +// CHECK: Identifier: "g" [77:23 - 77:24] OverloadedDeclRef= // CHECK: Punctuation: "(" [77:24 - 77:25] CallExpr= // CHECK: Identifier: "t" [77:25 - 77:26] DeclRefExpr=t:74:12 // CHECK: Punctuation: ")" [77:26 - 77:27] CallExpr= diff --git a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp index 87774b00956a5a..739f495510dee5 100644 --- a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp +++ b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp @@ -1569,8 +1569,8 @@ TEST_P(ASTMatchersTest, IsArrow_MatchesMemberVariablesViaArrow) { matches("class Y { void x() { y; } int y; };", memberExpr(isArrow()))); EXPECT_TRUE(notMatches("class Y { void x() { (*this).y; } int y; };", memberExpr(isArrow()))); - EXPECT_TRUE(matches("template <class T> class Y { void x() { this->m; } };", - cxxDependentScopeMemberExpr(isArrow()))); + EXPECT_TRUE(matches("template <class T> class Y { void x() { this->m; } int m; };", + memberExpr(isArrow()))); EXPECT_TRUE( notMatches("template <class T> class Y { void x() { (*this).m; } };", cxxDependentScopeMemberExpr(isArrow()))); >From ea2c98c112da97074b73b9708c45ba6d07f43a60 Mon Sep 17 00:00:00 2001 From: Krystian Stasiowski <sdkryst...@gmail.com> Date: Tue, 5 Mar 2024 12:33:40 -0500 Subject: [PATCH 06/14] [FOLD] cleanup --- clang/lib/Sema/SemaExprMember.cpp | 19 ------------------- clang/test/SemaTemplate/dependent-names.cpp | 4 ++-- 2 files changed, 2 insertions(+), 21 deletions(-) diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp index fd3f8860d46f98..eb87e0edda0128 100644 --- a/clang/lib/Sema/SemaExprMember.cpp +++ b/clang/lib/Sema/SemaExprMember.cpp @@ -802,16 +802,6 @@ Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType, const TemplateArgumentListInfo *TemplateArgs, const Scope *S, ActOnMemberAccessExtraArgs *ExtraArgs) { - #if 0 - if (BaseType->isDependentType() || - (SS.isSet() && isDependentScopeSpecifier(SS)) || - NameInfo.getName().isDependentName()) - return ActOnDependentMemberExpr(Base, BaseType, - IsArrow, OpLoc, - SS, TemplateKWLoc, FirstQualifierInScope, - NameInfo, TemplateArgs); - #endif - LookupResult R(*this, NameInfo, LookupMemberName); // Implicit member accesses. @@ -1826,15 +1816,6 @@ ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base, if (Result.isInvalid()) return ExprError(); Base = Result.get(); - #if 0 - if (Base->getType()->isDependentType() || Name.isDependentName() || - isDependentScopeSpecifier(SS)) { - return ActOnDependentMemberExpr(Base, Base->getType(), IsArrow, OpLoc, SS, - TemplateKWLoc, FirstQualifierInScope, - NameInfo, TemplateArgs); - } - #endif - ActOnMemberAccessExtraArgs ExtraArgs = {S, Id, ObjCImpDecl}; ExprResult Res = BuildMemberReferenceExpr( Base, Base->getType(), OpLoc, IsArrow, SS, TemplateKWLoc, diff --git a/clang/test/SemaTemplate/dependent-names.cpp b/clang/test/SemaTemplate/dependent-names.cpp index a661f14af80d34..641ec950054f57 100644 --- a/clang/test/SemaTemplate/dependent-names.cpp +++ b/clang/test/SemaTemplate/dependent-names.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s typedef double A; template<typename T> class B { @@ -334,7 +334,7 @@ int arr[sizeof(Sub)]; namespace PR11421 { template < unsigned > struct X { static const unsigned dimension = 3; - template<unsigned dim=dimension> + template<unsigned dim=dimension> struct Y: Y<dim> { }; // expected-error{{circular inheritance between 'Y<dim>' and 'Y<dim>'}} }; typedef X<3> X3; >From ccf3667673412f1b4c140d9600a5dd9943df477d Mon Sep 17 00:00:00 2001 From: Krystian Stasiowski <sdkryst...@gmail.com> Date: Tue, 5 Mar 2024 13:03:00 -0500 Subject: [PATCH 07/14] [FOLD] format --- clang/lib/Sema/SemaExpr.cpp | 7 +-- clang/lib/Sema/SemaExprMember.cpp | 59 ++++++++----------- clang/lib/Sema/SemaOverload.cpp | 6 +- clang/lib/Sema/TreeTransform.h | 14 ++--- .../ASTMatchers/ASTMatchersNarrowingTest.cpp | 5 +- 5 files changed, 41 insertions(+), 50 deletions(-) diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 31d902b3572413..3bf2731b4b0476 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -666,10 +666,9 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) { // expressions of certain types in C++. if (getLangOpts().CPlusPlus && (E->getType() == Context.OverloadTy || - // FIXME: This is a hack! We want the lvalue-to-rvalue conversion applied - // to pointer types even if the pointee type is dependent. - (T->isDependentType() && !T->isPointerType()) || - T->isRecordType())) + // FIXME: This is a hack! We want the lvalue-to-rvalue conversion applied + // to pointer types even if the pointee type is dependent. + (T->isDependentType() && !T->isPointerType()) || T->isRecordType())) return E; // The C standard is actually really unclear on this point, and diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp index eb87e0edda0128..da32ea251aeee1 100644 --- a/clang/lib/Sema/SemaExprMember.cpp +++ b/clang/lib/Sema/SemaExprMember.cpp @@ -670,8 +670,7 @@ class RecordMemberExprValidatorCCC final : public CorrectionCandidateCallback { } static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, - Expr *BaseExpr, - QualType RTy, + Expr *BaseExpr, QualType RTy, SourceLocation OpLoc, bool IsArrow, CXXScopeSpec &SS, bool HasTemplateArgs, SourceLocation TemplateKWLoc, @@ -695,9 +694,8 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, SourceRange BaseRange = BaseExpr ? BaseExpr->getSourceRange() : SourceRange(); if (!RTy->isDependentType() && !SemaRef.isThisOutsideMemberFunctionBody(RTy) && - SemaRef.RequireCompleteType(OpLoc, RTy, - diag::err_typecheck_incomplete_tag, - BaseRange)) + SemaRef.RequireCompleteType( + OpLoc, RTy, diag::err_typecheck_incomplete_tag, BaseRange)) return true; if (HasTemplateArgs || TemplateKWLoc.isValid()) { @@ -792,16 +790,12 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R, Decl *ObjCImpDecl, bool HasTemplateArgs, SourceLocation TemplateKWLoc); -ExprResult -Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType, - SourceLocation OpLoc, bool IsArrow, - CXXScopeSpec &SS, - SourceLocation TemplateKWLoc, - NamedDecl *FirstQualifierInScope, - const DeclarationNameInfo &NameInfo, - const TemplateArgumentListInfo *TemplateArgs, - const Scope *S, - ActOnMemberAccessExtraArgs *ExtraArgs) { +ExprResult Sema::BuildMemberReferenceExpr( + Expr *Base, QualType BaseType, SourceLocation OpLoc, bool IsArrow, + CXXScopeSpec &SS, SourceLocation TemplateKWLoc, + NamedDecl *FirstQualifierInScope, const DeclarationNameInfo &NameInfo, + const TemplateArgumentListInfo *TemplateArgs, const Scope *S, + ActOnMemberAccessExtraArgs *ExtraArgs) { LookupResult R(*this, NameInfo, LookupMemberName); // Implicit member accesses. @@ -809,9 +803,9 @@ Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType, TypoExpr *TE = nullptr; QualType RecordTy = BaseType; if (IsArrow) RecordTy = RecordTy->castAs<PointerType>()->getPointeeType(); - if (LookupMemberExprInRecord( - *this, R, nullptr, RecordTy, OpLoc, IsArrow, - SS, TemplateArgs != nullptr, TemplateKWLoc, TE)) + if (LookupMemberExprInRecord(*this, R, nullptr, RecordTy, OpLoc, IsArrow, + SS, TemplateArgs != nullptr, TemplateKWLoc, + TE)) return ExprError(); if (TE) return TE; @@ -1006,9 +1000,8 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, if (R.wasNotFoundInCurrentInstantiation() || (SS.isValid() && !computeDeclContext(SS, false))) { - return ActOnDependentMemberExpr(BaseExpr, BaseExprType, - IsArrow, OpLoc, - SS, TemplateKWLoc, FirstQualifierInScope, + return ActOnDependentMemberExpr(BaseExpr, BaseExprType, IsArrow, OpLoc, SS, + TemplateKWLoc, FirstQualifierInScope, R.getLookupNameInfo(), TemplateArgs); } @@ -1048,9 +1041,8 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, if (R.empty()) { // Rederive where we looked up. - DeclContext *DC = (SS.isSet() - ? computeDeclContext(SS, false) - : BaseType->getAsRecordDecl()); + DeclContext *DC = (SS.isSet() ? computeDeclContext(SS, false) + : BaseType->getAsRecordDecl()); if (ExtraArgs) { ExprResult RetryExpr; @@ -1077,7 +1069,7 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, } } - if(DC) { + if (DC) { Diag(R.getNameLoc(), diag::err_no_member) << MemberName << DC << (BaseExpr ? BaseExpr->getSourceRange() : SourceRange()); @@ -1317,9 +1309,9 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R, QualType BaseType = BaseExpr.get()->getType(); - #if 0 +#if 0 assert(!BaseType->isDependentType()); - #endif +#endif DeclarationName MemberName = R.getLookupName(); SourceLocation MemberLoc = R.getNameLoc(); @@ -1332,12 +1324,12 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R, if (const PointerType *Ptr = BaseType->getAs<PointerType>()) BaseType = Ptr->getPointeeType(); else if (!BaseType->isDependentType()) { - if (const ObjCObjectPointerType *Ptr - = BaseType->getAs<ObjCObjectPointerType>()) - BaseType = Ptr->getPointeeType(); + if (const ObjCObjectPointerType *Ptr = + BaseType->getAs<ObjCObjectPointerType>()) + BaseType = Ptr->getPointeeType(); else if (BaseType->isRecordType()) { // Recover from arrow accesses to records, e.g.: - // struct MyRecord foo; + // struct MyRecord foo; // foo->bar // This is actually well-formed in C++ if MyRecord has an // overloaded operator->, but that should have been dealt with @@ -1356,7 +1348,6 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R, << BaseType << BaseExpr.get()->getSourceRange(); return ExprError(); } - } } @@ -1378,8 +1369,8 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R, // Handle field access to simple records. if (BaseType->getAsRecordDecl() || BaseType->isDependentType()) { TypoExpr *TE = nullptr; - if (LookupMemberExprInRecord(S, R, BaseExpr.get(), BaseType, OpLoc, IsArrow, SS, - HasTemplateArgs, TemplateKWLoc, TE)) + if (LookupMemberExprInRecord(S, R, BaseExpr.get(), BaseType, OpLoc, IsArrow, + SS, HasTemplateArgs, TemplateKWLoc, TE)) return ExprError(); // Returning valid-but-null is how we indicate to the caller that diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index a41bf334990e51..632d476dfe7eb7 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -5789,10 +5789,10 @@ static ImplicitConversionSequence TryObjectArgumentInitialization( return ICS; } - // FIXME: Should this check getAsRecordDecl instead? - #if 0 +// FIXME: Should this check getAsRecordDecl instead? +#if 0 assert(FromType->isRecordType()); - #endif +#endif QualType ClassType = S.Context.getTypeDeclType(ActingContext); // C++98 [class.dtor]p2: diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 0a585b0de3e7d7..4eea9688cc20b5 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -12947,14 +12947,14 @@ bool TreeTransform<Derived>::TransformOverloadExprDecls(OverloadExpr *Old, if (R.empty()) { // If a 'template' keyword was used, a lookup that finds only non-template // names is an error. - getSema().Diag(R.getNameLoc(), diag::err_template_kw_refers_to_non_template) - << R.getLookupName() - << Old->getQualifierLoc().getSourceRange() - << Old->hasTemplateKeyword() - << Old->getTemplateKeywordLoc(); - getSema().Diag(FoundDecl->getLocation(), diag::note_template_kw_refers_to_non_template) + getSema().Diag(R.getNameLoc(), + diag::err_template_kw_refers_to_non_template) + << R.getLookupName() << Old->getQualifierLoc().getSourceRange() + << Old->hasTemplateKeyword() << Old->getTemplateKeywordLoc(); + getSema().Diag(FoundDecl->getLocation(), + diag::note_template_kw_refers_to_non_template) << R.getLookupName(); - return true; + return true; } } diff --git a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp index 739f495510dee5..c08deb903f129b 100644 --- a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp +++ b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp @@ -1569,8 +1569,9 @@ TEST_P(ASTMatchersTest, IsArrow_MatchesMemberVariablesViaArrow) { matches("class Y { void x() { y; } int y; };", memberExpr(isArrow()))); EXPECT_TRUE(notMatches("class Y { void x() { (*this).y; } int y; };", memberExpr(isArrow()))); - EXPECT_TRUE(matches("template <class T> class Y { void x() { this->m; } int m; };", - memberExpr(isArrow()))); + EXPECT_TRUE( + matches("template <class T> class Y { void x() { this->m; } int m; };", + memberExpr(isArrow()))); EXPECT_TRUE( notMatches("template <class T> class Y { void x() { (*this).m; } };", cxxDependentScopeMemberExpr(isArrow()))); >From 5b0461fa0ba27e4adea77a5c580d82efc4f15f5f Mon Sep 17 00:00:00 2001 From: Krystian Stasiowski <sdkryst...@gmail.com> Date: Thu, 7 Mar 2024 12:43:15 -0500 Subject: [PATCH 08/14] [FOLD] more tests --- .../temp.res/temp.dep/temp.dep.type/p4.cpp | 383 +++++++++++++++--- 1 file changed, 323 insertions(+), 60 deletions(-) diff --git a/clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p4.cpp b/clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p4.cpp index 7b36e3ad3b0131..2649addf1175ac 100644 --- a/clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p4.cpp +++ b/clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p4.cpp @@ -1,71 +1,334 @@ // RUN: %clang_cc1 -Wno-unused-value -verify %s namespace N0 { - template<typename T> struct A { - int x; - void f(); - using X = int; - - void not_instantiated(A *a, A &b) { - x; - f(); - new X; - - this->x; - this->f(); - this->A::x; - this->A::f(); - - a->x; - a->f(); - a->A::x; - a->A::f(); - - (*this).x; - (*this).f(); - (*this).A::x; - (*this).A::f(); - - b.x; - b.f(); - b.A::x; - b.A::f(); - - A::x; - A::f(); - new A::X; - - y; // expected-error{{use of undeclared identifier 'y'}} - g(); // expected-error{{use of undeclared identifier 'g'}} - new Y; // expected-error{{unknown type name 'Y'}} - - this->y; // expected-error{{no member named 'y' in 'A<T>'}} - this->g(); // expected-error{{no member named 'g' in 'A<T>'}} - this->A::y; // expected-error{{no member named 'y' in 'A<T>'}} - this->A::g(); // expected-error{{no member named 'g' in 'A<T>'}} - - a->y; // expected-error{{no member named 'y' in 'A<T>'}} - a->g(); // expected-error{{no member named 'g' in 'A<T>'}} - a->A::y; // expected-error{{no member named 'y' in 'A<T>'}} - a->A::g(); // expected-error{{no member named 'g' in 'A<T>'}} + int x0; + static int x1; + int x2; + static int x3; + + void f0(); + static void f1(); + void f2(); + static void f3(); + + using M0 = int; + using M1 = int; + + struct C0 { }; + struct C1 { }; + }; + + template<typename T> + struct B : A { + int x4; + static int x5; + + using A::x2; + using A::x3; + + void f4(); + static void f5(); + + using A::f2; + using A::f3; + + using M2 = int; + + using A::M1; + + struct C2 { }; + + using A::C1; + + void not_instantiated(B *a, B &b) { + // All of the following should be found in the current instantiation. + + new M0; + new B::M0; + new A::M0; + new B::A::M0; + new C0; + new B::C0; + new A::C0; + new B::A::C0; + new M1; + new B::M1; + new A::M1; + new B::A::M1; + new C1; + new B::C1; + new A::C1; + new B::A::C1; + new M2; + new B::M2; + new C2; + new B::C2; + + x0; + B::x0; + A::x0; + B::A::x0; + x1; + B::x1; + A::x1; + B::A::x1; + x2; + B::x2; + A::x2; + B::A::x2; + x3; + B::x3; + A::x3; + B::A::x3; + x4; + B::x4; + x5; + B::x5; + + f0(); + B::f0(); + A::f0(); + B::A::f0(); + f1(); + B::f1(); + A::f1(); + B::A::f1(); + f2(); + B::f2(); + A::f2(); + B::A::f2(); + f3(); + B::f3(); + A::f3(); + B::A::f3(); + f4(); + B::f4(); + f5(); + B::f5(); + + this->x0; + this->B::x0; + this->A::x0; + this->B::A::x0; + this->x1; + this->B::x1; + this->A::x1; + this->B::A::x1; + this->x2; + this->B::x2; + this->A::x2; + this->B::A::x2; + this->x3; + this->B::x3; + this->A::x3; + this->B::A::x3; + this->x4; + this->B::x4; + this->x5; + this->B::x5; + + this->f0(); + this->B::f0(); + this->A::f0(); + this->B::A::f0(); + this->f1(); + this->B::f1(); + this->A::f1(); + this->B::A::f1(); + this->f2(); + this->B::f2(); + this->A::f2(); + this->B::A::f2(); + this->f3(); + this->B::f3(); + this->A::f3(); + this->B::A::f3(); + this->f4(); + this->B::f4(); + this->f5(); + this->B::f5(); + + a->x0; + a->B::x0; + a->A::x0; + a->B::A::x0; + a->x1; + a->B::x1; + a->A::x1; + a->B::A::x1; + a->x2; + a->B::x2; + a->A::x2; + a->B::A::x2; + a->x3; + a->B::x3; + a->A::x3; + a->B::A::x3; + a->x4; + a->B::x4; + a->x5; + a->B::x5; + + a->f0(); + a->B::f0(); + a->A::f0(); + a->B::A::f0(); + a->f1(); + a->B::f1(); + a->A::f1(); + a->B::A::f1(); + a->f2(); + a->B::f2(); + a->A::f2(); + a->B::A::f2(); + a->f3(); + a->B::f3(); + a->A::f3(); + a->B::A::f3(); + a->f4(); + a->B::f4(); + a->f5(); + a->B::f5(); + + (*this).x0; + (*this).B::x0; + (*this).A::x0; + (*this).B::A::x0; + (*this).x1; + (*this).B::x1; + (*this).A::x1; + (*this).B::A::x1; + (*this).x2; + (*this).B::x2; + (*this).A::x2; + (*this).B::A::x2; + (*this).x3; + (*this).B::x3; + (*this).A::x3; + (*this).B::A::x3; + (*this).x4; + (*this).B::x4; + (*this).x5; + (*this).B::x5; + + (*this).f0(); + (*this).B::f0(); + (*this).A::f0(); + (*this).B::A::f0(); + (*this).f1(); + (*this).B::f1(); + (*this).A::f1(); + (*this).B::A::f1(); + (*this).f2(); + (*this).B::f2(); + (*this).A::f2(); + (*this).B::A::f2(); + (*this).f3(); + (*this).B::f3(); + (*this).A::f3(); + (*this).B::A::f3(); + (*this).f4(); + (*this).B::f4(); + (*this).f5(); + (*this).B::f5(); + + b.x0; + b.B::x0; + b.A::x0; + b.B::A::x0; + b.x1; + b.B::x1; + b.A::x1; + b.B::A::x1; + b.x2; + b.B::x2; + b.A::x2; + b.B::A::x2; + b.x3; + b.B::x3; + b.A::x3; + b.B::A::x3; + b.x4; + b.B::x4; + b.x5; + b.B::x5; + + b.f0(); + b.B::f0(); + b.A::f0(); + b.B::A::f0(); + b.f1(); + b.B::f1(); + b.A::f1(); + b.B::A::f1(); + b.f2(); + b.B::f2(); + b.A::f2(); + b.B::A::f2(); + b.f3(); + b.B::f3(); + b.A::f3(); + b.B::A::f3(); + b.f4(); + b.B::f4(); + b.f5(); + b.B::f5(); + + // None of the following should be found in the current instantiation. + + new M3; // expected-error{{unknown type name 'M3'}} + new B::M3; // expected-error{{no type named 'M3' in 'B<T>'}} + new A::M3; // expected-error{{no type named 'M3' in 'N0::A'}} + new B::A::M3; // expected-error{{no type named 'M3' in 'N0::A'}} + + x6; // expected-error{{use of undeclared identifier 'x6'}} + B::x6; // expected-error{{no member named 'x6' in 'B<T>'}} + A::x6; // expected-error{{no member named 'x6' in 'N0::A'}} + B::A::x6; // expected-error{{no member named 'x6' in 'N0::A'}} + f6(); // expected-error{{use of undeclared identifier 'f6'}} + B::f6(); // expected-error{{no member named 'f6' in 'B<T>'}} + A::f6(); // expected-error{{no member named 'f6' in 'N0::A'}} + B::A::f6(); // expected-error{{no member named 'f6' in 'N0::A'}} + + this->x6; // expected-error{{no member named 'x6' in 'B<T>'}} + this->B::x6; // expected-error{{no member named 'x6' in 'B<T>'}} + this->A::x6; // expected-error{{no member named 'x6' in 'N0::A'}} + this->B::A::x6; // expected-error{{no member named 'x6' in 'N0::A'}} + this->f6(); // expected-error{{no member named 'f6' in 'B<T>'}} + this->B::f6(); // expected-error{{no member named 'f6' in 'B<T>'}} + this->A::f6(); // expected-error{{no member named 'f6' in 'N0::A'}} + this->B::A::f6(); // expected-error{{no member named 'f6' in 'N0::A'}} + + a->x6; // expected-error{{no member named 'x6' in 'B<T>'}} + a->B::x6; // expected-error{{no member named 'x6' in 'B<T>'}} + a->A::x6; // expected-error{{no member named 'x6' in 'N0::A'}} + a->B::A::x6; // expected-error{{no member named 'x6' in 'N0::A'}} + a->f6(); // expected-error{{no member named 'f6' in 'B<T>'}} + a->B::f6(); // expected-error{{no member named 'f6' in 'B<T>'}} + a->A::f6(); // expected-error{{no member named 'f6' in 'N0::A'}} + a->B::A::f6(); // expected-error{{no member named 'f6' in 'N0::A'}} // FIXME: An overloaded unary 'operator*' is built for these // even though the operand is a pointer (to a dependent type). // Type::isOverloadableType should return false for such cases. - (*this).y; - (*this).g(); - (*this).A::y; - (*this).A::g(); - - b.y; // expected-error{{no member named 'y' in 'A<T>'}} - b.g(); // expected-error{{no member named 'g' in 'A<T>'}} - b.A::y; // expected-error{{no member named 'y' in 'A<T>'}} - b.A::g(); // expected-error{{no member named 'g' in 'A<T>'}} - - A::y; // expected-error{{no member named 'y' in 'A<T>'}} - A::g(); // expected-error{{no member named 'g' in 'A<T>'}} - new A::Y; // expected-error{{no type named 'Y' in 'A<T>'}} + (*this).x6; + (*this).B::x6; + (*this).A::x6; + (*this).B::A::x6; + (*this).f6(); + (*this).B::f6(); + (*this).A::f6(); + (*this).B::A::f6(); + + b.x6; // expected-error{{no member named 'x6' in 'B<T>'}} + b.B::x6; // expected-error{{no member named 'x6' in 'B<T>'}} + b.A::x6; // expected-error{{no member named 'x6' in 'N0::A'}} + b.B::A::x6; // expected-error{{no member named 'x6' in 'N0::A'}} + b.f6(); // expected-error{{no member named 'f6' in 'B<T>'}} + b.B::f6(); // expected-error{{no member named 'f6' in 'B<T>'}} + b.A::f6(); // expected-error{{no member named 'f6' in 'N0::A'}} + b.B::A::f6(); // expected-error{{no member named 'f6' in 'N0::A'}} } }; } // namespace N0 >From 329574ec59ce3ac6c4f4cc061b09bb1ed70211a2 Mon Sep 17 00:00:00 2001 From: Krystian Stasiowski <sdkryst...@gmail.com> Date: Thu, 7 Mar 2024 14:21:10 -0500 Subject: [PATCH 09/14] [FOLD] LookupParsedName takes ObjectType --- clang/include/clang/Sema/Sema.h | 5 +- clang/lib/Parse/ParseDecl.cpp | 2 +- clang/lib/Sema/HLSLExternalSemaSource.cpp | 4 +- clang/lib/Sema/SemaAttr.cpp | 5 +- clang/lib/Sema/SemaDecl.cpp | 6 +-- clang/lib/Sema/SemaDeclCXX.cpp | 6 +-- clang/lib/Sema/SemaExpr.cpp | 5 +- clang/lib/Sema/SemaExprCXX.cpp | 2 +- clang/lib/Sema/SemaExprMember.cpp | 24 +++++++-- clang/lib/Sema/SemaLookup.cpp | 62 +++++++++++++++-------- clang/lib/Sema/SemaOpenMP.cpp | 14 +++-- clang/lib/Sema/SemaTemplate.cpp | 4 +- 12 files changed, 93 insertions(+), 46 deletions(-) diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 95ea5ebc7f1ac1..a085f9ca09f1b8 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -7725,7 +7725,10 @@ class Sema final { bool InUnqualifiedLookup = false); bool LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, CXXScopeSpec &SS); - bool LookupParsedName(LookupResult &R, Scope *S, CXXScopeSpec *SS, + bool LookupParsedName(LookupResult &R, + Scope *S, + CXXScopeSpec *SS, + QualType ObjectType, bool AllowBuiltinCreation = false, bool EnteringContext = false); ObjCProtocolDecl * diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index dd179414a14191..c88eb863e5b895 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -2994,7 +2994,7 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, << TokenName << TagName << getLangOpts().CPlusPlus << FixItHint::CreateInsertion(Tok.getLocation(), FixitTagName); - if (Actions.LookupParsedName(R, getCurScope(), SS)) { + if (Actions.LookupParsedName(R, getCurScope(), SS, /*ObjectType=*/QualType())) { for (LookupResult::iterator I = R.begin(), IEnd = R.end(); I != IEnd; ++I) Diag((*I)->getLocation(), diag::note_decl_hiding_tag_type) diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp index 1a1febf7a35241..f6a93c378acf4b 100644 --- a/clang/lib/Sema/HLSLExternalSemaSource.cpp +++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp @@ -131,7 +131,9 @@ struct BuiltinTypeDeclBuilder { DeclarationNameInfo NameInfo = DeclarationNameInfo(DeclarationName(&II), SourceLocation()); LookupResult R(S, NameInfo, Sema::LookupOrdinaryName); - S.LookupParsedName(R, S.getCurScope(), &SS, false); + S.LookupParsedName(R, S.getCurScope(), &SS, + /*ObjectType=*/QualType(), + /*AllowBuiltinCreation*/false); assert(R.isSingleResult() && "Since this is a builtin it should always resolve!"); auto *VD = cast<ValueDecl>(R.getFoundDecl()); diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp index 0dcf42e4899713..c15fd3dfb4331a 100644 --- a/clang/lib/Sema/SemaAttr.cpp +++ b/clang/lib/Sema/SemaAttr.cpp @@ -825,7 +825,10 @@ void Sema::ActOnPragmaUnused(const Token &IdTok, Scope *curScope, IdentifierInfo *Name = IdTok.getIdentifierInfo(); LookupResult Lookup(*this, Name, IdTok.getLocation(), LookupOrdinaryName); - LookupParsedName(Lookup, curScope, nullptr, true); + LookupParsedName(Lookup, curScope, + /*SS=*/nullptr, + /*ObjectType=*/QualType(), + /*AllowBuiltinCreation*/true); if (Lookup.empty()) { Diag(PragmaLoc, diag::warn_pragma_unused_undeclared_var) diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 5850cd0ab6b9aa..49ea960e51af25 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -828,7 +828,7 @@ static bool isTagTypeWithMissingTag(Sema &SemaRef, LookupResult &Result, IdentifierInfo *&Name, SourceLocation NameLoc) { LookupResult R(SemaRef, Name, NameLoc, Sema::LookupTagName); - SemaRef.LookupParsedName(R, S, &SS); + SemaRef.LookupParsedName(R, S, &SS, /*ObjectType=*/QualType()); if (TagDecl *Tag = R.getAsSingle<TagDecl>()) { StringRef FixItTagName; switch (Tag->getTagKind()) { @@ -865,7 +865,7 @@ static bool isTagTypeWithMissingTag(Sema &SemaRef, LookupResult &Result, // Replace lookup results with just the tag decl. Result.clear(Sema::LookupTagName); - SemaRef.LookupParsedName(Result, S, &SS); + SemaRef.LookupParsedName(Result, S, &SS, /*ObjectType=*/QualType()); return true; } @@ -892,7 +892,7 @@ Sema::NameClassification Sema::ClassifyName(Scope *S, CXXScopeSpec &SS, } LookupResult Result(*this, Name, NameLoc, LookupOrdinaryName); - LookupParsedName(Result, S, &SS, !CurMethod); + LookupParsedName(Result, S, &SS, /*ObjectType=*/QualType(), /*AllowBuiltinCreation*/!CurMethod); if (SS.isInvalid()) return NameClassification::Error(); diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index e258a4f7c89415..6162c53a354704 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -4514,7 +4514,7 @@ Sema::BuildMemInitializer(Decl *ConstructorD, DS.getBeginLoc(), DS.getEllipsisLoc()); } else { LookupResult R(*this, MemberOrBase, IdLoc, LookupOrdinaryName); - LookupParsedName(R, S, &SS); + LookupParsedName(R, S, &SS, /*ObjectType=*/QualType()); TypeDecl *TyD = R.getAsSingle<TypeDecl>(); if (!TyD) { @@ -12224,7 +12224,7 @@ Decl *Sema::ActOnUsingDirective(Scope *S, SourceLocation UsingLoc, // Lookup namespace name. LookupResult R(*this, NamespcName, IdentLoc, LookupNamespaceName); - LookupParsedName(R, S, &SS); + LookupParsedName(R, S, &SS, /*ObjectType=*/QualType()); if (R.isAmbiguous()) return nullptr; @@ -13682,7 +13682,7 @@ Decl *Sema::ActOnNamespaceAliasDef(Scope *S, SourceLocation NamespaceLoc, // Lookup the namespace name. LookupResult R(*this, Ident, IdentLoc, LookupNamespaceName); - LookupParsedName(R, S, &SS); + LookupParsedName(R, S, &SS, /*ObjectType=*/QualType()); if (R.isAmbiguous()) return nullptr; diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 3bf2731b4b0476..7a28083054c2da 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -2751,7 +2751,8 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS, // results until we get here but it's likely not worth it. bool MemberOfUnknownSpecialization; AssumedTemplateKind AssumedTemplate; - if (LookupTemplateName(R, S, SS, QualType(), /*EnteringContext=*/false, + if (LookupTemplateName(R, S, SS, /*ObjectType=*/QualType(), + /*EnteringContext=*/false, MemberOfUnknownSpecialization, TemplateKWLoc, &AssumedTemplate)) return ExprError(); @@ -2762,7 +2763,7 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS, IsAddressOfOperand, TemplateArgs); } else { bool IvarLookupFollowUp = II && !SS.isSet() && getCurMethodDecl(); - LookupParsedName(R, S, &SS, !IvarLookupFollowUp); + LookupParsedName(R, S, &SS, /*ObjectType=*/QualType(), /*AllowBuiltinCreation=*/!IvarLookupFollowUp); // If the result might be in a dependent base class, this is a dependent // id-expression. diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index c34a40fa7c81ac..6a6331b476308b 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -9073,7 +9073,7 @@ Sema::CheckMicrosoftIfExistsSymbol(Scope *S, // Do the redeclaration lookup in the current scope. LookupResult R(*this, TargetNameInfo, Sema::LookupAnyName, Sema::NotForRedeclaration); - LookupParsedName(R, S, &SS); + LookupParsedName(R, S, &SS, /*ObjectType=*/QualType()); R.suppressDiagnostics(); switch (R.getResultKind()) { diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp index da32ea251aeee1..bb58bf6c7ca55f 100644 --- a/clang/lib/Sema/SemaExprMember.cpp +++ b/clang/lib/Sema/SemaExprMember.cpp @@ -675,6 +675,7 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, CXXScopeSpec &SS, bool HasTemplateArgs, SourceLocation TemplateKWLoc, TypoExpr *&TE) { + #if 1 DeclContext *DC = SemaRef.computeDeclContext(RTy); // If the object expression is dependent and isn't the current instantiation, // lookup will not find anything and we must defer until instantiation. @@ -682,6 +683,7 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, R.setNotFoundInCurrentInstantiation(); return false; } + #endif // FIXME: Should this use Name.isDependentName()? if (DeclarationName Name = R.getLookupName(); @@ -698,15 +700,21 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, OpLoc, RTy, diag::err_typecheck_incomplete_tag, BaseRange)) return true; + // LookupTemplateName/LookupParsedName don't expect these both to exist simultaneously. + QualType ObjectType = SS.isSet() ? QualType() : RTy; if (HasTemplateArgs || TemplateKWLoc.isValid()) { - // LookupTemplateName doesn't expect these both to exist simultaneously. - QualType ObjectType = SS.isSet() ? QualType() : RTy; - bool MOUS; - return SemaRef.LookupTemplateName(R, nullptr, SS, ObjectType, false, MOUS, + return SemaRef.LookupTemplateName(R, + /*S=*/nullptr, + SS, + ObjectType, + /*EnteringContext=*/false, + MOUS, TemplateKWLoc); } - + #if 0 + SemaRef.LookupParsedName(R, /*S=*/nullptr, &SS, ObjectType); + #else if (SS.isSet()) { // If the member name was a qualified-id, look into the // nested-name-specifier. @@ -735,12 +743,18 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, // The record definition is complete, now look up the member. SemaRef.LookupQualifiedName(R, DC, SS); + #endif if (!R.empty() || R.wasNotFoundInCurrentInstantiation()) return false; DeclarationName Typo = R.getLookupName(); SourceLocation TypoLoc = R.getNameLoc(); + #if 0 + DeclContext *DC = SS.isSet() + ? SemaRef.computeDeclContext(SS) + : SemaRef.computeDeclContext(RTy); + #endif struct QueryState { Sema &SemaRef; diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index d3a9c7abd0e944..ca67a8445fc0a3 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -2716,39 +2716,57 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, /// context of the scope-specifier SS (if present). /// /// @returns True if any decls were found (but possibly ambiguous) -bool Sema::LookupParsedName(LookupResult &R, Scope *S, CXXScopeSpec *SS, - bool AllowBuiltinCreation, bool EnteringContext) { +bool Sema::LookupParsedName(LookupResult &R, + Scope *S, + CXXScopeSpec *SS, + QualType ObjectType, + bool AllowBuiltinCreation, + bool EnteringContext) { if (SS && SS->isInvalid()) { // When the scope specifier is invalid, don't even look for // anything. return false; } - if (SS && SS->isSet()) { - NestedNameSpecifier *NNS = SS->getScopeRep(); - if (NNS->getKind() == NestedNameSpecifier::Super) + // Determine where to perform name lookup + DeclContext *DC = nullptr; + 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 || SS->isEmpty()) && "ObjectType and scope specifier cannot coexist"); + DC = computeDeclContext(ObjectType); + assert(((!DC && ObjectType->isDependentType()) || + !ObjectType->isIncompleteType() || + !ObjectType->getAs<TagType>() || + ObjectType->castAs<TagType>()->isBeingDefined()) && + "Caller should have completed object type"); + } else if (SS && SS->isNotEmpty()) { + if (NestedNameSpecifier *NNS = SS->getScopeRep(); + NNS->getKind() == NestedNameSpecifier::Super) return LookupInSuper(R, NNS->getAsRecordDecl()); - - if (DeclContext *DC = computeDeclContext(*SS, EnteringContext)) { - // We have resolved the scope specifier to a particular declaration - // contex, and will perform name lookup in that context. + // This nested-name-specifier occurs after another nested-name-specifier, + // so long into the context associated with the prior nested-name-specifier. + if (DC = computeDeclContext(*SS, EnteringContext)) { + // The declaration context must be complete. if (!DC->isDependentContext() && RequireCompleteDeclContext(*SS, DC)) return false; - R.setContextRange(SS->getRange()); - return LookupQualifiedName(R, DC); } - - // We could not resolve the scope specified to a specific declaration - // context, which means that SS refers to an unknown specialization. - // Name lookup can't find anything in this case. - R.setNotFoundInCurrentInstantiation(); - R.setContextRange(SS->getRange()); - return false; + } else { + // Perform unqualified name lookup starting in the given scope. + return LookupName(R, S, AllowBuiltinCreation); } - // Perform unqualified name lookup starting in the given scope. - return LookupName(R, S, AllowBuiltinCreation); + // If we were able to compute a declaration context, perform qualified name + // lookup in that context. + if (DC) + return LookupQualifiedName(R, DC); + + // We could not resolve the scope specified to a specific declaration + // context, which means that SS refers to an unknown specialization. + // Name lookup can't find anything in this case. + R.setNotFoundInCurrentInstantiation(); + return false; } /// Perform qualified name lookup into all base classes of the given @@ -5011,7 +5029,9 @@ static void LookupPotentialTypoResult(Sema &SemaRef, return; } - SemaRef.LookupParsedName(Res, S, SS, /*AllowBuiltinCreation=*/false, + SemaRef.LookupParsedName(Res, S, SS, + /*ObjectType=*/QualType(), + /*AllowBuiltinCreation=*/false, EnteringContext); // Fake ivar lookup; this should really be part of diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index e9ad7bbde0f9b5..4266347933101e 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -3052,7 +3052,9 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope, const DeclarationNameInfo &Id, OpenMPDirectiveKind Kind) { LookupResult Lookup(*this, Id, LookupOrdinaryName); - LookupParsedName(Lookup, CurScope, &ScopeSpec, true); + LookupParsedName(Lookup, CurScope, &ScopeSpec, + /*ObjectType=*/QualType(), + /*AllowBuiltinCreation=*/true); if (Lookup.isAmbiguous()) return ExprError(); @@ -7303,7 +7305,7 @@ void Sema::ActOnStartOfFunctionDefinitionInOpenMPDeclareVariantScope( IdentifierInfo *BaseII = D.getIdentifier(); LookupResult Lookup(*this, DeclarationName(BaseII), D.getIdentifierLoc(), LookupOrdinaryName); - LookupParsedName(Lookup, S, &D.getCXXScopeSpec()); + LookupParsedName(Lookup, S, &D.getCXXScopeSpec(), /*ObjectType=*/QualType()); TypeSourceInfo *TInfo = GetTypeForDeclarator(D); QualType FType = TInfo->getType(); @@ -19157,7 +19159,7 @@ buildDeclareReductionRef(Sema &SemaRef, SourceLocation Loc, SourceRange Range, if (S) { LookupResult Lookup(SemaRef, ReductionId, Sema::LookupOMPReductionName); Lookup.suppressDiagnostics(); - while (S && SemaRef.LookupParsedName(Lookup, S, &ReductionIdScopeSpec)) { + while (S && SemaRef.LookupParsedName(Lookup, S, &ReductionIdScopeSpec, /*ObjectType=*/QualType())) { NamedDecl *D = Lookup.getRepresentativeDecl(); do { S = S->getParent(); @@ -22010,7 +22012,7 @@ static ExprResult buildUserDefinedMapperRef(Sema &SemaRef, Scope *S, LookupResult Lookup(SemaRef, MapperId, Sema::LookupOMPMapperName); Lookup.suppressDiagnostics(); if (S) { - while (S && SemaRef.LookupParsedName(Lookup, S, &MapperIdScopeSpec)) { + while (S && SemaRef.LookupParsedName(Lookup, S, &MapperIdScopeSpec, /*ObjectType=*/QualType())) { NamedDecl *D = Lookup.getRepresentativeDecl(); while (S && !S->isDeclScope(D)) S = S->getParent(); @@ -23317,7 +23319,9 @@ NamedDecl *Sema::lookupOpenMPDeclareTargetName(Scope *CurScope, CXXScopeSpec &ScopeSpec, const DeclarationNameInfo &Id) { LookupResult Lookup(*this, Id, LookupOrdinaryName); - LookupParsedName(Lookup, CurScope, &ScopeSpec, true); + LookupParsedName(Lookup, CurScope, &ScopeSpec, + /*ObjectType=*/QualType(), + /*AllowBuiltinCreation=*/true); if (Lookup.isAmbiguous()) return nullptr; diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 005529a53270c3..4f7c9c4f44b635 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -5668,7 +5668,7 @@ bool Sema::CheckTemplateTypeArgument( if (auto *II = NameInfo.getName().getAsIdentifierInfo()) { LookupResult Result(*this, NameInfo, LookupOrdinaryName); - LookupParsedName(Result, CurScope, &SS); + LookupParsedName(Result, CurScope, &SS, /*ObjectType=*/QualType()); if (Result.getAsSingle<TypeDecl>() || Result.getResultKind() == @@ -11025,7 +11025,7 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, : TSK_ExplicitInstantiationDeclaration; LookupResult Previous(*this, NameInfo, LookupOrdinaryName); - LookupParsedName(Previous, S, &D.getCXXScopeSpec()); + LookupParsedName(Previous, S, &D.getCXXScopeSpec(), /*ObjectType=*/QualType()); if (!R->isFunctionType()) { // C++ [temp.explicit]p1: >From 6d7e156bf12dc82ffcd67f0c181845ffb8954335 Mon Sep 17 00:00:00 2001 From: Krystian Stasiowski <sdkryst...@gmail.com> Date: Fri, 8 Mar 2024 10:09:40 -0500 Subject: [PATCH 10/14] [FOLD] use LookupParsedName for class member access --- clang/lib/Sema/SemaExprMember.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp index bb58bf6c7ca55f..2af37e8b635241 100644 --- a/clang/lib/Sema/SemaExprMember.cpp +++ b/clang/lib/Sema/SemaExprMember.cpp @@ -675,7 +675,7 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, CXXScopeSpec &SS, bool HasTemplateArgs, SourceLocation TemplateKWLoc, TypoExpr *&TE) { - #if 1 + #if 0 DeclContext *DC = SemaRef.computeDeclContext(RTy); // If the object expression is dependent and isn't the current instantiation, // lookup will not find anything and we must defer until instantiation. @@ -704,15 +704,18 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, QualType ObjectType = SS.isSet() ? QualType() : RTy; if (HasTemplateArgs || TemplateKWLoc.isValid()) { bool MOUS; - return SemaRef.LookupTemplateName(R, + bool Invalid = SemaRef.LookupTemplateName(R, /*S=*/nullptr, SS, ObjectType, /*EnteringContext=*/false, MOUS, TemplateKWLoc); + if (MOUS) + R.setNotFoundInCurrentInstantiation(); + return Invalid; } - #if 0 + #if 1 SemaRef.LookupParsedName(R, /*S=*/nullptr, &SS, ObjectType); #else if (SS.isSet()) { @@ -750,7 +753,7 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, DeclarationName Typo = R.getLookupName(); SourceLocation TypoLoc = R.getNameLoc(); - #if 0 + #if 1 DeclContext *DC = SS.isSet() ? SemaRef.computeDeclContext(SS) : SemaRef.computeDeclContext(RTy); >From 3b855de87516d16962a2a86e5596743ce8062ec3 Mon Sep 17 00:00:00 2001 From: Krystian Stasiowski <sdkryst...@gmail.com> Date: Fri, 8 Mar 2024 11:45:40 -0500 Subject: [PATCH 11/14] [FOLD] update tests --- clang/test/CXX/drs/dr2xx.cpp | 12 ++++++------ clang/test/CXX/drs/dr3xx.cpp | 26 +++++++++++++------------- clang/test/SemaCXX/member-expr.cpp | 4 ++-- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/clang/test/CXX/drs/dr2xx.cpp b/clang/test/CXX/drs/dr2xx.cpp index cbb8734e10c649..e321dbfe95d4ff 100644 --- a/clang/test/CXX/drs/dr2xx.cpp +++ b/clang/test/CXX/drs/dr2xx.cpp @@ -556,9 +556,9 @@ namespace dr244 { // dr244: 11 B_ptr->B_alias::~B(); B_ptr->B_alias::~B_alias(); B_ptr->dr244::~B(); - // expected-error@-1 {{qualified member access refers to a member in namespace 'dr244'}} + // expected-error@-1 {{no member named '~B' in namespace 'dr244'}} B_ptr->dr244::~B_alias(); - // expected-error@-1 {{qualified member access refers to a member in namespace 'dr244'}} + // expected-error@-1 {{no member named '~B' in namespace 'dr244'}} } template<typename T, typename U> @@ -724,7 +724,7 @@ namespace dr252 { // dr252: 3.1 struct E { void operator delete(void*, int); void operator delete(void*) = delete; // #dr252-E - // cxx98-error@-1 {{deleted function definitions are a C++11 extension}} + // cxx98-error@-1 {{deleted function definitions are a C++11 extension}} virtual ~E(); }; E::~E() {} @@ -831,7 +831,7 @@ namespace dr258 { // dr258: 2.8 namespace dr259 { // dr259: 4 template<typename T> struct A {}; - template struct A<int>; // #dr259-A-int + template struct A<int>; // #dr259-A-int template struct A<int>; // expected-error@-1 {{duplicate explicit instantiation of 'A<int>'}} // expected-note@#dr259-A-int {{previous explicit instantiation is here}} @@ -992,7 +992,7 @@ namespace dr275 { // dr275: no // expected-error@-1 {{no function template matches function template specialization 'f'}} } - template <class T> void g(T) {} // #dr275-g + template <class T> void g(T) {} // #dr275-g template <> void N::f(char) {} template <> void f(int) {} @@ -1159,7 +1159,7 @@ namespace dr285 { // dr285: yes namespace dr286 { // dr286: 2.8 template<class T> struct A { class C { - template<class T2> struct B {}; // #dr286-B + template<class T2> struct B {}; // #dr286-B }; }; diff --git a/clang/test/CXX/drs/dr3xx.cpp b/clang/test/CXX/drs/dr3xx.cpp index 4584801f9f9714..fde4e186e6c033 100644 --- a/clang/test/CXX/drs/dr3xx.cpp +++ b/clang/test/CXX/drs/dr3xx.cpp @@ -23,7 +23,7 @@ namespace dr301 { // dr301: 3.5 bool b = (void(*)(S, S))operator- < (void(*)(S, S))operator-; // cxx98-17-warning@-1 {{ordered comparison of function pointers ('void (*)(S, S)' and 'void (*)(S, S)')}} // cxx20-23-error@-2 {{expected '>'}} - // cxx20-23-note@-3 {{to match this '<'}} + // cxx20-23-note@-3 {{to match this '<'}} bool c = (void(*)(S, S))operator+ < (void(*)(S, S))operator-; // expected-error@-1 {{expected '>'}} // expected-note@-2 {{to match this '<'}} @@ -432,7 +432,7 @@ namespace dr329 { // dr329: 3.5 // expected-note@#dr329-b {{in instantiation of template class 'dr329::A<char>' requested here}} // expected-note@#dr329-i {{previous definition is here}} }; - A<int> a; + A<int> a; A<char> b; // #dr329-b void test() { @@ -631,7 +631,7 @@ namespace dr339 { // dr339: 2.8 char xxx(int); char (&xxx(float))[2]; - template<class T> A<sizeof(xxx((T)0))> f(T) {} // #dr339-f + template<class T> A<sizeof(xxx((T)0))> f(T) {} // #dr339-f void test() { A<1> a = f(0); @@ -673,9 +673,9 @@ namespace dr341 { // dr341: sup 1708 namespace B { extern "C" int &dr341_a = dr341_a; // expected-error@-1 {{redefinition of 'dr341_a'}} - // expected-note@#dr341_a {{previous definition is here}} + // expected-note@#dr341_a {{previous definition is here}} } - extern "C" void dr341_b(); // #dr341_b + extern "C" void dr341_b(); // #dr341_b } int dr341_a; // expected-error@-1 {{declaration of 'dr341_a' in global scope conflicts with declaration with C language linkage}} @@ -693,7 +693,7 @@ namespace dr341 { // expected-error@-1 {{declaration of 'dr341_d' with C language linkage conflicts with declaration in global scope}} // expected-note@#dr341_d {{declared in global scope here}} - namespace A { extern "C" int dr341_e; } // #dr341_e + namespace A { extern "C" int dr341_e; } // #dr341_e namespace B { extern "C" void dr341_e(); } // expected-error@-1 {{redefinition of 'dr341_e' as different kind of symbol}} // expected-note@#dr341_e {{previous definition is here}} @@ -817,7 +817,7 @@ namespace dr352 { // dr352: 2.8 void g(A::E e) { foo(e, &arg); // expected-error@-1 {{no matching function for call to 'foo'}} - // expected-note@#dr352-foo {{candidate template ignored: couldn't infer template argument 'R'}} + // expected-note@#dr352-foo {{candidate template ignored: couldn't infer template argument 'R'}} using A::foo; foo<int, int>(e, &arg); // ok, uses non-template @@ -918,7 +918,7 @@ namespace dr352 { // dr352: 2.8 namespace example5 { template<int I> class A {}; - template<int I> void g(A<I+1>); // #dr352-g + template<int I> void g(A<I+1>); // #dr352-g template<int I> void f(A<I>, A<I+1>); void h(A<1> a1, A<2> a2) { g(a1); @@ -1095,7 +1095,7 @@ namespace dr364 { // dr364: yes } // dr366: yes -#if "foo" // expected-error {{invalid token at start of a preprocessor expression}} +#if "foo" // expected-error {{invalid token at start of a preprocessor expression}} #endif namespace dr367 { // dr367: yes @@ -1252,7 +1252,7 @@ namespace dr373 { // dr373: 5 } }; - struct A { struct B {}; }; // #dr373-A + struct A { struct B {}; }; // #dr373-A namespace X = A::B; // expected-error@-1 {{expected namespace name}} // expected-note@#dr373-A {{'A' declared here}} @@ -1585,7 +1585,7 @@ namespace dr395 { // dr395: 3.0 // expected-error@-2 {{conversion function cannot have any parameters}} // expected-error@-3 {{cannot specify any part of a return type in the declaration of a conversion function}} // expected-error@-4 {{conversion function cannot convert to a function type}} - + }; struct null1_t { @@ -1698,9 +1698,9 @@ namespace dr399 { // dr399: 11 B_ptr->B_alias::~B(); B_ptr->B_alias::~B_alias(); B_ptr->dr399::~B(); - // expected-error@-1 {{qualified member access refers to a member in namespace 'dr399'}} + // expected-error@-1 {{no member named '~B' in namespace 'dr399'}} B_ptr->dr399::~B_alias(); - // expected-error@-1 {{qualified member access refers to a member in namespace 'dr399'}} + // expected-error@-1 {{no member named '~B' in namespace 'dr399'}} } template<typename T, typename U> diff --git a/clang/test/SemaCXX/member-expr.cpp b/clang/test/SemaCXX/member-expr.cpp index 75c9ef0caa2e00..0596e40f6c2f6a 100644 --- a/clang/test/SemaCXX/member-expr.cpp +++ b/clang/test/SemaCXX/member-expr.cpp @@ -40,8 +40,8 @@ namespace C { } void test2(X *xp) { - xp->::i = 7; // expected-error{{qualified member access refers to a member in the global namespace}} - xp->C::i = 7; // expected-error{{qualified member access refers to a member in namespace 'C'}} + xp->::i = 7; // expected-error{{'i' is not a member of class 'X'}} + xp->C::i = 7; // expected-error{{'C::i' is not a member of class 'X'}} } >From e76fbf468b589755b0552375f17ed143dce2f5a0 Mon Sep 17 00:00:00 2001 From: Krystian Stasiowski <sdkryst...@gmail.com> Date: Fri, 8 Mar 2024 11:47:20 -0500 Subject: [PATCH 12/14] [FOLD] discard invalid nested-name-specifiers --- clang/include/clang/Sema/Lookup.h | 2 +- clang/lib/Sema/SemaExprMember.cpp | 23 ++++++++++++++++++++--- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/clang/include/clang/Sema/Lookup.h b/clang/include/clang/Sema/Lookup.h index 2f2f2607a937fe..16c23dd903e86a 100644 --- a/clang/include/clang/Sema/Lookup.h +++ b/clang/include/clang/Sema/Lookup.h @@ -496,7 +496,7 @@ class LookupResult { /// Note that while no result was found in the current instantiation, /// there were dependent base classes that could not be searched. void setNotFoundInCurrentInstantiation() { - assert(ResultKind == NotFound && Decls.empty()); + assert((ResultKind == NotFound || ResultKind == NotFoundInCurrentInstantiation) && Decls.empty()); ResultKind = NotFoundInCurrentInstantiation; } diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp index 2af37e8b635241..086730bfec3b02 100644 --- a/clang/lib/Sema/SemaExprMember.cpp +++ b/clang/lib/Sema/SemaExprMember.cpp @@ -815,6 +815,9 @@ ExprResult Sema::BuildMemberReferenceExpr( ActOnMemberAccessExtraArgs *ExtraArgs) { LookupResult R(*this, NameInfo, LookupMemberName); + if (SS.isInvalid()) + SS.clear(); + // Implicit member accesses. if (!Base) { TypoExpr *TE = nullptr; @@ -1014,7 +1017,7 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, const Scope *S, bool SuppressQualifierCheck, ActOnMemberAccessExtraArgs *ExtraArgs) { - + assert(!SS.isInvalid() && "nested-name-specifier cannot be invalid"); if (R.wasNotFoundInCurrentInstantiation() || (SS.isValid() && !computeDeclContext(SS, false))) { return ActOnDependentMemberExpr(BaseExpr, BaseExprType, IsArrow, OpLoc, SS, @@ -1059,7 +1062,8 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, if (R.empty()) { // Rederive where we looked up. DeclContext *DC = (SS.isSet() ? computeDeclContext(SS, false) - : BaseType->getAsRecordDecl()); + : computeDeclContext(BaseType)); + // : BaseType->getAsRecordDecl()); if (ExtraArgs) { ExprResult RetryExpr; @@ -1086,7 +1090,10 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, } } - if (DC) { + if (SS.isInvalid() || (SS.isNotEmpty() && !DC)) { + Diag(R.getNameLoc(), diag::err_undeclared_use) + << MemberName << SS.getRange(); + } else if (DC) { Diag(R.getNameLoc(), diag::err_no_member) << MemberName << DC << (BaseExpr ? BaseExpr->getSourceRange() : SourceRange()); @@ -1096,6 +1103,16 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, << MemberName << BaseExprType << (BaseExpr ? BaseExpr->getSourceRange() : SourceRange()); } + + if (DC) { + } else { + #if 0 + // FIXME: Is this needed? + Diag(R.getNameLoc(), diag::err_no_member) + << MemberName << BaseExprType + << (BaseExpr ? BaseExpr->getSourceRange() : SourceRange()); + #endif + } return ExprError(); } >From 3c9d3eac874f675a66b537fbd6f14debc4b5c412 Mon Sep 17 00:00:00 2001 From: Krystian Stasiowski <sdkryst...@gmail.com> Date: Fri, 8 Mar 2024 13:58:04 -0500 Subject: [PATCH 13/14] [FOLD] --- clang/include/clang/Sema/Sema.h | 6 ++++++ clang/lib/Sema/SemaLookup.cpp | 19 ++++++++++--------- clang/lib/Sema/SemaTemplate.cpp | 26 +++++++++++++++++--------- 3 files changed, 33 insertions(+), 18 deletions(-) diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index a085f9ca09f1b8..e0f20a67116422 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -9138,6 +9138,12 @@ class Sema final { bool EnteringContext, bool &MemberOfUnknownSpecialization, RequiredTemplateKind RequiredTemplate = SourceLocation(), AssumedTemplateKind *ATK = nullptr, bool AllowTypoCorrection = true); + + bool LookupTemplateName( + LookupResult &R, Scope *S, CXXScopeSpec &SS, QualType ObjectType, + bool EnteringContext, + RequiredTemplateKind RequiredTemplate = SourceLocation(), + AssumedTemplateKind *ATK = nullptr, bool AllowTypoCorrection = true); TemplateNameKind isTemplateName(Scope *S, CXXScopeSpec &SS, bool hasTemplateKeyword, diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index ca67a8445fc0a3..a4594170a6df57 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -2722,19 +2722,19 @@ bool Sema::LookupParsedName(LookupResult &R, QualType ObjectType, bool AllowBuiltinCreation, bool EnteringContext) { - if (SS && SS->isInvalid()) { - // When the scope specifier is invalid, don't even look for - // anything. + // When the scope specifier is invalid, don't even look for anything. + if (SS && SS->isInvalid()) return false; - } // Determine where to perform name lookup DeclContext *DC = 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 || SS->isEmpty()) && "ObjectType and scope specifier cannot coexist"); DC = computeDeclContext(ObjectType); + IsDependent = !DC && ObjectType->isDependentType(); assert(((!DC && ObjectType->isDependentType()) || !ObjectType->isIncompleteType() || !ObjectType->getAs<TagType>() || @@ -2752,6 +2752,7 @@ bool Sema::LookupParsedName(LookupResult &R, return false; R.setContextRange(SS->getRange()); } + IsDependent = !DC && isDependentScopeSpecifier(*SS); } else { // Perform unqualified name lookup starting in the given scope. return LookupName(R, S, AllowBuiltinCreation); @@ -2761,11 +2762,11 @@ bool Sema::LookupParsedName(LookupResult &R, // lookup in that context. if (DC) return LookupQualifiedName(R, DC); - - // We could not resolve the scope specified to a specific declaration - // context, which means that SS refers to an unknown specialization. - // Name lookup can't find anything in this case. - R.setNotFoundInCurrentInstantiation(); + else if (IsDependent) + // We could not resolve the scope specified to a specific declaration + // context, which means that SS refers to an unknown specialization. + // Name lookup can't find anything in this case. + R.setNotFoundInCurrentInstantiation(); return false; } diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 4f7c9c4f44b635..dae692852d405e 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -319,15 +319,12 @@ TemplateNameKind Sema::isTemplateName(Scope *S, bool Sema::isDeductionGuideName(Scope *S, const IdentifierInfo &Name, SourceLocation NameLoc, CXXScopeSpec &SS, ParsedTemplateTy *Template /*=nullptr*/) { - bool MemberOfUnknownSpecialization = false; - // We could use redeclaration lookup here, but we don't need to: the // syntactic form of a deduction guide is enough to identify it even // if we can't look up the template name at all. LookupResult R(*this, DeclarationName(&Name), NameLoc, LookupOrdinaryName); if (LookupTemplateName(R, S, SS, /*ObjectType*/ QualType(), - /*EnteringContext*/ false, - MemberOfUnknownSpecialization)) + /*EnteringContext*/ false)) return false; if (R.empty()) return false; @@ -373,6 +370,19 @@ bool Sema::DiagnoseUnknownTemplateName(const IdentifierInfo &II, return true; } +bool Sema::LookupTemplateName(LookupResult &Found, + Scope *S, CXXScopeSpec &SS, + QualType ObjectType, + bool EnteringContext, + RequiredTemplateKind RequiredTemplate, + AssumedTemplateKind *ATK, + bool AllowTypoCorrection) { + bool MemberOfUnknownSpecialization; + return LookupTemplateName(Found, S, SS, ObjectType, EnteringContext, + MemberOfUnknownSpecialization, RequiredTemplate, + ATK, AllowTypoCorrection); +} + bool Sema::LookupTemplateName(LookupResult &Found, Scope *S, CXXScopeSpec &SS, QualType ObjectType, @@ -5447,10 +5457,9 @@ Sema::BuildQualifiedTemplateIdExpr(CXXScopeSpec &SS, RequireCompleteDeclContext(SS, DC)) return BuildDependentDeclRefExpr(SS, TemplateKWLoc, NameInfo, TemplateArgs); - bool MemberOfUnknownSpecialization; LookupResult R(*this, NameInfo, LookupOrdinaryName); if (LookupTemplateName(R, (Scope *)nullptr, SS, QualType(), - /*Entering*/false, MemberOfUnknownSpecialization, + /*Entering*/false, TemplateKWLoc)) return ExprError(); @@ -5572,14 +5581,13 @@ TemplateNameKind Sema::ActOnTemplateName(Scope *S, DeclarationNameInfo DNI = GetNameFromUnqualifiedId(Name); LookupResult R(*this, DNI.getName(), Name.getBeginLoc(), LookupOrdinaryName); - bool MOUS; // Tell LookupTemplateName that we require a template so that it diagnoses // cases where it finds a non-template. RequiredTemplateKind RTK = TemplateKWLoc.isValid() ? RequiredTemplateKind(TemplateKWLoc) : TemplateNameIsRequired; - if (!LookupTemplateName(R, S, SS, ObjectType.get(), EnteringContext, MOUS, - RTK, nullptr, /*AllowTypoCorrection=*/false) && + if (!LookupTemplateName(R, S, SS, ObjectType.get(), EnteringContext, + RTK, /*ATK=*/nullptr, /*AllowTypoCorrection=*/false) && !R.isAmbiguous()) { if (LookupCtx) Diag(Name.getBeginLoc(), diag::err_no_member) >From 7f19dbe72e4a976db07dd14e99f617700ec12f25 Mon Sep 17 00:00:00 2001 From: Krystian Stasiowski <sdkryst...@gmail.com> Date: Mon, 11 Mar 2024 07:20:00 -0400 Subject: [PATCH 14/14] [FOLD] --- clang/lib/Sema/SemaExpr.cpp | 3 +-- clang/lib/Sema/SemaExprMember.cpp | 5 +---- clang/lib/Sema/SemaTemplate.cpp | 2 ++ 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 7a28083054c2da..d945e08369d9a0 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -2757,8 +2757,7 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS, &AssumedTemplate)) return ExprError(); - if (MemberOfUnknownSpecialization || - (R.getResultKind() == LookupResult::NotFoundInCurrentInstantiation)) + if (R.wasNotFoundInCurrentInstantiation()) return ActOnDependentIdExpression(SS, TemplateKWLoc, NameInfo, IsAddressOfOperand, TemplateArgs); } else { diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp index 086730bfec3b02..260a6a203334fd 100644 --- a/clang/lib/Sema/SemaExprMember.cpp +++ b/clang/lib/Sema/SemaExprMember.cpp @@ -704,16 +704,13 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, QualType ObjectType = SS.isSet() ? QualType() : RTy; if (HasTemplateArgs || TemplateKWLoc.isValid()) { bool MOUS; - bool Invalid = SemaRef.LookupTemplateName(R, + return SemaRef.LookupTemplateName(R, /*S=*/nullptr, SS, ObjectType, /*EnteringContext=*/false, MOUS, TemplateKWLoc); - if (MOUS) - R.setNotFoundInCurrentInstantiation(); - return Invalid; } #if 1 SemaRef.LookupParsedName(R, /*S=*/nullptr, &SS, ObjectType); diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index dae692852d405e..5ec50df2c10b99 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -213,6 +213,7 @@ TemplateNameKind Sema::isTemplateName(Scope *S, &AssumedTemplate, /*AllowTypoCorrection=*/!Disambiguation)) return TNK_Non_template; + MemberOfUnknownSpecialization = R.wasNotFoundInCurrentInstantiation(); if (AssumedTemplate != AssumedTemplateKind::None) { TemplateResult = TemplateTy::make(Context.getAssumedTemplateName(TName)); @@ -558,6 +559,7 @@ bool Sema::LookupTemplateName(LookupResult &Found, if (Found.empty()) { if (IsDependent) { MemberOfUnknownSpecialization = true; + Found.setNotFoundInCurrentInstantiation(); return false; } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits