diff options
author | Pranav Kant <prka@google.com> | 2024-04-26 00:18:08 +0000 |
---|---|---|
committer | Pranav Kant <prka@google.com> | 2024-04-26 00:18:08 +0000 |
commit | 0c6e1ca1c704a3a0fb53ae54f7e3723736f477c7 (patch) | |
tree | d37068c5c994c1a90ba67d13f3a682d9dfd41331 /clang/lib | |
parent | 45fc0e6b38b62a61b0ddcda2e7fe9b4fee7e3e58 (diff) | |
download | llvm-0c6e1ca1c704a3a0fb53ae54f7e3723736f477c7.zip llvm-0c6e1ca1c704a3a0fb53ae54f7e3723736f477c7.tar.gz llvm-0c6e1ca1c704a3a0fb53ae54f7e3723736f477c7.tar.bz2 |
Revert "[Clang][Sema] Diagnose class member access expressions naming non-existent members of the current instantiation prior to instantiation in the absence of dependent base classes (#84050)"
This reverts commit a8fd0d029dca7d17eee72d0445223c2fe1ee7758.
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/AST/Expr.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Parse/ParseDecl.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Sema/HLSLExternalSemaSource.cpp | 7 | ||||
-rw-r--r-- | clang/lib/Sema/SemaAttr.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 7 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 6 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 20 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExprCXX.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExprMember.cpp | 182 | ||||
-rw-r--r-- | clang/lib/Sema/SemaLookup.cpp | 114 | ||||
-rw-r--r-- | clang/lib/Sema/SemaOpenMP.cpp | 17 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplate.cpp | 32 | ||||
-rw-r--r-- | clang/lib/Sema/TreeTransform.h | 20 |
13 files changed, 175 insertions, 238 deletions
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index d2e40be..63dcdb9 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()->getAsRecordDecl()); + assert(ME->getBase()->getType()->isRecordType()); if (const auto *Field = dyn_cast<FieldDecl>(ME->getMemberDecl())) { if (!Field->isBitField() && !Field->getType()->isReferenceType()) { E = ME->getBase(); diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 53a33fa..05ad5ec 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -2998,7 +2998,7 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, << TokenName << TagName << getLangOpts().CPlusPlus << FixItHint::CreateInsertion(Tok.getLocation(), FixitTagName); - if (Actions.LookupName(R, getCurScope())) { + if (Actions.LookupParsedName(R, getCurScope(), SS)) { 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 bb283c5..1a1febf 100644 --- a/clang/lib/Sema/HLSLExternalSemaSource.cpp +++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp @@ -126,15 +126,12 @@ struct BuiltinTypeDeclBuilder { static DeclRefExpr *lookupBuiltinFunction(ASTContext &AST, Sema &S, StringRef Name) { + CXXScopeSpec SS; IdentifierInfo &II = AST.Idents.get(Name, tok::TokenKind::identifier); DeclarationNameInfo NameInfo = DeclarationNameInfo(DeclarationName(&II), SourceLocation()); LookupResult R(S, NameInfo, Sema::LookupOrdinaryName); - // AllowBuiltinCreation is false but LookupDirect will create - // the builtin when searching the global scope anyways... - S.LookupName(R, S.getCurScope()); - // FIXME: If the builtin function was user-declared in global scope, - // this assert *will* fail. Should this call LookupBuiltin instead? + S.LookupParsedName(R, S.getCurScope(), &SS, 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 a83b1e8..a5dd158 100644 --- a/clang/lib/Sema/SemaAttr.cpp +++ b/clang/lib/Sema/SemaAttr.cpp @@ -837,7 +837,7 @@ void Sema::ActOnPragmaUnused(const Token &IdTok, Scope *curScope, IdentifierInfo *Name = IdTok.getIdentifierInfo(); LookupResult Lookup(*this, Name, IdTok.getLocation(), LookupOrdinaryName); - LookupName(Lookup, curScope, /*AllowBuiltinCreation=*/true); + LookupParsedName(Lookup, curScope, nullptr, 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 4e275dc..e0745fe9 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -832,7 +832,7 @@ static bool isTagTypeWithMissingTag(Sema &SemaRef, LookupResult &Result, IdentifierInfo *&Name, SourceLocation NameLoc) { LookupResult R(SemaRef, Name, NameLoc, Sema::LookupTagName); - SemaRef.LookupParsedName(R, S, &SS, /*ObjectType=*/QualType()); + SemaRef.LookupParsedName(R, S, &SS); if (TagDecl *Tag = R.getAsSingle<TagDecl>()) { StringRef FixItTagName; switch (Tag->getTagKind()) { @@ -869,7 +869,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, /*ObjectType=*/QualType()); + SemaRef.LookupParsedName(Result, S, &SS); return true; } @@ -896,8 +896,7 @@ Sema::NameClassification Sema::ClassifyName(Scope *S, CXXScopeSpec &SS, } LookupResult Result(*this, Name, NameLoc, LookupOrdinaryName); - LookupParsedName(Result, S, &SS, /*ObjectType=*/QualType(), - /*AllowBuiltinCreation=*/!CurMethod); + LookupParsedName(Result, S, &SS, !CurMethod); if (SS.isInvalid()) return NameClassification::Error(); diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 4d58367..abdbc9d 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -4517,7 +4517,7 @@ Sema::BuildMemInitializer(Decl *ConstructorD, DS.getBeginLoc(), DS.getEllipsisLoc()); } else { LookupResult R(*this, MemberOrBase, IdLoc, LookupOrdinaryName); - LookupParsedName(R, S, &SS, /*ObjectType=*/QualType()); + LookupParsedName(R, S, &SS); TypeDecl *TyD = R.getAsSingle<TypeDecl>(); if (!TyD) { @@ -12262,7 +12262,7 @@ Decl *Sema::ActOnUsingDirective(Scope *S, SourceLocation UsingLoc, // Lookup namespace name. LookupResult R(*this, NamespcName, IdentLoc, LookupNamespaceName); - LookupParsedName(R, S, &SS, /*ObjectType=*/QualType()); + LookupParsedName(R, S, &SS); if (R.isAmbiguous()) return nullptr; @@ -13721,7 +13721,7 @@ Decl *Sema::ActOnNamespaceAliasDef(Scope *S, SourceLocation NamespaceLoc, // Lookup the namespace name. LookupResult R(*this, Ident, IdentLoc, LookupNamespaceName); - LookupParsedName(R, S, &SS, /*ObjectType=*/QualType()); + LookupParsedName(R, S, &SS); if (R.isAmbiguous()) return nullptr; diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 0c37f43f7..50f92c4 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -673,9 +673,8 @@ 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())) + T->isDependentType() || + T->isRecordType())) return E; // The C standard is actually really unclear on this point, and @@ -2752,8 +2751,8 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS, if (isBoundsAttrContext() && !getLangOpts().CPlusPlus && S->isClassScope()) { // See if this is reference to a field of struct. LookupResult R(*this, NameInfo, LookupMemberName); - // LookupName handles a name lookup from within anonymous struct. - if (LookupName(R, S)) { + // LookupParsedName handles a name lookup from within anonymous struct. + if (LookupParsedName(R, S, &SS)) { if (auto *VD = dyn_cast<ValueDecl>(R.getFoundDecl())) { QualType type = VD->getType().getNonReferenceType(); // This will eventually be translated into MemberExpr upon @@ -2774,19 +2773,20 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS, // lookup to determine that it was a template name in the first place. If // this becomes a performance hit, we can work harder to preserve those // results until we get here but it's likely not worth it. + bool MemberOfUnknownSpecialization; AssumedTemplateKind AssumedTemplate; - if (LookupTemplateName(R, S, SS, /*ObjectType=*/QualType(), - /*EnteringContext=*/false, TemplateKWLoc, + if (LookupTemplateName(R, S, SS, QualType(), /*EnteringContext=*/false, + MemberOfUnknownSpecialization, TemplateKWLoc, &AssumedTemplate)) return ExprError(); - if (R.wasNotFoundInCurrentInstantiation()) + if (MemberOfUnknownSpecialization || + (R.getResultKind() == LookupResult::NotFoundInCurrentInstantiation)) return ActOnDependentIdExpression(SS, TemplateKWLoc, NameInfo, IsAddressOfOperand, TemplateArgs); } else { bool IvarLookupFollowUp = II && !SS.isSet() && getCurMethodDecl(); - LookupParsedName(R, S, &SS, /*ObjectType=*/QualType(), - /*AllowBuiltinCreation=*/!IvarLookupFollowUp); + LookupParsedName(R, S, &SS, !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 c1cb03e..779a416 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -9157,7 +9157,7 @@ Sema::CheckMicrosoftIfExistsSymbol(Scope *S, // Do the redeclaration lookup in the current scope. LookupResult R(*this, TargetNameInfo, Sema::LookupAnyName, RedeclarationKind::NotForRedeclaration); - LookupParsedName(R, S, &SS, /*ObjectType=*/QualType()); + LookupParsedName(R, S, &SS); R.suppressDiagnostics(); switch (R.getResultKind()) { diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp index 0eeb7b1..6e30716 100644 --- a/clang/lib/Sema/SemaExprMember.cpp +++ b/clang/lib/Sema/SemaExprMember.cpp @@ -667,8 +667,8 @@ namespace { // classes, one of its base classes. class RecordMemberExprValidatorCCC final : public CorrectionCandidateCallback { public: - explicit RecordMemberExprValidatorCCC(QualType RTy) - : Record(RTy->getAsRecordDecl()) { + explicit RecordMemberExprValidatorCCC(const RecordType *RTy) + : Record(RTy->getDecl()) { // 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; @@ -713,36 +713,58 @@ private: } static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, - Expr *BaseExpr, QualType RTy, + Expr *BaseExpr, + const RecordType *RTy, SourceLocation OpLoc, bool IsArrow, CXXScopeSpec &SS, bool HasTemplateArgs, SourceLocation TemplateKWLoc, TypoExpr *&TE) { SourceRange BaseRange = BaseExpr ? BaseExpr->getSourceRange() : SourceRange(); - if (!RTy->isDependentType() && - !SemaRef.isThisOutsideMemberFunctionBody(RTy) && - SemaRef.RequireCompleteType( - OpLoc, RTy, diag::err_typecheck_incomplete_tag, BaseRange)) + RecordDecl *RDecl = RTy->getDecl(); + if (!SemaRef.isThisOutsideMemberFunctionBody(QualType(RTy, 0)) && + SemaRef.RequireCompleteType(OpLoc, QualType(RTy, 0), + 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()) - return SemaRef.LookupTemplateName(R, - /*S=*/nullptr, SS, ObjectType, - /*EnteringContext=*/false, TemplateKWLoc); + if (HasTemplateArgs || TemplateKWLoc.isValid()) { + // LookupTemplateName doesn't expect these both to exist simultaneously. + QualType ObjectType = SS.isSet() ? QualType() : QualType(RTy, 0); - SemaRef.LookupParsedName(R, /*S=*/nullptr, &SS, ObjectType); + 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); + + if (SemaRef.RequireCompleteDeclContext(SS, DC)) { + SemaRef.Diag(SS.getRange().getEnd(), diag::err_typecheck_incomplete_tag) + << SS.getRange() << DC; + return true; + } + + assert(DC && "Cannot handle non-computable dependent contexts in lookup"); + + if (!isa<TypeDecl>(DC)) { + SemaRef.Diag(R.getNameLoc(), diag::err_qualified_member_nonclass) + << DC << SS.getRange(); + return true; + } + } - if (!R.empty() || R.wasNotFoundInCurrentInstantiation()) + // The record definition is complete, now look up the member. + SemaRef.LookupQualifiedName(R, DC, SS); + + if (!R.empty()) return false; DeclarationName Typo = R.getLookupName(); SourceLocation TypoLoc = R.getNameLoc(); - // Recompute the lookup context. - DeclContext *DC = SS.isSet() ? SemaRef.computeDeclContext(SS) - : SemaRef.computeDeclContext(RTy); struct QueryState { Sema &SemaRef; @@ -766,8 +788,7 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, << Typo << DC << DroppedSpecifier << SS.getRange()); } else { - SemaRef.Diag(TypoLoc, diag::err_no_member) - << Typo << DC << (SS.isSet() ? SS.getRange() : BaseRange); + SemaRef.Diag(TypoLoc, diag::err_no_member) << Typo << DC << BaseRange; } }, [=](Sema &SemaRef, TypoExpr *TE, TypoCorrection TC) mutable { @@ -793,25 +814,34 @@ 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) { - LookupResult R(*this, NameInfo, LookupMemberName); +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) { + if (BaseType->isDependentType() || + (SS.isSet() && isDependentScopeSpecifier(SS)) || + NameInfo.getName().isDependentName()) + return ActOnDependentMemberExpr(Base, BaseType, + IsArrow, OpLoc, + SS, TemplateKWLoc, FirstQualifierInScope, + NameInfo, TemplateArgs); - if (SS.isInvalid()) - return ExprError(); + LookupResult R(*this, NameInfo, LookupMemberName); // Implicit member accesses. if (!Base) { 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->castAs<RecordType>(), OpLoc, IsArrow, + SS, TemplateArgs != nullptr, TemplateKWLoc, TE)) return ExprError(); if (TE) return TE; @@ -1003,12 +1033,6 @@ 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()) - return ActOnDependentMemberExpr(BaseExpr, BaseExprType, IsArrow, OpLoc, SS, - TemplateKWLoc, FirstQualifierInScope, - R.getLookupNameInfo(), TemplateArgs); - QualType BaseType = BaseExprType; if (IsArrow) { assert(BaseType->isPointerType()); @@ -1016,11 +1040,6 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, } R.setBaseObjectType(BaseType); - assert((SS.isEmpty() - ? !BaseType->isDependentType() || computeDeclContext(BaseType) - : !isDependentScopeSpecifier(SS) || computeDeclContext(SS)) && - "dependent lookup context that isn't the current instantiation?"); - // C++1z [expr.ref]p2: // For the first option (dot) the first expression shall be a glvalue [...] if (!IsArrow && BaseExpr && BaseExpr->isPRValue()) { @@ -1050,11 +1069,13 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, if (R.empty()) { // Rederive where we looked up. - DeclContext *DC = - (SS.isSet() ? computeDeclContext(SS) : computeDeclContext(BaseType)); + DeclContext *DC = (SS.isSet() + ? computeDeclContext(SS, false) + : BaseType->castAs<RecordType>()->getDecl()); + if (ExtraArgs) { ExprResult RetryExpr; - if (!IsArrow && BaseExpr && !BaseExpr->isTypeDependent()) { + if (!IsArrow && BaseExpr) { SFINAETrap Trap(*this, true); ParsedType ObjectType; bool MayBePseudoDestructor = false; @@ -1077,12 +1098,9 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, } } - assert(DC); Diag(R.getNameLoc(), diag::err_no_member) - << MemberName << DC - << (SS.isSet() - ? SS.getRange() - : (BaseExpr ? BaseExpr->getSourceRange() : SourceRange())); + << MemberName << DC + << (BaseExpr ? BaseExpr->getSourceRange() : SourceRange()); return ExprError(); } @@ -1312,6 +1330,7 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R, return ExprError(); QualType BaseType = BaseExpr.get()->getType(); + assert(!BaseType->isDependentType()); DeclarationName MemberName = R.getLookupName(); SourceLocation MemberLoc = R.getNameLoc(); @@ -1323,31 +1342,29 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R, if (IsArrow) { if (const PointerType *Ptr = BaseType->getAs<PointerType>()) BaseType = Ptr->getPointeeType(); - 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, "."); - } - IsArrow = false; - } else if (BaseType->isFunctionType()) { - goto fail; - } else { - S.Diag(MemberLoc, diag::err_typecheck_member_reference_arrow) - << BaseType << BaseExpr.get()->getSourceRange(); - return ExprError(); + else 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, "."); } + IsArrow = false; + } else if (BaseType->isFunctionType()) { + goto fail; + } else { + S.Diag(MemberLoc, diag::err_typecheck_member_reference_arrow) + << BaseType << BaseExpr.get()->getSourceRange(); + return ExprError(); } } @@ -1367,10 +1384,10 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R, } // Handle field access to simple records. - if (BaseType->getAsRecordDecl() || BaseType->isDependentType()) { + if (const RecordType *RTy = BaseType->getAs<RecordType>()) { TypoExpr *TE = nullptr; - if (LookupMemberExprInRecord(S, R, BaseExpr.get(), BaseType, OpLoc, IsArrow, - SS, HasTemplateArgs, TemplateKWLoc, TE)) + if (LookupMemberExprInRecord(S, R, BaseExpr.get(), RTy, OpLoc, IsArrow, SS, + HasTemplateArgs, TemplateKWLoc, TE)) return ExprError(); // Returning valid-but-null is how we indicate to the caller that @@ -1807,6 +1824,13 @@ ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base, if (Result.isInvalid()) return ExprError(); Base = Result.get(); + if (Base->getType()->isDependentType() || Name.isDependentName() || + isDependentScopeSpecifier(SS)) { + return ActOnDependentMemberExpr(Base, Base->getType(), IsArrow, OpLoc, SS, + TemplateKWLoc, FirstQualifierInScope, + NameInfo, TemplateArgs); + } + ActOnMemberAccessExtraArgs ExtraArgs = {S, Id, ObjCImpDecl}; ExprResult Res = BuildMemberReferenceExpr( Base, Base->getType(), OpLoc, IsArrow, SS, TemplateKWLoc, diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index a537ecc..55af414 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -1282,31 +1282,6 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { if (DeclContext *DC = PreS->getEntity()) DeclareImplicitMemberFunctionsWithName(*this, Name, R.getNameLoc(), DC); } - // C++23 [temp.dep.general]p2: - // The component name of an unqualified-id is dependent if - // - it is a conversion-function-id whose conversion-type-id - // is dependent, or - // - it is operator= and the current class is a templated entity, or - // - the unqualified-id is the postfix-expression in a dependent call. - if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName && - Name.getCXXNameType()->isDependentType()) { - R.setNotFoundInCurrentInstantiation(); - return false; - } - - // If this is the name of an implicitly-declared special member function, - // go through the scope stack to implicitly declare - if (isImplicitlyDeclaredMemberFunctionName(Name)) { - for (Scope *PreS = S; PreS; PreS = PreS->getParent()) - if (DeclContext *DC = PreS->getEntity()) { - if (DC->isDependentContext() && isa<CXXRecordDecl>(DC) && - Name.getCXXOverloadedOperator() == OO_Equal) { - R.setNotFoundInCurrentInstantiation(); - return false; - } - DeclareImplicitMemberFunctionsWithName(*this, Name, R.getNameLoc(), DC); - } - } // Implicitly declare member functions with the name we're looking for, if in // fact we are in a scope where it matters. @@ -2471,33 +2446,10 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, } } QL(LookupCtx); - CXXRecordDecl *LookupRec = dyn_cast<CXXRecordDecl>(LookupCtx); - // FIXME: Per [temp.dep.general]p2, an unqualified name is also dependent - // if it's a dependent conversion-function-id or operator= where the current - // class is a templated entity. This should be handled in LookupName. - if (!InUnqualifiedLookup && !R.isForRedeclaration()) { - // C++23 [temp.dep.type]p5: - // A qualified name is dependent if - // - it is a conversion-function-id whose conversion-type-id - // is dependent, or - // - [...] - // - its lookup context is the current instantiation and it - // is operator=, or - // - [...] - if (DeclarationName Name = R.getLookupName(); - (Name.getNameKind() == DeclarationName::CXXConversionFunctionName && - Name.getCXXNameType()->isDependentType()) || - (Name.getCXXOverloadedOperator() == OO_Equal && LookupRec && - LookupRec->isDependentContext())) { - R.setNotFoundInCurrentInstantiation(); - return false; - } - } - if (LookupDirect(*this, R, LookupCtx)) { R.resolveKind(); - if (LookupRec) - R.setNamingClass(LookupRec); + if (isa<CXXRecordDecl>(LookupCtx)) + R.setNamingClass(cast<CXXRecordDecl>(LookupCtx)); return true; } @@ -2519,6 +2471,7 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, // If this isn't a C++ class, we aren't allowed to look into base // classes, we're done. + CXXRecordDecl *LookupRec = dyn_cast<CXXRecordDecl>(LookupCtx); if (!LookupRec || !LookupRec->getDefinition()) return false; @@ -2765,54 +2718,38 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, /// /// @returns True if any decls were found (but possibly ambiguous) bool Sema::LookupParsedName(LookupResult &R, Scope *S, CXXScopeSpec *SS, - QualType ObjectType, bool AllowBuiltinCreation, - bool EnteringContext) { - // When the scope specifier is invalid, don't even look for anything. - if (SS && SS->isInvalid()) + bool AllowBuiltinCreation, bool EnteringContext) { + if (SS && SS->isInvalid()) { + // When the scope specifier is invalid, don't even look for + // anything. 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>() || - ObjectType->castAs<TagType>()->isBeingDefined()) && - "Caller should have completed object type"); - } else if (SS && SS->isNotEmpty()) { - if (NestedNameSpecifier *NNS = SS->getScopeRep(); - NNS->getKind() == NestedNameSpecifier::Super) + if (SS && SS->isSet()) { + NestedNameSpecifier *NNS = SS->getScopeRep(); + if (NNS->getKind() == NestedNameSpecifier::Super) return LookupInSuper(R, NNS->getAsRecordDecl()); - // 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 (DeclContext *DC = computeDeclContext(*SS, EnteringContext)) { + // We have resolved the scope specifier to a particular declaration + // contex, and will perform name lookup in that context. if (!DC->isDependentContext() && RequireCompleteDeclContext(*SS, DC)) return false; + R.setContextRange(SS->getRange()); + return LookupQualifiedName(R, DC); } - IsDependent = !DC && isDependentScopeSpecifier(*SS); - } else { - // 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); - 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; + R.setContextRange(SS->getRange()); + return false; + } + + // Perform unqualified name lookup starting in the given scope. + return LookupName(R, S, AllowBuiltinCreation); } /// Perform qualified name lookup into all base classes of the given @@ -5081,9 +5018,8 @@ static void LookupPotentialTypoResult(Sema &SemaRef, return; } - SemaRef.LookupParsedName(Res, S, SS, - /*ObjectType=*/QualType(), - /*AllowBuiltinCreation=*/false, EnteringContext); + SemaRef.LookupParsedName(Res, S, SS, /*AllowBuiltinCreation=*/false, + EnteringContext); // Fake ivar lookup; this should really be part of // LookupParsedName. diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index cf5447f..cee8da4 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -3061,9 +3061,7 @@ ExprResult SemaOpenMP::ActOnOpenMPIdExpression(Scope *CurScope, OpenMPDirectiveKind Kind) { ASTContext &Context = getASTContext(); LookupResult Lookup(SemaRef, Id, Sema::LookupOrdinaryName); - SemaRef.LookupParsedName(Lookup, CurScope, &ScopeSpec, - /*ObjectType=*/QualType(), - /*AllowBuiltinCreation=*/true); + SemaRef.LookupParsedName(Lookup, CurScope, &ScopeSpec, true); if (Lookup.isAmbiguous()) return ExprError(); @@ -7409,8 +7407,7 @@ void SemaOpenMP::ActOnStartOfFunctionDefinitionInOpenMPDeclareVariantScope( const IdentifierInfo *BaseII = D.getIdentifier(); LookupResult Lookup(SemaRef, DeclarationName(BaseII), D.getIdentifierLoc(), Sema::LookupOrdinaryName); - SemaRef.LookupParsedName(Lookup, S, &D.getCXXScopeSpec(), - /*ObjectType=*/QualType()); + SemaRef.LookupParsedName(Lookup, S, &D.getCXXScopeSpec()); TypeSourceInfo *TInfo = SemaRef.GetTypeForDeclarator(D); QualType FType = TInfo->getType(); @@ -19314,8 +19311,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, - /*ObjectType=*/QualType())) { + while (S && SemaRef.LookupParsedName(Lookup, S, &ReductionIdScopeSpec)) { NamedDecl *D = Lookup.getRepresentativeDecl(); do { S = S->getParent(); @@ -22184,8 +22180,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, - /*ObjectType=*/QualType())) { + while (S && SemaRef.LookupParsedName(Lookup, S, &MapperIdScopeSpec)) { NamedDecl *D = Lookup.getRepresentativeDecl(); while (S && !S->isDeclScope(D)) S = S->getParent(); @@ -23502,9 +23497,7 @@ void SemaOpenMP::DiagnoseUnterminatedOpenMPDeclareTarget() { NamedDecl *SemaOpenMP::lookupOpenMPDeclareTargetName( Scope *CurScope, CXXScopeSpec &ScopeSpec, const DeclarationNameInfo &Id) { LookupResult Lookup(SemaRef, Id, Sema::LookupOrdinaryName); - SemaRef.LookupParsedName(Lookup, CurScope, &ScopeSpec, - /*ObjectType=*/QualType(), - /*AllowBuiltinCreation=*/true); + SemaRef.LookupParsedName(Lookup, CurScope, &ScopeSpec, true); if (Lookup.isAmbiguous()) return nullptr; diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 72bf637..bbcb7c3 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -210,11 +210,10 @@ TemplateNameKind Sema::isTemplateName(Scope *S, AssumedTemplateKind AssumedTemplate; LookupResult R(*this, TName, Name.getBeginLoc(), LookupOrdinaryName); if (LookupTemplateName(R, S, SS, ObjectType, EnteringContext, - /*RequiredTemplate=*/SourceLocation(), + MemberOfUnknownSpecialization, SourceLocation(), &AssumedTemplate, /*AllowTypoCorrection=*/!Disambiguation)) return TNK_Non_template; - MemberOfUnknownSpecialization = R.wasNotFoundInCurrentInstantiation(); if (AssumedTemplate != AssumedTemplateKind::None) { TemplateResult = TemplateTy::make(Context.getAssumedTemplateName(TName)); @@ -321,12 +320,15 @@ 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)) + /*EnteringContext*/ false, + MemberOfUnknownSpecialization)) return false; if (R.empty()) return false; @@ -372,8 +374,11 @@ bool Sema::DiagnoseUnknownTemplateName(const IdentifierInfo &II, return true; } -bool Sema::LookupTemplateName(LookupResult &Found, Scope *S, CXXScopeSpec &SS, - QualType ObjectType, bool EnteringContext, +bool Sema::LookupTemplateName(LookupResult &Found, + Scope *S, CXXScopeSpec &SS, + QualType ObjectType, + bool EnteringContext, + bool &MemberOfUnknownSpecialization, RequiredTemplateKind RequiredTemplate, AssumedTemplateKind *ATK, bool AllowTypoCorrection) { @@ -386,6 +391,7 @@ bool Sema::LookupTemplateName(LookupResult &Found, Scope *S, CXXScopeSpec &SS, Found.setTemplateNameLookup(true); // Determine where to perform name lookup + MemberOfUnknownSpecialization = false; DeclContext *LookupCtx = nullptr; bool IsDependent = false; if (!ObjectType.isNull()) { @@ -542,7 +548,7 @@ bool Sema::LookupTemplateName(LookupResult &Found, Scope *S, CXXScopeSpec &SS, FilterAcceptableTemplateNames(Found, AllowFunctionTemplatesInLookup); if (Found.empty()) { if (IsDependent) { - Found.setNotFoundInCurrentInstantiation(); + MemberOfUnknownSpecialization = true; return false; } @@ -5589,9 +5595,11 @@ 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, TemplateKWLoc)) + /*Entering*/false, MemberOfUnknownSpecialization, + TemplateKWLoc)) return ExprError(); if (R.isAmbiguous()) @@ -5712,13 +5720,14 @@ 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, RTK, - /*ATK=*/nullptr, /*AllowTypoCorrection=*/false) && + if (!LookupTemplateName(R, S, SS, ObjectType.get(), EnteringContext, MOUS, + RTK, nullptr, /*AllowTypoCorrection=*/false) && !R.isAmbiguous()) { if (LookupCtx) Diag(Name.getBeginLoc(), diag::err_no_member) @@ -5807,7 +5816,7 @@ bool Sema::CheckTemplateTypeArgument( if (auto *II = NameInfo.getName().getAsIdentifierInfo()) { LookupResult Result(*this, NameInfo, LookupOrdinaryName); - LookupParsedName(Result, CurScope, &SS, /*ObjectType=*/QualType()); + LookupParsedName(Result, CurScope, &SS); if (Result.getAsSingle<TypeDecl>() || Result.getResultKind() == @@ -11170,8 +11179,7 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, : TSK_ExplicitInstantiationDeclaration; LookupResult Previous(*this, NameInfo, LookupOrdinaryName); - LookupParsedName(Previous, S, &D.getCXXScopeSpec(), - /*ObjectType=*/QualType()); + LookupParsedName(Previous, S, &D.getCXXScopeSpec()); if (!R->isFunctionType()) { // C++ [temp.explicit]p1: diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 28d3d1b..f47bc21 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -13217,26 +13217,6 @@ 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; } |