diff options
author | Argyrios Kyrtzidis <akyrtzi@gmail.com> | 2011-05-02 18:21:19 +0000 |
---|---|---|
committer | Argyrios Kyrtzidis <akyrtzi@gmail.com> | 2011-05-02 18:21:19 +0000 |
commit | f4bbbf0aaf741cc7d014e2cf059670a6756f8cbd (patch) | |
tree | f00903dbb4602d61bedeedc340e10637859f051b /lib | |
parent | c6d07821c529bb95e4cf072e49b736c5142f1786 (diff) |
Add a warning for when reinterpret_cast leads to undefined behavior, patch by Richard Trieu!
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@130703 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Sema/SemaCXXCast.cpp | 60 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 8 |
2 files changed, 67 insertions, 1 deletions
diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp index ed54f0f544..2ea3b46829 100644 --- a/lib/Sema/SemaCXXCast.cpp +++ b/lib/Sema/SemaCXXCast.cpp @@ -1288,6 +1288,61 @@ static TryCastResult TryConstCast(Sema &Self, Expr *SrcExpr, QualType DestType, return TC_Success; } +// Checks for undefined behavior in reinterpret_cast. +// The cases that is checked for is: +// *reinterpret_cast<T*>(&a) +// reinterpret_cast<T&>(a) +// where accessing 'a' as type 'T' will result in undefined behavior. +void Sema::CheckCompatibleReinterpretCast(QualType SrcType, QualType DestType, + bool IsDereference, + SourceRange Range) { + unsigned DiagID = IsDereference ? + diag::warn_pointer_indirection_from_incompatible_type : + diag::warn_undefined_reinterpret_cast; + + if (Diags.getDiagnosticLevel(DiagID, Range.getBegin()) == + Diagnostic::Ignored) { + return; + } + + QualType SrcTy, DestTy; + if (IsDereference) { + if (!SrcType->getAs<PointerType>() || !DestType->getAs<PointerType>()) { + return; + } + SrcTy = SrcType->getPointeeType(); + DestTy = DestType->getPointeeType(); + } else { + if (!DestType->getAs<ReferenceType>()) { + return; + } + SrcTy = SrcType; + DestTy = DestType->getPointeeType(); + } + + // Cast is compatible if the types are the same. + if (Context.hasSameUnqualifiedType(DestTy, SrcTy)) { + return; + } + // or one of the types is a char or void type + if (DestTy->isAnyCharacterType() || DestTy->isVoidType() || + SrcTy->isAnyCharacterType() || SrcTy->isVoidType()) { + return; + } + // or one of the types is a tag type. + if (isa<TagType>(SrcTy) || isa<TagType>(DestTy)) { + return; + } + + if ((SrcTy->isUnsignedIntegerType() && DestTy->isSignedIntegerType()) || + (SrcTy->isSignedIntegerType() && DestTy->isUnsignedIntegerType())) { + if (Context.getTypeSize(DestTy) == Context.getTypeSize(SrcTy)) { + return; + } + } + + Diag(Range.getBegin(), DiagID) << SrcType << DestType << Range; +} static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, bool CStyle, @@ -1324,6 +1379,11 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, return TC_NotApplicable; } + if (!CStyle) { + Self.CheckCompatibleReinterpretCast(SrcType, DestType, + /*isDereference=*/false, OpRange); + } + // C++ 5.2.10p10: [...] a reference cast reinterpret_cast<T&>(x) has the // same effect as the conversion *reinterpret_cast<T*>(&x) with the // built-in & and * operators. diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 20b92b8420..afcde44814 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -8404,7 +8404,13 @@ static QualType CheckIndirectionOperand(Sema &S, Expr *Op, ExprValueKind &VK, Op = ConvResult.take(); QualType OpTy = Op->getType(); QualType Result; - + + if (isa<CXXReinterpretCastExpr>(Op)) { + QualType OpOrigType = Op->IgnoreParenCasts()->getType(); + S.CheckCompatibleReinterpretCast(OpOrigType, OpTy, /*IsDereference*/true, + Op->getSourceRange()); + } + // Note that per both C89 and C99, indirection is always legal, even if OpTy // is an incomplete type or void. It would be possible to warn about // dereferencing a void pointer, but it's completely well-defined, and such a |