Index: clang/lib/AST/ExprConstant.cpp =================================================================== --- clang/lib/AST/ExprConstant.cpp +++ clang/lib/AST/ExprConstant.cpp @@ -744,12 +744,11 @@ /// can't be modeled. EM_IgnoreSideEffects, - /// Evaluate as a constant expression. Stop if we find that the expression - /// is not a constant expression. Some expressions can be retried in the + /// Evaluate as a constant fold. Some expressions can be retried in the /// optimizer if we don't constant fold them here, but in an unevaluated - /// context we try to fold them immediately since the optimizer never - /// gets a chance to look at it. - EM_ConstantExpressionUnevaluated, + /// context we try to fold them immediately since the optimizer never gets + /// a chance to look at it. + EM_ConstantFoldUnevaluated, /// Evaluate as a potential constant expression. Keep going if we hit a /// construct that we can't evaluate yet (because we don't yet know the @@ -854,13 +853,13 @@ case EM_ConstantFold: case EM_IgnoreSideEffects: case EM_EvaluateForOverflow: + case EM_ConstantFoldUnevaluated: if (!HasFoldFailureDiagnostic) break; // We've already failed to fold something. Keep that diagnostic. LLVM_FALLTHROUGH; case EM_ConstantExpression: case EM_PotentialConstantExpression: - case EM_ConstantExpressionUnevaluated: case EM_PotentialConstantExpressionUnevaluated: HasActiveDiagnostic = false; return OptionalDiagnostic(); @@ -951,7 +950,7 @@ return true; case EM_ConstantExpression: - case EM_ConstantExpressionUnevaluated: + case EM_ConstantFoldUnevaluated: case EM_ConstantFold: return false; } @@ -971,12 +970,12 @@ case EM_EvaluateForOverflow: case EM_IgnoreSideEffects: case EM_ConstantFold: + case EM_ConstantFoldUnevaluated: return true; case EM_PotentialConstantExpression: case EM_PotentialConstantExpressionUnevaluated: case EM_ConstantExpression: - case EM_ConstantExpressionUnevaluated: return false; } llvm_unreachable("Missed EvalMode case"); @@ -1003,7 +1002,7 @@ return true; case EM_ConstantExpression: - case EM_ConstantExpressionUnevaluated: + case EM_ConstantFoldUnevaluated: case EM_ConstantFold: case EM_IgnoreSideEffects: return false; @@ -1063,9 +1062,7 @@ Info.EvalStatus.Diag->empty() && !Info.EvalStatus.HasSideEffects), OldMode(Info.EvalMode) { - if (Enabled && - (Info.EvalMode == EvalInfo::EM_ConstantExpression || - Info.EvalMode == EvalInfo::EM_ConstantExpressionUnevaluated)) + if (Enabled && Info.EvalMode == EvalInfo::EM_ConstantExpression) Info.EvalMode = EvalInfo::EM_ConstantFold; } void keepDiagnostics() { Enabled = false; } @@ -8103,7 +8100,7 @@ case EvalInfo::EM_IgnoreSideEffects: // Leave it to IR generation. return Error(E); - case EvalInfo::EM_ConstantExpressionUnevaluated: + case EvalInfo::EM_ConstantFoldUnevaluated: case EvalInfo::EM_PotentialConstantExpressionUnevaluated: // Reduce it to a constant now. return Success((Type & 2) ? 0 : -1, E); @@ -11388,7 +11385,7 @@ ArrayRef Args, const Expr *This) const { Expr::EvalStatus Status; - EvalInfo Info(Ctx, Status, EvalInfo::EM_ConstantExpressionUnevaluated); + EvalInfo Info(Ctx, Status, EvalInfo::EM_ConstantFoldUnevaluated); LValue ThisVal; const LValue *ThisPtr = nullptr; @@ -11400,7 +11397,7 @@ #endif if (EvaluateObjectArgument(Info, This, ThisVal)) ThisPtr = &ThisVal; - if (Info.EvalStatus.HasSideEffects) + if (Info.EvalStatus.HasSideEffects || Info.EvalStatus.HasUndefinedBehavior) return false; } @@ -11411,14 +11408,14 @@ !Evaluate(ArgValues[I - Args.begin()], Info, *I)) // If evaluation fails, throw away the argument entirely. ArgValues[I - Args.begin()] = APValue(); - if (Info.EvalStatus.HasSideEffects) + if (Info.EvalStatus.HasSideEffects || Info.EvalStatus.HasUndefinedBehavior) return false; } // Build fake call to Callee. CallStackFrame Frame(Info, Callee->getLocation(), Callee, ThisPtr, ArgValues.data()); - return Evaluate(Value, Info, this) && !Info.EvalStatus.HasSideEffects; + return Evaluate(Value, Info, this) && !Info.EvalStatus.HasSideEffects && !Info.EvalStatus.HasUndefinedBehavior; } bool Expr::isPotentialConstantExpr(const FunctionDecl *FD, Index: clang/test/Sema/enable_if.c =================================================================== --- clang/test/Sema/enable_if.c +++ clang/test/Sema/enable_if.c @@ -170,4 +170,24 @@ variadic_enable_if(0, m); // expected-error{{no matching}} variadic_enable_if(0, m, 3); // expected-error{{no matching}} } + +// Test of the current weird semantics of enable_if (and diagnose_if). +// +// There's two kinds of checking of the expression going on: +// 1. Whether it could potentially be a constexpr -- without access to the +// parameters. +// 2. Checking if the condition evaluates to true with concrete +// arguments. While #1 requires that it could potentially be a constexpr, +// this step does not require that it actually _IS_ a constexpr, only that +// it's evaluable! (Note: this looseness might be unintended) + +void non_constexpr() __attribute__((enable_if((int*)(char*)0 == 0, ""))); // expected-error{{'enable_if' attribute expression never produces a constant expression}} expected-note{{cast that performs the conversions of a reinterpret_cast is not allowed in a constant expression}} +void non_constexpr_call() { + non_constexpr(); +} + +void non_constexpr_conditional(long x) __attribute__((enable_if(x?1: (int*)(char*)0 == 0, ""))); +void non_constexpr_conditional_call() { + non_constexpr_conditional(0); +} #endif