Index: clang/docs/ReleaseNotes.rst =================================================================== --- clang/docs/ReleaseNotes.rst +++ clang/docs/ReleaseNotes.rst @@ -62,6 +62,11 @@ either return ``None`` or a ``llvm::Optional`` wrapping a valid ``Expr*``. This fixes `Issue 53742 `_. +- Now allow the `restrict` and `_Atomic` qualifiers to be used in conjunction + with `__auto_type` to match the behavior in GCC. This fixes + `Issue 53652 `_. + + Improvements to Clang's diagnostics ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - ``-Wliteral-range`` will warn on floating-point equality comparisons with Index: clang/lib/AST/ASTContext.cpp =================================================================== --- clang/lib/AST/ASTContext.cpp +++ clang/lib/AST/ASTContext.cpp @@ -10285,7 +10285,16 @@ if (RHS->isObjCIdType() && LHS->isBlockPointerType()) return RHS; } - + // Allow __auto_type to match anything; it merges to the type with more + // information. + if (const auto *AT = LHS->getAs()) { + if (AT->getKeyword() == AutoTypeKeyword::GNUAutoType) + return RHS; + } + if (const auto *AT = LHS->getAs()) { + if (AT->getKeyword() == AutoTypeKeyword::GNUAutoType) + return RHS; + } return {}; } Index: clang/lib/Sema/SemaExpr.cpp =================================================================== --- clang/lib/Sema/SemaExpr.cpp +++ clang/lib/Sema/SemaExpr.cpp @@ -9399,6 +9399,15 @@ return Compatible; } + // If the LHS has an __auto_type, there are no additional type constraints + // to be worried about. + if (const auto *AT = dyn_cast(LHSType)) { + if (AT->getKeyword() == AutoTypeKeyword::GNUAutoType) { + Kind = CK_NoOp; + return Compatible; + } + } + // If we have an atomic type, try a non-atomic assignment, then just add an // atomic qualification step. if (const AtomicType *AtomicTy = dyn_cast(LHSType)) { Index: clang/lib/Sema/SemaType.cpp =================================================================== --- clang/lib/Sema/SemaType.cpp +++ clang/lib/Sema/SemaType.cpp @@ -1880,6 +1880,14 @@ return "type name"; } +static bool isDependentOrGNUAutoType(QualType T) { + if (T->isDependentType()) + return true; + + const auto *AT = dyn_cast(T); + return AT && AT->getKeyword() == AutoTypeKeyword::GNUAutoType; +} + QualType Sema::BuildQualifiedType(QualType T, SourceLocation Loc, Qualifiers Qs, const DeclSpec *DS) { if (T.isNull()) @@ -1913,9 +1921,15 @@ DiagID = diag::err_typecheck_invalid_restrict_invalid_pointee; ProblemTy = EltTy; } - } else if (!T->isDependentType()) { - DiagID = diag::err_typecheck_invalid_restrict_not_pointer; - ProblemTy = T; + } 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. + const auto *AT = dyn_cast(T); + if (!AT || AT->getKeyword() != AutoTypeKeyword::GNUAutoType) { + DiagID = diag::err_typecheck_invalid_restrict_not_pointer; + ProblemTy = T; + } } if (DiagID) { @@ -9101,7 +9115,7 @@ } QualType Sema::BuildAtomicType(QualType T, SourceLocation Loc) { - if (!T->isDependentType()) { + if (!isDependentOrGNUAutoType(T)) { // FIXME: It isn't entirely clear whether incomplete atomic types // are allowed or not; for simplicity, ban them for the moment. if (RequireCompleteType(Loc, T, diag::err_atomic_specifier_bad_type, 0)) Index: clang/test/Sema/auto-type.c =================================================================== --- clang/test/Sema/auto-type.c +++ clang/test/Sema/auto-type.c @@ -24,3 +24,39 @@ int k(l) __auto_type l; // expected-error {{'__auto_type' not allowed in K&R-style function parameter}} {} + +void Issue53652(void) { + // Ensure that qualifiers all work the same way as GCC. + const __auto_type cat = a; + const __auto_type pcat = &a; + volatile __auto_type vat = a; + volatile __auto_type pvat = &a; + restrict __auto_type rat = &a; + _Atomic __auto_type aat1 = a; + _Atomic __auto_type paat = &a; + + // GCC does not accept this either, for the same reason. + _Atomic(__auto_type) aat2 = a; // expected-error {{'__auto_type' not allowed here}} \ + // expected-warning {{type specifier missing, defaults to 'int'}} + + // Ensure the types are what we expect them to be. + _Static_assert(__builtin_types_compatible_p(__typeof(cat), const int), ""); + _Static_assert(__builtin_types_compatible_p(__typeof(pcat), int *const), ""); + _Static_assert(__builtin_types_compatible_p(__typeof(vat), volatile int), ""); + _Static_assert(__builtin_types_compatible_p(__typeof(pvat), int *volatile), ""); + _Static_assert(__builtin_types_compatible_p(__typeof(rat), int *restrict), ""); + _Static_assert(__builtin_types_compatible_p(__typeof(aat1), _Atomic int), ""); + _Static_assert(__builtin_types_compatible_p(__typeof(paat), _Atomic(int *)), ""); + + // Ensure the types also work in generic selection expressions. Remember, the + // type of the expression argument to _Generic is treated as-if it undergoes + // lvalue to rvalue conversion, which drops qualifiers. We're making sure the + // use of __auto_type doesn't impact that. + (void)_Generic(cat, int : 0); + (void)_Generic(pcat, int * : 0); + (void)_Generic(vat, int : 0); + (void)_Generic(pvat, int * : 0); + (void)_Generic(rat, int * : 0); + (void)_Generic(aat1, int : 0); + (void)_Generic(paat, int * : 0); +}