Skip to content
This repository was archived by the owner on Nov 1, 2021. It is now read-only.

Commit 36a127d

Browse files
committed
Diagnostic specific failed condition in a static_assert.
When a static_assert fails, dig out a specific condition to diagnose, using the same logic that we use to find the enable_if condition to diagnose. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@313315 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 13a5489 commit 36a127d

File tree

5 files changed

+64
-16
lines changed

5 files changed

+64
-16
lines changed

include/clang/Basic/DiagnosticSemaKinds.td

+2
Original file line numberDiff line numberDiff line change
@@ -1219,6 +1219,8 @@ def warn_messaging_unqualified_id : Warning<
12191219
def err_static_assert_expression_is_not_constant : Error<
12201220
"static_assert expression is not an integral constant expression">;
12211221
def err_static_assert_failed : Error<"static_assert failed%select{ %1|}0">;
1222+
def err_static_assert_requirement_failed : Error<
1223+
"static_assert failed due to requirement '%0'%select{ %2|}1">;
12221224
def ext_static_assert_no_message : ExtWarn<
12231225
"static_assert with no message is a C++17 extension">, InGroup<CXX17>;
12241226
def warn_cxx14_compat_static_assert_no_message : Warning<

include/clang/Sema/Sema.h

+8
Original file line numberDiff line numberDiff line change
@@ -2783,6 +2783,14 @@ class Sema {
27832783
EnableIfAttr *CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> Args,
27842784
bool MissingImplicitThis = false);
27852785

2786+
/// Find the failed Boolean condition within a given Boolean
2787+
/// constant expression, and describe it with a string.
2788+
///
2789+
/// \param AllowTopLevelCond Whether to allow the result to be the
2790+
/// complete top-level condition.
2791+
std::pair<Expr *, std::string>
2792+
findFailedBooleanCondition(Expr *Cond, bool AllowTopLevelCond);
2793+
27862794
/// Emit diagnostics for the diagnose_if attributes on Function, ignoring any
27872795
/// non-ArgDependent DiagnoseIfAttrs.
27882796
///

lib/Sema/SemaDeclCXX.cpp

+14-2
Original file line numberDiff line numberDiff line change
@@ -13296,8 +13296,20 @@ Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc,
1329613296
llvm::raw_svector_ostream Msg(MsgBuffer);
1329713297
if (AssertMessage)
1329813298
AssertMessage->printPretty(Msg, nullptr, getPrintingPolicy());
13299-
Diag(StaticAssertLoc, diag::err_static_assert_failed)
13300-
<< !AssertMessage << Msg.str() << AssertExpr->getSourceRange();
13299+
13300+
Expr *InnerCond = nullptr;
13301+
std::string InnerCondDescription;
13302+
std::tie(InnerCond, InnerCondDescription) =
13303+
findFailedBooleanCondition(Converted.get(),
13304+
/*AllowTopLevelCond=*/false);
13305+
if (InnerCond) {
13306+
Diag(StaticAssertLoc, diag::err_static_assert_requirement_failed)
13307+
<< InnerCondDescription << !AssertMessage
13308+
<< Msg.str() << InnerCond->getSourceRange();
13309+
} else {
13310+
Diag(StaticAssertLoc, diag::err_static_assert_failed)
13311+
<< !AssertMessage << Msg.str() << AssertExpr->getSourceRange();
13312+
}
1330113313
Failed = true;
1330213314
}
1330313315
}

lib/Sema/SemaTemplate.cpp

+23-14
Original file line numberDiff line numberDiff line change
@@ -2863,11 +2863,9 @@ static Expr *lookThroughRangesV3Condition(Preprocessor &PP, Expr *Cond) {
28632863
return Cond;
28642864
}
28652865

2866-
/// Find the failed subexpression within enable_if, and describe it
2867-
/// with a string.
2868-
static std::pair<Expr *, std::string>
2869-
findFailedEnableIfCondition(Sema &S, Expr *Cond) {
2870-
Cond = lookThroughRangesV3Condition(S.PP, Cond);
2866+
std::pair<Expr *, std::string>
2867+
Sema::findFailedBooleanCondition(Expr *Cond, bool AllowTopLevelCond) {
2868+
Cond = lookThroughRangesV3Condition(PP, Cond);
28712869

28722870
// Separate out all of the terms in a conjunction.
28732871
SmallVector<Expr *, 4> Terms;
@@ -2876,27 +2874,37 @@ findFailedEnableIfCondition(Sema &S, Expr *Cond) {
28762874
// Determine which term failed.
28772875
Expr *FailedCond = nullptr;
28782876
for (Expr *Term : Terms) {
2877+
Expr *TermAsWritten = Term->IgnoreParenImpCasts();
2878+
2879+
// Literals are uninteresting.
2880+
if (isa<CXXBoolLiteralExpr>(TermAsWritten) ||
2881+
isa<IntegerLiteral>(TermAsWritten))
2882+
continue;
2883+
28792884
// The initialization of the parameter from the argument is
28802885
// a constant-evaluated context.
28812886
EnterExpressionEvaluationContext ConstantEvaluated(
2882-
S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
2887+
*this, Sema::ExpressionEvaluationContext::ConstantEvaluated);
28832888

28842889
bool Succeeded;
2885-
if (Term->EvaluateAsBooleanCondition(Succeeded, S.Context) &&
2890+
if (Term->EvaluateAsBooleanCondition(Succeeded, Context) &&
28862891
!Succeeded) {
2887-
FailedCond = Term->IgnoreParenImpCasts();
2892+
FailedCond = TermAsWritten;
28882893
break;
28892894
}
28902895
}
28912896

2892-
if (!FailedCond)
2897+
if (!FailedCond) {
2898+
if (!AllowTopLevelCond)
2899+
return { nullptr, "" };
2900+
28932901
FailedCond = Cond->IgnoreParenImpCasts();
2902+
}
28942903

28952904
std::string Description;
28962905
{
28972906
llvm::raw_string_ostream Out(Description);
2898-
FailedCond->printPretty(Out, nullptr,
2899-
PrintingPolicy(S.Context.getLangOpts()));
2907+
FailedCond->printPretty(Out, nullptr, getPrintingPolicy());
29002908
}
29012909
return { FailedCond, Description };
29022910
}
@@ -2980,8 +2988,9 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
29802988
Expr *FailedCond;
29812989
std::string FailedDescription;
29822990
std::tie(FailedCond, FailedDescription) =
2983-
findFailedEnableIfCondition(
2984-
*this, TemplateArgs[0].getSourceExpression());
2991+
findFailedBooleanCondition(
2992+
TemplateArgs[0].getSourceExpression(),
2993+
/*AllowTopLevelCond=*/true);
29852994

29862995
// Remove the old SFINAE diagnostic.
29872996
PartialDiagnosticAt OldDiag =
@@ -9513,7 +9522,7 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,
95139522
Expr *FailedCond;
95149523
std::string FailedDescription;
95159524
std::tie(FailedCond, FailedDescription) =
9516-
findFailedEnableIfCondition(*this, Cond);
9525+
findFailedBooleanCondition(Cond, /*AllowTopLevelCond=*/true);
95179526

95189527
Diag(FailedCond->getExprLoc(),
95199528
diag::err_typename_nested_not_found_requirement)

test/SemaCXX/static-assert.cpp

+17
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,20 @@ StaticAssertProtected<X> sap2; // expected-note {{instantiation}}
5151

5252
static_assert(true); // expected-warning {{C++17 extension}}
5353
static_assert(false); // expected-error-re {{failed{{$}}}} expected-warning {{extension}}
54+
55+
56+
// Diagnostics for static_assert with multiple conditions
57+
template<typename T> struct first_trait {
58+
static const bool value = false;
59+
};
60+
61+
template<>
62+
struct first_trait<X> {
63+
static const bool value = true;
64+
};
65+
66+
template<typename T> struct second_trait {
67+
static const bool value = false;
68+
};
69+
70+
static_assert(first_trait<X>::value && second_trait<X>::value, "message"); // expected-error{{static_assert failed due to requirement 'second_trait<X>::value' "message"}}

0 commit comments

Comments
 (0)