diff --git a/clang/lib/AST/AttrImpl.cpp b/clang/lib/AST/AttrImpl.cpp index 87afedba7b4b5..3a379891016f8 100644 --- a/clang/lib/AST/AttrImpl.cpp +++ b/clang/lib/AST/AttrImpl.cpp @@ -291,8 +291,8 @@ namespace { // - VariadicOMPInteropInfoArgument #define USE_DEFAULT_EQUALITY \ (std::is_same_v || std::is_same_v || \ - std::is_same_v || std::is_same_v || \ - std::is_same_v || std::is_enum_v || std::is_integral_v) + std::is_same_v || std::is_same_v || \ + std::is_enum_v || std::is_integral_v) template typename std::enable_if_t @@ -306,6 +306,20 @@ equalAttrArgs(T A1, T A2, StructuralEquivalenceContext &Context) { return A1 == A2; } +template <> +bool equalAttrArgs(ParamIdx P1, ParamIdx P2, + StructuralEquivalenceContext &) { + // ParamIdx can be invalid when representing an optional parameter that was + // not specified (e.g. the second argument of alloc_size(N)). + // ParamIdx::operator== asserts both sides are valid, so guard against the + // invalid case before delegating to it. + if (P1.isValid() != P2.isValid()) + return false; + if (!P1.isValid()) + return true; + return P1 == P2; +} + template bool equalAttrArgs(T *A1_B, T *A1_E, T *A2_B, T *A2_E, StructuralEquivalenceContext &Context) { diff --git a/clang/test/Sema/alloc-size.c b/clang/test/Sema/alloc-size.c index 93714894a630a..74e08cb9d22c2 100644 --- a/clang/test/Sema/alloc-size.c +++ b/clang/test/Sema/alloc-size.c @@ -58,3 +58,8 @@ int main() { my_malloc_fn_pointer_type f3 = fn2; my_other_malloc_fn_pointer_type f4 = fn2; } + +// Regression test for GH199407: structural equivalence of alloc_size attrs +// with an unset optional ParamIdx must not crash. +#define GH199407(Ty, Name) _Alignas(Ty) char Name[sizeof(Ty)] +GH199407(struct GH199407S { float *f(long) __attribute__((alloc_size(1))); }, gbuf); // expected-error 2{{field 'f' declared as a function}} expected-error{{redefinition of 'GH199407S'}} expected-note{{previous definition is here}} diff --git a/clang/test/Sema/attr-nonnull.c b/clang/test/Sema/attr-nonnull.c index 865348daef10e..54f3cde0d12eb 100644 --- a/clang/test/Sema/attr-nonnull.c +++ b/clang/test/Sema/attr-nonnull.c @@ -6,3 +6,8 @@ void f1(int *a1, int *a2, int *a3, int *a4, int *a5, int *a6, int *a7, int *a15, int *a16) __attribute__((nonnull(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16))); void f2(void) __attribute__((nonnull())); // expected-warning {{'nonnull' attribute applied to function with no pointer arguments}} + +// Regression test for GH199407: verify no crash when structural equivalence +// checks nonnull attrs with VariadicParamIdx (always-valid) elements. +#define GH199407(Ty, Name) _Alignas(Ty) char Name[sizeof(Ty)] +GH199407(struct GH199407T { void *g(void *p) __attribute__((nonnull(1))); }, gbuf); // expected-error 2{{field 'g' declared as a function}} expected-error{{redefinition of 'GH199407T'}} expected-note{{previous definition is here}}