[cfe-commits] r143204 - in /cfe/trunk: include/clang/AST/ASTContext.h include/clang/AST/Expr.h lib/AST/ExprConstant.cpp test/CodeGenCXX/static-data-member.cpp test/SemaCXX/constant-expression-cxx11.cpp

Chad Rosier mcrosier at apple.com
Fri Oct 28 13:21:14 PDT 2011


Hi Richard,
I'm seeing assertion failures on some of our testers, which bisected to this revision.

Assertion failed: (E->isRValue() && E->getType()->isRealFloatingType()), function EvaluateFloat, file /Users/mcrosier/llvm-clean/llvm/tools/clang/lib/AST/ExprConstant.cpp, line 2203.
0  clang             0x0000000109bb1c52 _ZL15PrintStackTracePv + 34
1  clang             0x0000000109bb2179 _ZL13SignalHandleri + 697
2  libsystem_c.dylib 0x00007fff8d815cfa _sigtramp + 26
3  libsystem_c.dylib 0x000000010a5ef278 _sigtramp + 18446603342611060120
4  clang             0x0000000109bb1ea6 abort + 22
5  clang             0x0000000109bb1e65 __assert_rtn + 53
6  clang             0x00000001090f7b6f (anonymous namespace)::FloatExprEvaluator::VisitBinaryOperator(clang::BinaryOperator const*) + 607
7  clang             0x00000001090f71e1 clang::StmtVisitorBase<clang::make_const_ptr, (anonymous namespace)::FloatExprEvaluator, bool>::Visit(clang::Stmt const*) + 2865
8  clang             0x00000001090f71be clang::StmtVisitorBase<clang::make_const_ptr, (anonymous namespace)::FloatExprEvaluator, bool>::Visit(clang::Stmt const*) + 2830
9  clang             0x00000001090f3841 (anonymous namespace)::IntExprEvaluator::VisitBinaryOperator(clang::BinaryOperator const*) + 2289
10 clang             0x00000001090f29e6 clang::StmtVisitorBase<clang::make_const_ptr, (anonymous namespace)::IntExprEvaluator, bool>::Visit(clang::Stmt const*) + 6262
11 clang             0x00000001090ec885 _ZL8EvaluateRN5clang7APValueERN12_GLOBAL__N_18EvalInfoEPKNS_4ExprE + 325
12 clang             0x00000001090ec645 clang::Expr::Evaluate(clang::Expr::EvalResult&, clang::ASTContext const&) const + 69
13 clang             0x00000001090ed192 clang::Expr::EvaluateAsBooleanCondition(bool&, clang::ASTContext const&) const + 50
14 clang             0x0000000108ee3fac (anonymous namespace)::CFGBuilder::Visit(clang::Stmt*, (anonymous namespace)::AddStmtChoice) + 10940
15 clang             0x0000000108ee5d57 (anonymous namespace)::CFGBuilder::VisitCompoundStmt(clang::CompoundStmt*) + 119
16 clang             0x0000000108ee4c68 (anonymous namespace)::CFGBuilder::Visit(clang::Stmt*, (anonymous namespace)::AddStmtChoice) + 14200
17 clang             0x0000000108edc4fb clang::CFG::buildCFG(clang::Decl const*, clang::Stmt*, clang::ASTContext*, clang::CFG::BuildOptions const&) + 1531
18 clang             0x0000000108ed90ed clang::AnalysisDeclContext::getCFG() + 77
19 clang             0x0000000108b7a966 clang::sema::AnalysisBasedWarnings::IssueWarnings(clang::sema::AnalysisBasedWarnings::Policy, clang::sema::FunctionScopeInfo*, clang::Decl const*, clang::BlockExpr const*) + 2198
20 clang             0x0000000108b93c9f clang::Sema::PopFunctionOrBlockScope(clang::sema::AnalysisBasedWarnings::Policy const*, clang::Decl const*, clang::BlockExpr const*) + 95
21 clang             0x0000000108c243d6 clang::Sema::ActOnFinishFunctionBody(clang::Decl*, clang::Stmt*, bool) + 1510
22 clang             0x0000000108b68634 clang::Parser::ParseFunctionStatementBody(clang::Decl*, clang::Parser::ParseScope&) + 244
23 clang             0x0000000108b75fe1 clang::Parser::ParseFunctionDefinition(clang::Parser::ParsingDeclarator&, clang::Parser::ParsedTemplateInfo const&) + 2241
24 clang             0x0000000108b2813c clang::Parser::ParseDeclGroup(clang::Parser::ParsingDeclSpec&, unsigned int, bool, clang::SourceLocation*, clang::Parser::ForRangeInit*) + 1020
25 clang             0x0000000108b7519a clang::Parser::ParseDeclarationOrFunctionDefinition(clang::Parser::ParsingDeclSpec&, clang::AccessSpecifier) + 858
26 clang             0x0000000108b75399 clang::Parser::ParseDeclarationOrFunctionDefinition(clang::ParsedAttributes&, clang::AccessSpecifier) + 393
27 clang             0x0000000108b7434f clang::Parser::ParseExternalDeclaration(clang::Parser::ParsedAttributesWithRange&, clang::Parser::ParsingDeclSpec*) + 3295
28 clang             0x0000000108b735f7 clang::Parser::ParseTopLevelDecl(clang::OpaquePtr<clang::DeclGroupRef>&) + 247
29 clang             0x0000000108b1e0ed clang::ParseAST(clang::Sema&, bool) + 317
30 clang             0x0000000108aec920 clang::CodeGenAction::ExecuteAction() + 1040
31 clang             0x00000001088fe48b clang::CompilerInstance::ExecuteAction(clang::FrontendAction&) + 955
32 clang             0x00000001088e8318 clang::ExecuteCompilerInvocation(clang::CompilerInstance*) + 2792
33 clang             0x00000001088e0aa3 cc1_main(char const**, char const**, char const*, void*) + 5219
34 clang             0x00000001088e475f main + 687
35 clang             0x00000001088df634 start + 52

Here's a delta reduced test case:
-------------- next part --------------
A non-text attachment was scrubbed...
Name: foo.i
Type: application/octet-stream
Size: 441 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20111028/51a5da06/attachment.obj>
-------------- next part --------------


Reproduce with:
clang -Os -arch i386 -c foo.i -o /dev/null

Please take a moment to investigate.

 Regards,
  Chad



On Oct 28, 2011, at 10:51 AM, Richard Smith wrote:

> Author: rsmith
> Date: Fri Oct 28 12:51:58 2011
> New Revision: 143204
> 
> URL: http://llvm.org/viewvc/llvm-project?rev=143204&view=rev
> Log:
> Reinstate r142844 (reverted in r142872) now that lvalue-to-rvalue conversions
> are present in all the necessary places:
> 
> In constant expression evaluation, evaluate lvalues as lvalues and rvalues as
> rvalues. Remove special case for caching reference initialization and fix a
> cyclic initialization crash in the process.
> 
> Modified:
>    cfe/trunk/include/clang/AST/ASTContext.h
>    cfe/trunk/include/clang/AST/Expr.h
>    cfe/trunk/lib/AST/ExprConstant.cpp
>    cfe/trunk/test/CodeGenCXX/static-data-member.cpp
>    cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp
> 
> Modified: cfe/trunk/include/clang/AST/ASTContext.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=143204&r1=143203&r2=143204&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/AST/ASTContext.h (original)
> +++ cfe/trunk/include/clang/AST/ASTContext.h Fri Oct 28 12:51:58 2011
> @@ -1274,7 +1274,7 @@
>   CanQualType getCanonicalParamType(QualType T) const;
> 
>   /// \brief Determine whether the given types are equivalent.
> -  bool hasSameType(QualType T1, QualType T2) {
> +  bool hasSameType(QualType T1, QualType T2) const {
>     return getCanonicalType(T1) == getCanonicalType(T2);
>   }
> 
> @@ -1294,7 +1294,7 @@
> 
>   /// \brief Determine whether the given types are equivalent after
>   /// cvr-qualifiers have been removed.
> -  bool hasSameUnqualifiedType(QualType T1, QualType T2) {
> +  bool hasSameUnqualifiedType(QualType T1, QualType T2) const {
>     return getCanonicalType(T1).getTypePtr() ==
>            getCanonicalType(T2).getTypePtr();
>   }
> 
> Modified: cfe/trunk/include/clang/AST/Expr.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Expr.h?rev=143204&r1=143203&r2=143204&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/AST/Expr.h (original)
> +++ cfe/trunk/include/clang/AST/Expr.h Fri Oct 28 12:51:58 2011
> @@ -465,7 +465,8 @@
>   /// Evaluate - Return true if this is a constant which we can fold using
>   /// any crazy technique (that has nothing to do with language standards) that
>   /// we want to.  If this function returns true, it returns the folded constant
> -  /// in Result.
> +  /// in Result. If this expression is a glvalue, an lvalue-to-rvalue conversion
> +  /// will be applied.
>   bool Evaluate(EvalResult &Result, const ASTContext &Ctx) const;
> 
>   /// EvaluateAsBooleanCondition - Return true if this is a constant
> 
> Modified: cfe/trunk/lib/AST/ExprConstant.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=143204&r1=143203&r2=143204&view=diff
> ==============================================================================
> --- cfe/trunk/lib/AST/ExprConstant.cpp (original)
> +++ cfe/trunk/lib/AST/ExprConstant.cpp Fri Oct 28 12:51:58 2011
> @@ -148,10 +148,13 @@
>   if (const CompoundLiteralExpr *CLE = dyn_cast<CompoundLiteralExpr>(E))
>     return CLE->isFileScope();
> 
> +  if (isa<MemberExpr>(E))
> +    return false;
> +
>   return true;
> }
> 
> -static bool EvalPointerValueAsBool(LValue& Value, bool& Result) {
> +static bool EvalPointerValueAsBool(const LValue &Value, bool &Result) {
>   const Expr* Base = Value.Base;
> 
>   // A null base expression indicates a null pointer.  These are always
> @@ -183,40 +186,44 @@
>   return true;
> }
> 
> -static bool HandleConversionToBool(const Expr* E, bool& Result,
> -                                   EvalInfo &Info) {
> -  if (E->getType()->isIntegralOrEnumerationType()) {
> -    APSInt IntResult;
> -    if (!EvaluateInteger(E, IntResult, Info))
> -      return false;
> -    Result = IntResult != 0;
> +static bool HandleConversionToBool(const APValue &Val, bool &Result) {
> +  switch (Val.getKind()) {
> +  case APValue::Uninitialized:
> +    return false;
> +  case APValue::Int:
> +    Result = Val.getInt().getBoolValue();
>     return true;
> -  } else if (E->getType()->isRealFloatingType()) {
> -    APFloat FloatResult(0.0);
> -    if (!EvaluateFloat(E, FloatResult, Info))
> -      return false;
> -    Result = !FloatResult.isZero();
> +  case APValue::Float:
> +    Result = !Val.getFloat().isZero();
>     return true;
> -  } else if (E->getType()->hasPointerRepresentation()) {
> -    LValue PointerResult;
> -    if (!EvaluatePointer(E, PointerResult, Info))
> -      return false;
> -    return EvalPointerValueAsBool(PointerResult, Result);
> -  } else if (E->getType()->isAnyComplexType()) {
> -    ComplexValue ComplexResult;
> -    if (!EvaluateComplex(E, ComplexResult, Info))
> -      return false;
> -    if (ComplexResult.isComplexFloat()) {
> -      Result = !ComplexResult.getComplexFloatReal().isZero() ||
> -               !ComplexResult.getComplexFloatImag().isZero();
> -    } else {
> -      Result = ComplexResult.getComplexIntReal().getBoolValue() ||
> -               ComplexResult.getComplexIntImag().getBoolValue();
> -    }
> +  case APValue::ComplexInt:
> +    Result = Val.getComplexIntReal().getBoolValue() ||
> +             Val.getComplexIntImag().getBoolValue();
> +    return true;
> +  case APValue::ComplexFloat:
> +    Result = !Val.getComplexFloatReal().isZero() ||
> +             !Val.getComplexFloatImag().isZero();
>     return true;
> +  case APValue::LValue:
> +    {
> +      LValue PointerResult;
> +      PointerResult.setFrom(Val);
> +      return EvalPointerValueAsBool(PointerResult, Result);
> +    }
> +  case APValue::Vector:
> +    return false;
>   }
> 
> -  return false;
> +  llvm_unreachable("unknown APValue kind");
> +}
> +
> +static bool EvaluateAsBooleanCondition(const Expr *E, bool &Result,
> +                                       EvalInfo &Info) {
> +  assert(E->isRValue() && "missing lvalue-to-rvalue conv in bool condition");
> +  APValue Val;
> +  if (!Evaluate(Val, Info, E))
> +    return false;
> +  return HandleConversionToBool(Val, Result);
> }
> 
> static APSInt HandleFloatToIntCast(QualType DestType, QualType SrcType,
> @@ -263,6 +270,8 @@
> 
> /// Try to evaluate the initializer for a variable declaration.
> static APValue *EvaluateVarDeclInit(EvalInfo &Info, const VarDecl *VD) {
> +  // FIXME: If this is a parameter to an active constexpr function call, perform
> +  // substitution now.
>   if (isa<ParmVarDecl>(VD))
>     return 0;
> 
> @@ -278,10 +287,11 @@
> 
>   VD->setEvaluatingValue();
> 
> -  // FIXME: If the initializer isn't a constant expression, propagate up any
> -  // diagnostic explaining why not.
>   Expr::EvalResult EResult;
> -  if (Init->Evaluate(EResult, Info.Ctx) && !EResult.HasSideEffects)
> +  EvalInfo InitInfo(Info.Ctx, EResult);
> +  // FIXME: The caller will need to know whether the value was a constant
> +  // expression. If not, we should propagate up a diagnostic.
> +  if (Evaluate(EResult.Val, InitInfo, Init))
>     VD->setEvaluatedValue(EResult.Val);
>   else
>     VD->setEvaluatedValue(APValue());
> @@ -289,11 +299,92 @@
>   return VD->getEvaluatedValue();
> }
> 
> -bool IsConstNonVolatile(QualType T) {
> +static bool IsConstNonVolatile(QualType T) {
>   Qualifiers Quals = T.getQualifiers();
>   return Quals.hasConst() && !Quals.hasVolatile();
> }
> 
> +bool HandleLValueToRValueConversion(EvalInfo &Info, QualType Type,
> +                                    const LValue &LVal, APValue &RVal) {
> +  const Expr *Base = LVal.Base;
> +
> +  // FIXME: Indirection through a null pointer deserves a diagnostic.
> +  if (!Base)
> +    return false;
> +
> +  // FIXME: Support accessing subobjects of objects of literal types. A simple
> +  // byte offset is insufficient for C++11 semantics: we need to know how the
> +  // reference was formed (which union member was named, for instance).
> +  // FIXME: Support subobjects of StringLiteral and PredefinedExpr.
> +  if (!LVal.Offset.isZero())
> +    return false;
> +
> +  const Decl *D = 0;
> +
> +  if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Base)) {
> +    // If the lvalue has been cast to some other type, don't try to read it.
> +    // FIXME: Could simulate a bitcast here.
> +    if (!Info.Ctx.hasSameUnqualifiedType(Type, DRE->getType()))
> +      return false;
> +    D = DRE->getDecl();
> +  }
> +
> +  // FIXME: Static data members accessed via a MemberExpr are represented as
> +  // that MemberExpr. We should use the Decl directly instead.
> +  if (const MemberExpr *ME = dyn_cast<MemberExpr>(Base)) {
> +    if (!Info.Ctx.hasSameUnqualifiedType(Type, ME->getType()))
> +      return false;
> +    D = ME->getMemberDecl();
> +    assert(!isa<FieldDecl>(D) && "shouldn't see fields here");
> +  }
> +
> +  if (D) {
> +    // In C++98, const, non-volatile integers initialized with ICEs are ICEs.
> +    // In C++11, constexpr, non-volatile variables initialized with constant
> +    // expressions are constant expressions too.
> +    // In C, such things can also be folded, although they are not ICEs.
> +    //
> +    // FIXME: Allow folding any const variable of literal type initialized with
> +    // a constant expression. For now, we only allow variables with integral and
> +    // floating types to be folded.
> +    const VarDecl *VD = dyn_cast<VarDecl>(D);
> +    if (!VD || !IsConstNonVolatile(VD->getType()) ||
> +        (!Type->isIntegralOrEnumerationType() && !Type->isRealFloatingType()))
> +      return false;
> +
> +    APValue *V = EvaluateVarDeclInit(Info, VD);
> +    if (!V || V->isUninit())
> +      return false;
> +
> +    if (!VD->getAnyInitializer()->isLValue()) {
> +      RVal = *V;
> +      return true;
> +    }
> +
> +    // The declaration was initialized by an lvalue, with no lvalue-to-rvalue
> +    // conversion. This happens when the declaration and the lvalue should be
> +    // considered synonymous, for instance when initializing an array of char
> +    // from a string literal. Continue as if the initializer lvalue was the
> +    // value we were originally given.
> +    Base = V->getLValueBase();
> +    if (!V->getLValueOffset().isZero())
> +      return false;
> +  }
> +
> +  // FIXME: C++11: Support MaterializeTemporaryExpr in LValueExprEvaluator and
> +  // here.
> +
> +  // In C99, a CompoundLiteralExpr is an lvalue, and we defer evaluating the
> +  // initializer until now for such expressions. Such an expression can't be
> +  // an ICE in C, so this only matters for fold.
> +  if (const CompoundLiteralExpr *CLE = dyn_cast<CompoundLiteralExpr>(Base)) {
> +    assert(!Info.getLangOpts().CPlusPlus && "lvalue compound literal in c++?");
> +    return Evaluate(RVal, Info, CLE->getInitializer());
> +  }
> +
> +  return false;
> +}
> +
> namespace {
> class HasSideEffect
>   : public ConstStmtVisitor<HasSideEffect, bool> {
> @@ -454,7 +545,7 @@
>       return DerivedError(E);
> 
>     bool cond;
> -    if (!HandleConversionToBool(E->getCond(), cond, Info))
> +    if (!EvaluateAsBooleanCondition(E->getCond(), cond, Info))
>       return DerivedError(E);
> 
>     return StmtVisitorTy::Visit(cond ? E->getTrueExpr() : E->getFalseExpr());
> @@ -462,10 +553,10 @@
> 
>   RetTy VisitConditionalOperator(const ConditionalOperator *E) {
>     bool BoolResult;
> -    if (!HandleConversionToBool(E->getCond(), BoolResult, Info))
> +    if (!EvaluateAsBooleanCondition(E->getCond(), BoolResult, Info))
>       return DerivedError(E);
> 
> -    Expr* EvalExpr = BoolResult ? E->getTrueExpr() : E->getFalseExpr();
> +    Expr *EvalExpr = BoolResult ? E->getTrueExpr() : E->getFalseExpr();
>     return StmtVisitorTy::Visit(EvalExpr);
>   }
> 
> @@ -477,6 +568,9 @@
>     return DerivedSuccess(*value, E);
>   }
> 
> +  RetTy VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) {
> +    return StmtVisitorTy::Visit(E->getInitializer());
> +  }
>   RetTy VisitInitListExpr(const InitListExpr *E) {
>     if (Info.getLangOpts().CPlusPlus0x) {
>       if (E->getNumInits() == 0)
> @@ -493,6 +587,28 @@
>     return DerivedValueInitialization(E);
>   }
> 
> +  RetTy VisitCastExpr(const CastExpr *E) {
> +    switch (E->getCastKind()) {
> +    default:
> +      break;
> +
> +    case CK_NoOp:
> +      return StmtVisitorTy::Visit(E->getSubExpr());
> +
> +    case CK_LValueToRValue: {
> +      LValue LVal;
> +      if (EvaluateLValue(E->getSubExpr(), LVal, Info)) {
> +        APValue RVal;
> +        if (HandleLValueToRValueConversion(Info, E->getType(), LVal, RVal))
> +          return DerivedSuccess(RVal, E);
> +      }
> +      break;
> +    }
> +    }
> +
> +    return DerivedError(E);
> +  }
> +
>   /// Visit a value which is evaluated, but whose value is ignored.
>   void VisitIgnoredValue(const Expr *E) {
>     APValue Scratch;
> @@ -505,6 +621,23 @@
> 
> //===----------------------------------------------------------------------===//
> // LValue Evaluation
> +//
> +// This is used for evaluating lvalues (in C and C++), xvalues (in C++11),
> +// function designators (in C), decl references to void objects (in C), and
> +// temporaries (if building with -Wno-address-of-temporary).
> +//
> +// LValue evaluation produces values comprising a base expression of one of the
> +// following types:
> +//  * DeclRefExpr
> +//  * MemberExpr for a static member
> +//  * CompoundLiteralExpr in C
> +//  * StringLiteral
> +//  * PredefinedExpr
> +//  * ObjCEncodeExpr
> +//  * AddrLabelExpr
> +//  * BlockExpr
> +//  * CallExpr for a MakeStringConstant builtin
> +// plus an offset in bytes.
> //===----------------------------------------------------------------------===//
> namespace {
> class LValueExprEvaluator
> @@ -530,6 +663,8 @@
>     return false;
>   }
> 
> +  bool VisitVarDecl(const Expr *E, const VarDecl *VD);
> +
>   bool VisitDeclRefExpr(const DeclRefExpr *E);
>   bool VisitPredefinedExpr(const PredefinedExpr *E) { return Success(E); }
>   bool VisitCompoundLiteralExpr(const CompoundLiteralExpr *E);
> @@ -542,13 +677,13 @@
>   bool VisitCastExpr(const CastExpr *E) {
>     switch (E->getCastKind()) {
>     default:
> -      return false;
> +      return ExprEvaluatorBaseTy::VisitCastExpr(E);
> 
> -    case CK_NoOp:
>     case CK_LValueBitCast:
>       return Visit(E->getSubExpr());
> 
> -    // FIXME: Support CK_DerivedToBase and friends.
> +    // FIXME: Support CK_DerivedToBase and CK_UncheckedDerivedToBase.
> +    // Reuse PointerExprEvaluator::VisitCastExpr for these.
>     }
>   }
> 
> @@ -557,39 +692,52 @@
> };
> } // end anonymous namespace
> 
> +/// Evaluate an expression as an lvalue. This can be legitimately called on
> +/// expressions which are not glvalues, in a few cases:
> +///  * function designators in C,
> +///  * "extern void" objects,
> +///  * temporaries, if building with -Wno-address-of-temporary.
> static bool EvaluateLValue(const Expr* E, LValue& Result, EvalInfo &Info) {
> +  assert((E->isGLValue() || E->getType()->isFunctionType() ||
> +          E->getType()->isVoidType() || isa<CXXTemporaryObjectExpr>(E)) &&
> +         "can't evaluate expression as an lvalue");
>   return LValueExprEvaluator(Info, Result).Visit(E);
> }
> 
> bool LValueExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) {
> -  if (isa<FunctionDecl>(E->getDecl())) {
> +  if (isa<FunctionDecl>(E->getDecl()))
>     return Success(E);
> -  } else if (const VarDecl* VD = dyn_cast<VarDecl>(E->getDecl())) {
> -    if (!VD->getType()->isReferenceType())
> -      return Success(E);
> -    // Reference parameters can refer to anything even if they have an
> -    // "initializer" in the form of a default argument.
> -    if (!isa<ParmVarDecl>(VD)) {
> -      // FIXME: Check whether VD might be overridden!
> +  if (const VarDecl* VD = dyn_cast<VarDecl>(E->getDecl()))
> +    return VisitVarDecl(E, VD);
> +  return Error(E);
> +}
> 
> -      // Check for recursive initializers of references.
> -      if (PrevDecl == VD)
> -        return Error(E);
> -      PrevDecl = VD;
> -      if (const Expr *Init = VD->getAnyInitializer())
> -        return Visit(Init);
> -    }
> -  }
> +bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) {
> +  if (!VD->getType()->isReferenceType())
> +    return Success(E);
> +
> +  APValue *V = EvaluateVarDeclInit(Info, VD);
> +  if (V && !V->isUninit())
> +    return Success(*V, E);
> 
> -  return ExprEvaluatorBaseTy::VisitDeclRefExpr(E);
> +  return Error(E);
> }
> 
> bool
> LValueExprEvaluator::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) {
> +  assert(!Info.getLangOpts().CPlusPlus && "lvalue compound literal in c++?");
> +  // Defer visiting the literal until the lvalue-to-rvalue conversion. We can
> +  // only see this when folding in C, so there's no standard to follow here.
>   return Success(E);
> }
> 
> bool LValueExprEvaluator::VisitMemberExpr(const MemberExpr *E) {
> +  // Handle static data members.
> +  if (const VarDecl *VD = dyn_cast<VarDecl>(E->getMemberDecl())) {
> +    VisitIgnoredValue(E->getBase());
> +    return VisitVarDecl(E, VD);
> +  }
> +
>   QualType Ty;
>   if (E->isArrow()) {
>     if (!EvaluatePointer(E->getBase(), Result, Info))
> @@ -617,6 +765,10 @@
> }
> 
> bool LValueExprEvaluator::VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
> +  // FIXME: Deal with vectors as array subscript bases.
> +  if (E->getBase()->getType()->isVectorType())
> +    return false;
> +
>   if (!EvaluatePointer(E->getBase(), Result, Info))
>     return false;
> 
> @@ -684,7 +836,7 @@
> } // end anonymous namespace
> 
> static bool EvaluatePointer(const Expr* E, LValue& Result, EvalInfo &Info) {
> -  assert(E->getType()->hasPointerRepresentation());
> +  assert(E->isRValue() && E->getType()->hasPointerRepresentation());
>   return PointerExprEvaluator(Info, Result).Visit(E);
> }
> 
> @@ -740,7 +892,6 @@
>   default:
>     break;
> 
> -  case CK_NoOp:
>   case CK_BitCast:
>   case CK_CPointerToObjCPointerCast:
>   case CK_BlockPointerToObjCPointerCast:
> @@ -810,7 +961,7 @@
>     return EvaluateLValue(SubExpr, Result, Info);
>   }
> 
> -  return false;
> +  return ExprEvaluatorBaseTy::VisitCastExpr(E);
> }
> 
> bool PointerExprEvaluator::VisitCallExpr(const CallExpr *E) {
> @@ -852,7 +1003,6 @@
>     bool VisitUnaryReal(const UnaryOperator *E)
>       { return Visit(E->getSubExpr()); }
>     bool VisitCastExpr(const CastExpr* E);
> -    bool VisitCompoundLiteralExpr(const CompoundLiteralExpr *E);
>     bool VisitInitListExpr(const InitListExpr *E);
>     bool VisitUnaryImag(const UnaryOperator *E);
>     // FIXME: Missing: unary -, unary ~, binary add/sub/mul/div,
> @@ -864,8 +1014,7 @@
> } // end anonymous namespace
> 
> static bool EvaluateVector(const Expr* E, APValue& Result, EvalInfo &Info) {
> -  if (!E->getType()->isVectorType())
> -    return false;
> +  assert(E->isRValue() && E->getType()->isVectorType() &&"not a vector rvalue");
>   return VectorExprEvaluator(Info, Result).Visit(E);
> }
> 
> @@ -927,20 +1076,12 @@
>     }
>     return Success(Elts, E);
>   }
> -  case CK_LValueToRValue:
> -  case CK_NoOp:
> -    return Visit(SE);
>   default:
> -    return Error(E);
> +    return ExprEvaluatorBaseTy::VisitCastExpr(E);
>   }
> }
> 
> bool
> -VectorExprEvaluator::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) {
> -  return Visit(E->getInitializer());
> -}
> -
> -bool
> VectorExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
>   const VectorType *VT = E->getType()->castAs<VectorType>();
>   unsigned NumInits = E->getNumInits();
> @@ -1022,6 +1163,10 @@
> 
> //===----------------------------------------------------------------------===//
> // Integer Evaluation
> +//
> +// As a GNU extension, we support casting pointers to sufficiently-wide integer
> +// types and back in constant folding. Integer values are thus represented
> +// either as an integer-valued APValue, or as an lvalue-valued APValue.
> //===----------------------------------------------------------------------===//
> 
> namespace {
> @@ -1105,8 +1250,7 @@
>   }
>   bool VisitMemberExpr(const MemberExpr *E) {
>     if (CheckReferencedDecl(E, E->getMemberDecl())) {
> -      // Conservatively assume a MemberExpr will have side-effects
> -      Info.EvalStatus.HasSideEffects = true;
> +      VisitIgnoredValue(E->getBase());
>       return true;
>     }
> 
> @@ -1161,14 +1305,20 @@
> };
> } // end anonymous namespace
> 
> +/// EvaluateIntegerOrLValue - Evaluate an rvalue integral-typed expression, and
> +/// produce either the integer value or a pointer.
> +///
> +/// GCC has a heinous extension which folds casts between pointer types and
> +/// pointer-sized integral types. We support this by allowing the evaluation of
> +/// an integer rvalue to produce a pointer (represented as an lvalue) instead.
> +/// Some simple arithmetic on such values is supported (they are treated much
> +/// like char*).
> static bool EvaluateIntegerOrLValue(const Expr* E, APValue &Result, EvalInfo &Info) {
> -  assert(E->getType()->isIntegralOrEnumerationType());
> +  assert(E->isRValue() && E->getType()->isIntegralOrEnumerationType());
>   return IntExprEvaluator(Info, Result).Visit(E);
> }
> 
> static bool EvaluateInteger(const Expr* E, APSInt &Result, EvalInfo &Info) {
> -  assert(E->getType()->isIntegralOrEnumerationType());
> -
>   APValue Val;
>   if (!EvaluateIntegerOrLValue(E, Val, Info) || !Val.isInt())
>     return false;
> @@ -1197,18 +1347,6 @@
>       return Success(Val, E);
>     }
>   }
> -
> -  // In C++, const, non-volatile integers initialized with ICEs are ICEs.
> -  // In C, they can also be folded, although they are not ICEs.
> -  if (IsConstNonVolatile(E->getType())) {
> -    if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
> -      APValue *V = EvaluateVarDeclInit(Info, VD);
> -      if (V && V->isInt())
> -        return Success(V->getInt(), E);
> -    }
> -  }
> -
> -  // Otherwise, random variable references are not constants.
>   return false;
> }
> 
> @@ -1411,6 +1549,9 @@
> }
> 
> bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
> +  if (E->isAssignmentOp())
> +    return Error(E->getOperatorLoc(), diag::note_invalid_subexpr_in_ice, E);
> +
>   if (E->getOpcode() == BO_Comma) {
>     VisitIgnoredValue(E->getLHS());
>     return Visit(E->getRHS());
> @@ -1421,20 +1562,20 @@
>     // necessarily integral
>     bool lhsResult, rhsResult;
> 
> -    if (HandleConversionToBool(E->getLHS(), lhsResult, Info)) {
> +    if (EvaluateAsBooleanCondition(E->getLHS(), lhsResult, Info)) {
>       // We were able to evaluate the LHS, see if we can get away with not
>       // evaluating the RHS: 0 && X -> 0, 1 || X -> 1
>       if (lhsResult == (E->getOpcode() == BO_LOr))
>         return Success(lhsResult, E);
> 
> -      if (HandleConversionToBool(E->getRHS(), rhsResult, Info)) {
> +      if (EvaluateAsBooleanCondition(E->getRHS(), rhsResult, Info)) {
>         if (E->getOpcode() == BO_LOr)
>           return Success(lhsResult || rhsResult, E);
>         else
>           return Success(lhsResult && rhsResult, E);
>       }
>     } else {
> -      if (HandleConversionToBool(E->getRHS(), rhsResult, Info)) {
> +      if (EvaluateAsBooleanCondition(E->getRHS(), rhsResult, Info)) {
>         // We can't evaluate the LHS; however, sometimes the result
>         // is determined by the RHS: X && 0 -> 0, X || 1 -> 1.
>         if (rhsResult == (E->getOpcode() == BO_LOr) ||
> @@ -1590,58 +1731,60 @@
>   }
> 
>   // The LHS of a constant expr is always evaluated and needed.
> -  if (!Visit(E->getLHS()))
> +  APValue LHSVal;
> +  if (!EvaluateIntegerOrLValue(E->getLHS(), LHSVal, Info))
>     return false; // error in subexpression.
> 
> -  APValue RHSVal;
> -  if (!EvaluateIntegerOrLValue(E->getRHS(), RHSVal, Info))
> +  if (!Visit(E->getRHS()))
>     return false;
> +  APValue &RHSVal = Result;
> 
>   // Handle cases like (unsigned long)&a + 4.
> -  if (E->isAdditiveOp() && Result.isLValue() && RHSVal.isInt()) {
> -    CharUnits Offset = Result.getLValueOffset();
> +  if (E->isAdditiveOp() && LHSVal.isLValue() && RHSVal.isInt()) {
> +    CharUnits Offset = LHSVal.getLValueOffset();
>     CharUnits AdditionalOffset = CharUnits::fromQuantity(
>                                      RHSVal.getInt().getZExtValue());
>     if (E->getOpcode() == BO_Add)
>       Offset += AdditionalOffset;
>     else
>       Offset -= AdditionalOffset;
> -    Result = APValue(Result.getLValueBase(), Offset);
> +    Result = APValue(LHSVal.getLValueBase(), Offset);
>     return true;
>   }
> 
>   // Handle cases like 4 + (unsigned long)&a
>   if (E->getOpcode() == BO_Add &&
> -        RHSVal.isLValue() && Result.isInt()) {
> +        RHSVal.isLValue() && LHSVal.isInt()) {
>     CharUnits Offset = RHSVal.getLValueOffset();
> -    Offset += CharUnits::fromQuantity(Result.getInt().getZExtValue());
> +    Offset += CharUnits::fromQuantity(LHSVal.getInt().getZExtValue());
>     Result = APValue(RHSVal.getLValueBase(), Offset);
>     return true;
>   }
> 
>   // All the following cases expect both operands to be an integer
> -  if (!Result.isInt() || !RHSVal.isInt())
> +  if (!LHSVal.isInt() || !RHSVal.isInt())
>     return false;
> 
> -  APSInt& RHS = RHSVal.getInt();
> +  APSInt &LHS = LHSVal.getInt();
> +  APSInt &RHS = RHSVal.getInt();
> 
>   switch (E->getOpcode()) {
>   default:
>     return Error(E->getOperatorLoc(), diag::note_invalid_subexpr_in_ice, E);
> -  case BO_Mul: return Success(Result.getInt() * RHS, E);
> -  case BO_Add: return Success(Result.getInt() + RHS, E);
> -  case BO_Sub: return Success(Result.getInt() - RHS, E);
> -  case BO_And: return Success(Result.getInt() & RHS, E);
> -  case BO_Xor: return Success(Result.getInt() ^ RHS, E);
> -  case BO_Or:  return Success(Result.getInt() | RHS, E);
> +  case BO_Mul: return Success(LHS * RHS, E);
> +  case BO_Add: return Success(LHS + RHS, E);
> +  case BO_Sub: return Success(LHS - RHS, E);
> +  case BO_And: return Success(LHS & RHS, E);
> +  case BO_Xor: return Success(LHS ^ RHS, E);
> +  case BO_Or:  return Success(LHS | RHS, E);
>   case BO_Div:
>     if (RHS == 0)
>       return Error(E->getOperatorLoc(), diag::note_expr_divide_by_zero, E);
> -    return Success(Result.getInt() / RHS, E);
> +    return Success(LHS / RHS, E);
>   case BO_Rem:
>     if (RHS == 0)
>       return Error(E->getOperatorLoc(), diag::note_expr_divide_by_zero, E);
> -    return Success(Result.getInt() % RHS, E);
> +    return Success(LHS % RHS, E);
>   case BO_Shl: {
>     // During constant-folding, a negative shift is an opposite shift.
>     if (RHS.isSigned() && RHS.isNegative()) {
> @@ -1651,8 +1794,8 @@
> 
>   shift_left:
>     unsigned SA
> -      = (unsigned) RHS.getLimitedValue(Result.getInt().getBitWidth()-1);
> -    return Success(Result.getInt() << SA, E);
> +      = (unsigned) RHS.getLimitedValue(LHS.getBitWidth()-1);
> +    return Success(LHS << SA, E);
>   }
>   case BO_Shr: {
>     // During constant-folding, a negative shift is an opposite shift.
> @@ -1663,16 +1806,16 @@
> 
>   shift_right:
>     unsigned SA =
> -      (unsigned) RHS.getLimitedValue(Result.getInt().getBitWidth()-1);
> -    return Success(Result.getInt() >> SA, E);
> +      (unsigned) RHS.getLimitedValue(LHS.getBitWidth()-1);
> +    return Success(LHS >> SA, E);
>   }
> 
> -  case BO_LT: return Success(Result.getInt() < RHS, E);
> -  case BO_GT: return Success(Result.getInt() > RHS, E);
> -  case BO_LE: return Success(Result.getInt() <= RHS, E);
> -  case BO_GE: return Success(Result.getInt() >= RHS, E);
> -  case BO_EQ: return Success(Result.getInt() == RHS, E);
> -  case BO_NE: return Success(Result.getInt() != RHS, E);
> +  case BO_LT: return Success(LHS < RHS, E);
> +  case BO_GT: return Success(LHS > RHS, E);
> +  case BO_LE: return Success(LHS <= RHS, E);
> +  case BO_GE: return Success(LHS >= RHS, E);
> +  case BO_EQ: return Success(LHS == RHS, E);
> +  case BO_NE: return Success(LHS != RHS, E);
>   }
> }
> 
> @@ -1833,7 +1976,7 @@
>   if (E->getOpcode() == UO_LNot) {
>     // LNot's operand isn't necessarily an integer, so we handle it specially.
>     bool bres;
> -    if (!HandleConversionToBool(E->getSubExpr(), bres, Info))
> +    if (!EvaluateAsBooleanCondition(E->getSubExpr(), bres, Info))
>       return false;
>     return Success(!bres, E);
>   }
> @@ -1842,8 +1985,9 @@
>   if (!E->getSubExpr()->getType()->isIntegralOrEnumerationType())
>     return false;
> 
> -  // Get the operand value into 'Result'.
> -  if (!Visit(E->getSubExpr()))
> +  // Get the operand value.
> +  APValue Val;
> +  if (!Evaluate(Val, Info, E->getSubExpr()))
>     return false;
> 
>   switch (E->getOpcode()) {
> @@ -1854,16 +1998,16 @@
>   case UO_Extension:
>     // FIXME: Should extension allow i-c-e extension expressions in its scope?
>     // If so, we could clear the diagnostic ID.
> -    return true;
> +    return Success(Val, E);
>   case UO_Plus:
> -    // The result is always just the subexpr.
> -    return true;
> +    // The result is just the value.
> +    return Success(Val, E);
>   case UO_Minus:
> -    if (!Result.isInt()) return false;
> -    return Success(-Result.getInt(), E);
> +    if (!Val.isInt()) return false;
> +    return Success(-Val.getInt(), E);
>   case UO_Not:
> -    if (!Result.isInt()) return false;
> -    return Success(~Result.getInt(), E);
> +    if (!Val.isInt()) return false;
> +    return Success(~Val.getInt(), E);
>   }
> }
> 
> @@ -1918,7 +2062,7 @@
> 
>   case CK_LValueToRValue:
>   case CK_NoOp:
> -    return Visit(E->getSubExpr());
> +    return ExprEvaluatorBaseTy::VisitCastExpr(E);
> 
>   case CK_MemberPointerToBoolean:
>   case CK_PointerToBoolean:
> @@ -1927,7 +2071,7 @@
>   case CK_FloatingComplexToBoolean:
>   case CK_IntegralComplexToBoolean: {
>     bool BoolResult;
> -    if (!HandleConversionToBool(SubExpr, BoolResult, Info))
> +    if (!EvaluateAsBooleanCondition(SubExpr, BoolResult, Info))
>       return false;
>     return Success(BoolResult, E);
>   }
> @@ -2050,15 +2194,13 @@
>   bool VisitUnaryReal(const UnaryOperator *E);
>   bool VisitUnaryImag(const UnaryOperator *E);
> 
> -  bool VisitDeclRefExpr(const DeclRefExpr *E);
> -
>   // FIXME: Missing: array subscript of vector, member of vector,
>   //                 ImplicitValueInitExpr
> };
> } // end anonymous namespace
> 
> static bool EvaluateFloat(const Expr* E, APFloat& Result, EvalInfo &Info) {
> -  assert(E->getType()->isRealFloatingType());
> +  assert(E->isRValue() && E->getType()->isRealFloatingType());
>   return FloatExprEvaluator(Info, Result).Visit(E);
> }
> 
> @@ -2141,21 +2283,6 @@
>   }
> }
> 
> -bool FloatExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) {
> -  if (ExprEvaluatorBaseTy::VisitDeclRefExpr(E))
> -    return true;
> -
> -  const VarDecl *VD = dyn_cast<VarDecl>(E->getDecl());
> -  if (VD && IsConstNonVolatile(VD->getType())) {
> -    APValue *V = EvaluateVarDeclInit(Info, VD);
> -    if (V && V->isFloat()) {
> -      Result = V->getFloat();
> -      return true;
> -    }
> -  }
> -  return false;
> -}
> -
> bool FloatExprEvaluator::VisitUnaryReal(const UnaryOperator *E) {
>   if (E->getSubExpr()->getType()->isAnyComplexType()) {
>     ComplexValue CV;
> @@ -2245,11 +2372,7 @@
> 
>   switch (E->getCastKind()) {
>   default:
> -    return false;
> -
> -  case CK_LValueToRValue:
> -  case CK_NoOp:
> -    return Visit(SubExpr);
> +    return ExprEvaluatorBaseTy::VisitCastExpr(E);
> 
>   case CK_IntegralToFloating: {
>     APSInt IntResult;
> @@ -2317,7 +2440,7 @@
> 
> static bool EvaluateComplex(const Expr *E, ComplexValue &Result,
>                             EvalInfo &Info) {
> -  assert(E->getType()->isAnyComplexType());
> +  assert(E->isRValue() && E->getType()->isAnyComplexType());
>   return ComplexExprEvaluator(Info, Result).Visit(E);
> }
> 
> @@ -2390,7 +2513,7 @@
> 
>   case CK_LValueToRValue:
>   case CK_NoOp:
> -    return Visit(E->getSubExpr());
> +    return ExprEvaluatorBaseTy::VisitCastExpr(E);
> 
>   case CK_Dependent:
>   case CK_GetObjCProperty:
> @@ -2634,27 +2757,28 @@
> //===----------------------------------------------------------------------===//
> 
> static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E) {
> -  if (E->getType()->isVectorType()) {
> +  // In C, function designators are not lvalues, but we evaluate them as if they
> +  // are.
> +  if (E->isGLValue() || E->getType()->isFunctionType()) {
> +    LValue LV;
> +    if (!EvaluateLValue(E, LV, Info))
> +      return false;
> +    LV.moveInto(Result);
> +  } else if (E->getType()->isVectorType()) {
>     if (!EvaluateVector(E, Result, Info))
>       return false;
>   } else if (E->getType()->isIntegralOrEnumerationType()) {
>     if (!IntExprEvaluator(Info, Result).Visit(E))
>       return false;
> -    if (Result.isLValue() &&
> -        !IsGlobalLValue(Result.getLValueBase()))
> -      return false;
>   } else if (E->getType()->hasPointerRepresentation()) {
>     LValue LV;
>     if (!EvaluatePointer(E, LV, Info))
>       return false;
> -    if (!IsGlobalLValue(LV.Base))
> -      return false;
>     LV.moveInto(Result);
>   } else if (E->getType()->isRealFloatingType()) {
>     llvm::APFloat F(0.0);
>     if (!EvaluateFloat(E, F, Info))
>       return false;
> -
>     Result = APValue(F);
>   } else if (E->getType()->isAnyComplexType()) {
>     ComplexValue C;
> @@ -2667,36 +2791,50 @@
>   return true;
> }
> 
> +
> /// Evaluate - Return true if this is a constant which we can fold using
> /// any crazy technique (that has nothing to do with language standards) that
> /// we want to.  If this function returns true, it returns the folded constant
> -/// in Result.
> +/// in Result. If this expression is a glvalue, an lvalue-to-rvalue conversion
> +/// will be applied to the result.
> bool Expr::Evaluate(EvalResult &Result, const ASTContext &Ctx) const {
>   EvalInfo Info(Ctx, Result);
> -  return ::Evaluate(Result.Val, Info, this);
> +
> +  if (!::Evaluate(Result.Val, Info, this))
> +    return false;
> +
> +  if (isGLValue()) {
> +    LValue LV;
> +    LV.setFrom(Result.Val);
> +    return HandleLValueToRValueConversion(Info, getType(), LV, Result.Val);
> +  }
> +
> +  // FIXME: We don't allow expressions to fold to pointers or references to
> +  // locals. Code which calls Evaluate() isn't ready for that yet.
> +  return !Result.Val.isLValue() || IsGlobalLValue(Result.Val.getLValueBase());
> }
> 
> bool Expr::EvaluateAsBooleanCondition(bool &Result,
>                                       const ASTContext &Ctx) const {
> -  EvalStatus Scratch;
> -  EvalInfo Info(Ctx, Scratch);
> -
> -  return HandleConversionToBool(this, Result, Info);
> +  EvalResult Scratch;
> +  return Evaluate(Scratch, Ctx) && HandleConversionToBool(Scratch.Val, Result);
> }
> 
> bool Expr::EvaluateAsInt(APSInt &Result, const ASTContext &Ctx) const {
> -  EvalStatus Scratch;
> -  EvalInfo Info(Ctx, Scratch);
> -
> -  return EvaluateInteger(this, Result, Info) && !Scratch.HasSideEffects;
> +  EvalResult ExprResult;
> +  if (!Evaluate(ExprResult, Ctx) || ExprResult.HasSideEffects ||
> +      !ExprResult.Val.isInt()) {
> +    return false;
> +  }
> +  Result = ExprResult.Val.getInt();
> +  return true;
> }
> 
> bool Expr::EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx) const {
>   EvalInfo Info(Ctx, Result);
> 
>   LValue LV;
> -  if (EvaluateLValue(this, LV, Info) &&
> -      !Result.HasSideEffects &&
> +  if (EvaluateLValue(this, LV, Info) && !Result.HasSideEffects &&
>       IsGlobalLValue(LV.Base)) {
>     LV.moveInto(Result.Val);
>     return true;
> @@ -3193,11 +3331,7 @@
>     if (Loc) *Loc = d.Loc;
>     return false;
>   }
> -  EvalResult EvalResult;
> -  if (!Evaluate(EvalResult, Ctx))
> +  if (!EvaluateAsInt(Result, Ctx))
>     llvm_unreachable("ICE cannot be evaluated!");
> -  assert(!EvalResult.HasSideEffects && "ICE with side effects!");
> -  assert(EvalResult.Val.isInt() && "ICE that isn't integer!");
> -  Result = EvalResult.Val.getInt();
>   return true;
> }
> 
> Modified: cfe/trunk/test/CodeGenCXX/static-data-member.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/static-data-member.cpp?rev=143204&r1=143203&r2=143204&view=diff
> ==============================================================================
> --- cfe/trunk/test/CodeGenCXX/static-data-member.cpp (original)
> +++ cfe/trunk/test/CodeGenCXX/static-data-member.cpp Fri Oct 28 12:51:58 2011
> @@ -64,3 +64,17 @@
>   // CHECK-NEXT: br label
>   // CHECK:      ret void
> }
> +
> +// Test that we can fold member lookup expressions which resolve to static data
> +// members.
> +namespace test4 {
> +  struct A {
> +    static const int n = 76;
> +  };
> +
> +  int f(A *a) {
> +    // CHECK: define i32 @_ZN5test41fEPNS_1AE
> +    // CHECK: ret i32 76
> +    return a->n;
> +  }
> +}
> 
> Modified: cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp?rev=143204&r1=143203&r2=143204&view=diff
> ==============================================================================
> --- cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp (original)
> +++ cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp Fri Oct 28 12:51:58 2011
> @@ -26,3 +26,17 @@
>     }
>   }
> }
> +
> +extern int &Recurse1;
> +int &Recurse2 = Recurse1, &Recurse1 = Recurse2;
> +constexpr int &Recurse3 = Recurse2; // expected-error {{must be initialized by a constant expression}}
> +
> +namespace MemberEnum {
> +  struct WithMemberEnum {
> +    enum E { A = 42 };
> +  } wme;
> +  // FIXME: b's initializer is not treated as a constant expression yet, but we
> +  // can at least fold it.
> +  constexpr bool b = wme.A == 42;
> +  int n[b];
> +}
> 
> 
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits



More information about the cfe-commits mailing list