return Cond;
}
-namespace {
-
-// A PrinterHelper that prints more helpful diagnostics for some sub-expressions
-// within failing boolean expression, such as substituting template parameters
-// for actual types.
-class FailedBooleanConditionPrinterHelper : public PrinterHelper {
-public:
- explicit FailedBooleanConditionPrinterHelper(const PrintingPolicy &Policy)
- : Policy(Policy) {}
-
- bool handledStmt(Stmt *E, raw_ostream &OS) override {
- const auto *DR = dyn_cast<DeclRefExpr>(E);
- if (DR && DR->getQualifier()) {
- // If this is a qualified name, expand the template arguments in nested
- // qualifiers.
- DR->getQualifier()->print(OS, Policy, true);
- // Then print the decl itself.
- const ValueDecl *VD = DR->getDecl();
- OS << VD->getName();
- if (const auto *IV = dyn_cast<VarTemplateSpecializationDecl>(VD)) {
- // This is a template variable, print the expanded template arguments.
- printTemplateArgumentList(OS, IV->getTemplateArgs().asArray(), Policy);
- }
- return true;
+// Print a diagnostic for the failing static_assert expression. Defaults to
+// pretty-printing the expression.
+static void prettyPrintFailedBooleanCondition(llvm::raw_string_ostream &OS,
+ const Expr *FailedCond,
+ const PrintingPolicy &Policy) {
+ const auto *DR = dyn_cast<DeclRefExpr>(FailedCond);
+ if (DR && DR->getQualifier()) {
+ // If this is a qualified name, expand the template arguments in nested
+ // qualifiers.
+ DR->getQualifier()->print(OS, Policy, true);
+ // Then print the decl itself.
+ const ValueDecl *VD = DR->getDecl();
+ OS << VD->getName();
+ if (const auto *IV = dyn_cast<VarTemplateSpecializationDecl>(VD)) {
+ // This is a template variable, print the expanded template arguments.
+ printTemplateArgumentList(OS, IV->getTemplateArgs().asArray(), Policy);
}
- return false;
+ return;
}
-
-private:
- const PrintingPolicy &Policy;
-};
-
-} // end anonymous namespace
+ FailedCond->printPretty(OS, nullptr, Policy);
+}
std::pair<Expr *, std::string>
-Sema::findFailedBooleanCondition(Expr *Cond) {
+Sema::findFailedBooleanCondition(Expr *Cond, bool AllowTopLevelCond) {
Cond = lookThroughRangesV3Condition(PP, Cond);
// Separate out all of the terms in a conjunction.
for (Expr *Term : Terms) {
Expr *TermAsWritten = Term->IgnoreParenImpCasts();
+ // Literals are uninteresting.
+ if (isa<CXXBoolLiteralExpr>(TermAsWritten) ||
+ isa<IntegerLiteral>(TermAsWritten))
+ continue;
+
// The initialization of the parameter from the argument is
// a constant-evaluated context.
EnterExpressionEvaluationContext ConstantEvaluated(
break;
}
}
- if (!FailedCond)
- FailedCond = Cond->IgnoreParenImpCasts();
- // Literals are uninteresting.
- if (isa<CXXBoolLiteralExpr>(FailedCond) || isa<IntegerLiteral>(FailedCond))
- return {nullptr, ""};
+ if (!FailedCond) {
+ if (!AllowTopLevelCond)
+ return { nullptr, "" };
+
+ FailedCond = Cond->IgnoreParenImpCasts();
+ }
std::string Description;
{
llvm::raw_string_ostream Out(Description);
- FailedBooleanConditionPrinterHelper Helper(getPrintingPolicy());
- FailedCond->printPretty(Out, &Helper, getPrintingPolicy());
+ prettyPrintFailedBooleanCondition(Out, FailedCond, getPrintingPolicy());
}
return { FailedCond, Description };
}
Expr *FailedCond;
std::string FailedDescription;
std::tie(FailedCond, FailedDescription) =
- findFailedBooleanCondition(TemplateArgs[0].getSourceExpression());
+ findFailedBooleanCondition(
+ TemplateArgs[0].getSourceExpression(),
+ /*AllowTopLevelCond=*/true);
// Remove the old SFINAE diagnostic.
PartialDiagnosticAt OldDiag =
Expr *FailedCond;
std::string FailedDescription;
std::tie(FailedCond, FailedDescription) =
- findFailedBooleanCondition(Cond);
+ findFailedBooleanCondition(Cond, /*AllowTopLevelCond=*/true);
Diag(FailedCond->getExprLoc(),
diag::err_typename_nested_not_found_requirement)
};
template<int N> struct T {
- static_assert(N == 2, "N is not 2!"); // expected-error {{static_assert failed due to requirement '1 == 2' "N is not 2!"}}
+ static_assert(N == 2, "N is not 2!"); // expected-error {{static_assert failed "N is not 2!"}}
};
T<1> t1; // expected-note {{in instantiation of template class 'T<1>' requested here}}
T<2> t2;
template<typename T> struct S {
- static_assert(sizeof(T) > sizeof(char), "Type not big enough!"); // expected-error {{static_assert failed due to requirement 'sizeof(char) > sizeof(char)' "Type not big enough!"}}
+ static_assert(sizeof(T) > sizeof(char), "Type not big enough!"); // expected-error {{static_assert failed "Type not big enough!"}}
};
S<char> s1; // expected-note {{in instantiation of template class 'S<char>' requested here}}
// expected-error@-1{{static_assert failed due to requirement 'std::is_same<int, float>::value' "message"}}
static_assert(std::is_const<ExampleTypes::T>::value, "message");
// expected-error@-1{{static_assert failed due to requirement 'std::is_const<int>::value' "message"}}
-static_assert(!std::is_const<const ExampleTypes::T>::value, "message");
-// expected-error@-1{{static_assert failed due to requirement '!std::is_const<const int>::value' "message"}}
-static_assert(!(std::is_const<const ExampleTypes::T>::value), "message");
-// expected-error@-1{{static_assert failed due to requirement '!(std::is_const<const int>::value)' "message"}}
-static_assert(std::is_const<const ExampleTypes::T>::value == false, "message");
-// expected-error@-1{{static_assert failed due to requirement 'std::is_const<const int>::value == false' "message"}}
-static_assert(!(std::is_const<const ExampleTypes::T>::value == true), "message");
-// expected-error@-1{{static_assert failed due to requirement '!(std::is_const<const int>::value == true)' "message"}}
struct BI_tag {};
struct RAI_tag : BI_tag {};