From 6bd9719fd97abac1b8126eae866e96db88be4ac8 Mon Sep 17 00:00:00 2001 From: Eli Friedman Date: Wed, 21 Dec 2011 00:43:02 +0000 Subject: [PATCH] Fix a case where Expr::isConstantInitializer would return true for an expression we can't support. In a slightly amusing twist, the case in question was already in the clang regression tests marked as a valid construct. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@147026 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/AST/Expr.cpp | 31 ++++++++++++++++++++++--------- test/Sema/static-init.c | 3 ++- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 40da32284d..9f87161290 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -2550,17 +2550,30 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const { if (getType()->isVectorType() && CE->getCastKind() == CK_BitCast) return CE->getSubExpr()->isConstantInitializer(Ctx, false); - // Handle casts with a destination that's a struct or union; this - // deals with both the gcc no-op struct cast extension and the - // cast-to-union extension. - if (getType()->isRecordType()) + // Handle misc casts we want to ignore. + // FIXME: Is it really safe to ignore all these? + if (CE->getCastKind() == CK_NoOp || + CE->getCastKind() == CK_LValueToRValue || + CE->getCastKind() == CK_ToUnion || + CE->getCastKind() == CK_ConstructorConversion) return CE->getSubExpr()->isConstantInitializer(Ctx, false); - // Integer->integer casts can be handled here, which is important for - // things like (int)(&&x-&&y). Scary but true. - if (getType()->isIntegerType() && - CE->getSubExpr()->getType()->isIntegerType()) - return CE->getSubExpr()->isConstantInitializer(Ctx, false); + // Handle things like (int)(&&x-&&y). It's a bit nasty, but we support it. + if (CE->getCastKind() == CK_IntegralCast) { + const Expr *E = CE->getSubExpr()->IgnoreParenNoopCasts(Ctx); + while (const CastExpr *InnerCE = dyn_cast(E)) { + if (InnerCE->getCastKind() != CK_IntegralCast) + break; + E = InnerCE->getSubExpr()->IgnoreParenNoopCasts(Ctx); + } + + if (const BinaryOperator *BO = dyn_cast(E)) { + if (BO->getOpcode() == BO_Sub && + isa(BO->getLHS()->IgnoreParenNoopCasts(Ctx)) && + isa(BO->getRHS()->IgnoreParenNoopCasts(Ctx))) + return true; + } + } break; } diff --git a/test/Sema/static-init.c b/test/Sema/static-init.c index b4de92713b..ec6d1e8fc0 100644 --- a/test/Sema/static-init.c +++ b/test/Sema/static-init.c @@ -19,5 +19,6 @@ struct foo { }; union bar u[1]; -struct foo x = {(intptr_t) u}; // no-error +struct foo x = {(intptr_t) u}; // expected-error {{initializer element is not a compile-time constant}} struct foo y = {(char) u}; // expected-error {{initializer element is not a compile-time constant}} +intptr_t z = (intptr_t) u; // no-error -- 2.40.0