Skip to content

Commit badfb4b

Browse files
authored
[Clang][Interp] Fix display of syntactically-invalid note for member function calls (#102170)
This PR fix display of syntactically-invalid note for member function calls to follow the behavior of current interpreter. --------- Signed-off-by: yronglin <[email protected]>
1 parent 059e7be commit badfb4b

File tree

6 files changed

+114
-12
lines changed

6 files changed

+114
-12
lines changed

clang/lib/AST/Interp/InterpFrame.cpp

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "Program.h"
1919
#include "clang/AST/ASTContext.h"
2020
#include "clang/AST/DeclCXX.h"
21+
#include "clang/AST/ExprCXX.h"
2122

2223
using namespace clang;
2324
using namespace clang::interp;
@@ -169,11 +170,32 @@ void InterpFrame::describe(llvm::raw_ostream &OS) const {
169170
F && (F->isBuiltin() || F->isLambdaStaticInvoker()))
170171
return;
171172

173+
const Expr *CallExpr = Caller->getExpr(getRetPC());
172174
const FunctionDecl *F = getCallee();
173-
if (const auto *M = dyn_cast<CXXMethodDecl>(F);
174-
M && M->isInstance() && !isa<CXXConstructorDecl>(F)) {
175-
print(OS, This, S.getCtx(), S.getCtx().getRecordType(M->getParent()));
176-
OS << "->";
175+
bool IsMemberCall = isa<CXXMethodDecl>(F) && !isa<CXXConstructorDecl>(F) &&
176+
cast<CXXMethodDecl>(F)->isImplicitObjectMemberFunction();
177+
if (Func->hasThisPointer() && IsMemberCall) {
178+
if (const auto *MCE = dyn_cast_if_present<CXXMemberCallExpr>(CallExpr)) {
179+
const Expr *Object = MCE->getImplicitObjectArgument();
180+
Object->printPretty(OS, /*Helper=*/nullptr,
181+
S.getCtx().getPrintingPolicy(),
182+
/*Indentation=*/0);
183+
if (Object->getType()->isPointerType())
184+
OS << "->";
185+
else
186+
OS << ".";
187+
} else if (const auto *OCE =
188+
dyn_cast_if_present<CXXOperatorCallExpr>(CallExpr)) {
189+
OCE->getArg(0)->printPretty(OS, /*Helper=*/nullptr,
190+
S.getCtx().getPrintingPolicy(),
191+
/*Indentation=*/0);
192+
OS << ".";
193+
} else if (const auto *M = dyn_cast<CXXMethodDecl>(F)) {
194+
print(OS, This, S.getCtx(),
195+
S.getCtx().getLValueReferenceType(
196+
S.getCtx().getRecordType(M->getParent())));
197+
OS << ".";
198+
}
177199
}
178200

179201
F->getNameForDiagnostic(OS, S.getCtx().getPrintingPolicy(),

clang/lib/AST/Interp/Source.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ const Expr *SourceInfo::asExpr() const {
4141
const Expr *SourceMapper::getExpr(const Function *F, CodePtr PC) const {
4242
if (const Expr *E = getSource(F, PC).asExpr())
4343
return E;
44-
llvm::report_fatal_error("missing source expression");
44+
return nullptr;
4545
}
4646

4747
SourceLocation SourceMapper::getLocation(const Function *F, CodePtr PC) const {
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify=ref,both %s
2+
// RUN: %clang_cc1 -std=c++20 -fexperimental-new-constant-interpreter -fsyntax-only -verify=expected,both %s
3+
4+
5+
struct Foo {
6+
constexpr void zomg() const { (void)(1 / 0); } // both-error {{constant expression}} \
7+
both-warning {{division by zero}} \
8+
both-note 2{{division by zero}}
9+
};
10+
11+
struct S {
12+
constexpr S() {}
13+
constexpr bool operator==(const S&) const { // both-error {{never produces a constant expression}}
14+
return 1 / 0; // both-warning {{division by zero}} \
15+
both-note 3{{division by zero}}
16+
}
17+
18+
constexpr bool heh() const {
19+
auto F = new Foo();
20+
F->zomg(); // both-note {{in call to 'F->zomg()'}}
21+
delete F;
22+
return false;
23+
}
24+
};
25+
26+
constexpr S s;
27+
28+
static_assert(s.heh()); // both-error {{constant expression}} \
29+
both-note {{in call to 's.heh()'}}
30+
31+
constexpr S s2;
32+
constexpr const S *sptr = &s;
33+
constexpr const S *sptr2 = &s2;
34+
static_assert(s == s2); // both-error {{constant expression}} \
35+
both-note {{in call to 's.operator==(s2)'}}
36+
static_assert(*sptr == *sptr2); // both-error {{constant expression}} \
37+
both-note {{in call to '*sptr.operator==(s2)'}}
38+
39+
struct A {
40+
constexpr int foo() { (void)(1/0); return 1;} // both-error {{never produces a constant expression}} \
41+
both-warning {{division by zero}} \
42+
both-note 2{{division by zero}}
43+
};
44+
45+
struct B {
46+
A aa;
47+
A *a = &aa;
48+
};
49+
50+
struct C {
51+
B b;
52+
};
53+
54+
struct D {
55+
C cc;
56+
C *c = &cc;
57+
};
58+
59+
constexpr D d{};
60+
static_assert(d.c->b.a->foo() == 1); // both-error {{constant expression}} \
61+
both-note {{in call to 'd.c->b.a->foo()'}}
62+
63+
template <typename T>
64+
struct Bar {
65+
template <typename U>
66+
constexpr int fail1() const { return 1 / 0; } // both-warning {{division by zero}} \
67+
// both-note {{division by zero}}
68+
template <typename U, int num>
69+
constexpr int fail2() const { return 1 / 0; } // both-warning {{division by zero}} \
70+
// both-note {{division by zero}}
71+
template <typename ...Args>
72+
constexpr int fail3(Args... args) const { return 1 / 0; } // both-warning {{division by zero}} \
73+
// both-note {{division by zero}}
74+
};
75+
76+
constexpr Bar<int> bar;
77+
static_assert(bar.fail1<int>()); // both-error {{constant expression}} \
78+
// both-note {{in call to 'bar.fail1<int>()'}}
79+
static_assert(bar.fail2<int*, 42>()); // both-error {{constant expression}} \
80+
// both-note {{in call to 'bar.fail2<int *, 42>()'}}
81+
static_assert(bar.fail3(3, 4UL, bar, &bar)); // both-error {{constant expression}} \
82+
// expected-note {{in call to 'bar.fail3<int, unsigned long, Bar<int>, const Bar<int> *>(3, 4, &bar, &bar)'}} \
83+
// ref-note {{in call to 'bar.fail3<int, unsigned long, Bar<int>, const Bar<int> *>(3, 4, {}, &bar)'}}

clang/test/AST/Interp/constexpr-nqueens.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ constexpr Board buildBoardScan(int N, int Col, int Row, const Board &B) {
4949
return Row == N ? Board(0, true) :
5050
B.ok(Row, Col) ?
5151
tryBoard(buildBoardRecurse(N, Col + 1, B.addQueen(Row, Col)), // ref-note {{in call to 'B.addQueen(0, 0)}} \
52-
// expected-note {{in call to '&Board()->addQueen(0, 0)}}
52+
// expected-note {{in call to 'B.addQueen(0, 0)}}
5353
N, Col, Row+1, B) :
5454
buildBoardScan(N, Col, Row + 1, B);
5555
}

clang/test/AST/Interp/lambda.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,7 @@ constexpr int div(int a, int b) {
4646
return a / b; // both-note {{division by zero}}
4747
};
4848

49-
return f(); // expected-note {{in call to '&f->operator()()'}} \
50-
// ref-note {{in call to 'f.operator()()'}}
49+
return f(); // both-note {{in call to 'f.operator()()'}}
5150
}
5251
static_assert(div(8, 2) == 4);
5352
static_assert(div(8, 0) == 4); // both-error {{not an integral constant expression}} \

clang/test/AST/Interp/records.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -334,8 +334,7 @@ namespace InitializerTemporaries {
334334
};
335335

336336
constexpr int f() {
337-
S{}; // ref-note {{in call to 'S{}.~S()'}} \
338-
// expected-note {{in call to '&S{}->~S()'}}
337+
S{}; // both-note {{in call to 'S{}.~S()'}}
339338
return 12;
340339
}
341340
static_assert(f() == 12); // both-error {{not an integral constant expression}} \
@@ -598,8 +597,7 @@ namespace Destructors {
598597
}
599598
};
600599
constexpr int testS() {
601-
S{}; // ref-note {{in call to 'S{}.~S()'}} \
602-
// expected-note {{in call to '&S{}->~S()'}}
600+
S{}; // both-note {{in call to 'S{}.~S()'}}
603601
return 1;
604602
}
605603
static_assert(testS() == 1); // both-error {{not an integral constant expression}} \

0 commit comments

Comments
 (0)