r273602 - Implement p0292r2 (constexpr if), a likely C++1z feature.

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Thu Jun 23 22:03:47 PDT 2016


On Thu, Jun 23, 2016 at 12:26 PM, Aaron Ballman via cfe-commits <
cfe-commits at lists.llvm.org> wrote:

> On Thu, Jun 23, 2016 at 3:16 PM, Richard Smith via cfe-commits
> <cfe-commits at lists.llvm.org> wrote:
> > Author: rsmith
> > Date: Thu Jun 23 14:16:49 2016
> > New Revision: 273602
> >
> > URL: http://llvm.org/viewvc/llvm-project?rev=273602&view=rev
> > Log:
> > Implement p0292r2 (constexpr if), a likely C++1z feature.
>
> Is there a feature testing macro for this, or is one not required (or
> is one not determined by SG10 yet)?
>

The paper does not propose one. I expect we'll add one, though; I can
imagine reasonable use cases where you'd want to make an 'if' constexpr if
the feature is supported (and otherwise have a regular if).


> ~Aaron
>
> >
> > Added:
> >     cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p2-1z.cpp
> >     cfe/trunk/test/CXX/stmt.stmt/stmt.select/stmt.if/p2.cpp
> >     cfe/trunk/test/CodeGenCXX/cxx1z-constexpr-if.cpp
> > Modified:
> >     cfe/trunk/include/clang/AST/Stmt.h
> >     cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
> >     cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
> >     cfe/trunk/include/clang/Sema/Sema.h
> >     cfe/trunk/lib/AST/ASTImporter.cpp
> >     cfe/trunk/lib/AST/Stmt.cpp
> >     cfe/trunk/lib/Analysis/BodyFarm.cpp
> >     cfe/trunk/lib/CodeGen/CGStmt.cpp
> >     cfe/trunk/lib/CodeGen/CodeGenFunction.cpp
> >     cfe/trunk/lib/CodeGen/CodeGenFunction.h
> >     cfe/trunk/lib/Parse/ParseStmt.cpp
> >     cfe/trunk/lib/Sema/JumpDiagnostics.cpp
> >     cfe/trunk/lib/Sema/SemaExpr.cpp
> >     cfe/trunk/lib/Sema/SemaExprCXX.cpp
> >     cfe/trunk/lib/Sema/SemaExprMember.cpp
> >     cfe/trunk/lib/Sema/SemaLambda.cpp
> >     cfe/trunk/lib/Sema/SemaStmt.cpp
> >     cfe/trunk/lib/Sema/TreeTransform.h
> >     cfe/trunk/lib/Serialization/ASTReaderStmt.cpp
> >     cfe/trunk/lib/Serialization/ASTWriterStmt.cpp
> >     cfe/trunk/www/cxx_status.html
> >
> > Modified: cfe/trunk/include/clang/AST/Stmt.h
> > URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Stmt.h?rev=273602&r1=273601&r2=273602&view=diff
> >
> ==============================================================================
> > --- cfe/trunk/include/clang/AST/Stmt.h (original)
> > +++ cfe/trunk/include/clang/AST/Stmt.h Thu Jun 23 14:16:49 2016
> > @@ -93,6 +93,13 @@ protected:
> >      unsigned NumStmts : 32 - NumStmtBits;
> >    };
> >
> > +  class IfStmtBitfields {
> > +    friend class IfStmt;
> > +    unsigned : NumStmtBits;
> > +
> > +    unsigned IsConstexpr : 1;
> > +  };
> > +
> >    class ExprBitfields {
> >      friend class Expr;
> >      friend class DeclRefExpr; // computeDependence
> > @@ -248,6 +255,7 @@ protected:
> >    union {
> >      StmtBitfields StmtBits;
> >      CompoundStmtBitfields CompoundStmtBits;
> > +    IfStmtBitfields IfStmtBits;
> >      ExprBitfields ExprBits;
> >      CharacterLiteralBitfields CharacterLiteralBits;
> >      FloatingLiteralBitfields FloatingLiteralBits;
> > @@ -878,7 +886,8 @@ class IfStmt : public Stmt {
> >    SourceLocation ElseLoc;
> >
> >  public:
> > -  IfStmt(const ASTContext &C, SourceLocation IL, VarDecl *var, Expr
> *cond,
> > +  IfStmt(const ASTContext &C, SourceLocation IL,
> > +         bool IsConstexpr, VarDecl *var, Expr *cond,
> >           Stmt *then, SourceLocation EL = SourceLocation(),
> >           Stmt *elsev = nullptr);
> >
> > @@ -918,6 +927,9 @@ public:
> >    SourceLocation getElseLoc() const { return ElseLoc; }
> >    void setElseLoc(SourceLocation L) { ElseLoc = L; }
> >
> > +  bool isConstexpr() const { return IfStmtBits.IsConstexpr; }
> > +  void setConstexpr(bool C) { IfStmtBits.IsConstexpr = C; }
> > +
> >    SourceLocation getLocStart() const LLVM_READONLY { return IfLoc; }
> >    SourceLocation getLocEnd() const LLVM_READONLY {
> >      if (SubExprs[ELSE])
> >
> > Modified: cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
> > URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td?rev=273602&r1=273601&r2=273602&view=diff
> >
> ==============================================================================
> > --- cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td (original)
> > +++ cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td Thu Jun 23
> 14:16:49 2016
> > @@ -512,6 +512,11 @@ def err_function_is_not_record : Error<
> >    "unexpected %0 in function call; perhaps remove the %0?">;
> >  def err_super_in_using_declaration : Error<
> >    "'__super' cannot be used with a using declaration">;
> > +def ext_constexpr_if : ExtWarn<
> > +  "constexpr if is a C++1z extension">, InGroup<CXX1z>;
> > +def warn_cxx14_compat_constexpr_if : Warning<
> > +  "constexpr if is incompatible with C++ standards before C++1z">,
> > +  DefaultIgnore, InGroup<CXXPre1zCompat>;
> >
> >  // C++ derived classes
> >  def err_dup_virtual : Error<"duplicate 'virtual' in base specifier">;
> >
> > Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
> > URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=273602&r1=273601&r2=273602&view=diff
> >
> ==============================================================================
> > --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
> > +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Jun 23
> 14:16:49 2016
> > @@ -75,10 +75,12 @@ def err_typecheck_converted_constant_exp
> >    "conversion from %0 to %1 in converted constant expression would "
> >    "bind reference to a temporary">;
> >  def err_expr_not_cce : Error<
> > -  "%select{case value|enumerator value|non-type template argument|array
> size}0 "
> > +  "%select{case value|enumerator value|non-type template argument|"
> > +  "array size|constexpr if condition}0 "
> >    "is not a constant expression">;
> >  def ext_cce_narrowing : ExtWarn<
> > -  "%select{case value|enumerator value|non-type template argument|array
> size}0 "
> > +  "%select{case value|enumerator value|non-type template argument|"
> > +  "array size|constexpr if condition}0 "
> >    "%select{cannot be narrowed from type %2 to %3|"
> >    "evaluates to %2, which cannot be narrowed to type %3}1">,
> >    InGroup<CXX11Narrowing>, DefaultError, SFINAEFailure;
> > @@ -4641,6 +4643,8 @@ def note_protected_by_vla_typedef : Note
> >    "jump bypasses initialization of VLA typedef">;
> >  def note_protected_by_vla_type_alias : Note<
> >    "jump bypasses initialization of VLA type alias">;
> > +def note_protected_by_constexpr_if : Note<
> > +  "jump enters controlled statement of constexpr if">;
> >  def note_protected_by_vla : Note<
> >    "jump bypasses initialization of variable length array">;
> >  def note_protected_by_objc_try : Note<
> >
> > Modified: cfe/trunk/include/clang/Sema/Sema.h
> > URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=273602&r1=273601&r2=273602&view=diff
> >
> ==============================================================================
> > --- cfe/trunk/include/clang/Sema/Sema.h (original)
> > +++ cfe/trunk/include/clang/Sema/Sema.h Thu Jun 23 14:16:49 2016
> > @@ -797,6 +797,11 @@ public:
> >      /// run time.
> >      Unevaluated,
> >
> > +    /// \brief The current expression occurs within a discarded
> statement.
> > +    /// This behaves largely similarly to an unevaluated operand in
> preventing
> > +    /// definitions from being required, but not in other ways.
> > +    DiscardedStatement,
> > +
> >      /// \brief The current expression occurs within an unevaluated
> >      /// operand that unconditionally permits abstract references to
> >      /// fields, such as a SIZE operator in MS-style inline assembly.
> > @@ -2329,7 +2334,8 @@ public:
> >      CCEK_CaseValue,   ///< Expression in a case label.
> >      CCEK_Enumerator,  ///< Enumerator value with fixed underlying type.
> >      CCEK_TemplateArg, ///< Value of a non-type template parameter.
> > -    CCEK_NewExpr      ///< Constant expression in a
> noptr-new-declarator.
> > +    CCEK_NewExpr,     ///< Constant expression in a
> noptr-new-declarator.
> > +    CCEK_ConstexprIf  ///< Condition in a constexpr if statement.
> >    };
> >    ExprResult CheckConvertedConstantExpression(Expr *From, QualType T,
> >                                                llvm::APSInt &Value,
> CCEKind CCE);
> > @@ -3393,8 +3399,12 @@ public:
> >                                   Stmt *SubStmt);
> >
> >    class ConditionResult;
> > -  StmtResult ActOnIfStmt(SourceLocation IfLoc, ConditionResult Cond,
> > -                         Stmt *ThenVal, SourceLocation ElseLoc, Stmt
> *ElseVal);
> > +  StmtResult ActOnIfStmt(SourceLocation IfLoc, bool IsConstexpr,
> > +                         ConditionResult Cond, Stmt *ThenVal,
> > +                         SourceLocation ElseLoc, Stmt *ElseVal);
> > +  StmtResult BuildIfStmt(SourceLocation IfLoc, bool IsConstexpr,
> > +                         ConditionResult Cond, Stmt *ThenVal,
> > +                         SourceLocation ElseLoc, Stmt *ElseVal);
> >    StmtResult ActOnStartOfSwitchStmt(SourceLocation SwitchLoc,
> >                                      ConditionResult Cond);
> >    StmtResult ActOnFinishSwitchStmt(SourceLocation SwitchLoc,
> > @@ -8919,12 +8929,20 @@ public:
> >      Decl *ConditionVar;
> >      FullExprArg Condition;
> >      bool Invalid;
> > +    bool HasKnownValue;
> > +    bool KnownValue;
> >
> >      friend class Sema;
> > -    ConditionResult(Decl *ConditionVar, FullExprArg Condition)
> > -        : ConditionVar(ConditionVar), Condition(Condition),
> Invalid(false) {}
> > +    ConditionResult(Sema &S, Decl *ConditionVar, FullExprArg Condition,
> > +                    bool IsConstexpr)
> > +        : ConditionVar(ConditionVar), Condition(Condition),
> Invalid(false),
> > +          HasKnownValue(IsConstexpr && Condition.get() &&
> > +                        !Condition.get()->isValueDependent()),
> > +          KnownValue(HasKnownValue &&
> > +
>  !!Condition.get()->EvaluateKnownConstInt(S.Context)) {}
> >      explicit ConditionResult(bool Invalid)
> > -        : ConditionVar(nullptr), Condition(nullptr), Invalid(Invalid) {}
> > +        : ConditionVar(nullptr), Condition(nullptr), Invalid(Invalid),
> > +          HasKnownValue(false), KnownValue(false) {}
> >
> >    public:
> >      ConditionResult() : ConditionResult(false) {}
> > @@ -8933,12 +8951,18 @@ public:
> >        return std::make_pair(cast_or_null<VarDecl>(ConditionVar),
> >                              Condition.get());
> >      }
> > +    llvm::Optional<bool> getKnownValue() const {
> > +      if (!HasKnownValue)
> > +        return None;
> > +      return KnownValue;
> > +    }
> >    };
> >    static ConditionResult ConditionError() { return
> ConditionResult(true); }
> >
> >    enum class ConditionKind {
> > -    Boolean, ///< A boolean condition, from 'if', 'while', 'for', or
> 'do'.
> > -    Switch   ///< An integral condition for a 'switch' statement.
> > +    Boolean,     ///< A boolean condition, from 'if', 'while', 'for',
> or 'do'.
> > +    ConstexprIf, ///< A constant boolean condition from 'if constexpr'.
> > +    Switch       ///< An integral condition for a 'switch' statement.
> >    };
> >
> >    ConditionResult ActOnCondition(Scope *S, SourceLocation Loc,
> > @@ -8963,7 +8987,8 @@ public:
> >    /// \param Loc - A location associated with the condition, e.g. the
> >    /// 'if' keyword.
> >    /// \return true iff there were any errors
> > -  ExprResult CheckBooleanCondition(SourceLocation Loc, Expr *E);
> > +  ExprResult CheckBooleanCondition(SourceLocation Loc, Expr *E,
> > +                                   bool IsConstexpr = false);
> >
> >    /// DiagnoseAssignmentAsCondition - Given that an expression is
> >    /// being used as a boolean condition, warn if it's an assignment.
> > @@ -8974,7 +8999,7 @@ public:
> >    void DiagnoseEqualityWithExtraParens(ParenExpr *ParenE);
> >
> >    /// CheckCXXBooleanCondition - Returns true if conversion to bool is
> invalid.
> > -  ExprResult CheckCXXBooleanCondition(Expr *CondExpr);
> > +  ExprResult CheckCXXBooleanCondition(Expr *CondExpr, bool IsConstexpr
> = false);
> >
> >    /// ConvertIntegerToTypeWarnOnOverflow - Convert the specified APInt
> to have
> >    /// the specified width and sign.  If an overflow occurs, detect it
> and emit
> > @@ -9533,15 +9558,18 @@ public:
> >  /// \brief RAII object that enters a new expression evaluation context.
> >  class EnterExpressionEvaluationContext {
> >    Sema &Actions;
> > +  bool Entered = true;
> >
> >  public:
> >    EnterExpressionEvaluationContext(Sema &Actions,
> >                                     Sema::ExpressionEvaluationContext
> NewContext,
> >                                     Decl *LambdaContextDecl = nullptr,
> > -                                   bool IsDecltype = false)
> > -    : Actions(Actions) {
> > -    Actions.PushExpressionEvaluationContext(NewContext,
> LambdaContextDecl,
> > -                                            IsDecltype);
> > +                                   bool IsDecltype = false,
> > +                                   bool ShouldEnter = true)
> > +      : Actions(Actions), Entered(ShouldEnter) {
> > +    if (Entered)
> > +      Actions.PushExpressionEvaluationContext(NewContext,
> LambdaContextDecl,
> > +                                              IsDecltype);
> >    }
> >    EnterExpressionEvaluationContext(Sema &Actions,
> >                                     Sema::ExpressionEvaluationContext
> NewContext,
> > @@ -9554,7 +9582,8 @@ public:
> >    }
> >
> >    ~EnterExpressionEvaluationContext() {
> > -    Actions.PopExpressionEvaluationContext();
> > +    if (Entered)
> > +      Actions.PopExpressionEvaluationContext();
> >    }
> >  };
> >
> >
> > Modified: cfe/trunk/lib/AST/ASTImporter.cpp
> > URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTImporter.cpp?rev=273602&r1=273601&r2=273602&view=diff
> >
> ==============================================================================
> > --- cfe/trunk/lib/AST/ASTImporter.cpp (original)
> > +++ cfe/trunk/lib/AST/ASTImporter.cpp Thu Jun 23 14:16:49 2016
> > @@ -4981,7 +4981,8 @@ Stmt *ASTNodeImporter::VisitIfStmt(IfStm
> >    if (!ToElseStmt && S->getElse())
> >      return nullptr;
> >    return new (Importer.getToContext()) IfStmt(Importer.getToContext(),
> > -                                              ToIfLoc,
> ToConditionVariable,
> > +                                              ToIfLoc, S->isConstexpr(),
> > +                                              ToConditionVariable,
> >                                                ToCondition, ToThenStmt,
> >                                                ToElseLoc, ToElseStmt);
> >  }
> >
> > Modified: cfe/trunk/lib/AST/Stmt.cpp
> > URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Stmt.cpp?rev=273602&r1=273601&r2=273602&view=diff
> >
> ==============================================================================
> > --- cfe/trunk/lib/AST/Stmt.cpp (original)
> > +++ cfe/trunk/lib/AST/Stmt.cpp Thu Jun 23 14:16:49 2016
> > @@ -763,10 +763,11 @@ void MSAsmStmt::initialize(const ASTCont
> >                   });
> >  }
> >
> > -IfStmt::IfStmt(const ASTContext &C, SourceLocation IL, VarDecl *var,
> Expr *cond,
> > -               Stmt *then, SourceLocation EL, Stmt *elsev)
> > -  : Stmt(IfStmtClass), IfLoc(IL), ElseLoc(EL)
> > -{
> > +IfStmt::IfStmt(const ASTContext &C, SourceLocation IL, bool IsConstexpr,
> > +               VarDecl *var, Expr *cond, Stmt *then, SourceLocation EL,
> > +               Stmt *elsev)
> > +    : Stmt(IfStmtClass), IfLoc(IL), ElseLoc(EL) {
> > +  setConstexpr(IsConstexpr);
> >    setConditionVariable(C, var);
> >    SubExprs[COND] = cond;
> >    SubExprs[THEN] = then;
> >
> > Modified: cfe/trunk/lib/Analysis/BodyFarm.cpp
> > URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/BodyFarm.cpp?rev=273602&r1=273601&r2=273602&view=diff
> >
> ==============================================================================
> > --- cfe/trunk/lib/Analysis/BodyFarm.cpp (original)
> > +++ cfe/trunk/lib/Analysis/BodyFarm.cpp Thu Jun 23 14:16:49 2016
> > @@ -239,7 +239,7 @@ static Stmt *create_dispatch_once(ASTCon
> >                                             SourceLocation());
> >
> >    // (5) Create the 'if' statement.
> > -  IfStmt *If = new (C) IfStmt(C, SourceLocation(), nullptr, UO, CS);
> > +  IfStmt *If = new (C) IfStmt(C, SourceLocation(), false, nullptr, UO,
> CS);
> >    return If;
> >  }
> >
> > @@ -343,7 +343,7 @@ static Stmt *create_OSAtomicCompareAndSw
> >
> >    /// Construct the If.
> >    Stmt *If =
> > -    new (C) IfStmt(C, SourceLocation(), nullptr, Comparison, Body,
> > +    new (C) IfStmt(C, SourceLocation(), false, nullptr, Comparison,
> Body,
> >                     SourceLocation(), Else);
> >
> >    return If;
> >
> > Modified: cfe/trunk/lib/CodeGen/CGStmt.cpp
> > URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGStmt.cpp?rev=273602&r1=273601&r2=273602&view=diff
> >
> ==============================================================================
> > --- cfe/trunk/lib/CodeGen/CGStmt.cpp (original)
> > +++ cfe/trunk/lib/CodeGen/CGStmt.cpp Thu Jun 23 14:16:49 2016
> > @@ -563,7 +563,8 @@ void CodeGenFunction::EmitIfStmt(const I
> >    // If the condition constant folds and can be elided, try to avoid
> emitting
> >    // the condition and the dead arm of the if/else.
> >    bool CondConstant;
> > -  if (ConstantFoldsToSimpleInteger(S.getCond(), CondConstant)) {
> > +  if (ConstantFoldsToSimpleInteger(S.getCond(), CondConstant,
> > +                                   S.isConstexpr())) {
> >      // Figure out which block (then or else) is executed.
> >      const Stmt *Executed = S.getThen();
> >      const Stmt *Skipped  = S.getElse();
> > @@ -572,7 +573,7 @@ void CodeGenFunction::EmitIfStmt(const I
> >
> >      // If the skipped block has no labels in it, just emit the executed
> block.
> >      // This avoids emitting dead code and simplifies the CFG
> substantially.
> > -    if (!ContainsLabel(Skipped)) {
> > +    if (S.isConstexpr() || !ContainsLabel(Skipped)) {
> >        if (CondConstant)
> >          incrementProfileCounter(&S);
> >        if (Executed) {
> >
> > Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.cpp
> > URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.cpp?rev=273602&r1=273601&r2=273602&view=diff
> >
> ==============================================================================
> > --- cfe/trunk/lib/CodeGen/CodeGenFunction.cpp (original)
> > +++ cfe/trunk/lib/CodeGen/CodeGenFunction.cpp Thu Jun 23 14:16:49 2016
> > @@ -1107,9 +1107,10 @@ bool CodeGenFunction::containsBreak(cons
> >  /// to a constant, or if it does but contains a label, return false.
> If it
> >  /// constant folds return true and set the boolean result in Result.
> >  bool CodeGenFunction::ConstantFoldsToSimpleInteger(const Expr *Cond,
> > -                                                   bool &ResultBool) {
> > +                                                   bool &ResultBool,
> > +                                                   bool AllowLabels) {
> >    llvm::APSInt ResultInt;
> > -  if (!ConstantFoldsToSimpleInteger(Cond, ResultInt))
> > +  if (!ConstantFoldsToSimpleInteger(Cond, ResultInt, AllowLabels))
> >      return false;
> >
> >    ResultBool = ResultInt.getBoolValue();
> > @@ -1119,15 +1120,16 @@ bool CodeGenFunction::ConstantFoldsToSim
> >  /// ConstantFoldsToSimpleInteger - If the specified expression does not
> fold
> >  /// to a constant, or if it does but contains a label, return false.
> If it
> >  /// constant folds return true and set the folded value.
> > -bool CodeGenFunction::
> > -ConstantFoldsToSimpleInteger(const Expr *Cond, llvm::APSInt &ResultInt)
> {
> > +bool CodeGenFunction::ConstantFoldsToSimpleInteger(const Expr *Cond,
> > +                                                   llvm::APSInt
> &ResultInt,
> > +                                                   bool AllowLabels) {
> >    // FIXME: Rename and handle conversion of other evaluatable things
> >    // to bool.
> >    llvm::APSInt Int;
> >    if (!Cond->EvaluateAsInt(Int, getContext()))
> >      return false;  // Not foldable, not integer or not fully
> evaluatable.
> >
> > -  if (CodeGenFunction::ContainsLabel(Cond))
> > +  if (!AllowLabels && CodeGenFunction::ContainsLabel(Cond))
> >      return false;  // Contains a label.
> >
> >    ResultInt = Int;
> >
> > Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
> > URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=273602&r1=273601&r2=273602&view=diff
> >
> ==============================================================================
> > --- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
> > +++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Thu Jun 23 14:16:49 2016
> > @@ -3051,13 +3051,15 @@ public:
> >    /// ConstantFoldsToSimpleInteger - If the specified expression does
> not fold
> >    /// to a constant, or if it does but contains a label, return false.
> If it
> >    /// constant folds return true and set the boolean result in Result.
> > -  bool ConstantFoldsToSimpleInteger(const Expr *Cond, bool &Result);
> > +  bool ConstantFoldsToSimpleInteger(const Expr *Cond, bool &Result,
> > +                                    bool AllowLabels = false);
> >
> >    /// ConstantFoldsToSimpleInteger - If the specified expression does
> not fold
> >    /// to a constant, or if it does but contains a label, return false.
> If it
> >    /// constant folds return true and set the folded value.
> > -  bool ConstantFoldsToSimpleInteger(const Expr *Cond, llvm::APSInt
> &Result);
> > -
> > +  bool ConstantFoldsToSimpleInteger(const Expr *Cond, llvm::APSInt
> &Result,
> > +                                    bool AllowLabels = false);
> > +
> >    /// EmitBranchOnBoolExpr - Emit a branch on a boolean condition (e.g.
> for an
> >    /// if statement) to the specified blocks.  Based on the condition,
> this might
> >    /// try to simplify the codegen of the conditional based on the
> branch.
> >
> > Modified: cfe/trunk/lib/Parse/ParseStmt.cpp
> > URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseStmt.cpp?rev=273602&r1=273601&r2=273602&view=diff
> >
> ==============================================================================
> > --- cfe/trunk/lib/Parse/ParseStmt.cpp (original)
> > +++ cfe/trunk/lib/Parse/ParseStmt.cpp Thu Jun 23 14:16:49 2016
> > @@ -1108,6 +1108,14 @@ StmtResult Parser::ParseIfStatement(Sour
> >    assert(Tok.is(tok::kw_if) && "Not an if stmt!");
> >    SourceLocation IfLoc = ConsumeToken();  // eat the 'if'.
> >
> > +  bool IsConstexpr = false;
> > +  if (Tok.is(tok::kw_constexpr)) {
> > +    Diag(Tok, getLangOpts().CPlusPlus1z ?
> diag::warn_cxx14_compat_constexpr_if
> > +                                        : diag::ext_constexpr_if);
> > +    IsConstexpr = true;
> > +    ConsumeToken();
> > +  }
> > +
> >    if (Tok.isNot(tok::l_paren)) {
> >      Diag(Tok, diag::err_expected_lparen_after) << "if";
> >      SkipUntil(tok::semi);
> > @@ -1132,9 +1140,15 @@ StmtResult Parser::ParseIfStatement(Sour
> >
> >    // Parse the condition.
> >    Sema::ConditionResult Cond;
> > -  if (ParseParenExprOrCondition(Cond, IfLoc,
> Sema::ConditionKind::Boolean))
> > +  if (ParseParenExprOrCondition(Cond, IfLoc,
> > +                                IsConstexpr ?
> Sema::ConditionKind::ConstexprIf
> > +                                            :
> Sema::ConditionKind::Boolean))
> >      return StmtError();
> >
> > +  llvm::Optional<bool> ConstexprCondition;
> > +  if (IsConstexpr)
> > +    ConstexprCondition = Cond.getKnownValue();
> > +
> >    // C99 6.8.4p3 - In C99, the body of the if statement is a scope,
> even if
> >    // there is no compound stmt.  C90 does not have this clause.  We
> only do this
> >    // if the body isn't a compound statement to avoid push/pop in common
> cases.
> > @@ -1159,7 +1173,13 @@ StmtResult Parser::ParseIfStatement(Sour
> >    SourceLocation ThenStmtLoc = Tok.getLocation();
> >
> >    SourceLocation InnerStatementTrailingElseLoc;
> > -  StmtResult ThenStmt(ParseStatement(&InnerStatementTrailingElseLoc));
> > +  StmtResult ThenStmt;
> > +  {
> > +    EnterExpressionEvaluationContext PotentiallyDiscarded(
> > +        Actions, Sema::DiscardedStatement, nullptr, false,
> > +        /*ShouldEnter=*/ConstexprCondition && !*ConstexprCondition);
> > +    ThenStmt = ParseStatement(&InnerStatementTrailingElseLoc);
> > +  }
> >
> >    // Pop the 'if' scope if needed.
> >    InnerScope.Exit();
> > @@ -1185,8 +1205,12 @@ StmtResult Parser::ParseIfStatement(Sour
> >      // The substatement in a selection-statement (each substatement, in
> the else
> >      // form of the if statement) implicitly defines a local scope.
> >      //
> > -    ParseScope InnerScope(this, Scope::DeclScope, C99orCXX,
> Tok.is(tok::l_brace));
> > +    ParseScope InnerScope(this, Scope::DeclScope, C99orCXX,
> > +                          Tok.is(tok::l_brace));
> >
> > +    EnterExpressionEvaluationContext PotentiallyDiscarded(
> > +        Actions, Sema::DiscardedStatement, nullptr, false,
> > +        /*ShouldEnter=*/ConstexprCondition && *ConstexprCondition);
> >      ElseStmt = ParseStatement();
> >
> >      // Pop the 'else' scope if needed.
> > @@ -1217,7 +1241,7 @@ StmtResult Parser::ParseIfStatement(Sour
> >    if (ElseStmt.isInvalid())
> >      ElseStmt = Actions.ActOnNullStmt(ElseStmtLoc);
> >
> > -  return Actions.ActOnIfStmt(IfLoc, Cond, ThenStmt.get(), ElseLoc,
> > +  return Actions.ActOnIfStmt(IfLoc, IsConstexpr, Cond, ThenStmt.get(),
> ElseLoc,
> >                               ElseStmt.get());
> >  }
> >
> >
> > Modified: cfe/trunk/lib/Sema/JumpDiagnostics.cpp
> > URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/JumpDiagnostics.cpp?rev=273602&r1=273601&r2=273602&view=diff
> >
> ==============================================================================
> > --- cfe/trunk/lib/Sema/JumpDiagnostics.cpp (original)
> > +++ cfe/trunk/lib/Sema/JumpDiagnostics.cpp Thu Jun 23 14:16:49 2016
> > @@ -319,6 +319,37 @@ void JumpScopeChecker::BuildScopeInforma
> >      Jumps.push_back(S);
> >      break;
> >
> > +  case Stmt::IfStmtClass: {
> > +    IfStmt *IS = cast<IfStmt>(S);
> > +    if (!IS->isConstexpr())
> > +      break;
> > +
> > +    if (VarDecl *Var = IS->getConditionVariable())
> > +      BuildScopeInformation(Var, ParentScope);
> > +
> > +    // Cannot jump into the middle of the condition.
> > +    unsigned NewParentScope = Scopes.size();
> > +    Scopes.push_back(GotoScope(ParentScope,
> > +                               diag::note_protected_by_constexpr_if, 0,
> > +                               IS->getLocStart()));
> > +    BuildScopeInformation(IS->getCond(), NewParentScope);
> > +
> > +    // Jumps into either arm of an 'if constexpr' are not allowed.
> > +    NewParentScope = Scopes.size();
> > +    Scopes.push_back(GotoScope(ParentScope,
> > +                               diag::note_protected_by_constexpr_if, 0,
> > +                               IS->getLocStart()));
> > +    BuildScopeInformation(IS->getThen(), NewParentScope);
> > +    if (Stmt *Else = IS->getElse()) {
> > +      NewParentScope = Scopes.size();
> > +      Scopes.push_back(GotoScope(ParentScope,
> > +                                 diag::note_protected_by_constexpr_if,
> 0,
> > +                                 IS->getLocStart()));
> > +      BuildScopeInformation(Else, NewParentScope);
> > +    }
> > +    return;
> > +  }
> > +
> >    case Stmt::CXXTryStmtClass: {
> >      CXXTryStmt *TS = cast<CXXTryStmt>(S);
> >      {
> >
> > Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
> > URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=273602&r1=273601&r2=273602&view=diff
> >
> ==============================================================================
> > --- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
> > +++ cfe/trunk/lib/Sema/SemaExpr.cpp Thu Jun 23 14:16:49 2016
> > @@ -12903,6 +12903,11 @@ static bool IsPotentiallyEvaluatedContex
> >        // definition of a null pointer constant is completely crazy.)
> >        return false;
> >
> > +    case Sema::DiscardedStatement:
> > +      // These are technically a potentially evaluated but they have
> the effect
> > +      // of suppressing use marking.
> > +      return false;
> > +
> >      case Sema::ConstantEvaluated:
> >      case Sema::PotentiallyEvaluated:
> >        // We are in a potentially evaluated expression (or a
> constant-expression
> > @@ -14192,6 +14197,7 @@ bool Sema::DiagRuntimeBehavior(SourceLoc
> >    switch (ExprEvalContexts.back().Context) {
> >    case Unevaluated:
> >    case UnevaluatedAbstract:
> > +  case DiscardedStatement:
> >      // The argument will never be evaluated, so don't complain.
> >      break;
> >
> > @@ -14341,7 +14347,8 @@ void Sema::DiagnoseEqualityWithExtraPare
> >      }
> >  }
> >
> > -ExprResult Sema::CheckBooleanCondition(SourceLocation Loc, Expr *E) {
> > +ExprResult Sema::CheckBooleanCondition(SourceLocation Loc, Expr *E,
> > +                                       bool IsConstexpr) {
> >    DiagnoseAssignmentAsCondition(E);
> >    if (ParenExpr *parenE = dyn_cast<ParenExpr>(E))
> >      DiagnoseEqualityWithExtraParens(parenE);
> > @@ -14352,7 +14359,7 @@ ExprResult Sema::CheckBooleanCondition(S
> >
> >    if (!E->isTypeDependent()) {
> >      if (getLangOpts().CPlusPlus)
> > -      return CheckCXXBooleanCondition(E); // C++ 6.4p4
> > +      return CheckCXXBooleanCondition(E, IsConstexpr); // C++ 6.4p4
> >
> >      ExprResult ERes = DefaultFunctionArrayLvalueConversion(E);
> >      if (ERes.isInvalid())
> > @@ -14383,6 +14390,10 @@ Sema::ConditionResult Sema::ActOnConditi
> >      Cond = CheckBooleanCondition(Loc, SubExpr);
> >      break;
> >
> > +  case ConditionKind::ConstexprIf:
> > +    Cond = CheckBooleanCondition(Loc, SubExpr, true);
> > +    break;
> > +
> >    case ConditionKind::Switch:
> >      Cond = CheckSwitchCondition(Loc, SubExpr);
> >      break;
> > @@ -14390,7 +14401,8 @@ Sema::ConditionResult Sema::ActOnConditi
> >    if (Cond.isInvalid())
> >      return ConditionError();
> >
> > -  return ConditionResult(nullptr, MakeFullExpr(Cond.get(), Loc));
> > +  return ConditionResult(*this, nullptr, MakeFullExpr(Cond.get(), Loc),
> > +                         CK == ConditionKind::ConstexprIf);
> >  }
> >
> >  namespace {
> >
> > Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
> > URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=273602&r1=273601&r2=273602&view=diff
> >
> ==============================================================================
> > --- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
> > +++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Thu Jun 23 14:16:49 2016
> > @@ -3061,7 +3061,8 @@ Sema::ConditionResult Sema::ActOnConditi
> >        CheckConditionVariable(cast<VarDecl>(ConditionVar), StmtLoc, CK);
> >    if (E.isInvalid())
> >      return ConditionError();
> > -  return ConditionResult(ConditionVar, MakeFullExpr(E.get(), StmtLoc));
> > +  return ConditionResult(*this, ConditionVar, MakeFullExpr(E.get(),
> StmtLoc),
> > +                         CK == ConditionKind::ConstexprIf);
> >  }
> >
> >  /// \brief Check the use of the given variable as a C++ condition in an
> if,
> > @@ -3096,6 +3097,9 @@ ExprResult Sema::CheckConditionVariable(
> >    case ConditionKind::Boolean:
> >      return CheckBooleanCondition(StmtLoc, Condition.get());
> >
> > +  case ConditionKind::ConstexprIf:
> > +    return CheckBooleanCondition(StmtLoc, Condition.get(), true);
> > +
> >    case ConditionKind::Switch:
> >      return CheckSwitchCondition(StmtLoc, Condition.get());
> >    }
> > @@ -3104,7 +3108,7 @@ ExprResult Sema::CheckConditionVariable(
> >  }
> >
> >  /// CheckCXXBooleanCondition - Returns true if a conversion to bool is
> invalid.
> > -ExprResult Sema::CheckCXXBooleanCondition(Expr *CondExpr) {
> > +ExprResult Sema::CheckCXXBooleanCondition(Expr *CondExpr, bool
> IsConstexpr) {
> >    // C++ 6.4p4:
> >    // The value of a condition that is an initialized declaration in a
> statement
> >    // other than a switch statement is the value of the declared variable
> > @@ -3113,7 +3117,12 @@ ExprResult Sema::CheckCXXBooleanConditio
> >    // The value of a condition that is an expression is the value of the
> >    // expression, implicitly converted to bool.
> >    //
> > -  return PerformContextuallyConvertToBool(CondExpr);
> > +  // FIXME: Return this value to the caller so they don't need to
> recompute it.
> > +  llvm::APSInt Value(/*BitWidth*/1);
> > +  return (IsConstexpr && !CondExpr->isValueDependent())
> > +             ? CheckConvertedConstantExpression(CondExpr,
> Context.BoolTy, Value,
> > +                                                CCEK_ConstexprIf)
> > +             : PerformContextuallyConvertToBool(CondExpr);
> >  }
> >
> >  /// Helper function to determine whether this is the (deprecated) C++
> >
> > Modified: cfe/trunk/lib/Sema/SemaExprMember.cpp
> > URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprMember.cpp?rev=273602&r1=273601&r2=273602&view=diff
> >
> ==============================================================================
> > --- cfe/trunk/lib/Sema/SemaExprMember.cpp (original)
> > +++ cfe/trunk/lib/Sema/SemaExprMember.cpp Thu Jun 23 14:16:49 2016
> > @@ -142,6 +142,7 @@ static IMAKind ClassifyImplicitMemberAcc
> >      AbstractInstanceResult = IMA_Abstract;
> >      break;
> >
> > +  case Sema::DiscardedStatement:
> >    case Sema::ConstantEvaluated:
> >    case Sema::PotentiallyEvaluated:
> >    case Sema::PotentiallyEvaluatedIfUsed:
> >
> > Modified: cfe/trunk/lib/Sema/SemaLambda.cpp
> > URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLambda.cpp?rev=273602&r1=273601&r2=273602&view=diff
> >
> ==============================================================================
> > --- cfe/trunk/lib/Sema/SemaLambda.cpp (original)
> > +++ cfe/trunk/lib/Sema/SemaLambda.cpp Thu Jun 23 14:16:49 2016
> > @@ -1635,6 +1635,7 @@ ExprResult Sema::BuildLambdaExpr(SourceL
> >        ExprEvalContexts.back().Lambdas.push_back(Lambda);
> >        break;
> >
> > +    case DiscardedStatement:
> >      case PotentiallyEvaluated:
> >      case PotentiallyEvaluatedIfUsed:
> >        break;
> >
> > Modified: cfe/trunk/lib/Sema/SemaStmt.cpp
> > URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaStmt.cpp?rev=273602&r1=273601&r2=273602&view=diff
> >
> ==============================================================================
> > --- cfe/trunk/lib/Sema/SemaStmt.cpp (original)
> > +++ cfe/trunk/lib/Sema/SemaStmt.cpp Thu Jun 23 14:16:49 2016
> > @@ -504,31 +504,43 @@ public:
> >  }
> >
> >  StmtResult
> > -Sema::ActOnIfStmt(SourceLocation IfLoc, ConditionResult Cond,
> > +Sema::ActOnIfStmt(SourceLocation IfLoc, bool IsConstexpr,
> ConditionResult Cond,
> >                    Stmt *thenStmt, SourceLocation ElseLoc,
> >                    Stmt *elseStmt) {
> > -  auto CondVal = Cond.get();
> > -  if (Cond.isInvalid()) {
> > -    CondVal.first = nullptr;
> > -    CondVal.second = new (Context)
> > -        OpaqueValueExpr(SourceLocation(), Context.BoolTy, VK_RValue);
> > -  }
> > +  if (Cond.isInvalid())
> > +    Cond = ConditionResult(
> > +        *this, nullptr,
> > +        MakeFullExpr(new (Context) OpaqueValueExpr(SourceLocation(),
> > +                                                   Context.BoolTy,
> VK_RValue),
> > +                     IfLoc),
> > +        false);
> >
> > +  Expr *CondExpr = Cond.get().second;
> >    if (!Diags.isIgnored(diag::warn_comma_operator,
> > -                       CondVal.second->getExprLoc()))
> > -    CommaVisitor(*this).Visit(CondVal.second);
> > -
> > -  DiagnoseUnusedExprResult(thenStmt);
> > +                       CondExpr->getExprLoc()))
> > +    CommaVisitor(*this).Visit(CondExpr);
> >
> > -  if (!elseStmt) {
> > -    DiagnoseEmptyStmtBody(CondVal.second->getLocEnd(), thenStmt,
> > +  if (!elseStmt)
> > +    DiagnoseEmptyStmtBody(CondExpr->getLocEnd(), thenStmt,
> >                            diag::warn_empty_if_body);
> > -  }
> >
> > +  return BuildIfStmt(IfLoc, IsConstexpr, Cond, thenStmt, ElseLoc,
> elseStmt);
> > +}
> > +
> > +StmtResult Sema::BuildIfStmt(SourceLocation IfLoc, bool IsConstexpr,
> > +                             ConditionResult Cond, Stmt *thenStmt,
> > +                             SourceLocation ElseLoc, Stmt *elseStmt) {
> > +  if (Cond.isInvalid())
> > +    return StmtError();
> > +
> > +  if (IsConstexpr)
> > +    getCurFunction()->setHasBranchProtectedScope();
> > +
> > +  DiagnoseUnusedExprResult(thenStmt);
> >    DiagnoseUnusedExprResult(elseStmt);
> >
> > -  return new (Context) IfStmt(Context, IfLoc, CondVal.first,
> CondVal.second,
> > -                              thenStmt, ElseLoc, elseStmt);
> > +  return new (Context) IfStmt(Context, IfLoc, IsConstexpr,
> Cond.get().first,
> > +                              Cond.get().second, thenStmt, ElseLoc,
> elseStmt);
> >  }
> >
> >  namespace {
> > @@ -2836,8 +2848,21 @@ Sema::ActOnCapScopeReturnStmt(SourceLoca
> >    CapturingScopeInfo *CurCap =
> cast<CapturingScopeInfo>(getCurFunction());
> >    QualType FnRetType = CurCap->ReturnType;
> >    LambdaScopeInfo *CurLambda = dyn_cast<LambdaScopeInfo>(CurCap);
> > +  bool HasDeducedReturnType =
> > +      CurLambda && hasDeducedReturnType(CurLambda->CallOperator);
> > +
> > +  if (ExprEvalContexts.back().Context == DiscardedStatement &&
> > +      (HasDeducedReturnType || CurCap->HasImplicitReturnType)) {
> > +    if (RetValExp) {
> > +      ExprResult ER = ActOnFinishFullExpr(RetValExp, ReturnLoc);
> > +      if (ER.isInvalid())
> > +        return StmtError();
> > +      RetValExp = ER.get();
> > +    }
> > +    return new (Context) ReturnStmt(ReturnLoc, RetValExp, nullptr);
> > +  }
> >
> > -  if (CurLambda && hasDeducedReturnType(CurLambda->CallOperator)) {
> > +  if (HasDeducedReturnType) {
> >      // In C++1y, the return type may involve 'auto'.
> >      // FIXME: Blocks might have a return type of 'auto' explicitly
> specified.
> >      FunctionDecl *FD = CurLambda->CallOperator;
> > @@ -3118,9 +3143,8 @@ StmtResult
> >  Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp,
> >                        Scope *CurScope) {
> >    StmtResult R = BuildReturnStmt(ReturnLoc, RetValExp);
> > -  if (R.isInvalid()) {
> > +  if (R.isInvalid() || ExprEvalContexts.back().Context ==
> DiscardedStatement)
> >      return R;
> > -  }
> >
> >    if (VarDecl *VD =
> >
> const_cast<VarDecl*>(cast<ReturnStmt>(R.get())->getNRVOCandidate())) {
> > @@ -3169,6 +3193,19 @@ StmtResult Sema::BuildReturnStmt(SourceL
> >    } else // If we don't have a function/method context, bail.
> >      return StmtError();
> >
> > +  // C++1z: discarded return statements are not considered when
> deducing a
> > +  // return type.
> > +  if (ExprEvalContexts.back().Context == DiscardedStatement &&
> > +      FnRetType->getContainedAutoType()) {
> > +    if (RetValExp) {
> > +      ExprResult ER = ActOnFinishFullExpr(RetValExp, ReturnLoc);
> > +      if (ER.isInvalid())
> > +        return StmtError();
> > +      RetValExp = ER.get();
> > +    }
> > +    return new (Context) ReturnStmt(ReturnLoc, RetValExp, nullptr);
> > +  }
> > +
> >    // FIXME: Add a flag to the ScopeInfo to indicate whether we're
> performing
> >    // deduction.
> >    if (getLangOpts().CPlusPlus14) {
> >
> > Modified: cfe/trunk/lib/Sema/TreeTransform.h
> > URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=273602&r1=273601&r2=273602&view=diff
> >
> ==============================================================================
> > --- cfe/trunk/lib/Sema/TreeTransform.h (original)
> > +++ cfe/trunk/lib/Sema/TreeTransform.h Thu Jun 23 14:16:49 2016
> > @@ -1174,9 +1174,10 @@ public:
> >    ///
> >    /// By default, performs semantic analysis to build the new statement.
> >    /// Subclasses may override this routine to provide different
> behavior.
> > -  StmtResult RebuildIfStmt(SourceLocation IfLoc, Sema::ConditionResult
> Cond,
> > -                           Stmt *Then, SourceLocation ElseLoc, Stmt
> *Else) {
> > -    return getSema().ActOnIfStmt(IfLoc, Cond, Then, ElseLoc, Else);
> > +  StmtResult RebuildIfStmt(SourceLocation IfLoc, bool IsConstexpr,
> > +                           Sema::ConditionResult Cond, Stmt *Then,
> > +                           SourceLocation ElseLoc, Stmt *Else) {
> > +    return getSema().ActOnIfStmt(IfLoc, IsConstexpr, Cond, Then,
> ElseLoc, Else);
> >    }
> >
> >    /// \brief Start building a new switch statement.
> > @@ -6228,19 +6229,33 @@ TreeTransform<Derived>::TransformIfStmt(
> >    // Transform the condition
> >    Sema::ConditionResult Cond = getDerived().TransformCondition(
> >        S->getIfLoc(), S->getConditionVariable(), S->getCond(),
> > -      Sema::ConditionKind::Boolean);
> > +      S->isConstexpr() ? Sema::ConditionKind::ConstexprIf
> > +                       : Sema::ConditionKind::Boolean);
> >    if (Cond.isInvalid())
> >      return StmtError();
> >
> > +  // If this is a constexpr if, determine which arm we should
> instantiate.
> > +  llvm::Optional<bool> ConstexprConditionValue;
> > +  if (S->isConstexpr())
> > +    ConstexprConditionValue = Cond.getKnownValue();
> > +
> >    // Transform the "then" branch.
> > -  StmtResult Then = getDerived().TransformStmt(S->getThen());
> > -  if (Then.isInvalid())
> > -    return StmtError();
> > +  StmtResult Then;
> > +  if (!ConstexprConditionValue || *ConstexprConditionValue) {
> > +    Then = getDerived().TransformStmt(S->getThen());
> > +    if (Then.isInvalid())
> > +      return StmtError();
> > +  } else {
> > +    Then = new (getSema().Context)
> NullStmt(S->getThen()->getLocStart());
> > +  }
> >
> >    // Transform the "else" branch.
> > -  StmtResult Else = getDerived().TransformStmt(S->getElse());
> > -  if (Else.isInvalid())
> > -    return StmtError();
> > +  StmtResult Else;
> > +  if (!ConstexprConditionValue || !*ConstexprConditionValue) {
> > +    Else = getDerived().TransformStmt(S->getElse());
> > +    if (Else.isInvalid())
> > +      return StmtError();
> > +  }
> >
> >    if (!getDerived().AlwaysRebuild() &&
> >        Cond.get() == std::make_pair(S->getConditionVariable(),
> S->getCond()) &&
> > @@ -6248,8 +6263,8 @@ TreeTransform<Derived>::TransformIfStmt(
> >        Else.get() == S->getElse())
> >      return S;
> >
> > -  return getDerived().RebuildIfStmt(S->getIfLoc(), Cond, Then.get(),
> > -                                    S->getElseLoc(), Else.get());
> > +  return getDerived().RebuildIfStmt(S->getIfLoc(), S->isConstexpr(),
> Cond,
> > +                                    Then.get(), S->getElseLoc(),
> Else.get());
> >  }
> >
> >  template<typename Derived>
> >
> > Modified: cfe/trunk/lib/Serialization/ASTReaderStmt.cpp
> > URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderStmt.cpp?rev=273602&r1=273601&r2=273602&view=diff
> >
> ==============================================================================
> > --- cfe/trunk/lib/Serialization/ASTReaderStmt.cpp (original)
> > +++ cfe/trunk/lib/Serialization/ASTReaderStmt.cpp Thu Jun 23 14:16:49
> 2016
> > @@ -184,6 +184,7 @@ void ASTStmtReader::VisitAttributedStmt(
> >
> >  void ASTStmtReader::VisitIfStmt(IfStmt *S) {
> >    VisitStmt(S);
> > +  S->setConstexpr(Record[Idx++]);
> >    S->setConditionVariable(Reader.getContext(),
> >                            ReadDeclAs<VarDecl>(Record, Idx));
> >    S->setCond(Reader.ReadSubExpr());
> >
> > Modified: cfe/trunk/lib/Serialization/ASTWriterStmt.cpp
> > URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterStmt.cpp?rev=273602&r1=273601&r2=273602&view=diff
> >
> ==============================================================================
> > --- cfe/trunk/lib/Serialization/ASTWriterStmt.cpp (original)
> > +++ cfe/trunk/lib/Serialization/ASTWriterStmt.cpp Thu Jun 23 14:16:49
> 2016
> > @@ -128,6 +128,7 @@ void ASTStmtWriter::VisitAttributedStmt(
> >
> >  void ASTStmtWriter::VisitIfStmt(IfStmt *S) {
> >    VisitStmt(S);
> > +  Record.push_back(S->isConstexpr());
> >    Record.AddDeclRef(S->getConditionVariable());
> >    Record.AddStmt(S->getCond());
> >    Record.AddStmt(S->getThen());
> >
> > Added:
> cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p2-1z.cpp
> > URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p2-1z.cpp?rev=273602&view=auto
> >
> ==============================================================================
> > --- cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p2-1z.cpp
> (added)
> > +++ cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p2-1z.cpp
> Thu Jun 23 14:16:49 2016
> > @@ -0,0 +1,47 @@
> > +// RUN: %clang_cc1 -std=c++1z -verify %s
> > +
> > +template<typename T, typename U> constexpr bool same = false;
> > +template<typename T> constexpr bool same<T, T> = true;
> > +
> > +auto a() {
> > +  if constexpr (false)
> > +    return 0;
> > +}
> > +static_assert(same<decltype(a()), void>);
> > +
> > +auto b() {
> > +  if constexpr (false)
> > +    return 0;
> > +  else
> > +    return 0.0;
> > +}
> > +static_assert(same<decltype(b()), double>);
> > +
> > +auto c() {
> > +  if constexpr (true)
> > +    return "foo";
> > +  else
> > +    return 'x';
> > +  if constexpr (false)
> > +    return 7.6;
> > +  else
> > +    return 5; // expected-error {{deduced as 'int' here but deduced as
> 'const char *' in earlier}}
> > +}
> > +
> > +template<int k> auto d() {
> > +  if constexpr(k == 0)
> > +    return 0;
> > +  if constexpr(k == 1)
> > +    return "foo";
> > +  else if constexpr (k == 2)
> > +    return 1.0;
> > +}
> > +static_assert(same<decltype(d<0>()), int>);
> > +static_assert(same<decltype(d<1>()), const char *>);
> > +static_assert(same<decltype(d<2>()), double>);
> > +static_assert(same<decltype(d<3>()), void>);
> > +
> > +auto e = []{ if constexpr (false) return 0; }(); // expected-error
> {{variable has incomplete type 'void'}}
> > +
> > +auto f = []{ if constexpr (true) return 0; }();
> > +static_assert(same<decltype(e), int>);
> >
> > Added: cfe/trunk/test/CXX/stmt.stmt/stmt.select/stmt.if/p2.cpp
> > URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/stmt.stmt/stmt.select/stmt.if/p2.cpp?rev=273602&view=auto
> >
> ==============================================================================
> > --- cfe/trunk/test/CXX/stmt.stmt/stmt.select/stmt.if/p2.cpp (added)
> > +++ cfe/trunk/test/CXX/stmt.stmt/stmt.select/stmt.if/p2.cpp Thu Jun 23
> 14:16:49 2016
> > @@ -0,0 +1,137 @@
> > +// RUN: %clang_cc1 -std=c++1z -verify %s
> > +// RUN: %clang_cc1 -std=c++1z -verify %s -DUNDEFINED
> > +
> > +#ifdef UNDEFINED
> > +// "used but not defined" errors don't get produced if we have more
> interesting
> > +// errors.
> > +namespace std_example {
> > +  template <typename T, typename... Rest> void g(T &&p, Rest &&... rs) {
> > +    // use p
> > +    if constexpr(sizeof...(rs) > 0)
> > +      g(rs...);
> > +  }
> > +  void use_g() {
> > +    g(1, 2, 3);
> > +  }
> > +
> > +  static int x(); // no definition of x required
> > +  int f() {
> > +    if constexpr (true)
> > +      return 0;
> > +    else if (x())
> > +      return x();
> > +    else
> > +      return -x();
> > +  }
> > +}
> > +
> > +namespace odr_use_in_selected_arm {
> > +  static int x(); // expected-warning {{is not defined}}
> > +  int f() {
> > +    if constexpr (false)
> > +      return 0;
> > +    else if (x()) // expected-note {{here}}
> > +      return x();
> > +    else
> > +      return -x();
> > +  }
> > +}
> > +#else
> > +namespace ccce {
> > +  void f() {
> > +    if (5) {}
> > +    if constexpr (5) {} // expected-error {{cannot be narrowed}}
> > +  }
> > +  template<int N> void g() {
> > +    if constexpr (N) {} // expected-error {{cannot be narrowed}}
> > +  }
> > +  template void g<5>(); // expected-note {{instantiation of}}
> > +}
> > +
> > +namespace generic_lambda {
> > +  // Substituting for T produces a hard error here, even if
> substituting for
> > +  // the type of x would remove the error.
> > +  template<typename T> void f() {
> > +    [](auto x) {
> > +      if constexpr (sizeof(T) == 1 && sizeof(x) == 1)
> > +        T::error(); // expected-error 2{{'::'}}
> > +    } (0);
> > +  }
> > +
> > +  template<typename T> void g() {
> > +    [](auto x) {
> > +      if constexpr (sizeof(T) == 1)
> > +        if constexpr (sizeof(x) == 1)
> > +          T::error(); // expected-error {{'::'}}
> > +    } (0);
> > +  }
> > +
> > +  void use() {
> > +    f<int>(); // expected-note {{instantiation of}}
> > +    f<char>(); // expected-note {{instantiation of}}
> > +    g<int>(); // ok
> > +    g<char>(); // expected-note {{instantiation of}}
> > +  }
> > +}
> > +
> > +namespace potentially_discarded_branch_target {
> > +  void in_switch(int n) {
> > +    switch (n)
> > +      case 4: if constexpr(sizeof(n) == 4) return;
> > +    if constexpr(sizeof(n) == 4)
> > +      switch (n) case 4: return;
> > +    switch (n) {
> > +      if constexpr (sizeof(n) == 4) // expected-note 2{{constexpr if}}
> > +        case 4: return; // expected-error {{cannot jump}}
> > +      else
> > +        default: break; // expected-error {{cannot jump}}
> > +    }
> > +  }
> > +
> > +  template<typename T>
> > +  void in_switch_tmpl(int n) {
> > +    switch (n) {
> > +      if constexpr (sizeof(T) == 4) // expected-note 2{{constexpr if}}
> > +        case 4: return; // expected-error {{cannot jump}}
> > +      else
> > +        default: break; // expected-error {{cannot jump}}
> > +    }
> > +  }
> > +
> > +  void goto_scope(int n) {
> > +    goto foo; // expected-error {{cannot jump}}
> > +    if constexpr(sizeof(n) == 4) // expected-note {{constexpr if}}
> > +      foo: return;
> > +bar:
> > +    if constexpr(sizeof(n) == 4)
> > +      goto bar; // ok
> > +  }
> > +
> > +  template<typename T>
> > +  void goto_scope(int n) {
> > +    goto foo; // expected-error {{cannot jump}}
> > +    if constexpr(sizeof(n) == 4) // expected-note {{constexpr if}}
> > +      foo: return;
> > +bar:
> > +    if constexpr(sizeof(n) == 4)
> > +      goto bar; // ok
> > +  }
> > +
> > +  void goto_redef(int n) {
> > +a:  if constexpr(sizeof(n) == 4) // expected-error {{redefinition}}
> expected-note {{constexpr if}}
> > +      a: goto a; // expected-note 2{{previous}}
> > +    else
> > +      a: goto a; // expected-error {{redefinition}} expected-error
> {{cannot jump}}
> > +  }
> > +
> > +  void evil_things() {
> > +    goto evil_label; // expected-error {{cannot jump}}
> > +    if constexpr (true || ({evil_label: false;})) {} // expected-note
> {{constexpr if}}
> > +
> > +    if constexpr (true) // expected-note {{constexpr if}}
> > +      goto surprise; // expected-error {{cannot jump}}
> > +    else
> > +      surprise: {}
> > +  }
> > +}
> > +#endif
> >
> > Added: cfe/trunk/test/CodeGenCXX/cxx1z-constexpr-if.cpp
> > URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/cxx1z-constexpr-if.cpp?rev=273602&view=auto
> >
> ==============================================================================
> > --- cfe/trunk/test/CodeGenCXX/cxx1z-constexpr-if.cpp (added)
> > +++ cfe/trunk/test/CodeGenCXX/cxx1z-constexpr-if.cpp Thu Jun 23 14:16:49
> 2016
> > @@ -0,0 +1,21 @@
> > +// RUN: %clang_cc1 -std=c++1z %s -emit-llvm -o - | FileCheck %s
> --implicit-check-not=should_not_be_used
> > +
> > +void should_be_used_1();
> > +void should_be_used_2();
> > +void should_not_be_used();
> > +void f() {
> > +  if constexpr (false)
> > +    should_not_be_used();
> > +  else
> > +    should_be_used_1();
> > +
> > +  if constexpr (true || ({ label: false; }))
> > +    should_be_used_2();
> > +  else {
> > +    goto foo;
> > +foo: should_not_be_used();
> > +  }
> > +}
> > +
> > +// CHECK: should_be_used_1
> > +// CHECK: should_be_used_2
> >
> > Modified: cfe/trunk/www/cxx_status.html
> > URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_status.html?rev=273602&r1=273601&r2=273602&view=diff
> >
> ==============================================================================
> > --- cfe/trunk/www/cxx_status.html (original)
> > +++ cfe/trunk/www/cxx_status.html Thu Jun 23 14:16:49 2016
> > @@ -671,6 +671,12 @@ as the draft C++1z standard evolves.</p>
> >        <td><a href="http://wg21.link/p0245r1">P0245R1</a></td>
> >        <td class="full" align="center">Yes</td>
> >      </tr>
> > +    <!-- Oulu papers -->
> > +    <tr>
> > +      <td><tt>constexpr</tt> <em>if-statement</em>s</td>
> > +      <td><a href="http://wg21.link/p0292r2">P0292R2</a></td>
> > +      <td class="svn" align="center">SVN</td>
> > +    </tr>
> >  </table>
> >
> >  <p>
> >
> >
> > _______________________________________________
> > cfe-commits mailing list
> > cfe-commits at lists.llvm.org
> > http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20160623/079c009c/attachment-0001.html>


More information about the cfe-commits mailing list