aaron.ballman updated this revision to Diff 416928.
aaron.ballman marked 2 inline comments as done.
aaron.ballman added a comment.
Updated based on review feedback.
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D122029/new/
https://reviews.llvm.org/D122029
Files:
clang/docs/ReleaseNotes.rst
clang/include/clang/AST/Type.h
clang/lib/AST/ASTContext.cpp
clang/lib/Sema/SemaExpr.cpp
clang/lib/Sema/SemaType.cpp
clang/test/Sema/auto-type.c
Index: clang/test/Sema/auto-type.c
===================================================================
--- clang/test/Sema/auto-type.c
+++ clang/test/Sema/auto-type.c
@@ -24,3 +24,57 @@
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')}}
+}
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<AutoType>(T);
+ return AT && AT->isGNUAutoType();
+}
+
QualType Sema::BuildQualifiedType(QualType T, SourceLocation Loc,
Qualifiers Qs, const DeclSpec *DS) {
if (T.isNull())
@@ -1913,7 +1921,10 @@
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;
}
@@ -9101,7 +9112,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/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<AutoType>(LHSType)) {
+ if (AT->isGNUAutoType()) {
+ 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<AtomicType>(LHSType)) {
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<AutoType>()) {
+ if (AT->isGNUAutoType())
+ return RHS;
+ }
+ if (const auto *AT = RHS->getAs<AutoType>()) {
+ if (AT->isGNUAutoType())
+ return LHS;
+ }
return {};
}
Index: clang/include/clang/AST/Type.h
===================================================================
--- clang/include/clang/AST/Type.h
+++ clang/include/clang/AST/Type.h
@@ -5085,6 +5085,10 @@
return getKeyword() == AutoTypeKeyword::DecltypeAuto;
}
+ bool isGNUAutoType() const {
+ return getKeyword() == AutoTypeKeyword::GNUAutoType;
+ }
+
AutoTypeKeyword getKeyword() const {
return (AutoTypeKeyword)AutoTypeBits.Keyword;
}
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 <https://github.com/llvm/llvm-project/issues/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 <https://github.com/llvm/llvm-project/issues/53652>`_.
+
+
Improvements to Clang's diagnostics
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- ``-Wliteral-range`` will warn on floating-point equality comparisons with
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits