- Clang now correctly points to the problematic parameter for the ``-Wnonnull``
warning. This fixes
`Issue 58273 <https://github.com/llvm/llvm-project/issues/58273>`_.
-- Introduced ``-Wcast-function-type-strict`` to warn about function type mismatches
- in casts that may result in runtime indirect call `Control-Flow Integrity (CFI)
- <https://clang.llvm.org/docs/ControlFlowIntegrity.html>`_ failures. This diagnostic
- is grouped under ``-Wcast-function-type`` as it identifies a more strict set of
- potentially problematic function type casts.
+- Introduced ``-Wcast-function-type-strict`` and
+ ``-Wincompatible-function-pointer-types-strict`` to warn about function type
+ mismatches in casts and assignments that may result in runtime indirect call
+ `Control-Flow Integrity (CFI)
+ <https://clang.llvm.org/docs/ControlFlowIntegrity.html>`_ failures. The
+ ``-Wcast-function-type-strict`` diagnostic is grouped under
+ ``-Wcast-function-type`` as it identifies a more strict set of potentially
+ problematic function type casts.
- Clang will now disambiguate NTTP types when printing diagnostic that contain NTTP types.
Fixes `Issue 57562 <https://github.com/llvm/llvm-project/issues/57562>`_.
- Better error recovery for pack expansion of expressions.
def ext_typecheck_convert_incompatible_function_pointer : ExtWarn<
err_typecheck_convert_incompatible_function_pointer.Text>,
InGroup<IncompatibleFunctionPointerTypes>, DefaultError;
+def warn_typecheck_convert_incompatible_function_pointer_strict : Warning<
+ err_typecheck_convert_incompatible_function_pointer.Text>,
+ InGroup<DiagGroup<"incompatible-function-pointer-types-strict">>, DefaultIgnore;
def ext_typecheck_convert_discards_qualifiers : ExtWarn<
"%select{%diff{assigning to $ from $|assigning to different types}0,1"
"|%diff{passing $ to parameter of type $|"
/// extension.
IncompatibleFunctionPointer,
+ /// IncompatibleFunctionPointerStrict - The assignment is between two
+ /// function pointer types that are not identical, but are compatible,
+ /// unless compiled with -fsanitize=cfi, in which case the type mismatch
+ /// may trip an indirect call runtime check.
+ IncompatibleFunctionPointerStrict,
+
/// IncompatiblePointerSign - The assignment is between two pointers types
/// which point to integers which have a different sign, but are otherwise
/// identical. This is a subset of the above, but broken out because it's by
// This circumvents the usual type rules specified in 6.2.7p1 & 6.7.5.[1-3].
// FIXME: add a couple examples in this comment.
static Sema::AssignConvertType
-checkPointerTypesForAssignment(Sema &S, QualType LHSType, QualType RHSType) {
+checkPointerTypesForAssignment(Sema &S, QualType LHSType, QualType RHSType,
+ SourceLocation Loc) {
assert(LHSType.isCanonical() && "LHS not canonicalized!");
assert(RHSType.isCanonical() && "RHS not canonicalized!");
return Sema::FunctionVoidPointer;
}
+ if (!S.Diags.isIgnored(
+ diag::warn_typecheck_convert_incompatible_function_pointer_strict,
+ Loc) &&
+ RHSType->isFunctionPointerType() && LHSType->isFunctionPointerType() &&
+ !S.IsFunctionConversion(RHSType, LHSType, RHSType))
+ return Sema::IncompatibleFunctionPointerStrict;
+
// C99 6.5.16.1p1 (constraint 3): both operands are pointers to qualified or
// unqualified versions of compatible types, ...
QualType ltrans = QualType(lhptee, 0), rtrans = QualType(rhptee, 0);
Kind = CK_NoOp;
else
Kind = CK_BitCast;
- return checkPointerTypesForAssignment(*this, LHSType, RHSType);
+ return checkPointerTypesForAssignment(*this, LHSType, RHSType,
+ RHS.get()->getBeginLoc());
}
// int -> T*
ConvHints.tryToFixConversion(SrcExpr, SrcType, DstType, *this);
MayHaveConvFixit = true;
break;
+ case IncompatibleFunctionPointerStrict:
+ DiagKind =
+ diag::warn_typecheck_convert_incompatible_function_pointer_strict;
+ ConvHints.tryToFixConversion(SrcExpr, SrcType, DstType, *this);
+ MayHaveConvFixit = true;
+ break;
case IncompatibleFunctionPointer:
if (getLangOpts().CPlusPlus) {
DiagKind = diag::err_typecheck_convert_incompatible_function_pointer;
--- /dev/null
+// RUN: %clang_cc1 -fsyntax-only %s -Wincompatible-function-pointer-types-strict -verify=soft,strict
+// RUN: %clang_cc1 -fsyntax-only %s -Werror=incompatible-function-pointer-types-strict -verify=hard,strict
+// RUN: %clang_cc1 -fsyntax-only %s -Wincompatible-function-pointer-types -verify=nonstrict
+// nonstrict-no-diagnostics
+
+enum E { A = -1, B };
+typedef enum E (*fn_a_t)(void);
+typedef void (*fn_b_t)(void);
+
+int a(void) { return 0; }
+void __attribute__((noreturn)) b(void) { while (1); }
+
+void fa(fn_a_t x) {} // strict-note {{passing argument to parameter 'x' here}}
+void fb(fn_b_t x) {}
+
+void baz(void) {
+ fa(&a); // soft-warning {{incompatible function pointer types passing 'int (*)(void)' to parameter of type 'fn_a_t' (aka 'enum E (*)(void)')}} \
+ hard-error {{incompatible function pointer types passing 'int (*)(void)' to parameter of type 'fn_a_t' (aka 'enum E (*)(void)')}}
+ fb(&b); // no-warning
+}