arichardson updated this revision to Diff 455258.
arichardson marked 2 inline comments as done.
arichardson added a comment.
Herald added a project: All.
rebase and address feedback
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D108211/new/
https://reviews.llvm.org/D108211
Files:
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/include/clang/Sema/Sema.h
clang/lib/Sema/SemaDeclCXX.cpp
clang/lib/Sema/SemaTemplate.cpp
clang/test/CXX/dcl.decl/dcl.meaning/dcl.array/p3.cpp
clang/test/Parser/objc-static-assert.mm
clang/test/Sema/static-assert.c
clang/test/SemaCXX/constant-expression-cxx11.cpp
clang/test/SemaCXX/static-assert-cxx17.cpp
clang/test/SemaCXX/static-assert.cpp
clang/test/SemaTemplate/overload-candidates.cpp
Index: clang/test/SemaTemplate/overload-candidates.cpp
===================================================================
--- clang/test/SemaTemplate/overload-candidates.cpp
+++ clang/test/SemaTemplate/overload-candidates.cpp
@@ -62,6 +62,8 @@
template<typename T> struct NonTemplateFunction {
typename boost::enable_if<sizeof(T) == 4, int>::type f(); // expected-error{{failed requirement 'sizeof(char) == 4'; 'enable_if' cannot be used to disable this declaration}}
+ // expected-note@-1{{expression evaluates to '1 == 4'}}
+ // expected-note@-2{{with 'sizeof(char)' equal to 1}}
};
NonTemplateFunction<char> NTFC; // expected-note{{here}}
Index: clang/test/SemaCXX/static-assert.cpp
===================================================================
--- clang/test/SemaCXX/static-assert.cpp
+++ clang/test/SemaCXX/static-assert.cpp
@@ -23,7 +23,9 @@
template<typename T> struct S {
static_assert(sizeof(T) > sizeof(char), "Type not big enough!"); // expected-error {{static assertion failed due to requirement 'sizeof(char) > sizeof(char)': Type not big enough!}} \
- // expected-note {{1 > 1}}
+ // expected-note {{1 > 1}} \
+ // expected-note {{with 'sizeof(char)' equal to 1}} \
+ // expected-note {{with 'sizeof(char)' equal to 1}}
};
S<char> s1; // expected-note {{in instantiation of template class 'S<char>' requested here}}
@@ -264,3 +266,30 @@
}
+
+struct IntAndPointer {
+ int i;
+ void *p;
+};
+static_assert(sizeof(IntAndPointer) == 4, "message");
+// expected-error@-1{{static assertion failed}} \
+// expected-note@-1{{expression evaluates to '16 == 4'}} \
+// expected-note@-1{{with 'sizeof(IntAndPointer)' equal to 16}}
+static_assert(alignof(IntAndPointer) == 4, "message");
+// expected-error@-1{{static assertion failed}} \
+// expected-note@-1{{expression evaluates to '8 == 4'}} \
+// expected-note@-1{{with 'alignof(IntAndPointer)' equal to 8}}
+static_assert(alignof(IntAndPointer) == sizeof(IntAndPointer), "message");
+// expected-error@-1{{static assertion failed}} \
+// expected-note@-1{{expression evaluates to '8 == 16'}} \
+// expected-note@-1{{with 'alignof(IntAndPointer)' equal to 8}} \
+// expected-note@-1{{with 'sizeof(IntAndPointer)' equal to 16}}
+static_assert(alignof(IntAndPointer) + sizeof(int) == sizeof(IntAndPointer), "message");
+// expected-error@-1{{static assertion failed}} \
+// expected-note@-1{{expression evaluates to '12 == 16'}} \
+// expected-note@-1{{with 'alignof(IntAndPointer)' equal to 8}} \
+// expected-note@-1{{with 'sizeof(int)' equal to 4}} \
+// expected-note@-1{{with 'sizeof(IntAndPointer)' equal to 16}}
+/// Should not print the sizeof(int) value here since it's not evaluated.
+static_assert(std::is_same<float, decltype(sizeof(int))>::value, "message");
+// expected-error@-1{{static assertion failed}}
Index: clang/test/SemaCXX/static-assert-cxx17.cpp
===================================================================
--- clang/test/SemaCXX/static-assert-cxx17.cpp
+++ clang/test/SemaCXX/static-assert-cxx17.cpp
@@ -89,7 +89,8 @@
// expected-error@-1{{static assertion failed due to requirement 'int(0)'}}
static_assert(sizeof(X<typename T::T>) == 0);
// expected-error@-1{{static assertion failed due to requirement 'sizeof(X<int>) == 0'}} \
- // expected-note@-1 {{evaluates to '8 == 0'}}
+ // expected-note@-1 {{evaluates to '8 == 0'}} \
+ // expected-note@-1 {{with 'sizeof(X<int>)' equal to 8}}
static_assert((const X<typename T::T> *)nullptr);
// expected-error@-1{{static assertion failed due to requirement '(const X<int> *)nullptr'}}
static_assert(static_cast<const X<typename T::T> *>(nullptr));
@@ -98,7 +99,8 @@
// expected-error@-1{{static assertion failed due to requirement '(const X<int>[0]){} == nullptr'}}
static_assert(sizeof(X<decltype(X<typename T::T>().X<typename T::T>::~X())>) == 0);
// expected-error@-1{{static assertion failed due to requirement 'sizeof(X<void>) == 0'}} \
- // expected-note@-1 {{evaluates to '8 == 0'}}
+ // expected-note@-1 {{evaluates to '8 == 0'}} \
+ // expected-note@-1 {{with 'sizeof(X<void>)' equal to 8}}
static_assert(constexpr_return_false<typename T::T, typename T::U>());
// expected-error@-1{{static assertion failed due to requirement 'constexpr_return_false<int, float>()'}}
}
Index: clang/test/SemaCXX/constant-expression-cxx11.cpp
===================================================================
--- clang/test/SemaCXX/constant-expression-cxx11.cpp
+++ clang/test/SemaCXX/constant-expression-cxx11.cpp
@@ -1918,12 +1918,14 @@
// cxx11-note@-2 {{call to virtual function}}
// cxx20_2b-error@-3 {{static assertion failed}}
// cxx20_2b-note@-4 {{8 == 16}}
+ // cxx20_2b-note@-5 {{with 'sizeof(VirtualFromBase::X<VirtualFromBase::S1>)' equal to 16}}
// Non-virtual f(), OK.
constexpr X<X<S2>> xxs2;
constexpr X<S2> *q = const_cast<X<X<S2>>*>(&xxs2);
static_assert(q->f() == sizeof(S2), ""); // cxx20_2b-error {{static assertion failed}} \
// cxx20_2b-note {{16 == 8}}
+ // cxx20_2b-note@-2 {{with 'sizeof(VirtualFromBase::S2)' equal to 8}}
}
namespace ConstexprConstructorRecovery {
Index: clang/test/Sema/static-assert.c
===================================================================
--- clang/test/Sema/static-assert.c
+++ clang/test/Sema/static-assert.c
@@ -56,7 +56,9 @@
UNION(char[2], short) u2 = { .one = { 'a', 'b' } }; // ext-warning 3 {{'_Static_assert' is a C11 extension}} cxx-warning {{designated initializers are a C++20 extension}}
typedef UNION(char, short) U3; // expected-error {{static assertion failed due to requirement 'sizeof(char) == sizeof(short)': type size mismatch}} \
// expected-note{{evaluates to '1 == 2'}} \
- // ext-warning 3 {{'_Static_assert' is a C11 extension}}
+ // ext-warning 3 {{'_Static_assert' is a C11 extension}} \
+ // expected-note {{with 'sizeof(char)' equal to 1}} \
+ // expected-note {{with 'sizeof(short)' equal to 2}}
typedef UNION(float, 0.5f) U4; // expected-error {{expected a type}} \
// ext-warning 3 {{'_Static_assert' is a C11 extension}}
Index: clang/test/Parser/objc-static-assert.mm
===================================================================
--- clang/test/Parser/objc-static-assert.mm
+++ clang/test/Parser/objc-static-assert.mm
@@ -27,7 +27,8 @@
static_assert(a, ""); // expected-error {{static assertion expression is not an integral constant expression}}
static_assert(sizeof(a) == 4, "");
static_assert(sizeof(a) == 3, ""); // expected-error {{static assertion failed}} \
- // expected-note {{evaluates to '4 == 3'}}
+ // expected-note {{evaluates to '4 == 3'}} \
+ // expected-note {{with 'sizeof (a)' equal to 4}}
}
static_assert(1, "");
@@ -42,7 +43,8 @@
_Static_assert(1, "");
static_assert(sizeof(b) == 4, "");
static_assert(sizeof(b) == 3, ""); // expected-error {{static assertion failed}} \
- // expected-note {{evaluates to '4 == 3'}}
+ // expected-note {{evaluates to '4 == 3'}} \
+ // expected-note{{with 'sizeof (b)' equal to 4}}
}
static_assert(1, "");
@@ -59,7 +61,8 @@
int b;
static_assert(sizeof(b) == 4, "");
static_assert(sizeof(b) == 3, ""); // expected-error {{static assertion failed}} \
- // expected-note {{evaluates to '4 == 3'}}
+ // expected-note {{evaluates to '4 == 3'}} \
+ // expected-note{{with 'sizeof (b)' equal to 4}}
}
@end
Index: clang/test/CXX/dcl.decl/dcl.meaning/dcl.array/p3.cpp
===================================================================
--- clang/test/CXX/dcl.decl/dcl.meaning/dcl.array/p3.cpp
+++ clang/test/CXX/dcl.decl/dcl.meaning/dcl.array/p3.cpp
@@ -99,7 +99,8 @@
// Use a failing test to ensure the type isn't considered dependent.
static_assert(sizeof(arr2) == 13, ""); // expected-error {{failed}} \
- // expected-note {{evaluates to '12 == 13'}}
+ // expected-note {{evaluates to '12 == 13'}} \
+ // expected-note{{with 'sizeof (arr2)' equal to 12}}
}
void g() { f<int[3]>(); } // expected-note {{in instantiation of}}
Index: clang/lib/Sema/SemaTemplate.cpp
===================================================================
--- clang/lib/Sema/SemaTemplate.cpp
+++ clang/lib/Sema/SemaTemplate.cpp
@@ -3631,8 +3631,10 @@
// for actual types.
class FailedBooleanConditionPrinterHelper : public PrinterHelper {
public:
- explicit FailedBooleanConditionPrinterHelper(const PrintingPolicy &P)
- : Policy(P) {}
+ explicit FailedBooleanConditionPrinterHelper(
+ const PrintingPolicy &P, Sema &S,
+ SmallVectorImpl<PartialDiagnosticAt> &Notes)
+ : Policy(P), S(S), Notes(Notes) {}
bool handledStmt(Stmt *E, raw_ostream &OS) override {
const auto *DR = dyn_cast<DeclRefExpr>(E);
@@ -3651,17 +3653,35 @@
}
return true;
}
+
+ if (auto *UE = dyn_cast<UnaryExprOrTypeTraitExpr>(E)) {
+ Expr::EvalResult Result;
+ if (UE->EvaluateAsConstantExpr(Result, S.Context) && Result.Val.isInt()) {
+ std::string ExprStr;
+ llvm::raw_string_ostream ExprStream(ExprStr);
+ UE->printPretty(ExprStream, nullptr, Policy);
+ ExprStream.flush();
+ Notes.push_back(PartialDiagnosticAt(
+ UE->getExprLoc(),
+ S.PDiag(diag::note_static_assert_requirement_context)
+ << ExprStr << toString(Result.Val.getInt(), 10)
+ << UE->getSourceRange()));
+ }
+ }
return false;
}
private:
const PrintingPolicy Policy;
+ Sema &S;
+ SmallVectorImpl<PartialDiagnosticAt> &Notes;
};
} // end anonymous namespace
std::pair<Expr *, std::string>
-Sema::findFailedBooleanCondition(Expr *Cond) {
+Sema::findFailedBooleanCondition(Expr *Cond,
+ SmallVectorImpl<PartialDiagnosticAt> &Notes) {
Cond = lookThroughRangesV3Condition(PP, Cond);
// Separate out all of the terms in a conjunction.
@@ -3693,12 +3713,15 @@
if (!FailedCond)
FailedCond = Cond->IgnoreParenImpCasts();
+ // Create an "evaluates to" note for complex binary expressions.
+ DiagnoseFailedBoolExprDetails(FailedCond, Notes);
+
std::string Description;
{
llvm::raw_string_ostream Out(Description);
PrintingPolicy Policy = getPrintingPolicy();
Policy.PrintCanonicalTypes = true;
- FailedBooleanConditionPrinterHelper Helper(Policy);
+ FailedBooleanConditionPrinterHelper Helper(Policy, *this, Notes);
FailedCond->printPretty(Out, &Helper, Policy, 0, "\n", nullptr);
}
return { FailedCond, Description };
@@ -3786,8 +3809,10 @@
== TemplateArgument::Expression) {
Expr *FailedCond;
std::string FailedDescription;
+ SmallVector<PartialDiagnosticAt, 2> Notes;
std::tie(FailedCond, FailedDescription) =
- findFailedBooleanCondition(TemplateArgs[0].getSourceExpression());
+ findFailedBooleanCondition(
+ TemplateArgs[0].getSourceExpression(), Notes);
// Remove the old SFINAE diagnostic.
PartialDiagnosticAt OldDiag =
@@ -3801,6 +3826,8 @@
PDiag(diag::err_typename_nested_not_found_requirement)
<< FailedDescription
<< FailedCond->getSourceRange());
+ for (const PartialDiagnosticAt &Note : Notes)
+ (*DeductionInfo)->addSFINAEDiagnostic(Note.first, Note.second);
}
}
}
@@ -10713,13 +10740,16 @@
if (Cond) {
Expr *FailedCond;
std::string FailedDescription;
+ SmallVector<PartialDiagnosticAt, 2> Notes;
std::tie(FailedCond, FailedDescription) =
- findFailedBooleanCondition(Cond);
+ findFailedBooleanCondition(Cond, Notes);
Diag(FailedCond->getExprLoc(),
diag::err_typename_nested_not_found_requirement)
<< FailedDescription
<< FailedCond->getSourceRange();
+ for (const PartialDiagnosticAt &Note : Notes)
+ Diag(Note.first, Note.second);
return QualType();
}
Index: clang/lib/Sema/SemaDeclCXX.cpp
===================================================================
--- clang/lib/Sema/SemaDeclCXX.cpp
+++ clang/lib/Sema/SemaDeclCXX.cpp
@@ -16670,8 +16670,9 @@
}
/// Try to print more useful information about a failed static_assert
-/// with expression \E
-void Sema::DiagnoseStaticAssertDetails(const Expr *E) {
+/// with expression \p E and if found append the diagnostic to \p Notes.
+void Sema::DiagnoseFailedBoolExprDetails(
+ const Expr *E, SmallVectorImpl<PartialDiagnosticAt> &Notes) {
if (const auto *Op = dyn_cast_or_null<BinaryOperator>(E)) {
const Expr *LHS = Op->getLHS()->IgnoreParenImpCasts();
const Expr *RHS = Op->getRHS()->IgnoreParenImpCasts();
@@ -16701,9 +16702,11 @@
DiagSide[I].Result.Val, Side->getType(), DiagSide[I].ValueString);
}
if (DiagSide[0].Print && DiagSide[1].Print) {
- Diag(Op->getExprLoc(), diag::note_expr_evaluates_to)
- << DiagSide[0].ValueString << Op->getOpcodeStr()
- << DiagSide[1].ValueString << Op->getSourceRange();
+ Notes.emplace_back(Op->getExprLoc(), PDiag(diag::note_expr_evaluates_to)
+ << DiagSide[0].ValueString
+ << Op->getOpcodeStr()
+ << DiagSide[1].ValueString
+ << Op->getSourceRange());
}
}
}
@@ -16751,8 +16754,9 @@
Expr *InnerCond = nullptr;
std::string InnerCondDescription;
+ SmallVector<PartialDiagnosticAt, 2> Notes;
std::tie(InnerCond, InnerCondDescription) =
- findFailedBooleanCondition(Converted.get());
+ findFailedBooleanCondition(Converted.get(), Notes);
if (InnerCond && isa<ConceptSpecializationExpr>(InnerCond)) {
// Drill down into concept specialization expressions to see why they
// weren't satisfied.
@@ -16766,11 +16770,12 @@
Diag(StaticAssertLoc, diag::err_static_assert_requirement_failed)
<< InnerCondDescription << !AssertMessage
<< Msg.str() << InnerCond->getSourceRange();
- DiagnoseStaticAssertDetails(InnerCond);
} else {
Diag(StaticAssertLoc, diag::err_static_assert_failed)
<< !AssertMessage << Msg.str() << AssertExpr->getSourceRange();
}
+ for (const PartialDiagnosticAt &Note : Notes)
+ Diag(Note.first, Note.second);
Failed = true;
}
} else {
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -3980,7 +3980,9 @@
/// Find the failed Boolean condition within a given Boolean
/// constant expression, and describe it with a string.
- std::pair<Expr *, std::string> findFailedBooleanCondition(Expr *Cond);
+ std::pair<Expr *, std::string>
+ findFailedBooleanCondition(Expr *Cond,
+ SmallVectorImpl<PartialDiagnosticAt> &Notes);
/// Emit diagnostics for the diagnose_if attributes on Function, ignoring any
/// non-ArgDependent DiagnoseIfAttrs.
@@ -7502,7 +7504,9 @@
StringLiteral *AssertMessageExpr,
SourceLocation RParenLoc,
bool Failed);
- void DiagnoseStaticAssertDetails(const Expr *E);
+ void
+ DiagnoseFailedBoolExprDetails(const Expr *E,
+ SmallVectorImpl<PartialDiagnosticAt> &Notes);
FriendDecl *CheckFriendTypeDecl(SourceLocation LocStart,
SourceLocation FriendLoc,
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1532,6 +1532,7 @@
def err_static_assert_failed : Error<"static assertion failed%select{: %1|}0">;
def err_static_assert_requirement_failed : Error<
"static assertion failed due to requirement '%0'%select{: %2|}1">;
+def note_static_assert_requirement_context : Note<"with '%0' equal to %1">;
def note_expr_evaluates_to : Note<
"expression evaluates to '%0 %1 %2'">;
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits