[clang] 178c2b4 - Correctly diagnose taking the address of a register variable in C

Aaron Ballman via cfe-commits cfe-commits at lists.llvm.org
Thu Jul 22 11:53:32 PDT 2021


Author: Aaron Ballman
Date: 2021-07-22T14:53:23-04:00
New Revision: 178c2b4c1eb12b2153adb384ac7f22a8791edc86

URL: https://github.com/llvm/llvm-project/commit/178c2b4c1eb12b2153adb384ac7f22a8791edc86
DIFF: https://github.com/llvm/llvm-project/commit/178c2b4c1eb12b2153adb384ac7f22a8791edc86.diff

LOG: Correctly diagnose taking the address of a register variable in C

We caught the cases where the user would explicitly use the & operator,
but we were missing implicit conversions such as array decay.

Fixes PR26336. Thanks to Samuel Neves for inspiration for the patch.

Added: 
    

Modified: 
    clang/lib/Sema/Sema.cpp
    clang/lib/Sema/SemaExpr.cpp
    clang/test/Sema/expr-address-of.c

Removed: 
    


################################################################################
diff  --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index fbbb347f57da..054a65265079 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -629,16 +629,36 @@ ExprResult Sema::ImpCastExprToType(Expr *E, QualType Ty,
   if (ExprTy == TypeTy)
     return E;
 
-  // C++1z [conv.array]: The temporary materialization conversion is applied.
-  // We also use this to fuel C++ DR1213, which applies to C++11 onwards.
-  if (Kind == CK_ArrayToPointerDecay && getLangOpts().CPlusPlus &&
-      E->getValueKind() == VK_PRValue) {
-    // The temporary is an lvalue in C++98 and an xvalue otherwise.
-    ExprResult Materialized = CreateMaterializeTemporaryExpr(
-        E->getType(), E, !getLangOpts().CPlusPlus11);
-    if (Materialized.isInvalid())
-      return ExprError();
-    E = Materialized.get();
+  if (Kind == CK_ArrayToPointerDecay) {
+    // C++1z [conv.array]: The temporary materialization conversion is applied.
+    // We also use this to fuel C++ DR1213, which applies to C++11 onwards.
+    if (getLangOpts().CPlusPlus && E->getValueKind() == VK_PRValue) {
+      // The temporary is an lvalue in C++98 and an xvalue otherwise.
+      ExprResult Materialized = CreateMaterializeTemporaryExpr(
+          E->getType(), E, !getLangOpts().CPlusPlus11);
+      if (Materialized.isInvalid())
+        return ExprError();
+      E = Materialized.get();
+    }
+    // C17 6.7.1p6 footnote 124: The implementation can treat any register
+    // declaration simply as an auto declaration. However, whether or not
+    // addressable storage is actually used, the address of any part of an
+    // object declared with storage-class specifier register cannot be
+    // computed, either explicitly(by use of the unary & operator as discussed
+    // in 6.5.3.2) or implicitly(by converting an array name to a pointer as
+    // discussed in 6.3.2.1).Thus, the only operator that can be applied to an
+    // array declared with storage-class specifier register is sizeof.
+    if (VK == VK_PRValue && !getLangOpts().CPlusPlus && !E->isPRValue()) {
+      if (const auto *DRE = dyn_cast<DeclRefExpr>(E)) {
+        if (const auto *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
+          if (VD->getStorageClass() == SC_Register) {
+            Diag(E->getExprLoc(), diag::err_typecheck_address_of)
+                << /*register variable*/ 3 << E->getSourceRange();
+            return ExprError();
+          }
+        }
+      }
+    }
   }
 
   if (ImplicitCastExpr *ImpCast = dyn_cast<ImplicitCastExpr>(E)) {

diff  --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 3926c49077ce..d19eb8475e9f 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -525,9 +525,13 @@ ExprResult Sema::DefaultFunctionArrayConversion(Expr *E, bool Diagnose) {
     // An lvalue or rvalue of type "array of N T" or "array of unknown bound of
     // T" can be converted to an rvalue of type "pointer to T".
     //
-    if (getLangOpts().C99 || getLangOpts().CPlusPlus || E->isLValue())
-      E = ImpCastExprToType(E, Context.getArrayDecayedType(Ty),
-                            CK_ArrayToPointerDecay).get();
+    if (getLangOpts().C99 || getLangOpts().CPlusPlus || E->isLValue()) {
+      ExprResult Res = ImpCastExprToType(E, Context.getArrayDecayedType(Ty),
+                                         CK_ArrayToPointerDecay);
+      if (Res.isInvalid())
+        return ExprError();
+      E = Res.get();
+    }
   }
   return E;
 }

diff  --git a/clang/test/Sema/expr-address-of.c b/clang/test/Sema/expr-address-of.c
index 480871afad2a..aed488284ab1 100644
--- a/clang/test/Sema/expr-address-of.c
+++ b/clang/test/Sema/expr-address-of.c
@@ -45,24 +45,27 @@ void f0() {
   int *_dummy1 = &(*(x1 + 1));
 }
 
-// FIXME: The checks for this function are broken; we should error
-// on promoting a register array to a pointer! (C99 6.3.2.1p3)
 void f1() {
   register int x0[10];
-  int *_dummy00 = x0; // fixme-error {{address of register variable requested}}
-  int *_dummy01 = &(*x0); // fixme-error {{address of register variable requested}}
+  int *_dummy00 = x0;     // expected-error {{address of register variable requested}}
+  int *_dummy01 = &(*x0); // expected-error {{address of register variable requested}}
 
   register int x1[10];
-  int *_dummy1 = &(*(x1 + 1)); // fixme-error {{address of register variable requested}}
+  int *_dummy1 = &(*(x1 + 1)); // expected-error {{address of register variable requested}}
 
   register int *x2;
   int *_dummy2 = &(*(x2 + 1));
 
   register int x3[10][10][10];
-  int (*_dummy3)[10] = &x3[0][0]; // expected-error {{address of register variable requested}}
+  int(*_dummy3)[10] = &x3[0][0]; // expected-error {{address of register variable requested}}
 
   register struct { int f0[10]; } x4;
   int *_dummy4 = &x4.f0[2]; // expected-error {{address of register variable requested}}
+
+  add_one(x0);      // expected-error {{address of register variable requested}}
+  (void)sizeof(x0); // OK, not an array decay.
+
+  int *p = ((int *)x0)++; // expected-error {{address of register variable requested}}
 }
 
 void f2() {
@@ -86,12 +89,8 @@ void f4() {
 void f5() {
   register int arr[2];
 
-  /* This is just here because if we happened to support this as an
-     lvalue we would need to give a warning. Note that gcc warns about
-     this as a register before it warns about it as an invalid
-     lvalue. */
-  int *_dummy0 = &(int*) arr; // expected-error {{cannot take the address of an rvalue}}
-  int *_dummy1 = &(arr + 1); // expected-error {{cannot take the address of an rvalue}}
+  int *_dummy0 = &(int*) arr; // expected-error {{address of register variable requested}}
+  int *_dummy1 = &(arr + 1); // expected-error {{address of register variable requested}}
 }
 
 void f6(register int x) {


        


More information about the cfe-commits mailing list