Implement the initial part of C++0x [expr.const]p2, which specifies

that the unevaluated subexpressions of &&, ||, and ? : are not
considered when determining whether the expression is a constant
expression. Also, turn the "used in its own initializer" warning into
a runtime-behavior warning, so that it doesn't fire when a variable is
used as part of an unevaluated subexpression of its own initializer.

Fixes PR9999.

llvm-svn: 131968
This commit is contained in:
Douglas Gregor 2011-05-24 16:02:01 +00:00
parent 7c2c664500
commit fcafc6e3de
3 changed files with 59 additions and 5 deletions

View File

@ -2957,6 +2957,21 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
case BO_LAnd:
case BO_LOr: {
ICEDiag LHSResult = CheckICE(Exp->getLHS(), Ctx);
// C++0x [expr.const]p2:
// [...] subexpressions of logical AND (5.14), logical OR
// (5.15), and condi- tional (5.16) operations that are not
// evaluated are not considered.
if (Ctx.getLangOptions().CPlusPlus0x && LHSResult.Val == 0) {
if (Exp->getOpcode() == BO_LAnd &&
Exp->getLHS()->EvaluateAsInt(Ctx) == 0)
return LHSResult;
if (Exp->getOpcode() == BO_LOr &&
Exp->getLHS()->EvaluateAsInt(Ctx) != 0)
return LHSResult;
}
ICEDiag RHSResult = CheckICE(Exp->getRHS(), Ctx);
if (LHSResult.Val == 0 && RHSResult.Val == 1) {
// Rare case where the RHS has a comma "side-effect"; we need
@ -3015,10 +3030,22 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
return NoDiag();
}
ICEDiag CondResult = CheckICE(Exp->getCond(), Ctx);
ICEDiag TrueResult = CheckICE(Exp->getTrueExpr(), Ctx);
ICEDiag FalseResult = CheckICE(Exp->getFalseExpr(), Ctx);
if (CondResult.Val == 2)
return CondResult;
// C++0x [expr.const]p2:
// subexpressions of [...] conditional (5.16) operations that
// are not evaluated are not considered
bool TrueBranch = Ctx.getLangOptions().CPlusPlus0x
? Exp->getCond()->EvaluateAsInt(Ctx) != 0
: false;
ICEDiag TrueResult = NoDiag();
if (!Ctx.getLangOptions().CPlusPlus0x || TrueBranch)
TrueResult = CheckICE(Exp->getTrueExpr(), Ctx);
ICEDiag FalseResult = NoDiag();
if (!Ctx.getLangOptions().CPlusPlus0x || !TrueBranch)
FalseResult = CheckICE(Exp->getFalseExpr(), Ctx);
if (TrueResult.Val == 2)
return TrueResult;
if (FalseResult.Val == 2)

View File

@ -5149,9 +5149,11 @@ namespace {
if (OrigDecl != ReferenceDecl) return;
LookupResult Result(S, DRE->getNameInfo(), Sema::LookupOrdinaryName,
Sema::NotForRedeclaration);
S.Diag(SubExpr->getLocStart(), diag::warn_uninit_self_reference_in_init)
<< Result.getLookupName() << OrigDecl->getLocation()
<< SubExpr->getSourceRange();
S.DiagRuntimeBehavior(SubExpr->getLocStart(), SubExpr,
S.PDiag(diag::warn_uninit_self_reference_in_init)
<< Result.getLookupName()
<< OrigDecl->getLocation()
<< SubExpr->getSourceRange());
}
};
}

View File

@ -0,0 +1,25 @@
// RUN: %clang_cc1 -fsyntax-only -std=c++0x -verify %s
// PR9999
template<bool v>
class bitWidthHolding {
public:
static const
unsigned int width = (v == 0 ? 0 : bitWidthHolding<(v >> 1)>::width + 1);
};
static const int width=bitWidthHolding<255>::width;
template<bool b>
struct always_false {
static const bool value = false;
};
template<bool b>
struct and_or {
static const bool and_value = b && and_or<always_false<b>::value>::and_value;
static const bool or_value = !b || and_or<always_false<b>::value>::or_value;
};
static const bool and_value = and_or<true>::and_value;
static const bool or_value = and_or<true>::or_value;