Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 21 additions & 1 deletion clang/lib/AST/ByteCode/Compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,19 @@ template <class Emitter> class LocOverrideScope final {
} // namespace interp
} // namespace clang

template <class Emitter>
bool Compiler<Emitter>::isValidBitCast(const CastExpr *E) {
QualType FromTy = E->getSubExpr()->getType()->getPointeeType();
QualType ToTy = E->getType()->getPointeeType();

if (classify(FromTy) == classify(ToTy))
return true;

if (FromTy->isVoidType() || ToTy->isVoidType())
return true;
return false;
}

template <class Emitter>
bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) {
const Expr *SubExpr = CE->getSubExpr();
Expand Down Expand Up @@ -476,8 +489,9 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) {
return this->delegate(SubExpr);

case CK_BitCast: {
QualType CETy = CE->getType();
// Reject bitcasts to atomic types.
if (CE->getType()->isAtomicType()) {
if (CETy->isAtomicType()) {
if (!this->discard(SubExpr))
return false;
return this->emitInvalidCast(CastKind::Reinterpret, /*Fatal=*/true, CE);
Expand All @@ -492,6 +506,12 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) {
if (!FromT || !ToT)
return false;

if (!this->isValidBitCast(CE)) {
if (!this->emitInvalidCast(CastKind::ReinterpretLike, /*Fatal=*/false,
CE))
return false;
}
Comment on lines +509 to +513
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps

Suggested change
if (!this->isValidBitCast(CE)) {
if (!this->emitInvalidCast(CastKind::ReinterpretLike, /*Fatal=*/false,
CE))
return false;
}
if (!this->isValidBitCast(CE) &&
!this->emitInvalidCast(CastKind::ReinterpretLike, /*Fatal=*/false, CE))


assert(isPtrType(*FromT));
assert(isPtrType(*ToT));
if (FromT == ToT) {
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/AST/ByteCode/Compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,8 @@ class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>,

bool refersToUnion(const Expr *E);

bool isValidBitCast(const CastExpr *E);

protected:
/// Variable to storage mapping.
llvm::DenseMap<const ValueDecl *, Scope::Local> Locals;
Expand Down
29 changes: 21 additions & 8 deletions clang/lib/AST/ByteCode/Interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -1914,6 +1914,10 @@ bool Load(InterpState &S, CodePtr OpPC) {
return false;
if (!Ptr.isBlockPointer())
return false;
if (!(Ptr.getFieldDesc()->isPrimitive() ||
Ptr.getFieldDesc()->isPrimitiveArray()) ||
Ptr.getFieldDesc()->getPrimType() != Name)
return false;
Comment on lines +1917 to +1920
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (!(Ptr.getFieldDesc()->isPrimitive() ||
Ptr.getFieldDesc()->isPrimitiveArray()) ||
Ptr.getFieldDesc()->getPrimType() != Name)
return false;
const Descriptor *FieldDesc = Ptr.getFieldDesc();
if (!(FieldDesc->isPrimitive() || FieldDesc->isPrimitiveArray()) ||
FieldDesc->getPrimType() != Name)
return false;

and similar below

S.Stk.push<T>(Ptr.deref<T>());
return true;
}
Expand All @@ -1925,6 +1929,10 @@ bool LoadPop(InterpState &S, CodePtr OpPC) {
return false;
if (!Ptr.isBlockPointer())
return false;
if (!(Ptr.getFieldDesc()->isPrimitive() ||
Ptr.getFieldDesc()->isPrimitiveArray()) ||
Ptr.getFieldDesc()->getPrimType() != Name)
return false;
S.Stk.push<T>(Ptr.deref<T>());
return true;
}
Expand Down Expand Up @@ -3286,12 +3294,18 @@ inline bool InvalidCast(InterpState &S, CodePtr OpPC, CastKind Kind,
bool Fatal) {
const SourceLocation &Loc = S.Current->getLocation(OpPC);

if (Kind == CastKind::Reinterpret) {
switch (Kind) {
case CastKind::Reinterpret:
S.CCEDiag(Loc, diag::note_constexpr_invalid_cast)
<< static_cast<unsigned>(Kind) << S.Current->getRange(OpPC);
<< diag::ConstexprInvalidCastKind::Reinterpret
<< S.Current->getRange(OpPC);
return !Fatal;
}
if (Kind == CastKind::Volatile) {
case CastKind::ReinterpretLike:
S.CCEDiag(Loc, diag::note_constexpr_invalid_cast)
<< diag::ConstexprInvalidCastKind::ThisConversionOrReinterpret
<< S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);
return !Fatal;
case CastKind::Volatile:
if (!S.checkingPotentialConstantExpression()) {
const auto *E = cast<CastExpr>(S.Current->getExpr(OpPC));
if (S.getLangOpts().CPlusPlus)
Expand All @@ -3302,14 +3316,13 @@ inline bool InvalidCast(InterpState &S, CodePtr OpPC, CastKind Kind,
}

return false;
}
if (Kind == CastKind::Dynamic) {
case CastKind::Dynamic:
assert(!S.getLangOpts().CPlusPlus20);
S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_invalid_cast)
S.CCEDiag(Loc, diag::note_constexpr_invalid_cast)
<< diag::ConstexprInvalidCastKind::Dynamic;
return true;
}

llvm_unreachable("Unhandled CastKind");
return false;
}

Expand Down
4 changes: 4 additions & 0 deletions clang/lib/AST/ByteCode/PrimType.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ inline constexpr bool isSignedType(PrimType T) {

enum class CastKind : uint8_t {
Reinterpret,
ReinterpretLike,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would Bitwise be better than ReinterpretLike?

Volatile,
Dynamic,
};
Expand All @@ -111,6 +112,9 @@ inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
case interp::CastKind::Reinterpret:
OS << "reinterpret_cast";
break;
case interp::CastKind::ReinterpretLike:
OS << "reinterpret_like";
break;
case interp::CastKind::Volatile:
OS << "volatile";
break;
Expand Down
50 changes: 11 additions & 39 deletions clang/lib/AST/ByteCode/Program.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,30 +36,19 @@ unsigned Program::createGlobalString(const StringLiteral *S, const Expr *Base) {
const size_t BitWidth = CharWidth * Ctx.getCharBit();
unsigned StringLength = S->getLength();

PrimType CharType;
switch (CharWidth) {
case 1:
CharType = PT_Sint8;
break;
case 2:
CharType = PT_Uint16;
break;
case 4:
CharType = PT_Uint32;
break;
default:
llvm_unreachable("unsupported character width");
}
OptPrimType CharType =
Ctx.classify(S->getType()->castAsArrayTypeUnsafe()->getElementType());
assert(CharType);

if (!Base)
Base = S;

// Create a descriptor for the string.
Descriptor *Desc =
allocateDescriptor(Base, CharType, Descriptor::GlobalMD, StringLength + 1,
/*isConst=*/true,
/*isTemporary=*/false,
/*isMutable=*/false);
Descriptor *Desc = allocateDescriptor(Base, *CharType, Descriptor::GlobalMD,
StringLength + 1,
/*isConst=*/true,
/*isTemporary=*/false,
/*isMutable=*/false);

// Allocate storage for the string.
// The byte length does not include the null terminator.
Expand All @@ -79,26 +68,9 @@ unsigned Program::createGlobalString(const StringLiteral *S, const Expr *Base) {
} else {
// Construct the string in storage.
for (unsigned I = 0; I <= StringLength; ++I) {
const uint32_t CodePoint = I == StringLength ? 0 : S->getCodeUnit(I);
switch (CharType) {
case PT_Sint8: {
using T = PrimConv<PT_Sint8>::T;
Ptr.elem<T>(I) = T::from(CodePoint, BitWidth);
break;
}
case PT_Uint16: {
using T = PrimConv<PT_Uint16>::T;
Ptr.elem<T>(I) = T::from(CodePoint, BitWidth);
break;
}
case PT_Uint32: {
using T = PrimConv<PT_Uint32>::T;
Ptr.elem<T>(I) = T::from(CodePoint, BitWidth);
break;
}
default:
llvm_unreachable("unsupported character type");
}
uint32_t CodePoint = I == StringLength ? 0 : S->getCodeUnit(I);
INT_TYPE_SWITCH_NO_BOOL(*CharType,
Ptr.elem<T>(I) = T::from(CodePoint, BitWidth););
}
}
Ptr.initializeAllElements();
Expand Down
23 changes: 23 additions & 0 deletions clang/test/AST/ByteCode/invalid.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,26 @@ struct S {
S s;
S *sp[2] = {&s, &s};
S *&spp = sp[1];

namespace InvalidBitCast {
void foo() {
const long long int i = 1; // both-note {{declared const here}}
if (*(double *)&i == 2) {
i = 0; // both-error {{cannot assign to variable}}
}
}

struct S2 {
void *p;
};
struct T {
S2 s;
};
constexpr T t = {{nullptr}};
constexpr void *foo2() { return ((void **)&t)[0]; } // both-error {{never produces a constant expression}} \
// both-note 2{{cast that performs the conversions of a reinterpret_cast}}
constexpr auto x = foo2(); // both-error {{must be initialized by a constant expression}} \
// both-note {{in call to}}


}