On Thu, Jun 23, 2016 at 3:16 PM, Richard Smith via cfe-commits <cfe-commits@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)? ~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@lists.llvm.org > http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits