Skip to content
Merged
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: 5 additions & 17 deletions clang/lib/AST/ByteCode/Compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -208,19 +208,6 @@ 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 @@ -506,12 +493,9 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) {
if (!FromT || !ToT)
return false;

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

assert(isPtrType(*FromT));
assert(isPtrType(*ToT));
bool SrcIsVoidPtr = SubExprTy->isVoidPointerType();
if (FromT == ToT) {
if (CE->getType()->isVoidPointerType() &&
!SubExprTy->isFunctionPointerType()) {
Expand All @@ -520,6 +504,10 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) {

if (!this->visit(SubExpr))
return false;
if (!this->emitCheckBitCast(CETy->getPointeeType().getTypePtr(),
SrcIsVoidPtr, CE))
return false;

if (CE->getType()->isFunctionPointerType() ||
SubExprTy->isFunctionPointerType()) {
return this->emitFnPtrCast(CE);
Expand Down
2 changes: 0 additions & 2 deletions clang/lib/AST/ByteCode/Compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -425,8 +425,6 @@ 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
46 changes: 46 additions & 0 deletions clang/lib/AST/ByteCode/Interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -3290,6 +3290,52 @@ inline bool SideEffect(InterpState &S, CodePtr OpPC) {
return S.noteSideEffect();
}

inline bool CheckBitCast(InterpState &S, CodePtr OpPC, const Type *TargetType,
bool SrcIsVoidPtr) {
const auto &Ptr = S.Stk.peek<Pointer>();
if (Ptr.isZero())
return true;
if (!Ptr.isBlockPointer())
return true;

if (TargetType->isIntegerType())
return true;

if (SrcIsVoidPtr && S.getLangOpts().CPlusPlus) {
bool HasValidResult = !Ptr.isZero();

if (HasValidResult) {
if (S.getStdAllocatorCaller("allocate"))
return true;

const auto &E = cast<CastExpr>(S.Current->getExpr(OpPC));
if (S.getLangOpts().CPlusPlus26 &&
S.getASTContext().hasSimilarType(Ptr.getType(),
QualType(TargetType, 0)))
return true;

S.CCEDiag(E, diag::note_constexpr_invalid_void_star_cast)
<< E->getSubExpr()->getType() << S.getLangOpts().CPlusPlus26
<< Ptr.getType().getCanonicalType() << E->getType()->getPointeeType();
} else if (!S.getLangOpts().CPlusPlus26) {
const SourceInfo &E = S.Current->getSource(OpPC);
S.CCEDiag(E, diag::note_constexpr_invalid_cast)
<< diag::ConstexprInvalidCastKind::CastFrom << "'void *'"
<< S.Current->getRange(OpPC);
}
}

QualType PtrType = Ptr.getType();
if (PtrType->isRecordType() &&
PtrType->getAsRecordDecl() != TargetType->getAsRecordDecl()) {
S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_invalid_cast)
<< diag::ConstexprInvalidCastKind::ThisConversionOrReinterpret
<< S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);
return false;
}
return true;
}

/// Same here, but only for casts.
inline bool InvalidCast(InterpState &S, CodePtr OpPC, CastKind Kind,
bool Fatal) {
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/ByteCode/Opcodes.td
Original file line number Diff line number Diff line change
Expand Up @@ -422,8 +422,8 @@ def CheckLiteralType : Opcode {
}

def CheckArraySize : Opcode { let Args = [ArgUint64]; }

def CheckFunctionDecl : Opcode { let Args = [ArgFunctionDecl]; }
def CheckBitCast : Opcode { let Args = [ArgTypePtr, ArgBool]; }

// [] -> [Value]
def GetGlobal : AccessOpcode;
Expand Down
11 changes: 11 additions & 0 deletions clang/test/AST/ByteCode/cxx11.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -387,3 +387,14 @@ struct Counter {
// Passing an lvalue by value makes a non-elidable copy.
constexpr int PassByValue(Counter c) { return c.copies; }
static_assert(PassByValue(Counter(0)) == 0, "expect no copies");

namespace PointerCast {
/// The two interpreters disagree here.
struct S { int x, y; } s;
constexpr S* sptr = &s;
struct U {};
struct Str {
int e : (Str*)(sptr) == (Str*)(sptr); // expected-error {{not an integral constant expression}} \
// expected-note {{cast that performs the conversions of a reinterpret_cast}}
};
}
18 changes: 18 additions & 0 deletions clang/test/AST/ByteCode/invalid.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,4 +88,22 @@ namespace InvalidBitCast {
// both-note {{in call to}}


struct sockaddr
{
char sa_data[8];
};
struct in_addr
{
unsigned int s_addr;
};
struct sockaddr_in
{
unsigned short int sin_port;
struct in_addr sin_addr;
};
/// Bitcast from sockaddr to sockaddr_in. Used to crash.
unsigned int get_addr(sockaddr addr) {
return ((sockaddr_in *)&addr)->sin_addr.s_addr;
}

}