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