to268 created this revision.
to268 added reviewers: aaron.ballman, clang-language-wg, jyknight.
Herald added a project: All.
to268 requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

This patches implements the `auto` keyword from the N3007 
<https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3007.htm> standard 
specification.
This allows deducing the type of the variable like in C++

  auto nb = 1;
  auto chr = 'A';
  auto str = "String";


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D133289

Files:
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Sema/DeclSpec.cpp
  clang/test/C/C2X/n3007.c
  clang/test/CodeGen/auto.c
  clang/test/Parser/c2x-auto.c
  clang/test/Sema/c2x-auto.c
  clang/www/c_status.html

Index: clang/www/c_status.html
===================================================================
--- clang/www/c_status.html
+++ clang/www/c_status.html
@@ -1193,7 +1193,7 @@
     <tr>
       <td>Type inference for object declarations</td>
       <td><a href="https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3007.htm";>N3007</a></td>
-      <td class="none" align="center">No</td>
+      <td class="full" align="center">Yes</td>
     </tr>
     <tr>
       <td>constexpr for object definitions</td>
Index: clang/test/Sema/c2x-auto.c
===================================================================
--- /dev/null
+++ clang/test/Sema/c2x-auto.c
@@ -0,0 +1,43 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c2x %s
+
+#include <stdalign.h>
+
+void test_basic_types(void) {
+  auto undefined;                 // expected-error {{declaration of variable 'undefined' with deduced type 'auto' requires an initializer}}
+  auto auto_int = 4;
+  auto auto_long = 4UL;
+}
+
+void test_structs(void) {
+  struct s_auto { auto a; };      // expected-error {{'auto' not allowed in struct member}}
+  auto s_int = (struct { int a; } *)0;
+  typedef auto auto_type;         // expected-error {{'auto' not allowed in typedef}}
+}
+
+void test_sizeof_alignas(void) {
+  auto auto_size = sizeof(auto);  // expected-error {{expected expression}}
+  alignas(4) auto b[4];           // expected-error {{'b' declared as array of 'auto'}}
+}
+
+void test_casts(void) {
+  auto int_cast = (int)(4 + 3);
+  auto double_cast = (double)(1 / 3);
+  auto long_cast = (long)(4UL + 3UL);
+  auto auto_cast = (auto)(4 + 3); // expected-error {{expected expression}}
+}
+
+void test_compound_literral(void) {
+  auto int_cl = (int){13};
+  auto double_cl = (double){2.5};
+  auto auto_cl = (auto){13};  // expected-error {{expected expression}}
+  auto array[] = { 1, 2, 3 }; // expected-error {{'array' declared as array of 'auto'}}
+}
+
+void test_qualifiers(int x, const int y) {
+  const auto a = x;
+  auto b = y;
+  static auto c = 1UL;
+  int* pa = &a; // expected-warning {{initializing 'int *' with an expression of type 'const int *' discards qualifiers}}
+  const int* pb = &b;
+  int* pc = &c; // expected-warning {{incompatible pointer types initializing 'int *' with an expression of type 'unsigned long *'}}
+}
Index: clang/test/Parser/c2x-auto.c
===================================================================
--- /dev/null
+++ clang/test/Parser/c2x-auto.c
@@ -0,0 +1,54 @@
+// RUN: %clang_cc1 -fsyntax-only -verify=expected,c2x -std=c2x %s
+// RUN: %clang_cc1 -fsyntax-only -verify=expected,c17 -std=c17 %s
+
+#define AUTO_MACRO(_NAME, ARG, ARG2, ARG3) \
+  auto _NAME = ARG + (ARG2 / ARG3);
+
+struct S {
+    int a;
+    int b;
+    union {
+      char c;
+      auto smth; // c2x-error {{'auto' not allowed in union member}} \
+                    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}}
+    } u;
+};
+
+enum E : auto { // c2x-error {{'auto' not allowed here}} \
+                   c17-error {{expected a type}} \
+                   c17-error {{type name does not allow storage class to be specified}}
+  One,
+  Two,
+  Tree,
+};
+
+auto auto_usage(auto auto) {  // c2x-error {{'auto' not allowed in function prototype}} \
+                                 c2x-error {{'auto' not allowed in function return type}} \
+                                 c2x-error {{cannot combine with previous 'auto' declaration specifier}} \
+                                 c17-error {{invalid storage class specifier in function declarator}} \
+                                 c17-error {{illegal storage class on function}} \
+                                 c17-warning {{duplicate 'auto' declaration specifier}} \
+                                 c17-warning {{omitting the parameter name in a function definition is a C2x extension}} \
+                                 c17-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}} \
+                                 c17-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}}
+
+  auto = 4;                   // expected-error {{expected identifier or '('}}
+
+  auto a = 4;                 // c17-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}}
+
+  auto b[4];                  // c2x-error {{'b' declared as array of 'auto'}} \
+                                 c17-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}}
+
+  auto array[auto];           // expected-error {{expected expression}} \
+                                 c2x-error {{declaration of variable 'array' with deduced type 'auto' requires an initializer}} \
+                                 c17-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}}
+
+  AUTO_MACRO(auto, 1, 2, 3);  // c2x-error {{cannot combine with previous 'auto' declaration specifier}} \
+                                 expected-error {{expected identifier or '('}} \
+                                 c17-warning {{duplicate 'auto' declaration specifier}}
+
+  auto c = (auto)a;           // expected-error {{expected expression}} \
+                                 c17-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}}
+  return c;
+}
Index: clang/test/CodeGen/auto.c
===================================================================
--- /dev/null
+++ clang/test/CodeGen/auto.c
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -std=c2x -emit-llvm %s -o - | FileCheck %s
+
+void basic_types(void) {
+    auto nb = 4;        // CHECK: %nb = alloca i32, align 4
+    auto dbl = 4.3;     // CHECK: %dbl = alloca double, align 8
+    auto lng = 4UL;     // CHECK: %lng = alloca i64, align 8
+    auto bl = true;     // CHECK: %bl = alloca i8, align 1
+    auto chr = 'A';     // CHECK: %chr = alloca i32, align 4
+    auto str = "Test";  // CHECK: %str = alloca ptr, align 8
+}
+
+void misc_declarations(void) {
+  auto strct_ptr = (struct { int a; } *)0;  // CHECK: %strct_ptr = alloca ptr, align 8
+  auto int_cl = (int){13};                  // CHECK: %int_cl = alloca i32, align 4
+  auto double_cl = (double){2.5};           // CHECK: %double_cl = alloca double, align 8
+}
+
+void loop(void) {
+  auto j = 4;                       // CHECK: %j = alloca i32, align 4
+  for (auto i = j; i < 2 * j; i++); // CHECK: %i = alloca i32, align 4
+}
+
+#define AUTO_MACRO(_NAME, ARG, ARG2, ARG3) \
+  auto _NAME = ARG + (ARG2 / ARG3);
+
+#define AUTO_INT_MACRO(_NAME, ARG, ARG2, ARG3) \
+  auto _NAME = (ARG ^ ARG2) & ARG3;
+
+int macros(int in_int) {
+  auto a = in_int + 1;              // CHECK: %a = alloca i32, align 4
+  AUTO_MACRO(b, 1.3, 2.5f, 3);      // CHECK: %b = alloca double, align 8
+  AUTO_INT_MACRO(c, 64, 23, 0xff);  // CHECK: %c = alloca i32, align 4
+  return (a + (int)b) - c;          // CHECK: ret i32 %sub
+}
Index: clang/test/C/C2X/n3007.c
===================================================================
--- /dev/null
+++ clang/test/C/C2X/n3007.c
@@ -0,0 +1,72 @@
+// RUN: %clang_cc1 -std=c2x -verify %s
+
+/* WG14 N3007: Yes
+ * Type Inference for object definitions
+ */
+#include <stdalign.h>
+
+void test_qualifiers(int x, const int y) {
+  const auto a = x;
+  auto b = y;
+  static auto c = 1UL;
+  int* pa = &a; // expected-warning {{initializing 'int *' with an expression of type 'const int *' discards qualifiers}}
+  const int* pb = &b;
+  int* pc = &c; // expected-warning {{incompatible pointer types initializing 'int *' with an expression of type 'unsigned long *'}}
+}
+
+void test_double(void) {
+  double A[3] = { 0 };
+  auto pA = A;
+  auto qA = &A;
+  auto pi = 3.14;
+}
+
+int test_auto_param(auto a) { // expected-error {{'auto' not allowed in function prototype}}
+  return (int)(a * 2);
+}
+
+auto test_auto_return(float a, int b) { // expected-error {{'auto' not allowed in function return type}}
+  return ((a * b) * (a / b));
+}
+
+void test_arrary(void) {
+  auto a[4];          // expected-error {{'a' declared as array of 'auto'}}
+  auto b[] = {1, 2};  // expected-error {{'b' declared as array of 'auto'}}
+}
+
+void test_sizeof_alignas(void) {
+  auto auto_size = sizeof(auto);  // expected-error {{expected expression}}
+  alignas(4) auto b[4];           // expected-error {{'b' declared as array of 'auto'}}
+}
+
+void test_structs(void) {
+  auto a = (struct { int a; } *)0;
+  struct B { auto b; };   // expected-error {{'auto' not allowed in struct member}}
+  typedef auto auto_type; // expected-error {{'auto' not allowed in typedef}}
+}
+
+void test_misc(void) {
+  auto test_char = 'A';
+  auto test_char_ptr = "test";
+  auto something; // expected-error {{declaration of variable 'something' with deduced type 'auto' requires an initializer}}
+}
+
+void test_loop(void) {
+  auto j = 4;
+  for (auto i = j; i < 2 * j; i++);
+}
+
+#define AUTO_MACRO(_NAME, ARG, ARG2, ARG3) \
+  auto _NAME = ARG + (ARG2 / ARG3);
+
+// This macro should only work with integers due to the usage of binary operators
+#define AUTO_INT_MACRO(_NAME, ARG, ARG2, ARG3) \
+  auto _NAME = (ARG ^ ARG2) & ARG3;
+
+int test_macros(int in_int) {
+  auto a = in_int + 1;
+  AUTO_MACRO(b, 1.3, 2.5f, 3);
+  AUTO_INT_MACRO(c, 64, 23, 0xff);
+  AUTO_INT_MACRO(not_valid, 51.5, 25, 0xff); // expected-error {{invalid operands to binary expression ('double' and 'int')}}
+  return (a + (int)b) - c;
+}
Index: clang/lib/Sema/DeclSpec.cpp
===================================================================
--- clang/lib/Sema/DeclSpec.cpp
+++ clang/lib/Sema/DeclSpec.cpp
@@ -1361,8 +1361,8 @@
     StorageClassSpecLoc = SourceLocation();
   }
   // Diagnose if we've recovered from an ill-formed 'auto' storage class
-  // specifier in a pre-C++11 dialect of C++.
-  if (!S.getLangOpts().CPlusPlus11 && TypeSpecType == TST_auto)
+  // specifier in a pre-C++11 dialect of C++ or in a C2X dialect of C.
+  if ((!S.getLangOpts().CPlusPlus11 && !S.getLangOpts().C2x) && TypeSpecType == TST_auto)
     S.Diag(TSTLoc, diag::ext_auto_type_specifier);
   if (S.getLangOpts().CPlusPlus && !S.getLangOpts().CPlusPlus11 &&
       StorageClassSpec == SCS_auto)
Index: clang/lib/Parse/ParseDecl.cpp
===================================================================
--- clang/lib/Parse/ParseDecl.cpp
+++ clang/lib/Parse/ParseDecl.cpp
@@ -3791,7 +3791,7 @@
       isStorageClass = true;
       break;
     case tok::kw_auto:
-      if (getLangOpts().CPlusPlus11) {
+      if (getLangOpts().CPlusPlus11 || getLangOpts().C2x) {
         if (isKnownToBeTypeSpecifier(GetLookAheadToken(1))) {
           isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_auto, Loc,
                                              PrevSpec, DiagID, Policy);
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to