aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEli Friedman <eli.friedman@gmail.com>2011-12-21 00:43:02 +0000
committerEli Friedman <eli.friedman@gmail.com>2011-12-21 00:43:02 +0000
commit6bd9719fd97abac1b8126eae866e96db88be4ac8 (patch)
tree54cdb69b17857cb8905c0c71090181f39e143f49
parent3e9ea0b8cd7c4691d62e385245556be5fded58a7 (diff)
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. <rdar://problem/10020074>
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@147026 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/AST/Expr.cpp31
-rw-r--r--test/Sema/static-init.c3
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<CastExpr>(E)) {
+ if (InnerCE->getCastKind() != CK_IntegralCast)
+ break;
+ E = InnerCE->getSubExpr()->IgnoreParenNoopCasts(Ctx);
+ }
+
+ if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
+ if (BO->getOpcode() == BO_Sub &&
+ isa<AddrLabelExpr>(BO->getLHS()->IgnoreParenNoopCasts(Ctx)) &&
+ isa<AddrLabelExpr>(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