[c++20] Improve phrasing of diagnostic for missing #include <compare>.

This commit is contained in:
Richard Smith 2019-12-11 17:28:46 -08:00
parent 5688f16852
commit 38c3b5d562
5 changed files with 40 additions and 10 deletions

View File

@ -10145,8 +10145,8 @@ def warn_dispatch_body_ignored : Warning<
// three-way comparison operator diagnostics // three-way comparison operator diagnostics
def err_implied_comparison_category_type_not_found : Error< def err_implied_comparison_category_type_not_found : Error<
"cannot deduce return type of 'operator<=>' because type '%0' was not found; " "cannot %select{use builtin operator '<=>'|default 'operator<=>'}1 "
"include <compare>">; "because type '%0' was not found; include <compare>">;
def err_spaceship_argument_narrowing : Error< def err_spaceship_argument_narrowing : Error<
"argument to 'operator<=>' " "argument to 'operator<=>' "
"%select{cannot be narrowed from type %1 to %2|" "%select{cannot be narrowed from type %1 to %2|"

View File

@ -5038,6 +5038,16 @@ private:
IdentifierInfo *MemberOrBase); IdentifierInfo *MemberOrBase);
public: public:
enum class ComparisonCategoryUsage {
/// The '<=>' operator was used in an expression and a builtin operator
/// was selected.
OperatorInExpression,
/// A defaulted 'operator<=>' needed the comparison category. This
/// typically only applies to 'std::strong_ordering', due to the implicit
/// fallback return value.
DefaultedOperator,
};
/// Lookup the specified comparison category types in the standard /// Lookup the specified comparison category types in the standard
/// library, an check the VarDecls possibly returned by the operator<=> /// library, an check the VarDecls possibly returned by the operator<=>
/// builtins for that type. /// builtins for that type.
@ -5045,7 +5055,8 @@ public:
/// \return The type of the comparison category type corresponding to the /// \return The type of the comparison category type corresponding to the
/// specified Kind, or a null type if an error occurs /// specified Kind, or a null type if an error occurs
QualType CheckComparisonCategoryType(ComparisonCategoryType Kind, QualType CheckComparisonCategoryType(ComparisonCategoryType Kind,
SourceLocation Loc); SourceLocation Loc,
ComparisonCategoryUsage Usage);
/// Tests whether Ty is an instance of std::initializer_list and, if /// Tests whether Ty is an instance of std::initializer_list and, if
/// it is and Element is not NULL, assigns the element type to Element. /// it is and Element is not NULL, assigns the element type to Element.

View File

@ -7599,7 +7599,8 @@ public:
// Per C++2a [class.spaceship]p3, as a fallback add: // Per C++2a [class.spaceship]p3, as a fallback add:
// return static_cast<R>(std::strong_ordering::equal); // return static_cast<R>(std::strong_ordering::equal);
QualType StrongOrdering = S.CheckComparisonCategoryType( QualType StrongOrdering = S.CheckComparisonCategoryType(
ComparisonCategoryType::StrongOrdering, Loc); ComparisonCategoryType::StrongOrdering, Loc,
Sema::ComparisonCategoryUsage::DefaultedOperator);
if (StrongOrdering.isNull()) if (StrongOrdering.isNull())
return StmtError(); return StmtError();
VarDecl *EqualVD = S.Context.CompCategories.getInfoForType(StrongOrdering) VarDecl *EqualVD = S.Context.CompCategories.getInfoForType(StrongOrdering)
@ -8057,7 +8058,8 @@ bool Sema::CheckExplicitlyDefaultedComparison(Scope *S, FunctionDecl *FD,
RetLoc = FD->getBeginLoc(); RetLoc = FD->getBeginLoc();
// FIXME: Should we really care whether we have the complete type and the // FIXME: Should we really care whether we have the complete type and the
// 'enumerator' constants here? A forward declaration seems sufficient. // 'enumerator' constants here? A forward declaration seems sufficient.
QualType Cat = CheckComparisonCategoryType(Info.Category, RetLoc); QualType Cat = CheckComparisonCategoryType(
Info.Category, RetLoc, ComparisonCategoryUsage::DefaultedOperator);
if (Cat.isNull()) if (Cat.isNull())
return true; return true;
Context.adjustDeducedFunctionResultType( Context.adjustDeducedFunctionResultType(
@ -10591,7 +10593,8 @@ struct InvalidSTLDiagnoser {
} // namespace } // namespace
QualType Sema::CheckComparisonCategoryType(ComparisonCategoryType Kind, QualType Sema::CheckComparisonCategoryType(ComparisonCategoryType Kind,
SourceLocation Loc) { SourceLocation Loc,
ComparisonCategoryUsage Usage) {
assert(getLangOpts().CPlusPlus && assert(getLangOpts().CPlusPlus &&
"Looking for comparison category type outside of C++."); "Looking for comparison category type outside of C++.");
@ -10620,7 +10623,7 @@ QualType Sema::CheckComparisonCategoryType(ComparisonCategoryType Kind,
std::string NameForDiags = "std::"; std::string NameForDiags = "std::";
NameForDiags += ComparisonCategories::getCategoryString(Kind); NameForDiags += ComparisonCategories::getCategoryString(Kind);
Diag(Loc, diag::err_implied_comparison_category_type_not_found) Diag(Loc, diag::err_implied_comparison_category_type_not_found)
<< NameForDiags; << NameForDiags << (int)Usage;
return QualType(); return QualType();
} }

View File

@ -10601,7 +10601,8 @@ static QualType checkArithmeticOrEnumeralThreeWayCompare(Sema &S,
assert(!Type.isNull() && "composite type for <=> has not been set"); assert(!Type.isNull() && "composite type for <=> has not been set");
return S.CheckComparisonCategoryType( return S.CheckComparisonCategoryType(
*getComparisonCategoryForBuiltinCmp(Type), Loc); *getComparisonCategoryForBuiltinCmp(Type), Loc,
Sema::ComparisonCategoryUsage::OperatorInExpression);
} }
static QualType checkArithmeticOrEnumeralCompare(Sema &S, ExprResult &LHS, static QualType checkArithmeticOrEnumeralCompare(Sema &S, ExprResult &LHS,
@ -10738,7 +10739,8 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
CCT = ComparisonCategoryType::StrongEquality; CCT = ComparisonCategoryType::StrongEquality;
} }
return CheckComparisonCategoryType(*CCT, Loc); return CheckComparisonCategoryType(
*CCT, Loc, ComparisonCategoryUsage::OperatorInExpression);
}; };
if (!IsRelational && LHSIsNull != RHSIsNull) { if (!IsRelational && LHSIsNull != RHSIsNull) {

View File

@ -3,10 +3,24 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin -fcxx-exceptions -fsyntax-only -pedantic -verify -Wsign-compare -std=c++2a %s // RUN: %clang_cc1 -triple x86_64-apple-darwin -fcxx-exceptions -fsyntax-only -pedantic -verify -Wsign-compare -std=c++2a %s
void compare_not_found_test() { void compare_not_found_test() {
// expected-error@+1 {{cannot deduce return type of 'operator<=>' because type 'std::partial_ordering' was not found; include <compare>}} // expected-error@+1 {{cannot use builtin operator '<=>' because type 'std::partial_ordering' was not found; include <compare>}}
(void)(0.0 <=> 42.123); (void)(0.0 <=> 42.123);
} }
struct deduction_compare_not_found {
// expected-error@+1 {{cannot default 'operator<=>' because type 'std::strong_ordering' was not found; include <compare>}}
friend auto operator<=>(const deduction_compare_not_found&, const deduction_compare_not_found&) = default;
};
struct comparable {
int operator<=>(comparable);
};
struct default_compare_not_found {
// expected-error@+1 {{cannot default 'operator<=>' because type 'std::strong_ordering' was not found; include <compare>}}
friend int operator<=>(const default_compare_not_found&, const default_compare_not_found&) = default;
};
bool b = default_compare_not_found() < default_compare_not_found(); // expected-note {{first required here}}
namespace std { namespace std {
inline namespace __1 { inline namespace __1 {
struct partial_ordering; // expected-note {{forward declaration}} struct partial_ordering; // expected-note {{forward declaration}}