Skip to content

Commit

Permalink
[Sema] Better static assert diagnostics for expressions involving tem…
Browse files Browse the repository at this point in the history
…poraries/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

llvm-svn: 349729
  • Loading branch information
legrosbuffle committed Dec 20, 2018
1 parent 2d98eb1 commit fb2c74d
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 14 deletions.
5 changes: 4 additions & 1 deletion clang/include/clang/AST/PrettyPrinter.h
Expand Up @@ -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
Expand Down Expand Up @@ -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;
};
Expand Down
8 changes: 2 additions & 6 deletions clang/include/clang/AST/Type.h
Expand Up @@ -980,9 +980,7 @@ class QualType {

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,
Expand All @@ -996,9 +994,7 @@ class QualType {
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) {
Expand Down
31 changes: 26 additions & 5 deletions clang/lib/AST/TypePrinter.cpp
Expand Up @@ -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);
Expand All @@ -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
Expand Down Expand Up @@ -160,8 +162,15 @@ void TypePrinter::spaceBeforePlaceHolder(raw_ostream &OS) {
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);
}

Expand Down Expand Up @@ -260,7 +269,7 @@ bool TypePrinter::canPrefixQualifiers(const Type *T,
}

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.
Expand Down Expand Up @@ -320,7 +329,7 @@ void TypePrinter::printBefore(const Type *T,Qualifiers Quals, raw_ostream &OS) {
}

void TypePrinter::printAfter(QualType t, raw_ostream &OS) {
SplitQualType split = t.split();
SplitQualType split = splitAccordingToPolicy(t, Policy);
printAfter(split.Ty, split.Quals, OS);
}

Expand Down Expand Up @@ -1815,6 +1824,12 @@ std::string QualType::getAsString(const Type *ty, Qualifiers qs,
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) {
Expand All @@ -1824,6 +1839,12 @@ void QualType::print(const Type *ty, Qualifiers qs,
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) {
Expand Down
6 changes: 4 additions & 2 deletions clang/lib/Sema/SemaTemplate.cpp
Expand Up @@ -3122,8 +3122,10 @@ Sema::findFailedBooleanCondition(Expr *Cond) {
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 };
}
Expand Down
41 changes: 41 additions & 0 deletions clang/test/SemaCXX/static-assert-cxx17.cpp
Expand Up @@ -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}}
15 changes: 15 additions & 0 deletions clang/test/SemaCXX/static-assert.cpp
Expand Up @@ -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>
Expand Down Expand Up @@ -103,6 +105,7 @@ struct is_same<T, T> {
} // namespace std

struct ExampleTypes {
explicit ExampleTypes(int);
using T = int;
using U = float;
};
Expand All @@ -119,6 +122,18 @@ 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"}}
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 {};
Expand Down

0 comments on commit fb2c74d

Please sign in to comment.