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())
DiagID = diag::err_typecheck_invalid_restrict_invalid_pointee;
ProblemTy = EltTy;
}
- } else if (!T->isDependentType()) {
+ } 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;
}
}
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))
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, regardless of order we
+ // pass the types.
+ _Static_assert(__builtin_types_compatible_p(__typeof(cat), const int), "");
+ _Static_assert(__builtin_types_compatible_p(const int, __typeof(cat)), "");
+ _Static_assert(__builtin_types_compatible_p(__typeof(pcat), int *const), "");
+ _Static_assert(__builtin_types_compatible_p(int *const, __typeof(pcat)), "");
+ _Static_assert(__builtin_types_compatible_p(__typeof(vat), volatile int), "");
+ _Static_assert(__builtin_types_compatible_p(volatile int, __typeof(vat)), "");
+ _Static_assert(__builtin_types_compatible_p(__typeof(pvat), int *volatile), "");
+ _Static_assert(__builtin_types_compatible_p(int *volatile, __typeof(pvat)), "");
+ _Static_assert(__builtin_types_compatible_p(__typeof(rat), int *restrict), "");
+ _Static_assert(__builtin_types_compatible_p(int *restrict, __typeof(rat)), "");
+ _Static_assert(__builtin_types_compatible_p(__typeof(aat1), _Atomic int), "");
+ _Static_assert(__builtin_types_compatible_p(_Atomic int, __typeof(aat1)), "");
+ _Static_assert(__builtin_types_compatible_p(__typeof(paat), _Atomic(int *)), "");
+ _Static_assert(__builtin_types_compatible_p(_Atomic(int *), __typeof(paat)), "");
+
+ // 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);
+
+ // Ensure that trying to merge two different __auto_type types does not
+ // decide that they are both the same type when they're actually different,
+ // and that we reject when the types are the same.
+ __auto_type i = 12;
+ __auto_type f = 1.2f;
+ (void)_Generic(a, __typeof__(i) : 0, __typeof__(f) : 1);
+ (void)_Generic(a,
+ __typeof__(i) : 0, // expected-note {{compatible type 'typeof (i)' (aka 'int') specified here}}
+ __typeof__(a) : 1); // expected-error {{type 'typeof (a)' (aka 'int') in generic association compatible with previously specified type 'typeof (i)' (aka 'int')}}
+}