Skip to content

Commit

Permalink
[Clang][Interp] Fix display of syntactically-invalid note for member …
Browse files Browse the repository at this point in the history
…function calls (llvm#102170)

This PR fix display of syntactically-invalid note for member function
calls to follow the behavior of current interpreter.

---------

Signed-off-by: yronglin <yronglin777@gmail.com>
  • Loading branch information
yronglin authored Aug 9, 2024
1 parent 059e7be commit badfb4b
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 12 deletions.
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=ref,both %s
// RUN: %clang_cc1 -std=c++20 -fexperimental-new-constant-interpreter -fsyntax-only -verify=expected,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
3 changes: 1 addition & 2 deletions clang/test/AST/Interp/lambda.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +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()()'}} \
// ref-note {{in call to 'f.operator()()'}}
return f(); // both-note {{in call to 'f.operator()()'}}
}
static_assert(div(8, 2) == 4);
static_assert(div(8, 0) == 4); // both-error {{not an integral constant expression}} \
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

0 comments on commit badfb4b

Please sign in to comment.