[C23] Allow deducing restrict and _Atomic qualifiers (#207994)
We were limiting the logic to __auto_type when it should apply to auto as well. Fixes #207466
This commit is contained in:
1 parent
5343b20425
commit
849d90b64e
4 files changed
+34
-19
No files matched your search
@@ -299,6 +299,9 @@ latest release, please see the [Clang Web Site](https://clang.llvm.org) or the
|
||||
- Clang now recognizes the C23 `H`, `D`, and `DD` length modifiers in
|
||||
format strings and diagnoses their use because Clang does not yet support
|
||||
the corresponding decimal floating-point types, `_Decimal32`, `_Decimal64`, and `_Decimal128`. (#GH116962)
|
||||
- Fixed a bug with deducing qualified inferred types with `auto`. `auto` can now
|
||||
be combined with `restrict` or `_Atomic` to form a properly-qualified type. (#GH207466)
|
||||
|
||||
|
||||
### Objective-C Language Changes
|
||||
|
||||
|
||||
@@ -1608,14 +1608,6 @@ static std::string getPrintableNameForEntity(DeclarationName Entity) {
|
||||
return "type name";
|
||||
}
|
||||
|
||||
static bool isDependentOrGNUAutoType(QualType T) {
|
||||
if (T->isDependentType())
|
||||
return true;
|
||||
|
||||
const auto *AT = dyn_cast<AutoType>(T);
|
||||
return AT && AT->isGNUAutoType();
|
||||
}
|
||||
|
||||
QualType Sema::BuildQualifiedType(QualType T, SourceLocation Loc,
|
||||
Qualifiers Qs, const DeclSpec *DS) {
|
||||
if (T.isNull())
|
||||
@@ -1646,10 +1638,9 @@ QualType Sema::BuildQualifiedType(QualType T, SourceLocation Loc,
|
||||
if (!EltTy->isIncompleteOrObjectType())
|
||||
DiagID = diag::err_typecheck_invalid_restrict_invalid_pointee;
|
||||
|
||||
} 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.
|
||||
} else if (!T->isDependentType() && !isa<AutoType>(T)) {
|
||||
// For an inferred type, 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;
|
||||
EltTy = T;
|
||||
}
|
||||
@@ -10394,7 +10385,7 @@ QualType Sema::BuildUnaryTransformType(QualType BaseType, UTTKind UKind,
|
||||
}
|
||||
|
||||
QualType Sema::BuildAtomicType(QualType T, SourceLocation Loc) {
|
||||
if (!isDependentOrGNUAutoType(T)) {
|
||||
if (!T->isDependentType() && !isa<AutoType>(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))
|
||||
|
||||
@@ -19,25 +19,47 @@ void test_qualifiers(int x, const int y, int * restrict z) {
|
||||
auto yup = ci;
|
||||
yup = 12;
|
||||
|
||||
// Because inference happens after lvalue conversion, top-level qualifiers
|
||||
// are stripped. So r_test will not be restrict qualified, while r_test_2
|
||||
// will be because of the explicit use of the qualifier.
|
||||
auto r_test = z;
|
||||
auto restrict r_test_2 = z;
|
||||
|
||||
// Yes, you can unfortunately infer the type when _Atomic is used as a
|
||||
// qualifier. (Remember, string literals in C are not const char[], they are
|
||||
// char[].)
|
||||
_Atomic auto atom_int = 12;
|
||||
_Atomic auto atom_float = 1.2f;
|
||||
_Atomic auto atom_str = "really?";
|
||||
|
||||
_Static_assert(_Generic(a, int : 1));
|
||||
_Static_assert(_Generic(c, unsigned long : 1));
|
||||
_Static_assert(_Generic(pa, int * : 1));
|
||||
_Static_assert(_Generic(pb, const int * : 1));
|
||||
_Static_assert(_Generic(r_test, int * : 1));
|
||||
_Static_assert(_Generic(&r_test, int ** : 1));
|
||||
_Static_assert(_Generic(&r_test_2, int * restrict * : 1));
|
||||
_Static_assert(_Generic(&atom_int, _Atomic(int) * : 1));
|
||||
_Static_assert(_Generic(&atom_float, _Atomic(float) * : 1));
|
||||
_Static_assert(_Generic(&atom_str, _Atomic(char *) * : 1));
|
||||
}
|
||||
|
||||
void test_atomic(void) {
|
||||
_Atomic auto i = 12; // expected-error {{_Atomic cannot be applied to type 'auto' in C23}}
|
||||
// As silly as this seems, it's required to accept `_Atomic auto` because
|
||||
// _Atomic is a qualifier in that case. But it's required to reject
|
||||
// `_Atomic(auto)` because _Atomic is a type specifier in that case and you
|
||||
// cannot combine auto with other type specifiers (e.g., no `_Complex auto`
|
||||
// either).
|
||||
_Atomic auto i = 12;
|
||||
_Atomic(auto) j = 12; // expected-error {{'auto' not allowed here}} \
|
||||
expected-error {{a type specifier is required for all declarations}}
|
||||
|
||||
_Atomic(int) foo(void);
|
||||
auto k = foo();
|
||||
|
||||
_Static_assert(_Generic(&i, _Atomic auto *: 1)); // expected-error {{_Atomic cannot be applied to type 'auto' in C23}} \
|
||||
expected-error {{'auto' not allowed here}}
|
||||
// Despite being valid as a construct, it's only valid if you can actually
|
||||
// deduce the type, which requires an initializer. So it cannot be used in a
|
||||
// generic association.
|
||||
_Static_assert(_Generic(&i, _Atomic auto *: 1)); // expected-error {{'auto' not allowed here}}
|
||||
_Static_assert(_Generic(k, int: 1));
|
||||
}
|
||||
|
||||
|
||||
@@ -123,8 +123,7 @@ void atomic(void) {
|
||||
c17-error {{type name does not allow storage class to be specified}} \
|
||||
c17-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}}
|
||||
|
||||
_Atomic auto atom2 = 12; // c23-error {{_Atomic cannot be applied to type 'auto' in C23}} \
|
||||
c17-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}}
|
||||
_Atomic auto atom2 = 12; // c17-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}}
|
||||
}
|
||||
|
||||
void attributes(void) {
|
||||
|
||||
Reference in new issue
Block a user