Author: courbet Date: Thu Dec 20 01:05:15 2018 New Revision: 349729 URL: http://llvm.org/viewvc/llvm-project?rev=349729&view=rev Log: [Sema] Better static assert diagnostics for expressions involving temporaries/casts/....
Summary: Handles expressions such as: - `std::is_const<T>()` - `std::is_const<T>()()`; - `std::is_same(decltype(U()), V>::value`; Reviewers: aaron.ballman, Quuxplusone Subscribers: cfe-commits, llvm-commits Differential Revision: https://reviews.llvm.org/D55552 Modified: cfe/trunk/include/clang/AST/PrettyPrinter.h cfe/trunk/include/clang/AST/Type.h cfe/trunk/lib/AST/TypePrinter.cpp cfe/trunk/lib/Sema/SemaTemplate.cpp cfe/trunk/test/SemaCXX/static-assert-cxx17.cpp cfe/trunk/test/SemaCXX/static-assert.cpp Modified: cfe/trunk/include/clang/AST/PrettyPrinter.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/PrettyPrinter.h?rev=349729&r1=349728&r2=349729&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/PrettyPrinter.h (original) +++ cfe/trunk/include/clang/AST/PrettyPrinter.h Thu Dec 20 01:05:15 2018 @@ -51,7 +51,7 @@ struct PrintingPolicy { MSWChar(LO.MicrosoftExt && !LO.WChar), IncludeNewlines(true), MSVCFormatting(false), ConstantsAsWritten(false), SuppressImplicitBase(false), FullyQualifiedName(false), - RemapFilePaths(false) {} + RemapFilePaths(false), PrintCanonicalTypes(false) {} /// Adjust this printing policy for cases where it's known that we're /// printing C++ code (for instance, if AST dumping reaches a C++-only @@ -228,6 +228,9 @@ struct PrintingPolicy { /// Whether to apply -fdebug-prefix-map to any file paths. unsigned RemapFilePaths : 1; + /// Whether to print types as written or canonically. + unsigned PrintCanonicalTypes : 1; + /// When RemapFilePaths is true, this function performs the action. std::function<std::string(StringRef)> remapPath; }; Modified: cfe/trunk/include/clang/AST/Type.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=349729&r1=349728&r2=349729&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/Type.h (original) +++ cfe/trunk/include/clang/AST/Type.h Thu Dec 20 01:05:15 2018 @@ -980,9 +980,7 @@ public: void print(raw_ostream &OS, const PrintingPolicy &Policy, const Twine &PlaceHolder = Twine(), - unsigned Indentation = 0) const { - print(split(), OS, Policy, PlaceHolder, Indentation); - } + unsigned Indentation = 0) const; static void print(SplitQualType split, raw_ostream &OS, const PrintingPolicy &policy, const Twine &PlaceHolder, @@ -996,9 +994,7 @@ public: unsigned Indentation = 0); void getAsStringInternal(std::string &Str, - const PrintingPolicy &Policy) const { - return getAsStringInternal(split(), Str, Policy); - } + const PrintingPolicy &Policy) const; static void getAsStringInternal(SplitQualType split, std::string &out, const PrintingPolicy &policy) { Modified: cfe/trunk/lib/AST/TypePrinter.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/TypePrinter.cpp?rev=349729&r1=349728&r2=349729&view=diff ============================================================================== --- cfe/trunk/lib/AST/TypePrinter.cpp (original) +++ cfe/trunk/lib/AST/TypePrinter.cpp Thu Dec 20 01:05:15 2018 @@ -117,9 +117,7 @@ namespace { void spaceBeforePlaceHolder(raw_ostream &OS); void printTypeSpec(NamedDecl *D, raw_ostream &OS); - void printBefore(const Type *ty, Qualifiers qs, raw_ostream &OS); void printBefore(QualType T, raw_ostream &OS); - void printAfter(const Type *ty, Qualifiers qs, raw_ostream &OS); void printAfter(QualType T, raw_ostream &OS); void AppendScope(DeclContext *DC, raw_ostream &OS); void printTag(TagDecl *T, raw_ostream &OS); @@ -129,6 +127,10 @@ namespace { void print##CLASS##Before(const CLASS##Type *T, raw_ostream &OS); \ void print##CLASS##After(const CLASS##Type *T, raw_ostream &OS); #include "clang/AST/TypeNodes.def" + + private: + void printBefore(const Type *ty, Qualifiers qs, raw_ostream &OS); + void printAfter(const Type *ty, Qualifiers qs, raw_ostream &OS); }; } // namespace @@ -160,8 +162,15 @@ void TypePrinter::spaceBeforePlaceHolder OS << ' '; } +static SplitQualType splitAccordingToPolicy(QualType QT, + const PrintingPolicy &Policy) { + if (Policy.PrintCanonicalTypes) + QT = QT.getCanonicalType(); + return QT.split(); +} + void TypePrinter::print(QualType t, raw_ostream &OS, StringRef PlaceHolder) { - SplitQualType split = t.split(); + SplitQualType split = splitAccordingToPolicy(t, Policy); print(split.Ty, split.Quals, OS, PlaceHolder); } @@ -260,7 +269,7 @@ bool TypePrinter::canPrefixQualifiers(co } void TypePrinter::printBefore(QualType T, raw_ostream &OS) { - SplitQualType Split = T.split(); + SplitQualType Split = splitAccordingToPolicy(T, Policy); // If we have cv1 T, where T is substituted for cv2 U, only print cv1 - cv2 // at this level. @@ -320,7 +329,7 @@ void TypePrinter::printBefore(const Type } void TypePrinter::printAfter(QualType t, raw_ostream &OS) { - SplitQualType split = t.split(); + SplitQualType split = splitAccordingToPolicy(t, Policy); printAfter(split.Ty, split.Quals, OS); } @@ -1815,6 +1824,12 @@ std::string QualType::getAsString(const return buffer; } +void QualType::print(raw_ostream &OS, const PrintingPolicy &Policy, + const Twine &PlaceHolder, unsigned Indentation) const { + print(splitAccordingToPolicy(*this, Policy), OS, Policy, PlaceHolder, + Indentation); +} + void QualType::print(const Type *ty, Qualifiers qs, raw_ostream &OS, const PrintingPolicy &policy, const Twine &PlaceHolder, unsigned Indentation) { @@ -1824,6 +1839,12 @@ void QualType::print(const Type *ty, Qua TypePrinter(policy, Indentation).print(ty, qs, OS, PH); } +void QualType::getAsStringInternal(std::string &Str, + const PrintingPolicy &Policy) const { + return getAsStringInternal(splitAccordingToPolicy(*this, Policy), Str, + Policy); +} + void QualType::getAsStringInternal(const Type *ty, Qualifiers qs, std::string &buffer, const PrintingPolicy &policy) { Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=349729&r1=349728&r2=349729&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaTemplate.cpp (original) +++ cfe/trunk/lib/Sema/SemaTemplate.cpp Thu Dec 20 01:05:15 2018 @@ -3122,8 +3122,10 @@ Sema::findFailedBooleanCondition(Expr *C std::string Description; { llvm::raw_string_ostream Out(Description); - FailedBooleanConditionPrinterHelper Helper(getPrintingPolicy()); - FailedCond->printPretty(Out, &Helper, getPrintingPolicy()); + PrintingPolicy Policy = getPrintingPolicy(); + Policy.PrintCanonicalTypes = true; + FailedBooleanConditionPrinterHelper Helper(Policy); + FailedCond->printPretty(Out, &Helper, Policy, 0, "\n", nullptr); } return { FailedCond, Description }; } Modified: cfe/trunk/test/SemaCXX/static-assert-cxx17.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/static-assert-cxx17.cpp?rev=349729&r1=349728&r2=349729&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/static-assert-cxx17.cpp (original) +++ cfe/trunk/test/SemaCXX/static-assert-cxx17.cpp Thu Dec 20 01:05:15 2018 @@ -54,3 +54,44 @@ void foo5() { } template void foo5<int, float>(); // expected-note@-1{{in instantiation of function template specialization 'foo5<int, float>' requested here}} + +struct ExampleTypes { + explicit ExampleTypes(int); + using T = int; + using U = float; +}; + +template <class T> +struct X { + int i = 0; + int j = 0; + constexpr operator bool() const { return false; } +}; + +template <class T> +void foo6() { + static_assert(X<typename T::T>()); + // expected-error@-1{{static_assert failed due to requirement 'X<int>()'}} + static_assert(X<typename T::T>{}); + // expected-error@-1{{static_assert failed due to requirement 'X<int>{}'}} + static_assert(X<typename T::T>{1, 2}); + // expected-error@-1{{static_assert failed due to requirement 'X<int>{1, 2}'}} + static_assert(X<typename T::T>({1, 2})); + // expected-error@-1{{static_assert failed due to requirement 'X<int>({1, 2})'}} + static_assert(typename T::T{0}); + // expected-error@-1{{static_assert failed due to requirement 'int{0}'}} + static_assert(typename T::T(0)); + // expected-error@-1{{static_assert failed due to requirement 'int(0)'}} + static_assert(sizeof(X<typename T::T>) == 0); + // expected-error@-1{{static_assert failed due to requirement 'sizeof(X<int>) == 0'}} + static_assert((const X<typename T::T> *)nullptr); + // expected-error@-1{{static_assert failed due to requirement '(const X<int> *)nullptr'}} + static_assert(static_cast<const X<typename T::T> *>(nullptr)); + // expected-error@-1{{static_assert failed due to requirement 'static_cast<const X<int> *>(nullptr)'}} + static_assert((const X<typename T::T>[]){} == nullptr); + // expected-error@-1{{static_assert failed due to requirement '(X<int> const[0]){} == nullptr'}} + static_assert(sizeof(X<decltype(X<typename T::T>().X<typename T::T>::~X())>) == 0); + // expected-error@-1{{static_assert failed due to requirement 'sizeof(X<void>) == 0'}} +} +template void foo6<ExampleTypes>(); +// expected-note@-1{{in instantiation of function template specialization 'foo6<ExampleTypes>' requested here}} Modified: cfe/trunk/test/SemaCXX/static-assert.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/static-assert.cpp?rev=349729&r1=349728&r2=349729&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/static-assert.cpp (original) +++ cfe/trunk/test/SemaCXX/static-assert.cpp Thu Dec 20 01:05:15 2018 @@ -76,6 +76,8 @@ struct integral_constant { static const Tp value = v; typedef Tp value_type; typedef integral_constant type; + constexpr operator value_type() const noexcept { return value; } + constexpr value_type operator()() const noexcept { return value; } }; template <class Tp, Tp v> @@ -103,6 +105,7 @@ struct is_same<T, T> { } // namespace std struct ExampleTypes { + explicit ExampleTypes(int); using T = int; using U = float; }; @@ -119,6 +122,18 @@ static_assert(std::is_const<const Exampl // 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"}} +static_assert(std::is_const<ExampleTypes::T>(), "message"); +// expected-error@-1{{static_assert failed due to requirement 'std::is_const<int>()' "message"}} +static_assert(!(std::is_const<const ExampleTypes::T>()()), "message"); +// expected-error@-1{{static_assert failed due to requirement '!(std::is_const<const int>()())' "message"}} +static_assert(std::is_same<decltype(std::is_const<const ExampleTypes::T>()), int>::value, "message"); +// expected-error@-1{{static_assert failed due to requirement 'std::is_same<std::is_const<const int>, int>::value' "message"}} +static_assert(std::is_const<decltype(ExampleTypes::T(3))>::value, "message"); +// expected-error@-1{{static_assert failed due to requirement 'std::is_const<int>::value' "message"}} +static_assert(std::is_const<decltype(ExampleTypes::T())>::value, "message"); +// expected-error@-1{{static_assert failed due to requirement 'std::is_const<int>::value' "message"}} +static_assert(std::is_const<decltype(ExampleTypes(3))>::value, "message"); +// expected-error@-1{{static_assert failed due to requirement 'std::is_const<ExampleTypes>::value' "message"}} struct BI_tag {}; struct RAI_tag : BI_tag {}; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits