aaron.ballman created this revision.
aaron.ballman added reviewers: rsmith, comex, erichkeane, jyknight, rjmccall.
Herald added a project: All.
aaron.ballman requested review of this revision.
Herald added a project: clang.

Currently, Clang handles some qualifiers correctly for `__auto_type`, but it 
does not handle the `restrict` or `_Atomic` qualifiers in the same way that GCC 
does. This patch handles those qualifiers so that they attach to the deduced 
type the same as `const` and `volatile` already do.

This fixes https://github.com/llvm/llvm-project/issues/53652


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D122029

Files:
  clang/docs/ReleaseNotes.rst
  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,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);
+}
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->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<AutoType>(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/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->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<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->getKeyword() == AutoTypeKeyword::GNUAutoType)
+        return RHS;
+    }
+    if (const auto *AT = LHS->getAs<AutoType>()) {
+      if (AT->getKeyword() == AutoTypeKeyword::GNUAutoType)
+        return RHS;
+    }
     return {};
   }
 
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

Reply via email to