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