[clang] 53e8790 - [clang][Interp][NFC] Remove double using namespace stmt
Author: Timm Bäder Date: 2024-08-03T05:45:00+02:00 New Revision: 53e87908c67f158bfe196a3c7cec690dc5eed1fc URL: https://github.com/llvm/llvm-project/commit/53e87908c67f158bfe196a3c7cec690dc5eed1fc DIFF: https://github.com/llvm/llvm-project/commit/53e87908c67f158bfe196a3c7cec690dc5eed1fc.diff LOG: [clang][Interp][NFC] Remove double using namespace stmt Added: Modified: clang/lib/AST/Interp/Interp.cpp Removed: diff --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp index 3694253ae9782..9009cf820244d 100644 --- a/clang/lib/AST/Interp/Interp.cpp +++ b/clang/lib/AST/Interp/Interp.cpp @@ -26,8 +26,6 @@ #include #include -using namespace clang; - using namespace clang; using namespace clang::interp; ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 4d2c9d8 - [clang][Interp][NFC] Add more assertions to add/removePointer
Author: Timm Bäder Date: 2024-08-03T05:44:59+02:00 New Revision: 4d2c9d8cd849e8097f41b3c3b52e4475188b5489 URL: https://github.com/llvm/llvm-project/commit/4d2c9d8cd849e8097f41b3c3b52e4475188b5489 DIFF: https://github.com/llvm/llvm-project/commit/4d2c9d8cd849e8097f41b3c3b52e4475188b5489.diff LOG: [clang][Interp][NFC] Add more assertions to add/removePointer Added: Modified: clang/lib/AST/Interp/InterpBlock.cpp clang/lib/AST/Interp/Pointer.cpp Removed: diff --git a/clang/lib/AST/Interp/InterpBlock.cpp b/clang/lib/AST/Interp/InterpBlock.cpp index 5ac778aeb6075..7a3962290edb4 100644 --- a/clang/lib/AST/Interp/InterpBlock.cpp +++ b/clang/lib/AST/Interp/InterpBlock.cpp @@ -31,9 +31,13 @@ void Block::addPointer(Pointer *P) { P->Next = Pointers; P->Prev = nullptr; Pointers = P; +#ifndef NDEBUG + assert(hasPointer(P)); +#endif } void Block::removePointer(Pointer *P) { + assert(P->isBlockPointer()); assert(P); if (IsStatic) { assert(!Pointers); @@ -51,6 +55,10 @@ void Block::removePointer(Pointer *P) { P->Prev->Next = P->Next; if (P->Next) P->Next->Prev = P->Prev; + P->PointeeStorage.BS.Pointee = nullptr; +#ifndef NDEBUG + assert(!hasPointer(P)); +#endif } void Block::cleanup() { diff --git a/clang/lib/AST/Interp/Pointer.cpp b/clang/lib/AST/Interp/Pointer.cpp index afa9d19d62823..79fe317a61dff 100644 --- a/clang/lib/AST/Interp/Pointer.cpp +++ b/clang/lib/AST/Interp/Pointer.cpp @@ -60,6 +60,7 @@ Pointer::~Pointer() { if (Block *Pointee = PointeeStorage.BS.Pointee) { Pointee->removePointer(this); +PointeeStorage.BS.Pointee = nullptr; Pointee->cleanup(); } } @@ -68,8 +69,15 @@ void Pointer::operator=(const Pointer ) { // If the current storage type is Block, we need to remove // this pointer from the block. if (isBlockPointer()) { +if (P.isBlockPointer() && this->block() == P.block()) { + Offset = P.Offset; + PointeeStorage.BS.Base = P.PointeeStorage.BS.Base; + return; +} + if (Block *Pointee = PointeeStorage.BS.Pointee) { Pointee->removePointer(this); + PointeeStorage.BS.Pointee = nullptr; Pointee->cleanup(); } } @@ -96,8 +104,16 @@ void Pointer::operator=(Pointer &) { // If the current storage type is Block, we need to remove // this pointer from the block. if (isBlockPointer()) { +if (P.isBlockPointer() && this->block() == P.block()) { + Offset = P.Offset; + PointeeStorage.BS.Base = P.PointeeStorage.BS.Base; + return; +} + if (Block *Pointee = PointeeStorage.BS.Pointee) { + assert(P.block() != this->block()); Pointee->removePointer(this); + PointeeStorage.BS.Pointee = nullptr; Pointee->cleanup(); } } ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 13faed8 - [clang][Interp][NFC] Use move ctor in moveArrayTy
Author: Timm Bäder Date: 2024-08-03T05:44:59+02:00 New Revision: 13faed8737b3021e59c3df6db3066876ce831dc9 URL: https://github.com/llvm/llvm-project/commit/13faed8737b3021e59c3df6db3066876ce831dc9 DIFF: https://github.com/llvm/llvm-project/commit/13faed8737b3021e59c3df6db3066876ce831dc9.diff LOG: [clang][Interp][NFC] Use move ctor in moveArrayTy Similar to what we did previously for primitive types, do it for primitive arrays as well. Added: Modified: clang/lib/AST/Interp/Descriptor.cpp Removed: diff --git a/clang/lib/AST/Interp/Descriptor.cpp b/clang/lib/AST/Interp/Descriptor.cpp index 671f2c03d7e5c..8becdca6f5c24 100644 --- a/clang/lib/AST/Interp/Descriptor.cpp +++ b/clang/lib/AST/Interp/Descriptor.cpp @@ -76,7 +76,7 @@ static void moveArrayTy(Block *, const std::byte *Src, std::byte *Dst, Src += sizeof(InitMapPtr); Dst += sizeof(InitMapPtr); for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) { -const auto *SrcPtr = _cast(Src)[I]; +auto *SrcPtr = _cast(const_cast(Src))[I]; auto *DstPtr = _cast(Dst)[I]; new (DstPtr) T(std::move(*SrcPtr)); } ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 400c7c7 - [clang][Interp][NFC] Simplify Pointer move/copy assignment op
Author: Timm Bäder Date: 2024-08-03T04:59:16+02:00 New Revision: 400c7c7cf2b15138aa674355983be74270de93bc URL: https://github.com/llvm/llvm-project/commit/400c7c7cf2b15138aa674355983be74270de93bc DIFF: https://github.com/llvm/llvm-project/commit/400c7c7cf2b15138aa674355983be74270de93bc.diff LOG: [clang][Interp][NFC] Simplify Pointer move/copy assignment op Added: Modified: clang/lib/AST/Interp/Pointer.cpp Removed: diff --git a/clang/lib/AST/Interp/Pointer.cpp b/clang/lib/AST/Interp/Pointer.cpp index 3ac8bc2b09709..afa9d19d62823 100644 --- a/clang/lib/AST/Interp/Pointer.cpp +++ b/clang/lib/AST/Interp/Pointer.cpp @@ -67,12 +67,10 @@ Pointer::~Pointer() { void Pointer::operator=(const Pointer ) { // If the current storage type is Block, we need to remove // this pointer from the block. - bool WasBlockPointer = isBlockPointer(); - if (StorageKind == Storage::Block) { -Block *Old = PointeeStorage.BS.Pointee; -if (WasBlockPointer && Old) { - PointeeStorage.BS.Pointee->removePointer(this); - Old->cleanup(); + if (isBlockPointer()) { +if (Block *Pointee = PointeeStorage.BS.Pointee) { + Pointee->removePointer(this); + Pointee->cleanup(); } } @@ -97,12 +95,10 @@ void Pointer::operator=(const Pointer ) { void Pointer::operator=(Pointer &) { // If the current storage type is Block, we need to remove // this pointer from the block. - bool WasBlockPointer = isBlockPointer(); - if (StorageKind == Storage::Block) { -Block *Old = PointeeStorage.BS.Pointee; -if (WasBlockPointer && Old) { - PointeeStorage.BS.Pointee->removePointer(this); - Old->cleanup(); + if (isBlockPointer()) { +if (Block *Pointee = PointeeStorage.BS.Pointee) { + Pointee->removePointer(this); + Pointee->cleanup(); } } ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 803db1f - [clang][Interp][NFC] Add missing fallthrough when parsing While loops
Author: Timm Bäder Date: 2024-07-30T12:42:04+02:00 New Revision: 803db1f5254047b08b6887c52009d4e72e67a673 URL: https://github.com/llvm/llvm-project/commit/803db1f5254047b08b6887c52009d4e72e67a673 DIFF: https://github.com/llvm/llvm-project/commit/803db1f5254047b08b6887c52009d4e72e67a673.diff LOG: [clang][Interp][NFC] Add missing fallthrough when parsing While loops Added: Modified: clang/lib/AST/Interp/Compiler.cpp Removed: diff --git a/clang/lib/AST/Interp/Compiler.cpp b/clang/lib/AST/Interp/Compiler.cpp index c07c1062f68a1..258e4ed645254 100644 --- a/clang/lib/AST/Interp/Compiler.cpp +++ b/clang/lib/AST/Interp/Compiler.cpp @@ -4373,6 +4373,7 @@ bool Compiler::visitWhileStmt(const WhileStmt *S) { if (!this->jump(CondLabel)) return false; + this->fallthrough(EndLabel); this->emitLabel(EndLabel); return true; ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 7e04937 - [clang][Interp][NFC] Improve InterpFrame::dump
Author: Timm Bäder Date: 2024-07-26T16:09:02+02:00 New Revision: 7e049373f4d26780f558f798b403a8477dd6af08 URL: https://github.com/llvm/llvm-project/commit/7e049373f4d26780f558f798b403a8477dd6af08 DIFF: https://github.com/llvm/llvm-project/commit/7e049373f4d26780f558f798b403a8477dd6af08.diff LOG: [clang][Interp][NFC] Improve InterpFrame::dump Added: Modified: clang/lib/AST/Interp/Disasm.cpp Removed: diff --git a/clang/lib/AST/Interp/Disasm.cpp b/clang/lib/AST/Interp/Disasm.cpp index 867284ecf7f4b..5e3a5b9515b52 100644 --- a/clang/lib/AST/Interp/Disasm.cpp +++ b/clang/lib/AST/Interp/Disasm.cpp @@ -278,10 +278,15 @@ LLVM_DUMP_METHOD void InterpFrame::dump(llvm::raw_ostream , OS << "\n"; OS.indent(Spaces) << "This: " << getThis() << "\n"; OS.indent(Spaces) << "RVO: " << getRVOPtr() << "\n"; - - while (const InterpFrame *F = this->Caller) { + OS.indent(Spaces) << "Depth: " << Depth << "\n"; + OS.indent(Spaces) << "ArgSize: " << ArgSize << "\n"; + OS.indent(Spaces) << "Args: " << (void *)Args << "\n"; + OS.indent(Spaces) << "FrameOffset: " << FrameOffset << "\n"; + OS.indent(Spaces) << "FrameSize: " << (Func ? Func->getFrameSize() : 0) +<< "\n"; + + for (const InterpFrame *F = this->Caller; F; F = F->Caller) { F->dump(OS, Indent + 1); -F = F->Caller; } } ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 7304936 - [clang][Interp] Add preliminary __builtin_constant_p implementation
Author: Timm Bäder Date: 2024-07-25T18:51:36+02:00 New Revision: 7304936479a7eb61adc9edcaf6ce56e4792590ad URL: https://github.com/llvm/llvm-project/commit/7304936479a7eb61adc9edcaf6ce56e4792590ad DIFF: https://github.com/llvm/llvm-project/commit/7304936479a7eb61adc9edcaf6ce56e4792590ad.diff LOG: [clang][Interp] Add preliminary __builtin_constant_p implementation This is not perfect or complete, but it helps us pass the simple tests and those tests where __builtin_constant_p is not the main subject of testing. Added: clang/test/AST/Interp/builtin-constant-p.cpp Modified: clang/lib/AST/Interp/ByteCodeEmitter.cpp clang/lib/AST/Interp/InterpBuiltin.cpp Removed: diff --git a/clang/lib/AST/Interp/ByteCodeEmitter.cpp b/clang/lib/AST/Interp/ByteCodeEmitter.cpp index fee4432a8f661..a01fa15dc0b7d 100644 --- a/clang/lib/AST/Interp/ByteCodeEmitter.cpp +++ b/clang/lib/AST/Interp/ByteCodeEmitter.cpp @@ -28,7 +28,8 @@ using namespace clang::interp; /// but that is not correct for our use cases. static bool isUnevaluatedBuiltin(unsigned BuiltinID) { return BuiltinID == Builtin::BI__builtin_classify_type || - BuiltinID == Builtin::BI__builtin_os_log_format_buffer_size; + BuiltinID == Builtin::BI__builtin_os_log_format_buffer_size || + BuiltinID == Builtin::BI__builtin_constant_p; } Function *ByteCodeEmitter::compileFunc(const FunctionDecl *FuncDecl) { diff --git a/clang/lib/AST/Interp/InterpBuiltin.cpp b/clang/lib/AST/Interp/InterpBuiltin.cpp index c170042144acc..c59bbc8313edc 100644 --- a/clang/lib/AST/Interp/InterpBuiltin.cpp +++ b/clang/lib/AST/Interp/InterpBuiltin.cpp @@ -7,6 +7,8 @@ //===--===// #include "../ExprConstShared.h" #include "Boolean.h" +#include "Compiler.h" +#include "EvalEmitter.h" #include "Interp.h" #include "PrimType.h" #include "clang/AST/OSLog.h" @@ -1127,6 +1129,73 @@ static bool interp__builtin_ptrauth_string_discriminator( return true; } +// FIXME: This implementation is not complete. +// The Compiler instance we create cannot access the current stack frame, local +// variables, function parameters, etc. We also need protection from +// side-effects, fatal errors, etc. +static bool interp__builtin_constant_p(InterpState , CodePtr OpPC, + const InterpFrame *Frame, + const Function *Func, + const CallExpr *Call) { + const Expr *Arg = Call->getArg(0); + QualType ArgType = Arg->getType(); + + auto returnInt = [, Call](bool Value) -> bool { +pushInteger(S, Value, Call->getType()); +return true; + }; + + // __builtin_constant_p always has one operand. The rules which gcc follows + // are not precisely documented, but are as follows: + // + // - If the operand is of integral, floating, complex or enumeration type, + //and can be folded to a known value of that type, it returns 1. + // - If the operand can be folded to a pointer to the first character + //of a string literal (or such a pointer cast to an integral type) + //or to a null pointer or an integer cast to a pointer, it returns 1. + // + // Otherwise, it returns 0. + // + // FIXME: GCC also intends to return 1 for literals of aggregate types, but + // its support for this did not work prior to GCC 9 and is not yet well + // understood. + if (ArgType->isIntegralOrEnumerationType() || ArgType->isFloatingType() || + ArgType->isAnyComplexType() || ArgType->isPointerType() || + ArgType->isNullPtrType()) { +InterpStack Stk; +Compiler C(S.Ctx, S.P, S, Stk); +auto Res = C.interpretExpr(Arg, /*ConvertResultToRValue=*/Arg->isGLValue()); +if (Res.isInvalid()) { + C.cleanup(); + Stk.clear(); +} + +const APValue = Res.toAPValue(); +if (!Res.isInvalid() && LV.isLValue()) { + APValue::LValueBase Base = LV.getLValueBase(); + if (Base.isNull()) { +// A null base is acceptable. +return returnInt(true); + } else if (const auto *E = Base.dyn_cast()) { +if (!isa(E)) + return returnInt(false); +return returnInt(LV.getLValueOffset().isZero()); + } else if (Base.is()) { +// Surprisingly, GCC considers __builtin_constant_p((int)) to +// evaluate to true. +return returnInt(true); + } else { +// Any other base is not constant enough for GCC. +return returnInt(false); + } +} + +return returnInt(!Res.isInvalid() && !Res.empty()); + } + + return returnInt(false); +} + bool InterpretBuiltin(InterpState , CodePtr OpPC, const Function *F, const CallExpr *Call) { const InterpFrame *Frame = S.Current; @@ -1456,6 +1525,11 @@ bool InterpretBuiltin(InterpState , CodePtr OpPC, const Function *F, return
[clang] 8608cc1 - [clang][Interp] Fix array element This chains
Author: Timm Bäder Date: 2024-07-25T06:45:48+02:00 New Revision: 8608cc1c89640bd3d8120f24c964af21310253b6 URL: https://github.com/llvm/llvm-project/commit/8608cc1c89640bd3d8120f24c964af21310253b6 DIFF: https://github.com/llvm/llvm-project/commit/8608cc1c89640bd3d8120f24c964af21310253b6.diff LOG: [clang][Interp] Fix array element This chains The previous test was too minimal. If we actually do something after initializing the nested array element, we end up causing a stack element type mismatch. Added: Modified: clang/lib/AST/Interp/Compiler.cpp clang/test/AST/Interp/records.cpp Removed: diff --git a/clang/lib/AST/Interp/Compiler.cpp b/clang/lib/AST/Interp/Compiler.cpp index 4d5d725d6964c..df55d01b8b9d6 100644 --- a/clang/lib/AST/Interp/Compiler.cpp +++ b/clang/lib/AST/Interp/Compiler.cpp @@ -92,7 +92,7 @@ bool InitLink::emit(Compiler *Ctx, const Expr *E) const { case K_Elem: if (!Ctx->emitConstUint32(Offset, E)) return false; -return Ctx->emitArrayElemPtrUint32(E); +return Ctx->emitArrayElemPtrPopUint32(E); default: llvm_unreachable("Unhandled InitLink kind"); } @@ -4156,7 +4156,8 @@ bool Compiler::VisitCXXThisExpr(const CXXThisExpr *E) { if (InitStackActive && !InitStack.empty()) { unsigned StartIndex = 0; for (StartIndex = InitStack.size() - 1; StartIndex > 0; --StartIndex) { - if (InitStack[StartIndex].Kind != InitLink::K_Field) + if (InitStack[StartIndex].Kind != InitLink::K_Field && + InitStack[StartIndex].Kind != InitLink::K_Elem) break; } diff --git a/clang/test/AST/Interp/records.cpp b/clang/test/AST/Interp/records.cpp index d77e5a5c782ce..9551630caf3d6 100644 --- a/clang/test/AST/Interp/records.cpp +++ b/clang/test/AST/Interp/records.cpp @@ -1551,8 +1551,12 @@ namespace ArrayInitChain { constexpr CustomOperandVal A[] = { {}, +{{"depctr_hold_cnt"}, 12, 13}, }; static_assert(A[0].Str.S == nullptr, ""); static_assert(A[0].Width == 0, ""); static_assert(A[0].Mask == 1, ""); + + static_assert(A[1].Width == 12, ""); + static_assert(A[1].Mask == 13, ""); } ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] bb0300c - [clang][Interp] Fix initializing array subobjects with This pointers
Author: Timm Bäder Date: 2024-07-24T19:15:10+02:00 New Revision: bb0300cf7ce54bfbb1607348c89cb0525e12076b URL: https://github.com/llvm/llvm-project/commit/bb0300cf7ce54bfbb1607348c89cb0525e12076b DIFF: https://github.com/llvm/llvm-project/commit/bb0300cf7ce54bfbb1607348c89cb0525e12076b.diff LOG: [clang][Interp] Fix initializing array subobjects with This pointers We need to select the right array element once we see the CXXThisExpr. Added: Modified: clang/lib/AST/Interp/Compiler.cpp clang/lib/AST/Interp/Compiler.h clang/test/AST/Interp/records.cpp Removed: diff --git a/clang/lib/AST/Interp/Compiler.cpp b/clang/lib/AST/Interp/Compiler.cpp index 58a0852aca755..4d5d725d6964c 100644 --- a/clang/lib/AST/Interp/Compiler.cpp +++ b/clang/lib/AST/Interp/Compiler.cpp @@ -89,6 +89,10 @@ bool InitLink::emit(Compiler *Ctx, const Expr *E) const { return Ctx->emitGetPtrLocal(Offset, E); case K_Decl: return Ctx->visitDeclRef(D, E); + case K_Elem: +if (!Ctx->emitConstUint32(Offset, E)) + return false; +return Ctx->emitArrayElemPtrUint32(E); default: llvm_unreachable("Unhandled InitLink kind"); } @@ -1556,6 +1560,7 @@ bool Compiler::visitArrayElemInit(unsigned ElemIndex, return this->emitInitElem(*T, ElemIndex, Init); } + InitLinkScope ILS(this, InitLink::Elem(ElemIndex)); // Advance the pointer currently on the stack to the given // dimension. if (!this->emitConstUint32(ElemIndex, Init)) diff --git a/clang/lib/AST/Interp/Compiler.h b/clang/lib/AST/Interp/Compiler.h index 084f5aef25f8e..d22b29d29a92d 100644 --- a/clang/lib/AST/Interp/Compiler.h +++ b/clang/lib/AST/Interp/Compiler.h @@ -50,6 +50,7 @@ struct InitLink { K_Field = 1, K_Temp = 2, K_Decl = 3, +K_Elem = 5, }; static InitLink This() { return InitLink{K_This}; } @@ -68,6 +69,11 @@ struct InitLink { IL.D = D; return IL; } + static InitLink Elem(unsigned Index) { +InitLink IL{K_Elem}; +IL.Offset = Index; +return IL; + } InitLink(uint8_t Kind) : Kind(Kind) {} template diff --git a/clang/test/AST/Interp/records.cpp b/clang/test/AST/Interp/records.cpp index 2fc88a0b1df6a..d77e5a5c782ce 100644 --- a/clang/test/AST/Interp/records.cpp +++ b/clang/test/AST/Interp/records.cpp @@ -1537,3 +1537,22 @@ namespace BitSet { Bitset() }; } + +namespace ArrayInitChain { + struct StringLiteral { +const char *S; + }; + + struct CustomOperandVal { +StringLiteral Str; +unsigned Width; +unsigned Mask = Width + 1; + }; + + constexpr CustomOperandVal A[] = { +{}, + }; + static_assert(A[0].Str.S == nullptr, ""); + static_assert(A[0].Width == 0, ""); + static_assert(A[0].Mask == 1, ""); +} ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 338c35a - [clang][Interp] Fix calling variadic call operators
Author: Timm Bäder Date: 2024-07-24T17:06:24+02:00 New Revision: 338c35aabfbede9ba10a4f48a13e63f37d6f8c7c URL: https://github.com/llvm/llvm-project/commit/338c35aabfbede9ba10a4f48a13e63f37d6f8c7c DIFF: https://github.com/llvm/llvm-project/commit/338c35aabfbede9ba10a4f48a13e63f37d6f8c7c.diff LOG: [clang][Interp] Fix calling variadic call operators Added: Modified: clang/lib/AST/Interp/Interp.cpp clang/test/AST/Interp/cxx20.cpp Removed: diff --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp index bf29b85041d82..3694253ae9782 100644 --- a/clang/lib/AST/Interp/Interp.cpp +++ b/clang/lib/AST/Interp/Interp.cpp @@ -233,7 +233,8 @@ void cleanupAfterFunctionCall(InterpState , CodePtr OpPC) { assert(false && "Can't get arguments from that expression type"); assert(NumArgs >= CurFunc->getNumWrittenParams()); -NumVarArgs = NumArgs - CurFunc->getNumWrittenParams(); +NumVarArgs = NumArgs - (CurFunc->getNumWrittenParams() + +isa(CallSite)); for (unsigned I = 0; I != NumVarArgs; ++I) { const Expr *A = Args[NumArgs - 1 - I]; popArg(S, A); diff --git a/clang/test/AST/Interp/cxx20.cpp b/clang/test/AST/Interp/cxx20.cpp index 2faacbbf70fd7..da80454b7a820 100644 --- a/clang/test/AST/Interp/cxx20.cpp +++ b/clang/test/AST/Interp/cxx20.cpp @@ -827,3 +827,17 @@ namespace CheckingNullPtrForInitialization { return x; } } + +namespace VariadicCallOperator { + class F { + public: +constexpr void operator()(int a, int b, ...) {} + }; + constexpr int foo() { +F f; + +f(1,2, 3); +return 1; + } + constexpr int A = foo(); +} ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 9f08ae8 - [clang][Interp][NFC] Fix getting the record decl from a pointer type
Author: Timm Bäder Date: 2024-07-24T16:54:38+02:00 New Revision: 9f08ae8d2dd1ff9ec3b033d099282dee05528413 URL: https://github.com/llvm/llvm-project/commit/9f08ae8d2dd1ff9ec3b033d099282dee05528413 DIFF: https://github.com/llvm/llvm-project/commit/9f08ae8d2dd1ff9ec3b033d099282dee05528413.diff LOG: [clang][Interp][NFC] Fix getting the record decl from a pointer type Added: Modified: clang/lib/AST/Interp/Compiler.cpp Removed: diff --git a/clang/lib/AST/Interp/Compiler.cpp b/clang/lib/AST/Interp/Compiler.cpp index 0455eec3f0145..58a0852aca755 100644 --- a/clang/lib/AST/Interp/Compiler.cpp +++ b/clang/lib/AST/Interp/Compiler.cpp @@ -5281,8 +5281,8 @@ template unsigned Compiler::collectBaseOffset(const QualType BaseType, const QualType DerivedType) { const auto extractRecordDecl = [](QualType Ty) -> const CXXRecordDecl * { -if (const auto *PT = dyn_cast(Ty)) - return PT->getPointeeType()->getAsCXXRecordDecl(); +if (const auto *R = Ty->getPointeeCXXRecordDecl()) + return R; return Ty->getAsCXXRecordDecl(); }; const CXXRecordDecl *BaseDecl = extractRecordDecl(BaseType); ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] d36edf8 - [clang][Interp] Bail out on value dependent variable initializers
Author: Timm Bäder Date: 2024-07-24T12:11:06+02:00 New Revision: d36edf8146cfea9f0407e2fb26283297eb6a6ac4 URL: https://github.com/llvm/llvm-project/commit/d36edf8146cfea9f0407e2fb26283297eb6a6ac4 DIFF: https://github.com/llvm/llvm-project/commit/d36edf8146cfea9f0407e2fb26283297eb6a6ac4.diff LOG: [clang][Interp] Bail out on value dependent variable initializers Added: Modified: clang/lib/AST/Interp/Compiler.cpp clang/test/AST/Interp/literals.cpp Removed: diff --git a/clang/lib/AST/Interp/Compiler.cpp b/clang/lib/AST/Interp/Compiler.cpp index dbd2686b17f09..0455eec3f0145 100644 --- a/clang/lib/AST/Interp/Compiler.cpp +++ b/clang/lib/AST/Interp/Compiler.cpp @@ -3683,6 +3683,9 @@ VarCreationState Compiler::visitVarDecl(const VarDecl *VD, bool Topleve const Expr *Init = VD->getInit(); std::optional VarT = classify(VD->getType()); + if (Init && Init->isValueDependent()) +return false; + if (Context::shouldBeGloballyIndexed(VD)) { auto checkDecl = [&]() -> bool { bool NeedsOp = !Toplevel && VD->isLocalVarDecl() && VD->isStaticLocal(); diff --git a/clang/test/AST/Interp/literals.cpp b/clang/test/AST/Interp/literals.cpp index 2b8abf665b20d..815fb67b9bbfc 100644 --- a/clang/test/AST/Interp/literals.cpp +++ b/clang/test/AST/Interp/literals.cpp @@ -1307,3 +1307,15 @@ namespace VolatileReads { static_assert(b, ""); // both-error {{not an integral constant expression}} \ // both-note {{read of volatile-qualified type 'const volatile int' is not allowed in a constant expression}} } +#if __cplusplus >= 201703L +namespace { + struct C { +int x; + }; + + template void f() { +const auto &[c] = *p; + // both-warning {{expression result unused}} + } +} +#endif ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 0b262bb - [clang][Interp] Properly reject StmtExprs with Stmt result
Author: Timm Bäder Date: 2024-07-23T19:46:15+02:00 New Revision: 0b262bbb5713ebfdf66f40021711307e9c8d4bf5 URL: https://github.com/llvm/llvm-project/commit/0b262bbb5713ebfdf66f40021711307e9c8d4bf5 DIFF: https://github.com/llvm/llvm-project/commit/0b262bbb5713ebfdf66f40021711307e9c8d4bf5.diff LOG: [clang][Interp] Properly reject StmtExprs with Stmt result Added: Modified: clang/lib/AST/Interp/Compiler.cpp clang/test/AST/Interp/literals.cpp Removed: diff --git a/clang/lib/AST/Interp/Compiler.cpp b/clang/lib/AST/Interp/Compiler.cpp index 0fc93c14131e6..dbd2686b17f09 100644 --- a/clang/lib/AST/Interp/Compiler.cpp +++ b/clang/lib/AST/Interp/Compiler.cpp @@ -3194,13 +3194,9 @@ bool Compiler::VisitStmtExpr(const StmtExpr *E) { } assert(S == Result); -if (const Expr *ResultExpr = dyn_cast(S)) { - if (DiscardResult) -return this->discard(ResultExpr); +if (const Expr *ResultExpr = dyn_cast(S)) return this->delegate(ResultExpr); -} - -return this->visitStmt(S); +return this->emitUnsupported(E); } return BS.destroyLocals(); diff --git a/clang/test/AST/Interp/literals.cpp b/clang/test/AST/Interp/literals.cpp index 9cd65462a0af3..9c828afdef18b 100644 --- a/clang/test/AST/Interp/literals.cpp +++ b/clang/test/AST/Interp/literals.cpp @@ -1214,6 +1214,10 @@ namespace StmtExprs { return 76; } static_assert(foo() == 76, ""); + + namespace CrossFuncLabelDiff { +constexpr long a(bool x) { return x ? 0 : (long)& + (0 && ({lbl: 0;})); } + } } #endif ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 5589f29 - [clang][Interp] Merge FunctionPointer into Pointer
Author: Timm Bäder Date: 2024-07-23T16:06:04+02:00 New Revision: 5589f2977117ec4685018472ca5f01355424bab9 URL: https://github.com/llvm/llvm-project/commit/5589f2977117ec4685018472ca5f01355424bab9 DIFF: https://github.com/llvm/llvm-project/commit/5589f2977117ec4685018472ca5f01355424bab9.diff LOG: [clang][Interp] Merge FunctionPointer into Pointer Back when I introduced the FunctionPointer class, I assumed that we can always know that a Pointer is not a FunctionPointer. With the DecayPtr op, that changed somewhat, but the information whether a Pointer was created through a FunctionPointer was lost. However, we need this information, especially when we're in the codegen stage. Added: Modified: clang/lib/AST/Interp/FunctionPointer.h clang/lib/AST/Interp/Interp.cpp clang/lib/AST/Interp/Interp.h clang/lib/AST/Interp/Pointer.cpp clang/lib/AST/Interp/Pointer.h Removed: diff --git a/clang/lib/AST/Interp/FunctionPointer.h b/clang/lib/AST/Interp/FunctionPointer.h index 0f2c6e571a1d8..d92cd32933fcd 100644 --- a/clang/lib/AST/Interp/FunctionPointer.h +++ b/clang/lib/AST/Interp/FunctionPointer.h @@ -23,11 +23,10 @@ class FunctionPointer final { bool Valid; public: - FunctionPointer(const Function *Func) : Func(Func), Valid(true) { -assert(Func); - } + FunctionPointer() = default; + FunctionPointer(const Function *Func) : Func(Func), Valid(true) {} - FunctionPointer(uintptr_t IntVal = 0, const Descriptor *Desc = nullptr) + FunctionPointer(uintptr_t IntVal, const Descriptor *Desc = nullptr) : Func(reinterpret_cast(IntVal)), Valid(false) {} const Function *getFunction() const { return Func; } diff --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp index 6fcd90e5f5849..bf29b85041d82 100644 --- a/clang/lib/AST/Interp/Interp.cpp +++ b/clang/lib/AST/Interp/Interp.cpp @@ -333,7 +333,7 @@ bool CheckConstant(InterpState , CodePtr OpPC, const Descriptor *Desc) { } static bool CheckConstant(InterpState , CodePtr OpPC, const Pointer ) { - if (Ptr.isIntegralPointer()) + if (!Ptr.isBlockPointer()) return true; return CheckConstant(S, OpPC, Ptr.getDeclDesc()); } diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h index 8e96f78d90568..492802897f013 100644 --- a/clang/lib/AST/Interp/Interp.h +++ b/clang/lib/AST/Interp/Interp.h @@ -2811,6 +2811,13 @@ inline bool DecayPtr(InterpState , CodePtr OpPC) { using ToT = typename PrimConv::T; const FromT = S.Stk.pop(); + + if constexpr (std::is_same_v && +std::is_same_v) { +S.Stk.push(OldPtr.getFunction()); +return true; + } + S.Stk.push(ToT(OldPtr.getIntegerRepresentation(), nullptr)); return true; } diff --git a/clang/lib/AST/Interp/Pointer.cpp b/clang/lib/AST/Interp/Pointer.cpp index 29579f5db40b6..3ac8bc2b09709 100644 --- a/clang/lib/AST/Interp/Pointer.cpp +++ b/clang/lib/AST/Interp/Pointer.cpp @@ -55,7 +55,7 @@ Pointer::Pointer(Pointer &) } Pointer::~Pointer() { - if (isIntegralPointer()) + if (!isBlockPointer()) return; if (Block *Pointee = PointeeStorage.BS.Pointee) { @@ -87,6 +87,8 @@ void Pointer::operator=(const Pointer ) { PointeeStorage.BS.Pointee->addPointer(this); } else if (P.isIntegralPointer()) { PointeeStorage.Int = P.PointeeStorage.Int; + } else if (P.isFunctionPointer()) { +PointeeStorage.Fn = P.PointeeStorage.Fn; } else { assert(false && "Unhandled storage kind"); } @@ -115,6 +117,8 @@ void Pointer::operator=(Pointer &) { PointeeStorage.BS.Pointee->addPointer(this); } else if (P.isIntegralPointer()) { PointeeStorage.Int = P.PointeeStorage.Int; + } else if (P.isFunctionPointer()) { +PointeeStorage.Fn = P.PointeeStorage.Fn; } else { assert(false && "Unhandled storage kind"); } @@ -131,6 +135,8 @@ APValue Pointer::toAPValue(const ASTContext ) const { CharUnits::fromQuantity(asIntPointer().Value + this->Offset), Path, /*IsOnePastEnd=*/false, /*IsNullPtr=*/false); + if (isFunctionPointer()) +return asFunctionPointer().toAPValue(ASTCtx); // Build the lvalue base from the block. const Descriptor *Desc = getDeclDesc(); @@ -263,7 +269,7 @@ std::string Pointer::toDiagnosticString(const ASTContext ) const { } bool Pointer::isInitialized() const { - if (isIntegralPointer()) + if (!isBlockPointer()) return true; if (isRoot() && PointeeStorage.BS.Base == sizeof(GlobalInlineDescriptor)) { @@ -299,7 +305,7 @@ bool Pointer::isInitialized() const { } void Pointer::initialize() const { - if (isIntegralPointer()) + if (!isBlockPointer()) return; assert(PointeeStorage.BS.Pointee && "Cannot initialize null pointer"); @@ -368,10 +374,15 @@ bool Pointer::hasSameBase(const Pointer , const Pointer ) { if (A.isIntegralPointer() &&
[clang] 20d7fff - [clang][Interp] Fix atomic builtins with integral pointers
Author: Timm Bäder Date: 2024-07-23T13:15:32+02:00 New Revision: 20d7fff5eaaa9d78807035d63e5c503bfc1b497e URL: https://github.com/llvm/llvm-project/commit/20d7fff5eaaa9d78807035d63e5c503bfc1b497e DIFF: https://github.com/llvm/llvm-project/commit/20d7fff5eaaa9d78807035d63e5c503bfc1b497e.diff LOG: [clang][Interp] Fix atomic builtins with integral pointers Check the integral pointer value. Added: Modified: clang/lib/AST/Interp/InterpBuiltin.cpp clang/test/AST/Interp/atomic.c Removed: diff --git a/clang/lib/AST/Interp/InterpBuiltin.cpp b/clang/lib/AST/Interp/InterpBuiltin.cpp index 98928b3c22d7c..c170042144acc 100644 --- a/clang/lib/AST/Interp/InterpBuiltin.cpp +++ b/clang/lib/AST/Interp/InterpBuiltin.cpp @@ -942,15 +942,29 @@ static bool interp__builtin_atomic_lock_free(InterpState , CodePtr OpPC, if (Ptr.isZero()) return returnBool(true); - QualType PointeeType = Call->getArg(1) - ->IgnoreImpCasts() - ->getType() - ->castAs() - ->getPointeeType(); - // OK, we will inline operations on this object. - if (!PointeeType->isIncompleteType() && - S.getCtx().getTypeAlignInChars(PointeeType) >= Size) -return returnBool(true); + if (Ptr.isIntegralPointer()) { +uint64_t IntVal = Ptr.getIntegerRepresentation(); +if (APSInt(APInt(64, IntVal, false), true).isAligned(Size.getAsAlign())) + return returnBool(true); + } + + const Expr *PtrArg = Call->getArg(1); + // Otherwise, check if the type's alignment against Size. + if (const auto *ICE = dyn_cast(PtrArg)) { +// Drop the potential implicit-cast to 'const volatile void*', getting +// the underlying type. +if (ICE->getCastKind() == CK_BitCast) + PtrArg = ICE->getSubExpr(); + } + + if (auto PtrTy = PtrArg->getType()->getAs()) { +QualType PointeeType = PtrTy->getPointeeType(); +if (!PointeeType->isIncompleteType() && +S.getCtx().getTypeAlignInChars(PointeeType) >= Size) { + // OK, we will inline operations on this object. + return returnBool(true); +} + } } } diff --git a/clang/test/AST/Interp/atomic.c b/clang/test/AST/Interp/atomic.c index c5fd9ab222934..c8469d4a938b8 100644 --- a/clang/test/AST/Interp/atomic.c +++ b/clang/test/AST/Interp/atomic.c @@ -58,3 +58,16 @@ _Static_assert(atomic_is_lock_free((atomic_short*)0), ""); _Static_assert(atomic_is_lock_free((atomic_int*)0), ""); _Static_assert(atomic_is_lock_free((atomic_long*)0), ""); _Static_assert(atomic_is_lock_free(0 + (atomic_char*)0), ""); + +_Static_assert(__atomic_always_lock_free(1, (void*)1), ""); +_Static_assert(__atomic_always_lock_free(1, (void*)-1), ""); +_Static_assert(!__atomic_always_lock_free(4, (void*)2), ""); +_Static_assert(!__atomic_always_lock_free(4, (void*)-2), ""); +_Static_assert(__atomic_always_lock_free(4, (void*)4), ""); +_Static_assert(__atomic_always_lock_free(4, (void*)-4), ""); + +_Static_assert(__atomic_always_lock_free(1, "string"), ""); +_Static_assert(!__atomic_always_lock_free(2, "string"), ""); +_Static_assert(__atomic_always_lock_free(2, (int[2]){}), ""); +void dummyfn(); +_Static_assert(__atomic_always_lock_free(2, dummyfn) || 1, ""); ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] f18dd9e - Reapply "[Clang][Interp] `__builtin_os_log_format_buffer_size` should be an unevaluated builtin (#99895)"
Author: Timm Bäder Date: 2024-07-23T11:57:40+02:00 New Revision: f18dd9edec9c2135a8906d795258a8c5a24f74f3 URL: https://github.com/llvm/llvm-project/commit/f18dd9edec9c2135a8906d795258a8c5a24f74f3 DIFF: https://github.com/llvm/llvm-project/commit/f18dd9edec9c2135a8906d795258a8c5a24f74f3.diff LOG: Reapply "[Clang][Interp] `__builtin_os_log_format_buffer_size` should be an unevaluated builtin (#99895)" This reverts commit 5f05d5ec8f9bb15c0ac29fce843a2c73165ac414. Reapply the original commit without the test. The memory leak is caused by a well known problem in the new constant interpreter. Added: Modified: clang/lib/AST/Interp/ByteCodeEmitter.cpp Removed: diff --git a/clang/lib/AST/Interp/ByteCodeEmitter.cpp b/clang/lib/AST/Interp/ByteCodeEmitter.cpp index a3d4c7d7392da..fee4432a8f661 100644 --- a/clang/lib/AST/Interp/ByteCodeEmitter.cpp +++ b/clang/lib/AST/Interp/ByteCodeEmitter.cpp @@ -27,7 +27,8 @@ using namespace clang::interp; /// Similar information is available via ASTContext::BuiltinInfo, /// but that is not correct for our use cases. static bool isUnevaluatedBuiltin(unsigned BuiltinID) { - return BuiltinID == Builtin::BI__builtin_classify_type; + return BuiltinID == Builtin::BI__builtin_classify_type || + BuiltinID == Builtin::BI__builtin_os_log_format_buffer_size; } Function *ByteCodeEmitter::compileFunc(const FunctionDecl *FuncDecl) { ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 613d2c3 - [clang][Interp][NFC] Avoid hitting an assertion in invalid code
Author: Timm Bäder Date: 2024-07-22T16:59:31+02:00 New Revision: 613d2c393992eee470405f1859aaf5fd1837e36c URL: https://github.com/llvm/llvm-project/commit/613d2c393992eee470405f1859aaf5fd1837e36c DIFF: https://github.com/llvm/llvm-project/commit/613d2c393992eee470405f1859aaf5fd1837e36c.diff LOG: [clang][Interp][NFC] Avoid hitting an assertion in invalid code Added: Modified: clang/lib/AST/Interp/Pointer.cpp Removed: diff --git a/clang/lib/AST/Interp/Pointer.cpp b/clang/lib/AST/Interp/Pointer.cpp index 229007c6d720a..3324691cdb7b7 100644 --- a/clang/lib/AST/Interp/Pointer.cpp +++ b/clang/lib/AST/Interp/Pointer.cpp @@ -149,6 +149,10 @@ APValue Pointer::toAPValue(const ASTContext ) const { CharUnits Offset = CharUnits::Zero(); auto getFieldOffset = [&](const FieldDecl *FD) -> CharUnits { +// This shouldn't happen, but if it does, don't crash inside +// getASTRecordLayout. +if (FD->getParent()->isInvalidDecl()) + return CharUnits::Zero(); const ASTRecordLayout = ASTCtx.getASTRecordLayout(FD->getParent()); unsigned FieldIndex = FD->getFieldIndex(); return ASTCtx.toCharUnitsFromBits(Layout.getFieldOffset(FieldIndex)); ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 5303ca1 - [clang][Interp] Start computing APValue offsets
Author: Timm Bäder Date: 2024-07-20T17:29:31+02:00 New Revision: 5303ca1496fc5f604f37c071d37821597788e83e URL: https://github.com/llvm/llvm-project/commit/5303ca1496fc5f604f37c071d37821597788e83e DIFF: https://github.com/llvm/llvm-project/commit/5303ca1496fc5f604f37c071d37821597788e83e.diff LOG: [clang][Interp] Start computing APValue offsets For array elements, arrays roots and fields. Added: clang/test/AST/Interp/codegen.cpp Modified: clang/lib/AST/Interp/Pointer.cpp Removed: diff --git a/clang/lib/AST/Interp/Pointer.cpp b/clang/lib/AST/Interp/Pointer.cpp index f7bd76b260584..229007c6d720a 100644 --- a/clang/lib/AST/Interp/Pointer.cpp +++ b/clang/lib/AST/Interp/Pointer.cpp @@ -16,6 +16,7 @@ #include "MemberPointer.h" #include "PrimType.h" #include "Record.h" +#include "clang/AST/RecordLayout.h" using namespace clang; using namespace clang::interp; @@ -141,25 +142,38 @@ APValue Pointer::toAPValue(const ASTContext ) const { else llvm_unreachable("Invalid allocation type"); - if (isDummy() || isUnknownSizeArray() || Desc->asExpr()) + if (isUnknownSizeArray() || Desc->asExpr()) return APValue(Base, CharUnits::Zero(), Path, /*IsOnePastEnd=*/isOnePastEnd(), /*IsNullPtr=*/false); - // TODO: compute the offset into the object. CharUnits Offset = CharUnits::Zero(); + auto getFieldOffset = [&](const FieldDecl *FD) -> CharUnits { +const ASTRecordLayout = ASTCtx.getASTRecordLayout(FD->getParent()); +unsigned FieldIndex = FD->getFieldIndex(); +return ASTCtx.toCharUnitsFromBits(Layout.getFieldOffset(FieldIndex)); + }; + // Build the path into the object. Pointer Ptr = *this; while (Ptr.isField() || Ptr.isArrayElement()) { if (Ptr.isArrayRoot()) { Path.push_back(APValue::LValuePathEntry( {Ptr.getFieldDesc()->asDecl(), /*IsVirtual=*/false})); + + if (const auto *FD = dyn_cast(Ptr.getFieldDesc()->asDecl())) +Offset += getFieldOffset(FD); + Ptr = Ptr.getBase(); } else if (Ptr.isArrayElement()) { + unsigned Index; if (Ptr.isOnePastEnd()) - Path.push_back(APValue::LValuePathEntry::ArrayIndex(Ptr.getArray().getNumElems())); +Index = Ptr.getArray().getNumElems(); else -Path.push_back(APValue::LValuePathEntry::ArrayIndex(Ptr.getIndex())); +Index = Ptr.getIndex(); + + Offset += (Index * ASTCtx.getTypeSizeInChars(Ptr.getType())); + Path.push_back(APValue::LValuePathEntry::ArrayIndex(Index)); Ptr = Ptr.getArray(); } else { // TODO: figure out if base is virtual @@ -170,12 +184,21 @@ APValue Pointer::toAPValue(const ASTContext ) const { if (const auto *BaseOrMember = Desc->asDecl()) { Path.push_back(APValue::LValuePathEntry({BaseOrMember, IsVirtual})); Ptr = Ptr.getBase(); + +if (const auto *FD = dyn_cast(BaseOrMember)) + Offset += getFieldOffset(FD); + continue; } llvm_unreachable("Invalid field type"); } } + // FIXME(perf): We compute the lvalue path above, but we can't supply it + // for dummy pointers (that causes crashes later in CheckConstantExpression). + if (isDummy()) +Path.clear(); + // We assemble the LValuePath starting from the innermost pointer to the // outermost one. SO in a.b.c, the first element in Path will refer to // the field 'c', while later code expects it to refer to 'a'. diff --git a/clang/test/AST/Interp/codegen.cpp b/clang/test/AST/Interp/codegen.cpp new file mode 100644 index 0..8a0d070d19da3 --- /dev/null +++ b/clang/test/AST/Interp/codegen.cpp @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -triple x86_64-linux -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-linux -emit-llvm -o - %s -fexperimental-new-constant-interpreter | FileCheck %s + + +int arr[2]; +// CHECK: @pastEnd = constant ptr getelementptr (i8, ptr @arr, i64 8) +int = arr[2]; + +// CHECK: @F = constant ptr @arr, align 8 +int = arr[0]; + +struct S { + int a; + float c[3]; +}; + +// CHECK: @s = global %struct.S zeroinitializer, align 4 +S s; +// CHECK: @sp = constant ptr getelementptr (i8, ptr @s, i64 16), align 8 +float = s.c[3]; ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 56a9f7c - [clang][Interp] Pass ASTContext to toAPValue()
Author: Timm Bäder Date: 2024-07-20T15:29:32+02:00 New Revision: 56a9f7ce611ba21f51043d91c965b59e116013f2 URL: https://github.com/llvm/llvm-project/commit/56a9f7ce611ba21f51043d91c965b59e116013f2 DIFF: https://github.com/llvm/llvm-project/commit/56a9f7ce611ba21f51043d91c965b59e116013f2.diff LOG: [clang][Interp] Pass ASTContext to toAPValue() Not yet needed, but we need to ASTContext in a later patch when we start computing proper values for the APValue offset. Added: Modified: clang/lib/AST/Interp/Boolean.h clang/lib/AST/Interp/Disasm.cpp clang/lib/AST/Interp/EvalEmitter.cpp clang/lib/AST/Interp/EvaluationResult.cpp clang/lib/AST/Interp/Floating.h clang/lib/AST/Interp/FunctionPointer.h clang/lib/AST/Interp/Integral.h clang/lib/AST/Interp/IntegralAP.h clang/lib/AST/Interp/Interp.h clang/lib/AST/Interp/MemberPointer.cpp clang/lib/AST/Interp/MemberPointer.h clang/lib/AST/Interp/Pointer.cpp clang/lib/AST/Interp/Pointer.h clang/unittests/AST/Interp/toAPValue.cpp Removed: diff --git a/clang/lib/AST/Interp/Boolean.h b/clang/lib/AST/Interp/Boolean.h index 1bfb26b1b669f..23f7286036764 100644 --- a/clang/lib/AST/Interp/Boolean.h +++ b/clang/lib/AST/Interp/Boolean.h @@ -56,7 +56,7 @@ class Boolean final { APSInt toAPSInt(unsigned NumBits) const { return APSInt(toAPSInt().zextOrTrunc(NumBits), true); } - APValue toAPValue() const { return APValue(toAPSInt()); } + APValue toAPValue(const ASTContext &) const { return APValue(toAPSInt()); } Boolean toUnsigned() const { return *this; } diff --git a/clang/lib/AST/Interp/Disasm.cpp b/clang/lib/AST/Interp/Disasm.cpp index c6c6275593007..867284ecf7f4b 100644 --- a/clang/lib/AST/Interp/Disasm.cpp +++ b/clang/lib/AST/Interp/Disasm.cpp @@ -366,9 +366,9 @@ LLVM_DUMP_METHOD void EvaluationResult::dump() const { OS << "LValue: "; if (const auto *P = std::get_if()) - P->toAPValue().printPretty(OS, ASTCtx, SourceType); + P->toAPValue(ASTCtx).printPretty(OS, ASTCtx, SourceType); else if (const auto *FP = std::get_if()) // Nope - FP->toAPValue().printPretty(OS, ASTCtx, SourceType); + FP->toAPValue(ASTCtx).printPretty(OS, ASTCtx, SourceType); OS << "\n"; break; } diff --git a/clang/lib/AST/Interp/EvalEmitter.cpp b/clang/lib/AST/Interp/EvalEmitter.cpp index 221bbfdc542ff..08536536ac3c2 100644 --- a/clang/lib/AST/Interp/EvalEmitter.cpp +++ b/clang/lib/AST/Interp/EvalEmitter.cpp @@ -145,7 +145,7 @@ template bool EvalEmitter::emitRet(const SourceInfo ) { return false; using T = typename PrimConv::T; - EvalResult.setValue(S.Stk.pop().toAPValue()); + EvalResult.setValue(S.Stk.pop().toAPValue(Ctx.getASTContext())); return true; } @@ -181,7 +181,7 @@ template <> bool EvalEmitter::emitRet(const SourceInfo ) { return false; } } else { -EvalResult.setValue(Ptr.toAPValue()); +EvalResult.setValue(Ptr.toAPValue(Ctx.getASTContext())); } return true; @@ -285,7 +285,8 @@ void EvalEmitter::updateGlobalTemporaries() { APValue *Cached = Temp->getOrCreateValue(true); if (std::optional T = Ctx.classify(E->getType())) { -TYPE_SWITCH(*T, { *Cached = Ptr.deref().toAPValue(); }); +TYPE_SWITCH( +*T, { *Cached = Ptr.deref().toAPValue(Ctx.getASTContext()); }); } else { if (std::optional APV = Ptr.toRValue(Ctx, Temp->getTemporaryExpr()->getType())) diff --git a/clang/lib/AST/Interp/EvaluationResult.cpp b/clang/lib/AST/Interp/EvaluationResult.cpp index 0bebfd4ad984e..1b255711c7b36 100644 --- a/clang/lib/AST/Interp/EvaluationResult.cpp +++ b/clang/lib/AST/Interp/EvaluationResult.cpp @@ -21,9 +21,9 @@ APValue EvaluationResult::toAPValue() const { case LValue: // Either a pointer or a function pointer. if (const auto *P = std::get_if()) - return P->toAPValue(); + return P->toAPValue(Ctx->getASTContext()); else if (const auto *FP = std::get_if()) - return FP->toAPValue(); + return FP->toAPValue(Ctx->getASTContext()); else llvm_unreachable("Unhandled LValue type"); break; @@ -46,7 +46,7 @@ std::optional EvaluationResult::toRValue() const { if (const auto *P = std::get_if()) return P->toRValue(*Ctx, getSourceType()); else if (const auto *FP = std::get_if()) // Nope -return FP->toAPValue(); +return FP->toAPValue(Ctx->getASTContext()); llvm_unreachable("Unhandled lvalue kind"); } diff --git a/clang/lib/AST/Interp/Floating.h b/clang/lib/AST/Interp/Floating.h index e4ac76d8509fb..114487821880f 100644 --- a/clang/lib/AST/Interp/Floating.h +++ b/clang/lib/AST/Interp/Floating.h @@ -69,7 +69,7 @@ class Floating final { APSInt toAPSInt(unsigned NumBits = 0) const { return APSInt(F.bitcastToAPInt()); } - APValue toAPValue() const { return APValue(F); } + APValue
[clang] 155f6b4 - [clang][Interp] Fix reporting invalid new/delete expressions
Author: Timm Bäder Date: 2024-07-20T10:41:12+02:00 New Revision: 155f6b49d90357d4062aa97f035f42617565ee26 URL: https://github.com/llvm/llvm-project/commit/155f6b49d90357d4062aa97f035f42617565ee26 DIFF: https://github.com/llvm/llvm-project/commit/155f6b49d90357d4062aa97f035f42617565ee26.diff LOG: [clang][Interp] Fix reporting invalid new/delete expressions This should be a CCEDiag call and we do *not* abort because of it. Added: Modified: clang/lib/AST/Interp/Interp.cpp clang/test/AST/Interp/new-delete.cpp Removed: diff --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp index cd6fc60400ebd..6fcd90e5f5849 100644 --- a/clang/lib/AST/Interp/Interp.cpp +++ b/clang/lib/AST/Interp/Interp.cpp @@ -728,8 +728,8 @@ bool CheckDynamicMemoryAllocation(InterpState , CodePtr OpPC) { return true; const SourceInfo = S.Current->getSource(OpPC); - S.FFDiag(E, diag::note_constexpr_new); - return false; + S.CCEDiag(E, diag::note_constexpr_new); + return true; } bool CheckNewDeleteForms(InterpState , CodePtr OpPC, bool NewWasArray, diff --git a/clang/test/AST/Interp/new-delete.cpp b/clang/test/AST/Interp/new-delete.cpp index cb46426c0e3be..7a85def784920 100644 --- a/clang/test/AST/Interp/new-delete.cpp +++ b/clang/test/AST/Interp/new-delete.cpp @@ -560,4 +560,9 @@ constexpr int a() { // both-error {{never produces a constant expression}} } static_assert(a() == 1, ""); // both-error {{not an integral constant expression}} \ // both-note {{in call to 'a()'}} + + +static_assert(true ? *new int : 4, ""); // both-error {{expression is not an integral constant expression}} \ +// both-note {{read of uninitialized object is not allowed in a constant expression}} + #endif ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 0d26f65 - [clang][Interp] Emit diagnostics if final ltor conversion fails
Author: Timm Bäder Date: 2024-07-20T10:01:25+02:00 New Revision: 0d26f65414afe496b00ee803cc24722a9bf3f41d URL: https://github.com/llvm/llvm-project/commit/0d26f65414afe496b00ee803cc24722a9bf3f41d DIFF: https://github.com/llvm/llvm-project/commit/0d26f65414afe496b00ee803cc24722a9bf3f41d.diff LOG: [clang][Interp] Emit diagnostics if final ltor conversion fails Added: Modified: clang/lib/AST/Interp/EvalEmitter.cpp clang/test/AST/Interp/cxx11.cpp Removed: diff --git a/clang/lib/AST/Interp/EvalEmitter.cpp b/clang/lib/AST/Interp/EvalEmitter.cpp index 59e78686b78ad..221bbfdc542ff 100644 --- a/clang/lib/AST/Interp/EvalEmitter.cpp +++ b/clang/lib/AST/Interp/EvalEmitter.cpp @@ -169,7 +169,9 @@ template <> bool EvalEmitter::emitRet(const SourceInfo ) { return false; // Never allow reading from a non-const pointer, unless the memory // has been created in this evaluation. -if (!Ptr.isConst() && Ptr.block()->getEvalID() != Ctx.getEvalID()) +if (!Ptr.isZero() && Ptr.isBlockPointer() && +Ptr.block()->getEvalID() != Ctx.getEvalID() && +(!CheckLoad(S, OpPC, Ptr, AK_Read) || !Ptr.isConst())) return false; if (std::optional V = diff --git a/clang/test/AST/Interp/cxx11.cpp b/clang/test/AST/Interp/cxx11.cpp index 92ab9b605f30d..cf2dfba079ef7 100644 --- a/clang/test/AST/Interp/cxx11.cpp +++ b/clang/test/AST/Interp/cxx11.cpp @@ -152,3 +152,11 @@ void A::f(SortOrder order) { return; } } + +namespace FinalLtorDiags { + template struct A {}; // both-note {{template parameter is declared here}} + int k; + int *q = // both-note {{declared here}} + A c; // both-error {{non-type template argument of type 'int *' is not a constant expression}} \ + // both-note {{read of non-constexpr variable 'q' is not allowed in a constant expression}} +} ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 06d2176 - [clang][Interp][NFC] Move global variable init case to the top
Author: Timm Bäder Date: 2024-07-20T08:26:06+02:00 New Revision: 06d2176d81cab1d3ed8d0c17f78c1d3ef65cbab8 URL: https://github.com/llvm/llvm-project/commit/06d2176d81cab1d3ed8d0c17f78c1d3ef65cbab8 DIFF: https://github.com/llvm/llvm-project/commit/06d2176d81cab1d3ed8d0c17f78c1d3ef65cbab8.diff LOG: [clang][Interp][NFC] Move global variable init case to the top of the respective functions. Previously, we did not properly mark global zero sized arrays as initialized. Added: Modified: clang/lib/AST/Interp/Pointer.cpp Removed: diff --git a/clang/lib/AST/Interp/Pointer.cpp b/clang/lib/AST/Interp/Pointer.cpp index ff4da0fa805dc..b22b4b1918ba5 100644 --- a/clang/lib/AST/Interp/Pointer.cpp +++ b/clang/lib/AST/Interp/Pointer.cpp @@ -227,6 +227,12 @@ bool Pointer::isInitialized() const { if (isIntegralPointer()) return true; + if (isRoot() && PointeeStorage.BS.Base == sizeof(GlobalInlineDescriptor)) { +const GlobalInlineDescriptor = +*reinterpret_cast(block()->rawData()); +return GD.InitState == GlobalInitState::Initialized; + } + assert(PointeeStorage.BS.Pointee && "Cannot check if null pointer was initialized"); const Descriptor *Desc = getFieldDesc(); @@ -249,12 +255,6 @@ bool Pointer::isInitialized() const { if (asBlockPointer().Base == 0) return true; - if (isRoot() && PointeeStorage.BS.Base == sizeof(GlobalInlineDescriptor)) { -const GlobalInlineDescriptor = -*reinterpret_cast(block()->rawData()); -return GD.InitState == GlobalInitState::Initialized; - } - // Field has its bit in an inline descriptor. return getInlineDesc()->IsInitialized; } @@ -266,6 +266,13 @@ void Pointer::initialize() const { assert(PointeeStorage.BS.Pointee && "Cannot initialize null pointer"); const Descriptor *Desc = getFieldDesc(); + if (isRoot() && PointeeStorage.BS.Base == sizeof(GlobalInlineDescriptor)) { +GlobalInlineDescriptor = *reinterpret_cast( +asBlockPointer().Pointee->rawData()); +GD.InitState = GlobalInitState::Initialized; +return; + } + assert(Desc); if (Desc->isPrimitiveArray()) { // Primitive global arrays don't have an initmap. @@ -294,13 +301,6 @@ void Pointer::initialize() const { return; } - if (isRoot() && PointeeStorage.BS.Base == sizeof(GlobalInlineDescriptor)) { -GlobalInlineDescriptor = *reinterpret_cast( -asBlockPointer().Pointee->rawData()); -GD.InitState = GlobalInitState::Initialized; -return; - } - // Field has its bit in an inline descriptor. assert(PointeeStorage.BS.Base != 0 && "Only composite fields can be initialised"); ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 9145ffa - [clang][Interp] Only diagnose out of bounds enum values in C++
Author: Timm Bäder Date: 2024-07-19T16:06:49+02:00 New Revision: 9145ffa134ed57c25ec62879c1aeff50595d08be URL: https://github.com/llvm/llvm-project/commit/9145ffa134ed57c25ec62879c1aeff50595d08be DIFF: https://github.com/llvm/llvm-project/commit/9145ffa134ed57c25ec62879c1aeff50595d08be.diff LOG: [clang][Interp] Only diagnose out of bounds enum values in C++ Added: Modified: clang/lib/AST/Interp/Compiler.cpp clang/test/Sema/switch.c Removed: diff --git a/clang/lib/AST/Interp/Compiler.cpp b/clang/lib/AST/Interp/Compiler.cpp index 7da711ed485db..ef579bc5d8972 100644 --- a/clang/lib/AST/Interp/Compiler.cpp +++ b/clang/lib/AST/Interp/Compiler.cpp @@ -468,7 +468,7 @@ bool Compiler::VisitCastExpr(const CastExpr *CE) { // Possibly diagnose casts to enum types if the target type does not // have a fixed size. -if (CE->getType()->isEnumeralType()) { +if (Ctx.getLangOpts().CPlusPlus && CE->getType()->isEnumeralType()) { if (const auto *ET = CE->getType().getCanonicalType()->getAs(); ET && !ET->getDecl()->isFixed()) { if (!this->emitCheckEnumValue(*FromT, ET->getDecl(), CE)) diff --git a/clang/test/Sema/switch.c b/clang/test/Sema/switch.c index 69b34f96820d3..6e912d02d6cc7 100644 --- a/clang/test/Sema/switch.c +++ b/clang/test/Sema/switch.c @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -fsyntax-only -verify -Wswitch-enum -Wcovered-switch-default -triple x86_64-linux-gnu %s +// RUN: %clang_cc1 -fsyntax-only -verify -Wswitch-enum -Wcovered-switch-default -triple x86_64-linux-gnu %s -fexperimental-new-constant-interpreter void f (int z) { while (z) { default: z--;// expected-error {{statement not in switch}} ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] d31603e - [clang][Interp] Control InitStack activity state in visitInitList
Author: Timm Bäder Date: 2024-07-19T15:00:35+02:00 New Revision: d31603eefc2d8becfd1f41327b6a8db3e0e91a27 URL: https://github.com/llvm/llvm-project/commit/d31603eefc2d8becfd1f41327b6a8db3e0e91a27 DIFF: https://github.com/llvm/llvm-project/commit/d31603eefc2d8becfd1f41327b6a8db3e0e91a27.diff LOG: [clang][Interp] Control InitStack activity state in visitInitList This doesn't change anything about the current tests, but helps once those tests change because of #97308 Added: Modified: clang/lib/AST/Interp/Compiler.cpp clang/lib/AST/Interp/Compiler.h Removed: diff --git a/clang/lib/AST/Interp/Compiler.cpp b/clang/lib/AST/Interp/Compiler.cpp index 24140b23c1f0b..7da711ed485db 100644 --- a/clang/lib/AST/Interp/Compiler.cpp +++ b/clang/lib/AST/Interp/Compiler.cpp @@ -1334,6 +1334,7 @@ bool Compiler::visitInitList(ArrayRef Inits, auto initPrimitiveField = [=](const Record::Field *FieldToInit, const Expr *Init, PrimType T) -> bool { + InitStackScope ISS(this, isa(Init)); if (!this->visit(Init)) return false; @@ -1344,6 +1345,7 @@ bool Compiler::visitInitList(ArrayRef Inits, auto initCompositeField = [=](const Record::Field *FieldToInit, const Expr *Init) -> bool { + InitStackScope ISS(this, isa(Init)); InitLinkScope ILS(this, InitLink::Field(FieldToInit->Offset)); // Non-primitive case. Get a pointer to the field-to-initialize // on the stack and recurse into visitInitializer(). @@ -4088,12 +4090,7 @@ template bool Compiler::VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *E) { SourceLocScope SLS(this, E); - bool Old = InitStackActive; - InitStackActive = - !(E->getUsedContext()->getDeclKind() == Decl::CXXConstructor); - bool Result = this->delegate(E->getExpr()); - InitStackActive = Old; - return Result; + return this->delegate(E->getExpr()); } template @@ -4151,6 +4148,9 @@ bool Compiler::VisitCXXThisExpr(const CXXThisExpr *E) { // instance pointer of the current function frame, but e.g. to the declaration // currently being initialized. Here we emit the necessary instruction(s) for // this scenario. + if (!InitStackActive || !E->isImplicit()) +return this->emitThis(E); + if (InitStackActive && !InitStack.empty()) { unsigned StartIndex = 0; for (StartIndex = InitStack.size() - 1; StartIndex > 0; --StartIndex) { diff --git a/clang/lib/AST/Interp/Compiler.h b/clang/lib/AST/Interp/Compiler.h index 6df723df2b444..084f5aef25f8e 100644 --- a/clang/lib/AST/Interp/Compiler.h +++ b/clang/lib/AST/Interp/Compiler.h @@ -33,6 +33,7 @@ template class DestructorScope; template class VariableScope; template class DeclScope; template class InitLinkScope; +template class InitStackScope; template class OptionScope; template class ArrayIndexScope; template class SourceLocScope; @@ -298,6 +299,7 @@ class Compiler : public ConstStmtVisitor, bool>, friend class DestructorScope; friend class DeclScope; friend class InitLinkScope; + friend class InitStackScope; friend class OptionScope; friend class ArrayIndexScope; friend class SourceLocScope; @@ -612,6 +614,20 @@ template class InitLinkScope final { Compiler *Ctx; }; +template class InitStackScope final { +public: + InitStackScope(Compiler *Ctx, bool Active) + : Ctx(Ctx), OldValue(Ctx->InitStackActive) { +Ctx->InitStackActive = Active; + } + + ~InitStackScope() { this->Ctx->InitStackActive = OldValue; } + +private: + Compiler *Ctx; + bool OldValue; +}; + } // namespace interp } // namespace clang ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 8c8e0dd - [clang][Interp][test] Use fixed triple in cxx11 test
Author: Timm Bäder Date: 2024-07-18T18:25:08+02:00 New Revision: 8c8e0ddae96882247717b8ae1739abcf09726eab URL: https://github.com/llvm/llvm-project/commit/8c8e0ddae96882247717b8ae1739abcf09726eab DIFF: https://github.com/llvm/llvm-project/commit/8c8e0ddae96882247717b8ae1739abcf09726eab.diff LOG: [clang][Interp][test] Use fixed triple in cxx11 test This uses 'long', which has a different size on Windows. The test I copied this from also uses x86_64-linux. This should fix the bot: https://lab.llvm.org/buildbot/#/builders/81/builds/853 Added: Modified: clang/test/AST/Interp/cxx11.cpp Removed: diff --git a/clang/test/AST/Interp/cxx11.cpp b/clang/test/AST/Interp/cxx11.cpp index c0b88f0e567e0..92ab9b605f30d 100644 --- a/clang/test/AST/Interp/cxx11.cpp +++ b/clang/test/AST/Interp/cxx11.cpp @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify=both,expected -std=c++11 %s -// RUN: %clang_cc1 -verify=both,ref -std=c++11 %s +// RUN: %clang_cc1 -triple x86_64-linux -fexperimental-new-constant-interpreter -verify=both,expected -std=c++11 %s +// RUN: %clang_cc1 -triple x86_64-linux -verify=both,ref -std=c++11 %s namespace IntOrEnum { const int k = 0; ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 9fae0c6 - Reapply "[clang][Interp] Fix CheckCallable for undefined-and-not-constexpr fns"
Author: Timm Bäder Date: 2024-07-18T16:15:59+02:00 New Revision: 9fae0c6f9c05915a5daac5b368258a40e1fab237 URL: https://github.com/llvm/llvm-project/commit/9fae0c6f9c05915a5daac5b368258a40e1fab237 DIFF: https://github.com/llvm/llvm-project/commit/9fae0c6f9c05915a5daac5b368258a40e1fab237.diff LOG: Reapply "[clang][Interp] Fix CheckCallable for undefined-and-not-constexpr fns" This reverts commit ad7aeb0ff58ebd29f68adb85c64e8010639e2a76. Added: clang/test/AST/Interp/cxx2a.cpp Modified: clang/lib/AST/Interp/Interp.cpp clang/lib/AST/Interp/Interp.h Removed: diff --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp index 2be9b5360d055..e6e9298982887 100644 --- a/clang/lib/AST/Interp/Interp.cpp +++ b/clang/lib/AST/Interp/Interp.cpp @@ -579,57 +579,62 @@ bool CheckCallable(InterpState , CodePtr OpPC, const Function *F) { return false; } - if (!F->isConstexpr() || !F->hasBody()) { -const SourceLocation = S.Current->getLocation(OpPC); -if (S.getLangOpts().CPlusPlus11) { - const FunctionDecl *DiagDecl = F->getDecl(); + if (F->isConstexpr() && F->hasBody() && + (F->getDecl()->isConstexpr() || F->getDecl()->hasAttr())) +return true; - // Invalid decls have been diagnosed before. - if (DiagDecl->isInvalidDecl()) -return false; + // Implicitly constexpr. + if (F->isLambdaStaticInvoker()) +return true; - // If this function is not constexpr because it is an inherited - // non-constexpr constructor, diagnose that directly. - const auto *CD = dyn_cast(DiagDecl); - if (CD && CD->isInheritingConstructor()) { -const auto *Inherited = CD->getInheritedConstructor().getConstructor(); -if (!Inherited->isConstexpr()) - DiagDecl = CD = Inherited; - } + const SourceLocation = S.Current->getLocation(OpPC); + if (S.getLangOpts().CPlusPlus11) { +const FunctionDecl *DiagDecl = F->getDecl(); + +// Invalid decls have been diagnosed before. +if (DiagDecl->isInvalidDecl()) + return false; + +// If this function is not constexpr because it is an inherited +// non-constexpr constructor, diagnose that directly. +const auto *CD = dyn_cast(DiagDecl); +if (CD && CD->isInheritingConstructor()) { + const auto *Inherited = CD->getInheritedConstructor().getConstructor(); + if (!Inherited->isConstexpr()) +DiagDecl = CD = Inherited; +} - // FIXME: If DiagDecl is an implicitly-declared special member function - // or an inheriting constructor, we should be much more explicit about why - // it's not constexpr. - if (CD && CD->isInheritingConstructor()) { -S.FFDiag(Loc, diag::note_constexpr_invalid_inhctor, 1) +// FIXME: If DiagDecl is an implicitly-declared special member function +// or an inheriting constructor, we should be much more explicit about why +// it's not constexpr. +if (CD && CD->isInheritingConstructor()) { + S.FFDiag(Loc, diag::note_constexpr_invalid_inhctor, 1) << CD->getInheritedConstructor().getConstructor()->getParent(); -S.Note(DiagDecl->getLocation(), diag::note_declared_at); - } else { -// Don't emit anything if the function isn't defined and we're checking -// for a constant expression. It might be defined at the point we're -// actually calling it. -bool IsExtern = DiagDecl->getStorageClass() == SC_Extern; -if (!DiagDecl->isDefined() && !IsExtern && -S.checkingPotentialConstantExpression()) - return false; + S.Note(DiagDecl->getLocation(), diag::note_declared_at); +} else { + // Don't emit anything if the function isn't defined and we're checking + // for a constant expression. It might be defined at the point we're + // actually calling it. + bool IsExtern = DiagDecl->getStorageClass() == SC_Extern; + if (!DiagDecl->isDefined() && !IsExtern && DiagDecl->isConstexpr() && + S.checkingPotentialConstantExpression()) +return false; -// If the declaration is defined, declared 'constexpr' _and_ has a body, -// the below diagnostic doesn't add anything useful. -if (DiagDecl->isDefined() && DiagDecl->isConstexpr() && -DiagDecl->hasBody()) - return false; + // If the declaration is defined, declared 'constexpr' _and_ has a body, + // the below diagnostic doesn't add anything useful. + if (DiagDecl->isDefined() && DiagDecl->isConstexpr() && + DiagDecl->hasBody()) +return false; -S.FFDiag(Loc, diag::note_constexpr_invalid_function, 1) + S.FFDiag(Loc, diag::note_constexpr_invalid_function, 1) << DiagDecl->isConstexpr() << (bool)CD << DiagDecl; -S.Note(DiagDecl->getLocation(), diag::note_declared_at); - } -} else { - S.FFDiag(Loc,
[clang] d00b355 - [clang][Interp] Fix CheckCallable for undefined-and-not-constexpr fns
Author: Timm Bäder Date: 2024-07-18T15:22:02+02:00 New Revision: d00b35534d068510025d22e5bd9c4fdac45757fb URL: https://github.com/llvm/llvm-project/commit/d00b35534d068510025d22e5bd9c4fdac45757fb DIFF: https://github.com/llvm/llvm-project/commit/d00b35534d068510025d22e5bd9c4fdac45757fb.diff LOG: [clang][Interp] Fix CheckCallable for undefined-and-not-constexpr fns Added: clang/test/AST/Interp/cxx2a.cpp Modified: clang/lib/AST/Interp/Interp.cpp clang/lib/AST/Interp/Interp.h Removed: diff --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp index 2be9b5360d055..be47f72e65a29 100644 --- a/clang/lib/AST/Interp/Interp.cpp +++ b/clang/lib/AST/Interp/Interp.cpp @@ -579,57 +579,61 @@ bool CheckCallable(InterpState , CodePtr OpPC, const Function *F) { return false; } - if (!F->isConstexpr() || !F->hasBody()) { -const SourceLocation = S.Current->getLocation(OpPC); -if (S.getLangOpts().CPlusPlus11) { - const FunctionDecl *DiagDecl = F->getDecl(); + if (F->isConstexpr() && F->hasBody() && F->getDecl()->isConstexpr()) +return true; - // Invalid decls have been diagnosed before. - if (DiagDecl->isInvalidDecl()) -return false; + // Implicitly constexpr. + if (F->isLambdaStaticInvoker()) +return true; - // If this function is not constexpr because it is an inherited - // non-constexpr constructor, diagnose that directly. - const auto *CD = dyn_cast(DiagDecl); - if (CD && CD->isInheritingConstructor()) { -const auto *Inherited = CD->getInheritedConstructor().getConstructor(); -if (!Inherited->isConstexpr()) - DiagDecl = CD = Inherited; - } + const SourceLocation = S.Current->getLocation(OpPC); + if (S.getLangOpts().CPlusPlus11) { +const FunctionDecl *DiagDecl = F->getDecl(); + +// Invalid decls have been diagnosed before. +if (DiagDecl->isInvalidDecl()) + return false; + +// If this function is not constexpr because it is an inherited +// non-constexpr constructor, diagnose that directly. +const auto *CD = dyn_cast(DiagDecl); +if (CD && CD->isInheritingConstructor()) { + const auto *Inherited = CD->getInheritedConstructor().getConstructor(); + if (!Inherited->isConstexpr()) +DiagDecl = CD = Inherited; +} - // FIXME: If DiagDecl is an implicitly-declared special member function - // or an inheriting constructor, we should be much more explicit about why - // it's not constexpr. - if (CD && CD->isInheritingConstructor()) { -S.FFDiag(Loc, diag::note_constexpr_invalid_inhctor, 1) +// FIXME: If DiagDecl is an implicitly-declared special member function +// or an inheriting constructor, we should be much more explicit about why +// it's not constexpr. +if (CD && CD->isInheritingConstructor()) { + S.FFDiag(Loc, diag::note_constexpr_invalid_inhctor, 1) << CD->getInheritedConstructor().getConstructor()->getParent(); -S.Note(DiagDecl->getLocation(), diag::note_declared_at); - } else { -// Don't emit anything if the function isn't defined and we're checking -// for a constant expression. It might be defined at the point we're -// actually calling it. -bool IsExtern = DiagDecl->getStorageClass() == SC_Extern; -if (!DiagDecl->isDefined() && !IsExtern && -S.checkingPotentialConstantExpression()) - return false; + S.Note(DiagDecl->getLocation(), diag::note_declared_at); +} else { + // Don't emit anything if the function isn't defined and we're checking + // for a constant expression. It might be defined at the point we're + // actually calling it. + bool IsExtern = DiagDecl->getStorageClass() == SC_Extern; + if (!DiagDecl->isDefined() && !IsExtern && DiagDecl->isConstexpr() && + S.checkingPotentialConstantExpression()) +return false; -// If the declaration is defined, declared 'constexpr' _and_ has a body, -// the below diagnostic doesn't add anything useful. -if (DiagDecl->isDefined() && DiagDecl->isConstexpr() && -DiagDecl->hasBody()) - return false; + // If the declaration is defined, declared 'constexpr' _and_ has a body, + // the below diagnostic doesn't add anything useful. + if (DiagDecl->isDefined() && DiagDecl->isConstexpr() && + DiagDecl->hasBody()) +return false; -S.FFDiag(Loc, diag::note_constexpr_invalid_function, 1) + S.FFDiag(Loc, diag::note_constexpr_invalid_function, 1) << DiagDecl->isConstexpr() << (bool)CD << DiagDecl; -S.Note(DiagDecl->getLocation(), diag::note_declared_at); - } -} else { - S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr); + S.Note(DiagDecl->getLocation(), diag::note_declared_at);
[clang] fc65a96 - [clang][Interp] Run record destructors when deallocating dynamic memory
Author: Timm Bäder Date: 2024-07-18T15:07:29+02:00 New Revision: fc65a9603bf16ed1fe98fbee6933bca9e2083384 URL: https://github.com/llvm/llvm-project/commit/fc65a9603bf16ed1fe98fbee6933bca9e2083384 DIFF: https://github.com/llvm/llvm-project/commit/fc65a9603bf16ed1fe98fbee6933bca9e2083384.diff LOG: [clang][Interp] Run record destructors when deallocating dynamic memory Added: Modified: clang/lib/AST/Interp/Interp.cpp clang/lib/AST/Interp/Interp.h clang/test/AST/Interp/new-delete.cpp Removed: diff --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp index fb63228f8aea8..2be9b5360d055 100644 --- a/clang/lib/AST/Interp/Interp.cpp +++ b/clang/lib/AST/Interp/Interp.cpp @@ -819,6 +819,81 @@ bool CheckNonNullArgs(InterpState , CodePtr OpPC, const Function *F, return true; } +// FIXME: This is similar to code we already have in Compiler.cpp. +// I think it makes sense to instead add the field and base destruction stuff +// to the destructor Function itself. Then destroying a record would really +// _just_ be calling its destructor. That would also help with the diagnostic +// diff erence when the destructor or a field/base fails. +static bool runRecordDestructor(InterpState , CodePtr OpPC, +const Pointer , +const Descriptor *Desc) { + assert(Desc->isRecord()); + const Record *R = Desc->ElemRecord; + assert(R); + + // Fields. + for (const Record::Field : llvm::reverse(R->fields())) { +const Descriptor *D = Field.Desc; +if (D->isRecord()) { + if (!runRecordDestructor(S, OpPC, BasePtr.atField(Field.Offset), D)) +return false; +} else if (D->isCompositeArray()) { + const Descriptor *ElemDesc = Desc->ElemDesc; + assert(ElemDesc->isRecord()); + for (unsigned I = 0; I != Desc->getNumElems(); ++I) { +if (!runRecordDestructor(S, OpPC, BasePtr.atIndex(I).narrow(), + ElemDesc)) + return false; + } +} + } + + // Destructor of this record. + if (const CXXDestructorDecl *Dtor = R->getDestructor(); + Dtor && !Dtor->isTrivial()) { +const Function *DtorFunc = S.getContext().getOrCreateFunction(Dtor); +if (!DtorFunc) + return false; + +S.Stk.push(BasePtr); +if (!Call(S, OpPC, DtorFunc, 0)) + return false; + } + + // Bases. + for (const Record::Base : llvm::reverse(R->bases())) { +if (!runRecordDestructor(S, OpPC, BasePtr.atField(Base.Offset), Base.Desc)) + return false; + } + + return true; +} + +bool RunDestructors(InterpState , CodePtr OpPC, const Block *B) { + assert(B); + const Descriptor *Desc = B->getDescriptor(); + + if (Desc->isPrimitive() || Desc->isPrimitiveArray()) +return true; + + assert(Desc->isRecord() || Desc->isCompositeArray()); + + if (Desc->isCompositeArray()) { +const Descriptor *ElemDesc = Desc->ElemDesc; +assert(ElemDesc->isRecord()); + +Pointer RP(const_cast(B)); +for (unsigned I = 0; I != Desc->getNumElems(); ++I) { + if (!runRecordDestructor(S, OpPC, RP.atIndex(I).narrow(), ElemDesc)) +return false; +} +return true; + } + + assert(Desc->isRecord()); + return runRecordDestructor(S, OpPC, Pointer(const_cast(B)), Desc); +} + bool Interpret(InterpState , APValue ) { // The current stack frame when we started Interpret(). // This is being used by the ops to determine wheter diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h index b4f8c03280c85..17b3157cb40a9 100644 --- a/clang/lib/AST/Interp/Interp.h +++ b/clang/lib/AST/Interp/Interp.h @@ -2872,8 +2872,8 @@ inline bool AllocCN(InterpState , CodePtr OpPC, const Descriptor *ElementDesc, return true; } +bool RunDestructors(InterpState , CodePtr OpPC, const Block *B); static inline bool Free(InterpState , CodePtr OpPC, bool DeleteIsArrayForm) { - if (!CheckDynamicMemoryAllocation(S, OpPC)) return false; @@ -2904,6 +2904,10 @@ static inline bool Free(InterpState , CodePtr OpPC, bool DeleteIsArrayForm) { assert(Source); assert(BlockToDelete); + // Invoke destructors before deallocating the memory. + if (!RunDestructors(S, OpPC, BlockToDelete)) +return false; + DynamicAllocator = S.getAllocator(); bool WasArrayAlloc = Allocator.isArrayAllocation(Source); const Descriptor *BlockDesc = BlockToDelete->getDescriptor(); diff --git a/clang/test/AST/Interp/new-delete.cpp b/clang/test/AST/Interp/new-delete.cpp index 04ce3ae5f6637..cb46426c0e3be 100644 --- a/clang/test/AST/Interp/new-delete.cpp +++ b/clang/test/AST/Interp/new-delete.cpp @@ -476,7 +476,80 @@ constexpr Sp ss[] = {Sp{new int{154}}}; // both-error {{must be initialized by a // both-note {{pointer to heap-allocated object}} \ // both-note {{allocation
[clang] 7aabdb8 - [clang][Interp][NFC] Protect ByteCodeEmitter against unfinished fns
Author: Timm Bäder Date: 2024-07-18T09:05:48+02:00 New Revision: 7aabdb8776eb11b90d43162254db47df46806ec9 URL: https://github.com/llvm/llvm-project/commit/7aabdb8776eb11b90d43162254db47df46806ec9 DIFF: https://github.com/llvm/llvm-project/commit/7aabdb8776eb11b90d43162254db47df46806ec9.diff LOG: [clang][Interp][NFC] Protect ByteCodeEmitter against unfinished fns This is similar to a check in TextNodeDumper.cpp. Without this, we will crash later when trying to iterate over FuncDecl->params(). Added: Modified: clang/lib/AST/Interp/ByteCodeEmitter.cpp Removed: diff --git a/clang/lib/AST/Interp/ByteCodeEmitter.cpp b/clang/lib/AST/Interp/ByteCodeEmitter.cpp index 17da77bc63c9b..a3d4c7d7392da 100644 --- a/clang/lib/AST/Interp/ByteCodeEmitter.cpp +++ b/clang/lib/AST/Interp/ByteCodeEmitter.cpp @@ -31,6 +31,12 @@ static bool isUnevaluatedBuiltin(unsigned BuiltinID) { } Function *ByteCodeEmitter::compileFunc(const FunctionDecl *FuncDecl) { + + // Manually created functions that haven't been assigned proper + // parameters yet. + if (!FuncDecl->param_empty() && !FuncDecl->param_begin()) +return nullptr; + bool IsLambdaStaticInvoker = false; if (const auto *MD = dyn_cast(FuncDecl); MD && MD->isLambdaStaticInvoker()) { ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] fbf8b82 - [clang][Interp][NFC] Be more cautious about Block initialization state
Author: Timm Bäder Date: 2024-07-18T08:01:24+02:00 New Revision: fbf8b82cd02818c005bb39abbf550333bea6 URL: https://github.com/llvm/llvm-project/commit/fbf8b82cd02818c005bb39abbf550333bea6 DIFF: https://github.com/llvm/llvm-project/commit/fbf8b82cd02818c005bb39abbf550333bea6.diff LOG: [clang][Interp][NFC] Be more cautious about Block initialization state ... when moving a Block to a DeadBlock. Only invoke the MoveFn if the old block was initialized at all. Added: Modified: clang/lib/AST/Interp/InterpBlock.cpp clang/lib/AST/Interp/InterpState.cpp Removed: diff --git a/clang/lib/AST/Interp/InterpBlock.cpp b/clang/lib/AST/Interp/InterpBlock.cpp index 7bef5e678c074..5ac778aeb6075 100644 --- a/clang/lib/AST/Interp/InterpBlock.cpp +++ b/clang/lib/AST/Interp/InterpBlock.cpp @@ -110,6 +110,9 @@ DeadBlock::DeadBlock(DeadBlock *, Block *Blk) } void DeadBlock::free() { + if (B.IsInitialized) +B.invokeDtor(); + if (Prev) Prev->Next = Next; if (Next) diff --git a/clang/lib/AST/Interp/InterpState.cpp b/clang/lib/AST/Interp/InterpState.cpp index 332f551838b72..4ea05305540ee 100644 --- a/clang/lib/AST/Interp/InterpState.cpp +++ b/clang/lib/AST/Interp/InterpState.cpp @@ -69,13 +69,15 @@ void InterpState::deallocate(Block *B) { char *Memory = reinterpret_cast(std::malloc(sizeof(DeadBlock) + Size)); auto *D = new (Memory) DeadBlock(DeadBlocks, B); +std::memset(D->B.rawData(), 0, D->B.getSize()); // Move data and metadata from the old block to the new (dead)block. -if (Desc->MoveFn) { +if (B->IsInitialized && Desc->MoveFn) { Desc->MoveFn(B, B->data(), D->data(), Desc); if (Desc->getMetadataSize() > 0) std::memcpy(D->rawData(), B->rawData(), Desc->getMetadataSize()); } +D->B.IsInitialized = B->IsInitialized; // We moved the contents over to the DeadBlock. B->IsInitialized = false; ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 39d751a - [clang][Interp] Use an array root's field decl in the LValuePath
Author: Timm Bäder Date: 2024-07-17T11:26:50+02:00 New Revision: 39d751ad976ba9f5e8a1ad3880559faba38c3c3f URL: https://github.com/llvm/llvm-project/commit/39d751ad976ba9f5e8a1ad3880559faba38c3c3f DIFF: https://github.com/llvm/llvm-project/commit/39d751ad976ba9f5e8a1ad3880559faba38c3c3f.diff LOG: [clang][Interp] Use an array root's field decl in the LValuePath Instead of pushing the index 0. Added: Modified: clang/lib/AST/Interp/Pointer.cpp clang/test/AST/Interp/functions.cpp Removed: diff --git a/clang/lib/AST/Interp/Pointer.cpp b/clang/lib/AST/Interp/Pointer.cpp index b2e3a7ff70881..ff4da0fa805dc 100644 --- a/clang/lib/AST/Interp/Pointer.cpp +++ b/clang/lib/AST/Interp/Pointer.cpp @@ -152,8 +152,9 @@ APValue Pointer::toAPValue() const { Pointer Ptr = *this; while (Ptr.isField() || Ptr.isArrayElement()) { if (Ptr.isArrayRoot()) { -Path.push_back(APValue::LValuePathEntry::ArrayIndex(0)); -Ptr = Ptr.getBase(); + Path.push_back(APValue::LValuePathEntry( + {Ptr.getFieldDesc()->asDecl(), /*IsVirtual=*/false})); + Ptr = Ptr.getBase(); } else if (Ptr.isArrayElement()) { if (Ptr.isOnePastEnd()) Path.push_back(APValue::LValuePathEntry::ArrayIndex(Ptr.getArray().getNumElems())); diff --git a/clang/test/AST/Interp/functions.cpp b/clang/test/AST/Interp/functions.cpp index fa29e08a30175..f190262ad3ebe 100644 --- a/clang/test/AST/Interp/functions.cpp +++ b/clang/test/AST/Interp/functions.cpp @@ -644,3 +644,21 @@ namespace FunctionCast { // both-warning {{are a Clang extension}} int b[(int)IntFn(f)()];// ok } + +#if __cplusplus >= 202002L +namespace StableAddress { + template struct str { +char arr[N]; + }; + // FIXME: Deduction guide not needed with P1816R0. + template str(const char (&)[N]) -> str; + + template constexpr int sum() { +int n = 0; +for (char c : s.arr) + n += c; +return n; + } + static_assert(sum() == 1234, ""); +} +#endif ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 72b3d7b - [clang][Interp] Makre sure we don't overflow Descriptor::AllocSize
Author: Timm Bäder Date: 2024-07-17T10:56:14+02:00 New Revision: 72b3d7bc87019ba7ef268ce322f90382f01b11af URL: https://github.com/llvm/llvm-project/commit/72b3d7bc87019ba7ef268ce322f90382f01b11af DIFF: https://github.com/llvm/llvm-project/commit/72b3d7bc87019ba7ef268ce322f90382f01b11af.diff LOG: [clang][Interp] Makre sure we don't overflow Descriptor::AllocSize We allocate the metadata and the array elements in one allocation, and we save its size in a field of type 'unsigned'. Makre sure the full size of the allocation doesn't overflow the field. Added: Modified: clang/lib/AST/Interp/Descriptor.cpp clang/lib/AST/Interp/Descriptor.h Removed: diff --git a/clang/lib/AST/Interp/Descriptor.cpp b/clang/lib/AST/Interp/Descriptor.cpp index a3801a01688c8..f7d1201f625bb 100644 --- a/clang/lib/AST/Interp/Descriptor.cpp +++ b/clang/lib/AST/Interp/Descriptor.cpp @@ -303,6 +303,7 @@ Descriptor::Descriptor(const DeclTy , PrimType Type, MetadataSize MD, IsArray(true), CtorFn(getCtorArrayPrim(Type)), DtorFn(getDtorArrayPrim(Type)), MoveFn(getMoveArrayPrim(Type)) { assert(Source && "Missing source"); + assert(NumElems <= (MaxArrayElemBytes / ElemSize)); } /// Primitive unknown-size arrays. diff --git a/clang/lib/AST/Interp/Descriptor.h b/clang/lib/AST/Interp/Descriptor.h index f444b8a78e802..0dd97812e5a5c 100644 --- a/clang/lib/AST/Interp/Descriptor.h +++ b/clang/lib/AST/Interp/Descriptor.h @@ -13,6 +13,7 @@ #ifndef LLVM_CLANG_AST_INTERP_DESCRIPTOR_H #define LLVM_CLANG_AST_INTERP_DESCRIPTOR_H +#include "PrimType.h" #include "clang/AST/Decl.h" #include "clang/AST/Expr.h" @@ -125,6 +126,11 @@ struct Descriptor final { static constexpr MetadataSize InlineDescMD = sizeof(InlineDescriptor); static constexpr MetadataSize GlobalMD = sizeof(GlobalInlineDescriptor); + /// Maximum number of bytes to be used for array elements. + static constexpr unsigned MaxArrayElemBytes = + std::numeric_limits::max() - sizeof(InitMapPtr) - + align(std::max(*InlineDescMD, *GlobalMD)); + /// Pointer to the record, if block contains records. const Record *const ElemRecord = nullptr; /// Descriptor of the array element. ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 85cedd8 - [clang][Interp] Ignore incomplete records when visiting lambdas
Author: Timm Bäder Date: 2024-07-16T15:04:32+02:00 New Revision: 85cedd8e59be5eebad6292aee3b053f31afc8977 URL: https://github.com/llvm/llvm-project/commit/85cedd8e59be5eebad6292aee3b053f31afc8977 DIFF: https://github.com/llvm/llvm-project/commit/85cedd8e59be5eebad6292aee3b053f31afc8977.diff LOG: [clang][Interp] Ignore incomplete records when visiting lambdas We need them to be complete so we have knowledge about all the lambda captures. Added: Modified: clang/lib/AST/Interp/ByteCodeEmitter.cpp clang/lib/AST/Interp/Context.cpp clang/test/AST/Interp/lambda.cpp Removed: diff --git a/clang/lib/AST/Interp/ByteCodeEmitter.cpp b/clang/lib/AST/Interp/ByteCodeEmitter.cpp index ae777d555e916..17da77bc63c9b 100644 --- a/clang/lib/AST/Interp/ByteCodeEmitter.cpp +++ b/clang/lib/AST/Interp/ByteCodeEmitter.cpp @@ -93,6 +93,11 @@ Function *ByteCodeEmitter::compileFunc(const FunctionDecl *FuncDecl) { // Set up lambda capture to closure record field mapping. if (isLambdaCallOperator(MD)) { + // The parent record needs to be complete, we need to know about all + // the lambda captures. + if (!MD->getParent()->isCompleteDefinition()) +return nullptr; + const Record *R = P.getOrCreateRecord(MD->getParent()); llvm::DenseMap LC; FieldDecl *LTC; diff --git a/clang/lib/AST/Interp/Context.cpp b/clang/lib/AST/Interp/Context.cpp index 913e8d514282a..b5e992c5a9ac1 100644 --- a/clang/lib/AST/Interp/Context.cpp +++ b/clang/lib/AST/Interp/Context.cpp @@ -31,6 +31,9 @@ bool Context::isPotentialConstantExpr(State , const FunctionDecl *FD) { if (!Func || !Func->hasBody()) Func = Compiler(*this, *P).compileFunc(FD); + if (!Func) +return false; + APValue DummyResult; if (!Run(Parent, Func, DummyResult)) return false; diff --git a/clang/test/AST/Interp/lambda.cpp b/clang/test/AST/Interp/lambda.cpp index 0eb12643b1b7f..d68fe995e8fa1 100644 --- a/clang/test/AST/Interp/lambda.cpp +++ b/clang/test/AST/Interp/lambda.cpp @@ -280,3 +280,9 @@ namespace InvalidCapture { } (); } } + +constexpr int fn() { + int Capture = 42; + return [=]() constexpr { return Capture; }(); +} +static_assert(fn() == 42, ""); ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 5b310a1 - [clang][Interp] Ignore lambda static invoker frames in backtraces
Author: Timm Bäder Date: 2024-07-16T13:57:41+02:00 New Revision: 5b310a1c3c5aabae325934a6475e93ea8b71cdc2 URL: https://github.com/llvm/llvm-project/commit/5b310a1c3c5aabae325934a6475e93ea8b71cdc2 DIFF: https://github.com/llvm/llvm-project/commit/5b310a1c3c5aabae325934a6475e93ea8b71cdc2.diff LOG: [clang][Interp] Ignore lambda static invoker frames in backtraces See comment. No test but this is neccessary for a later commit. Added: Modified: clang/lib/AST/Interp/InterpFrame.cpp Removed: diff --git a/clang/lib/AST/Interp/InterpFrame.cpp b/clang/lib/AST/Interp/InterpFrame.cpp index 383380f485e03..d3f3e216b7eb2 100644 --- a/clang/lib/AST/Interp/InterpFrame.cpp +++ b/clang/lib/AST/Interp/InterpFrame.cpp @@ -158,7 +158,9 @@ void InterpFrame::describe(llvm::raw_ostream ) const { // diagnose them. The 'in call to' diagnostics for them add no value to the // user _and_ it doesn't generally work since the argument types don't always // match the function prototype. Just ignore them. - if (const auto *F = getFunction(); F && F->isBuiltin()) + // Similarly, for lambda static invokers, we would just print __invoke(). + if (const auto *F = getFunction(); + F && (F->isBuiltin() || F->isLambdaStaticInvoker())) return; const FunctionDecl *F = getCallee(); ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] d8f0611 - [clang][Interp] Allow ltor casts for null pointers
Author: Timm Bäder Date: 2024-07-16T08:28:51+02:00 New Revision: d8f0611acc2658ccc54d985044aa115716c6ad34 URL: https://github.com/llvm/llvm-project/commit/d8f0611acc2658ccc54d985044aa115716c6ad34 DIFF: https://github.com/llvm/llvm-project/commit/d8f0611acc2658ccc54d985044aa115716c6ad34.diff LOG: [clang][Interp] Allow ltor casts for null pointers We can't read from them but we special-case them later. Added: Modified: clang/lib/AST/Interp/EvalEmitter.cpp clang/test/CodeGenCXX/nullptr.cpp Removed: diff --git a/clang/lib/AST/Interp/EvalEmitter.cpp b/clang/lib/AST/Interp/EvalEmitter.cpp index 1a9444d38fdd5..74413baf6fc0c 100644 --- a/clang/lib/AST/Interp/EvalEmitter.cpp +++ b/clang/lib/AST/Interp/EvalEmitter.cpp @@ -152,7 +152,7 @@ template <> bool EvalEmitter::emitRet(const SourceInfo ) { // Implicitly convert lvalue to rvalue, if requested. if (ConvertResultToRValue) { -if (!Ptr.isDereferencable()) +if (!Ptr.isZero() && !Ptr.isDereferencable()) return false; // Never allow reading from a non-const pointer, unless the memory // has been created in this evaluation. diff --git a/clang/test/CodeGenCXX/nullptr.cpp b/clang/test/CodeGenCXX/nullptr.cpp index ca76c55e2122d..0d8837b216bec 100644 --- a/clang/test/CodeGenCXX/nullptr.cpp +++ b/clang/test/CodeGenCXX/nullptr.cpp @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin10 -I%S -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin10 -I%S -emit-llvm -o - %s -fexperimental-new-constant-interpreter | FileCheck %s #include ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] ff96ad8 - [clang][Interp][NFC] Add Pointer::isDereferencable()
Author: Timm Bäder Date: 2024-07-16T07:24:08+02:00 New Revision: ff96ad84f52022af295d11749f106480e7292a89 URL: https://github.com/llvm/llvm-project/commit/ff96ad84f52022af295d11749f106480e7292a89 DIFF: https://github.com/llvm/llvm-project/commit/ff96ad84f52022af295d11749f106480e7292a89.diff LOG: [clang][Interp][NFC] Add Pointer::isDereferencable() We currently have a few places where we check whether a pointer can be read from at all. Add a function to do that. Added: Modified: clang/lib/AST/Interp/Pointer.h Removed: diff --git a/clang/lib/AST/Interp/Pointer.h b/clang/lib/AST/Interp/Pointer.h index 6e9e8675306ef..28bc42985adb2 100644 --- a/clang/lib/AST/Interp/Pointer.h +++ b/clang/lib/AST/Interp/Pointer.h @@ -584,6 +584,7 @@ class Pointer { assert(isLive() && "Invalid pointer"); assert(isBlockPointer()); assert(asBlockPointer().Pointee); +assert(isDereferencable()); assert(Offset + sizeof(T) <= asBlockPointer().Pointee->getDescriptor()->getAllocSize()); @@ -603,6 +604,17 @@ class Pointer { sizeof(InitMapPtr))[I]; } + /// Whether this block can be read from at all. This is only true for + /// block pointers that point to a valid location inside that block. + bool isDereferencable() const { +if (!isBlockPointer()) + return false; +if (isPastEnd()) + return false; + +return true; + } + /// Initializes a field. void initialize() const; /// Activats a field. ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] f30c09e - [clang][Interp][NFC] Use a templated conversion operator
Author: Timm Bäder Date: 2024-07-16T04:49:05+02:00 New Revision: f30c09e2d3107e117faf8311c6d8642fa95680af URL: https://github.com/llvm/llvm-project/commit/f30c09e2d3107e117faf8311c6d8642fa95680af DIFF: https://github.com/llvm/llvm-project/commit/f30c09e2d3107e117faf8311c6d8642fa95680af.diff LOG: [clang][Interp][NFC] Use a templated conversion operator Added: Modified: clang/lib/AST/Interp/Boolean.h clang/lib/AST/Interp/Integral.h Removed: diff --git a/clang/lib/AST/Interp/Boolean.h b/clang/lib/AST/Interp/Boolean.h index 336f7941dfc47..1bfb26b1b669f 100644 --- a/clang/lib/AST/Interp/Boolean.h +++ b/clang/lib/AST/Interp/Boolean.h @@ -45,15 +45,10 @@ class Boolean final { Boolean operator-(const Boolean ) const { return Boolean(V - Other.V); } Boolean operator~() const { return Boolean(true); } - explicit operator int8_t() const { return V; } - explicit operator uint8_t() const { return V; } - explicit operator int16_t() const { return V; } - explicit operator uint16_t() const { return V; } - explicit operator int32_t() const { return V; } - explicit operator uint32_t() const { return V; } - explicit operator int64_t() const { return V; } - explicit operator uint64_t() const { return V; } - explicit operator bool() const { return V; } + template >> + explicit operator Ty() const { +return V; + } APSInt toAPSInt() const { return APSInt(APInt(1, static_cast(V), false), true); diff --git a/clang/lib/AST/Interp/Integral.h b/clang/lib/AST/Interp/Integral.h index cc1cab8f39fb1..db4cc9ae45b49 100644 --- a/clang/lib/AST/Interp/Integral.h +++ b/clang/lib/AST/Interp/Integral.h @@ -98,10 +98,10 @@ template class Integral final { return Integral(V); } - explicit operator unsigned() const { return V; } - explicit operator int64_t() const { return V; } - explicit operator uint64_t() const { return V; } - explicit operator int32_t() const { return V; } + template >> + explicit operator Ty() const { +return V; + } APSInt toAPSInt() const { return APSInt(APInt(Bits, static_cast(V), Signed), !Signed); ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 6484655 - [clang][Interp] Allow initialization of extern variables via ctors
Author: Timm Bäder Date: 2024-07-15T13:12:52+02:00 New Revision: 6484655f9dd07c6d5669dd540feef3c80af84827 URL: https://github.com/llvm/llvm-project/commit/6484655f9dd07c6d5669dd540feef3c80af84827 DIFF: https://github.com/llvm/llvm-project/commit/6484655f9dd07c6d5669dd540feef3c80af84827.diff LOG: [clang][Interp] Allow initialization of extern variables via ctors Added: Modified: clang/lib/AST/Interp/Interp.cpp clang/test/AST/Interp/literals.cpp Removed: diff --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp index 7b2c0480f80ae..b673cc27aee21 100644 --- a/clang/lib/AST/Interp/Interp.cpp +++ b/clang/lib/AST/Interp/Interp.cpp @@ -248,7 +248,8 @@ bool CheckExtern(InterpState , CodePtr OpPC, const Pointer ) { if (!Ptr.isExtern()) return true; - if (Ptr.isInitialized()) + if (Ptr.isInitialized() || + (Ptr.getDeclDesc()->asVarDecl() == S.EvaluatingDecl)) return true; if (!S.checkingPotentialConstantExpression() && S.getLangOpts().CPlusPlus) { diff --git a/clang/test/AST/Interp/literals.cpp b/clang/test/AST/Interp/literals.cpp index 6c214f5a6efa7..9cd65462a0af3 100644 --- a/clang/test/AST/Interp/literals.cpp +++ b/clang/test/AST/Interp/literals.cpp @@ -1232,6 +1232,13 @@ namespace Extern { } static_assert(() == , ""); #endif + + struct A { +int b; + }; + + extern constexpr A a{12}; + static_assert(a.b == 12, ""); } #if __cplusplus >= 201402L ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 9ac2b89 - [clang][Interp] Diagnose volatile reads
Author: Timm Bäder Date: 2024-07-15T09:37:45+02:00 New Revision: 9ac2b8965264a7f20a3e07c913b25c375a080c0f URL: https://github.com/llvm/llvm-project/commit/9ac2b8965264a7f20a3e07c913b25c375a080c0f DIFF: https://github.com/llvm/llvm-project/commit/9ac2b8965264a7f20a3e07c913b25c375a080c0f.diff LOG: [clang][Interp] Diagnose volatile reads Added: Modified: clang/lib/AST/Interp/Interp.cpp clang/test/AST/Interp/literals.cpp Removed: diff --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp index 70a470021e7f2..7b2c0480f80ae 100644 --- a/clang/lib/AST/Interp/Interp.cpp +++ b/clang/lib/AST/Interp/Interp.cpp @@ -444,6 +444,27 @@ bool CheckMutable(InterpState , CodePtr OpPC, const Pointer ) { return false; } +bool CheckVolatile(InterpState , CodePtr OpPC, const Pointer , + AccessKinds AK) { + assert(Ptr.isLive()); + + // FIXME: This check here might be kinda expensive. Maybe it would be better + // to have another field in InlineDescriptor for this? + if (!Ptr.isBlockPointer()) +return true; + + QualType PtrType = Ptr.getType(); + if (!PtrType.isVolatileQualified()) +return true; + + const SourceInfo = S.Current->getSource(OpPC); + if (S.getLangOpts().CPlusPlus) +S.FFDiag(Loc, diag::note_constexpr_access_volatile_type) << AK << PtrType; + else +S.FFDiag(Loc); + return false; +} + bool CheckInitialized(InterpState , CodePtr OpPC, const Pointer , AccessKinds AK) { assert(Ptr.isLive()); @@ -508,6 +529,8 @@ bool CheckLoad(InterpState , CodePtr OpPC, const Pointer , return false; if (!CheckMutable(S, OpPC, Ptr)) return false; + if (!CheckVolatile(S, OpPC, Ptr, AK)) +return false; return true; } diff --git a/clang/test/AST/Interp/literals.cpp b/clang/test/AST/Interp/literals.cpp index af5bcb6d48ae7..6c214f5a6efa7 100644 --- a/clang/test/AST/Interp/literals.cpp +++ b/clang/test/AST/Interp/literals.cpp @@ -1290,3 +1290,9 @@ namespace UnaryOpError { } } #endif + +namespace VolatileReads { + const volatile int b = 1; + static_assert(b, ""); // both-error {{not an integral constant expression}} \ +// both-note {{read of volatile-qualified type 'const volatile int' is not allowed in a constant expression}} +} ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 48d703e - Revert "[clang][Interp] Implement dynamic memory allocation handling (#70306)"
Author: Timm Bäder Date: 2024-07-14T21:17:47+02:00 New Revision: 48d703e7f56282ce5d690e45a129a4a7fd040ee6 URL: https://github.com/llvm/llvm-project/commit/48d703e7f56282ce5d690e45a129a4a7fd040ee6 DIFF: https://github.com/llvm/llvm-project/commit/48d703e7f56282ce5d690e45a129a4a7fd040ee6.diff LOG: Revert "[clang][Interp] Implement dynamic memory allocation handling (#70306)" This reverts commit fa133d3151b5e428b1c5819d29b0ad28a90882a2. It looks like this has some more serious problems: https://lab.llvm.org/buildbot/#/builders/39/builds/528 As well as build failures on MacOS. Added: Modified: clang/lib/AST/CMakeLists.txt clang/lib/AST/Interp/Compiler.cpp clang/lib/AST/Interp/Compiler.h clang/lib/AST/Interp/EvalEmitter.cpp clang/lib/AST/Interp/EvaluationResult.cpp clang/lib/AST/Interp/EvaluationResult.h clang/lib/AST/Interp/Interp.cpp clang/lib/AST/Interp/Interp.h clang/lib/AST/Interp/InterpBlock.h clang/lib/AST/Interp/InterpState.cpp clang/lib/AST/Interp/InterpState.h clang/lib/AST/Interp/Opcodes.td clang/lib/AST/Interp/Pointer.h clang/test/Rewriter/rewrite-modern-catch.m clang/test/SemaCXX/delete.cpp clang/test/SemaCXX/new-delete.cpp Removed: clang/lib/AST/Interp/DynamicAllocator.cpp clang/lib/AST/Interp/DynamicAllocator.h clang/test/AST/Interp/new-delete.cpp diff --git a/clang/lib/AST/CMakeLists.txt b/clang/lib/AST/CMakeLists.txt index 70aecb781c2ff..ceaad8d3c5a86 100644 --- a/clang/lib/AST/CMakeLists.txt +++ b/clang/lib/AST/CMakeLists.txt @@ -75,7 +75,6 @@ add_clang_library(clangAST Interp/InterpBuiltin.cpp Interp/Floating.cpp Interp/EvaluationResult.cpp - Interp/DynamicAllocator.cpp Interp/Interp.cpp Interp/InterpBlock.cpp Interp/InterpFrame.cpp diff --git a/clang/lib/AST/Interp/Compiler.cpp b/clang/lib/AST/Interp/Compiler.cpp index 1f43f46c399f1..30dc7f5e4840b 100644 --- a/clang/lib/AST/Interp/Compiler.cpp +++ b/clang/lib/AST/Interp/Compiler.cpp @@ -2771,109 +2771,6 @@ bool Compiler::VisitCXXInheritedCtorInitExpr( return this->emitCall(F, 0, E); } -template -bool Compiler::VisitCXXNewExpr(const CXXNewExpr *E) { - assert(classifyPrim(E->getType()) == PT_Ptr); - const Expr *Init = E->getInitializer(); - QualType ElementType = E->getAllocatedType(); - std::optional ElemT = classify(ElementType); - unsigned PlacementArgs = E->getNumPlacementArgs(); - bool IsNoThrow = false; - - // FIXME: Better diagnostic. diag::note_constexpr_new_placement - if (PlacementArgs != 0) { -// The only new-placement list we support is of the form (std::nothrow). -// -// FIXME: There is no restriction on this, but it's not clear that any -// other form makes any sense. We get here for cases such as: -// -// new (std::align_val_t{N}) X(int) -// -// (which should presumably be valid only if N is a multiple of -// alignof(int), and in any case can't be deallocated unless N is -// alignof(X) and X has new-extended alignment). -if (PlacementArgs != 1 || !E->getPlacementArg(0)->getType()->isNothrowT()) - return this->emitInvalid(E); - -if (!this->discard(E->getPlacementArg(0))) - return false; -IsNoThrow = true; - } - - const Descriptor *Desc; - if (ElemT) { -if (E->isArray()) - Desc = nullptr; // We're not going to use it in this case. -else - Desc = P.createDescriptor(E, *ElemT, Descriptor::InlineDescMD, -/*IsConst=*/false, /*IsTemporary=*/false, -/*IsMutable=*/false); - } else { -Desc = P.createDescriptor( -E, ElementType.getTypePtr(), -E->isArray() ? std::nullopt : Descriptor::InlineDescMD, -/*IsConst=*/false, /*IsTemporary=*/false, /*IsMutable=*/false, Init); - } - - if (E->isArray()) { -std::optional ArraySizeExpr = E->getArraySize(); -if (!ArraySizeExpr) - return false; -PrimType SizeT = classifyPrim((*ArraySizeExpr)->getType()); - -if (!this->visit(*ArraySizeExpr)) - return false; - -if (ElemT) { - // N primitive elements. - if (!this->emitAllocN(SizeT, *ElemT, E, IsNoThrow, E)) -return false; -} else { - // N Composite elements. - if (!this->emitAllocCN(SizeT, Desc, IsNoThrow, E)) -return false; -} - -if (Init && !this->visitInitializer(Init)) - return false; - - } else { -// Allocate just one element. -if (!this->emitAlloc(Desc, E)) - return false; - -if (Init) { - if (ElemT) { -if (!this->visit(Init)) - return false; - -if (!this->emitInit(*ElemT, E)) - return false; - } else { -// Composite. -if (!this->visitInitializer(Init)) - return false; - } -} - } - - if (DiscardResult) -return this->emitPopPtr(E); - - return true; -} - -template -bool
[clang] ba3dcec - Revert "[clang][Interp] Fix a build failure on Windows"
Author: Timm Bäder Date: 2024-07-14T21:17:39+02:00 New Revision: ba3dcec16b6bb955f2c65a3df157744069441d7f URL: https://github.com/llvm/llvm-project/commit/ba3dcec16b6bb955f2c65a3df157744069441d7f DIFF: https://github.com/llvm/llvm-project/commit/ba3dcec16b6bb955f2c65a3df157744069441d7f.diff LOG: Revert "[clang][Interp] Fix a build failure on Windows" This reverts commit 27f5c00c607e08b3cdf37f3bf9f4ccf156de2ab4. Added: Modified: clang/lib/AST/Interp/Interp.cpp Removed: diff --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp index 0ec77200c3a79..cafe2175f5cc4 100644 --- a/clang/lib/AST/Interp/Interp.cpp +++ b/clang/lib/AST/Interp/Interp.cpp @@ -715,8 +715,8 @@ bool CheckNewDeleteForms(InterpState , CodePtr OpPC, bool NewWasArray, if (D->isArray()) { QualType ElemQT = D->getType()->getPointeeType(); TypeToDiagnose = S.getCtx().getConstantArrayType( -ElemQT, APInt(64, static_cast(D->getNumElems()), false), -nullptr, ArraySizeModifier::Normal, 0); +ElemQT, APInt(64, D->getNumElems(), false), nullptr, +ArraySizeModifier::Normal, 0); } else TypeToDiagnose = D->getType()->getPointeeType(); ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 27f5c00 - [clang][Interp] Fix a build failure on Windows
Author: Timm Bäder Date: 2024-07-14T20:15:20+02:00 New Revision: 27f5c00c607e08b3cdf37f3bf9f4ccf156de2ab4 URL: https://github.com/llvm/llvm-project/commit/27f5c00c607e08b3cdf37f3bf9f4ccf156de2ab4 DIFF: https://github.com/llvm/llvm-project/commit/27f5c00c607e08b3cdf37f3bf9f4ccf156de2ab4.diff LOG: [clang][Interp] Fix a build failure on Windows The usual ambiguous APInt constructor: https://lab.llvm.org/buildbot/#/builders/141/builds/764 Added: Modified: clang/lib/AST/Interp/Interp.cpp Removed: diff --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp index cafe2175f5cc4..0ec77200c3a79 100644 --- a/clang/lib/AST/Interp/Interp.cpp +++ b/clang/lib/AST/Interp/Interp.cpp @@ -715,8 +715,8 @@ bool CheckNewDeleteForms(InterpState , CodePtr OpPC, bool NewWasArray, if (D->isArray()) { QualType ElemQT = D->getType()->getPointeeType(); TypeToDiagnose = S.getCtx().getConstantArrayType( -ElemQT, APInt(64, D->getNumElems(), false), nullptr, -ArraySizeModifier::Normal, 0); +ElemQT, APInt(64, static_cast(D->getNumElems()), false), +nullptr, ArraySizeModifier::Normal, 0); } else TypeToDiagnose = D->getType()->getPointeeType(); ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 3aae4ca - [clang][Interp] Improve InterpFrame::describe()
Author: Timm Bäder Date: 2024-07-14T18:20:51+02:00 New Revision: 3aae4caffa3134d4edd1811fd2c35cbc95eb7441 URL: https://github.com/llvm/llvm-project/commit/3aae4caffa3134d4edd1811fd2c35cbc95eb7441 DIFF: https://github.com/llvm/llvm-project/commit/3aae4caffa3134d4edd1811fd2c35cbc95eb7441.diff LOG: [clang][Interp] Improve InterpFrame::describe() Use getNameForDiagnostic(), like the CallStackFrame of the current interpreter. Added: Modified: clang/lib/AST/Interp/InterpFrame.cpp clang/test/AST/Interp/literals.cpp Removed: diff --git a/clang/lib/AST/Interp/InterpFrame.cpp b/clang/lib/AST/Interp/InterpFrame.cpp index b33f74dfe99f..383380f485e0 100644 --- a/clang/lib/AST/Interp/InterpFrame.cpp +++ b/clang/lib/AST/Interp/InterpFrame.cpp @@ -167,7 +167,10 @@ void InterpFrame::describe(llvm::raw_ostream ) const { print(OS, This, S.getCtx(), S.getCtx().getRecordType(M->getParent())); OS << "->"; } - OS << *F << "("; + + F->getNameForDiagnostic(OS, S.getCtx().getPrintingPolicy(), + /*Qualified=*/false); + OS << '('; unsigned Off = 0; Off += Func->hasRVO() ? primSize(PT_Ptr) : 0; diff --git a/clang/test/AST/Interp/literals.cpp b/clang/test/AST/Interp/literals.cpp index 93e7e8b52a45..af5bcb6d48ae 100644 --- a/clang/test/AST/Interp/literals.cpp +++ b/clang/test/AST/Interp/literals.cpp @@ -568,37 +568,27 @@ namespace IncDec { return 1; } static_assert(uninit(), ""); // both-error {{not an integral constant expression}} \ -// ref-note {{in call to 'uninit()'}} \ -// expected-note {{in call to 'uninit()'}} +// both-note {{in call to 'uninit()'}} static_assert(uninit(), ""); // both-error {{not an integral constant expression}} \ - // ref-note {{in call to 'uninit()'}} \ - // expected-note {{in call to 'uninit()'}} + // both-note {{in call to 'uninit()'}} static_assert(uninit(), ""); // both-error {{not an integral constant expression}} \ - // ref-note {{in call to 'uninit()'}} \ - // expected-note {{in call to 'uninit()'}} + // both-note {{in call to 'uninit()'}} static_assert(uninit(), ""); // both-error {{not an integral constant expression}} \ - // ref-note {{in call to 'uninit()'}} \ - // expected-note {{in call to 'uninit()'}} + // both-note {{in call to 'uninit()'}} static_assert(uninit(), ""); // both-error {{not an integral constant expression}} \ - // ref-note {{in call to 'uninit()'}} \ - // expected-note {{in call to 'uninit()'}} + // both-note {{in call to 'uninit()'}} static_assert(uninit(), ""); // both-error {{not an integral constant expression}} \ -// ref-note {{in call to 'uninit()'}} \ -// expected-note {{in call to 'uninit()'}} +// both-note {{in call to 'uninit()'}} static_assert(uninit(), ""); // both-error {{not an integral constant expression}} \ - // ref-note {{in call to 'uninit()'}} \ - // expected-note {{in call to 'uninit()'}} + // both-note {{in call to 'uninit()'}} static_assert(uninit(), ""); // both-error {{not an integral constant expression}} \ - // ref-note {{in call to 'uninit()'}} \ - // expected-note {{in call to 'uninit()'}} + // both-note {{in call to 'uninit()'}} static_assert(uninit(), ""); // both-error {{not an integral constant expression}} \ - // ref-note {{in call to 'uninit()'}} \ - // expected-note {{in call to 'uninit()'}} + // both-note {{in call to 'uninit()'}} static_assert(uninit(), ""); // both-error {{not an integral constant expression}} \ - // ref-note {{in call to
[clang] 33af112 - [clang][Interp] Fix modifying const objects in functions calls in ctors
Author: Timm Bäder Date: 2024-07-14T17:47:11+02:00 New Revision: 33af112f99fe956fb93fb2b797a141ee93956283 URL: https://github.com/llvm/llvm-project/commit/33af112f99fe956fb93fb2b797a141ee93956283 DIFF: https://github.com/llvm/llvm-project/commit/33af112f99fe956fb93fb2b797a141ee93956283.diff LOG: [clang][Interp] Fix modifying const objects in functions calls in ctors The current frame might not be a constructor for the object we're initializing, but a parent frame might. Added: Modified: clang/lib/AST/Interp/Interp.cpp clang/test/AST/Interp/records.cpp Removed: diff --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp index 0411fcad88ad0..70a470021e7f2 100644 --- a/clang/lib/AST/Interp/Interp.cpp +++ b/clang/lib/AST/Interp/Interp.cpp @@ -405,10 +405,16 @@ bool CheckConst(InterpState , CodePtr OpPC, const Pointer ) { // The This pointer is writable in constructors and destructors, // even if isConst() returns true. - if (const Function *Func = S.Current->getFunction(); - Func && (Func->isConstructor() || Func->isDestructor()) && - Ptr.block() == S.Current->getThis().block()) { -return true; + // TODO(perf): We could be hitting this code path quite a lot in complex + // constructors. Is there a better way to do this? + if (S.Current->getFunction()) { +for (const InterpFrame *Frame = S.Current; Frame; Frame = Frame->Caller) { + if (const Function *Func = Frame->getFunction(); + Func && (Func->isConstructor() || Func->isDestructor()) && + Ptr.block() == Frame->getThis().block()) { +return true; + } +} } if (!Ptr.isBlockPointer()) diff --git a/clang/test/AST/Interp/records.cpp b/clang/test/AST/Interp/records.cpp index 4b06fc7522d45..2fc88a0b1df6a 100644 --- a/clang/test/AST/Interp/records.cpp +++ b/clang/test/AST/Interp/records.cpp @@ -1512,3 +1512,28 @@ namespace OnePastEndAndBack { constexpr const Base *d = c - 1; static_assert(d == , ""); } + +namespace BitSet { + class Bitset { +unsigned Bit = 0; + + public: +constexpr Bitset() { + int Init[2] = {1,2}; + for (auto I : Init) +set(I); +} +constexpr void set(unsigned I) { + this->Bit++; + this->Bit = 1u << 1; +} + }; + + struct ArchInfo { +Bitset DefaultExts; + }; + + constexpr ArchInfo ARMV8A = { +Bitset() + }; +} ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 181e4c6 - [clang][Interp] Check for non-primitive types in unary operators
Author: Timm Bäder Date: 2024-07-14T10:47:51+02:00 New Revision: 181e4c6291c94a38c0ee89d2128f8d70b15d2d23 URL: https://github.com/llvm/llvm-project/commit/181e4c6291c94a38c0ee89d2128f8d70b15d2d23 DIFF: https://github.com/llvm/llvm-project/commit/181e4c6291c94a38c0ee89d2128f8d70b15d2d23.diff LOG: [clang][Interp] Check for non-primitive types in unary operators For invalid cases (non-vector/complex/...), this should only happen in error cases such as the attached test case. Added: Modified: clang/lib/AST/Interp/Compiler.cpp clang/test/AST/Interp/literals.cpp Removed: diff --git a/clang/lib/AST/Interp/Compiler.cpp b/clang/lib/AST/Interp/Compiler.cpp index c58eb2eaa477..30dc7f5e4840 100644 --- a/clang/lib/AST/Interp/Compiler.cpp +++ b/clang/lib/AST/Interp/Compiler.cpp @@ -4706,6 +4706,8 @@ bool Compiler::VisitUnaryOperator(const UnaryOperator *E) { case UO_PostInc: { // x++ if (!Ctx.getLangOpts().CPlusPlus14) return this->emitInvalid(E); +if (!T) + return this->emitError(E); if (!this->visit(SubExpr)) return false; @@ -4727,6 +4729,8 @@ bool Compiler::VisitUnaryOperator(const UnaryOperator *E) { case UO_PostDec: { // x-- if (!Ctx.getLangOpts().CPlusPlus14) return this->emitInvalid(E); +if (!T) + return this->emitError(E); if (!this->visit(SubExpr)) return false; @@ -4748,6 +4752,8 @@ bool Compiler::VisitUnaryOperator(const UnaryOperator *E) { case UO_PreInc: { // ++x if (!Ctx.getLangOpts().CPlusPlus14) return this->emitInvalid(E); +if (!T) + return this->emitError(E); if (!this->visit(SubExpr)) return false; @@ -4795,6 +4801,8 @@ bool Compiler::VisitUnaryOperator(const UnaryOperator *E) { case UO_PreDec: { // --x if (!Ctx.getLangOpts().CPlusPlus14) return this->emitInvalid(E); +if (!T) + return this->emitError(E); if (!this->visit(SubExpr)) return false; @@ -4840,6 +4848,9 @@ bool Compiler::VisitUnaryOperator(const UnaryOperator *E) { return E->isGLValue() || this->emitLoadPop(*T, E); } case UO_LNot: // !x +if (!T) + return this->emitError(E); + if (DiscardResult) return this->discard(SubExpr); @@ -4853,10 +4864,16 @@ bool Compiler::VisitUnaryOperator(const UnaryOperator *E) { return this->emitCast(PT_Bool, ET, E); return true; case UO_Minus: // -x +if (!T) + return this->emitError(E); + if (!this->visit(SubExpr)) return false; return DiscardResult ? this->emitPop(*T, E) : this->emitNeg(*T, E); case UO_Plus:// +x +if (!T) + return this->emitError(E); + if (!this->visit(SubExpr)) // noop return false; return DiscardResult ? this->emitPop(*T, E) : true; @@ -4873,6 +4890,9 @@ bool Compiler::VisitUnaryOperator(const UnaryOperator *E) { return this->discard(SubExpr); return this->visit(SubExpr); case UO_Not: // ~x +if (!T) + return this->emitError(E); + if (!this->visit(SubExpr)) return false; return DiscardResult ? this->emitPop(*T, E) : this->emitComp(*T, E); diff --git a/clang/test/AST/Interp/literals.cpp b/clang/test/AST/Interp/literals.cpp index 1f2755e710e3..93e7e8b52a45 100644 --- a/clang/test/AST/Interp/literals.cpp +++ b/clang/test/AST/Interp/literals.cpp @@ -1290,3 +1290,13 @@ namespace NTTP { return size(Chars); } } + +#if __cplusplus >= 201402L +namespace UnaryOpError { + constexpr int foo() { +int f = 0; +++g; // both-error {{use of undeclared identifier 'g'}} +return f; + } +} +#endif ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 9d88990 - [clang][Interp][NFC] Remove visit{Global,Local,This}Initializer
Author: Timm Bäder Date: 2024-07-14T10:47:50+02:00 New Revision: 9d889906720c1a4fbdb3b8aaacfeebd62f235b87 URL: https://github.com/llvm/llvm-project/commit/9d889906720c1a4fbdb3b8aaacfeebd62f235b87 DIFF: https://github.com/llvm/llvm-project/commit/9d889906720c1a4fbdb3b8aaacfeebd62f235b87.diff LOG: [clang][Interp][NFC] Remove visit{Global,Local,This}Initializer They were only called once, or not at all. Added: Modified: clang/lib/AST/Interp/Compiler.cpp clang/lib/AST/Interp/Compiler.h Removed: diff --git a/clang/lib/AST/Interp/Compiler.cpp b/clang/lib/AST/Interp/Compiler.cpp index 0b2a38d02b4a..c58eb2eaa477 100644 --- a/clang/lib/AST/Interp/Compiler.cpp +++ b/clang/lib/AST/Interp/Compiler.cpp @@ -3583,7 +3583,19 @@ VarCreationState Compiler::visitVarDecl(const VarDecl *VD, bool Topleve return checkDecl() && this->emitInitGlobal(*VarT, GlobalIndex, VD); } - return checkDecl() && this->visitGlobalInitializer(Init, GlobalIndex); + if (!checkDecl()) +return false; + + if (!this->emitGetPtrGlobal(GlobalIndex, Init)) +return false; + + if (!visitInitializer(Init)) +return false; + + if (!this->emitFinishInit(Init)) +return false; + + return this->emitPopPtr(Init); }; // We've already seen and initialized this global. @@ -3627,7 +3639,16 @@ VarCreationState Compiler::visitVarDecl(const VarDecl *VD, bool Topleve if (!Init) return true; -return this->visitLocalInitializer(Init, *Offset); +if (!this->emitGetPtrLocal(*Offset, Init)) + return false; + +if (!visitInitializer(Init)) + return false; + +if (!this->emitFinishInit(Init)) + return false; + +return this->emitPopPtr(Init); } return false; } diff --git a/clang/lib/AST/Interp/Compiler.h b/clang/lib/AST/Interp/Compiler.h index de873c7e6825..23e7afd767e8 100644 --- a/clang/lib/AST/Interp/Compiler.h +++ b/clang/lib/AST/Interp/Compiler.h @@ -278,45 +278,6 @@ class Compiler : public ConstStmtVisitor, bool>, /// Visits an expression and converts it to a boolean. bool visitBool(const Expr *E); - /// Visits an initializer for a local. - bool visitLocalInitializer(const Expr *Init, unsigned I) { -if (!this->emitGetPtrLocal(I, Init)) - return false; - -if (!visitInitializer(Init)) - return false; - -if (!this->emitFinishInit(Init)) - return false; - -return this->emitPopPtr(Init); - } - - /// Visits an initializer for a global. - bool visitGlobalInitializer(const Expr *Init, unsigned I) { -if (!this->emitGetPtrGlobal(I, Init)) - return false; - -if (!visitInitializer(Init)) - return false; - -if (!this->emitFinishInit(Init)) - return false; - -return this->emitPopPtr(Init); - } - - /// Visits a delegated initializer. - bool visitThisInitializer(const Expr *I) { -if (!this->emitThis(I)) - return false; - -if (!visitInitializer(I)) - return false; - -return this->emitFinishInitPop(I); - } - bool visitInitList(ArrayRef Inits, const Expr *ArrayFiller, const Expr *E); bool visitArrayElemInit(unsigned ElemIndex, const Expr *Init); ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 92fe391 - [clang][Interp] Reject non-pointer typed dummies
Author: Timm Bäder Date: 2024-07-14T07:32:42+02:00 New Revision: 92fe3911c3e0f5e76cf60c8b3203002e6e6aa047 URL: https://github.com/llvm/llvm-project/commit/92fe3911c3e0f5e76cf60c8b3203002e6e6aa047 DIFF: https://github.com/llvm/llvm-project/commit/92fe3911c3e0f5e76cf60c8b3203002e6e6aa047.diff LOG: [clang][Interp] Reject non-pointer typed dummies This happens a lot for NonTypeTemplateParm decls. Added: Modified: clang/lib/AST/Interp/Compiler.cpp clang/test/AST/Interp/literals.cpp Removed: diff --git a/clang/lib/AST/Interp/Compiler.cpp b/clang/lib/AST/Interp/Compiler.cpp index 209fb54ecdcb..0b2a38d02b4a 100644 --- a/clang/lib/AST/Interp/Compiler.cpp +++ b/clang/lib/AST/Interp/Compiler.cpp @@ -5094,9 +5094,10 @@ bool Compiler::visitDeclRef(const ValueDecl *D, const Expr *E) { if (E->getType()->isVoidType()) return true; // Convert the dummy pointer to another pointer type if we have to. -if (PrimType PT = classifyPrim(E); PT != PT_Ptr && isPtrType(PT)) { - if (!this->emitDecayPtr(PT_Ptr, PT, E)) -return false; +if (PrimType PT = classifyPrim(E); PT != PT_Ptr) { + if (isPtrType(PT)) +return this->emitDecayPtr(PT_Ptr, PT, E); + return false; } return true; } diff --git a/clang/test/AST/Interp/literals.cpp b/clang/test/AST/Interp/literals.cpp index 630d9b53cca2..1f2755e710e3 100644 --- a/clang/test/AST/Interp/literals.cpp +++ b/clang/test/AST/Interp/literals.cpp @@ -1276,3 +1276,17 @@ namespace ComparisonAgainstOnePastEnd { static_assert( + 1 == + 1, ""); // both-error {{static assertion failed}} }; + +namespace NTTP { + template +constexpr unsigned +size(const _Tp (&)[_Nm]) noexcept +{ return _Nm; } + + template + static int write_padding() { +static const char Chars[] = {C}; + +return size(Chars); + } +} ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 77d2283 - [clang][Interp] Diagnose shift overflows
Author: Timm Bäder Date: 2024-07-14T07:28:02+02:00 New Revision: 77d2283e5824fb5bf375df65559a88a68159594b URL: https://github.com/llvm/llvm-project/commit/77d2283e5824fb5bf375df65559a88a68159594b DIFF: https://github.com/llvm/llvm-project/commit/77d2283e5824fb5bf375df65559a88a68159594b.diff LOG: [clang][Interp] Diagnose shift overflows Added: Modified: clang/lib/AST/Interp/Interp.h clang/test/AST/Interp/shifts.cpp Removed: diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h index 60e1d78f7405..c7d8604c7dc2 100644 --- a/clang/lib/AST/Interp/Interp.h +++ b/clang/lib/AST/Interp/Interp.h @@ -147,7 +147,7 @@ bool CheckShift(InterpState , CodePtr OpPC, const LT , const RT , const APSInt Val = RHS.toAPSInt(); QualType Ty = E->getType(); S.CCEDiag(E, diag::note_constexpr_large_shift) << Val << Ty << Bits; -return true; // We will do the shift anyway but fix up the shift amount. +return !(S.getEvalStatus().Diag && !S.getEvalStatus().Diag->empty() && S.getLangOpts().CPlusPlus11); } if (LHS.isSigned() && !S.getLangOpts().CPlusPlus20) { diff --git a/clang/test/AST/Interp/shifts.cpp b/clang/test/AST/Interp/shifts.cpp index c5abdb7dd8a1..360b87b7ee04 100644 --- a/clang/test/AST/Interp/shifts.cpp +++ b/clang/test/AST/Interp/shifts.cpp @@ -200,13 +200,14 @@ namespace LongInt { }; enum shiftof { -X = (1<<-29) // all-error {{expression is not an integral constant expression}} \ - // all-note {{negative shift count -29}} -}; +X = (1<<-29), // all-error {{expression is not an integral constant expression}} \ + // all-note {{negative shift count -29}} + +X2 = (-1<<29), // cxx17-error {{expression is not an integral constant expression}} \ + // cxx17-note {{left shift of negative value -1}} \ + // ref-cxx17-error {{expression is not an integral constant expression}} \ + // ref-cxx17-note {{left shift of negative value -1}} -enum shiftof2 { -X2 = (-1<<29) // cxx17-error {{expression is not an integral constant expression}} \ - // cxx17-note {{left shift of negative value -1}} \ - // ref-cxx17-error {{expression is not an integral constant expression}} \ - // ref-cxx17-note {{left shift of negative value -1}} +X3 = (1<<32) // all-error {{expression is not an integral constant expression}} \ + // all-note {{shift count 32 >= width of type 'int'}} }; ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] ed304b6 - [clang][Interp] Diagnose left shifts of negative values
Author: Timm Bäder Date: 2024-07-14T07:28:02+02:00 New Revision: ed304b6790ba0391211bffe66856b00d0a949670 URL: https://github.com/llvm/llvm-project/commit/ed304b6790ba0391211bffe66856b00d0a949670 DIFF: https://github.com/llvm/llvm-project/commit/ed304b6790ba0391211bffe66856b00d0a949670.diff LOG: [clang][Interp] Diagnose left shifts of negative values Added: Modified: clang/lib/AST/Interp/Interp.h clang/test/AST/Interp/shifts.cpp Removed: diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h index 8502b7ca136e..60e1d78f7405 100644 --- a/clang/lib/AST/Interp/Interp.h +++ b/clang/lib/AST/Interp/Interp.h @@ -2234,6 +2234,20 @@ inline bool DoShift(InterpState , CodePtr OpPC, LT , RT ) { : ShiftDir::Left > (S, OpPC, LHS, RHS); } + if constexpr (Dir == ShiftDir::Left) { +if (LHS.isNegative() && !S.getLangOpts().CPlusPlus20) { + // C++11 [expr.shift]p2: A signed left shift must have a non-negative + // operand, and must not overflow the corresponding unsigned type. + // C++2a [expr.shift]p2: E1 << E2 is the unique value congruent to + // E1 x 2^E2 module 2^N. + const SourceInfo = S.Current->getSource(OpPC); + S.CCEDiag(Loc, diag::note_constexpr_lshift_of_negative) << LHS.toAPSInt(); + if (S.getLangOpts().CPlusPlus11 && S.getEvalStatus().Diag && + !S.getEvalStatus().Diag->empty()) +return false; +} + } + if (!CheckShift(S, OpPC, LHS, RHS, Bits)) return false; diff --git a/clang/test/AST/Interp/shifts.cpp b/clang/test/AST/Interp/shifts.cpp index ce17fabc7833..c5abdb7dd8a1 100644 --- a/clang/test/AST/Interp/shifts.cpp +++ b/clang/test/AST/Interp/shifts.cpp @@ -203,3 +203,10 @@ enum shiftof { X = (1<<-29) // all-error {{expression is not an integral constant expression}} \ // all-note {{negative shift count -29}} }; + +enum shiftof2 { +X2 = (-1<<29) // cxx17-error {{expression is not an integral constant expression}} \ + // cxx17-note {{left shift of negative value -1}} \ + // ref-cxx17-error {{expression is not an integral constant expression}} \ + // ref-cxx17-note {{left shift of negative value -1}} +}; ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] de02994 - [clang][Interp] Handle negative shift amounts correctly
Author: Timm Bäder Date: 2024-07-14T07:28:02+02:00 New Revision: de029943cc5ad0028f16e6ecaffa03e32ffd1a6f URL: https://github.com/llvm/llvm-project/commit/de029943cc5ad0028f16e6ecaffa03e32ffd1a6f DIFF: https://github.com/llvm/llvm-project/commit/de029943cc5ad0028f16e6ecaffa03e32ffd1a6f.diff LOG: [clang][Interp] Handle negative shift amounts correctly We need to invert them and use the opposite shift. Added: Modified: clang/lib/AST/Interp/Interp.h clang/test/AST/Interp/shifts.cpp clang/test/Sema/shift-count-negative.c Removed: diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h index 95f89990a7a18..8502b7ca136ee 100644 --- a/clang/lib/AST/Interp/Interp.h +++ b/clang/lib/AST/Interp/Interp.h @@ -2209,13 +2209,10 @@ inline bool RVOPtr(InterpState , CodePtr OpPC) { //===--===// // Shr, Shl //===--===// +enum class ShiftDir { Left, Right }; -template -inline bool Shr(InterpState , CodePtr OpPC) { - using LT = typename PrimConv::T; - using RT = typename PrimConv::T; - auto RHS = S.Stk.pop(); - const auto = S.Stk.pop(); +template +inline bool DoShift(InterpState , CodePtr OpPC, LT , RT ) { const unsigned Bits = LHS.bitWidth(); // OpenCL 6.3j: shift values are effectively % word size of LHS. @@ -2223,6 +2220,20 @@ inline bool Shr(InterpState , CodePtr OpPC) { RT::bitAnd(RHS, RT::from(LHS.bitWidth() - 1, RHS.bitWidth()), RHS.bitWidth(), ); + if (RHS.isNegative()) { +// During constant-folding, a negative shift is an opposite shift. Such a +// shift is not a constant expression. +const SourceInfo = S.Current->getSource(OpPC); +S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt(); +if (S.getLangOpts().CPlusPlus11 && S.getEvalStatus().Diag && +!S.getEvalStatus().Diag->empty()) + return false; +RHS = -RHS; +return DoShift < LT, RT, + Dir == ShiftDir::Left ? ShiftDir::Right + : ShiftDir::Left > (S, OpPC, LHS, RHS); + } + if (!CheckShift(S, OpPC, LHS, RHS, Bits)) return false; @@ -2230,45 +2241,44 @@ inline bool Shr(InterpState , CodePtr OpPC) { // it has already been diagnosed by CheckShift() above, // but we still need to handle it. typename LT::AsUnsigned R; - if (RHS > RT::from(Bits - 1, RHS.bitWidth())) -LT::AsUnsigned::shiftRight(LT::AsUnsigned::from(LHS), - LT::AsUnsigned::from(Bits - 1), Bits, ); - else -LT::AsUnsigned::shiftRight(LT::AsUnsigned::from(LHS), - LT::AsUnsigned::from(RHS, Bits), Bits, ); + if constexpr (Dir == ShiftDir::Left) { +if (RHS > RT::from(Bits - 1, RHS.bitWidth())) + LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS), +LT::AsUnsigned::from(Bits - 1), Bits, ); +else + LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS), +LT::AsUnsigned::from(RHS, Bits), Bits, ); + } else { +if (RHS > RT::from(Bits - 1, RHS.bitWidth())) + LT::AsUnsigned::shiftRight(LT::AsUnsigned::from(LHS), + LT::AsUnsigned::from(Bits - 1), Bits, ); +else + LT::AsUnsigned::shiftRight(LT::AsUnsigned::from(LHS), + LT::AsUnsigned::from(RHS, Bits), Bits, ); + } + S.Stk.push(LT::from(R)); return true; } template -inline bool Shl(InterpState , CodePtr OpPC) { +inline bool Shr(InterpState , CodePtr OpPC) { using LT = typename PrimConv::T; using RT = typename PrimConv::T; auto RHS = S.Stk.pop(); - const auto = S.Stk.pop(); - const unsigned Bits = LHS.bitWidth(); - - // OpenCL 6.3j: shift values are effectively % word size of LHS. - if (S.getLangOpts().OpenCL) -RT::bitAnd(RHS, RT::from(LHS.bitWidth() - 1, RHS.bitWidth()), - RHS.bitWidth(), ); + auto LHS = S.Stk.pop(); - if (!CheckShift(S, OpPC, LHS, RHS, Bits)) -return false; + return DoShift(S, OpPC, LHS, RHS); +} - // Limit the shift amount to Bits - 1. If this happened, - // it has already been diagnosed by CheckShift() above, - // but we still need to handle it. - typename LT::AsUnsigned R; - if (RHS > RT::from(Bits - 1, RHS.bitWidth())) -LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS), - LT::AsUnsigned::from(Bits - 1), Bits, ); - else -LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS), - LT::AsUnsigned::from(RHS, Bits), Bits, ); +template +inline bool Shl(InterpState , CodePtr OpPC) { + using LT = typename PrimConv::T; + using RT = typename PrimConv::T; + auto RHS = S.Stk.pop(); + auto LHS = S.Stk.pop(); - S.Stk.push(LT::from(R)); - return true; + return DoShift(S, OpPC,
[clang] 7645823 - [clang][Interp] Don't require StmtExpr result to be an expression
Author: Timm Bäder Date: 2024-07-14T07:28:02+02:00 New Revision: 7645823564a34db84f0da53e53e38eb0ceb429ec URL: https://github.com/llvm/llvm-project/commit/7645823564a34db84f0da53e53e38eb0ceb429ec DIFF: https://github.com/llvm/llvm-project/commit/7645823564a34db84f0da53e53e38eb0ceb429ec.diff LOG: [clang][Interp] Don't require StmtExpr result to be an expression It can be a statement containing an expression. Added: Modified: clang/lib/AST/Interp/Compiler.cpp clang/test/CodeGenCXX/cxx1z-constexpr-if.cpp Removed: diff --git a/clang/lib/AST/Interp/Compiler.cpp b/clang/lib/AST/Interp/Compiler.cpp index 48e7519f8f89d..209fb54ecdcb5 100644 --- a/clang/lib/AST/Interp/Compiler.cpp +++ b/clang/lib/AST/Interp/Compiler.cpp @@ -3073,13 +3073,13 @@ bool Compiler::VisitStmtExpr(const StmtExpr *E) { } assert(S == Result); -// This better produces a value (i.e. is an expression). if (const Expr *ResultExpr = dyn_cast(S)) { if (DiscardResult) return this->discard(ResultExpr); return this->delegate(ResultExpr); } -return false; + +return this->visitStmt(S); } return BS.destroyLocals(); diff --git a/clang/test/CodeGenCXX/cxx1z-constexpr-if.cpp b/clang/test/CodeGenCXX/cxx1z-constexpr-if.cpp index d14e36406a45e..5a11afb8dec40 100644 --- a/clang/test/CodeGenCXX/cxx1z-constexpr-if.cpp +++ b/clang/test/CodeGenCXX/cxx1z-constexpr-if.cpp @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -std=c++1z %s -emit-llvm -fblocks -triple x86_64-apple-darwin10 -o - | FileCheck %s --implicit-check-not=should_not_be_used +// RUN: %clang_cc1 -std=c++1z %s -emit-llvm -fblocks -triple x86_64-apple-darwin10 -o - -fexperimental-new-constant-interpreter | FileCheck %s --implicit-check-not=should_not_be_used void should_be_used_1(); void should_be_used_2(); ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 6b380a8 - [clang][Interp] Fix integral overflow reporting
Author: Timm Bäder Date: 2024-07-14T07:28:01+02:00 New Revision: 6b380a810ea57fdb36ef911756bd2e1cbf2fbac0 URL: https://github.com/llvm/llvm-project/commit/6b380a810ea57fdb36ef911756bd2e1cbf2fbac0 DIFF: https://github.com/llvm/llvm-project/commit/6b380a810ea57fdb36ef911756bd2e1cbf2fbac0.diff LOG: [clang][Interp] Fix integral overflow reporting We need to always do the CCEDiag, the report() is optional. Added: Modified: clang/lib/AST/Interp/Interp.h clang/test/SemaCXX/enum.cpp Removed: diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h index 1df8d65c80445..95f89990a7a18 100644 --- a/clang/lib/AST/Interp/Interp.h +++ b/clang/lib/AST/Interp/Interp.h @@ -302,15 +302,16 @@ bool AddSubMulHelper(InterpState , CodePtr OpPC, unsigned Bits, const T , auto Loc = E->getExprLoc(); S.report(Loc, diag::warn_integer_constant_overflow) << Trunc << Type << E->getSourceRange(); -return true; - } else { -S.CCEDiag(E, diag::note_constexpr_overflow) << Value << Type; -if (!S.noteUndefinedBehavior()) { - S.Stk.pop(); - return false; -} -return true; } + + S.CCEDiag(E, diag::note_constexpr_overflow) << Value << Type; + + if (!S.noteUndefinedBehavior()) { +S.Stk.pop(); +return false; + } + + return true; } template ::T> diff --git a/clang/test/SemaCXX/enum.cpp b/clang/test/SemaCXX/enum.cpp index 7d4a05083b9cd..739d35ec4a06b 100644 --- a/clang/test/SemaCXX/enum.cpp +++ b/clang/test/SemaCXX/enum.cpp @@ -1,5 +1,9 @@ // RUN: %clang_cc1 -fsyntax-only -pedantic -std=c++98 -verify -triple x86_64-apple-darwin %s // RUN: %clang_cc1 -fsyntax-only -pedantic -std=c++11 -verify -triple x86_64-apple-darwin %s + +// RUN: %clang_cc1 -fsyntax-only -pedantic -std=c++98 -verify -triple x86_64-apple-darwin %s -fexperimental-new-constant-interpreter +// RUN: %clang_cc1 -fsyntax-only -pedantic -std=c++11 -verify -triple x86_64-apple-darwin %s -fexperimental-new-constant-interpreter + enum E { // expected-note{{previous definition is here}} Val1, Val2 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] b22adf0 - [clang][Interp] Clear pointers pointing to dead blocks
Author: Timm Bäder Date: 2024-07-13T15:55:55+02:00 New Revision: b22adf02a2d2cc290d618fe47bec5aeec47ab992 URL: https://github.com/llvm/llvm-project/commit/b22adf02a2d2cc290d618fe47bec5aeec47ab992 DIFF: https://github.com/llvm/llvm-project/commit/b22adf02a2d2cc290d618fe47bec5aeec47ab992.diff LOG: [clang][Interp] Clear pointers pointing to dead blocks before free()ing the dead blocks. Otherwise, we might end up with dangling Pointers to those dead blocks. Added: Modified: clang/lib/AST/Interp/InterpState.cpp clang/lib/AST/Interp/Pointer.h clang/test/AST/Interp/lifetimes.cpp Removed: diff --git a/clang/lib/AST/Interp/InterpState.cpp b/clang/lib/AST/Interp/InterpState.cpp index 550bc9f1a84b..a8538541f491 100644 --- a/clang/lib/AST/Interp/InterpState.cpp +++ b/clang/lib/AST/Interp/InterpState.cpp @@ -33,7 +33,15 @@ InterpState::~InterpState() { } } -void InterpState::cleanup() {} +void InterpState::cleanup() { + // As a last resort, make sure all pointers still pointing to a dead block + // don't point to it anymore. + for (DeadBlock *DB = DeadBlocks; DB; DB = DB->Next) { +for (Pointer *P = DB->B.Pointers; P; P = P->Next) { + P->PointeeStorage.BS.Pointee = nullptr; +} + } +} Frame *InterpState::getCurrentFrame() { if (Current && Current->Caller) diff --git a/clang/lib/AST/Interp/Pointer.h b/clang/lib/AST/Interp/Pointer.h index 3515f525a22f..6e9e8675306e 100644 --- a/clang/lib/AST/Interp/Pointer.h +++ b/clang/lib/AST/Interp/Pointer.h @@ -635,6 +635,7 @@ class Pointer { friend class Block; friend class DeadBlock; friend class MemberPointer; + friend class InterpState; friend struct InitMap; Pointer(Block *Pointee, unsigned Base, uint64_t Offset); diff --git a/clang/test/AST/Interp/lifetimes.cpp b/clang/test/AST/Interp/lifetimes.cpp index c544baba6178..d47533ab547b 100644 --- a/clang/test/AST/Interp/lifetimes.cpp +++ b/clang/test/AST/Interp/lifetimes.cpp @@ -1,6 +1,8 @@ // RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify=expected,both %s // RUN: %clang_cc1 -verify=ref,both %s +/// FIXME: Slight diff erence in diagnostic output here. + struct Foo { int a; }; @@ -20,3 +22,14 @@ static_assert(dead1() == 1, ""); // both-error {{not an integral constant expres // both-note {{in call to}} +struct S { + int & // both-note {{reference member declared here}} + int t; + constexpr S() : r(0), t(r) {} // both-error {{reference member 'r' binds to a temporary object whose lifetime would be shorter than the lifetime of the constructed object}} \ +// ref-note {{read of object outside its lifetime is not allowed in a constant expression}} \ +// expected-note {{temporary created here}} \ +// expected-note {{read of temporary whose lifetime has ended}} +}; +constexpr int k1 = S().t; // both-error {{must be initialized by a constant expression}} \ + // ref-note {{in call to}} \ + // expected-note {{in call to}} ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 66e6df2 - [clang][Interp] Fix one-past-end pointers going back into the block
Author: Timm Bäder Date: 2024-07-13T07:25:47+02:00 New Revision: 66e6df22b5a509c16e50364d72b1a40bacaea91a URL: https://github.com/llvm/llvm-project/commit/66e6df22b5a509c16e50364d72b1a40bacaea91a DIFF: https://github.com/llvm/llvm-project/commit/66e6df22b5a509c16e50364d72b1a40bacaea91a.diff LOG: [clang][Interp] Fix one-past-end pointers going back into the block Added: Modified: clang/lib/AST/Interp/Interp.h clang/test/AST/Interp/records.cpp Removed: diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h index 83c7e98c2dda0..1df8d65c80445 100644 --- a/clang/lib/AST/Interp/Interp.h +++ b/clang/lib/AST/Interp/Interp.h @@ -1844,6 +1844,15 @@ bool OffsetHelper(InterpState , CodePtr OpPC, const T , else Result = WideIndex - WideOffset; + // When the pointer is one-past-end, going back to index 0 is the only + // useful thing we can do. Any other index has been diagnosed before and + // we don't get here. + if (Result == 0 && Ptr.isOnePastEnd()) { +S.Stk.push(Ptr.asBlockPointer().Pointee, +Ptr.asBlockPointer().Base); +return true; + } + S.Stk.push(Ptr.atIndex(static_cast(Result))); return true; } diff --git a/clang/test/AST/Interp/records.cpp b/clang/test/AST/Interp/records.cpp index adc3799a20ce4..4b06fc7522d45 100644 --- a/clang/test/AST/Interp/records.cpp +++ b/clang/test/AST/Interp/records.cpp @@ -1500,3 +1500,15 @@ namespace LocalWithThisPtrInit { } static_assert(foo() == 2, ""); } + +namespace OnePastEndAndBack { + struct Base { +constexpr Base() {} +int n = 0; + }; + + constexpr Base a; + constexpr const Base *c = + 1; + constexpr const Base *d = c - 1; + static_assert(d == , ""); +} ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 634128b - [clang][Interp][NFC] Remove some unused includes
Author: Timm Bäder Date: 2024-07-13T07:25:47+02:00 New Revision: 634128be4610a4d85d92935109ed7761f0e06af1 URL: https://github.com/llvm/llvm-project/commit/634128be4610a4d85d92935109ed7761f0e06af1 DIFF: https://github.com/llvm/llvm-project/commit/634128be4610a4d85d92935109ed7761f0e06af1.diff LOG: [clang][Interp][NFC] Remove some unused includes Added: Modified: clang/lib/AST/Interp/Interp.h Removed: diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h index ac87901570ec..83c7e98c2dda 100644 --- a/clang/lib/AST/Interp/Interp.h +++ b/clang/lib/AST/Interp/Interp.h @@ -27,13 +27,9 @@ #include "Program.h" #include "State.h" #include "clang/AST/ASTContext.h" -#include "clang/AST/ASTDiagnostic.h" -#include "clang/AST/CXXInheritance.h" #include "clang/AST/Expr.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APSInt.h" -#include "llvm/Support/Endian.h" -#include #include namespace clang { ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 7d59020 - [clang][Interp][NFC] Remove unused include
Author: Timm Bäder Date: 2024-07-13T07:25:47+02:00 New Revision: 7d5902025d20e00b1865d02dfe514fb35259ae2a URL: https://github.com/llvm/llvm-project/commit/7d5902025d20e00b1865d02dfe514fb35259ae2a DIFF: https://github.com/llvm/llvm-project/commit/7d5902025d20e00b1865d02dfe514fb35259ae2a.diff LOG: [clang][Interp][NFC] Remove unused include Added: Modified: clang/lib/AST/Interp/Pointer.h Removed: diff --git a/clang/lib/AST/Interp/Pointer.h b/clang/lib/AST/Interp/Pointer.h index 0ebac1ba04551..3515f525a22fe 100644 --- a/clang/lib/AST/Interp/Pointer.h +++ b/clang/lib/AST/Interp/Pointer.h @@ -19,7 +19,6 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/Expr.h" -#include "llvm/ADT/PointerUnion.h" #include "llvm/Support/raw_ostream.h" namespace clang { ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] c784abf - [clang][Interp] Delay compiling functions that don't have a body yet
Author: Timm Bäder Date: 2024-07-12T17:32:39+02:00 New Revision: c784abf2007a98c5fea64a84b56fa21974983d90 URL: https://github.com/llvm/llvm-project/commit/c784abf2007a98c5fea64a84b56fa21974983d90 DIFF: https://github.com/llvm/llvm-project/commit/c784abf2007a98c5fea64a84b56fa21974983d90.diff LOG: [clang][Interp] Delay compiling functions that don't have a body yet Sometimes, isDefined() returns true, even though the function doesn't have a body yet, but will have one later. This is for example the case when referring to a class member function via a member pointer before the member function has been fully parsed. Reject them at first and compile them later. Added: Modified: clang/lib/AST/Interp/ByteCodeEmitter.cpp clang/test/AST/Interp/memberpointers.cpp Removed: diff --git a/clang/lib/AST/Interp/ByteCodeEmitter.cpp b/clang/lib/AST/Interp/ByteCodeEmitter.cpp index 918cd66c9a976..ae777d555e916 100644 --- a/clang/lib/AST/Interp/ByteCodeEmitter.cpp +++ b/clang/lib/AST/Interp/ByteCodeEmitter.cpp @@ -147,7 +147,8 @@ Function *ByteCodeEmitter::compileFunc(const FunctionDecl *FuncDecl) { assert(Func); // For not-yet-defined functions, we only create a Function instance and // compile their body later. - if (!FuncDecl->isDefined()) { + if (!FuncDecl->isDefined() || + (FuncDecl->willHaveBody() && !FuncDecl->hasBody())) { Func->setDefined(false); return Func; } diff --git a/clang/test/AST/Interp/memberpointers.cpp b/clang/test/AST/Interp/memberpointers.cpp index 178d2e23f1266..f38e948638631 100644 --- a/clang/test/AST/Interp/memberpointers.cpp +++ b/clang/test/AST/Interp/memberpointers.cpp @@ -1,5 +1,7 @@ // RUN: %clang_cc1 -std=c++14 -fexperimental-new-constant-interpreter -verify=expected,both %s +// RUN: %clang_cc1 -std=c++23 -fexperimental-new-constant-interpreter -verify=expected,both %s // RUN: %clang_cc1 -std=c++14 -verify=ref,both %s +// RUN: %clang_cc1 -std=c++23 -verify=ref,both %s namespace MemberPointers { struct A { ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 840c7c6 - [clang][Interp] Fix Pointer::expand() checking for metadata size
Author: Timm Bäder Date: 2024-07-12T17:18:26+02:00 New Revision: 840c7c6e1fba52748e3ceccd2842e5d96f658f2e URL: https://github.com/llvm/llvm-project/commit/840c7c6e1fba52748e3ceccd2842e5d96f658f2e DIFF: https://github.com/llvm/llvm-project/commit/840c7c6e1fba52748e3ceccd2842e5d96f658f2e.diff LOG: [clang][Interp] Fix Pointer::expand() checking for metadata size The == 0 check here was used before blocks had metadata, but doesn't work anymore today. Added: Modified: clang/lib/AST/Interp/Pointer.h clang/test/AST/Interp/arrays.cpp Removed: diff --git a/clang/lib/AST/Interp/Pointer.h b/clang/lib/AST/Interp/Pointer.h index 7785da1d68f63..0ebac1ba04551 100644 --- a/clang/lib/AST/Interp/Pointer.h +++ b/clang/lib/AST/Interp/Pointer.h @@ -211,6 +211,9 @@ class Pointer { /// Expands a pointer to the containing array, undoing narrowing. [[nodiscard]] Pointer expand() const { +assert(isBlockPointer()); +Block *Pointee = asBlockPointer().Pointee; + if (isElementPastEnd()) { // Revert to an outer one-past-end pointer. unsigned Adjust; @@ -218,7 +221,7 @@ class Pointer { Adjust = sizeof(InitMapPtr); else Adjust = sizeof(InlineDescriptor); - return Pointer(asBlockPointer().Pointee, asBlockPointer().Base, + return Pointer(Pointee, asBlockPointer().Base, asBlockPointer().Base + getSize() + Adjust); } @@ -228,15 +231,17 @@ class Pointer { // If at base, point to an array of base types. if (isRoot()) - return Pointer(asBlockPointer().Pointee, RootPtrMark, 0); + return Pointer(Pointee, RootPtrMark, 0); // Step into the containing array, if inside one. unsigned Next = asBlockPointer().Base - getInlineDesc()->Offset; const Descriptor *Desc = -Next == 0 ? getDeclDesc() : getDescriptor(Next)->Desc; +(Next == Pointee->getDescriptor()->getMetadataSize()) +? getDeclDesc() +: getDescriptor(Next)->Desc; if (!Desc->IsArray) return *this; -return Pointer(asBlockPointer().Pointee, Next, Offset); +return Pointer(Pointee, Next, Offset); } /// Checks if the pointer is null. diff --git a/clang/test/AST/Interp/arrays.cpp b/clang/test/AST/Interp/arrays.cpp index 933437c3401c4..612bd552aed48 100644 --- a/clang/test/AST/Interp/arrays.cpp +++ b/clang/test/AST/Interp/arrays.cpp @@ -625,3 +625,10 @@ constexpr int *get2() { return same_entity_2; } static_assert(get2() == same_entity_2, "failed to find previous decl"); + +constexpr int zs[2][2][2][2] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }; +constexpr int fail(const int ) { + return ()[64]; // both-note {{cannot refer to element 64 of array of 2 elements}} +} +static_assert(fail(*(&(&(*(*&([2] - 1)[0] + 2 - 2))[2])[-1][2] - 2)) == 11, ""); // both-error {{not an integral constant expression}} \ + // both-note {{in call to}} ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 1752b7b - [clang][Interp][NFC] Apply some clang-tidy suggestions
Author: Timm Bäder Date: 2024-07-12T17:18:26+02:00 New Revision: 1752b7bc521ae878355a1c9e48644b0ad320dbe5 URL: https://github.com/llvm/llvm-project/commit/1752b7bc521ae878355a1c9e48644b0ad320dbe5 DIFF: https://github.com/llvm/llvm-project/commit/1752b7bc521ae878355a1c9e48644b0ad320dbe5.diff LOG: [clang][Interp][NFC] Apply some clang-tidy suggestions Remove unused includes and don't use an else after a return. Added: Modified: clang/lib/AST/Interp/InterpFrame.h Removed: diff --git a/clang/lib/AST/Interp/InterpFrame.h b/clang/lib/AST/Interp/InterpFrame.h index 1f80a0a5d2c49..4a312a71bcf1c 100644 --- a/clang/lib/AST/Interp/InterpFrame.h +++ b/clang/lib/AST/Interp/InterpFrame.h @@ -15,8 +15,6 @@ #include "Frame.h" #include "Program.h" -#include -#include namespace clang { namespace interp { @@ -85,11 +83,9 @@ class InterpFrame final : public Frame { /// Returns the value of an argument. template const T (unsigned Offset) const { auto Pt = Params.find(Offset); -if (Pt == Params.end()) { +if (Pt == Params.end()) return stackRef(Offset); -} else { - return Pointer(reinterpret_cast(Pt->second.get())).deref(); -} +return Pointer(reinterpret_cast(Pt->second.get())).deref(); } /// Mutates a local copy of a parameter. ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 007e32d - [clang][Interp][NFC] Simplify record creation
Author: Timm Bäder Date: 2024-07-12T16:45:18+02:00 New Revision: 007e32d024f31ef157e3e16117a6c000bfaa2754 URL: https://github.com/llvm/llvm-project/commit/007e32d024f31ef157e3e16117a6c000bfaa2754 DIFF: https://github.com/llvm/llvm-project/commit/007e32d024f31ef157e3e16117a6c000bfaa2754.diff LOG: [clang][Interp][NFC] Simplify record creation Try to keep the indentation width lower here. Added: Modified: clang/lib/AST/Interp/Program.cpp Removed: diff --git a/clang/lib/AST/Interp/Program.cpp b/clang/lib/AST/Interp/Program.cpp index d3864d23925c0..5dd59d969853c 100644 --- a/clang/lib/AST/Interp/Program.cpp +++ b/clang/lib/AST/Interp/Program.cpp @@ -288,40 +288,41 @@ Record *Program::getOrCreateRecord(const RecordDecl *RD) { Record::BaseList Bases; Record::VirtualBaseList VirtBases; if (const auto *CD = dyn_cast(RD)) { - for (const CXXBaseSpecifier : CD->bases()) { if (Spec.isVirtual()) continue; // In error cases, the base might not be a RecordType. - if (const auto *RT = Spec.getType()->getAs()) { -const RecordDecl *BD = RT->getDecl(); -const Record *BR = getOrCreateRecord(BD); - -if (const Descriptor *Desc = GetBaseDesc(BD, BR)) { - BaseSize += align(sizeof(InlineDescriptor)); - Bases.push_back({BD, BaseSize, Desc, BR}); - BaseSize += align(BR->getSize()); - continue; -} - } - return nullptr; + const auto *RT = Spec.getType()->getAs(); + if (!RT) +return nullptr; + const RecordDecl *BD = RT->getDecl(); + const Record *BR = getOrCreateRecord(BD); + + const Descriptor *Desc = GetBaseDesc(BD, BR); + if (!Desc) +return nullptr; + + BaseSize += align(sizeof(InlineDescriptor)); + Bases.push_back({BD, BaseSize, Desc, BR}); + BaseSize += align(BR->getSize()); } for (const CXXBaseSpecifier : CD->vbases()) { + const auto *RT = Spec.getType()->getAs(); + if (!RT) +return nullptr; - if (const auto *RT = Spec.getType()->getAs()) { -const RecordDecl *BD = RT->getDecl(); -const Record *BR = getOrCreateRecord(BD); + const RecordDecl *BD = RT->getDecl(); + const Record *BR = getOrCreateRecord(BD); -if (const Descriptor *Desc = GetBaseDesc(BD, BR)) { - VirtSize += align(sizeof(InlineDescriptor)); - VirtBases.push_back({BD, VirtSize, Desc, BR}); - VirtSize += align(BR->getSize()); - continue; -} - } - return nullptr; + const Descriptor *Desc = GetBaseDesc(BD, BR); + if (!Desc) +return nullptr; + + VirtSize += align(sizeof(InlineDescriptor)); + VirtBases.push_back({BD, VirtSize, Desc, BR}); + VirtSize += align(BR->getSize()); } } ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 98edc0c - [clang][Interp] Fix member pointer temporaries
Author: Timm Bäder Date: 2024-07-12T16:37:04+02:00 New Revision: 98edc0cb1f4ca53bd2d490916566ff7d217110f8 URL: https://github.com/llvm/llvm-project/commit/98edc0cb1f4ca53bd2d490916566ff7d217110f8 DIFF: https://github.com/llvm/llvm-project/commit/98edc0cb1f4ca53bd2d490916566ff7d217110f8.diff LOG: [clang][Interp] Fix member pointer temporaries PT_MemberPtr also needs its ctor/dtor called, so add that. However, this exposed a problem in initializing virtual bases, so fix that as well. Added: Modified: clang/lib/AST/Interp/Descriptor.cpp clang/test/AST/Interp/memberpointers.cpp Removed: diff --git a/clang/lib/AST/Interp/Descriptor.cpp b/clang/lib/AST/Interp/Descriptor.cpp index afafae088aca0..a3801a01688c8 100644 --- a/clang/lib/AST/Interp/Descriptor.cpp +++ b/clang/lib/AST/Interp/Descriptor.cpp @@ -162,8 +162,7 @@ static void initField(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable, } static void initBase(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable, - bool IsActive, const Descriptor *D, unsigned FieldOffset, - bool IsVirtualBase) { + bool IsActive, const Descriptor *D, unsigned FieldOffset) { assert(D); assert(D->ElemRecord); @@ -179,43 +178,46 @@ static void initBase(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable, for (const auto : D->ElemRecord->bases()) initBase(B, Ptr + FieldOffset, IsConst, IsMutable, IsActive, V.Desc, - V.Offset, false); + V.Offset); for (const auto : D->ElemRecord->fields()) -initField(B, Ptr + FieldOffset, IsConst, IsMutable, IsActive, IsUnion, F.Desc, - F.Offset); - - // If this is initializing a virtual base, we do NOT want to consider its - // virtual bases, those are already flattened into the parent record when - // creating it. - if (IsVirtualBase) -return; - - for (const auto : D->ElemRecord->virtual_bases()) -initBase(B, Ptr + FieldOffset, IsConst, IsMutable, IsActive, V.Desc, - V.Offset, true); +initField(B, Ptr + FieldOffset, IsConst, IsMutable, IsActive, IsUnion, + F.Desc, F.Offset); } static void ctorRecord(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable, bool IsActive, const Descriptor *D) { for (const auto : D->ElemRecord->bases()) -initBase(B, Ptr, IsConst, IsMutable, IsActive, V.Desc, V.Offset, false); +initBase(B, Ptr, IsConst, IsMutable, IsActive, V.Desc, V.Offset); for (const auto : D->ElemRecord->fields()) initField(B, Ptr, IsConst, IsMutable, IsActive, D->ElemRecord->isUnion(), F.Desc, F.Offset); for (const auto : D->ElemRecord->virtual_bases()) -initBase(B, Ptr, IsConst, IsMutable, IsActive, V.Desc, V.Offset, true); +initBase(B, Ptr, IsConst, IsMutable, IsActive, V.Desc, V.Offset); +} + +static void destroyField(Block *B, std::byte *Ptr, const Descriptor *D, + unsigned FieldOffset) { + if (auto Fn = D->DtorFn) +Fn(B, Ptr + FieldOffset, D); +} + +static void destroyBase(Block *B, std::byte *Ptr, const Descriptor *D, +unsigned FieldOffset) { + assert(D); + assert(D->ElemRecord); + + for (const auto : D->ElemRecord->bases()) +destroyBase(B, Ptr + FieldOffset, V.Desc, V.Offset); + for (const auto : D->ElemRecord->fields()) +destroyField(B, Ptr + FieldOffset, F.Desc, F.Offset); } static void dtorRecord(Block *B, std::byte *Ptr, const Descriptor *D) { - auto DtorSub = [=](unsigned SubOff, const Descriptor *F) { -if (auto Fn = F->DtorFn) - Fn(B, Ptr + SubOff, F); - }; for (const auto : D->ElemRecord->bases()) -DtorSub(F.Offset, F.Desc); +destroyBase(B, Ptr, F.Desc, F.Offset); for (const auto : D->ElemRecord->fields()) -DtorSub(F.Offset, F.Desc); +destroyField(B, Ptr, F.Desc, F.Offset); for (const auto : D->ElemRecord->virtual_bases()) -DtorSub(F.Offset, F.Desc); +destroyBase(B, Ptr, F.Desc, F.Offset); } static void moveRecord(Block *B, const std::byte *Src, std::byte *Dst, @@ -238,6 +240,8 @@ static BlockCtorFn getCtorPrim(PrimType Type) { return ctorTy::T>; if (Type == PT_IntAPS) return ctorTy::T>; + if (Type == PT_MemberPtr) +return ctorTy::T>; COMPOSITE_TYPE_SWITCH(Type, return ctorTy, return nullptr); } @@ -251,6 +255,8 @@ static BlockDtorFn getDtorPrim(PrimType Type) { return dtorTy::T>; if (Type == PT_IntAPS) return dtorTy::T>; + if (Type == PT_MemberPtr) +return dtorTy::T>; COMPOSITE_TYPE_SWITCH(Type, return dtorTy, return nullptr); } diff --git a/clang/test/AST/Interp/memberpointers.cpp b/clang/test/AST/Interp/memberpointers.cpp index 54d73fe86ca18..178d2e23f1266 100644 --- a/clang/test/AST/Interp/memberpointers.cpp +++ b/clang/test/AST/Interp/memberpointers.cpp @@ -195,3 +195,15 @@ namespace {
[clang] 7a93508 - [clang][Interp] Reject calling function pointers if types don't match
Author: Timm Bäder Date: 2024-07-12T15:32:40+02:00 New Revision: 7a935089d4593de6767901810594058904412106 URL: https://github.com/llvm/llvm-project/commit/7a935089d4593de6767901810594058904412106 DIFF: https://github.com/llvm/llvm-project/commit/7a935089d4593de6767901810594058904412106.diff LOG: [clang][Interp] Reject calling function pointers if types don't match Added: Modified: clang/lib/AST/Interp/Interp.h clang/test/AST/Interp/functions.cpp Removed: diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h index 12143fbf50808..ac87901570ec1 100644 --- a/clang/lib/AST/Interp/Interp.h +++ b/clang/lib/AST/Interp/Interp.h @@ -2569,6 +2569,12 @@ inline bool CallPtr(InterpState , CodePtr OpPC, uint32_t ArgSize, assert(F); + // This happens when the call expression has been cast to + // something else, but we don't support that. + if (S.Ctx.classify(F->getDecl()->getReturnType()) != + S.Ctx.classify(CE->getType())) +return false; + // Check argument nullability state. if (F->hasNonNullAttr()) { if (!CheckNonNullArgs(S, OpPC, F, CE, ArgSize)) diff --git a/clang/test/AST/Interp/functions.cpp b/clang/test/AST/Interp/functions.cpp index f43be1d3c0403..fa29e08a30175 100644 --- a/clang/test/AST/Interp/functions.cpp +++ b/clang/test/AST/Interp/functions.cpp @@ -1,9 +1,9 @@ -// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify=expected,both %s -// RUN: %clang_cc1 -std=c++14 -fexperimental-new-constant-interpreter -verify=expected,both %s -// RUN: %clang_cc1 -std=c++20 -fexperimental-new-constant-interpreter -verify=expected,both %s -// RUN: %clang_cc1 -verify=ref,both %s -// RUN: %clang_cc1 -std=c++14 -verify=ref,both %s -// RUN: %clang_cc1 -std=c++20 -verify=ref,both %s +// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -pedantic -verify=expected,both %s +// RUN: %clang_cc1 -std=c++14 -fexperimental-new-constant-interpreter -pedantic -verify=expected,both %s +// RUN: %clang_cc1 -std=c++20 -fexperimental-new-constant-interpreter -pedantic -verify=expected,both %s +// RUN: %clang_cc1 -pedantic -verify=ref,both %s +// RUN: %clang_cc1 -pedantic -std=c++14 -verify=ref,both %s +// RUN: %clang_cc1 -pedantic -std=c++20 -verify=ref,both %s constexpr void doNothing() {} constexpr int gimme5() { @@ -471,7 +471,7 @@ namespace AddressOf { constexpr int foo() {return 1;} static_assert(__builtin_addressof(foo) == foo, ""); - constexpr _Complex float F = {3, 4}; + constexpr _Complex float F = {3, 4}; // both-warning {{'_Complex' is a C99 extension}} static_assert(__builtin_addressof(F) == , ""); void testAddressof(int x) { @@ -633,3 +633,14 @@ namespace { void ()() = f; void ()() = r; } + +namespace FunctionCast { + // When folding, we allow functions to be cast to diff erent types. Such + // cast functions cannot be called, even if they're constexpr. + constexpr int f() { return 1; } + typedef double (*DoubleFn)(); + typedef int (*IntFn)(); + int a[(int)DoubleFn(f)()]; // both-error {{variable length array}} \ + // both-warning {{are a Clang extension}} + int b[(int)IntFn(f)()];// ok +} ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 369d3a7 - [clang][Interp][NFC] Remove ExprScope
Author: Timm Bäder Date: 2024-07-09T11:52:40+02:00 New Revision: 369d3a738082a2fac1a98aae8a8cfded9a010e10 URL: https://github.com/llvm/llvm-project/commit/369d3a738082a2fac1a98aae8a8cfded9a010e10 DIFF: https://github.com/llvm/llvm-project/commit/369d3a738082a2fac1a98aae8a8cfded9a010e10.diff LOG: [clang][Interp][NFC] Remove ExprScope It's been nothing but a LocalScope for a while. Added: Modified: clang/lib/AST/Interp/Compiler.cpp clang/lib/AST/Interp/Compiler.h Removed: diff --git a/clang/lib/AST/Interp/Compiler.cpp b/clang/lib/AST/Interp/Compiler.cpp index 1d39d7bb9e15f..5fad24a0930ac 100644 --- a/clang/lib/AST/Interp/Compiler.cpp +++ b/clang/lib/AST/Interp/Compiler.cpp @@ -2204,7 +2204,7 @@ bool Compiler::VisitCompoundAssignOperator( template bool Compiler::VisitExprWithCleanups(const ExprWithCleanups *E) { - ExprScope ES(this); + LocalScope ES(this); const Expr *SubExpr = E->getSubExpr(); assert(E->getNumObjects() == 0 && "TODO: Implement cleanups"); @@ -3425,7 +3425,7 @@ const Function *Compiler::getFunction(const FunctionDecl *FD) { } template bool Compiler::visitExpr(const Expr *E) { - ExprScope RootScope(this); + LocalScope RootScope(this); // Void expressions. if (E->getType()->isVoidType()) { if (!visit(E)) @@ -3610,10 +3610,10 @@ VarCreationState Compiler::visitVarDecl(const VarDecl *VD, bool Topleve // If this is a toplevel declaration, create a scope for the // initializer. if (Toplevel) { - ExprScope Scope(this); + LocalScope Scope(this); if (!this->visit(Init)) return false; - return this->emitSetLocal(*VarT, Offset, VD); + return this->emitSetLocal(*VarT, Offset, VD) && Scope.destroyLocals(); } else { if (!this->visit(Init)) return false; @@ -4120,7 +4120,7 @@ bool Compiler::visitReturnStmt(const ReturnStmt *RS) { return this->emitUnsupported(RS); if (const Expr *RE = RS->getRetValue()) { -ExprScope RetScope(this); +LocalScope RetScope(this); if (ReturnType) { // Primitive types are simply returned. if (!this->visit(RE)) diff --git a/clang/lib/AST/Interp/Compiler.h b/clang/lib/AST/Interp/Compiler.h index fbeda8a0b7a4f..246ff25347067 100644 --- a/clang/lib/AST/Interp/Compiler.h +++ b/clang/lib/AST/Interp/Compiler.h @@ -612,11 +612,6 @@ template class BlockScope final : public AutoScope { } }; -template class ExprScope final : public AutoScope { -public: - ExprScope(Compiler *Ctx) : AutoScope(Ctx) {} -}; - template class ArrayIndexScope final { public: ArrayIndexScope(Compiler *Ctx, uint64_t Index) : Ctx(Ctx) { ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] f6712d2 - [clang][Interp][NFC] Get rid of AutoScope
Author: Timm Bäder Date: 2024-07-09T11:52:41+02:00 New Revision: f6712d27874004835170e6eb8ff5f348a8866057 URL: https://github.com/llvm/llvm-project/commit/f6712d27874004835170e6eb8ff5f348a8866057 DIFF: https://github.com/llvm/llvm-project/commit/f6712d27874004835170e6eb8ff5f348a8866057.diff LOG: [clang][Interp][NFC] Get rid of AutoScope Added: Modified: clang/lib/AST/Interp/Compiler.cpp clang/lib/AST/Interp/Compiler.h Removed: diff --git a/clang/lib/AST/Interp/Compiler.cpp b/clang/lib/AST/Interp/Compiler.cpp index 5fad24a0930ac..48e7519f8f89d 100644 --- a/clang/lib/AST/Interp/Compiler.cpp +++ b/clang/lib/AST/Interp/Compiler.cpp @@ -1794,6 +1794,8 @@ bool Compiler::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E) { if (!this->visitArrayElemInit(I, SubExpr)) return false; +if (!BS.destroyLocals()) + return false; } return true; } @@ -3080,7 +3082,7 @@ bool Compiler::VisitStmtExpr(const StmtExpr *E) { return false; } - return true; + return BS.destroyLocals(); } template bool Compiler::discard(const Expr *E) { @@ -4190,7 +4192,7 @@ template bool Compiler::visitIfStmt(const IfStmt *IS) { this->emitLabel(LabelEnd); } - return true; + return IfScope.destroyLocals(); } template @@ -4656,6 +4658,9 @@ bool Compiler::visitFunc(const FunctionDecl *F) { if (!this->emitPopPtr(InitExpr)) return false; } + + if (!Scope.destroyLocals()) +return false; } } diff --git a/clang/lib/AST/Interp/Compiler.h b/clang/lib/AST/Interp/Compiler.h index 246ff25347067..de873c7e6825f 100644 --- a/clang/lib/AST/Interp/Compiler.h +++ b/clang/lib/AST/Interp/Compiler.h @@ -589,20 +589,10 @@ template class DestructorScope final { LocalScope }; -/// Like a regular LocalScope, except that the destructors of all local -/// variables are automatically emitted when the AutoScope is destroyed. -template class AutoScope : public LocalScope { -public: - AutoScope(Compiler *Ctx) : LocalScope(Ctx), DS(*this) {} - -private: - DestructorScope DS; -}; - /// Scope for storage declared in a compound statement. -template class BlockScope final : public AutoScope { +template class BlockScope final : public LocalScope { public: - BlockScope(Compiler *Ctx) : AutoScope(Ctx) {} + BlockScope(Compiler *Ctx) : LocalScope(Ctx) {} void addExtended(const Scope::Local ) override { // If we to this point, just add the variable as a normal local ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] dd2bf3b - [clang][Interp] Redo variable (re)visiting
Author: Timm Bäder Date: 2024-07-09T10:43:35+02:00 New Revision: dd2bf3b840df260d794e37cc96d4498372aa08f6 URL: https://github.com/llvm/llvm-project/commit/dd2bf3b840df260d794e37cc96d4498372aa08f6 DIFF: https://github.com/llvm/llvm-project/commit/dd2bf3b840df260d794e37cc96d4498372aa08f6.diff LOG: [clang][Interp] Redo variable (re)visiting Depending on the circumstances we visit variables in, we need to be careful about when to destroy their temporaries and whether to emit a Ret op at all or not. Added: Modified: clang/lib/AST/Interp/ByteCodeEmitter.h clang/lib/AST/Interp/Compiler.cpp clang/lib/AST/Interp/Compiler.h clang/lib/AST/Interp/EvalEmitter.cpp clang/lib/AST/Interp/EvalEmitter.h clang/test/C/C23/n3017.c clang/test/CodeGenCXX/no-const-init-cxx2a.cpp clang/test/SemaCXX/warn-unused-variables.cpp Removed: diff --git a/clang/lib/AST/Interp/ByteCodeEmitter.h b/clang/lib/AST/Interp/ByteCodeEmitter.h index 9a329e969f339..a19a25c2f9e8e 100644 --- a/clang/lib/AST/Interp/ByteCodeEmitter.h +++ b/clang/lib/AST/Interp/ByteCodeEmitter.h @@ -46,7 +46,7 @@ class ByteCodeEmitter { /// Methods implemented by the compiler. virtual bool visitFunc(const FunctionDecl *E) = 0; virtual bool visitExpr(const Expr *E) = 0; - virtual bool visitDecl(const VarDecl *E, bool ConstantContext) = 0; + virtual bool visitDeclAndReturn(const VarDecl *E, bool ConstantContext) = 0; /// Emits jumps. bool jumpTrue(const LabelTy ); diff --git a/clang/lib/AST/Interp/Compiler.cpp b/clang/lib/AST/Interp/Compiler.cpp index 613bf4af137b6..1d39d7bb9e15f 100644 --- a/clang/lib/AST/Interp/Compiler.cpp +++ b/clang/lib/AST/Interp/Compiler.cpp @@ -25,10 +25,10 @@ namespace clang { namespace interp { /// Scope used to handle temporaries in toplevel variable declarations. -template class DeclScope final : public VariableScope { +template class DeclScope final : public LocalScope { public: DeclScope(Compiler *Ctx, const ValueDecl *VD) - : VariableScope(Ctx, nullptr), Scope(Ctx->P, VD), + : LocalScope(Ctx, VD), Scope(Ctx->P, VD), OldGlobalDecl(Ctx->GlobalDecl), OldInitializingDecl(Ctx->InitializingDecl) { Ctx->GlobalDecl = Context::shouldBeGloballyIndexed(VD); @@ -3462,40 +3462,52 @@ template bool Compiler::visitExpr(const Expr *E) { return false; } -/// Toplevel visitDecl(). +template +VarCreationState Compiler::visitDecl(const VarDecl *VD) { + + auto R = this->visitVarDecl(VD, /*Toplevel=*/true); + + if (R.notCreated()) +return R; + + if (R) +return true; + + if (!R && Context::shouldBeGloballyIndexed(VD)) { +if (auto GlobalIndex = P.getGlobal(VD)) { + Block *GlobalBlock = P.getGlobal(*GlobalIndex); + GlobalInlineDescriptor = + *reinterpret_cast(GlobalBlock->rawData()); + + GD.InitState = GlobalInitState::InitializerFailed; + GlobalBlock->invokeDtor(); +} + } + + return R; +} + +/// Toplevel visitDeclAndReturn(). /// We get here from evaluateAsInitializer(). /// We need to evaluate the initializer and return its value. template -bool Compiler::visitDecl(const VarDecl *VD, bool ConstantContext) { - assert(!VD->isInvalidDecl() && "Trying to constant evaluate an invalid decl"); - +bool Compiler::visitDeclAndReturn(const VarDecl *VD, + bool ConstantContext) { std::optional VarT = classify(VD->getType()); // We only create variables if we're evaluating in a constant context. // Otherwise, just evaluate the initializer and return it. if (!ConstantContext) { -DeclScope LocalScope(this, VD); +DeclScope LS(this, VD); if (!this->visit(VD->getAnyInitializer())) return false; -return this->emitRet(VarT.value_or(PT_Ptr), VD); - } - - // If we've seen the global variable already and the initializer failed, - // just return false immediately. - if (std::optional Index = P.getGlobal(VD)) { -const Pointer = P.getPtrGlobal(*Index); -const GlobalInlineDescriptor = -*reinterpret_cast( -Ptr.block()->rawData()); -if (GD.InitState == GlobalInitState::InitializerFailed) - return false; +return this->emitRet(VarT.value_or(PT_Ptr), VD) && LS.destroyLocals(); } - // Create and initialize the variable. + LocalScope VDScope(this, VD); if (!this->visitVarDecl(VD, /*Toplevel=*/true)) return false; - // Get a pointer to the variable if (Context::shouldBeGloballyIndexed(VD)) { auto GlobalIndex = P.getGlobal(VD); assert(GlobalIndex); // visitVarDecl() didn't return false. @@ -3535,7 +3547,7 @@ bool Compiler::visitDecl(const VarDecl *VD, bool ConstantContext) { return false; } - return true; + return VDScope.destroyLocals(); } template @@ -3589,26 +3601,34 @@ VarCreationState Compiler::visitVarDecl(const VarDecl *VD, bool Topleve return !Init
[clang] ad82d1c - [clang][Interp][NFC] Move a lambda declaration into its closest scope
Author: Timm Bäder Date: 2024-07-09T10:12:53+02:00 New Revision: ad82d1c53f089937c05af11ff45798ceb5ca894e URL: https://github.com/llvm/llvm-project/commit/ad82d1c53f089937c05af11ff45798ceb5ca894e DIFF: https://github.com/llvm/llvm-project/commit/ad82d1c53f089937c05af11ff45798ceb5ca894e.diff LOG: [clang][Interp][NFC] Move a lambda declaration into its closest scope Added: Modified: clang/lib/AST/Interp/Compiler.cpp Removed: diff --git a/clang/lib/AST/Interp/Compiler.cpp b/clang/lib/AST/Interp/Compiler.cpp index 3d9a0358c5487..613bf4af137b6 100644 --- a/clang/lib/AST/Interp/Compiler.cpp +++ b/clang/lib/AST/Interp/Compiler.cpp @@ -3552,12 +3552,12 @@ VarCreationState Compiler::visitVarDecl(const VarDecl *VD, bool Topleve const Expr *Init = VD->getInit(); std::optional VarT = classify(VD->getType()); - auto checkDecl = [&]() -> bool { -bool NeedsOp = !Toplevel && VD->isLocalVarDecl() && VD->isStaticLocal(); -return !NeedsOp || this->emitCheckDecl(VD, VD); - }; - if (Context::shouldBeGloballyIndexed(VD)) { +auto checkDecl = [&]() -> bool { + bool NeedsOp = !Toplevel && VD->isLocalVarDecl() && VD->isStaticLocal(); + return !NeedsOp || this->emitCheckDecl(VD, VD); +}; + auto initGlobal = [&](unsigned GlobalIndex) -> bool { assert(Init); DeclScope LocalScope(this, VD); ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 4f68d20 - [clang][Interp][NFC] Simplify Pointer Block accessing code
Author: Timm Bäder Date: 2024-07-09T10:12:53+02:00 New Revision: 4f68d20d87b5a4c06c4ec954c93069cebeb6dfee URL: https://github.com/llvm/llvm-project/commit/4f68d20d87b5a4c06c4ec954c93069cebeb6dfee DIFF: https://github.com/llvm/llvm-project/commit/4f68d20d87b5a4c06c4ec954c93069cebeb6dfee.diff LOG: [clang][Interp][NFC] Simplify Pointer Block accessing code Try to get PointeeStorage.BS.Pointee only once and reuse that. Added: Modified: clang/lib/AST/Interp/Pointer.cpp Removed: diff --git a/clang/lib/AST/Interp/Pointer.cpp b/clang/lib/AST/Interp/Pointer.cpp index 157892ea492f6..b2e3a7ff70881 100644 --- a/clang/lib/AST/Interp/Pointer.cpp +++ b/clang/lib/AST/Interp/Pointer.cpp @@ -57,9 +57,9 @@ Pointer::~Pointer() { if (isIntegralPointer()) return; - if (PointeeStorage.BS.Pointee) { -PointeeStorage.BS.Pointee->removePointer(this); -PointeeStorage.BS.Pointee->cleanup(); + if (Block *Pointee = PointeeStorage.BS.Pointee) { +Pointee->removePointer(this); +Pointee->cleanup(); } } @@ -188,6 +188,7 @@ APValue Pointer::toAPValue() const { void Pointer::print(llvm::raw_ostream ) const { OS << PointeeStorage.BS.Pointee << " ("; if (isBlockPointer()) { +const Block *B = PointeeStorage.BS.Pointee; OS << "Block) {"; if (isRoot()) @@ -200,8 +201,8 @@ void Pointer::print(llvm::raw_ostream ) const { else OS << Offset << ", "; -if (PointeeStorage.BS.Pointee) - OS << PointeeStorage.BS.Pointee->getSize(); +if (B) + OS << B->getSize(); else OS << "nullptr"; } else { ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] efc5a6a - [clang][Interp][NFC] Print Block descriptor in ::dump()
Author: Timm Bäder Date: 2024-07-09T09:59:52+02:00 New Revision: efc5a6aa82081aaa002f90baa21fc16655af0729 URL: https://github.com/llvm/llvm-project/commit/efc5a6aa82081aaa002f90baa21fc16655af0729 DIFF: https://github.com/llvm/llvm-project/commit/efc5a6aa82081aaa002f90baa21fc16655af0729.diff LOG: [clang][Interp][NFC] Print Block descriptor in ::dump() Added: Modified: clang/lib/AST/Interp/Disasm.cpp Removed: diff --git a/clang/lib/AST/Interp/Disasm.cpp b/clang/lib/AST/Interp/Disasm.cpp index d946a10c22dc3..c6c6275593007 100644 --- a/clang/lib/AST/Interp/Disasm.cpp +++ b/clang/lib/AST/Interp/Disasm.cpp @@ -325,8 +325,11 @@ LLVM_DUMP_METHOD void Record::dump(llvm::raw_ostream , unsigned Indentation, LLVM_DUMP_METHOD void Block::dump(llvm::raw_ostream ) const { { ColorScope SC(OS, true, {llvm::raw_ostream::BRIGHT_BLUE, true}); -OS << "Block " << (const void *)this << "\n"; +OS << "Block " << (const void *)this; } + OS << " ("; + Desc->dump(OS); + OS << ")\n"; unsigned NPointers = 0; for (const Pointer *P = Pointers; P; P = P->Next) { ++NPointers; ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 3655de7 - [clang][Interp] Avoid a dangling pointer
Author: Timm Bäder Date: 2024-07-09T09:59:51+02:00 New Revision: 3655de73809b0f8f100040c4b9c9ad889dca2225 URL: https://github.com/llvm/llvm-project/commit/3655de73809b0f8f100040c4b9c9ad889dca2225 DIFF: https://github.com/llvm/llvm-project/commit/3655de73809b0f8f100040c4b9c9ad889dca2225.diff LOG: [clang][Interp] Avoid a dangling pointer We've just moved all the pointers from the Block to the DeadBlock, so make sure the old Block doesn't point to a linked list of Pointers that don't even point to it anymore. Added: Modified: clang/lib/AST/Interp/InterpBlock.cpp Removed: diff --git a/clang/lib/AST/Interp/InterpBlock.cpp b/clang/lib/AST/Interp/InterpBlock.cpp index c34ea7634b4a9..7bef5e678c074 100644 --- a/clang/lib/AST/Interp/InterpBlock.cpp +++ b/clang/lib/AST/Interp/InterpBlock.cpp @@ -106,6 +106,7 @@ DeadBlock::DeadBlock(DeadBlock *, Block *Blk) B.Pointers = Blk->Pointers; for (Pointer *P = Blk->Pointers; P; P = P->Next) P->PointeeStorage.BS.Pointee = + Blk->Pointers = nullptr; } void DeadBlock::free() { ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 93869df - [clang][Interp][NFC] Simplify a test case
Author: Timm Bäder Date: 2024-07-09T09:23:14+02:00 New Revision: 93869dfd89387844bf8b605ebcd1abc0cc81bde8 URL: https://github.com/llvm/llvm-project/commit/93869dfd89387844bf8b605ebcd1abc0cc81bde8 DIFF: https://github.com/llvm/llvm-project/commit/93869dfd89387844bf8b605ebcd1abc0cc81bde8.diff LOG: [clang][Interp][NFC] Simplify a test case Added: Modified: clang/test/AST/Interp/lifetimes.cpp Removed: diff --git a/clang/test/AST/Interp/lifetimes.cpp b/clang/test/AST/Interp/lifetimes.cpp index c1046e5689207..c544baba6178c 100644 --- a/clang/test/AST/Interp/lifetimes.cpp +++ b/clang/test/AST/Interp/lifetimes.cpp @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify %s -// RUN: %clang_cc1 -verify=ref %s +// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify=expected,both %s +// RUN: %clang_cc1 -verify=ref,both %s struct Foo { int a; @@ -16,9 +16,7 @@ constexpr int dead1() { // expected-error {{never produces a constant expression return F2->a; // expected-note 2{{read of variable whose lifetime has ended}} \ // ref-note {{read of object outside its lifetime is not allowed in a constant expression}} } -static_assert(dead1() == 1, ""); // expected-error {{not an integral constant expression}} \ - // expected-note {{in call to}} \ - // ref-error {{not an integral constant expression}} \ - // ref-note {{in call to}} \ +static_assert(dead1() == 1, ""); // both-error {{not an integral constant expression}} \ + // both-note {{in call to}} ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] eee9efb - [clang][Interp][NFC] Add empty initializer list to test decl
Author: Timm Bäder Date: 2024-07-09T09:23:14+02:00 New Revision: eee9efb09c1a3cbbb1ad5471713f3da218c8b00e URL: https://github.com/llvm/llvm-project/commit/eee9efb09c1a3cbbb1ad5471713f3da218c8b00e DIFF: https://github.com/llvm/llvm-project/commit/eee9efb09c1a3cbbb1ad5471713f3da218c8b00e.diff LOG: [clang][Interp][NFC] Add empty initializer list to test decl This was missing in the test. Added: Modified: clang/test/AST/Interp/records.cpp Removed: diff --git a/clang/test/AST/Interp/records.cpp b/clang/test/AST/Interp/records.cpp index f27c895e89948..adc3799a20ce4 100644 --- a/clang/test/AST/Interp/records.cpp +++ b/clang/test/AST/Interp/records.cpp @@ -495,7 +495,7 @@ namespace DeclRefs { static_assert(b.a.m == 100, ""); static_assert(b.a.f == 100, ""); - constexpr B b2; + constexpr B b2{}; static_assert(b2.a.m == 100, ""); static_assert(b2.a.f == 100, ""); static_assert(b2.a.f == 101, ""); // both-error {{failed}} \ ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 00c622e - [clang][Interp][Test] Add test for #97302
Author: Timm Bäder Date: 2024-07-05T12:44:32+02:00 New Revision: 00c622e596f918d9d83674b58097c8982ae1af95 URL: https://github.com/llvm/llvm-project/commit/00c622e596f918d9d83674b58097c8982ae1af95 DIFF: https://github.com/llvm/llvm-project/commit/00c622e596f918d9d83674b58097c8982ae1af95.diff LOG: [clang][Interp][Test] Add test for #97302 Fixes #97302 Added: Modified: clang/test/AST/Interp/records.cpp Removed: diff --git a/clang/test/AST/Interp/records.cpp b/clang/test/AST/Interp/records.cpp index 1554e54275598a..f27c895e899486 100644 --- a/clang/test/AST/Interp/records.cpp +++ b/clang/test/AST/Interp/records.cpp @@ -494,6 +494,12 @@ namespace DeclRefs { constexpr B b; static_assert(b.a.m == 100, ""); static_assert(b.a.f == 100, ""); + + constexpr B b2; + static_assert(b2.a.m == 100, ""); + static_assert(b2.a.f == 100, ""); + static_assert(b2.a.f == 101, ""); // both-error {{failed}} \ +// both-note {{evaluates to '100 == 101'}} } namespace PointerArith { ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 2f0700a - [clang][Interp] Add a missing template keyword
Author: Timm Bäder Date: 2024-07-05T12:28:17+02:00 New Revision: 2f0700a84311d1a8b0fc12499fe9480ccbd188e9 URL: https://github.com/llvm/llvm-project/commit/2f0700a84311d1a8b0fc12499fe9480ccbd188e9 DIFF: https://github.com/llvm/llvm-project/commit/2f0700a84311d1a8b0fc12499fe9480ccbd188e9.diff LOG: [clang][Interp] Add a missing template keyword This broke a buildbot: https://lab.llvm.org/buildbot/#/builders/190/builds/1326 Added: Modified: clang/lib/AST/Interp/Compiler.cpp Removed: diff --git a/clang/lib/AST/Interp/Compiler.cpp b/clang/lib/AST/Interp/Compiler.cpp index 2ada68f6bc756..3d9a0358c5487 100644 --- a/clang/lib/AST/Interp/Compiler.cpp +++ b/clang/lib/AST/Interp/Compiler.cpp @@ -3995,7 +3995,7 @@ bool Compiler::VisitCXXThisExpr(const CXXThisExpr *E) { } for (unsigned I = StartIndex, N = InitStack.size(); I != N; ++I) { - if (!InitStack[I].emit(this, E)) + if (!InitStack[I].template emit(this, E)) return false; } return true; ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] f926e19 - Reapply "[clang][Interp] Fix init chain in local initializers"
Author: Timm Bäder Date: 2024-07-05T12:16:18+02:00 New Revision: f926e19aa9c0bdca3f05322e1b62562a9a3a05e2 URL: https://github.com/llvm/llvm-project/commit/f926e19aa9c0bdca3f05322e1b62562a9a3a05e2 DIFF: https://github.com/llvm/llvm-project/commit/f926e19aa9c0bdca3f05322e1b62562a9a3a05e2.diff LOG: Reapply "[clang][Interp] Fix init chain in local initializers" This reverts commit 2dda8a2650927e4b0fbb459507684455e196d9a9. Added: Modified: clang/lib/AST/Interp/Compiler.cpp clang/lib/AST/Interp/Compiler.h clang/lib/AST/Interp/EvalEmitter.cpp clang/lib/AST/Interp/Pointer.h clang/test/AST/Interp/records.cpp Removed: diff --git a/clang/lib/AST/Interp/Compiler.cpp b/clang/lib/AST/Interp/Compiler.cpp index 2fd20d8022126..2ada68f6bc756 100644 --- a/clang/lib/AST/Interp/Compiler.cpp +++ b/clang/lib/AST/Interp/Compiler.cpp @@ -85,8 +85,12 @@ bool InitLink::emit(Compiler *Ctx, const Expr *E) const { case K_Field: // We're assuming there's a base pointer on the stack already. return Ctx->emitGetPtrFieldPop(Offset, E); + case K_Temp: +return Ctx->emitGetPtrLocal(Offset, E); case K_Decl: return Ctx->visitDeclRef(D, E); + default: +llvm_unreachable("Unhandled InitLink kind"); } return true; } @@ -1330,6 +1334,7 @@ bool Compiler::visitInitList(ArrayRef Inits, auto initCompositeField = [=](const Record::Field *FieldToInit, const Expr *Init) -> bool { + InitLinkScope ILS(this, InitLink::Field(FieldToInit->Offset)); // Non-primitive case. Get a pointer to the field-to-initialize // on the stack and recurse into visitInitializer(). if (!this->emitGetPtrField(FieldToInit->Offset, Init)) @@ -2271,6 +2276,7 @@ bool Compiler::VisitMaterializeTemporaryExpr( const Expr *Inner = E->getSubExpr()->skipRValueSubobjectAdjustments(); if (std::optional LocalIndex = allocateLocal(Inner, E->getExtendingDecl())) { + InitLinkScope ILS(this, InitLink::Temp(*LocalIndex)); if (!this->emitGetPtrLocal(*LocalIndex, E)) return false; return this->visitInitializer(SubExpr); @@ -2449,6 +2455,7 @@ bool Compiler::VisitCXXConstructExpr(const CXXConstructExpr *E) { // Trivial copy/move constructor. Avoid copy. if (Ctor->isDefaulted() && Ctor->isCopyOrMoveConstructor() && +Ctor->isTrivial() && E->getArg(0)->isTemporaryObject(Ctx.getASTContext(), T->getAsCXXRecordDecl())) return this->visitInitializer(E->getArg(0)); @@ -3583,6 +3590,7 @@ VarCreationState Compiler::visitVarDecl(const VarDecl *VD, bool Topleve return !Init || (checkDecl() && initGlobal(*GlobalIndex)); } else { VariableScope LocalScope(this, VD); +InitLinkScope ILS(this, InitLink::Decl(VD)); if (VarT) { unsigned Offset = this->allocateLocalPrimitive( @@ -3917,7 +3925,8 @@ bool Compiler::VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *E) { SourceLocScope SLS(this, E); bool Old = InitStackActive; - InitStackActive = !isa(E->getUsedContext()); + InitStackActive = + !(E->getUsedContext()->getDeclKind() == Decl::CXXConstructor); bool Result = this->delegate(E->getExpr()); InitStackActive = Old; return Result; @@ -3979,8 +3988,14 @@ bool Compiler::VisitCXXThisExpr(const CXXThisExpr *E) { // currently being initialized. Here we emit the necessary instruction(s) for // this scenario. if (InitStackActive && !InitStack.empty()) { -for (const InitLink : InitStack) { - if (!IL.emit(this, E)) +unsigned StartIndex = 0; +for (StartIndex = InitStack.size() - 1; StartIndex > 0; --StartIndex) { + if (InitStack[StartIndex].Kind != InitLink::K_Field) +break; +} + +for (unsigned I = StartIndex, N = InitStack.size(); I != N; ++I) { + if (!InitStack[I].emit(this, E)) return false; } return true; diff --git a/clang/lib/AST/Interp/Compiler.h b/clang/lib/AST/Interp/Compiler.h index d28526c76fe13..1405abfc1a1e2 100644 --- a/clang/lib/AST/Interp/Compiler.h +++ b/clang/lib/AST/Interp/Compiler.h @@ -47,7 +47,8 @@ struct InitLink { enum { K_This = 0, K_Field = 1, -K_Decl = 2, +K_Temp = 2, +K_Decl = 3, }; static InitLink This() { return InitLink{K_This}; } @@ -56,6 +57,11 @@ struct InitLink { IL.Offset = Offset; return IL; } + static InitLink Temp(unsigned Offset) { +InitLink IL{K_Temp}; +IL.Offset = Offset; +return IL; + } static InitLink Decl(const ValueDecl *D) { InitLink IL{K_Decl}; IL.D = D; @@ -66,7 +72,6 @@ struct InitLink { template bool emit(Compiler *Ctx, const Expr *E) const; -private: uint32_t Kind; union { unsigned Offset; diff --git a/clang/lib/AST/Interp/EvalEmitter.cpp b/clang/lib/AST/Interp/EvalEmitter.cpp index
[clang] 6fbd26b - [clang][Interp] Add QualType parameter to Pointer::toRValue
Author: Timm Bäder Date: 2024-07-05T11:58:04+02:00 New Revision: 6fbd26b147ab93da4d0689ea2f6ff73cc9859cb8 URL: https://github.com/llvm/llvm-project/commit/6fbd26b147ab93da4d0689ea2f6ff73cc9859cb8 DIFF: https://github.com/llvm/llvm-project/commit/6fbd26b147ab93da4d0689ea2f6ff73cc9859cb8.diff LOG: [clang][Interp] Add QualType parameter to Pointer::toRValue This fixes the crash from #97302, but exposes an underlying problem. Added: Modified: clang/lib/AST/Interp/EvalEmitter.cpp clang/lib/AST/Interp/EvaluationResult.cpp clang/lib/AST/Interp/EvaluationResult.h clang/lib/AST/Interp/Interp.h clang/lib/AST/Interp/Pointer.cpp clang/lib/AST/Interp/Pointer.h Removed: diff --git a/clang/lib/AST/Interp/EvalEmitter.cpp b/clang/lib/AST/Interp/EvalEmitter.cpp index d17151416b44b..5d20a0b8182a9 100644 --- a/clang/lib/AST/Interp/EvalEmitter.cpp +++ b/clang/lib/AST/Interp/EvalEmitter.cpp @@ -156,7 +156,8 @@ template <> bool EvalEmitter::emitRet(const SourceInfo ) { if (!Ptr.isConst() && Ptr.block()->getEvalID() != Ctx.getEvalID()) return false; -if (std::optional V = Ptr.toRValue(Ctx)) { +if (std::optional V = +Ptr.toRValue(Ctx, EvalResult.getSourceType())) { EvalResult.setValue(*V); } else { return false; @@ -186,7 +187,8 @@ bool EvalEmitter::emitRetValue(const SourceInfo ) { if (CheckFullyInitialized && !EvalResult.checkFullyInitialized(S, Ptr)) return false; - if (std::optional APV = Ptr.toRValue(S.getCtx())) { + if (std::optional APV = + Ptr.toRValue(S.getCtx(), EvalResult.getSourceType())) { EvalResult.setValue(*APV); return true; } @@ -257,7 +259,8 @@ void EvalEmitter::updateGlobalTemporaries() { if (std::optional T = Ctx.classify(E->getType())) { TYPE_SWITCH(*T, { *Cached = Ptr.deref().toAPValue(); }); } else { -if (std::optional APV = Ptr.toRValue(Ctx)) +if (std::optional APV = +Ptr.toRValue(Ctx, Temp->getTemporaryExpr()->getType())) *Cached = *APV; } } diff --git a/clang/lib/AST/Interp/EvaluationResult.cpp b/clang/lib/AST/Interp/EvaluationResult.cpp index a62f3f635e6e0..d0d68f75dd803 100644 --- a/clang/lib/AST/Interp/EvaluationResult.cpp +++ b/clang/lib/AST/Interp/EvaluationResult.cpp @@ -43,7 +43,7 @@ std::optional EvaluationResult::toRValue() const { // We have a pointer and want an RValue. if (const auto *P = std::get_if()) -return P->toRValue(*Ctx); +return P->toRValue(*Ctx, getSourceType()); else if (const auto *FP = std::get_if()) // Nope return FP->toAPValue(); llvm_unreachable("Unhandled lvalue kind"); diff --git a/clang/lib/AST/Interp/EvaluationResult.h b/clang/lib/AST/Interp/EvaluationResult.h index ecf2250074cc9..378f1ccdb0af4 100644 --- a/clang/lib/AST/Interp/EvaluationResult.h +++ b/clang/lib/AST/Interp/EvaluationResult.h @@ -100,6 +100,15 @@ class EvaluationResult final { bool checkFullyInitialized(InterpState , const Pointer ) const; + QualType getSourceType() const { +if (const auto *D = +dyn_cast_if_present(Source.dyn_cast())) + return D->getType(); +else if (const auto *E = Source.dyn_cast()) + return E->getType(); +return QualType(); + } + /// Dump to stderr. void dump() const; diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h index 5d8362b4fa881..12143fbf50808 100644 --- a/clang/lib/AST/Interp/Interp.h +++ b/clang/lib/AST/Interp/Interp.h @@ -1309,7 +1309,8 @@ inline bool InitGlobalTempComp(InterpState , CodePtr OpPC, S.SeenGlobalTemporaries.push_back( std::make_pair(P.getDeclDesc()->asExpr(), Temp)); - if (std::optional APV = P.toRValue(S.getCtx())) { + if (std::optional APV = + P.toRValue(S.getCtx(), Temp->getTemporaryExpr()->getType())) { *Cached = *APV; return true; } diff --git a/clang/lib/AST/Interp/Pointer.cpp b/clang/lib/AST/Interp/Pointer.cpp index d6603f91fb127..157892ea492f6 100644 --- a/clang/lib/AST/Interp/Pointer.cpp +++ b/clang/lib/AST/Interp/Pointer.cpp @@ -340,7 +340,9 @@ bool Pointer::hasSameArray(const Pointer , const Pointer ) { A.getFieldDesc()->IsArray; } -std::optional Pointer::toRValue(const Context ) const { +std::optional Pointer::toRValue(const Context , + QualType ResultType) const { + assert(!ResultType.isNull()); // Method to recursively traverse composites. std::function Composite; Composite = [, ](QualType Ty, const Pointer , APValue ) { @@ -483,13 +485,19 @@ std::optional Pointer::toRValue(const Context ) const { llvm_unreachable("invalid value to return"); }; - if (isZero()) -return APValue(static_cast(nullptr), CharUnits::Zero(), {}, false, - true); - - if (isDummy() || !isLive()) + // Invalid to read from. + if (isDummy()
[clang] fbd7360 - [clang][Interp] Short-cirtuit Move/Copy constructors if we can
Author: Timm Bäder Date: 2024-07-05T11:29:32+02:00 New Revision: fbd736062e043d34cddd6031b4ee93954d4bf199 URL: https://github.com/llvm/llvm-project/commit/fbd736062e043d34cddd6031b4ee93954d4bf199 DIFF: https://github.com/llvm/llvm-project/commit/fbd736062e043d34cddd6031b4ee93954d4bf199.diff LOG: [clang][Interp] Short-cirtuit Move/Copy constructors if we can Added: Modified: clang/lib/AST/Interp/Compiler.cpp Removed: diff --git a/clang/lib/AST/Interp/Compiler.cpp b/clang/lib/AST/Interp/Compiler.cpp index 775cabf7f8c59..2fd20d8022126 100644 --- a/clang/lib/AST/Interp/Compiler.cpp +++ b/clang/lib/AST/Interp/Compiler.cpp @@ -2447,6 +2447,12 @@ bool Compiler::VisitCXXConstructExpr(const CXXConstructExpr *E) { if (T->isRecordType()) { const CXXConstructorDecl *Ctor = E->getConstructor(); +// Trivial copy/move constructor. Avoid copy. +if (Ctor->isDefaulted() && Ctor->isCopyOrMoveConstructor() && +E->getArg(0)->isTemporaryObject(Ctx.getASTContext(), +T->getAsCXXRecordDecl())) + return this->visitInitializer(E->getArg(0)); + // If we're discarding a construct expression, we still need // to allocate a variable and call the constructor and destructor. if (DiscardResult) { ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 2dda8a2 - Revert "[clang][Interp] Fix init chain in local initializers"
Author: Timm Bäder Date: 2024-07-04T08:50:14+02:00 New Revision: 2dda8a2650927e4b0fbb459507684455e196d9a9 URL: https://github.com/llvm/llvm-project/commit/2dda8a2650927e4b0fbb459507684455e196d9a9 DIFF: https://github.com/llvm/llvm-project/commit/2dda8a2650927e4b0fbb459507684455e196d9a9.diff LOG: Revert "[clang][Interp] Fix init chain in local initializers" This reverts commit 86187ed2998e43be62176c2c4a7b204cc52f6ce6. Seems like this breaks buildbots: https://lab.llvm.org/buildbot/#/builders/56/builds/1638 Added: Modified: clang/lib/AST/Interp/Compiler.cpp clang/test/AST/Interp/records.cpp Removed: diff --git a/clang/lib/AST/Interp/Compiler.cpp b/clang/lib/AST/Interp/Compiler.cpp index 2af4c38c5ac3d..775cabf7f8c59 100644 --- a/clang/lib/AST/Interp/Compiler.cpp +++ b/clang/lib/AST/Interp/Compiler.cpp @@ -3577,7 +3577,6 @@ VarCreationState Compiler::visitVarDecl(const VarDecl *VD, bool Topleve return !Init || (checkDecl() && initGlobal(*GlobalIndex)); } else { VariableScope LocalScope(this, VD); -InitLinkScope ILS(this, InitLink::Decl(VD)); if (VarT) { unsigned Offset = this->allocateLocalPrimitive( @@ -3912,8 +3911,7 @@ bool Compiler::VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *E) { SourceLocScope SLS(this, E); bool Old = InitStackActive; - InitStackActive = - !(E->getUsedContext()->getDeclKind() == Decl::CXXConstructor); + InitStackActive = !isa(E->getUsedContext()); bool Result = this->delegate(E->getExpr()); InitStackActive = Old; return Result; diff --git a/clang/test/AST/Interp/records.cpp b/clang/test/AST/Interp/records.cpp index 1554e54275598..9f341f5bc6d1d 100644 --- a/clang/test/AST/Interp/records.cpp +++ b/clang/test/AST/Interp/records.cpp @@ -1482,15 +1482,3 @@ namespace FloatAPValue { ClassTemplateArgRefTemplate ClassTemplateArgRefObj; } #endif - -namespace LocalWithThisPtrInit { - struct S { -int i; -int *p = - }; - constexpr int foo() { -S s{2}; -return *s.p; - } - static_assert(foo() == 2, ""); -} ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 86187ed - [clang][Interp] Fix init chain in local initializers
Author: Timm Bäder Date: 2024-07-04T08:41:09+02:00 New Revision: 86187ed2998e43be62176c2c4a7b204cc52f6ce6 URL: https://github.com/llvm/llvm-project/commit/86187ed2998e43be62176c2c4a7b204cc52f6ce6 DIFF: https://github.com/llvm/llvm-project/commit/86187ed2998e43be62176c2c4a7b204cc52f6ce6.diff LOG: [clang][Interp] Fix init chain in local initializers Added: Modified: clang/lib/AST/Interp/Compiler.cpp clang/test/AST/Interp/records.cpp Removed: diff --git a/clang/lib/AST/Interp/Compiler.cpp b/clang/lib/AST/Interp/Compiler.cpp index 775cabf7f8c59..2af4c38c5ac3d 100644 --- a/clang/lib/AST/Interp/Compiler.cpp +++ b/clang/lib/AST/Interp/Compiler.cpp @@ -3577,6 +3577,7 @@ VarCreationState Compiler::visitVarDecl(const VarDecl *VD, bool Topleve return !Init || (checkDecl() && initGlobal(*GlobalIndex)); } else { VariableScope LocalScope(this, VD); +InitLinkScope ILS(this, InitLink::Decl(VD)); if (VarT) { unsigned Offset = this->allocateLocalPrimitive( @@ -3911,7 +3912,8 @@ bool Compiler::VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *E) { SourceLocScope SLS(this, E); bool Old = InitStackActive; - InitStackActive = !isa(E->getUsedContext()); + InitStackActive = + !(E->getUsedContext()->getDeclKind() == Decl::CXXConstructor); bool Result = this->delegate(E->getExpr()); InitStackActive = Old; return Result; diff --git a/clang/test/AST/Interp/records.cpp b/clang/test/AST/Interp/records.cpp index 9f341f5bc6d1d..1554e54275598 100644 --- a/clang/test/AST/Interp/records.cpp +++ b/clang/test/AST/Interp/records.cpp @@ -1482,3 +1482,15 @@ namespace FloatAPValue { ClassTemplateArgRefTemplate ClassTemplateArgRefObj; } #endif + +namespace LocalWithThisPtrInit { + struct S { +int i; +int *p = + }; + constexpr int foo() { +S s{2}; +return *s.p; + } + static_assert(foo() == 2, ""); +} ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 54aa1d2 - [clang][Interp] Fix initializing atomic record types
Author: Timm Bäder Date: 2024-07-03T16:38:09+02:00 New Revision: 54aa1d28b6a26b4980df4d5448fb64d19dc1a100 URL: https://github.com/llvm/llvm-project/commit/54aa1d28b6a26b4980df4d5448fb64d19dc1a100 DIFF: https://github.com/llvm/llvm-project/commit/54aa1d28b6a26b4980df4d5448fb64d19dc1a100.diff LOG: [clang][Interp] Fix initializing atomic record types Remove the atomic type when visiting InitListExprs. Added: Modified: clang/lib/AST/Interp/Compiler.cpp clang/test/CodeGenCXX/atomicinit.cpp Removed: diff --git a/clang/lib/AST/Interp/Compiler.cpp b/clang/lib/AST/Interp/Compiler.cpp index 9ca71e0496989..775cabf7f8c59 100644 --- a/clang/lib/AST/Interp/Compiler.cpp +++ b/clang/lib/AST/Interp/Compiler.cpp @@ -1285,7 +1285,13 @@ bool Compiler::VisitArraySubscriptExpr(const ArraySubscriptExpr *E) { template bool Compiler::visitInitList(ArrayRef Inits, const Expr *ArrayFiller, const Expr *E) { - if (E->getType()->isVoidType()) + + QualType QT = E->getType(); + + if (const auto *AT = QT->getAs()) +QT = AT->getValueType(); + + if (QT->isVoidType()) return this->emitInvalid(E); // Handle discarding first. @@ -1298,17 +1304,16 @@ bool Compiler::visitInitList(ArrayRef Inits, } // Primitive values. - if (std::optional T = classify(E->getType())) { + if (std::optional T = classify(QT)) { assert(!DiscardResult); if (Inits.size() == 0) - return this->visitZeroInitializer(*T, E->getType(), E); + return this->visitZeroInitializer(*T, QT, E); assert(Inits.size() == 1); return this->delegate(Inits[0]); } - QualType T = E->getType(); - if (T->isRecordType()) { -const Record *R = getRecord(E->getType()); + if (QT->isRecordType()) { +const Record *R = getRecord(QT); if (Inits.size() == 1 && E->getType() == Inits[0]->getType()) return this->delegate(Inits[0]); @@ -1405,8 +1410,8 @@ bool Compiler::visitInitList(ArrayRef Inits, return this->emitFinishInit(E); } - if (T->isArrayType()) { -if (Inits.size() == 1 && E->getType() == Inits[0]->getType()) + if (QT->isArrayType()) { +if (Inits.size() == 1 && QT == Inits[0]->getType()) return this->delegate(Inits[0]); unsigned ElementIndex = 0; @@ -1438,7 +1443,7 @@ bool Compiler::visitInitList(ArrayRef Inits, // FIXME: This should go away. if (ArrayFiller) { const ConstantArrayType *CAT = - Ctx.getASTContext().getAsConstantArrayType(E->getType()); + Ctx.getASTContext().getAsConstantArrayType(QT); uint64_t NumElems = CAT->getZExtSize(); for (; ElementIndex != NumElems; ++ElementIndex) { @@ -1450,7 +1455,7 @@ bool Compiler::visitInitList(ArrayRef Inits, return this->emitFinishInit(E); } - if (const auto *ComplexTy = E->getType()->getAs()) { + if (const auto *ComplexTy = QT->getAs()) { unsigned NumInits = Inits.size(); if (NumInits == 1) @@ -1480,7 +1485,7 @@ bool Compiler::visitInitList(ArrayRef Inits, return true; } - if (const auto *VecT = E->getType()->getAs()) { + if (const auto *VecT = QT->getAs()) { unsigned NumVecElements = VecT->getNumElements(); assert(NumVecElements >= Inits.size()); diff --git a/clang/test/CodeGenCXX/atomicinit.cpp b/clang/test/CodeGenCXX/atomicinit.cpp index a568f17b90d0c..b507a22e84bc1 100644 --- a/clang/test/CodeGenCXX/atomicinit.cpp +++ b/clang/test/CodeGenCXX/atomicinit.cpp @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -fno-inline-functions %s -emit-llvm -O1 -o - -triple=i686-apple-darwin9 -std=c++11 | FileCheck %s +// RUN: %clang_cc1 -fno-inline-functions %s -emit-llvm -O1 -o - -triple=i686-apple-darwin9 -std=c++11 -fexperimental-new-constant-interpreter | FileCheck %s // CHECK-DAG: @PR22043 ={{.*}} local_unnamed_addr global i32 0, align 4 typedef _Atomic(int) AtomicInt; ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] c1af97d - [clang][Interp] Diagnose comparisons against one-past-end pointers
Author: Timm Bäder Date: 2024-07-03T14:07:28+02:00 New Revision: c1af97db1e3846db1188149afe86cee6585dfc9a URL: https://github.com/llvm/llvm-project/commit/c1af97db1e3846db1188149afe86cee6585dfc9a DIFF: https://github.com/llvm/llvm-project/commit/c1af97db1e3846db1188149afe86cee6585dfc9a.diff LOG: [clang][Interp] Diagnose comparisons against one-past-end pointers Added: Modified: clang/lib/AST/Interp/Interp.h clang/lib/AST/Interp/Pointer.cpp clang/lib/AST/Interp/Pointer.h clang/test/AST/Interp/literals.cpp Removed: diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h index 328db219ca628..5d8362b4fa881 100644 --- a/clang/lib/AST/Interp/Interp.h +++ b/clang/lib/AST/Interp/Interp.h @@ -922,6 +922,7 @@ inline bool CmpHelperEQ(InterpState , CodePtr OpPC, CompareFn Fn) { return true; } + // Reject comparisons to weak pointers. for (const auto : {LHS, RHS}) { if (P.isZero()) continue; @@ -934,6 +935,20 @@ inline bool CmpHelperEQ(InterpState , CodePtr OpPC, CompareFn Fn) { } if (!Pointer::hasSameBase(LHS, RHS)) { +if (LHS.isOnePastEnd() && !RHS.isOnePastEnd() && !RHS.isZero() && +RHS.getOffset() == 0) { + const SourceInfo = S.Current->getSource(OpPC); + S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_past_end) + << LHS.toDiagnosticString(S.getCtx()); + return false; +} else if (RHS.isOnePastEnd() && !LHS.isOnePastEnd() && !LHS.isZero() && + LHS.getOffset() == 0) { + const SourceInfo = S.Current->getSource(OpPC); + S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_past_end) + << RHS.toDiagnosticString(S.getCtx()); + return false; +} + S.Stk.push(BoolT::from(Fn(ComparisonCategoryResult::Unordered))); return true; } else { diff --git a/clang/lib/AST/Interp/Pointer.cpp b/clang/lib/AST/Interp/Pointer.cpp index 4070d0c54225d..d6603f91fb127 100644 --- a/clang/lib/AST/Interp/Pointer.cpp +++ b/clang/lib/AST/Interp/Pointer.cpp @@ -143,7 +143,7 @@ APValue Pointer::toAPValue() const { if (isDummy() || isUnknownSizeArray() || Desc->asExpr()) return APValue(Base, CharUnits::Zero(), Path, - /*IsOnePastEnd=*/false, /*IsNullPtr=*/false); + /*IsOnePastEnd=*/isOnePastEnd(), /*IsNullPtr=*/false); // TODO: compute the offset into the object. CharUnits Offset = CharUnits::Zero(); @@ -181,7 +181,8 @@ APValue Pointer::toAPValue() const { // Just invert the order of the elements. std::reverse(Path.begin(), Path.end()); - return APValue(Base, Offset, Path, /*IsOnePastEnd=*/false, /*IsNullPtr=*/false); + return APValue(Base, Offset, Path, /*IsOnePastEnd=*/isOnePastEnd(), + /*IsNullPtr=*/false); } void Pointer::print(llvm::raw_ostream ) const { @@ -348,7 +349,7 @@ std::optional Pointer::toRValue(const Context ) const { // Invalid pointers. if (Ptr.isDummy() || !Ptr.isLive() || !Ptr.isBlockPointer() || -(!Ptr.isUnknownSizeArray() && Ptr.isOnePastEnd())) +Ptr.isPastEnd()) return false; // Primitive values. diff --git a/clang/lib/AST/Interp/Pointer.h b/clang/lib/AST/Interp/Pointer.h index 5faec75cc3ec5..4f277eb7d9e58 100644 --- a/clang/lib/AST/Interp/Pointer.h +++ b/clang/lib/AST/Interp/Pointer.h @@ -556,10 +556,18 @@ class Pointer { if (isUnknownSizeArray()) return false; -return isElementPastEnd() || +return isElementPastEnd() || isPastEnd() || (getSize() == getOffset() && !isZeroSizeArray()); } + /// Checks if the pointer points past the end of the object. + bool isPastEnd() const { +if (isIntegralPointer()) + return false; + +return !isZero() && Offset > PointeeStorage.BS.Pointee->getSize(); + } + /// Checks if the pointer is an out-of-bounds element pointer. bool isElementPastEnd() const { return Offset == PastEndMark; } diff --git a/clang/test/AST/Interp/literals.cpp b/clang/test/AST/Interp/literals.cpp index f70ca79e216da..630d9b53cca25 100644 --- a/clang/test/AST/Interp/literals.cpp +++ b/clang/test/AST/Interp/literals.cpp @@ -1266,3 +1266,13 @@ static_assert(ReturnInStmtExpr() == 1, ""); // both-error {{not an integral cons // both-note {{in call to}} #endif + +namespace ComparisonAgainstOnePastEnd { + int a, b; + static_assert( + 1 == , ""); // both-error {{not an integral constant expression}} \ + // both-note {{comparison against pointer ' + 1' that points past the end of a complete object has unspecified value}} + static_assert( == + 1, ""); // both-error {{not an integral constant expression}} \ + // both-note {{comparison against pointer ' + 1' that points past the end of a complete object has unspecified value}} + +
[clang] c5f7f38 - [clang][Interp][NFC] Make some local pointers const
Author: Timm Bäder Date: 2024-07-02T13:17:06+02:00 New Revision: c5f7f380314c7d290e039e9c35562e1cedc01268 URL: https://github.com/llvm/llvm-project/commit/c5f7f380314c7d290e039e9c35562e1cedc01268 DIFF: https://github.com/llvm/llvm-project/commit/c5f7f380314c7d290e039e9c35562e1cedc01268.diff LOG: [clang][Interp][NFC] Make some local pointers const Added: Modified: clang/lib/AST/Interp/Compiler.cpp Removed: diff --git a/clang/lib/AST/Interp/Compiler.cpp b/clang/lib/AST/Interp/Compiler.cpp index 739a65070b21d..9ca71e0496989 100644 --- a/clang/lib/AST/Interp/Compiler.cpp +++ b/clang/lib/AST/Interp/Compiler.cpp @@ -4033,7 +4033,7 @@ template bool Compiler::visitLoopBody(const Stmt *S) { return true; if (const auto *CS = dyn_cast(S)) { -for (auto *InnerStmt : CS->body()) +for (const auto *InnerStmt : CS->body()) if (!visitStmt(InnerStmt)) return false; return true; @@ -4045,7 +4045,7 @@ template bool Compiler::visitLoopBody(const Stmt *S) { template bool Compiler::visitCompoundStmt(const CompoundStmt *S) { BlockScope Scope(this); - for (auto *InnerStmt : S->body()) + for (const auto *InnerStmt : S->body()) if (!visitStmt(InnerStmt)) return false; return true; ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] c49c386 - [clang][Interp] Reject StmtExprs containing return statements
Author: Timm Bäder Date: 2024-07-02T12:15:24+02:00 New Revision: c49c386caaf7132908995749fed4894cfa1b62d1 URL: https://github.com/llvm/llvm-project/commit/c49c386caaf7132908995749fed4894cfa1b62d1 DIFF: https://github.com/llvm/llvm-project/commit/c49c386caaf7132908995749fed4894cfa1b62d1.diff LOG: [clang][Interp] Reject StmtExprs containing return statements Added: Modified: clang/lib/AST/Interp/Compiler.cpp clang/lib/AST/Interp/Compiler.h clang/lib/AST/Interp/Interp.h clang/lib/AST/Interp/Opcodes.td clang/test/AST/Interp/literals.cpp Removed: diff --git a/clang/lib/AST/Interp/Compiler.cpp b/clang/lib/AST/Interp/Compiler.cpp index 3d9c72e2b6dee..739a65070b21d 100644 --- a/clang/lib/AST/Interp/Compiler.cpp +++ b/clang/lib/AST/Interp/Compiler.cpp @@ -154,6 +154,19 @@ template class SwitchScope final : public LabelScope { CaseMap OldCaseLabels; }; +template class StmtExprScope final { +public: + StmtExprScope(Compiler *Ctx) : Ctx(Ctx), OldFlag(Ctx->InStmtExpr) { +Ctx->InStmtExpr = true; + } + + ~StmtExprScope() { Ctx->InStmtExpr = OldFlag; } + +private: + Compiler *Ctx; + bool OldFlag; +}; + } // namespace interp } // namespace clang @@ -3028,6 +3041,7 @@ bool Compiler::VisitCXXStdInitializerListExpr( template bool Compiler::VisitStmtExpr(const StmtExpr *E) { BlockScope BS(this); + StmtExprScope SS(this); const CompoundStmt *CS = E->getSubStmt(); const Stmt *Result = CS->getStmtExprResult(); @@ -4056,6 +4070,9 @@ bool Compiler::visitDeclStmt(const DeclStmt *DS) { template bool Compiler::visitReturnStmt(const ReturnStmt *RS) { + if (this->InStmtExpr) +return this->emitUnsupported(RS); + if (const Expr *RE = RS->getRetValue()) { ExprScope RetScope(this); if (ReturnType) { diff --git a/clang/lib/AST/Interp/Compiler.h b/clang/lib/AST/Interp/Compiler.h index 67bd7efb3b091..d28526c76fe13 100644 --- a/clang/lib/AST/Interp/Compiler.h +++ b/clang/lib/AST/Interp/Compiler.h @@ -39,6 +39,7 @@ template class SourceLocScope; template class LoopScope; template class LabelScope; template class SwitchScope; +template class StmtExprScope; template class Compiler; struct InitLink { @@ -334,6 +335,7 @@ class Compiler : public ConstStmtVisitor, bool>, friend class LoopScope; friend class LabelScope; friend class SwitchScope; + friend class StmtExprScope; /// Emits a zero initializer. bool visitZeroInitializer(PrimType T, QualType QT, const Expr *E); @@ -398,6 +400,8 @@ class Compiler : public ConstStmtVisitor, bool>, /// Flag indicating if return value is to be discarded. bool DiscardResult = false; + bool InStmtExpr = false; + /// Flag inidicating if we're initializing an already created /// variable. This is set in visitInitializer(). bool Initializing = false; diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h index ff6d50ab9b6f8..328db219ca628 100644 --- a/clang/lib/AST/Interp/Interp.h +++ b/clang/lib/AST/Interp/Interp.h @@ -2618,6 +2618,13 @@ inline bool Invalid(InterpState , CodePtr OpPC) { return false; } +inline bool Unsupported(InterpState , CodePtr OpPC) { + const SourceLocation = S.Current->getLocation(OpPC); + S.FFDiag(Loc, diag::note_constexpr_stmt_expr_unsupported) + << S.Current->getRange(OpPC); + return false; +} + /// Do nothing and just abort execution. inline bool Error(InterpState , CodePtr OpPC) { return false; } diff --git a/clang/lib/AST/Interp/Opcodes.td b/clang/lib/AST/Interp/Opcodes.td index 81e7b812da237..8d01fe1ac2bd1 100644 --- a/clang/lib/AST/Interp/Opcodes.td +++ b/clang/lib/AST/Interp/Opcodes.td @@ -714,6 +714,7 @@ def Dup : Opcode { // [] -> [] def Invalid : Opcode {} +def Unsupported : Opcode {} def Error : Opcode {} def InvalidCast : Opcode { let Args = [ArgCastKind]; diff --git a/clang/test/AST/Interp/literals.cpp b/clang/test/AST/Interp/literals.cpp index 3abaf89e8bd01..f70ca79e216da 100644 --- a/clang/test/AST/Interp/literals.cpp +++ b/clang/test/AST/Interp/literals.cpp @@ -1255,4 +1255,14 @@ constexpr int StmtExprEval() { return 1; } static_assert(StmtExprEval() == 2, ""); + +constexpr int ReturnInStmtExpr() { // both-error {{never produces a constant expression}} + return ({ + return 1; // both-note 2{{this use of statement expressions is not supported in a constant expression}} + 2; + }); +} +static_assert(ReturnInStmtExpr() == 1, ""); // both-error {{not an integral constant expression}} \ +// both-note {{in call to}} + #endif ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 62e6255 - [clang][Interp] Add missing fallthrough in loops
Author: Timm Bäder Date: 2024-07-02T11:51:07+02:00 New Revision: 62e6255a58eb0e9bb31e366a9e30d5c1eaadd004 URL: https://github.com/llvm/llvm-project/commit/62e6255a58eb0e9bb31e366a9e30d5c1eaadd004 DIFF: https://github.com/llvm/llvm-project/commit/62e6255a58eb0e9bb31e366a9e30d5c1eaadd004.diff LOG: [clang][Interp] Add missing fallthrough in loops Added: Modified: clang/lib/AST/Interp/Compiler.cpp clang/test/AST/Interp/literals.cpp Removed: diff --git a/clang/lib/AST/Interp/Compiler.cpp b/clang/lib/AST/Interp/Compiler.cpp index 77c7e20632881..3d9c72e2b6dee 100644 --- a/clang/lib/AST/Interp/Compiler.cpp +++ b/clang/lib/AST/Interp/Compiler.cpp @@ -4139,6 +4139,7 @@ bool Compiler::visitWhileStmt(const WhileStmt *S) { LabelTy EndLabel = this->getLabel(); // Label after the loop. LoopScope LS(this, EndLabel, CondLabel); + this->fallthrough(CondLabel); this->emitLabel(CondLabel); if (const DeclStmt *CondDecl = S->getConditionVariableDeclStmt()) @@ -4174,12 +4175,14 @@ template bool Compiler::visitDoStmt(const DoStmt *S) { LoopScope LS(this, EndLabel, CondLabel); LocalScope Scope(this); + this->fallthrough(StartLabel); this->emitLabel(StartLabel); { DestructorScope DS(Scope); if (!this->visitLoopBody(Body)) return false; +this->fallthrough(CondLabel); this->emitLabel(CondLabel); if (!this->visitBool(Cond)) return false; @@ -4187,6 +4190,7 @@ template bool Compiler::visitDoStmt(const DoStmt *S) { if (!this->jumpTrue(StartLabel)) return false; + this->fallthrough(EndLabel); this->emitLabel(EndLabel); return true; } @@ -4207,6 +4211,7 @@ bool Compiler::visitForStmt(const ForStmt *S) { if (Init && !this->visitStmt(Init)) return false; + this->fallthrough(CondLabel); this->emitLabel(CondLabel); if (const DeclStmt *CondDecl = S->getConditionVariableDeclStmt()) @@ -4225,6 +4230,7 @@ bool Compiler::visitForStmt(const ForStmt *S) { if (Body && !this->visitLoopBody(Body)) return false; +this->fallthrough(IncLabel); this->emitLabel(IncLabel); if (Inc && !this->discard(Inc)) return false; @@ -4232,6 +4238,7 @@ bool Compiler::visitForStmt(const ForStmt *S) { if (!this->jump(CondLabel)) return false; + this->fallthrough(EndLabel); this->emitLabel(EndLabel); return true; } @@ -4263,6 +4270,7 @@ bool Compiler::visitCXXForRangeStmt(const CXXForRangeStmt *S) { return false; // Now the condition as well as the loop variable assignment. + this->fallthrough(CondLabel); this->emitLabel(CondLabel); if (!this->visitBool(Cond)) return false; @@ -4279,13 +4287,16 @@ bool Compiler::visitCXXForRangeStmt(const CXXForRangeStmt *S) { if (!this->visitLoopBody(Body)) return false; + this->fallthrough(IncLabel); this->emitLabel(IncLabel); if (!this->discard(Inc)) return false; } + if (!this->jump(CondLabel)) return false; + this->fallthrough(EndLabel); this->emitLabel(EndLabel); return true; } diff --git a/clang/test/AST/Interp/literals.cpp b/clang/test/AST/Interp/literals.cpp index a7a602ec355d5..3abaf89e8bd01 100644 --- a/clang/test/AST/Interp/literals.cpp +++ b/clang/test/AST/Interp/literals.cpp @@ -1243,3 +1243,16 @@ namespace Extern { static_assert(() == , ""); #endif } + +#if __cplusplus >= 201402L +constexpr int StmtExprEval() { + if (({ +while (0); +true; + })) { +return 2; + } + return 1; +} +static_assert(StmtExprEval() == 2, ""); +#endif ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 030ea6d - [clang][Interp] Only check toplevel declarations
Author: Timm Bäder Date: 2024-07-02T11:50:41+02:00 New Revision: 030ea6d38b7c6afc191bc721be9d59e89bbf7631 URL: https://github.com/llvm/llvm-project/commit/030ea6d38b7c6afc191bc721be9d59e89bbf7631 DIFF: https://github.com/llvm/llvm-project/commit/030ea6d38b7c6afc191bc721be9d59e89bbf7631.diff LOG: [clang][Interp] Only check toplevel declarations Added: Modified: clang/lib/AST/Interp/Compiler.cpp clang/lib/AST/Interp/Compiler.h clang/test/AST/Interp/c.c Removed: diff --git a/clang/lib/AST/Interp/Compiler.cpp b/clang/lib/AST/Interp/Compiler.cpp index 5ae36dae6557d..77c7e20632881 100644 --- a/clang/lib/AST/Interp/Compiler.cpp +++ b/clang/lib/AST/Interp/Compiler.cpp @@ -3460,7 +3460,7 @@ bool Compiler::visitDecl(const VarDecl *VD, bool ConstantContext) { } // Create and initialize the variable. - if (!this->visitVarDecl(VD)) + if (!this->visitVarDecl(VD, /*Toplevel=*/true)) return false; // Get a pointer to the variable @@ -3507,7 +3507,7 @@ bool Compiler::visitDecl(const VarDecl *VD, bool ConstantContext) { } template -VarCreationState Compiler::visitVarDecl(const VarDecl *VD) { +VarCreationState Compiler::visitVarDecl(const VarDecl *VD, bool Toplevel) { // We don't know what to do with these, so just return false. if (VD->getType().isNull()) return false; @@ -3521,7 +3521,7 @@ VarCreationState Compiler::visitVarDecl(const VarDecl *VD) { std::optional VarT = classify(VD->getType()); auto checkDecl = [&]() -> bool { -bool NeedsOp = VD->isLocalVarDecl() && VD->isStaticLocal(); +bool NeedsOp = !Toplevel && VD->isLocalVarDecl() && VD->isStaticLocal(); return !NeedsOp || this->emitCheckDecl(VD, VD); }; @@ -4991,7 +4991,7 @@ bool Compiler::visitDeclRef(const ValueDecl *D, const Expr *E) { if ((VD->hasGlobalStorage() || VD->isLocalVarDecl() || VD->isStaticDataMember()) && typeShouldBeVisited(VD->getType())) { - auto VarState = this->visitVarDecl(VD); + auto VarState = this->visitVarDecl(VD, true); if (VarState.notCreated()) return true; if (!VarState) @@ -5004,7 +5004,7 @@ bool Compiler::visitDeclRef(const ValueDecl *D, const Expr *E) { if (const auto *VD = dyn_cast(D); VD && VD->getAnyInitializer() && VD->getType().isConstant(Ctx.getASTContext()) && !VD->isWeak()) { -auto VarState = this->visitVarDecl(VD); +auto VarState = this->visitVarDecl(VD, true); if (VarState.notCreated()) return true; if (!VarState) diff --git a/clang/lib/AST/Interp/Compiler.h b/clang/lib/AST/Interp/Compiler.h index d188ce2200664..67bd7efb3b091 100644 --- a/clang/lib/AST/Interp/Compiler.h +++ b/clang/lib/AST/Interp/Compiler.h @@ -260,7 +260,7 @@ class Compiler : public ConstStmtVisitor, bool>, /// intact. bool delegate(const Expr *E); /// Creates and initializes a variable from the given decl. - VarCreationState visitVarDecl(const VarDecl *VD); + VarCreationState visitVarDecl(const VarDecl *VD, bool Toplevel = false); /// Visit an APValue. bool visitAPValue(const APValue , PrimType ValType, const Expr *E); bool visitAPValueInitializer(const APValue , const Expr *E); diff --git a/clang/test/AST/Interp/c.c b/clang/test/AST/Interp/c.c index 684658da26a0e..9ec305d59c68c 100644 --- a/clang/test/AST/Interp/c.c +++ b/clang/test/AST/Interp/c.c @@ -293,3 +293,11 @@ void SuperSpecialFunc(void) { const int SuperSpecialCase = 10; _Static_assert((sizeof(SuperSpecialCase) == 12 && SuperSpecialCase == 3) || SuperSpecialCase == 10, ""); // pedantic-warning {{GNU extension}} } + + +void T1(void) { + static int *y[1] = {({ static int _x = 20; (void*)0;})}; // all-error {{initializer element is not a compile-time constant}} \ + // pedantic-warning {{use of GNU statement expression extension}} +} + + ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 42fc93d - [clang][Interp][NFC] Make a local pointer const
Author: Timm Bäder Date: 2024-07-01T11:59:56+02:00 New Revision: 42fc93d3ffb35ec1ff5c6584e1b15d5118db7311 URL: https://github.com/llvm/llvm-project/commit/42fc93d3ffb35ec1ff5c6584e1b15d5118db7311 DIFF: https://github.com/llvm/llvm-project/commit/42fc93d3ffb35ec1ff5c6584e1b15d5118db7311.diff LOG: [clang][Interp][NFC] Make a local pointer const Added: Modified: clang/lib/AST/Interp/Compiler.cpp Removed: diff --git a/clang/lib/AST/Interp/Compiler.cpp b/clang/lib/AST/Interp/Compiler.cpp index ff755d503f871..5ae36dae6557d 100644 --- a/clang/lib/AST/Interp/Compiler.cpp +++ b/clang/lib/AST/Interp/Compiler.cpp @@ -4039,7 +4039,7 @@ bool Compiler::visitCompoundStmt(const CompoundStmt *S) { template bool Compiler::visitDeclStmt(const DeclStmt *DS) { - for (auto *D : DS->decls()) { + for (const auto *D : DS->decls()) { if (isa(D)) continue; ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 7f1d672 - [clang][Interp] Diagnose static declarations in constexpr functions
Author: Timm Bäder Date: 2024-07-01T11:58:56+02:00 New Revision: 7f1d672d70eabe010567fcd8c365d27549736c6d URL: https://github.com/llvm/llvm-project/commit/7f1d672d70eabe010567fcd8c365d27549736c6d DIFF: https://github.com/llvm/llvm-project/commit/7f1d672d70eabe010567fcd8c365d27549736c6d.diff LOG: [clang][Interp] Diagnose static declarations in constexpr functions Added: Modified: clang/lib/AST/Interp/Compiler.cpp clang/lib/AST/Interp/Interp.h clang/lib/AST/Interp/Opcodes.td clang/test/AST/Interp/cxx23.cpp Removed: diff --git a/clang/lib/AST/Interp/Compiler.cpp b/clang/lib/AST/Interp/Compiler.cpp index 424f4f84a0167..ff755d503f871 100644 --- a/clang/lib/AST/Interp/Compiler.cpp +++ b/clang/lib/AST/Interp/Compiler.cpp @@ -3520,6 +3520,11 @@ VarCreationState Compiler::visitVarDecl(const VarDecl *VD) { const Expr *Init = VD->getInit(); std::optional VarT = classify(VD->getType()); + auto checkDecl = [&]() -> bool { +bool NeedsOp = VD->isLocalVarDecl() && VD->isStaticLocal(); +return !NeedsOp || this->emitCheckDecl(VD, VD); + }; + if (Context::shouldBeGloballyIndexed(VD)) { auto initGlobal = [&](unsigned GlobalIndex) -> bool { assert(Init); @@ -3527,20 +3532,22 @@ VarCreationState Compiler::visitVarDecl(const VarDecl *VD) { if (VarT) { if (!this->visit(Init)) - return false; -return this->emitInitGlobal(*VarT, GlobalIndex, VD); + return checkDecl() && false; + +return checkDecl() && this->emitInitGlobal(*VarT, GlobalIndex, VD); } - return this->visitGlobalInitializer(Init, GlobalIndex); + + return checkDecl() && this->visitGlobalInitializer(Init, GlobalIndex); }; // We've already seen and initialized this global. if (std::optional GlobalIndex = P.getGlobal(VD)) { if (P.getPtrGlobal(*GlobalIndex).isInitialized()) -return true; +return checkDecl(); // The previous attempt at initialization might've been unsuccessful, // so let's try this one. - return Init && initGlobal(*GlobalIndex); + return Init && checkDecl() && initGlobal(*GlobalIndex); } std::optional GlobalIndex = P.createGlobal(VD, Init); @@ -3548,9 +3555,10 @@ VarCreationState Compiler::visitVarDecl(const VarDecl *VD) { if (!GlobalIndex) return false; -return !Init || initGlobal(*GlobalIndex); +return !Init || (checkDecl() && initGlobal(*GlobalIndex)); } else { VariableScope LocalScope(this, VD); + if (VarT) { unsigned Offset = this->allocateLocalPrimitive( VD, *VarT, VD->getType().isConstQualified()); diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h index 866593b9af094..ff6d50ab9b6f8 100644 --- a/clang/lib/AST/Interp/Interp.h +++ b/clang/lib/AST/Interp/Interp.h @@ -2689,6 +2689,25 @@ inline bool DecayPtr(InterpState , CodePtr OpPC) { return true; } +inline bool CheckDecl(InterpState , CodePtr OpPC, const VarDecl *VD) { + // An expression E is a core constant expression unless the evaluation of E + // would evaluate one of the following: [C++23] - a control flow that passes + // through a declaration of a variable with static or thread storage duration + // unless that variable is usable in constant expressions. + assert(VD->isLocalVarDecl() && + VD->isStaticLocal()); // Checked before emitting this. + + if (VD == S.EvaluatingDecl) +return true; + + if (!VD->isUsableInConstantExpressions(S.getCtx())) { +S.CCEDiag(VD->getLocation(), diag::note_constexpr_static_local) +<< (VD->getTSCSpec() == TSCS_unspecified ? 0 : 1) << VD; +return false; + } + return true; +} + //===--===// // Read opcode arguments //===--===// diff --git a/clang/lib/AST/Interp/Opcodes.td b/clang/lib/AST/Interp/Opcodes.td index ddd955fc4cfa4..81e7b812da237 100644 --- a/clang/lib/AST/Interp/Opcodes.td +++ b/clang/lib/AST/Interp/Opcodes.td @@ -63,6 +63,7 @@ def ArgDeclRef : ArgType { let Name = "const DeclRefExpr *"; } def ArgDesc : ArgType { let Name = "const Descriptor *"; } def ArgCCI : ArgType { let Name = "const ComparisonCategoryInfo *"; } def ArgDecl : ArgType { let Name = "const Decl*"; } +def ArgVarDecl : ArgType { let Name = "const VarDecl*"; } //===--===// // Classes of types instructions operate on. @@ -382,6 +383,10 @@ def GetLocal : AccessOpcode { let HasCustomEval = 1; } // [] -> [Pointer] def SetLocal : AccessOpcode { let HasCustomEval = 1; } +def CheckDecl : Opcode { + let Args = [ArgVarDecl]; +} + // [] -> [Value] def GetGlobal : AccessOpcode; def GetGlobalUnchecked : AccessOpcode; diff --git a/clang/test/AST/Interp/cxx23.cpp
[clang] 56a636f - [clang][Interp] Implement StmtExprs
Author: Timm Bäder Date: 2024-06-30T09:28:56+02:00 New Revision: 56a636f2d22890cc71f358ddc50d3e0f2b60bd9c URL: https://github.com/llvm/llvm-project/commit/56a636f2d22890cc71f358ddc50d3e0f2b60bd9c DIFF: https://github.com/llvm/llvm-project/commit/56a636f2d22890cc71f358ddc50d3e0f2b60bd9c.diff LOG: [clang][Interp] Implement StmtExprs Added: Modified: clang/lib/AST/Interp/Compiler.cpp clang/lib/AST/Interp/Compiler.h clang/test/AST/Interp/literals.cpp Removed: diff --git a/clang/lib/AST/Interp/Compiler.cpp b/clang/lib/AST/Interp/Compiler.cpp index 8b6f7f644a778..424f4f84a0167 100644 --- a/clang/lib/AST/Interp/Compiler.cpp +++ b/clang/lib/AST/Interp/Compiler.cpp @@ -3025,6 +3025,32 @@ bool Compiler::VisitCXXStdInitializerListExpr( return this->emitInitFieldPtr(R->getField(1u)->Offset, E); } +template +bool Compiler::VisitStmtExpr(const StmtExpr *E) { + BlockScope BS(this); + + const CompoundStmt *CS = E->getSubStmt(); + const Stmt *Result = CS->getStmtExprResult(); + for (const Stmt *S : CS->body()) { +if (S != Result) { + if (!this->visitStmt(S)) +return false; + continue; +} + +assert(S == Result); +// This better produces a value (i.e. is an expression). +if (const Expr *ResultExpr = dyn_cast(S)) { + if (DiscardResult) +return this->discard(ResultExpr); + return this->delegate(ResultExpr); +} +return false; + } + + return true; +} + template bool Compiler::discard(const Expr *E) { OptionScope Scope(this, /*NewDiscardResult=*/true, /*NewInitializing=*/false); diff --git a/clang/lib/AST/Interp/Compiler.h b/clang/lib/AST/Interp/Compiler.h index 89e36f9201a41..d188ce2200664 100644 --- a/clang/lib/AST/Interp/Compiler.h +++ b/clang/lib/AST/Interp/Compiler.h @@ -183,6 +183,7 @@ class Compiler : public ConstStmtVisitor, bool>, bool VisitExtVectorElementExpr(const ExtVectorElementExpr *E); bool VisitObjCBoxedExpr(const ObjCBoxedExpr *E); bool VisitCXXStdInitializerListExpr(const CXXStdInitializerListExpr *E); + bool VisitStmtExpr(const StmtExpr *E); // Statements. bool visitCompoundStmt(const CompoundStmt *S); diff --git a/clang/test/AST/Interp/literals.cpp b/clang/test/AST/Interp/literals.cpp index ef98b4947e64f..a7a602ec355d5 100644 --- a/clang/test/AST/Interp/literals.cpp +++ b/clang/test/AST/Interp/literals.cpp @@ -1213,6 +1213,18 @@ constexpr int externvar1() { // both-error {{never produces a constant expressio return arr[0]; // ref-note {{read of non-constexpr variable 'arr'}} \ // expected-note {{indexing of array without known bound}} } + +namespace StmtExprs { + constexpr int foo() { + ({ + int i; + for (i = 0; i < 76; i++) {} + i; // both-warning {{expression result unused}} +}); +return 76; + } + static_assert(foo() == 76, ""); +} #endif namespace Extern { ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 5a8c4b5 - [clang][Interp] Don't allow reading from non-const blocks when returning
Author: Timm Bäder Date: 2024-06-29T21:10:25+02:00 New Revision: 5a8c4b597beed38e392f221042d29f475a3d1626 URL: https://github.com/llvm/llvm-project/commit/5a8c4b597beed38e392f221042d29f475a3d1626 DIFF: https://github.com/llvm/llvm-project/commit/5a8c4b597beed38e392f221042d29f475a3d1626.diff LOG: [clang][Interp] Don't allow reading from non-const blocks when returning Added: Modified: clang/lib/AST/Interp/EvalEmitter.cpp clang/test/AST/Interp/const-temporaries.cpp Removed: diff --git a/clang/lib/AST/Interp/EvalEmitter.cpp b/clang/lib/AST/Interp/EvalEmitter.cpp index f4854adba9348..d17151416b44b 100644 --- a/clang/lib/AST/Interp/EvalEmitter.cpp +++ b/clang/lib/AST/Interp/EvalEmitter.cpp @@ -151,6 +151,11 @@ template <> bool EvalEmitter::emitRet(const SourceInfo ) { // Implicitly convert lvalue to rvalue, if requested. if (ConvertResultToRValue) { +// Never allow reading from a non-const pointer, unless the memory +// has been created in this evaluation. +if (!Ptr.isConst() && Ptr.block()->getEvalID() != Ctx.getEvalID()) + return false; + if (std::optional V = Ptr.toRValue(Ctx)) { EvalResult.setValue(*V); } else { diff --git a/clang/test/AST/Interp/const-temporaries.cpp b/clang/test/AST/Interp/const-temporaries.cpp index bbb95b3c3dff7..1dc16ef63a846 100644 --- a/clang/test/AST/Interp/const-temporaries.cpp +++ b/clang/test/AST/Interp/const-temporaries.cpp @@ -90,3 +90,12 @@ struct R { mutable long x; }; struct Z2 { const R , y; }; Z2 z2 = { R{1}, z2.x.x = 10 }; +// CHECK: __cxa_atexit({{.*}} @_ZN1BD1Ev, {{.*}} @b + +// CHECK: define +// CHECK-NOT: @_ZGRN21ModifyStaticTemporary1cE_ +// CHECK: store {{.*}} @_ZGRN21ModifyStaticTemporary1cE_, {{.*}} @_ZN21ModifyStaticTemporary1cE +// CHECK: add +// CHECK: store +// CHECK: load {{.*}} @_ZN21ModifyStaticTemporary1bE +// CHECK: store {{.*}} @_ZN21ModifyStaticTemporary1cE ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 40f4bd1 - [clang][Interp] Allow reading mutable members if they were created...
Author: Timm Bäder Date: 2024-06-29T21:10:24+02:00 New Revision: 40f4bd18f2fb01731fa7891fb7349e05dc98aeec URL: https://github.com/llvm/llvm-project/commit/40f4bd18f2fb01731fa7891fb7349e05dc98aeec DIFF: https://github.com/llvm/llvm-project/commit/40f4bd18f2fb01731fa7891fb7349e05dc98aeec.diff LOG: [clang][Interp] Allow reading mutable members if they were created... ... in this evaluation. Added: clang/test/AST/Interp/mutable.cpp Modified: clang/lib/AST/Interp/Context.cpp clang/lib/AST/Interp/Context.h clang/lib/AST/Interp/EvalEmitter.cpp clang/lib/AST/Interp/Interp.cpp clang/lib/AST/Interp/InterpBlock.cpp clang/lib/AST/Interp/InterpBlock.h clang/lib/AST/Interp/InterpFrame.cpp clang/lib/AST/Interp/Program.cpp clang/test/AST/Interp/const-temporaries.cpp Removed: diff --git a/clang/lib/AST/Interp/Context.cpp b/clang/lib/AST/Interp/Context.cpp index 22ccae4fa30f8..913e8d514282a 100644 --- a/clang/lib/AST/Interp/Context.cpp +++ b/clang/lib/AST/Interp/Context.cpp @@ -39,6 +39,7 @@ bool Context::isPotentialConstantExpr(State , const FunctionDecl *FD) { } bool Context::evaluateAsRValue(State , const Expr *E, APValue ) { + ++EvalID; bool Recursing = !Stk.empty(); Compiler C(*this, *P, Parent, Stk); @@ -65,6 +66,7 @@ bool Context::evaluateAsRValue(State , const Expr *E, APValue ) { } bool Context::evaluate(State , const Expr *E, APValue ) { + ++EvalID; bool Recursing = !Stk.empty(); Compiler C(*this, *P, Parent, Stk); @@ -90,6 +92,7 @@ bool Context::evaluate(State , const Expr *E, APValue ) { bool Context::evaluateAsInitializer(State , const VarDecl *VD, APValue ) { + ++EvalID; bool Recursing = !Stk.empty(); Compiler C(*this, *P, Parent, Stk); diff --git a/clang/lib/AST/Interp/Context.h b/clang/lib/AST/Interp/Context.h index c78dc9a2a471e..b8ea4ad6b3b44 100644 --- a/clang/lib/AST/Interp/Context.h +++ b/clang/lib/AST/Interp/Context.h @@ -109,6 +109,8 @@ class Context final { const Record *getRecord(const RecordDecl *D) const; + unsigned getEvalID() const { return EvalID; } + private: /// Runs a function. bool Run(State , const Function *Func, APValue ); @@ -119,6 +121,8 @@ class Context final { InterpStack Stk; /// Constexpr program. std::unique_ptr P; + /// ID identifying an evaluation. + unsigned EvalID = 0; }; } // namespace interp diff --git a/clang/lib/AST/Interp/EvalEmitter.cpp b/clang/lib/AST/Interp/EvalEmitter.cpp index 6748b305d5c8e..f4854adba9348 100644 --- a/clang/lib/AST/Interp/EvalEmitter.cpp +++ b/clang/lib/AST/Interp/EvalEmitter.cpp @@ -84,7 +84,7 @@ EvalEmitter::LabelTy EvalEmitter::getLabel() { return NextLabel++; } Scope::Local EvalEmitter::createLocal(Descriptor *D) { // Allocate memory for a local. auto Memory = std::make_unique(sizeof(Block) + D->getAllocSize()); - auto *B = new (Memory.get()) Block(D, /*isStatic=*/false); + auto *B = new (Memory.get()) Block(Ctx.getEvalID(), D, /*isStatic=*/false); B->invokeCtor(); // Initialize local variable inline descriptor. diff --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp index 2fe8ab7d0df4b..0411fcad88ad0 100644 --- a/clang/lib/AST/Interp/Interp.cpp +++ b/clang/lib/AST/Interp/Interp.cpp @@ -400,7 +400,7 @@ bool CheckDowncast(InterpState , CodePtr OpPC, const Pointer , bool CheckConst(InterpState , CodePtr OpPC, const Pointer ) { assert(Ptr.isLive() && "Pointer is not live"); - if (!Ptr.isConst()) + if (!Ptr.isConst() || Ptr.isMutable()) return true; // The This pointer is writable in constructors and destructors, @@ -422,9 +422,14 @@ bool CheckConst(InterpState , CodePtr OpPC, const Pointer ) { bool CheckMutable(InterpState , CodePtr OpPC, const Pointer ) { assert(Ptr.isLive() && "Pointer is not live"); - if (!Ptr.isMutable()) { + if (!Ptr.isMutable()) +return true; + + // In C++14 onwards, it is permitted to read a mutable member whose + // lifetime began within the evaluation. + if (S.getLangOpts().CPlusPlus14 && + Ptr.block()->getEvalID() == S.Ctx.getEvalID()) return true; - } const SourceInfo = S.Current->getSource(OpPC); const FieldDecl *Field = Ptr.getField(); diff --git a/clang/lib/AST/Interp/InterpBlock.cpp b/clang/lib/AST/Interp/InterpBlock.cpp index 9b33d1b778fb2..c34ea7634b4a9 100644 --- a/clang/lib/AST/Interp/InterpBlock.cpp +++ b/clang/lib/AST/Interp/InterpBlock.cpp @@ -92,7 +92,8 @@ bool Block::hasPointer(const Pointer *P) const { #endif DeadBlock::DeadBlock(DeadBlock *, Block *Blk) -: Root(Root), B(Blk->Desc, Blk->IsStatic, Blk->IsExtern, /*isDead=*/true) { +: Root(Root), + B(~0u, Blk->Desc, Blk->IsStatic, Blk->IsExtern, /*isDead=*/true) { // Add the block to the chain of dead blocks. if (Root) Root->Prev = this; diff --git
[clang] 37698d9 - [clang][Interp][NFC] Use CheckLoad() in Inc/Dec ops
Author: Timm Bäder Date: 2024-06-29T21:10:24+02:00 New Revision: 37698d924840a229e5a1bece8f5e845e0f5c80a6 URL: https://github.com/llvm/llvm-project/commit/37698d924840a229e5a1bece8f5e845e0f5c80a6 DIFF: https://github.com/llvm/llvm-project/commit/37698d924840a229e5a1bece8f5e845e0f5c80a6.diff LOG: [clang][Interp][NFC] Use CheckLoad() in Inc/Dec ops CheckLoad checks more things than we did before. Added: Modified: clang/lib/AST/Interp/Interp.cpp clang/lib/AST/Interp/Interp.h Removed: diff --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp index 76a0751a006e4..2fe8ab7d0df4b 100644 --- a/clang/lib/AST/Interp/Interp.cpp +++ b/clang/lib/AST/Interp/Interp.cpp @@ -476,23 +476,24 @@ bool CheckGlobalInitialized(InterpState , CodePtr OpPC, const Pointer ) { return false; } -bool CheckLoad(InterpState , CodePtr OpPC, const Pointer ) { - if (!CheckLive(S, OpPC, Ptr, AK_Read)) +bool CheckLoad(InterpState , CodePtr OpPC, const Pointer , + AccessKinds AK) { + if (!CheckLive(S, OpPC, Ptr, AK)) return false; if (!CheckConstant(S, OpPC, Ptr)) return false; - if (!CheckDummy(S, OpPC, Ptr, AK_Read)) + if (!CheckDummy(S, OpPC, Ptr, AK)) return false; if (!CheckExtern(S, OpPC, Ptr)) return false; - if (!CheckRange(S, OpPC, Ptr, AK_Read)) + if (!CheckRange(S, OpPC, Ptr, AK)) return false; - if (!CheckActive(S, OpPC, Ptr, AK_Read)) + if (!CheckActive(S, OpPC, Ptr, AK)) return false; - if (!CheckInitialized(S, OpPC, Ptr, AK_Read)) + if (!CheckInitialized(S, OpPC, Ptr, AK)) return false; - if (!CheckTemporary(S, OpPC, Ptr, AK_Read)) + if (!CheckTemporary(S, OpPC, Ptr, AK)) return false; if (!CheckMutable(S, OpPC, Ptr)) return false; diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h index 75a8f66cc5d50..866593b9af094 100644 --- a/clang/lib/AST/Interp/Interp.h +++ b/clang/lib/AST/Interp/Interp.h @@ -92,7 +92,8 @@ bool CheckConstant(InterpState , CodePtr OpPC, const Descriptor *Desc); bool CheckMutable(InterpState , CodePtr OpPC, const Pointer ); /// Checks if a value can be loaded from a block. -bool CheckLoad(InterpState , CodePtr OpPC, const Pointer ); +bool CheckLoad(InterpState , CodePtr OpPC, const Pointer , + AccessKinds AK = AK_Read); bool CheckInitialized(InterpState , CodePtr OpPC, const Pointer , AccessKinds AK); @@ -724,9 +725,7 @@ bool IncDecHelper(InterpState , CodePtr OpPC, const Pointer ) { template ::T> bool Inc(InterpState , CodePtr OpPC) { const Pointer = S.Stk.pop(); - if (!CheckDummy(S, OpPC, Ptr, AK_Increment)) -return false; - if (!CheckInitialized(S, OpPC, Ptr, AK_Increment)) + if (!CheckLoad(S, OpPC, Ptr, AK_Increment)) return false; return IncDecHelper(S, OpPC, Ptr); @@ -738,9 +737,7 @@ bool Inc(InterpState , CodePtr OpPC) { template ::T> bool IncPop(InterpState , CodePtr OpPC) { const Pointer = S.Stk.pop(); - if (!CheckDummy(S, OpPC, Ptr, AK_Increment)) -return false; - if (!CheckInitialized(S, OpPC, Ptr, AK_Increment)) + if (!CheckLoad(S, OpPC, Ptr, AK_Increment)) return false; return IncDecHelper(S, OpPC, Ptr); @@ -753,9 +750,7 @@ bool IncPop(InterpState , CodePtr OpPC) { template ::T> bool Dec(InterpState , CodePtr OpPC) { const Pointer = S.Stk.pop(); - if (!CheckDummy(S, OpPC, Ptr, AK_Decrement)) -return false; - if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement)) + if (!CheckLoad(S, OpPC, Ptr, AK_Decrement)) return false; return IncDecHelper(S, OpPC, Ptr); @@ -767,9 +762,7 @@ bool Dec(InterpState , CodePtr OpPC) { template ::T> bool DecPop(InterpState , CodePtr OpPC) { const Pointer = S.Stk.pop(); - if (!CheckDummy(S, OpPC, Ptr, AK_Decrement)) -return false; - if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement)) + if (!CheckLoad(S, OpPC, Ptr, AK_Decrement)) return false; return IncDecHelper(S, OpPC, Ptr); @@ -797,9 +790,7 @@ bool IncDecFloatHelper(InterpState , CodePtr OpPC, const Pointer , inline bool Incf(InterpState , CodePtr OpPC, llvm::RoundingMode RM) { const Pointer = S.Stk.pop(); - if (Ptr.isDummy()) -return false; - if (!CheckInitialized(S, OpPC, Ptr, AK_Increment)) + if (!CheckLoad(S, OpPC, Ptr, AK_Increment)) return false; return IncDecFloatHelper(S, OpPC, Ptr, RM); @@ -807,9 +798,7 @@ inline bool Incf(InterpState , CodePtr OpPC, llvm::RoundingMode RM) { inline bool IncfPop(InterpState , CodePtr OpPC, llvm::RoundingMode RM) { const Pointer = S.Stk.pop(); - if (Ptr.isDummy()) -return false; - if (!CheckInitialized(S, OpPC, Ptr, AK_Increment)) + if (!CheckLoad(S, OpPC, Ptr, AK_Increment)) return false; return IncDecFloatHelper(S, OpPC, Ptr, RM); @@ -817,11 +806,7 @@ inline bool IncfPop(InterpState , CodePtr OpPC, llvm::RoundingMode RM) { inline bool
[clang] 8d4aa1f - [clang][Interp] Update global temporaries at the end of a declaration
Author: Timm Bäder Date: 2024-06-29T21:10:24+02:00 New Revision: 8d4aa1f22ea08b12a7958b681e8a265f78cb349f URL: https://github.com/llvm/llvm-project/commit/8d4aa1f22ea08b12a7958b681e8a265f78cb349f DIFF: https://github.com/llvm/llvm-project/commit/8d4aa1f22ea08b12a7958b681e8a265f78cb349f.diff LOG: [clang][Interp] Update global temporaries at the end of a declaration When we create a global temporary variable via a LifetimeExtendedTemporaryDecl, we have an expression to initialize it with, so we evaluate that expression, convert it to an APValue and set it on the LETD. However, when the value is updated after the initialization, we don't propagate the new value to the LETD, which means we will see an outdated value set on the LETD. Fix this by keeping a list of seen LETDs and update them from the global variable at the end of evaluation a declaration. Added: clang/test/AST/Interp/const-temporaries.cpp Modified: clang/lib/AST/Interp/EvalEmitter.cpp clang/lib/AST/Interp/EvalEmitter.h clang/lib/AST/Interp/Interp.h clang/lib/AST/Interp/InterpState.h Removed: diff --git a/clang/lib/AST/Interp/EvalEmitter.cpp b/clang/lib/AST/Interp/EvalEmitter.cpp index a13cd94b0ba1c..6748b305d5c8e 100644 --- a/clang/lib/AST/Interp/EvalEmitter.cpp +++ b/clang/lib/AST/Interp/EvalEmitter.cpp @@ -71,6 +71,7 @@ EvaluationResult EvalEmitter::interpretDecl(const VarDecl *VD, EvalResult.setInvalid(); S.EvaluatingDecl = nullptr; + updateGlobalTemporaries(); return std::move(this->EvalResult); } @@ -237,6 +238,28 @@ bool EvalEmitter::emitDestroy(uint32_t I, const SourceInfo ) { return true; } +/// Global temporaries (LifetimeExtendedTemporary) carry their value +/// around as an APValue, which codegen accesses. +/// We set their value once when creating them, but we don't update it +/// afterwards when code changes it later. +/// This is what we do here. +void EvalEmitter::updateGlobalTemporaries() { + for (const auto &[E, Temp] : S.SeenGlobalTemporaries) { +if (std::optional GlobalIndex = P.getGlobal(E)) { + const Pointer = P.getPtrGlobal(*GlobalIndex); + APValue *Cached = Temp->getOrCreateValue(true); + + if (std::optional T = Ctx.classify(E->getType())) { +TYPE_SWITCH(*T, { *Cached = Ptr.deref().toAPValue(); }); + } else { +if (std::optional APV = Ptr.toRValue(Ctx)) + *Cached = *APV; + } +} + } + S.SeenGlobalTemporaries.clear(); +} + //===--===// // Opcode evaluators //===--===// diff --git a/clang/lib/AST/Interp/EvalEmitter.h b/clang/lib/AST/Interp/EvalEmitter.h index 109e6e0bc0d76..d1e125cae9594 100644 --- a/clang/lib/AST/Interp/EvalEmitter.h +++ b/clang/lib/AST/Interp/EvalEmitter.h @@ -109,6 +109,8 @@ class EvalEmitter : public SourceMapper { return reinterpret_cast(It->second.get()); } + void updateGlobalTemporaries(); + // The emitter always tracks the current instruction and sets OpPC to a token // value which is mapped to the location of the opcode being evaluated. CodePtr OpPC; diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h index 6c9246f692204..75a8f66cc5d50 100644 --- a/clang/lib/AST/Interp/Interp.h +++ b/clang/lib/AST/Interp/Interp.h @@ -1283,16 +1283,20 @@ bool InitGlobal(InterpState , CodePtr OpPC, uint32_t I) { template ::T> bool InitGlobalTemp(InterpState , CodePtr OpPC, uint32_t I, const LifetimeExtendedTemporaryDecl *Temp) { - assert(Temp); + const Pointer = S.P.getGlobal(I); + const T Value = S.Stk.peek(); APValue APV = Value.toAPValue(); APValue *Cached = Temp->getOrCreateValue(true); *Cached = APV; - const Pointer = S.P.getGlobal(I); - P.deref() = S.Stk.pop(); - P.initialize(); + assert(Ptr.getDeclDesc()->asExpr()); + + S.SeenGlobalTemporaries.push_back( + std::make_pair(Ptr.getDeclDesc()->asExpr(), Temp)); + Ptr.deref() = S.Stk.pop(); + Ptr.initialize(); return true; } @@ -1305,6 +1309,9 @@ inline bool InitGlobalTempComp(InterpState , CodePtr OpPC, const Pointer = S.Stk.peek(); APValue *Cached = Temp->getOrCreateValue(true); + S.SeenGlobalTemporaries.push_back( + std::make_pair(P.getDeclDesc()->asExpr(), Temp)); + if (std::optional APV = P.toRValue(S.getCtx())) { *Cached = *APV; return true; diff --git a/clang/lib/AST/Interp/InterpState.h b/clang/lib/AST/Interp/InterpState.h index 925395b6eba0c..138e1d7ac95d5 100644 --- a/clang/lib/AST/Interp/InterpState.h +++ b/clang/lib/AST/Interp/InterpState.h @@ -123,6 +123,10 @@ class InterpState final : public State, public SourceMapper { SourceLocation EvalLocation; /// Declaration we're initializing/evaluting, if any. const VarDecl *EvaluatingDecl = nullptr; + +
[clang] deb039e - [clang][Interp][NFC] Provide Program accessor for global temporaries
Author: Timm Bäder Date: 2024-06-29T19:55:30+02:00 New Revision: deb039e69ed7efc94ef517809f36298f40359c21 URL: https://github.com/llvm/llvm-project/commit/deb039e69ed7efc94ef517809f36298f40359c21 DIFF: https://github.com/llvm/llvm-project/commit/deb039e69ed7efc94ef517809f36298f40359c21.diff LOG: [clang][Interp][NFC] Provide Program accessor for global temporaries Just like the one we have taking a ValueDecl*, provide a getGlobal() version taking an expression. Added: Modified: clang/lib/AST/Interp/Program.cpp clang/lib/AST/Interp/Program.h Removed: diff --git a/clang/lib/AST/Interp/Program.cpp b/clang/lib/AST/Interp/Program.cpp index caff9d01cdfee..2a1ad4d4eb850 100644 --- a/clang/lib/AST/Interp/Program.cpp +++ b/clang/lib/AST/Interp/Program.cpp @@ -126,6 +126,12 @@ std::optional Program::getGlobal(const ValueDecl *VD) { return std::nullopt; } +std::optional Program::getGlobal(const Expr *E) { + if (auto It = GlobalIndices.find(E); It != GlobalIndices.end()) +return It->second; + return std::nullopt; +} + std::optional Program::getOrCreateGlobal(const ValueDecl *VD, const Expr *Init) { if (auto Idx = getGlobal(VD)) @@ -195,7 +201,14 @@ std::optional Program::createGlobal(const ValueDecl *VD, } std::optional Program::createGlobal(const Expr *E) { - return createGlobal(E, E->getType(), /*isStatic=*/true, /*isExtern=*/false); + if (auto Idx = getGlobal(E)) +return Idx; + if (auto Idx = createGlobal(E, E->getType(), /*isStatic=*/true, + /*isExtern=*/false)) { +GlobalIndices[E] = *Idx; +return *Idx; + } + return std::nullopt; } std::optional Program::createGlobal(const DeclTy , QualType Ty, diff --git a/clang/lib/AST/Interp/Program.h b/clang/lib/AST/Interp/Program.h index ec7c0744b8856..1cabc5212180f 100644 --- a/clang/lib/AST/Interp/Program.h +++ b/clang/lib/AST/Interp/Program.h @@ -77,6 +77,7 @@ class Program final { /// Finds a global's index. std::optional getGlobal(const ValueDecl *VD); + std::optional getGlobal(const Expr *E); /// Returns or creates a global an creates an index to it. std::optional getOrCreateGlobal(const ValueDecl *VD, ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] d957da8 - [clang][Interp] Allow taking the address of a non-const global reference
Author: Timm Bäder Date: 2024-06-29T19:55:29+02:00 New Revision: d957da83791930a3c23f4f936ca7c7644c4b07a4 URL: https://github.com/llvm/llvm-project/commit/d957da83791930a3c23f4f936ca7c7644c4b07a4 DIFF: https://github.com/llvm/llvm-project/commit/d957da83791930a3c23f4f936ca7c7644c4b07a4.diff LOG: [clang][Interp] Allow taking the address of a non-const global reference This is not a read, but the GetGlobal op before failed if the reference we were taking a pointer of was non-const. Use GetGlobalUnchecked instead. Added: Modified: clang/lib/AST/Interp/Compiler.cpp clang/lib/AST/Interp/Interp.h clang/test/AST/Interp/references.cpp Removed: diff --git a/clang/lib/AST/Interp/Compiler.cpp b/clang/lib/AST/Interp/Compiler.cpp index e21e2c0eb8b6a..8b6f7f644a778 100644 --- a/clang/lib/AST/Interp/Compiler.cpp +++ b/clang/lib/AST/Interp/Compiler.cpp @@ -4906,8 +4906,11 @@ bool Compiler::visitDeclRef(const ValueDecl *D, const Expr *E) { return this->emitGetLocal(PT_Ptr, Offset, E); return this->emitGetPtrLocal(Offset, E); } else if (auto GlobalIndex = P.getGlobal(D)) { -if (IsReference) - return this->emitGetGlobal(classifyPrim(E), *GlobalIndex, E); +if (IsReference) { + if (!Ctx.getLangOpts().CPlusPlus11) +return this->emitGetGlobal(classifyPrim(E), *GlobalIndex, E); + return this->emitGetGlobalUnchecked(classifyPrim(E), *GlobalIndex, E); +} return this->emitGetPtrGlobal(*GlobalIndex, E); } else if (const auto *PVD = dyn_cast(D)) { diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h index 916d268aa4f09..6c9246f692204 100644 --- a/clang/lib/AST/Interp/Interp.h +++ b/clang/lib/AST/Interp/Interp.h @@ -1255,7 +1255,10 @@ bool GetGlobal(InterpState , CodePtr OpPC, uint32_t I) { /// Same as GetGlobal, but without the checks. template ::T> bool GetGlobalUnchecked(InterpState , CodePtr OpPC, uint32_t I) { - auto *B = S.P.getGlobal(I); + const Pointer = S.P.getPtrGlobal(I); + if (!Ptr.isInitialized()) +return false; + const Block *B = S.P.getGlobal(I); S.Stk.push(B->deref()); return true; } diff --git a/clang/test/AST/Interp/references.cpp b/clang/test/AST/Interp/references.cpp index efb756545b4aa..9a790dc75d730 100644 --- a/clang/test/AST/Interp/references.cpp +++ b/clang/test/AST/Interp/references.cpp @@ -130,3 +130,8 @@ const char (_string_ref)[3] = {"hi"}; static_assert(nonextended_string_ref[0] == 'h', ""); static_assert(nonextended_string_ref[1] == 'i', ""); static_assert(nonextended_string_ref[2] == '\0', ""); + +/// This isa non-constant context. Reading A is not allowed, +/// but taking its address is. +int & = 12; +int arr[!]; ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] df067e5 - [clang][Interp][NFC] Pretty-print global temporary APValues
Author: Timm Bäder Date: 2024-06-29T18:29:02+02:00 New Revision: df067e567f7793a7c82096df0387a6e6dd31a828 URL: https://github.com/llvm/llvm-project/commit/df067e567f7793a7c82096df0387a6e6dd31a828 DIFF: https://github.com/llvm/llvm-project/commit/df067e567f7793a7c82096df0387a6e6dd31a828.diff LOG: [clang][Interp][NFC] Pretty-print global temporary APValues Added: Modified: clang/lib/AST/Interp/Disasm.cpp Removed: diff --git a/clang/lib/AST/Interp/Disasm.cpp b/clang/lib/AST/Interp/Disasm.cpp index 56c2b7032f6d5..d946a10c22dc3 100644 --- a/clang/lib/AST/Interp/Disasm.cpp +++ b/clang/lib/AST/Interp/Disasm.cpp @@ -156,15 +156,28 @@ LLVM_DUMP_METHOD void Program::dump(llvm::raw_ostream ) const { } Desc->dump(OS); -if (Desc->IsTemporary) { +if (GP.isInitialized() && Desc->IsTemporary) { if (const auto *MTE = dyn_cast_if_present(Desc->asExpr()); MTE && MTE->getLifetimeExtendedTemporaryDecl()) { -const APValue *V = MTE->getLifetimeExtendedTemporaryDecl()->getValue(); -if (V->isInt()) - OS << " (global temporary value: " << V->getInt() << ")"; -else - OS << " (huh?)"; +if (const APValue *V = +MTE->getLifetimeExtendedTemporaryDecl()->getValue()) { + OS << " (global temporary value: "; + { +ColorScope SC(OS, true, {llvm::raw_ostream::BRIGHT_MAGENTA, true}); +std::string VStr; +llvm::raw_string_ostream SS(VStr); +V->dump(SS, Ctx.getASTContext()); + +for (unsigned I = 0; I != VStr.size(); ++I) { + if (VStr[I] == '\n') +VStr[I] = ' '; +} +VStr.pop_back(); // Remove the newline (or now space) at the end. +OS << VStr; + } + OS << ')'; +} } } ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 58160e7 - [clang][Interp][NFC] Use const pointers in Descriptor::getType()
Author: Timm Bäder Date: 2024-06-29T09:42:37+02:00 New Revision: 58160e78e5ed82bdcc1dcbda4d57442aa4e1dd9e URL: https://github.com/llvm/llvm-project/commit/58160e78e5ed82bdcc1dcbda4d57442aa4e1dd9e DIFF: https://github.com/llvm/llvm-project/commit/58160e78e5ed82bdcc1dcbda4d57442aa4e1dd9e.diff LOG: [clang][Interp][NFC] Use const pointers in Descriptor::getType() Added: Modified: clang/lib/AST/Interp/Descriptor.cpp Removed: diff --git a/clang/lib/AST/Interp/Descriptor.cpp b/clang/lib/AST/Interp/Descriptor.cpp index fea8a7b1d14a9..afafae088aca0 100644 --- a/clang/lib/AST/Interp/Descriptor.cpp +++ b/clang/lib/AST/Interp/Descriptor.cpp @@ -355,11 +355,11 @@ Descriptor::Descriptor(const DeclTy ) } QualType Descriptor::getType() const { - if (auto *E = asExpr()) + if (const auto *E = asExpr()) return E->getType(); - if (auto *D = asValueDecl()) + if (const auto *D = asValueDecl()) return D->getType(); - if (auto *T = dyn_cast(asDecl())) + if (const auto *T = dyn_cast(asDecl())) return QualType(T->getTypeForDecl(), 0); llvm_unreachable("Invalid descriptor type"); } ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 99ff5d5 - [clang][Interp][NFC] Simplify test
Author: Timm Bäder Date: 2024-06-29T09:42:37+02:00 New Revision: 99ff5d5c963b8bd9ccae99fbb17b8fc537fe8095 URL: https://github.com/llvm/llvm-project/commit/99ff5d5c963b8bd9ccae99fbb17b8fc537fe8095 DIFF: https://github.com/llvm/llvm-project/commit/99ff5d5c963b8bd9ccae99fbb17b8fc537fe8095.diff LOG: [clang][Interp][NFC] Simplify test Added: Modified: clang/test/AST/Interp/arrays.cpp Removed: diff --git a/clang/test/AST/Interp/arrays.cpp b/clang/test/AST/Interp/arrays.cpp index 26ec39e9cca65..933437c3401c4 100644 --- a/clang/test/AST/Interp/arrays.cpp +++ b/clang/test/AST/Interp/arrays.cpp @@ -513,11 +513,9 @@ namespace NonConstReads { // both-note {{read of non-const variable 'z'}} #else void *p = nullptr; - int arr[!p]; // ref-error {{not allowed at file scope}} \ - // expected-error {{not allowed at file scope}} + int arr[!p]; // both-error {{not allowed at file scope}} int z; - int a[z]; // ref-error {{not allowed at file scope}} \ -// expected-error {{not allowed at file scope}} + int a[z]; // both-error {{not allowed at file scope}} #endif const int y = 0; ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 8d3abc9 - [clang][Interp][NFC] Dump expression address
Author: Timm Bäder Date: 2024-06-29T09:42:36+02:00 New Revision: 8d3abc92d663552b97de083e77d2cc76164d0dd4 URL: https://github.com/llvm/llvm-project/commit/8d3abc92d663552b97de083e77d2cc76164d0dd4 DIFF: https://github.com/llvm/llvm-project/commit/8d3abc92d663552b97de083e77d2cc76164d0dd4.diff LOG: [clang][Interp][NFC] Dump expression address Added: Modified: clang/lib/AST/Interp/Disasm.cpp Removed: diff --git a/clang/lib/AST/Interp/Disasm.cpp b/clang/lib/AST/Interp/Disasm.cpp index 8204fd1bc040c..56c2b7032f6d5 100644 --- a/clang/lib/AST/Interp/Disasm.cpp +++ b/clang/lib/AST/Interp/Disasm.cpp @@ -205,7 +205,7 @@ LLVM_DUMP_METHOD void Descriptor::dump(llvm::raw_ostream ) const { if (const auto *ND = dyn_cast_if_present(asDecl())) ND->printQualifiedName(OS); else if (asExpr()) - OS << "expr (TODO)"; + OS << "Expr " << (const void *)asExpr(); } // Print a few interesting bits about the descriptor. ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] e379629 - [clang][NFC] Use provided stream in APValue::dump()
Author: Timm Bäder Date: 2024-06-28T10:41:25+02:00 New Revision: e3796291abd83012762c832ec37ac4ecd9aba5ad URL: https://github.com/llvm/llvm-project/commit/e3796291abd83012762c832ec37ac4ecd9aba5ad DIFF: https://github.com/llvm/llvm-project/commit/e3796291abd83012762c832ec37ac4ecd9aba5ad.diff LOG: [clang][NFC] Use provided stream in APValue::dump() I assume this is a copy/paste error. Added: Modified: clang/lib/AST/ASTDumper.cpp Removed: diff --git a/clang/lib/AST/ASTDumper.cpp b/clang/lib/AST/ASTDumper.cpp index f0603880c32dd..864d0393f9a78 100644 --- a/clang/lib/AST/ASTDumper.cpp +++ b/clang/lib/AST/ASTDumper.cpp @@ -342,8 +342,7 @@ LLVM_DUMP_METHOD void APValue::dump() const { LLVM_DUMP_METHOD void APValue::dump(raw_ostream , const ASTContext ) const { - ASTDumper Dumper(llvm::errs(), Context, - Context.getDiagnostics().getShowColors()); + ASTDumper Dumper(OS, Context, Context.getDiagnostics().getShowColors()); Dumper.Visit(*this, /*Ty=*/Context.getPointerType(Context.CharTy)); } ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 61975cd - [clang][Interp][NFC] Print global temporary value in Program::dump()
Author: Timm Bäder Date: 2024-06-27T19:24:35+02:00 New Revision: 61975cdf44a75917a738ca7fa9971b03f6d4fad8 URL: https://github.com/llvm/llvm-project/commit/61975cdf44a75917a738ca7fa9971b03f6d4fad8 DIFF: https://github.com/llvm/llvm-project/commit/61975cdf44a75917a738ca7fa9971b03f6d4fad8.diff LOG: [clang][Interp][NFC] Print global temporary value in Program::dump() There is quite a problem here, so print both the value we have in Program as well as the value from the LifetimeExtendedTemporaryDecl. Added: Modified: clang/lib/AST/Interp/Disasm.cpp Removed: diff --git a/clang/lib/AST/Interp/Disasm.cpp b/clang/lib/AST/Interp/Disasm.cpp index 0ab84d159c58b..8204fd1bc040c 100644 --- a/clang/lib/AST/Interp/Disasm.cpp +++ b/clang/lib/AST/Interp/Disasm.cpp @@ -25,6 +25,7 @@ #include "Program.h" #include "clang/AST/ASTDumperUtils.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/ExprCXX.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Format.h" @@ -154,6 +155,19 @@ LLVM_DUMP_METHOD void Program::dump(llvm::raw_ostream ) const { OS << (GP.isInitialized() ? "initialized " : "uninitialized "); } Desc->dump(OS); + +if (Desc->IsTemporary) { + if (const auto *MTE = + dyn_cast_if_present(Desc->asExpr()); + MTE && MTE->getLifetimeExtendedTemporaryDecl()) { +const APValue *V = MTE->getLifetimeExtendedTemporaryDecl()->getValue(); +if (V->isInt()) + OS << " (global temporary value: " << V->getInt() << ")"; +else + OS << " (huh?)"; + } +} + OS << "\n"; if (GP.isInitialized() && Desc->isPrimitive() && !Desc->isDummy()) { OS << " "; ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 50b1534 - [clang][Interp] Don't diagnose non-const reads from the evaluating decl
Author: Timm Bäder Date: 2024-06-27T18:01:11+02:00 New Revision: 50b15341182e0a5f53dd6e9b4a00fef56f31147c URL: https://github.com/llvm/llvm-project/commit/50b15341182e0a5f53dd6e9b4a00fef56f31147c DIFF: https://github.com/llvm/llvm-project/commit/50b15341182e0a5f53dd6e9b4a00fef56f31147c.diff LOG: [clang][Interp] Don't diagnose non-const reads from the evaluating decl Added: Modified: clang/lib/AST/Interp/EvalEmitter.cpp clang/lib/AST/Interp/Interp.cpp clang/lib/AST/Interp/InterpState.h Removed: diff --git a/clang/lib/AST/Interp/EvalEmitter.cpp b/clang/lib/AST/Interp/EvalEmitter.cpp index 77ff901634a46..a13cd94b0ba1c 100644 --- a/clang/lib/AST/Interp/EvalEmitter.cpp +++ b/clang/lib/AST/Interp/EvalEmitter.cpp @@ -56,6 +56,7 @@ EvaluationResult EvalEmitter::interpretExpr(const Expr *E, EvaluationResult EvalEmitter::interpretDecl(const VarDecl *VD, bool CheckFullyInitialized) { this->CheckFullyInitialized = CheckFullyInitialized; + S.EvaluatingDecl = VD; if (const Expr *Init = VD->getAnyInitializer()) { QualType T = VD->getType(); @@ -69,6 +70,7 @@ EvaluationResult EvalEmitter::interpretDecl(const VarDecl *VD, if (!this->visitDecl(VD, S.inConstantContext()) && EvalResult.empty()) EvalResult.setInvalid(); + S.EvaluatingDecl = nullptr; return std::move(this->EvalResult); } diff --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp index fc4c0058fbda4..76a0751a006e4 100644 --- a/clang/lib/AST/Interp/Interp.cpp +++ b/clang/lib/AST/Interp/Interp.cpp @@ -322,7 +322,7 @@ bool CheckConstant(InterpState , CodePtr OpPC, const Descriptor *Desc) { }; if (const auto *D = Desc->asVarDecl(); - D && D->hasGlobalStorage() && !IsConstType(D)) { + D && D->hasGlobalStorage() && D != S.EvaluatingDecl && !IsConstType(D)) { diagnoseNonConstVariable(S, OpPC, D); return S.inConstantContext(); } diff --git a/clang/lib/AST/Interp/InterpState.h b/clang/lib/AST/Interp/InterpState.h index 0938a723a76d0..925395b6eba0c 100644 --- a/clang/lib/AST/Interp/InterpState.h +++ b/clang/lib/AST/Interp/InterpState.h @@ -121,6 +121,8 @@ class InterpState final : public State, public SourceMapper { InterpFrame *Current = nullptr; /// Source location of the evaluating expression SourceLocation EvalLocation; + /// Declaration we're initializing/evaluting, if any. + const VarDecl *EvaluatingDecl = nullptr; }; } // namespace interp ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits