Use the canonical type when matching a generic selection association
authorAaron Ballman <aaron@aaronballman.com>
Thu, 26 May 2022 11:40:10 +0000 (07:40 -0400)
committerAaron Ballman <aaron@aaronballman.com>
Thu, 26 May 2022 11:42:13 +0000 (07:42 -0400)
This ensures that a deduced type like __auto_type matches the correct
association instead of matching all associations.

This addresses a regression from e4a42c5b64d044ae28d9483b0ebd12038d5b5917

Fixes #55702

clang/lib/Sema/SemaExpr.cpp
clang/test/Sema/auto-type.c

index 9d9cb99..3e8bd63 100644 (file)
@@ -1753,10 +1753,14 @@ Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc,
 
   SmallVector<unsigned, 1> CompatIndices;
   unsigned DefaultIndex = -1U;
+  // Look at the canonical type of the controlling expression in case it was a
+  // deduced type like __auto_type. However, when issuing diagnostics, use the
+  // type the user wrote in source rather than the canonical one.
   for (unsigned i = 0; i < NumAssocs; ++i) {
     if (!Types[i])
       DefaultIndex = i;
-    else if (Context.typesAreCompatible(ControllingExpr->getType(),
+    else if (Context.typesAreCompatible(
+                 ControllingExpr->getType().getCanonicalType(),
                                         Types[i]->getType()))
       CompatIndices.push_back(i);
   }
index 4e85eec..1170c68 100644 (file)
@@ -78,3 +78,13 @@ void Issue53652(void) {
                  __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')}}
 }
+
+void Issue55702(void) {
+  // A controlling expression which uses __auto_type should not be
+  // automatically compatible with every association; we should be using the
+  // canonical type for that comparison.
+  void *ptr = 0;
+  __auto_type v = ptr;
+  (void)_Generic(v, long double : 0, double : 0, default : 1); // OK
+  _Static_assert(_Generic(v, long double : 0, default : 1) == 1, "fail");
+}