[clang] b93d2d3 - [clang][Interp] Handle SourceLocExprs
Timm Bäder via cfe-commits
cfe-commits at lists.llvm.org
Wed Sep 6 05:46:22 PDT 2023
Author: Timm Bäder
Date: 2023-09-06T14:45:49+02:00
New Revision: b93d2d37e70942c951055019428708982b4e8d72
URL: https://github.com/llvm/llvm-project/commit/b93d2d37e70942c951055019428708982b4e8d72
DIFF: https://github.com/llvm/llvm-project/commit/b93d2d37e70942c951055019428708982b4e8d72.diff
LOG: [clang][Interp] Handle SourceLocExprs
Differential Revision: https://reviews.llvm.org/D155627
Added:
Modified:
clang/lib/AST/Interp/ByteCodeExprGen.cpp
clang/lib/AST/Interp/ByteCodeExprGen.h
clang/lib/AST/Interp/Program.cpp
clang/test/AST/Interp/builtin-functions.cpp
Removed:
################################################################################
diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
index 244290dc6393f45..043a3eb6346e025 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -1383,6 +1383,62 @@ bool ByteCodeExprGen<Emitter>::VisitCXXConstructExpr(
return false;
}
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitSourceLocExpr(const SourceLocExpr *E) {
+ if (DiscardResult)
+ return true;
+
+ const APValue Val =
+ E->EvaluateInContext(Ctx.getASTContext(), SourceLocDefaultExpr);
+
+ // Things like __builtin_LINE().
+ if (E->getType()->isIntegerType()) {
+ assert(Val.isInt());
+ const APSInt &I = Val.getInt();
+ return this->emitConst(I, E);
+ }
+ // Otherwise, the APValue is an LValue, with only one element.
+ // Theoretically, we don't need the APValue at all of course.
+ assert(E->getType()->isPointerType());
+ assert(Val.isLValue());
+ const APValue::LValueBase &Base = Val.getLValueBase();
+ if (const Expr *LValueExpr = Base.dyn_cast<const Expr *>())
+ return this->visit(LValueExpr);
+
+ // Otherwise, we have a decl (which is the case for
+ // __builtin_source_location).
+ assert(Base.is<const ValueDecl *>());
+ assert(Val.getLValuePath().size() == 0);
+ const auto *BaseDecl = Base.dyn_cast<const ValueDecl *>();
+ assert(BaseDecl);
+
+ auto *UGCD = cast<UnnamedGlobalConstantDecl>(BaseDecl);
+
+ std::optional<unsigned> GlobalIndex = P.getOrCreateGlobal(UGCD);
+ if (!GlobalIndex)
+ return false;
+
+ if (!this->emitGetPtrGlobal(*GlobalIndex, E))
+ return false;
+
+ const Record *R = getRecord(E->getType());
+ const APValue &V = UGCD->getValue();
+ for (unsigned I = 0, N = R->getNumFields(); I != N; ++I) {
+ const Record::Field *F = R->getField(I);
+ const APValue &FieldValue = V.getStructField(I);
+
+ PrimType FieldT = classifyPrim(F->Decl->getType());
+
+ if (!this->visitAPValue(FieldValue, FieldT, E))
+ return false;
+ if (!this->emitInitField(FieldT, F->Offset, E))
+ return false;
+ }
+
+ // Leave the pointer to the global on the stack.
+ return true;
+}
+
template <class Emitter> bool ByteCodeExprGen<Emitter>::discard(const Expr *E) {
if (E->containsErrors())
return false;
@@ -1694,8 +1750,8 @@ bool ByteCodeExprGen<Emitter>::dereferenceVar(
template <class Emitter>
template <typename T>
-bool ByteCodeExprGen<Emitter>::emitConst(T Value, const Expr *E) {
- switch (classifyPrim(E->getType())) {
+bool ByteCodeExprGen<Emitter>::emitConst(T Value, PrimType Ty, const Expr *E) {
+ switch (Ty) {
case PT_Sint8:
return this->emitConstSint8(Value, E);
case PT_Uint8:
@@ -1724,10 +1780,22 @@ bool ByteCodeExprGen<Emitter>::emitConst(T Value, const Expr *E) {
}
template <class Emitter>
-bool ByteCodeExprGen<Emitter>::emitConst(const APSInt &Value, const Expr *E) {
+template <typename T>
+bool ByteCodeExprGen<Emitter>::emitConst(T Value, const Expr *E) {
+ return this->emitConst(Value, classifyPrim(E->getType()), E);
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::emitConst(const APSInt &Value, PrimType Ty,
+ const Expr *E) {
if (Value.isSigned())
- return this->emitConst(Value.getSExtValue(), E);
- return this->emitConst(Value.getZExtValue(), E);
+ return this->emitConst(Value.getSExtValue(), Ty, E);
+ return this->emitConst(Value.getZExtValue(), Ty, E);
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::emitConst(const APSInt &Value, const Expr *E) {
+ return this->emitConst(Value, classifyPrim(E->getType()), E);
}
template <class Emitter>
@@ -1923,6 +1991,22 @@ bool ByteCodeExprGen<Emitter>::visitVarDecl(const VarDecl *VD) {
return false;
}
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::visitAPValue(const APValue &Val,
+ PrimType ValType, const Expr *E) {
+ assert(!DiscardResult);
+ if (Val.isInt())
+ return this->emitConst(Val.getInt(), ValType, E);
+
+ if (Val.isLValue()) {
+ APValue::LValueBase Base = Val.getLValueBase();
+ if (const Expr *BaseExpr = Base.dyn_cast<const Expr *>())
+ return this->visit(BaseExpr);
+ }
+
+ return false;
+}
+
template <class Emitter>
bool ByteCodeExprGen<Emitter>::VisitBuiltinCallExpr(const CallExpr *E) {
const Function *Func = getFunction(E->getDirectCallee());
@@ -2054,14 +2138,16 @@ bool ByteCodeExprGen<Emitter>::VisitCXXDefaultInitExpr(
return this->visitInitializer(E->getExpr());
assert(classify(E->getType()));
+ SourceLocScope<Emitter> SLS(this, E);
return this->visit(E->getExpr());
}
template <class Emitter>
bool ByteCodeExprGen<Emitter>::VisitCXXDefaultArgExpr(
const CXXDefaultArgExpr *E) {
- const Expr *SubExpr = E->getExpr();
+ SourceLocScope<Emitter> SLS(this, E);
+ const Expr *SubExpr = E->getExpr();
if (std::optional<PrimType> T = classify(E->getExpr()))
return this->visit(SubExpr);
diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.h b/clang/lib/AST/Interp/ByteCodeExprGen.h
index 9b7593ce54f9e8b..8ff8bc568b687bd 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.h
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.h
@@ -35,6 +35,7 @@ template <class Emitter> class VariableScope;
template <class Emitter> class DeclScope;
template <class Emitter> class OptionScope;
template <class Emitter> class ArrayIndexScope;
+template <class Emitter> class SourceLocScope;
/// Compilation context for expressions.
template <class Emitter>
@@ -102,6 +103,7 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
bool VisitCXXReinterpretCastExpr(const CXXReinterpretCastExpr *E);
bool VisitCXXNoexceptExpr(const CXXNoexceptExpr *E);
bool VisitCXXConstructExpr(const CXXConstructExpr *E);
+ bool VisitSourceLocExpr(const SourceLocExpr *E);
protected:
bool visitExpr(const Expr *E) override;
@@ -154,6 +156,8 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
/// Creates and initializes a variable from the given decl.
bool visitVarDecl(const VarDecl *VD);
+ /// Visit an APValue.
+ bool visitAPValue(const APValue &Val, PrimType ValType, const Expr *E);
/// Visits an expression and converts it to a boolean.
bool visitBool(const Expr *E);
@@ -210,6 +214,7 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
friend class DeclScope<Emitter>;
friend class OptionScope<Emitter>;
friend class ArrayIndexScope<Emitter>;
+ friend class SourceLocScope<Emitter>;
/// Emits a zero initializer.
bool visitZeroInitializer(QualType QT, const Expr *E);
@@ -239,12 +244,14 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
llvm::function_ref<bool(PrimType)> Indirect);
/// Emits an APSInt constant.
+ bool emitConst(const llvm::APSInt &Value, PrimType Ty, const Expr *E);
bool emitConst(const llvm::APSInt &Value, const Expr *E);
bool emitConst(const llvm::APInt &Value, const Expr *E) {
return emitConst(static_cast<llvm::APSInt>(Value), E);
}
/// Emits an integer constant.
+ template <typename T> bool emitConst(T Value, PrimType Ty, const Expr *E);
template <typename T> bool emitConst(T Value, const Expr *E);
/// Returns the CXXRecordDecl for the type of the given expression,
@@ -285,6 +292,9 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
/// Current argument index. Needed to emit ArrayInitIndexExpr.
std::optional<uint64_t> ArrayIndex;
+ /// DefaultInit- or DefaultArgExpr, needed for SourceLocExpr.
+ const Expr *SourceLocDefaultExpr = nullptr;
+
/// Flag indicating if return value is to be discarded.
bool DiscardResult = false;
@@ -444,6 +454,28 @@ template <class Emitter> class ArrayIndexScope final {
std::optional<uint64_t> OldArrayIndex;
};
+template <class Emitter> class SourceLocScope final {
+public:
+ SourceLocScope(ByteCodeExprGen<Emitter> *Ctx, const Expr *DefaultExpr)
+ : Ctx(Ctx) {
+ assert(DefaultExpr);
+ // We only switch if the current SourceLocDefaultExpr is null.
+ if (!Ctx->SourceLocDefaultExpr) {
+ Enabled = true;
+ Ctx->SourceLocDefaultExpr = DefaultExpr;
+ }
+ }
+
+ ~SourceLocScope() {
+ if (Enabled)
+ Ctx->SourceLocDefaultExpr = nullptr;
+ }
+
+private:
+ ByteCodeExprGen<Emitter> *Ctx;
+ bool Enabled = false;
+};
+
} // namespace interp
} // namespace clang
diff --git a/clang/lib/AST/Interp/Program.cpp b/clang/lib/AST/Interp/Program.cpp
index c1697bb7fa6d640..63901d90703dc46 100644
--- a/clang/lib/AST/Interp/Program.cpp
+++ b/clang/lib/AST/Interp/Program.cpp
@@ -161,9 +161,12 @@ std::optional<unsigned> Program::createGlobal(const ValueDecl *VD,
const Expr *Init) {
assert(!getGlobal(VD));
bool IsStatic, IsExtern;
- if (auto *Var = dyn_cast<VarDecl>(VD)) {
+ if (const auto *Var = dyn_cast<VarDecl>(VD)) {
IsStatic = Context::shouldBeGloballyIndexed(VD);
IsExtern = !Var->getAnyInitializer();
+ } else if (isa<UnnamedGlobalConstantDecl>(VD)) {
+ IsStatic = true;
+ IsExtern = false;
} else {
IsStatic = false;
IsExtern = true;
diff --git a/clang/test/AST/Interp/builtin-functions.cpp b/clang/test/AST/Interp/builtin-functions.cpp
index 55ebab1122d58e1..52ecee536938f3f 100644
--- a/clang/test/AST/Interp/builtin-functions.cpp
+++ b/clang/test/AST/Interp/builtin-functions.cpp
@@ -221,3 +221,31 @@ namespace fpclassify {
namespace fabs {
static_assert(__builtin_fabs(-14.0) == 14.0, "");
}
+
+namespace std {
+struct source_location {
+ struct __impl {
+ unsigned int _M_line;
+ const char *_M_file_name;
+ signed char _M_column;
+ const char *_M_function_name;
+ };
+ using BuiltinT = decltype(__builtin_source_location()); // OK.
+};
+}
+
+namespace SourceLocation {
+ constexpr auto A = __builtin_source_location();
+ static_assert(A->_M_line == __LINE__ -1, "");
+ static_assert(A->_M_column == 22, "");
+ static_assert(__builtin_strcmp(A->_M_function_name, "") == 0, "");
+ static_assert(__builtin_strcmp(A->_M_file_name, __FILE__) == 0, "");
+
+ static_assert(__builtin_LINE() == __LINE__, "");
+
+ struct Foo {
+ int a = __builtin_LINE();
+ };
+
+ static_assert(Foo{}.a == __LINE__, "");
+}
More information about the cfe-commits
mailing list