summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/Sema/Sema.h6
-rw-r--r--lib/Sema/SemaDeclCXX.cpp6
-rw-r--r--lib/Sema/SemaTemplate.cpp68
-rw-r--r--test/PCH/cxx-static_assert.cpp4
-rw-r--r--test/Sema/static-assert.c2
-rw-r--r--test/SemaCXX/static-assert-cxx17.cpp9
-rw-r--r--test/SemaCXX/static-assert.cpp12
7 files changed, 63 insertions, 44 deletions
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 8e29447f1f..e67e918e99 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -2861,11 +2861,7 @@ public:
/// Find the failed Boolean condition within a given Boolean
/// constant expression, and describe it with a string.
- ///
- /// \param AllowTopLevelCond Whether to allow the result to be the
- /// complete top-level condition.
- std::pair<Expr *, std::string>
- findFailedBooleanCondition(Expr *Cond, bool AllowTopLevelCond);
+ std::pair<Expr *, std::string> findFailedBooleanCondition(Expr *Cond);
/// Emit diagnostics for the diagnose_if attributes on Function, ignoring any
/// non-ArgDependent DiagnoseIfAttrs.
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 16e4d84122..7914a5d40e 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -13913,9 +13913,9 @@ Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc,
Expr *InnerCond = nullptr;
std::string InnerCondDescription;
std::tie(InnerCond, InnerCondDescription) =
- findFailedBooleanCondition(Converted.get(),
- /*AllowTopLevelCond=*/false);
- if (InnerCond) {
+ findFailedBooleanCondition(Converted.get());
+ if (InnerCond && !isa<CXXBoolLiteralExpr>(InnerCond)
+ && !isa<IntegerLiteral>(InnerCond)) {
Diag(StaticAssertLoc, diag::err_static_assert_requirement_failed)
<< InnerCondDescription << !AssertMessage
<< Msg.str() << InnerCond->getSourceRange();
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 56302d6248..a3dbb44ba3 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -3052,30 +3052,42 @@ static Expr *lookThroughRangesV3Condition(Preprocessor &PP, Expr *Cond) {
return Cond;
}
-// 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);
+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 &P)
+ : Policy(P) {}
+
+ 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;
}
- return;
+ return false;
}
- FailedCond->printPretty(OS, nullptr, Policy);
-}
+
+private:
+ const PrintingPolicy Policy;
+};
+
+} // end anonymous namespace
std::pair<Expr *, std::string>
-Sema::findFailedBooleanCondition(Expr *Cond, bool AllowTopLevelCond) {
+Sema::findFailedBooleanCondition(Expr *Cond) {
Cond = lookThroughRangesV3Condition(PP, Cond);
// Separate out all of the terms in a conjunction.
@@ -3104,18 +3116,14 @@ Sema::findFailedBooleanCondition(Expr *Cond, bool AllowTopLevelCond) {
break;
}
}
-
- if (!FailedCond) {
- if (!AllowTopLevelCond)
- return { nullptr, "" };
-
+ if (!FailedCond)
FailedCond = Cond->IgnoreParenImpCasts();
- }
std::string Description;
{
llvm::raw_string_ostream Out(Description);
- prettyPrintFailedBooleanCondition(Out, FailedCond, getPrintingPolicy());
+ FailedBooleanConditionPrinterHelper Helper(getPrintingPolicy());
+ FailedCond->printPretty(Out, &Helper, getPrintingPolicy());
}
return { FailedCond, Description };
}
@@ -3199,9 +3207,7 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
Expr *FailedCond;
std::string FailedDescription;
std::tie(FailedCond, FailedDescription) =
- findFailedBooleanCondition(
- TemplateArgs[0].getSourceExpression(),
- /*AllowTopLevelCond=*/true);
+ findFailedBooleanCondition(TemplateArgs[0].getSourceExpression());
// Remove the old SFINAE diagnostic.
PartialDiagnosticAt OldDiag =
@@ -9649,7 +9655,7 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,
Expr *FailedCond;
std::string FailedDescription;
std::tie(FailedCond, FailedDescription) =
- findFailedBooleanCondition(Cond, /*AllowTopLevelCond=*/true);
+ findFailedBooleanCondition(Cond);
Diag(FailedCond->getExprLoc(),
diag::err_typename_nested_not_found_requirement)
diff --git a/test/PCH/cxx-static_assert.cpp b/test/PCH/cxx-static_assert.cpp
index 8049525fb5..be6c0ab2a7 100644
--- a/test/PCH/cxx-static_assert.cpp
+++ b/test/PCH/cxx-static_assert.cpp
@@ -3,7 +3,7 @@
// Test with pch.
// RUN: %clang_cc1 -std=c++11 -emit-pch -o %t %s
-// RUN: %clang_cc1 -include-pch %t -verify -std=c++11 %s
+// RUN: %clang_cc1 -include-pch %t -verify -std=c++11 %s
#ifndef HEADER
#define HEADER
@@ -14,7 +14,7 @@ template<int N> struct T {
#else
-// expected-error@12 {{static_assert failed "N is not 2!"}}
+// expected-error@12 {{static_assert failed due to requirement '1 == 2' "N is not 2!"}}
T<1> t1; // expected-note {{in instantiation of template class 'T<1>' requested here}}
T<2> t2;
diff --git a/test/Sema/static-assert.c b/test/Sema/static-assert.c
index 87fa0504b2..e8cfb1fa58 100644
--- a/test/Sema/static-assert.c
+++ b/test/Sema/static-assert.c
@@ -38,5 +38,5 @@ struct A {
typedef UNION(unsigned, struct A) U1;
UNION(char[2], short) u2 = { .one = { 'a', 'b' } };
-typedef UNION(char, short) U3; // expected-error {{static_assert failed "type size mismatch"}}
+typedef UNION(char, short) U3; // expected-error {{static_assert failed due to requirement 'sizeof(char) == sizeof(short)' "type size mismatch"}}
typedef UNION(float, 0.5f) U4; // expected-error {{expected a type}}
diff --git a/test/SemaCXX/static-assert-cxx17.cpp b/test/SemaCXX/static-assert-cxx17.cpp
index 7dcdb89719..67b3541bea 100644
--- a/test/SemaCXX/static-assert-cxx17.cpp
+++ b/test/SemaCXX/static-assert-cxx17.cpp
@@ -45,3 +45,12 @@ void foo4() {
};
template void foo4<float>();
// expected-note@-1{{in instantiation of function template specialization 'foo4<float>' requested here}}
+
+
+template <typename U, typename V>
+void foo5() {
+ static_assert(!!(global_inline_var<U, V>));
+ // expected-error@-1{{static_assert failed due to requirement '!!(global_inline_var<int, float>)'}}
+}
+template void foo5<int, float>();
+// expected-note@-1{{in instantiation of function template specialization 'foo5<int, float>' requested here}}
diff --git a/test/SemaCXX/static-assert.cpp b/test/SemaCXX/static-assert.cpp
index 38f82091ae..b43d56a922 100644
--- a/test/SemaCXX/static-assert.cpp
+++ b/test/SemaCXX/static-assert.cpp
@@ -15,14 +15,14 @@ class C {
};
template<int N> struct T {
- static_assert(N == 2, "N is not 2!"); // expected-error {{static_assert failed "N is not 2!"}}
+ static_assert(N == 2, "N is not 2!"); // expected-error {{static_assert failed due to requirement '1 == 2' "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 "Type not big enough!"}}
+ 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!"}}
};
S<char> s1; // expected-note {{in instantiation of template class 'S<char>' requested here}}
@@ -111,6 +111,14 @@ static_assert(std::is_same<ExampleTypes::T, ExampleTypes::U>::value, "message");
// 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 {};