Index: docs/ReleaseNotes.rst =================================================================== --- docs/ReleaseNotes.rst +++ docs/ReleaseNotes.rst @@ -52,6 +52,8 @@ Improvements to Clang's diagnostics ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +- -Wcast-qual was implemented for C++ (for pointers only, not references) + - -Wunused-lambda-capture warns when a variable explicitly captured by a lambda is not used in the body of the lambda. Index: lib/Sema/SemaCast.cpp =================================================================== --- lib/Sema/SemaCast.cpp +++ lib/Sema/SemaCast.cpp @@ -143,6 +143,9 @@ }; } +static void DiagnoseCastQual(Sema &Self, const ExprResult &SrcExpr, + QualType DestType); + // The Try functions attempt a specific way of casting. If they succeed, they // return TC_Success. If their way of casting is not appropriate for the given // arguments, they return TC_NotApplicable and *may* set diag to a diagnostic @@ -741,7 +744,8 @@ Self.Diag(OpRange.getBegin(), msg) << CT_Const << SrcExpr.get()->getType() << DestType << OpRange; SrcExpr = ExprError(); - } + } else + DiagnoseCastQual(Self, SrcExpr, DestType); } /// Check that a reinterpret_cast\(SrcExpr) is not used as upcast @@ -2177,6 +2181,8 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle, bool ListInitialization) { + assert(Self.getLangOpts().CPlusPlus); + // Handle placeholders. if (isPlaceholder()) { // C-style casts can resolve __unknown_any types. @@ -2305,6 +2311,9 @@ // Clear out SrcExpr if there was a fatal error. if (tcr != TC_Success) SrcExpr = ExprError(); + + // -Wcast-qual + DiagnoseCastQual(Self, SrcExpr, DestType); } /// DiagnoseBadFunctionCast - Warn whenever a function call is cast to a @@ -2582,28 +2591,42 @@ checkCastAlign(); // -Wcast-qual + DiagnoseCastQual(Self, SrcExpr, DestType); +} + +/// DiagnoseCastQual - Warn whenever casts discards a qualifiers, be it either +/// const, volatile or both. +static void DiagnoseCastQual(Sema &Self, const ExprResult &SrcExpr, + QualType DestType) { + if (SrcExpr.isInvalid()) + return; + + QualType SrcType = SrcExpr.get()->getType(); + if (!(SrcType->isAnyPointerType() && DestType->isAnyPointerType())) + return; + QualType TheOffendingSrcType, TheOffendingDestType; Qualifiers CastAwayQualifiers; - if (SrcType->isAnyPointerType() && DestType->isAnyPointerType() && - CastsAwayConstness(Self, SrcType, DestType, true, false, - &TheOffendingSrcType, &TheOffendingDestType, - &CastAwayQualifiers)) { - int qualifiers = -1; - if (CastAwayQualifiers.hasConst() && CastAwayQualifiers.hasVolatile()) { - qualifiers = 0; - } else if (CastAwayQualifiers.hasConst()) { - qualifiers = 1; - } else if (CastAwayQualifiers.hasVolatile()) { - qualifiers = 2; - } - // This is a variant of int **x; const int **y = (const int **)x; - if (qualifiers == -1) - Self.Diag(SrcExpr.get()->getLocStart(), diag::warn_cast_qual2) << - SrcType << DestType; - else - Self.Diag(SrcExpr.get()->getLocStart(), diag::warn_cast_qual) << - TheOffendingSrcType << TheOffendingDestType << qualifiers; + if (!CastsAwayConstness(Self, SrcType, DestType, true, false, + &TheOffendingSrcType, &TheOffendingDestType, + &CastAwayQualifiers)) + return; + + int qualifiers = -1; + if (CastAwayQualifiers.hasConst() && CastAwayQualifiers.hasVolatile()) { + qualifiers = 0; + } else if (CastAwayQualifiers.hasConst()) { + qualifiers = 1; + } else if (CastAwayQualifiers.hasVolatile()) { + qualifiers = 2; } + // This is a variant of int **x; const int **y = (const int **)x; + if (qualifiers == -1) + Self.Diag(SrcExpr.get()->getLocStart(), diag::warn_cast_qual2) + << SrcType << DestType; + else + Self.Diag(SrcExpr.get()->getLocStart(), diag::warn_cast_qual) + << TheOffendingSrcType << TheOffendingDestType << qualifiers; } ExprResult Sema::BuildCStyleCastExpr(SourceLocation LPLoc, Index: test/Sema/warn-cast-qual.c =================================================================== --- test/Sema/warn-cast-qual.c +++ test/Sema/warn-cast-qual.c @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -triple x86_64-unknown-unknown -fsyntax-only -Wcast-qual -verify %s +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -x c++ -fsyntax-only -Wcast-qual -verify %s #include @@ -26,4 +27,9 @@ const char **charptrptrc; char **charptrptr = (char **)charptrptrc; // expected-warning {{cast from 'const char *' to 'char *' drops const qualifier}} + + const char *constcharptr; + char *charptr = (char *)constcharptr; // expected-warning {{cast from 'const char *' to 'char *' drops const qualifier}} + const char *constcharptr2 = (char *)constcharptr; // expected-warning {{cast from 'const char *' to 'char *' drops const qualifier}} + const char *charptr2 = (char *)charptr; // no warning } Index: test/SemaCXX/warn-cast-qual.cpp =================================================================== --- /dev/null +++ test/SemaCXX/warn-cast-qual.cpp @@ -0,0 +1,58 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fsyntax-only -Wcast-qual -verify %s + +#include + +void foo() { + const char * const ptr = 0; + const char * const *ptrptr = 0; + const char * const x = const_cast(ptr); // no warning + char *y = const_cast(ptr); // expected-warning {{cast from 'const char *' to 'char *' drops const qualifier}} + char **y1 = const_cast(ptrptr); // expected-warning {{cast from 'const char *const' to 'char *' drops const qualifier}} + const char **y2 = const_cast(ptrptr); // expected-warning {{cast from 'const char *const *' to 'const char **' drops const qualifier}} + + char *z = reinterpret_cast(reinterpret_cast(static_cast(ptr))); // no warning + char *z1 = static_cast(const_cast(static_cast(ptr))); // expected-warning {{cast from 'const void *' to 'void *' drops const qualifier}} + + volatile char *vol = 0; + char *vol2 = const_cast(vol); // expected-warning {{cast from 'volatile char *' to 'char *' drops volatile qualifier}} + const volatile char *volc = 0; + char *volc2 = const_cast(volc); // expected-warning {{cast from 'const volatile char *' to 'char *' drops const and volatile qualifiers}} + + int **intptrptr = 0; + const int **intptrptrc = const_cast(intptrptr); // expected-warning {{cast from 'int **' to 'const int **' must have all intermediate pointers const qualified}} + volatile int **intptrptrv = const_cast(intptrptr); // expected-warning {{cast from 'int **' to 'volatile int **' must have all intermediate pointers const qualified}} + + int *intptr = 0; + const int *intptrc = const_cast(intptr); // no warning + + const char **charptrptrc = 0; + char **charptrptr = const_cast(charptrptrc); // expected-warning {{cast from 'const char *' to 'char *' drops const qualifier}} + + const char *constcharptr = 0; + const char *constcharptr2= const_cast(constcharptr); // no warning + char *charptr = const_cast(constcharptr); // expected-warning {{cast from 'const char *' to 'char *' drops const qualifier}} + const char *constcharptr3 = const_cast(constcharptr); // expected-warning {{cast from 'const char *' to 'char *' drops const qualifier}} + const char *charptr2 = static_cast(charptr); // no warning +} + +// FIXME +void bar() { + const int a = 0; + + const int &a0 = a; // no warning + const int &a1 = (const int &)a; // no warning + + int &a2 = (int &)a; + int &a3 = const_cast(a); + + const int &a4 = a3; // no warning + const int &a5 = (const int &)a3; // no warning + const int &a6 = const_cast(a3); // no warning + + const int &a7 = (int &)a; + const int &a8 = const_cast(a); + + const int &a9 = a8; // no warning + const int &a10 = (const int &)a8; // no warning + const int &a11 = const_cast(a8); // no warning +}