tbaeder updated this revision to Diff 488883.
tbaeder added a comment.
Add more tests and fix decomposition decls of reference type.
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D138802/new/
https://reviews.llvm.org/D138802
Files:
clang/lib/AST/Interp/ByteCodeExprGen.cpp
clang/lib/AST/Interp/ByteCodeExprGen.h
clang/lib/AST/Interp/ByteCodeStmtGen.cpp
clang/lib/AST/Interp/Program.h
clang/test/AST/Interp/cxx17.cpp
Index: clang/test/AST/Interp/cxx17.cpp
===================================================================
--- /dev/null
+++ clang/test/AST/Interp/cxx17.cpp
@@ -0,0 +1,79 @@
+// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++17 -verify %s
+// RUN: %clang_cc1 -std=c++17 -verify=ref %s
+
+// ref-no-diagnostics
+
+struct F { int a; int b;};
+constexpr F getF() {
+ return {12, 3};
+}
+constexpr int f() {
+ auto [a1, b1] = getF();
+ auto [a2, b2] = getF();
+
+ return a1 + a2 + b1 + b2;
+}
+static_assert(f() == 30);
+
+
+constexpr int structRefs() {
+ const auto &[a, b] = getF();
+
+ return a + b;
+}
+// FIXME: This should work, but the MaterializeTemporaryExpr handling is not ready for it.
+static_assert(structRefs() == 15); // expected-error {{not an integral constant expression}}
+
+constexpr int structRefs2() {
+ F f = getF();
+ const auto &[a, b] = f;
+
+ return a + b;
+}
+static_assert(structRefs2() == 15);
+
+
+template<typename T>
+struct Tuple {
+ T first;
+ T second;
+ constexpr Tuple(T a, T b) : first(a), second(b) {}
+};
+template<typename T>
+constexpr T addTuple(const Tuple<T> &Tu) {
+ auto [a, b] = Tu;
+ return a + b;
+}
+
+constexpr Tuple<int> T1 = Tuple(1,2);
+static_assert(addTuple(T1) == 3);
+
+constexpr Tuple<short> T2 = Tuple<short>(11,2);
+static_assert(addTuple(T2) == 13);
+
+
+
+
+constexpr int a() {
+ int a[2] = {5, 3};
+ auto [x, y] = a;
+ return x + y;
+}
+static_assert(a() == 8);
+
+
+constexpr int b() {
+ int a[2] = {5, 3};
+ auto &[x, y] = a;
+ x += 1;
+ y += 2;
+ return a[0] + a[1];
+}
+static_assert(b() == 11);
+
+
+constexpr int vol() {
+ struct {
+ volatile int a
+ } F = {12};
+}
Index: clang/lib/AST/Interp/Program.h
===================================================================
--- clang/lib/AST/Interp/Program.h
+++ clang/lib/AST/Interp/Program.h
@@ -131,7 +131,9 @@
/// Context to manage declaration lifetimes.
class DeclScope {
public:
- DeclScope(Program &P, const VarDecl *VD) : P(P) { P.startDeclaration(VD); }
+ DeclScope(Program &P, const ValueDecl *VD) : P(P) {
+ P.startDeclaration(VD);
+ }
~DeclScope() { P.endDeclaration(); }
private:
@@ -222,7 +224,7 @@
unsigned CurrentDeclaration = NoDeclaration;
/// Starts evaluating a declaration.
- void startDeclaration(const VarDecl *Decl) {
+ void startDeclaration(const ValueDecl *Decl) {
LastDeclaration += 1;
CurrentDeclaration = LastDeclaration;
}
Index: clang/lib/AST/Interp/ByteCodeStmtGen.cpp
===================================================================
--- clang/lib/AST/Interp/ByteCodeStmtGen.cpp
+++ clang/lib/AST/Interp/ByteCodeStmtGen.cpp
@@ -211,17 +211,11 @@
template <class Emitter>
bool ByteCodeStmtGen<Emitter>::visitDeclStmt(const DeclStmt *DS) {
for (auto *D : DS->decls()) {
- // Variable declarator.
- if (auto *VD = dyn_cast<VarDecl>(D)) {
- if (!this->visitVarDecl(VD))
- return false;
- continue;
- }
-
- // Decomposition declarator.
- if (auto *DD = dyn_cast<DecompositionDecl>(D)) {
- return this->bail(DD);
- }
+ const auto *VD = dyn_cast<VarDecl>(D);
+ if (!VD)
+ return false;
+ if (!this->visitVarDecl(VD))
+ return false;
}
return true;
Index: clang/lib/AST/Interp/ByteCodeExprGen.h
===================================================================
--- clang/lib/AST/Interp/ByteCodeExprGen.h
+++ clang/lib/AST/Interp/ByteCodeExprGen.h
@@ -232,6 +232,7 @@
bool dereferenceVar(const Expr *LV, PrimType T, const VarDecl *PD,
DerefKind AK, llvm::function_ref<bool(PrimType)> Direct,
llvm::function_ref<bool(PrimType)> Indirect);
+ bool allocateVariable(const ValueDecl *VD, const Expr *Init);
/// Emits an APSInt constant.
bool emitConst(const APSInt &Value, const Expr *E);
@@ -258,9 +259,12 @@
}
/// Returns whether we should create a global variable for the
- /// given VarDecl.
- bool shouldBeGloballyIndexed(const VarDecl *VD) const {
- return VD->hasGlobalStorage() || VD->isConstexpr();
+ /// given ValueDecl.
+ bool shouldBeGloballyIndexed(const ValueDecl *VD) const {
+ if (const auto *V = dyn_cast<VarDecl>(VD))
+ return V->hasGlobalStorage() || V->isConstexpr();
+
+ return false;
}
llvm::RoundingMode getRoundingMode(const Expr *E) const {
Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp
===================================================================
--- clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -28,9 +28,11 @@
/// Scope used to handle temporaries in toplevel variable declarations.
template <class Emitter> class DeclScope final : public LocalScope<Emitter> {
public:
- DeclScope(ByteCodeExprGen<Emitter> *Ctx, const VarDecl *VD)
+ DeclScope(ByteCodeExprGen<Emitter> *Ctx, const ValueDecl *VD)
: LocalScope<Emitter>(Ctx), Scope(Ctx->P, VD) {}
+ virtual ~DeclScope() override { this->emitDestruction(); }
+
void addExtended(const Scope::Local &Local) override {
return this->addLocal(Local);
}
@@ -766,11 +768,11 @@
if (std::optional<PrimType> T = classify(LV->getType())) {
if (!LV->refersToBitField()) {
// Only primitive, non bit-field types can be dereferenced directly.
- if (auto *DE = dyn_cast<DeclRefExpr>(LV)) {
+ if (const auto *DE = dyn_cast<DeclRefExpr>(LV)) {
if (!DE->getDecl()->getType()->isReferenceType()) {
- if (auto *PD = dyn_cast<ParmVarDecl>(DE->getDecl()))
+ if (const auto *PD = dyn_cast<ParmVarDecl>(DE->getDecl()))
return dereferenceParam(LV, *T, PD, AK, Direct, Indirect);
- if (auto *VD = dyn_cast<VarDecl>(DE->getDecl()))
+ if (const auto *VD = dyn_cast<VarDecl>(DE->getDecl()))
return dereferenceVar(LV, *T, VD, AK, Direct, Indirect);
}
}
@@ -1340,8 +1342,8 @@
}
template <class Emitter>
-bool ByteCodeExprGen<Emitter>::visitVarDecl(const VarDecl *VD) {
- const Expr *Init = VD->getInit();
+bool ByteCodeExprGen<Emitter>::allocateVariable(const ValueDecl *VD,
+ const Expr *Init) {
std::optional<PrimType> VarT = classify(VD->getType());
if (shouldBeGloballyIndexed(VD)) {
@@ -1364,6 +1366,11 @@
} else {
DeclScope<Emitter> LocalScope(this, VD);
+ if (auto *BD = dyn_cast<BindingDecl>(VD);
+ BD && BD->getDecomposedDecl()->getType()->isReferenceType()) {
+ VarT = PT_Ptr;
+ }
+
if (VarT) {
unsigned Offset = this->allocateLocalPrimitive(
VD, *VarT, VD->getType().isConstQualified());
@@ -1373,6 +1380,14 @@
if (!this->visit(Init))
return false;
+ // Initializers are supposed to be rvalues. However, sometimes
+ // they aren't. This is the case for C++ decomposition decl
+ // bindings.
+ if (Init && Init->isLValue() && *VarT != PT_Ptr) {
+ if (!this->emitLoadPop(*VarT, VD))
+ return false;
+ }
+
return this->emitSetLocal(*VarT, Offset, VD);
}
} else {
@@ -1387,6 +1402,29 @@
return false;
}
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::visitVarDecl(const VarDecl *VD) {
+ // For decomposition decls, we just emit multiple variables.
+ if (const auto *DD = dyn_cast<DecompositionDecl>(VD)) {
+ // Expression to decompose.
+ const Expr *Init = DD->getInit();
+
+ if (!this->allocateVariable(DD, Init))
+ return false;
+
+ for (const auto *BD : DD->bindings()) {
+ assert(!BD->getHoldingVar()); // FIXME
+ if (!this->allocateVariable(BD, BD->getBinding()))
+ return false;
+ }
+
+ return true;
+ }
+
+ // Regular variables.
+ return this->allocateVariable(VD, VD->getInit());
+}
+
template <class Emitter>
bool ByteCodeExprGen<Emitter>::VisitBuiltinCallExpr(const CallExpr *E) {
const Function *Func = getFunction(E->getDirectCallee());
@@ -1634,7 +1672,14 @@
// pointing to a reference, we need to get its value directly (i.e. the
// pointer to the actual value) instead of a pointer to the pointer to the
// value.
- bool IsReference = Decl->getType()->isReferenceType();
+ bool IsReference;
+
+ // Special case DecomposeDecls here. We need to check the decomposed decl
+ // for reference-ness, not the declaration the DeclRefExpr referes to.
+ if (const auto *BD = dyn_cast<BindingDecl>(Decl))
+ IsReference = BD->getDecomposedDecl()->getType()->isReferenceType();
+ else
+ IsReference = Decl->getType()->isReferenceType();
if (auto It = Locals.find(Decl); It != Locals.end()) {
const unsigned Offset = It->second.Offset;
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits