From: Daniel Dunbar Date: Mon, 4 Aug 2008 20:02:37 +0000 (+0000) Subject: Fix several issues in checking of address-of expressions. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=1e76ce6e5f892c89c9958657d44c323fb70f748c;p=clang 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: , 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 1f544927b7..8896f43539 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -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(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(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(E)->getSubExpr()); + case Stmt::UnaryOperatorClass: { + UnaryOperator *UO = cast(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(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(E)->getSubExpr()); case Stmt::ImplicitCastExprClass: diff --git a/test/Sema/expr-address-of.c b/test/Sema/expr-address-of.c index 46ba5dae4d..20390429dd 100644 --- a/test/Sema/expr-address-of.c +++ b/test/Sema/expr-address-of.c @@ -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}} +} +