https://github.com/zwuis created https://github.com/llvm/llvm-project/pull/220463
For `E1.E2()` and `E1->E2()`, 1. A `MemberExpr` is created to represent `E1.E2` and `E1->E2`. If overload resolution is performed, it is created using information from a `UnresolvedMemberExpr`. 2. If `E2` is an explicit object member function, a `DeclRefExpr` is created to represent `E2` using information from the `MemberExpr`. This PR adds missed information to the `DeclRefExpr`. Fixes 218829. >From 09fdee4bb5e89de3cf519510c8ca933baa204443 Mon Sep 17 00:00:00 2001 From: Yanzuo Liu <[email protected]> Date: Wed, 2 Sep 2026 10:50:29 +0800 Subject: [PATCH] Add missing information to AST for calling explicit object member functions --- clang/lib/Sema/SemaOverload.cpp | 64 ++++++++++++----- clang/test/AST/ast-print-deducing-this.cpp | 69 +++++++++++++++++++ .../ast-dump-sycl-kernel-call-stmt.cpp | 14 ++-- 3 files changed, 121 insertions(+), 26 deletions(-) create mode 100644 clang/test/AST/ast-print-deducing-this.cpp diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 106ddb90ed9dc..55c2bd04c2a0c 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -63,9 +63,12 @@ static bool functionHasPassObjectSizeParams(const FunctionDecl *FD) { /// A convenience routine for creating a decayed reference to a function. static ExprResult CreateFunctionRefExpr( - Sema &S, FunctionDecl *Fn, NamedDecl *FoundDecl, const Expr *Base, - bool HadMultipleCandidates, SourceLocation Loc = SourceLocation(), - const DeclarationNameLoc &LocInfo = DeclarationNameLoc()) { + Sema &S, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, + FunctionDecl *Fn, NamedDecl *FoundDecl, const Expr *Base, + bool HadMultipleCandidates, const DeclarationNameInfo &NameInfo, + const TemplateArgumentListInfo *TemplateArgs) { + SourceLocation Loc = NameInfo.getLoc(); + if (S.DiagnoseUseOfDecl(FoundDecl, Loc)) return ExprError(); // If FoundDecl is different from Fn (such as if one is a template @@ -76,8 +79,10 @@ static ExprResult CreateFunctionRefExpr( // being used. if (FoundDecl != Fn && S.DiagnoseUseOfDecl(Fn, Loc)) return ExprError(); - DeclRefExpr *DRE = new (S.Context) - DeclRefExpr(S.Context, Fn, false, Fn->getType(), VK_LValue, Loc, LocInfo); + auto *DRE = DeclRefExpr::Create(S.Context, QualifierLoc, TemplateKWLoc, Fn, + /*RefersToEnclosingVariableOrCapture=*/false, + NameInfo, Fn->getType(), VK_LValue, FoundDecl, + TemplateArgs); if (HadMultipleCandidates) DRE->setHadMultipleCandidates(true); @@ -92,6 +97,23 @@ static ExprResult CreateFunctionRefExpr( CK_FunctionToPointerDecay); } +static ExprResult CreateFunctionRefExpr(Sema &S, FunctionDecl *Fn, + NamedDecl *FoundDecl, const Expr *Base, + bool HadMultipleCandidates, + const DeclarationNameInfo &NameInfo) { + return CreateFunctionRefExpr(S, /*QualifierLoc=*/{}, /*TemplateKWLoc=*/{}, Fn, + FoundDecl, Base, HadMultipleCandidates, NameInfo, + /*TemplateArgs=*/nullptr); +} + +static ExprResult CreateFunctionRefExpr(Sema &S, FunctionDecl *Fn, + NamedDecl *FoundDecl, const Expr *Base, + bool HadMultipleCandidates, + SourceLocation Loc) { + return CreateFunctionRefExpr(S, Fn, FoundDecl, Base, HadMultipleCandidates, + DeclarationNameInfo(Fn->getDeclName(), Loc)); +} + static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType, bool InOverloadResolution, StandardConversionSequence &SCS, @@ -16225,9 +16247,9 @@ ExprResult Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, // Build the actual expression node. DeclarationNameInfo OpLocInfo(OpName, LLoc); OpLocInfo.setCXXOperatorNameRange(SourceRange(LLoc, RLoc)); - ExprResult FnExpr = CreateFunctionRefExpr( - *this, FnDecl, Best->FoundDecl, Base, HadMultipleCandidates, - OpLocInfo.getLoc(), OpLocInfo.getInfo()); + ExprResult FnExpr = + CreateFunctionRefExpr(*this, FnDecl, Best->FoundDecl, Base, + HadMultipleCandidates, OpLocInfo); if (FnExpr.isInvalid()) return ExprError(); @@ -16561,10 +16583,18 @@ ExprResult Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, NewArgs)) return ExprError(); + // FIXME: avoid copy. + TemplateArgumentListInfo TemplateArgsBuffer, *TemplateArgs = nullptr; + if (MemExpr->hasExplicitTemplateArgs()) { + MemExpr->copyTemplateArgumentsInto(TemplateArgsBuffer); + TemplateArgs = &TemplateArgsBuffer; + } + // Build the actual expression node. - ExprResult FnExpr = - CreateFunctionRefExpr(*this, Method, FoundDecl, MemExpr, - HadMultipleCandidates, MemExpr->getExprLoc()); + ExprResult FnExpr = CreateFunctionRefExpr( + *this, MemExpr->getQualifierLoc(), MemExpr->getTemplateKeywordLoc(), + Method, FoundDecl, MemExpr, HadMultipleCandidates, + MemExpr->getMemberNameInfo(), TemplateArgs); if (FnExpr.isInvalid()) return ExprError(); @@ -16853,10 +16883,8 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj, DeclarationNameInfo OpLocInfo( Context.DeclarationNames.getCXXOperatorName(OO_Call), LParenLoc); OpLocInfo.setCXXOperatorNameRange(SourceRange(LParenLoc, RParenLoc)); - ExprResult NewFn = CreateFunctionRefExpr(*this, Method, Best->FoundDecl, - Obj, HadMultipleCandidates, - OpLocInfo.getLoc(), - OpLocInfo.getInfo()); + ExprResult NewFn = CreateFunctionRefExpr(*this, Method, Best->FoundDecl, Obj, + HadMultipleCandidates, OpLocInfo); if (NewFn.isInvalid()) return true; @@ -17085,10 +17113,8 @@ ExprResult Sema::BuildLiteralOperatorCall(LookupResult &R, } FunctionDecl *FD = Best->Function; - ExprResult Fn = CreateFunctionRefExpr(*this, FD, Best->FoundDecl, - nullptr, HadMultipleCandidates, - SuffixInfo.getLoc(), - SuffixInfo.getInfo()); + ExprResult Fn = CreateFunctionRefExpr(*this, FD, Best->FoundDecl, nullptr, + HadMultipleCandidates, SuffixInfo); if (Fn.isInvalid()) return true; diff --git a/clang/test/AST/ast-print-deducing-this.cpp b/clang/test/AST/ast-print-deducing-this.cpp new file mode 100644 index 0000000000000..1fba787288cce --- /dev/null +++ b/clang/test/AST/ast-print-deducing-this.cpp @@ -0,0 +1,69 @@ +// RUN: %clang_cc1 -std=c++23 -ast-print %s | FileCheck %s --match-full-lines + +struct S { + void f(this const S &); + template <typename> void g(this const S &); +}; + +struct Ptr1 { + const S *operator->() const; +}; + +struct Ptr2 { + const S *operator->(this const Ptr2 &); +}; + +// FIXME: Should output the syntax of calling member functions. +void h(S s, S *ptr, Ptr1 ptr1, Ptr2 ptr2) { + s.f(); + // CHECK: f(s); + s.S::f(); + // CHECK: S::f(s); + s.g<S>(); + // CHECK: g<S>(s); + s.template g<S>(); + // CHECK: template g<S>(s); + s.S::g<S>(); + // CHECK: S::g<S>(s); + s.S::template g<S>(); + // CHECK: S::template g<S>(s); + + ptr->f(); + // CHECK: f(*ptr); + ptr->S::f(); + // CHECK: S::f(*ptr); + ptr->g<S>(); + // CHECK: g<S>(*ptr); + ptr->template g<S>(); + // CHECK: template g<S>(*ptr); + ptr->S::g<S>(); + // CHECK: S::g<S>(*ptr); + ptr->S::template g<S>(); + // CHECK: S::template g<S>(*ptr); + + ptr1->f(); + // CHECK: f(*ptr1); + ptr1->S::f(); + // CHECK: S::f(*ptr1); + ptr1->g<S>(); + // CHECK: g<S>(*ptr1); + ptr1->template g<S>(); + // CHECK: template g<S>(*ptr1); + ptr1->S::g<S>(); + // CHECK: S::g<S>(*ptr1); + ptr1->S::template g<S>(); + // CHECK: S::template g<S>(*ptr1); + + ptr2->f(); + // CHECK: f(*ptr2); + ptr2->S::f(); + // CHECK: S::f(*ptr2); + ptr2->g<S>(); + // CHECK: g<S>(*ptr2); + ptr2->template g<S>(); + // CHECK: template g<S>(*ptr2); + ptr2->S::g<S>(); + // CHECK: S::g<S>(*ptr2); + ptr2->S::template g<S>(); + // CHECK: S::template g<S>(*ptr2); +} diff --git a/clang/test/ASTSYCL/ast-dump-sycl-kernel-call-stmt.cpp b/clang/test/ASTSYCL/ast-dump-sycl-kernel-call-stmt.cpp index d66d4fdcc9483..fc66b78b85508 100644 --- a/clang/test/ASTSYCL/ast-dump-sycl-kernel-call-stmt.cpp +++ b/clang/test/ASTSYCL/ast-dump-sycl-kernel-call-stmt.cpp @@ -87,7 +87,7 @@ void skep2<KN<2>>(K<2>); // CHECK-NEXT: | | |-CompoundStmt {{.*}} // CHECK-NEXT: | | | `-CXXOperatorCallExpr {{.*}} 'void' '()' // CHECK-NEXT: | | | |-ImplicitCastExpr {{.*}} 'void (*)() const' <FunctionToPointerDecay> -// CHECK-NEXT: | | | | `-DeclRefExpr {{.*}} 'void () const' lvalue CXXMethod {{.*}} 'operator()' 'void () const' +// CHECK-NEXT: | | | | `-DeclRefExpr {{.*}} 'void () const' lvalue CXXMethod {{.*}} 'operator()' 'void () const' (FunctionTemplate {{.*}} 'operator()') // CHECK-NEXT: | | | `-ImplicitCastExpr {{.*}} 'const K<2>' lvalue <NoOp> // CHECK-NEXT: | | | `-DeclRefExpr {{.*}} 'K<2>' lvalue ParmVar {{.*}} 'k' 'K<2>' // CHECK-NEXT: | | |-CompoundStmt {{.*}} @@ -104,7 +104,7 @@ void skep2<KN<2>>(K<2>); // CHECK-NEXT: | | `-CompoundStmt {{.*}} // CHECK-NEXT: | | `-CXXOperatorCallExpr {{.*}} 'void' '()' // CHECK-NEXT: | | |-ImplicitCastExpr {{.*}} 'void (*)() const' <FunctionToPointerDecay> -// CHECK-NEXT: | | | `-DeclRefExpr {{.*}} 'void () const' lvalue CXXMethod {{.*}} 'operator()' 'void () const' +// CHECK-NEXT: | | | `-DeclRefExpr {{.*}} 'void () const' lvalue CXXMethod {{.*}} 'operator()' 'void () const' (FunctionTemplate {{.*}} 'operator()') // CHECK-NEXT: | | `-ImplicitCastExpr {{.*}} 'const K<2>' lvalue <NoOp> // CHECK-NEXT: | | `-DeclRefExpr {{.*}} 'K<2>' lvalue ImplicitParam {{.*}} 'k' 'K<2>' // CHECK-NEXT: | `-SYCLKernelEntryPointAttr {{.*}} KN<2> @@ -147,7 +147,7 @@ void skep3<KN<3>>(K<3> k) { // CHECK-NEXT: | | |-CompoundStmt {{.*}} // CHECK-NEXT: | | | `-CXXOperatorCallExpr {{.*}} 'void' '()' // CHECK-NEXT: | | | |-ImplicitCastExpr {{.*}} 'void (*)() const' <FunctionToPointerDecay> -// CHECK-NEXT: | | | | `-DeclRefExpr {{.*}} 'void () const' lvalue CXXMethod {{.*}} 'operator()' 'void () const' +// CHECK-NEXT: | | | | `-DeclRefExpr {{.*}} 'void () const' lvalue CXXMethod {{.*}} 'operator()' 'void () const' (FunctionTemplate {{.*}} 'operator()') // CHECK-NEXT: | | | `-ImplicitCastExpr {{.*}} 'const K<3>' lvalue <NoOp> // CHECK-NEXT: | | | `-DeclRefExpr {{.*}} 'K<3>' lvalue ParmVar {{.*}} 'k' 'K<3>' // CHECK-NEXT: | | |-CompoundStmt {{.*}} @@ -164,7 +164,7 @@ void skep3<KN<3>>(K<3> k) { // CHECK-NEXT: | | `-CompoundStmt {{.*}} // CHECK-NEXT: | | `-CXXOperatorCallExpr {{.*}} 'void' '()' // CHECK-NEXT: | | |-ImplicitCastExpr {{.*}} 'void (*)() const' <FunctionToPointerDecay> -// CHECK-NEXT: | | | `-DeclRefExpr {{.*}} 'void () const' lvalue CXXMethod {{.*}} 'operator()' 'void () const' +// CHECK-NEXT: | | | `-DeclRefExpr {{.*}} 'void () const' lvalue CXXMethod {{.*}} 'operator()' 'void () const' (FunctionTemplate {{.*}} 'operator()') // CHECK-NEXT: | | `-ImplicitCastExpr {{.*}} 'const K<3>' lvalue <NoOp> // CHECK-NEXT: | | `-DeclRefExpr {{.*}} 'K<3>' lvalue ImplicitParam {{.*}} 'k' 'K<3>' // CHECK-NEXT: | `-SYCLKernelEntryPointAttr {{.*}} KN<3> @@ -181,7 +181,7 @@ void skep4(K<4> k, int p1, int p2) { // CHECK-NEXT: | | |-CompoundStmt {{.*}} // CHECK-NEXT: | | | `-CXXOperatorCallExpr {{.*}} 'void' '()' // CHECK-NEXT: | | | |-ImplicitCastExpr {{.*}} 'void (*)(int, int) const' <FunctionToPointerDecay> -// CHECK-NEXT: | | | | `-DeclRefExpr {{.*}} 'void (int, int) const' lvalue CXXMethod {{.*}} 'operator()' 'void (int, int) const' +// CHECK-NEXT: | | | | `-DeclRefExpr {{.*}} 'void (int, int) const' lvalue CXXMethod {{.*}} 'operator()' 'void (int, int) const' (FunctionTemplate {{.*}} 'operator()') // CHECK-NEXT: | | | |-ImplicitCastExpr {{.*}} 'const K<4>' lvalue <NoOp> // CHECK-NEXT: | | | | `-DeclRefExpr {{.*}} 'K<4>' lvalue ParmVar {{.*}} 'k' 'K<4>' // CHECK-NEXT: | | | |-ImplicitCastExpr {{.*}} 'int' <LValueToRValue> @@ -210,7 +210,7 @@ void skep4(K<4> k, int p1, int p2) { // CHECK-NEXT: | | `-CompoundStmt {{.*}} // CHECK-NEXT: | | `-CXXOperatorCallExpr {{.*}} 'void' '()' // CHECK-NEXT: | | |-ImplicitCastExpr {{.*}} 'void (*)(int, int) const' <FunctionToPointerDecay> -// CHECK-NEXT: | | | `-DeclRefExpr {{.*}} 'void (int, int) const' lvalue CXXMethod {{.*}} 'operator()' 'void (int, int) const' +// CHECK-NEXT: | | | `-DeclRefExpr {{.*}} 'void (int, int) const' lvalue CXXMethod {{.*}} 'operator()' 'void (int, int) const' (FunctionTemplate {{.*}} 'operator()') // CHECK-NEXT: | | |-ImplicitCastExpr {{.*}} 'const K<4>' lvalue <NoOp> // CHECK-NEXT: | | | `-DeclRefExpr {{.*}} 'K<4>' lvalue ImplicitParam {{.*}} 'k' 'K<4>' // CHECK-NEXT: | | |-ImplicitCastExpr {{.*}} 'int' <LValueToRValue> @@ -269,7 +269,7 @@ void skep5(int unused1, K<5> k, int unused2, int p, int unused3) { // CHECK-NEXT: | | | `-IntegerLiteral {{.*}} 'int' 4 // CHECK-NEXT: | | `-CXXOperatorCallExpr {{.*}} 'void' '()' // CHECK-NEXT: | | |-ImplicitCastExpr {{.*}} 'void (*)(int, int, int, int, int, int, (lambda {{.*}}) const' <FunctionToPointerDecay> -// CHECK-NEXT: | | | `-DeclRefExpr {{.*}} 'void (int, int, int, int, int, int, (lambda {{.*}})) const' lvalue CXXMethod {{.*}} 'operator()' 'void (int, int, int, int, int, int, (lambda {{.*}})) const' +// CHECK-NEXT: | | | `-DeclRefExpr {{.*}} 'void (int, int, int, int, int, int, (lambda {{.*}})) const' lvalue CXXMethod {{.*}} 'operator()' 'void (int, int, int, int, int, int, (lambda {{.*}})) const' (FunctionTemplate {{.*}} 'operator()') // CHECK-NEXT: | | |-ImplicitCastExpr {{.*}} 'const K<5>' lvalue <NoOp> // CHECK-NEXT: | | | `-DeclRefExpr {{.*}} 'K<5>' lvalue ImplicitParam {{.*}} 'k' 'K<5>' // CHECK-NEXT: | | |-ImplicitCastExpr {{.*}} 'int' <LValueToRValue> _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
