Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Clang][Interp] Fix display of syntactically-invalid note for member function calls #102170

Merged
merged 2 commits into from
Aug 9, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 26 additions & 4 deletions clang/lib/AST/Interp/InterpFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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(),
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/Interp/Source.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
83 changes: 83 additions & 0 deletions clang/test/AST/Interp/constexpr-frame-describe.cpp
Original file line number Diff line number Diff line change
@@ -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)'}}
2 changes: 1 addition & 1 deletion clang/test/AST/Interp/constexpr-nqueens.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
2 changes: 1 addition & 1 deletion clang/test/AST/Interp/lambda.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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()()'}} \
yronglin marked this conversation as resolved.
Show resolved Hide resolved
// ref-note {{in call to 'f.operator()()'}}
}
static_assert(div(8, 2) == 4);
Expand Down
6 changes: 2 additions & 4 deletions clang/test/AST/Interp/records.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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}} \
Expand Down Expand Up @@ -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}} \
Expand Down
Loading