Fix several issues in checking of address-of expressions.
- 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
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 1f54492..8896f43 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -1968,8 +1968,16 @@
/// 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 @@
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 @@
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:
diff --git a/test/Sema/expr-address-of.c b/test/Sema/expr-address-of.c
index 46ba5da..2039042 100644
--- a/test/Sema/expr-address-of.c
+++ b/test/Sema/expr-address-of.c
@@ -31,3 +31,58 @@
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}}
+}
+