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