diff options
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 105 | ||||
-rw-r--r-- | test/CodeGen/struct-init.c | 1 |
2 files changed, 105 insertions, 1 deletions
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index ed34f9fe00..1b1e636a76 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -935,6 +935,97 @@ bool Sema::CheckAddressConstantExpression(const Expr* Init) { } } +static const Expr* FindExpressionBaseAddress(const Expr* E); + +static const Expr* FindExpressionBaseAddressLValue(const Expr* E) { + switch (E->getStmtClass()) { + default: + return E; + case Expr::ParenExprClass: { + const ParenExpr* PE = cast<ParenExpr>(E); + return FindExpressionBaseAddressLValue(PE->getSubExpr()); + } + case Expr::MemberExprClass: { + const MemberExpr *M = cast<MemberExpr>(E); + if (M->isArrow()) + return FindExpressionBaseAddress(M->getBase()); + return FindExpressionBaseAddressLValue(M->getBase()); + } + case Expr::ArraySubscriptExprClass: { + const ArraySubscriptExpr *ASE = cast<ArraySubscriptExpr>(E); + return FindExpressionBaseAddress(ASE->getBase()); + } + case Expr::UnaryOperatorClass: { + const UnaryOperator *Exp = cast<UnaryOperator>(E); + + if (Exp->getOpcode() == UnaryOperator::Deref) + return FindExpressionBaseAddress(Exp->getSubExpr()); + + return E; + } + } +} + +static const Expr* FindExpressionBaseAddress(const Expr* E) { + switch (E->getStmtClass()) { + default: + return E; + case Expr::ParenExprClass: { + const ParenExpr* PE = cast<ParenExpr>(E); + return FindExpressionBaseAddress(PE->getSubExpr()); + } + case Expr::UnaryOperatorClass: { + const UnaryOperator *Exp = cast<UnaryOperator>(E); + + // C99 6.6p9 + if (Exp->getOpcode() == UnaryOperator::AddrOf) + return FindExpressionBaseAddressLValue(Exp->getSubExpr()); + + if (Exp->getOpcode() == UnaryOperator::Extension) + return FindExpressionBaseAddress(Exp->getSubExpr()); + + return E; + } + case Expr::BinaryOperatorClass: { + const BinaryOperator *Exp = cast<BinaryOperator>(E); + + Expr *PExp = Exp->getLHS(); + Expr *IExp = Exp->getRHS(); + if (IExp->getType()->isPointerType()) + std::swap(PExp, IExp); + + return FindExpressionBaseAddress(PExp); + } + case Expr::ImplicitCastExprClass: { + const Expr* SubExpr = cast<ImplicitCastExpr>(E)->getSubExpr(); + + // Check for implicit promotion + if (SubExpr->getType()->isFunctionType() || + SubExpr->getType()->isArrayType()) + return FindExpressionBaseAddressLValue(SubExpr); + + // Check for pointer->pointer cast + if (SubExpr->getType()->isPointerType()) + return FindExpressionBaseAddress(SubExpr); + + // We assume that we have an arithmetic expression here; + // if we don't, we'll figure it out later + return 0; + } + case Expr::CastExprClass: { + const Expr* SubExpr = cast<CastExpr>(E)->getSubExpr(); + + // Check for pointer->pointer cast + if (SubExpr->getType()->isPointerType()) + return FindExpressionBaseAddress(SubExpr); + + // We assume that we have an arithmetic expression here; + // if we don't, we'll figure it out later + return 0; + } + } +} + bool Sema::CheckArithmeticConstantExpression(const Expr* Init) { switch (Init->getStmtClass()) { default: @@ -1027,6 +1118,20 @@ bool Sema::CheckArithmeticConstantExpression(const Expr* Init) { CheckArithmeticConstantExpression(Exp->getRHS()); } + if (Exp->getLHS()->getType()->isPointerType() && + Exp->getRHS()->getType()->isPointerType()) { + const Expr* LHSBase = FindExpressionBaseAddress(Exp->getLHS()); + const Expr* RHSBase = FindExpressionBaseAddress(Exp->getRHS()); + + // Only allow a null (constant integer) base; we could + // allow some additional cases if necessary, but this + // is sufficient to cover offsetof-like constructs. + if (!LHSBase && !RHSBase) { + return CheckAddressConstantExpression(Exp->getLHS()) || + CheckAddressConstantExpression(Exp->getRHS()); + } + } + Diag(Init->getExprLoc(), diag::err_init_element_not_constant, Init->getSourceRange()); return true; diff --git a/test/CodeGen/struct-init.c b/test/CodeGen/struct-init.c index 5b815de399..02cbee06b0 100644 --- a/test/CodeGen/struct-init.c +++ b/test/CodeGen/struct-init.c @@ -9,5 +9,4 @@ char a; const zend_ini_entry ini_entries[] = { { ((char*)&((zend_ini_entry*)0)->mh_arg1 - (char*)(void*)0)}, - { ((long long*)&a - (long long*)(void*)2)}, }; |