[clang] [Clang][Interp] Fix display of syntactically-invalid note for member function calls (PR #102170)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Aug 8 10:27:42 PDT 2024
https://github.com/yronglin updated https://github.com/llvm/llvm-project/pull/102170
>From f14464c0734776cd79a2fbd93cec94e815276009 Mon Sep 17 00:00:00 2001
From: yronglin <yronglin777 at gmail.com>
Date: Fri, 9 Aug 2024 01:22:29 +0800
Subject: [PATCH] [Clang][Interp] Fix display of syntactically-invalid note for
member function calls
Signed-off-by: yronglin <yronglin777 at gmail.com>
---
clang/lib/AST/Interp/InterpFrame.cpp | 30 ++++++-
clang/lib/AST/Interp/Source.cpp | 2 +-
.../AST/Interp/constexpr-frame-describe.cpp | 83 +++++++++++++++++++
clang/test/AST/Interp/constexpr-nqueens.cpp | 2 +-
clang/test/AST/Interp/lambda.cpp | 2 +-
clang/test/AST/Interp/records.cpp | 6 +-
6 files changed, 114 insertions(+), 11 deletions(-)
create mode 100644 clang/test/AST/Interp/constexpr-frame-describe.cpp
diff --git a/clang/lib/AST/Interp/InterpFrame.cpp b/clang/lib/AST/Interp/InterpFrame.cpp
index 83784db91f4f3e..27108f957305f3 100644
--- a/clang/lib/AST/Interp/InterpFrame.cpp
+++ b/clang/lib/AST/Interp/InterpFrame.cpp
@@ -18,6 +18,7 @@
#include "Program.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/ExprCXX.h"
using namespace clang;
using namespace clang::interp;
@@ -169,11 +170,32 @@ void InterpFrame::describe(llvm::raw_ostream &OS) const {
F && (F->isBuiltin() || F->isLambdaStaticInvoker()))
return;
+ const Expr *CallExpr = Caller->getExpr(getRetPC());
const FunctionDecl *F = getCallee();
- if (const auto *M = dyn_cast<CXXMethodDecl>(F);
- M && M->isInstance() && !isa<CXXConstructorDecl>(F)) {
- print(OS, This, S.getCtx(), S.getCtx().getRecordType(M->getParent()));
- OS << "->";
+ bool IsMemberCall = isa<CXXMethodDecl>(F) && !isa<CXXConstructorDecl>(F) &&
+ cast<CXXMethodDecl>(F)->isImplicitObjectMemberFunction();
+ if (Func->hasThisPointer() && IsMemberCall) {
+ if (const auto *MCE = dyn_cast_if_present<CXXMemberCallExpr>(CallExpr)) {
+ const Expr *Object = MCE->getImplicitObjectArgument();
+ Object->printPretty(OS, /*Helper=*/nullptr,
+ S.getCtx().getPrintingPolicy(),
+ /*Indentation=*/0);
+ if (Object->getType()->isPointerType())
+ OS << "->";
+ else
+ OS << ".";
+ } else if (const auto *OCE =
+ dyn_cast_if_present<CXXOperatorCallExpr>(CallExpr)) {
+ OCE->getArg(0)->printPretty(OS, /*Helper=*/nullptr,
+ S.getCtx().getPrintingPolicy(),
+ /*Indentation=*/0);
+ OS << ".";
+ } else if (const auto *M = dyn_cast<CXXMethodDecl>(F)) {
+ print(OS, This, S.getCtx(),
+ S.getCtx().getLValueReferenceType(
+ S.getCtx().getRecordType(M->getParent())));
+ OS << ".";
+ }
}
F->getNameForDiagnostic(OS, S.getCtx().getPrintingPolicy(),
diff --git a/clang/lib/AST/Interp/Source.cpp b/clang/lib/AST/Interp/Source.cpp
index 45cd0ad4fd4273..77796b00ca52cb 100644
--- a/clang/lib/AST/Interp/Source.cpp
+++ b/clang/lib/AST/Interp/Source.cpp
@@ -41,7 +41,7 @@ const Expr *SourceInfo::asExpr() const {
const Expr *SourceMapper::getExpr(const Function *F, CodePtr PC) const {
if (const Expr *E = getSource(F, PC).asExpr())
return E;
- llvm::report_fatal_error("missing source expression");
+ return nullptr;
}
SourceLocation SourceMapper::getLocation(const Function *F, CodePtr PC) const {
diff --git a/clang/test/AST/Interp/constexpr-frame-describe.cpp b/clang/test/AST/Interp/constexpr-frame-describe.cpp
new file mode 100644
index 00000000000000..fe698362e3d9b4
--- /dev/null
+++ b/clang/test/AST/Interp/constexpr-frame-describe.cpp
@@ -0,0 +1,83 @@
+// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify=expected,both %s
+// RUN: %clang_cc1 -std=c++20 -fexperimental-new-constant-interpreter -fsyntax-only -verify=ref,both %s
+
+
+struct Foo {
+ constexpr void zomg() const { (void)(1 / 0); } // both-error {{constant expression}} \
+ both-warning {{division by zero}} \
+ both-note 2{{division by zero}}
+};
+
+struct S {
+ constexpr S() {}
+ constexpr bool operator==(const S&) const { // both-error {{never produces a constant expression}}
+ return 1 / 0; // both-warning {{division by zero}} \
+ both-note 3{{division by zero}}
+ }
+
+ constexpr bool heh() const {
+ auto F = new Foo();
+ F->zomg(); // both-note {{in call to 'F->zomg()'}}
+ delete F;
+ return false;
+ }
+};
+
+constexpr S s;
+
+static_assert(s.heh()); // both-error {{constant expression}} \
+ both-note {{in call to 's.heh()'}}
+
+constexpr S s2;
+constexpr const S *sptr = &s;
+constexpr const S *sptr2 = &s2;
+static_assert(s == s2); // both-error {{constant expression}} \
+ both-note {{in call to 's.operator==(s2)'}}
+static_assert(*sptr == *sptr2); // both-error {{constant expression}} \
+ both-note {{in call to '*sptr.operator==(s2)'}}
+
+struct A {
+ constexpr int foo() { (void)(1/0); return 1;} // both-error {{never produces a constant expression}} \
+ both-warning {{division by zero}} \
+ both-note 2{{division by zero}}
+};
+
+struct B {
+ A aa;
+ A *a = &aa;
+};
+
+struct C {
+ B b;
+};
+
+struct D {
+ C cc;
+ C *c = &cc;
+};
+
+constexpr D d{};
+static_assert(d.c->b.a->foo() == 1); // both-error {{constant expression}} \
+ both-note {{in call to 'd.c->b.a->foo()'}}
+
+template <typename T>
+struct Bar {
+ template <typename U>
+ constexpr int fail1() const { return 1 / 0; } // both-warning {{division by zero}} \
+ // both-note {{division by zero}}
+ template <typename U, int num>
+ constexpr int fail2() const { return 1 / 0; } // both-warning {{division by zero}} \
+ // both-note {{division by zero}}
+ template <typename ...Args>
+ constexpr int fail3(Args... args) const { return 1 / 0; } // both-warning {{division by zero}} \
+ // both-note {{division by zero}}
+};
+
+constexpr Bar<int> bar;
+static_assert(bar.fail1<int>()); // both-error {{constant expression}} \
+ // both-note {{in call to 'bar.fail1<int>()'}}
+static_assert(bar.fail2<int*, 42>()); // both-error {{constant expression}} \
+ // both-note {{in call to 'bar.fail2<int *, 42>()'}}
+static_assert(bar.fail3(3, 4UL, bar, &bar)); // both-error {{constant expression}} \
+ // expected-note {{in call to 'bar.fail3<int, unsigned long, Bar<int>, const Bar<int> *>(3, 4, &bar, &bar)'}} \
+ // ref-note {{in call to 'bar.fail3<int, unsigned long, Bar<int>, const Bar<int> *>(3, 4, {}, &bar)'}}
diff --git a/clang/test/AST/Interp/constexpr-nqueens.cpp b/clang/test/AST/Interp/constexpr-nqueens.cpp
index 971f99a032b665..ed038dbc9b0779 100644
--- a/clang/test/AST/Interp/constexpr-nqueens.cpp
+++ b/clang/test/AST/Interp/constexpr-nqueens.cpp
@@ -49,7 +49,7 @@ constexpr Board buildBoardScan(int N, int Col, int Row, const Board &B) {
return Row == N ? Board(0, true) :
B.ok(Row, Col) ?
tryBoard(buildBoardRecurse(N, Col + 1, B.addQueen(Row, Col)), // ref-note {{in call to 'B.addQueen(0, 0)}} \
- // expected-note {{in call to '&Board()->addQueen(0, 0)}}
+ // expected-note {{in call to 'B.addQueen(0, 0)}}
N, Col, Row+1, B) :
buildBoardScan(N, Col, Row + 1, B);
}
diff --git a/clang/test/AST/Interp/lambda.cpp b/clang/test/AST/Interp/lambda.cpp
index d68fe995e8fa1c..27bbebddf44804 100644
--- a/clang/test/AST/Interp/lambda.cpp
+++ b/clang/test/AST/Interp/lambda.cpp
@@ -46,7 +46,7 @@ constexpr int div(int a, int b) {
return a / b; // both-note {{division by zero}}
};
- return f(); // expected-note {{in call to '&f->operator()()'}} \
+ return f(); // expected-note {{in call to 'f.operator()()'}} \
// ref-note {{in call to 'f.operator()()'}}
}
static_assert(div(8, 2) == 4);
diff --git a/clang/test/AST/Interp/records.cpp b/clang/test/AST/Interp/records.cpp
index 479c0487fecae0..9c8c1c344e1e8d 100644
--- a/clang/test/AST/Interp/records.cpp
+++ b/clang/test/AST/Interp/records.cpp
@@ -334,8 +334,7 @@ namespace InitializerTemporaries {
};
constexpr int f() {
- S{}; // ref-note {{in call to 'S{}.~S()'}} \
- // expected-note {{in call to '&S{}->~S()'}}
+ S{}; // both-note {{in call to 'S{}.~S()'}}
return 12;
}
static_assert(f() == 12); // both-error {{not an integral constant expression}} \
@@ -598,8 +597,7 @@ namespace Destructors {
}
};
constexpr int testS() {
- S{}; // ref-note {{in call to 'S{}.~S()'}} \
- // expected-note {{in call to '&S{}->~S()'}}
+ S{}; // both-note {{in call to 'S{}.~S()'}}
return 1;
}
static_assert(testS() == 1); // both-error {{not an integral constant expression}} \
More information about the cfe-commits
mailing list