llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Aaron Ballman (AaronBallman) <details> <summary>Changes</summary> This silences the diagnostic when the right-hand side is a null pointer constant that comes from a macro expansion, such as NULL. However, we do not limit to just NULL because other custom macros may expand to an implicit void * cast in C while expanding to something else in C++. --- Full diff: https://github.com/llvm/llvm-project/pull/140724.diff 2 Files Affected: - (modified) clang/lib/Sema/SemaExpr.cpp (+7-2) - (modified) clang/test/Sema/implicit-void-ptr-cast.c (+22) ``````````diff diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index b18e83b605e4f..6b04f8150b0a1 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -9966,8 +9966,13 @@ AssignConvertType Sema::CheckSingleAssignmentConstraints(QualType LHSType, // If there is a conversion of some kind, check to see what kind of // pointer conversion happened so we can diagnose a C++ compatibility // diagnostic if the conversion is invalid. This only matters if the RHS - // is some kind of void pointer. - if (Kind != CK_NoOp && !getLangOpts().CPlusPlus) { + // is some kind of void pointer. We have a carve-out when the RHS is from + // a macro expansion because the use of a macro may indicate different + // code between C and C++. Consider: char *s = NULL; where NULL is + // defined as (void *)0 in C (which would be invalid in C++), but 0 in + // C++, which is valid in C++. + if (Kind != CK_NoOp && !getLangOpts().CPlusPlus && + !RHS.get()->getBeginLoc().isMacroID()) { QualType CanRHS = RHS.get()->getType().getCanonicalType().getUnqualifiedType(); QualType CanLHS = LHSType.getCanonicalType().getUnqualifiedType(); diff --git a/clang/test/Sema/implicit-void-ptr-cast.c b/clang/test/Sema/implicit-void-ptr-cast.c index a469c49c36b49..3c3e153d1dbda 100644 --- a/clang/test/Sema/implicit-void-ptr-cast.c +++ b/clang/test/Sema/implicit-void-ptr-cast.c @@ -59,4 +59,26 @@ void more(void) { b3 = (char *)0; b3 = nullptr; b3 = 0; + + // Note that we explicitly silence the diagnostic if the RHS is from a macro + // expansion. This allows for things like NULL expanding to different token + // sequences depending on language mode, but applies to any macro that + // expands to a valid null pointer constant. +#if defined(__cplusplus) + #define NULL 0 +#else + #define NULL ((void *)0) +#endif + #define SOMETHING_NOT_SPELLED_NULL nullptr + #define SOMETHING_THAT_IS_NOT_NULL (void *)12 + + char *ptr1 = NULL; // Ok + char *ptr2 = SOMETHING_NOT_SPELLED_NULL; // Ok + char *ptr3 = SOMETHING_THAT_IS_NOT_NULL; // c-warning {{implicit conversion when initializing 'char *' with an expression of type 'void *' is not permitted in C++}} \ + cxx-error {{cannot initialize a variable of type 'char *' with an rvalue of type 'void *'}} + + ptr1 = NULL; // Ok + ptr2 = SOMETHING_NOT_SPELLED_NULL; // Ok + ptr3 = SOMETHING_THAT_IS_NOT_NULL; // c-warning {{implicit conversion when assigning to 'char *' from type 'void *' is not permitted in C++}} \ + cxx-error {{assigning to 'char *' from incompatible type 'void *'}} } `````````` </details> https://github.com/llvm/llvm-project/pull/140724 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits