Author: Oleksandr T. Date: 2025-02-14T19:06:30+02:00 New Revision: 3e94fc0682952f6f996809f83e9e67f6d5e1989e
URL: https://github.com/llvm/llvm-project/commit/3e94fc0682952f6f996809f83e9e67f6d5e1989e DIFF: https://github.com/llvm/llvm-project/commit/3e94fc0682952f6f996809f83e9e67f6d5e1989e.diff LOG: [Clang] allow restrict qualifier for array types with pointer types as element types (#120896) Fixes #92847 --- > Types other than pointer types whose referenced type is an object type and (possibly multi-dimensional) array types with such pointer types as element type shall not be restrict-qualified. Added: clang/test/Sema/pre-c2x-restrict-qualifier.c clang/test/Sema/restrict-qualifier.c Modified: clang/docs/ReleaseNotes.rst clang/include/clang/Basic/DiagnosticSemaKinds.td clang/lib/Sema/SemaType.cpp clang/test/Sema/types.c Removed: ################################################################################ diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 5c69415d16489..6056a6964fbcc 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -93,6 +93,7 @@ C Language Changes - Clang now allows an ``inline`` specifier on a typedef declaration of a function type in Microsoft compatibility mode. #GH124869 +- Clang now allows ``restrict`` qualifier for array types with pointer elements (#GH92847). C2y Feature Support ^^^^^^^^^^^^^^^^^^^ diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 2fce5e88ba8a0..c4f0fc55b4a38 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -7413,6 +7413,11 @@ def warn_c23_compat_utf8_string : Warning< def note_cxx20_c23_compat_utf8_string_remove_u8 : Note< "remove 'u8' prefix to avoid a change of behavior; " "Clang encodes unprefixed narrow string literals as UTF-8">; +def warn_c23_compat_restrict_on_array_of_pointers : Warning< + "'restrict' qualifier on an array of pointers is incompatible with C standards before C23">, + InGroup<CPre23Compat>, DefaultIgnore; +def ext_restrict_on_array_of_pointers_c23 : Extension< + "'restrict' qualifier on an array of pointers is a C23 extension">, InGroup<C23>; def err_array_init_ diff erent_type : Error< "cannot initialize array % diff {of type $ with array of type $|" "with diff erent type of array}0,1">; diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 6f30a36621601..db0177f9750e0 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -1593,35 +1593,38 @@ QualType Sema::BuildQualifiedType(QualType T, SourceLocation Loc, // object or incomplete types shall not be restrict-qualified." if (Qs.hasRestrict()) { unsigned DiagID = 0; - QualType ProblemTy; - - if (T->isAnyPointerType() || T->isReferenceType() || - T->isMemberPointerType()) { - QualType EltTy; - if (T->isObjCObjectPointerType()) - EltTy = T; - else if (const MemberPointerType *PTy = T->getAs<MemberPointerType>()) + QualType EltTy = Context.getBaseElementType(T); + + if (EltTy->isAnyPointerType() || EltTy->isReferenceType() || + EltTy->isMemberPointerType()) { + + if (const auto *PTy = EltTy->getAs<MemberPointerType>()) EltTy = PTy->getPointeeType(); else - EltTy = T->getPointeeType(); + EltTy = EltTy->getPointeeType(); // If we have a pointer or reference, the pointee must have an object // incomplete type. - if (!EltTy->isIncompleteOrObjectType()) { + if (!EltTy->isIncompleteOrObjectType()) DiagID = diag::err_typecheck_invalid_restrict_invalid_pointee; - ProblemTy = EltTy; - } + } else if (!isDependentOrGNUAutoType(T)) { // For an __auto_type variable, we may not have seen the initializer yet // and so have no idea whether the underlying type is a pointer type or // not. DiagID = diag::err_typecheck_invalid_restrict_not_pointer; - ProblemTy = T; + EltTy = T; } + Loc = DS ? DS->getRestrictSpecLoc() : Loc; if (DiagID) { - Diag(DS ? DS->getRestrictSpecLoc() : Loc, DiagID) << ProblemTy; + Diag(Loc, DiagID) << EltTy; Qs.removeRestrict(); + } else { + if (T->isArrayType()) + Diag(Loc, getLangOpts().C23 + ? diag::warn_c23_compat_restrict_on_array_of_pointers + : diag::ext_restrict_on_array_of_pointers_c23); } } diff --git a/clang/test/Sema/pre-c2x-restrict-qualifier.c b/clang/test/Sema/pre-c2x-restrict-qualifier.c new file mode 100644 index 0000000000000..5395180ee66b0 --- /dev/null +++ b/clang/test/Sema/pre-c2x-restrict-qualifier.c @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -std=c23 -fsyntax-only -verify %s +// RUN: %clang_cc1 -std=c17 -fsyntax-only -pedantic -verify=pedantic,expected %s +// RUN: %clang_cc1 -std=c2x -fsyntax-only -Wpre-c2x-compat -verify=c2x-compat,expected %s + +typedef int (*T1)[2]; +restrict T1 t1; + +typedef int *T2[2]; +restrict T2 t2; // pedantic-warning {{'restrict' qualifier on an array of pointers is a C23 extension}} \ + // c2x-compat-warning {{'restrict' qualifier on an array of pointers is incompatible with C standards before C23}} + +typedef int *T3[2][2]; +restrict T3 t3; // pedantic-warning {{'restrict' qualifier on an array of pointers is a C23 extension}} \ + // c2x-compat-warning {{'restrict' qualifier on an array of pointers is incompatible with C standards before C23}} + +typedef int (*t4)(); // pedantic-warning {{a function declaration without a prototype is deprecated in all versions of C}} +typedef t4 t5[2]; +typedef t5 restrict t6; // // expected-error-re {{pointer to function type 'int {{\((void)?\)}}' may not be 'restrict' qualified}} + +typedef int t7[2]; +typedef t7 restrict t8; // expected-error {{restrict requires a pointer or reference ('t7' (aka 'int[2]') is invalid)}} diff --git a/clang/test/Sema/restrict-qualifier.c b/clang/test/Sema/restrict-qualifier.c new file mode 100644 index 0000000000000..f96961c9c3314 --- /dev/null +++ b/clang/test/Sema/restrict-qualifier.c @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -std=c2y -fsyntax-only -verify -pedantic %s + +typedef int (*T1)[2]; +restrict T1 t1; +static_assert(_Generic(typeof (t1), int (*restrict)[2] : 1, default : 0)); + +typedef int *T2[2]; +restrict T2 t2; +static_assert(_Generic(typeof (t2), int *restrict[2] : 1, default : 0)); + +typedef int *T3[2][2]; +restrict T3 t3; +static_assert(_Generic(typeof (t3), int *restrict[2][2] : 1, default : 0)); +static_assert(_Generic(void(T3 restrict), void(int *restrict (*)[2]): 1, default: 0)); + +typedef int (*t4)(); +typedef t4 t5[2]; +typedef t5 restrict t6; // expected-error {{pointer to function type 'int (void)' may not be 'restrict' qualified}} + +typedef int t7[2]; +typedef t7 restrict t8; // expected-error {{restrict requires a pointer or reference ('t7' (aka 'int[2]')}} diff --git a/clang/test/Sema/types.c b/clang/test/Sema/types.c index e0a6ba4f0691b..2a5f530740e9a 100644 --- a/clang/test/Sema/types.c +++ b/clang/test/Sema/types.c @@ -9,20 +9,20 @@ typedef int (*T)[2]; restrict T x; typedef int *S[2]; -restrict S y; // expected-error {{restrict requires a pointer or reference ('S' (aka 'int *[2]') is invalid)}} - - +restrict S y; // expected-warning {{'restrict' qualifier on an array of pointers is a C23 extension}} // int128_t is available. -int a(void) { +void a(void) { __int128_t s; __uint128_t t; } + // but not a keyword -int b(void) { +void b(void) { int __int128_t; int __uint128_t; } + // __int128 is a keyword int c(void) { __int128 i; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits