aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/AST
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/AST')
-rw-r--r--clang/lib/AST/ASTConcept.cpp2
-rw-r--r--clang/lib/AST/ByteCode/Compiler.cpp148
-rw-r--r--clang/lib/AST/ByteCode/Context.cpp5
-rw-r--r--clang/lib/AST/ByteCode/Interp.h192
-rw-r--r--clang/lib/AST/ByteCode/InterpBuiltin.cpp13
-rw-r--r--clang/lib/AST/ByteCode/InterpHelpers.h141
-rw-r--r--clang/lib/AST/ByteCode/Opcodes.td13
-rw-r--r--clang/lib/AST/StmtOpenACC.cpp34
-rw-r--r--clang/lib/AST/TypePrinter.cpp3
9 files changed, 367 insertions, 184 deletions
diff --git a/clang/lib/AST/ASTConcept.cpp b/clang/lib/AST/ASTConcept.cpp
index 9ea104c..fd12bc4 100644
--- a/clang/lib/AST/ASTConcept.cpp
+++ b/clang/lib/AST/ASTConcept.cpp
@@ -86,7 +86,7 @@ void ConstraintSatisfaction::Profile(llvm::FoldingSetNodeID &ID,
ID.AddPointer(ConstraintOwner);
ID.AddInteger(TemplateArgs.size());
for (auto &Arg : TemplateArgs)
- C.getCanonicalTemplateArgument(Arg).Profile(ID, C);
+ Arg.Profile(ID, C);
}
ConceptReference *
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index 74cae03..f15b3c1 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -4841,46 +4841,39 @@ Compiler<Emitter>::visitVarDecl(const VarDecl *VD, const Expr *Init,
return !NeedsOp || this->emitCheckDecl(VD, VD);
};
- auto initGlobal = [&](unsigned GlobalIndex) -> bool {
- assert(Init);
-
- if (VarT) {
- if (!this->visit(Init))
- return checkDecl() && false;
-
- return checkDecl() && this->emitInitGlobal(*VarT, GlobalIndex, VD);
- }
-
- if (!checkDecl())
- return false;
-
- if (!this->emitGetPtrGlobal(GlobalIndex, Init))
- return false;
-
- if (!visitInitializer(Init))
- return false;
-
- return this->emitFinishInitGlobal(Init);
- };
-
DeclScope<Emitter> LocalScope(this, VD);
- // We've already seen and initialized this global.
- if (UnsignedOrNone GlobalIndex = P.getGlobal(VD)) {
+ UnsignedOrNone GlobalIndex = P.getGlobal(VD);
+ if (GlobalIndex) {
+ // We've already seen and initialized this global.
if (P.getPtrGlobal(*GlobalIndex).isInitialized())
return checkDecl();
-
// The previous attempt at initialization might've been unsuccessful,
// so let's try this one.
- return Init && checkDecl() && initGlobal(*GlobalIndex);
+ } else if ((GlobalIndex = P.createGlobal(VD, Init))) {
+ } else {
+ return false;
}
+ if (!Init)
+ return true;
- UnsignedOrNone GlobalIndex = P.createGlobal(VD, Init);
+ if (!checkDecl())
+ return false;
- if (!GlobalIndex)
+ if (VarT) {
+ if (!this->visit(Init))
+ return false;
+
+ return this->emitInitGlobal(*VarT, *GlobalIndex, VD);
+ }
+
+ if (!this->emitGetPtrGlobal(*GlobalIndex, Init))
+ return false;
+
+ if (!visitInitializer(Init))
return false;
- return !Init || (checkDecl() && initGlobal(*GlobalIndex));
+ return this->emitFinishInitGlobal(Init);
}
// Local variables.
InitLinkScope<Emitter> ILS(this, InitLink::Decl(VD));
@@ -4890,36 +4883,37 @@ Compiler<Emitter>::visitVarDecl(const VarDecl *VD, const Expr *Init,
VD, *VarT, VD->getType().isConstQualified(),
VD->getType().isVolatileQualified(), nullptr, ScopeKind::Block,
IsConstexprUnknown);
- if (Init) {
- // If this is a toplevel declaration, create a scope for the
- // initializer.
- if (Toplevel) {
- LocalScope<Emitter> Scope(this);
- if (!this->visit(Init))
- return false;
- return this->emitSetLocal(*VarT, Offset, VD) && Scope.destroyLocals();
- }
- if (!this->visit(Init))
- return false;
- return this->emitSetLocal(*VarT, Offset, VD);
- }
- } else {
- if (UnsignedOrNone Offset = this->allocateLocal(
- VD, VD->getType(), nullptr, ScopeKind::Block, IsConstexprUnknown)) {
- if (!Init)
- return true;
- if (!this->emitGetPtrLocal(*Offset, Init))
- return false;
+ if (!Init)
+ return true;
- if (!visitInitializer(Init))
+ // If this is a toplevel declaration, create a scope for the
+ // initializer.
+ if (Toplevel) {
+ LocalScope<Emitter> Scope(this);
+ if (!this->visit(Init))
return false;
-
- return this->emitFinishInitPop(Init);
+ return this->emitSetLocal(*VarT, Offset, VD) && Scope.destroyLocals();
}
- return false;
+ if (!this->visit(Init))
+ return false;
+ return this->emitSetLocal(*VarT, Offset, VD);
}
- return true;
+ // Local composite variables.
+ if (UnsignedOrNone Offset = this->allocateLocal(
+ VD, VD->getType(), nullptr, ScopeKind::Block, IsConstexprUnknown)) {
+ if (!Init)
+ return true;
+
+ if (!this->emitGetPtrLocal(*Offset, Init))
+ return false;
+
+ if (!visitInitializer(Init))
+ return false;
+
+ return this->emitFinishInitPop(Init);
+ }
+ return false;
}
template <class Emitter>
@@ -6438,6 +6432,13 @@ bool Compiler<Emitter>::visitFunc(const FunctionDecl *F) {
return this->emitNoRet(SourceInfo{});
}
+static uint32_t getBitWidth(const Expr *E) {
+ assert(E->refersToBitField());
+ const auto *ME = cast<MemberExpr>(E);
+ const auto *FD = cast<FieldDecl>(ME->getMemberDecl());
+ return FD->getBitWidthValue();
+}
+
template <class Emitter>
bool Compiler<Emitter>::VisitUnaryOperator(const UnaryOperator *E) {
const Expr *SubExpr = E->getSubExpr();
@@ -6466,10 +6467,15 @@ bool Compiler<Emitter>::VisitUnaryOperator(const UnaryOperator *E) {
return DiscardResult ? this->emitPopPtr(E) : true;
}
- if (T == PT_Float) {
+ if (T == PT_Float)
return DiscardResult ? this->emitIncfPop(getFPOptions(E), E)
: this->emitIncf(getFPOptions(E), E);
- }
+
+ if (SubExpr->refersToBitField())
+ return DiscardResult ? this->emitIncPopBitfield(*T, E->canOverflow(),
+ getBitWidth(SubExpr), E)
+ : this->emitIncBitfield(*T, E->canOverflow(),
+ getBitWidth(SubExpr), E);
return DiscardResult ? this->emitIncPop(*T, E->canOverflow(), E)
: this->emitInc(*T, E->canOverflow(), E);
@@ -6490,9 +6496,15 @@ bool Compiler<Emitter>::VisitUnaryOperator(const UnaryOperator *E) {
return DiscardResult ? this->emitPopPtr(E) : true;
}
- if (T == PT_Float) {
+ if (T == PT_Float)
return DiscardResult ? this->emitDecfPop(getFPOptions(E), E)
: this->emitDecf(getFPOptions(E), E);
+
+ if (SubExpr->refersToBitField()) {
+ return DiscardResult ? this->emitDecPopBitfield(*T, E->canOverflow(),
+ getBitWidth(SubExpr), E)
+ : this->emitDecBitfield(*T, E->canOverflow(),
+ getBitWidth(SubExpr), E);
}
return DiscardResult ? this->emitDecPop(*T, E->canOverflow(), E)
@@ -6521,6 +6533,11 @@ bool Compiler<Emitter>::VisitUnaryOperator(const UnaryOperator *E) {
if (DiscardResult) {
if (T == PT_Float)
return this->emitIncfPop(getFPOptions(E), E);
+ if (SubExpr->refersToBitField())
+ return DiscardResult ? this->emitIncPopBitfield(*T, E->canOverflow(),
+ getBitWidth(SubExpr), E)
+ : this->emitIncBitfield(*T, E->canOverflow(),
+ getBitWidth(SubExpr), E);
return this->emitIncPop(*T, E->canOverflow(), E);
}
@@ -6536,6 +6553,11 @@ bool Compiler<Emitter>::VisitUnaryOperator(const UnaryOperator *E) {
return false;
if (!this->emitStoreFloat(E))
return false;
+ } else if (SubExpr->refersToBitField()) {
+ assert(isIntegralType(*T));
+ if (!this->emitPreIncBitfield(*T, E->canOverflow(), getBitWidth(SubExpr),
+ E))
+ return false;
} else {
assert(isIntegralType(*T));
if (!this->emitPreInc(*T, E->canOverflow(), E))
@@ -6566,6 +6588,11 @@ bool Compiler<Emitter>::VisitUnaryOperator(const UnaryOperator *E) {
if (DiscardResult) {
if (T == PT_Float)
return this->emitDecfPop(getFPOptions(E), E);
+ if (SubExpr->refersToBitField())
+ return DiscardResult ? this->emitDecPopBitfield(*T, E->canOverflow(),
+ getBitWidth(SubExpr), E)
+ : this->emitDecBitfield(*T, E->canOverflow(),
+ getBitWidth(SubExpr), E);
return this->emitDecPop(*T, E->canOverflow(), E);
}
@@ -6581,6 +6608,11 @@ bool Compiler<Emitter>::VisitUnaryOperator(const UnaryOperator *E) {
return false;
if (!this->emitStoreFloat(E))
return false;
+ } else if (SubExpr->refersToBitField()) {
+ assert(isIntegralType(*T));
+ if (!this->emitPreDecBitfield(*T, E->canOverflow(), getBitWidth(SubExpr),
+ E))
+ return false;
} else {
assert(isIntegralType(*T));
if (!this->emitPreDec(*T, E->canOverflow(), E))
@@ -6633,7 +6665,7 @@ bool Compiler<Emitter>::VisitUnaryOperator(const UnaryOperator *E) {
if (!this->visit(SubExpr))
return false;
- if (!this->emitCheckNull(E))
+ if (!SubExpr->getType()->isFunctionPointerType() && !this->emitCheckNull(E))
return false;
if (classifyPrim(SubExpr) == PT_Ptr)
diff --git a/clang/lib/AST/ByteCode/Context.cpp b/clang/lib/AST/ByteCode/Context.cpp
index 4f4b122..12bf3a3 100644
--- a/clang/lib/AST/ByteCode/Context.cpp
+++ b/clang/lib/AST/ByteCode/Context.cpp
@@ -7,12 +7,15 @@
//===----------------------------------------------------------------------===//
#include "Context.h"
+#include "Boolean.h"
#include "ByteCodeEmitter.h"
#include "Compiler.h"
#include "EvalEmitter.h"
-#include "Interp.h"
+#include "Integral.h"
#include "InterpFrame.h"
+#include "InterpHelpers.h"
#include "InterpStack.h"
+#include "Pointer.h"
#include "PrimType.h"
#include "Program.h"
#include "clang/AST/ASTLambda.h"
diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index 2f7e2d9..89f6fbe 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -22,6 +22,7 @@
#include "Function.h"
#include "InterpBuiltinBitCast.h"
#include "InterpFrame.h"
+#include "InterpHelpers.h"
#include "InterpStack.h"
#include "InterpState.h"
#include "MemberPointer.h"
@@ -43,28 +44,10 @@ using FixedPointSemantics = llvm::FixedPointSemantics;
/// Checks if the variable has externally defined storage.
bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
-/// Checks if the array is offsetable.
-bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
-
-/// Checks if a pointer is live and accessible.
-bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
- AccessKinds AK);
-
-/// Checks if a pointer is a dummy pointer.
-bool CheckDummy(InterpState &S, CodePtr OpPC, const Block *B, AccessKinds AK);
-
/// Checks if a pointer is null.
bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
CheckSubobjectKind CSK);
-/// Checks if a pointer is in range.
-bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
- AccessKinds AK);
-
-/// Checks if a field from which a pointer is going to be derived is valid.
-bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
- CheckSubobjectKind CSK);
-
/// Checks if Ptr is a one-past-the-end pointer.
bool CheckSubobject(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
CheckSubobjectKind CSK);
@@ -80,12 +63,6 @@ bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
/// Checks if the Descriptor is of a constexpr or const global variable.
bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc);
-/// Checks if a pointer points to a mutable field.
-bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
-
-/// Checks if a value can be loaded from a block.
-bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
- AccessKinds AK = AK_Read);
bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
bool DiagnoseUninitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
@@ -110,12 +87,6 @@ bool CheckThis(InterpState &S, CodePtr OpPC);
/// language mode.
bool CheckDynamicMemoryAllocation(InterpState &S, CodePtr OpPC);
-/// Diagnose mismatched new[]/delete or new/delete[] pairs.
-bool CheckNewDeleteForms(InterpState &S, CodePtr OpPC,
- DynamicAllocator::Form AllocForm,
- DynamicAllocator::Form DeleteForm, const Descriptor *D,
- const Expr *NewExpr);
-
/// Check the source of the pointer passed to delete/delete[] has actually
/// been heap allocated by us.
bool CheckDeleteSource(InterpState &S, CodePtr OpPC, const Expr *Source,
@@ -129,9 +100,6 @@ bool CheckActive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
bool SetThreeWayComparisonField(InterpState &S, CodePtr OpPC,
const Pointer &Ptr, const APSInt &IntValue);
-/// Copy the contents of Src into Dest.
-bool DoMemcpy(InterpState &S, CodePtr OpPC, const Pointer &Src, Pointer &Dest);
-
bool CallVar(InterpState &S, CodePtr OpPC, const Function *Func,
uint32_t VarArgSize);
bool Call(InterpState &S, CodePtr OpPC, const Function *Func,
@@ -149,19 +117,11 @@ bool CheckBitCast(InterpState &S, CodePtr OpPC, bool HasIndeterminateBits,
bool CheckBCPResult(InterpState &S, const Pointer &Ptr);
bool CheckDestructor(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
-template <typename T>
-static bool handleOverflow(InterpState &S, CodePtr OpPC, const T &SrcValue) {
- const Expr *E = S.Current->getExpr(OpPC);
- S.CCEDiag(E, diag::note_constexpr_overflow) << SrcValue << E->getType();
- return S.noteUndefinedBehavior();
-}
bool handleFixedPointOverflow(InterpState &S, CodePtr OpPC,
const FixedPoint &FP);
bool isConstexprUnknown(const Pointer &P);
-inline bool CheckArraySize(InterpState &S, CodePtr OpPC, uint64_t NumElems);
-
enum class ShiftDir { Left, Right };
/// Checks if the shift operation is legal.
@@ -241,43 +201,6 @@ bool CheckDivRem(InterpState &S, CodePtr OpPC, const T &LHS, const T &RHS) {
return true;
}
-template <typename SizeT>
-bool CheckArraySize(InterpState &S, CodePtr OpPC, SizeT *NumElements,
- unsigned ElemSize, bool IsNoThrow) {
- // FIXME: Both the SizeT::from() as well as the
- // NumElements.toAPSInt() in this function are rather expensive.
-
- // Can't be too many elements if the bitwidth of NumElements is lower than
- // that of Descriptor::MaxArrayElemBytes.
- if ((NumElements->bitWidth() - NumElements->isSigned()) <
- (sizeof(Descriptor::MaxArrayElemBytes) * 8))
- return true;
-
- // FIXME: GH63562
- // APValue stores array extents as unsigned,
- // so anything that is greater that unsigned would overflow when
- // constructing the array, we catch this here.
- SizeT MaxElements = SizeT::from(Descriptor::MaxArrayElemBytes / ElemSize);
- assert(MaxElements.isPositive());
- if (NumElements->toAPSInt().getActiveBits() >
- ConstantArrayType::getMaxSizeBits(S.getASTContext()) ||
- *NumElements > MaxElements) {
- if (!IsNoThrow) {
- const SourceInfo &Loc = S.Current->getSource(OpPC);
-
- if (NumElements->isSigned() && NumElements->isNegative()) {
- S.FFDiag(Loc, diag::note_constexpr_new_negative)
- << NumElements->toDiagnosticString(S.getASTContext());
- } else {
- S.FFDiag(Loc, diag::note_constexpr_new_too_large)
- << NumElements->toDiagnosticString(S.getASTContext());
- }
- }
- return false;
- }
- return true;
-}
-
/// Checks if the result of a floating-point operation is valid
/// in the current context.
bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result,
@@ -286,19 +209,6 @@ bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result,
/// Checks why the given DeclRefExpr is invalid.
bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR);
-/// Interpreter entry point.
-bool Interpret(InterpState &S);
-
-/// Interpret a builtin function.
-bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
- uint32_t BuiltinID);
-
-/// Interpret an offsetof operation.
-bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E,
- ArrayRef<int64_t> ArrayIndices, int64_t &Result);
-
-inline bool Invalid(InterpState &S, CodePtr OpPC);
-
enum class ArithOp { Add, Sub };
//===----------------------------------------------------------------------===//
@@ -403,13 +313,6 @@ bool Add(InterpState &S, CodePtr OpPC) {
return AddSubMulHelper<T, T::add, std::plus>(S, OpPC, Bits, LHS, RHS);
}
-static inline llvm::RoundingMode getRoundingMode(FPOptions FPO) {
- auto RM = FPO.getRoundingMode();
- if (RM == llvm::RoundingMode::Dynamic)
- return llvm::RoundingMode::NearestTiesToEven;
- return RM;
-}
-
inline bool Addf(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
const Floating &RHS = S.Stk.pop<Floating>();
const Floating &LHS = S.Stk.pop<Floating>();
@@ -799,7 +702,7 @@ enum class IncDecOp {
template <typename T, IncDecOp Op, PushVal DoPush>
bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
- bool CanOverflow) {
+ bool CanOverflow, UnsignedOrNone BitWidth = std::nullopt) {
assert(!Ptr.isDummy());
if (!S.inConstantContext()) {
@@ -822,12 +725,18 @@ bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
if constexpr (Op == IncDecOp::Inc) {
if (!T::increment(Value, &Result) || !CanOverflow) {
- Ptr.deref<T>() = Result;
+ if (BitWidth)
+ Ptr.deref<T>() = Result.truncate(*BitWidth);
+ else
+ Ptr.deref<T>() = Result;
return true;
}
} else {
if (!T::decrement(Value, &Result) || !CanOverflow) {
- Ptr.deref<T>() = Result;
+ if (BitWidth)
+ Ptr.deref<T>() = Result.truncate(*BitWidth);
+ else
+ Ptr.deref<T>() = Result;
return true;
}
}
@@ -871,6 +780,17 @@ bool Inc(InterpState &S, CodePtr OpPC, bool CanOverflow) {
CanOverflow);
}
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool IncBitfield(InterpState &S, CodePtr OpPC, bool CanOverflow,
+ unsigned BitWidth) {
+ const Pointer &Ptr = S.Stk.pop<Pointer>();
+ if (!CheckLoad(S, OpPC, Ptr, AK_Increment))
+ return false;
+
+ return IncDecHelper<T, IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr, CanOverflow,
+ BitWidth);
+}
+
/// 1) Pops a pointer from the stack
/// 2) Load the value from the pointer
/// 3) Writes the value increased by one back to the pointer
@@ -884,6 +804,17 @@ bool IncPop(InterpState &S, CodePtr OpPC, bool CanOverflow) {
}
template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool IncPopBitfield(InterpState &S, CodePtr OpPC, bool CanOverflow,
+ uint32_t BitWidth) {
+ const Pointer &Ptr = S.Stk.pop<Pointer>();
+ if (!CheckLoad(S, OpPC, Ptr, AK_Increment))
+ return false;
+
+ return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, CanOverflow,
+ BitWidth);
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
bool PreInc(InterpState &S, CodePtr OpPC, bool CanOverflow) {
const Pointer &Ptr = S.Stk.peek<Pointer>();
if (!CheckLoad(S, OpPC, Ptr, AK_Increment))
@@ -892,6 +823,17 @@ bool PreInc(InterpState &S, CodePtr OpPC, bool CanOverflow) {
return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, CanOverflow);
}
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool PreIncBitfield(InterpState &S, CodePtr OpPC, bool CanOverflow,
+ uint32_t BitWidth) {
+ const Pointer &Ptr = S.Stk.peek<Pointer>();
+ if (!CheckLoad(S, OpPC, Ptr, AK_Increment))
+ return false;
+
+ return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, CanOverflow,
+ BitWidth);
+}
+
/// 1) Pops a pointer from the stack
/// 2) Load the value from the pointer
/// 3) Writes the value decreased by one back to the pointer
@@ -905,6 +847,16 @@ bool Dec(InterpState &S, CodePtr OpPC, bool CanOverflow) {
return IncDecHelper<T, IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr,
CanOverflow);
}
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool DecBitfield(InterpState &S, CodePtr OpPC, bool CanOverflow,
+ uint32_t BitWidth) {
+ const Pointer &Ptr = S.Stk.pop<Pointer>();
+ if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))
+ return false;
+
+ return IncDecHelper<T, IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr, CanOverflow,
+ BitWidth);
+}
/// 1) Pops a pointer from the stack
/// 2) Load the value from the pointer
@@ -919,6 +871,17 @@ bool DecPop(InterpState &S, CodePtr OpPC, bool CanOverflow) {
}
template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool DecPopBitfield(InterpState &S, CodePtr OpPC, bool CanOverflow,
+ uint32_t BitWidth) {
+ const Pointer &Ptr = S.Stk.pop<Pointer>();
+ if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))
+ return false;
+
+ return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, CanOverflow,
+ BitWidth);
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
bool PreDec(InterpState &S, CodePtr OpPC, bool CanOverflow) {
const Pointer &Ptr = S.Stk.peek<Pointer>();
if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))
@@ -926,6 +889,16 @@ bool PreDec(InterpState &S, CodePtr OpPC, bool CanOverflow) {
return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, CanOverflow);
}
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool PreDecBitfield(InterpState &S, CodePtr OpPC, bool CanOverflow,
+ uint32_t BitWidth) {
+ const Pointer &Ptr = S.Stk.peek<Pointer>();
+ if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))
+ return false;
+ return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, CanOverflow,
+ BitWidth);
+}
+
template <IncDecOp Op, PushVal DoPush>
bool IncDecFloatHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
uint32_t FPOI) {
@@ -3264,12 +3237,6 @@ inline bool GetMemberPtrDecl(InterpState &S, CodePtr OpPC) {
/// Just emit a diagnostic. The expression that caused emission of this
/// op is not valid in a constant context.
-inline bool Invalid(InterpState &S, CodePtr OpPC) {
- const SourceLocation &Loc = S.Current->getLocation(OpPC);
- S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr)
- << S.Current->getRange(OpPC);
- return false;
-}
inline bool Unsupported(InterpState &S, CodePtr OpPC) {
const SourceLocation &Loc = S.Current->getLocation(OpPC);
@@ -3701,17 +3668,6 @@ inline bool CheckDestruction(InterpState &S, CodePtr OpPC) {
return CheckDestructor(S, OpPC, Ptr);
}
-inline bool CheckArraySize(InterpState &S, CodePtr OpPC, uint64_t NumElems) {
- uint64_t Limit = S.getLangOpts().ConstexprStepLimit;
- if (Limit != 0 && NumElems > Limit) {
- S.FFDiag(S.Current->getSource(OpPC),
- diag::note_constexpr_new_exceeds_limits)
- << NumElems << Limit;
- return false;
- }
- return true;
-}
-
//===----------------------------------------------------------------------===//
// Read opcode arguments
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index 39b991c..ff83c52 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -8,9 +8,10 @@
#include "../ExprConstShared.h"
#include "Boolean.h"
#include "EvalEmitter.h"
-#include "Interp.h"
#include "InterpBuiltinBitCast.h"
+#include "InterpHelpers.h"
#include "PrimType.h"
+#include "Program.h"
#include "clang/AST/OSLog.h"
#include "clang/AST/RecordLayout.h"
#include "clang/Basic/Builtins.h"
@@ -2041,10 +2042,16 @@ static bool interp__builtin_memchr(InterpState &S, CodePtr OpPC,
}
if (ID == Builtin::BIstrchr || ID == Builtin::BI__builtin_strchr) {
+ int64_t DesiredTrunc;
+ if (S.getASTContext().CharTy->isSignedIntegerType())
+ DesiredTrunc =
+ Desired.trunc(S.getASTContext().getCharWidth()).getSExtValue();
+ else
+ DesiredTrunc =
+ Desired.trunc(S.getASTContext().getCharWidth()).getZExtValue();
// strchr compares directly to the passed integer, and therefore
// always fails if given an int that is not a char.
- if (Desired !=
- Desired.trunc(S.getASTContext().getCharWidth()).getSExtValue()) {
+ if (Desired != DesiredTrunc) {
S.Stk.push<Pointer>();
return true;
}
diff --git a/clang/lib/AST/ByteCode/InterpHelpers.h b/clang/lib/AST/ByteCode/InterpHelpers.h
new file mode 100644
index 0000000..6bf89d3
--- /dev/null
+++ b/clang/lib/AST/ByteCode/InterpHelpers.h
@@ -0,0 +1,141 @@
+//===--- InterpHelpers.h - Interpreter Helper Functions --------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_INTERP_INTERPHELPERS_H
+#define LLVM_CLANG_AST_INTERP_INTERPHELPERS_H
+
+#include "DynamicAllocator.h"
+#include "InterpState.h"
+#include "Pointer.h"
+
+namespace clang {
+class CallExpr;
+class OffsetOfExpr;
+
+namespace interp {
+class Block;
+struct Descriptor;
+
+/// Interpreter entry point.
+bool Interpret(InterpState &S);
+
+/// Interpret a builtin function.
+bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
+ uint32_t BuiltinID);
+
+/// Interpret an offsetof operation.
+bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E,
+ ArrayRef<int64_t> ArrayIndices, int64_t &Result);
+
+/// Checks if the array is offsetable.
+bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
+
+/// Checks if a pointer is live and accessible.
+bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
+ AccessKinds AK);
+
+/// Checks if a pointer is a dummy pointer.
+bool CheckDummy(InterpState &S, CodePtr OpPC, const Block *B, AccessKinds AK);
+
+/// Checks if a pointer is in range.
+bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
+ AccessKinds AK);
+
+/// Checks if a field from which a pointer is going to be derived is valid.
+bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
+ CheckSubobjectKind CSK);
+
+/// Checks if a pointer points to a mutable field.
+bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
+
+/// Checks if a value can be loaded from a block.
+bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
+ AccessKinds AK = AK_Read);
+
+/// Diagnose mismatched new[]/delete or new/delete[] pairs.
+bool CheckNewDeleteForms(InterpState &S, CodePtr OpPC,
+ DynamicAllocator::Form AllocForm,
+ DynamicAllocator::Form DeleteForm, const Descriptor *D,
+ const Expr *NewExpr);
+
+/// Copy the contents of Src into Dest.
+bool DoMemcpy(InterpState &S, CodePtr OpPC, const Pointer &Src, Pointer &Dest);
+
+template <typename T>
+static bool handleOverflow(InterpState &S, CodePtr OpPC, const T &SrcValue) {
+ const Expr *E = S.Current->getExpr(OpPC);
+ S.CCEDiag(E, diag::note_constexpr_overflow) << SrcValue << E->getType();
+ return S.noteUndefinedBehavior();
+}
+
+inline bool CheckArraySize(InterpState &S, CodePtr OpPC, uint64_t NumElems) {
+ uint64_t Limit = S.getLangOpts().ConstexprStepLimit;
+ if (Limit != 0 && NumElems > Limit) {
+ S.FFDiag(S.Current->getSource(OpPC),
+ diag::note_constexpr_new_exceeds_limits)
+ << NumElems << Limit;
+ return false;
+ }
+ return true;
+}
+
+static inline llvm::RoundingMode getRoundingMode(FPOptions FPO) {
+ auto RM = FPO.getRoundingMode();
+ if (RM == llvm::RoundingMode::Dynamic)
+ return llvm::RoundingMode::NearestTiesToEven;
+ return RM;
+}
+
+inline bool Invalid(InterpState &S, CodePtr OpPC) {
+ const SourceLocation &Loc = S.Current->getLocation(OpPC);
+ S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr)
+ << S.Current->getRange(OpPC);
+ return false;
+}
+
+template <typename SizeT>
+bool CheckArraySize(InterpState &S, CodePtr OpPC, SizeT *NumElements,
+ unsigned ElemSize, bool IsNoThrow) {
+ // FIXME: Both the SizeT::from() as well as the
+ // NumElements.toAPSInt() in this function are rather expensive.
+
+ // Can't be too many elements if the bitwidth of NumElements is lower than
+ // that of Descriptor::MaxArrayElemBytes.
+ if ((NumElements->bitWidth() - NumElements->isSigned()) <
+ (sizeof(Descriptor::MaxArrayElemBytes) * 8))
+ return true;
+
+ // FIXME: GH63562
+ // APValue stores array extents as unsigned,
+ // so anything that is greater that unsigned would overflow when
+ // constructing the array, we catch this here.
+ SizeT MaxElements = SizeT::from(Descriptor::MaxArrayElemBytes / ElemSize);
+ assert(MaxElements.isPositive());
+ if (NumElements->toAPSInt().getActiveBits() >
+ ConstantArrayType::getMaxSizeBits(S.getASTContext()) ||
+ *NumElements > MaxElements) {
+ if (!IsNoThrow) {
+ const SourceInfo &Loc = S.Current->getSource(OpPC);
+
+ if (NumElements->isSigned() && NumElements->isNegative()) {
+ S.FFDiag(Loc, diag::note_constexpr_new_negative)
+ << NumElements->toDiagnosticString(S.getASTContext());
+ } else {
+ S.FFDiag(Loc, diag::note_constexpr_new_too_large)
+ << NumElements->toDiagnosticString(S.getASTContext());
+ }
+ }
+ return false;
+ }
+ return true;
+}
+
+} // namespace interp
+} // namespace clang
+
+#endif // LLVM_CLANG_AST_INTERP_INTERPHELPERS_H
diff --git a/clang/lib/AST/ByteCode/Opcodes.td b/clang/lib/AST/ByteCode/Opcodes.td
index 532c444..406feb5 100644
--- a/clang/lib/AST/ByteCode/Opcodes.td
+++ b/clang/lib/AST/ByteCode/Opcodes.td
@@ -612,12 +612,25 @@ class OverflowOpcode : Opcode {
let HasGroup = 1;
}
+class OverflowBitfieldOpcode : Opcode {
+ let Types = [AluTypeClass];
+ let Args = [ArgBool, ArgUint32];
+ let HasGroup = 1;
+}
+
def Inc : OverflowOpcode;
+def IncBitfield : OverflowBitfieldOpcode;
def IncPop : OverflowOpcode;
+def IncPopBitfield : OverflowBitfieldOpcode;
def PreInc : OverflowOpcode;
+def PreIncBitfield : OverflowBitfieldOpcode;
+
def Dec : OverflowOpcode;
+def DecBitfield : OverflowBitfieldOpcode;
def DecPop : OverflowOpcode;
+def DecPopBitfield : OverflowBitfieldOpcode;
def PreDec : OverflowOpcode;
+def PreDecBitfield : OverflowBitfieldOpcode;
// Float increment and decrement.
def Incf: FloatOpcode;
diff --git a/clang/lib/AST/StmtOpenACC.cpp b/clang/lib/AST/StmtOpenACC.cpp
index 07e3de8..2b56c1e 100644
--- a/clang/lib/AST/StmtOpenACC.cpp
+++ b/clang/lib/AST/StmtOpenACC.cpp
@@ -12,7 +12,9 @@
#include "clang/AST/StmtOpenACC.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/ExprCXX.h"
#include "clang/AST/StmtCXX.h"
+
using namespace clang;
OpenACCComputeConstruct *
@@ -322,6 +324,38 @@ OpenACCAtomicConstruct *OpenACCAtomicConstruct::Create(
return Inst;
}
+const OpenACCAtomicConstruct::StmtInfo
+OpenACCAtomicConstruct::getAssociatedStmtInfo() const {
+ // This ends up being a vastly simplified version of SemaOpenACCAtomic, since
+ // it doesn't have to worry about erroring out, but we should do a lot of
+ // asserts to ensure we don't get off into the weeds.
+ assert(getAssociatedStmt() && "invalid associated stmt?");
+
+ switch (AtomicKind) {
+ case OpenACCAtomicKind::None:
+ case OpenACCAtomicKind::Write:
+ case OpenACCAtomicKind::Update:
+ case OpenACCAtomicKind::Capture:
+ assert(false && "Only 'read' has been implemented here");
+ return {};
+ case OpenACCAtomicKind::Read: {
+ // Read only supports the format 'v = x'; where both sides are a scalar
+ // expression. This can come in 2 forms; BinaryOperator or
+ // CXXOperatorCallExpr (rarely).
+ const Expr *AssignExpr = cast<const Expr>(getAssociatedStmt());
+ if (const auto *BO = dyn_cast<BinaryOperator>(AssignExpr)) {
+ assert(BO->getOpcode() == BO_Assign);
+ return {BO->getLHS()->IgnoreImpCasts(), BO->getRHS()->IgnoreImpCasts()};
+ }
+
+ const auto *OO = cast<CXXOperatorCallExpr>(AssignExpr);
+ assert(OO->getOperator() == OO_Equal);
+
+ return {OO->getArg(0)->IgnoreImpCasts(), OO->getArg(1)->IgnoreImpCasts()};
+ }
+ }
+}
+
OpenACCCacheConstruct *OpenACCCacheConstruct::CreateEmpty(const ASTContext &C,
unsigned NumVars) {
void *Mem =
diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
index 2da7789..c18b2ea 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -2147,9 +2147,6 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
}
case attr::AArch64VectorPcs: OS << "aarch64_vector_pcs"; break;
case attr::AArch64SVEPcs: OS << "aarch64_sve_pcs"; break;
- case attr::DeviceKernel:
- OS << T->getAttr()->getSpelling();
- break;
case attr::IntelOclBicc:
OS << "inteloclbicc";
break;