[clang] f18b71d - [clang][Interp] Implement remaining MaterializeTemporaryExpr bits
Timm Bäder via cfe-commits
cfe-commits at lists.llvm.org
Wed Mar 1 22:53:16 PST 2023
Author: Timm Bäder
Date: 2023-03-02T07:51:54+01:00
New Revision: f18b71d14f7efdbc76aba888fdfe233bf0de7841
URL: https://github.com/llvm/llvm-project/commit/f18b71d14f7efdbc76aba888fdfe233bf0de7841
DIFF: https://github.com/llvm/llvm-project/commit/f18b71d14f7efdbc76aba888fdfe233bf0de7841.diff
LOG: [clang][Interp] Implement remaining MaterializeTemporaryExpr bits
As well as support for CompoundLiteralExprs.
Differential Revision: https://reviews.llvm.org/D140668
Added:
Modified:
clang/lib/AST/Interp/ByteCodeExprGen.cpp
clang/lib/AST/Interp/ByteCodeExprGen.h
clang/test/AST/Interp/cxx17.cpp
clang/test/AST/Interp/literals.cpp
clang/test/AST/Interp/records.cpp
Removed:
################################################################################
diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
index d4c9292739609..7b8253c6e193e 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -835,19 +835,10 @@ bool ByteCodeExprGen<Emitter>::VisitExprWithCleanups(
template <class Emitter>
bool ByteCodeExprGen<Emitter>::VisitMaterializeTemporaryExpr(
const MaterializeTemporaryExpr *E) {
- StorageDuration SD = E->getStorageDuration();
-
- // We conservatively only support these for now.
- if (SD != SD_Static && SD != SD_Automatic)
- return false;
-
const Expr *SubExpr = E->getSubExpr();
std::optional<PrimType> SubExprT = classify(SubExpr);
- // FIXME: Implement this for records and arrays as well.
- if (!SubExprT)
- return false;
- if (SD == SD_Static) {
+ if (E->getStorageDuration() == SD_Static) {
if (std::optional<unsigned> GlobalIndex = P.createGlobal(E)) {
const LifetimeExtendedTemporaryDecl *TempDecl =
E->getLifetimeExtendedTemporaryDecl();
@@ -859,15 +850,54 @@ bool ByteCodeExprGen<Emitter>::VisitMaterializeTemporaryExpr(
return false;
return this->emitGetPtrGlobal(*GlobalIndex, E);
}
- } else if (SD == SD_Automatic) {
- if (std::optional<unsigned> LocalIndex =
- allocateLocalPrimitive(SubExpr, *SubExprT, true, true)) {
+
+ return false;
+ }
+
+ // For everyhing else, use local variables.
+ if (SubExprT) {
+ if (std::optional<unsigned> LocalIndex = allocateLocalPrimitive(
+ SubExpr, *SubExprT, /*IsMutable=*/true, /*IsExtended=*/true)) {
if (!this->visitInitializer(SubExpr))
return false;
+ this->emitSetLocal(*SubExprT, *LocalIndex, E);
+ return this->emitGetPtrLocal(*LocalIndex, E);
+ }
+ } else {
+ if (std::optional<unsigned> LocalIndex =
+ allocateLocal(SubExpr, /*IsExtended=*/true)) {
+ if (!this->emitGetPtrLocal(*LocalIndex, E))
+ return false;
+ return this->visitInitializer(SubExpr);
+ }
+ }
+ return false;
+}
- if (!this->emitSetLocal(*SubExprT, *LocalIndex, E))
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitCompoundLiteralExpr(
+ const CompoundLiteralExpr *E) {
+ std::optional<PrimType> T = classify(E->getType());
+ const Expr *Init = E->getInitializer();
+ if (E->isFileScope()) {
+ if (std::optional<unsigned> GlobalIndex = P.createGlobal(E)) {
+ if (classify(E->getType()))
+ return this->visit(Init);
+ if (!this->emitGetPtrGlobal(*GlobalIndex, E))
return false;
- return this->emitGetPtrLocal(*LocalIndex, E);
+ return this->visitInitializer(Init);
+ }
+ }
+
+ // Otherwise, use a local variable.
+ if (T) {
+ // For primitive types, we just visit the initializer.
+ return this->visit(Init);
+ } else {
+ if (std::optional<unsigned> LocalIndex = allocateLocal(Init)) {
+ if (!this->emitGetPtrLocal(*LocalIndex, E))
+ return false;
+ return this->visitInitializer(Init);
}
}
@@ -1326,6 +1356,8 @@ bool ByteCodeExprGen<Emitter>::visitArrayInitializer(const Expr *Initializer) {
}
}
return true;
+ } else if (const auto *CLE = dyn_cast<CompoundLiteralExpr>(Initializer)) {
+ return visitInitializer(CLE->getInitializer());
}
assert(false && "Unknown expression for array initialization");
@@ -1511,6 +1543,10 @@ bool ByteCodeExprGen<Emitter>::visitDecl(const VarDecl *VD) {
template <class Emitter>
bool ByteCodeExprGen<Emitter>::visitVarDecl(const VarDecl *VD) {
+ // We don't know what to do with these, so just return false.
+ if (VD->getType().isNull())
+ return false;
+
const Expr *Init = VD->getInit();
std::optional<PrimType> VarT = classify(VD->getType());
diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.h b/clang/lib/AST/Interp/ByteCodeExprGen.h
index d6390116010b4..7b804b4cad3d6 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.h
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.h
@@ -90,6 +90,7 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
bool VisitPointerCompoundAssignOperator(const CompoundAssignOperator *E);
bool VisitExprWithCleanups(const ExprWithCleanups *E);
bool VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *E);
+ bool VisitCompoundLiteralExpr(const CompoundLiteralExpr *E);
protected:
bool visitExpr(const Expr *E) override;
@@ -346,7 +347,10 @@ template <class Emitter> class BlockScope final : public LocalScope<Emitter> {
BlockScope(ByteCodeExprGen<Emitter> *Ctx) : LocalScope<Emitter>(Ctx) {}
void addExtended(const Scope::Local &Local) override {
- llvm_unreachable("Cannot create temporaries in full scopes");
+ // If we to this point, just add the variable as a normal local
+ // variable. It will be destroyed at the end of the block just
+ // like all others.
+ this->addLocal(Local);
}
};
@@ -357,8 +361,8 @@ template <class Emitter> class ExprScope final : public LocalScope<Emitter> {
ExprScope(ByteCodeExprGen<Emitter> *Ctx) : LocalScope<Emitter>(Ctx) {}
void addExtended(const Scope::Local &Local) override {
- assert(this->Parent);
- this->Parent->addLocal(Local);
+ if (this->Parent)
+ this->Parent->addLocal(Local);
}
};
diff --git a/clang/test/AST/Interp/cxx17.cpp b/clang/test/AST/Interp/cxx17.cpp
index e72ff738ff630..e1f578a4418d9 100644
--- a/clang/test/AST/Interp/cxx17.cpp
+++ b/clang/test/AST/Interp/cxx17.cpp
@@ -2,6 +2,7 @@
// RUN: %clang_cc1 -std=c++17 -verify=ref %s
// ref-no-diagnostics
+// expected-no-diagnostics
struct F { int a; int b;};
constexpr F getF() {
@@ -21,8 +22,7 @@ constexpr int structRefs() {
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}}
+static_assert(structRefs() == 15);
constexpr int structRefs2() {
F f = getF();
diff --git a/clang/test/AST/Interp/literals.cpp b/clang/test/AST/Interp/literals.cpp
index 7121a24052f9a..fc36c13ed07b3 100644
--- a/clang/test/AST/Interp/literals.cpp
+++ b/clang/test/AST/Interp/literals.cpp
@@ -708,3 +708,38 @@ namespace IncDec {
}
};
#endif
+
+namespace CompoundLiterals {
+ constexpr int get5() {
+ return (int[]){1,2,3,4,5}[4];
+ }
+ static_assert(get5() == 5, "");
+
+ constexpr int get6(int f = (int[]){1,2,6}[2]) { // ref-note {{subexpression not valid in a constant expression}} \
+ // ref-note {{declared here}}
+ return f;
+ }
+ static_assert(get6(6) == 6, "");
+ // FIXME: Who's right here?
+ static_assert(get6() == 6, ""); // ref-error {{not an integral constant expression}}
+
+ constexpr int x = (int){3};
+ static_assert(x == 3, "");
+#if __cplusplus >= 201402L
+ constexpr int getX() {
+ int x = (int){3};
+ x = (int){5};
+ return x;
+ }
+ static_assert(getX() == 5, "");
+#endif
+
+#if __cplusplus >= 202002L
+ constexpr int get3() {
+ int m;
+ m = (int){3};
+ return m;
+ }
+ static_assert(get3() == 3, "");
+#endif
+};
diff --git a/clang/test/AST/Interp/records.cpp b/clang/test/AST/Interp/records.cpp
index b5bd04ff1228f..027f881f4d803 100644
--- a/clang/test/AST/Interp/records.cpp
+++ b/clang/test/AST/Interp/records.cpp
@@ -50,9 +50,6 @@ static_assert(ints2.a == -20, "");
static_assert(ints2.b == -30, "");
static_assert(!ints2.c, "");
-#if __cplusplus >= 201703L
-// FIXME: In c++14, this uses a MaterializeTemporaryExpr,
-// which the new interpreter doesn't support yet.
constexpr Ints getInts() {
return {64, 128, true};
}
@@ -60,7 +57,6 @@ constexpr Ints ints3 = getInts();
static_assert(ints3.a == 64, "");
static_assert(ints3.b == 128, "");
static_assert(ints3.c, "");
-#endif
constexpr Ints ints4 = {
.a = 40 * 50,
@@ -88,9 +84,9 @@ struct Ints2 {
int a = 10;
int b;
};
-// FIXME: Broken in the new constant interpreter.
-// Should be rejected, but without asan errors.
-//constexpr Ints2 ints2;
+constexpr Ints2 ints22; // expected-error {{without a user-provided default constructor}} \
+ // expected-error {{must be initialized by a constant expression}} \
+ // ref-error {{without a user-provided default constructor}}
class C {
public:
@@ -124,9 +120,6 @@ constexpr const C* getPointer() {
}
static_assert(getPointer()->a == 100, "");
-#if __cplusplus >= 201703L
-// FIXME: In c++14, this uses a MaterializeTemporaryExpr,
-// which the new interpreter doesn't support yet.
constexpr C RVOAndParams(const C *c) {
return C();
}
@@ -137,7 +130,6 @@ constexpr C RVOAndParams(int a) {
return C();
}
constexpr C RVOAndParamsResult2 = RVOAndParams(12);
-#endif
class Bar { // expected-note {{definition of 'Bar' is not complete}} \
// ref-note {{definition of 'Bar' is not complete}}
@@ -158,16 +150,16 @@ constexpr int locals() {
c.a = 10;
// Assignment, not an initializer.
- // c = C(); FIXME
+ c = C();
c.a = 10;
// Assignment, not an initializer.
- //c = RVOAndParams(&c); FIXME
+ c = RVOAndParams(&c);
return c.a;
}
-static_assert(locals() == 10, "");
+static_assert(locals() == 100, "");
namespace thisPointer {
struct S {
@@ -235,10 +227,7 @@ struct S {
this->a; // expected-warning {{expression result unused}} \
// ref-warning {{expression result unused}}
get5();
-#if __cplusplus >= 201703L
- // FIXME: Enable once we support MaterializeConstantExpr properly.
getInts();
-#endif
}
constexpr int m() const {
More information about the cfe-commits
mailing list