]> granicus.if.org Git - clang/commitdiff
Fix several issues in checking of address-of expressions.
authorDaniel Dunbar <daniel@zuster.org>
Mon, 4 Aug 2008 20:02:37 +0000 (20:02 +0000)
committerDaniel Dunbar <daniel@zuster.org>
Mon, 4 Aug 2008 20:02:37 +0000 (20:02 +0000)
 - clang was erroneously accepting address-of applied to lvalue
   expressions involving pointer arithmetic.
 - clang was erroneously rejecting address-of applied to deref
   expressions of pointer-typed variables.
 - Improved existing test case.
 - Fixes: <rdar://problem/6113867>, <rdar://problem/6080158>

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@54326 91177308-0d34-0410-b5e6-96231b3b80d8

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

index 1f544927b790a9cf860976377f5a06b8758ed97a..8896f43539091ef2c9d1f2318a4761d4c6825b72 100644 (file)
@@ -1968,8 +1968,16 @@ QualType Sema::CheckIncrementDecrementOperand(Expr *op, SourceLocation OpLoc) {
 
 /// getPrimaryDecl - Helper function for CheckAddressOfOperand().
 /// This routine allows us to typecheck complex/recursive expressions
-/// where the declaration is needed for type checking. Here are some
-/// examples: &s.xx, &s.zz[1].yy, &(1+2), &(XX), &"123"[2].
+/// where the declaration is needed for type checking. We only need to
+/// handle cases when the expression references a function designator
+/// or is an lvalue. Here are some examples:
+///  - &(x) => x
+///  - &*****f => f for f a function designator.
+///  - &s.xx => s
+///  - &s.zz[1].yy -> s, if zz is an array
+///  - *(x + 1) -> x, if x is an array
+///  - &"123"[2] -> 0
+///  - & __real__ x -> x
 static ValueDecl *getPrimaryDecl(Expr *E) {
   switch (E->getStmtClass()) {
   case Stmt::DeclRefExprClass:
@@ -1981,7 +1989,7 @@ static ValueDecl *getPrimaryDecl(Expr *E) {
       return 0;
     return getPrimaryDecl(cast<MemberExpr>(E)->getBase());
   case Stmt::ArraySubscriptExprClass: {
-    // &X[4] and &4[X] is invalid if X is invalid and X is not a pointer.
+    // &X[4] and &4[X] refers to X if X is not a pointer.
   
     ValueDecl *VD = getPrimaryDecl(cast<ArraySubscriptExpr>(E)->getBase());
     if (!VD || VD->getType()->isPointerType())
@@ -1989,8 +1997,42 @@ static ValueDecl *getPrimaryDecl(Expr *E) {
     else
       return VD;
   }
-  case Stmt::UnaryOperatorClass:
-    return getPrimaryDecl(cast<UnaryOperator>(E)->getSubExpr());
+  case Stmt::UnaryOperatorClass: {
+    UnaryOperator *UO = cast<UnaryOperator>(E);
+    
+    switch(UO->getOpcode()) {
+    case UnaryOperator::Deref: {
+      // *(X + 1) refers to X if X is not a pointer.
+      ValueDecl *VD = getPrimaryDecl(UO->getSubExpr());
+      if (!VD || VD->getType()->isPointerType())
+        return 0;
+      return VD;
+    }
+    case UnaryOperator::Real:
+    case UnaryOperator::Imag:
+    case UnaryOperator::Extension:
+      return getPrimaryDecl(UO->getSubExpr());
+    default:
+      return 0;
+    }
+  }
+  case Stmt::BinaryOperatorClass: {
+    BinaryOperator *BO = cast<BinaryOperator>(E);
+
+    // Handle cases involving pointer arithmetic. The result of an
+    // Assign or AddAssign is not an lvalue so they can be ignored.
+
+    // (x + n) or (n + x) => x
+    if (BO->getOpcode() == BinaryOperator::Add) {
+      if (BO->getLHS()->getType()->isPointerType()) {
+        return getPrimaryDecl(BO->getLHS());
+      } else if (BO->getRHS()->getType()->isPointerType()) {
+        return getPrimaryDecl(BO->getRHS());
+      }
+    }
+
+    return 0;
+  }
   case Stmt::ParenExprClass:
     return getPrimaryDecl(cast<ParenExpr>(E)->getSubExpr());
   case Stmt::ImplicitCastExprClass:
index 46ba5dae4dd2587b4f02a1838cdf0b949fafab9b..20390429dd246d3bbb1f5a06d6d60e8998875edd 100644 (file)
@@ -31,3 +31,58 @@ void testVectorComponentAccess() {
   float* r = &q[0]; // expected-error {{address of vector requested}}
 }
 
+
+void f0() {
+  register int *x0;
+  int *_dummy0 = &(*x0);
+
+  register int *x1;
+  int *_dummy1 = &(*(x1 + 1));
+}
+
+void f1() {
+  register int x0[10];
+  int *_dummy0 = &(*x0); // expected-error {{address of register variable requested}}
+
+  register int x1[10];
+  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 = &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}}
+}
+
+void f2() {
+  register int *y;
+  
+  int *_dummy0 = &y; // expected-error {{address of register variable requested}}
+  int *_dummy1 = &y[10];
+}
+
+void f3() {
+  extern void f4();
+  void (*_dummy0)() = &****f4;
+}
+
+void f4() {
+  register _Complex int x;
+  
+  int *_dummy0 = &__real__ x; // expected-error {{address of register variable requested}}
+}
+
+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 {{address expression must be an lvalue or a function designator}}
+  int *_dummy1 = &(arr + 1); // expected-error {{address expression must be an lvalue or a function designator}}
+}
+