diff options
author | Mikhail Goncharov <goncharov.mikhail@gmail.com> | 2024-04-15 08:41:32 +0200 |
---|---|---|
committer | Mikhail Goncharov <goncharov.mikhail@gmail.com> | 2024-04-15 08:41:32 +0200 |
commit | 46131aaf616c5cd97df0ec376a7e6ba475e1913c (patch) | |
tree | ea2585af24d4c3bc1ebf4d15d533472d85ce5e4a /clang/lib | |
parent | 2cc0c2104909558680409f8a8f39755936305e72 (diff) | |
download | llvm-46131aaf616c5cd97df0ec376a7e6ba475e1913c.zip llvm-46131aaf616c5cd97df0ec376a7e6ba475e1913c.tar.gz llvm-46131aaf616c5cd97df0ec376a7e6ba475e1913c.tar.bz2 |
Revert "Reapply "[Clang][Sema] Fix crash when 'this' is used in a dependent class scope function template specialization that instantiates to a static member function (#87541)" (#88311)"
This reverts commit aa80f3ec48419a73aafcc2ff947c6dd1e3734481.
See
https://github.com/llvm/llvm-project/pull/88311#issuecomment-2052291140.
There is a fix forward proposed but I am reverting this commit to fix
trunk.
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 28 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExprCXX.cpp | 61 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExprMember.cpp | 63 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 8 | ||||
-rw-r--r-- | clang/lib/Sema/TreeTransform.h | 65 |
5 files changed, 91 insertions, 134 deletions
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 505d068..c5395fb 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -2917,9 +2917,26 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS, // to get this right here so that we don't end up making a // spuriously dependent expression if we're inside a dependent // instance method. - if (isPotentialImplicitMemberAccess(SS, R, IsAddressOfOperand)) - return BuildPossibleImplicitMemberExpr(SS, TemplateKWLoc, R, TemplateArgs, - S); + if (getLangOpts().CPlusPlus && !R.empty() && + (*R.begin())->isCXXClassMember()) { + bool MightBeImplicitMember; + if (!IsAddressOfOperand) + MightBeImplicitMember = true; + else if (!SS.isEmpty()) + MightBeImplicitMember = false; + else if (R.isOverloadedResult()) + MightBeImplicitMember = false; + else if (R.isUnresolvableResult()) + MightBeImplicitMember = true; + else + MightBeImplicitMember = isa<FieldDecl>(R.getFoundDecl()) || + isa<IndirectFieldDecl>(R.getFoundDecl()) || + isa<MSPropertyDecl>(R.getFoundDecl()); + + if (MightBeImplicitMember) + return BuildPossibleImplicitMemberExpr(SS, TemplateKWLoc, + R, TemplateArgs, S); + } if (TemplateArgs || TemplateKWLoc.isValid()) { @@ -3430,11 +3447,10 @@ static bool ShouldLookupResultBeMultiVersionOverload(const LookupResult &R) { ExprResult Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, LookupResult &R, bool NeedsADL, - bool AcceptInvalidDecl, - bool NeedUnresolved) { + bool AcceptInvalidDecl) { // If this is a single, fully-resolved result and we don't need ADL, // just build an ordinary singleton decl ref. - if (!NeedUnresolved && !NeedsADL && R.isSingleResult() && + if (!NeedsADL && R.isSingleResult() && !R.getAsSingle<FunctionTemplateDecl>() && !ShouldLookupResultBeMultiVersionOverload(R)) return BuildDeclarationNameExpr(SS, R.getLookupNameInfo(), R.getFoundDecl(), diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 25f23a3..fa7b92a 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -1416,42 +1416,26 @@ bool Sema::CheckCXXThisCapture(SourceLocation Loc, const bool Explicit, } ExprResult Sema::ActOnCXXThis(SourceLocation Loc) { - // C++20 [expr.prim.this]p1: - // The keyword this names a pointer to the object for which an - // implicit object member function is invoked or a non-static - // data member's initializer is evaluated. + /// C++ 9.3.2: In the body of a non-static member function, the keyword this + /// is a non-lvalue expression whose value is the address of the object for + /// which the function is called. QualType ThisTy = getCurrentThisType(); - if (CheckCXXThisType(Loc, ThisTy)) - return ExprError(); + if (ThisTy.isNull()) { + DeclContext *DC = getFunctionLevelDeclContext(); - return BuildCXXThisExpr(Loc, ThisTy, /*IsImplicit=*/false); -} + if (const auto *Method = dyn_cast<CXXMethodDecl>(DC); + Method && Method->isExplicitObjectMemberFunction()) { + return Diag(Loc, diag::err_invalid_this_use) << 1; + } -bool Sema::CheckCXXThisType(SourceLocation Loc, QualType Type) { - if (!Type.isNull()) - return false; + if (isLambdaCallWithExplicitObjectParameter(CurContext)) + return Diag(Loc, diag::err_invalid_this_use) << 1; - // C++20 [expr.prim.this]p3: - // If a declaration declares a member function or member function template - // of a class X, the expression this is a prvalue of type - // "pointer to cv-qualifier-seq X" wherever X is the current class between - // the optional cv-qualifier-seq and the end of the function-definition, - // member-declarator, or declarator. It shall not appear within the - // declaration of either a static member function or an explicit object - // member function of the current class (although its type and value - // category are defined within such member functions as they are within - // an implicit object member function). - DeclContext *DC = getFunctionLevelDeclContext(); - if (const auto *Method = dyn_cast<CXXMethodDecl>(DC); - Method && Method->isExplicitObjectMemberFunction()) { - Diag(Loc, diag::err_invalid_this_use) << 1; - } else if (isLambdaCallWithExplicitObjectParameter(CurContext)) { - Diag(Loc, diag::err_invalid_this_use) << 1; - } else { - Diag(Loc, diag::err_invalid_this_use) << 0; + return Diag(Loc, diag::err_invalid_this_use) << 0; } - return true; + + return BuildCXXThisExpr(Loc, ThisTy, /*IsImplicit=*/false); } Expr *Sema::BuildCXXThisExpr(SourceLocation Loc, QualType Type, @@ -8658,8 +8642,21 @@ static ExprResult attemptRecovery(Sema &SemaRef, // Detect and handle the case where the decl might be an implicit // member. - if (SemaRef.isPotentialImplicitMemberAccess( - NewSS, R, Consumer.isAddressOfOperand())) + bool MightBeImplicitMember; + if (!Consumer.isAddressOfOperand()) + MightBeImplicitMember = true; + else if (!NewSS.isEmpty()) + MightBeImplicitMember = false; + else if (R.isOverloadedResult()) + MightBeImplicitMember = false; + else if (R.isUnresolvableResult()) + MightBeImplicitMember = true; + else + MightBeImplicitMember = isa<FieldDecl>(ND) || + isa<IndirectFieldDecl>(ND) || + isa<MSPropertyDecl>(ND); + + if (MightBeImplicitMember) return SemaRef.BuildPossibleImplicitMemberExpr( NewSS, /*TemplateKWLoc*/ SourceLocation(), R, /*TemplateArgs*/ nullptr, /*S*/ nullptr); diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp index eeac753..32998ae 100644 --- a/clang/lib/Sema/SemaExprMember.cpp +++ b/clang/lib/Sema/SemaExprMember.cpp @@ -61,10 +61,6 @@ enum IMAKind { /// The reference is a contextually-permitted abstract member reference. IMA_Abstract, - /// Whether the context is static is dependent on the enclosing template (i.e. - /// in a dependent class scope explicit specialization). - IMA_Dependent, - /// The reference may be to an unresolved using declaration and the /// context is not an instance method. IMA_Unresolved_StaticOrExplicitContext, @@ -95,18 +91,10 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef, DeclContext *DC = SemaRef.getFunctionLevelDeclContext(); - bool couldInstantiateToStatic = false; - bool isStaticOrExplicitContext = SemaRef.CXXThisTypeOverride.isNull(); - - if (auto *MD = dyn_cast<CXXMethodDecl>(DC)) { - if (MD->isImplicitObjectMemberFunction()) { - isStaticOrExplicitContext = false; - // A dependent class scope function template explicit specialization - // that is neither declared 'static' nor with an explicit object - // parameter could instantiate to a static or non-static member function. - couldInstantiateToStatic = MD->getDependentSpecializationInfo(); - } - } + bool isStaticOrExplicitContext = + SemaRef.CXXThisTypeOverride.isNull() && + (!isa<CXXMethodDecl>(DC) || cast<CXXMethodDecl>(DC)->isStatic() || + cast<CXXMethodDecl>(DC)->isExplicitObjectMemberFunction()); if (R.isUnresolvableResult()) return isStaticOrExplicitContext ? IMA_Unresolved_StaticOrExplicitContext @@ -135,9 +123,6 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef, if (Classes.empty()) return IMA_Static; - if (couldInstantiateToStatic) - return IMA_Dependent; - // C++11 [expr.prim.general]p12: // An id-expression that denotes a non-static data member or non-static // member function of a class can only be used: @@ -278,52 +263,32 @@ static void diagnoseInstanceReference(Sema &SemaRef, } } -bool Sema::isPotentialImplicitMemberAccess(const CXXScopeSpec &SS, - LookupResult &R, - bool IsAddressOfOperand) { - if (!getLangOpts().CPlusPlus) - return false; - else if (R.empty() || !R.begin()->isCXXClassMember()) - return false; - else if (!IsAddressOfOperand) - return true; - else if (!SS.isEmpty()) - return false; - else if (R.isOverloadedResult()) - return false; - else if (R.isUnresolvableResult()) - return true; - else - return isa<FieldDecl, IndirectFieldDecl, MSPropertyDecl>(R.getFoundDecl()); -} - /// Builds an expression which might be an implicit member expression. ExprResult Sema::BuildPossibleImplicitMemberExpr( const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, LookupResult &R, - const TemplateArgumentListInfo *TemplateArgs, const Scope *S) { - switch (IMAKind Classification = ClassifyImplicitMemberAccess(*this, R)) { + const TemplateArgumentListInfo *TemplateArgs, const Scope *S, + UnresolvedLookupExpr *AsULE) { + switch (ClassifyImplicitMemberAccess(*this, R)) { case IMA_Instance: + return BuildImplicitMemberExpr(SS, TemplateKWLoc, R, TemplateArgs, true, S); + case IMA_Mixed: case IMA_Mixed_Unrelated: case IMA_Unresolved: - return BuildImplicitMemberExpr( - SS, TemplateKWLoc, R, TemplateArgs, - /*IsKnownInstance=*/Classification == IMA_Instance, S); + return BuildImplicitMemberExpr(SS, TemplateKWLoc, R, TemplateArgs, false, + S); + case IMA_Field_Uneval_Context: Diag(R.getNameLoc(), diag::warn_cxx98_compat_non_static_member_use) << R.getLookupNameInfo().getName(); [[fallthrough]]; case IMA_Static: case IMA_Abstract: - case IMA_Dependent: case IMA_Mixed_StaticOrExplicitContext: case IMA_Unresolved_StaticOrExplicitContext: if (TemplateArgs || TemplateKWLoc.isValid()) - return BuildTemplateIdExpr(SS, TemplateKWLoc, R, /*RequiresADL=*/false, - TemplateArgs); - return BuildDeclarationNameExpr( - SS, R, /*NeedsADL=*/false, /*AcceptInvalidDecl=*/false, - /*NeedUnresolved=*/Classification == IMA_Dependent); + return BuildTemplateIdExpr(SS, TemplateKWLoc, R, false, TemplateArgs); + return AsULE ? AsULE : BuildDeclarationNameExpr(SS, R, false); case IMA_Error_StaticOrExplicitContext: case IMA_Error_Unrelated: diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 21a139e..02d0b35 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -5097,14 +5097,6 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, EnterExpressionEvaluationContext EvalContext( *this, Sema::ExpressionEvaluationContext::PotentiallyEvaluated); - Qualifiers ThisTypeQuals; - CXXRecordDecl *ThisContext = nullptr; - if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Function)) { - ThisContext = Method->getParent(); - ThisTypeQuals = Method->getMethodQualifiers(); - } - CXXThisScopeRAII ThisScope(*this, ThisContext, ThisTypeQuals); - // Introduce a new scope where local variable instantiations will be // recorded, unless we're actually a member function within a local // class, in which case we need to merge our results with the parent diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index ee6bd22..fdf84c5 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -795,9 +795,6 @@ public: ParenExpr *PE, DependentScopeDeclRefExpr *DRE, bool IsAddressOfOperand, TypeSourceInfo **RecoveryTSI); - ExprResult TransformUnresolvedLookupExpr(UnresolvedLookupExpr *E, - bool IsAddressOfOperand); - StmtResult TransformOMPExecutableDirective(OMPExecutableDirective *S); // FIXME: We use LLVM_ATTRIBUTE_NOINLINE because inlining causes a ridiculous @@ -3312,13 +3309,12 @@ public: /// Build a new C++ "this" expression. /// - /// By default, performs semantic analysis to build a new "this" expression. - /// Subclasses may override this routine to provide different behavior. + /// By default, builds a new "this" expression without performing any + /// semantic analysis. Subclasses may override this routine to provide + /// different behavior. ExprResult RebuildCXXThisExpr(SourceLocation ThisLoc, QualType ThisType, bool isImplicit) { - if (getSema().CheckCXXThisType(ThisLoc, ThisType)) - return ExprError(); return getSema().BuildCXXThisExpr(ThisLoc, ThisType, isImplicit); } @@ -11369,11 +11365,7 @@ template<typename Derived> ExprResult TreeTransform<Derived>::TransformAddressOfOperand(Expr *E) { if (DependentScopeDeclRefExpr *DRE = dyn_cast<DependentScopeDeclRefExpr>(E)) - return getDerived().TransformDependentScopeDeclRefExpr( - DRE, /*IsAddressOfOperand=*/true, nullptr); - else if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(E)) - return getDerived().TransformUnresolvedLookupExpr( - ULE, /*IsAddressOfOperand=*/true); + return getDerived().TransformDependentScopeDeclRefExpr(DRE, true, nullptr); else return getDerived().TransformExpr(E); } @@ -13079,16 +13071,10 @@ bool TreeTransform<Derived>::TransformOverloadExprDecls(OverloadExpr *Old, return false; } -template <typename Derived> -ExprResult TreeTransform<Derived>::TransformUnresolvedLookupExpr( - UnresolvedLookupExpr *Old) { - return TransformUnresolvedLookupExpr(Old, /*IsAddressOfOperand=*/false); -} - -template <typename Derived> +template<typename Derived> ExprResult -TreeTransform<Derived>::TransformUnresolvedLookupExpr(UnresolvedLookupExpr *Old, - bool IsAddressOfOperand) { +TreeTransform<Derived>::TransformUnresolvedLookupExpr( + UnresolvedLookupExpr *Old) { LookupResult R(SemaRef, Old->getName(), Old->getNameLoc(), Sema::LookupOrdinaryName); @@ -13120,8 +13106,26 @@ TreeTransform<Derived>::TransformUnresolvedLookupExpr(UnresolvedLookupExpr *Old, R.setNamingClass(NamingClass); } - // Rebuild the template arguments, if any. SourceLocation TemplateKWLoc = Old->getTemplateKeywordLoc(); + + // If we have neither explicit template arguments, nor the template keyword, + // it's a normal declaration name or member reference. + if (!Old->hasExplicitTemplateArgs() && !TemplateKWLoc.isValid()) { + NamedDecl *D = R.getAsSingle<NamedDecl>(); + // In a C++11 unevaluated context, an UnresolvedLookupExpr might refer to an + // instance member. In other contexts, BuildPossibleImplicitMemberExpr will + // give a good diagnostic. + if (D && D->isCXXInstanceMember()) { + return SemaRef.BuildPossibleImplicitMemberExpr(SS, TemplateKWLoc, R, + /*TemplateArgs=*/nullptr, + /*Scope=*/nullptr); + } + + return getDerived().RebuildDeclarationNameExpr(SS, R, Old->requiresADL()); + } + + // If we have template arguments, rebuild them, then rebuild the + // templateid expression. TemplateArgumentListInfo TransArgs(Old->getLAngleLoc(), Old->getRAngleLoc()); if (Old->hasExplicitTemplateArgs() && getDerived().TransformTemplateArguments(Old->getTemplateArgs(), @@ -13131,23 +13135,6 @@ TreeTransform<Derived>::TransformUnresolvedLookupExpr(UnresolvedLookupExpr *Old, return ExprError(); } - // An UnresolvedLookupExpr can refer to a class member. This occurs e.g. when - // a non-static data member is named in an unevaluated operand, or when - // a member is named in a dependent class scope function template explicit - // specialization that is neither declared static nor with an explicit object - // parameter. - if (SemaRef.isPotentialImplicitMemberAccess(SS, R, IsAddressOfOperand)) - return SemaRef.BuildPossibleImplicitMemberExpr( - SS, TemplateKWLoc, R, - Old->hasExplicitTemplateArgs() ? &TransArgs : nullptr, - /*S=*/nullptr); - - // If we have neither explicit template arguments, nor the template keyword, - // it's a normal declaration name or member reference. - if (!Old->hasExplicitTemplateArgs() && !TemplateKWLoc.isValid()) - return getDerived().RebuildDeclarationNameExpr(SS, R, Old->requiresADL()); - - // If we have template arguments, then rebuild the template-id expression. return getDerived().RebuildTemplateIdExpr(SS, TemplateKWLoc, R, Old->requiresADL(), &TransArgs); } |