courbet updated this revision to Diff 180220.
courbet marked 2 inline comments as done.
courbet added a comment.
Handle {L,R}Value references.
Repository:
rC Clang
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D55933/new/
https://reviews.llvm.org/D55933
Files:
include/clang/AST/NestedNameSpecifier.h
lib/AST/NestedNameSpecifier.cpp
lib/AST/TypePrinter.cpp
lib/Sema/SemaTemplate.cpp
test/SemaCXX/static-assert-cxx17.cpp
test/SemaCXX/static-assert.cpp
Index: test/SemaCXX/static-assert.cpp
===================================================================
--- test/SemaCXX/static-assert.cpp
+++ test/SemaCXX/static-assert.cpp
@@ -127,7 +127,7 @@
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"}}
+// expected-error@-1{{static_assert failed due to requirement 'std::is_same<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");
Index: test/SemaCXX/static-assert-cxx17.cpp
===================================================================
--- test/SemaCXX/static-assert-cxx17.cpp
+++ test/SemaCXX/static-assert-cxx17.cpp
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++1z -triple=x86_64-linux-gnu
-template <typename U, typename V>
+template <typename U, typename V = U>
struct S1 {
static constexpr const bool value = false;
};
@@ -14,7 +14,7 @@
static inline constexpr bool var = global_inline_var<U, V>;
};
-template <typename U, typename V>
+template <typename U, typename V = double>
inline constexpr bool constexpr_return_false() {
return false;
}
@@ -23,6 +23,8 @@
void foo() {
static_assert(S1<U, V>::value);
// expected-error@-1{{static_assert failed due to requirement 'S1<int, float>::value'}}
+ static_assert(S1<U>::value);
+ // expected-error@-1{{static_assert failed due to requirement 'S1<int>::value'}}
}
template void foo<int, float>();
// expected-note@-1{{in instantiation of function template specialization 'foo<int, float>' requested here}}
@@ -66,7 +68,7 @@
using U = float;
};
-template <class T>
+template <class T, class U = double>
struct X {
int i = 0;
int j = 0;
@@ -74,7 +76,8 @@
};
template <class T>
-void foo6() {
+void test_template_parameter_from_default() {
+ X<typename T::T> x;
static_assert(X<typename T::T>());
// expected-error@-1{{static_assert failed due to requirement 'X<int>()'}}
static_assert(X<typename T::T>{});
@@ -93,12 +96,60 @@
// 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(static_cast<const X<typename T::T> &>(x));
+ // expected-error@-1{{static_assert failed due to requirement 'static_cast<const X<int> &>(x)'}}
+ static_assert(static_cast<const X<typename T::T> &&>(x));
+ // expected-error@-1{{static_assert failed due to requirement 'static_cast<const X<int> &&>(x)'}}
static_assert((const X<typename T::T>[]){} == nullptr);
- // expected-error@-1{{static_assert failed due to requirement '(X<int> const[0]){} == nullptr'}}
+ // expected-error@-1{{static_assert 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_assert failed due to requirement 'sizeof(X<void>) == 0'}}
+ static_assert(constexpr_return_false<typename T::T>());
+ // expected-error@-1{{static_assert failed due to requirement 'constexpr_return_false<int>()'}}
+}
+template void test_template_parameter_from_default<ExampleTypes>();
+// expected-note@-1{{in instantiation of function template specialization 'test_template_parameter_from_default<ExampleTypes>' requested here}}
+
+template <class T, class U>
+void test_template_parameter_as_written() {
+ static_assert(X<typename T::T, U>());
+ // expected-error@-1{{static_assert failed due to requirement 'X<int, float>()'}}
+ static_assert(sizeof(X<typename T::T, U>) == 0);
+ // expected-error@-1{{static_assert failed due to requirement 'sizeof(X<int, float>) == 0'}}
static_assert(constexpr_return_false<typename T::T, typename T::U>());
// expected-error@-1{{static_assert failed due to requirement 'constexpr_return_false<int, float>()'}}
}
-template void foo6<ExampleTypes>();
-// expected-note@-1{{in instantiation of function template specialization 'foo6<ExampleTypes>' requested here}}
+template void test_template_parameter_as_written<ExampleTypes, float>();
+// expected-note@-1{{in instantiation of function template specialization 'test_template_parameter_as_written<ExampleTypes, float>' requested here}}
+
+
+template<class T, class = decltype(sizeof(0))>
+struct is_pointerable { static constexpr bool value = false; };
+
+template<class T>
+struct is_pointerable<T, decltype(sizeof(T*))> { static constexpr bool value = true; };
+
+template<class T>
+void test_is_pointerable()
+{
+ static_assert(is_pointerable<T>::value);
+ // expected-error@-1{{due to requirement 'is_pointerable<int &>::value'}}
+ static_assert(not is_pointerable<T>::value);
+ // expected-error@-1{{due to requirement '!is_pointerable<int>::value'}}
+}
+template void test_is_pointerable<int&>();
+// expected-note@-1{{in instantiation of function template specialization 'test_is_pointerable<int &>' requested here}}
+template void test_is_pointerable<int>();
+// expected-note@-1{{in instantiation of function template specialization 'test_is_pointerable<int>' requested here}}
+
+
+// This test emulates std::vector with a default allocator.
+// FIXME: Ideally we would like to avoid printing the default here (print 'S1<V<int> *, void>::value')
+template<class> struct A {};
+template<class T, class = A<T>> struct V {};
+template<class C> void test_std_vector_like_from_default() {
+ static_assert(S1<C*, void>::value);
+ // expected-error@-1{{due to requirement 'S1<V<int, A<int> > *, void>::value'}}
+}
+template void test_std_vector_like_from_default<V<int>>();
+// expected-note@-1{{in instantiation of function template specialization 'test_std_vector_like_from_default<V<int, A<int> > >' requested here}}
Index: lib/Sema/SemaTemplate.cpp
===================================================================
--- lib/Sema/SemaTemplate.cpp
+++ lib/Sema/SemaTemplate.cpp
@@ -3052,40 +3052,6 @@
return Cond;
}
-namespace {
-
-// A PrinterHelper that prints more helpful diagnostics for some sub-expressions
-// within failing boolean expression, such as substituting template parameters
-// for actual types.
-class FailedBooleanConditionPrinterHelper : public PrinterHelper {
-public:
- explicit FailedBooleanConditionPrinterHelper(const PrintingPolicy &P)
- : Policy(P) {}
-
- bool handledStmt(Stmt *E, raw_ostream &OS) override {
- const auto *DR = dyn_cast<DeclRefExpr>(E);
- if (DR && DR->getQualifier()) {
- // If this is a qualified name, expand the template arguments in nested
- // qualifiers.
- DR->getQualifier()->print(OS, Policy, true);
- // Then print the decl itself.
- const ValueDecl *VD = DR->getDecl();
- OS << VD->getName();
- if (const auto *IV = dyn_cast<VarTemplateSpecializationDecl>(VD)) {
- // This is a template variable, print the expanded template arguments.
- printTemplateArgumentList(OS, IV->getTemplateArgs().asArray(), Policy);
- }
- return true;
- }
- return false;
- }
-
-private:
- const PrintingPolicy Policy;
-};
-
-} // end anonymous namespace
-
std::pair<Expr *, std::string>
Sema::findFailedBooleanCondition(Expr *Cond) {
Cond = lookThroughRangesV3Condition(PP, Cond);
@@ -3124,8 +3090,7 @@
llvm::raw_string_ostream Out(Description);
PrintingPolicy Policy = getPrintingPolicy();
Policy.PrintCanonicalTypes = true;
- FailedBooleanConditionPrinterHelper Helper(Policy);
- FailedCond->printPretty(Out, &Helper, Policy, 0, "\n", nullptr);
+ FailedCond->printPretty(Out, nullptr, Policy, 0, "\n", nullptr);
}
return { FailedCond, Description };
}
Index: lib/AST/TypePrinter.cpp
===================================================================
--- lib/AST/TypePrinter.cpp
+++ lib/AST/TypePrinter.cpp
@@ -164,9 +164,35 @@
static SplitQualType splitAccordingToPolicy(QualType QT,
const PrintingPolicy &Policy) {
- if (Policy.PrintCanonicalTypes)
- QT = QT.getCanonicalType();
- return QT.split();
+ if (!Policy.PrintCanonicalTypes)
+ return QT.split();
+ if (QT.isNull())
+ return QT.split();
+ // We do not canonicalize a few type classes because this would remove the
+ // information about whether a template parameter came from a default
+ // argument.
+ // In the following comments, consider:
+ // `template struct X<typename T, typename U = int> {};`, and
+ // `struct Some { using Class = float; };`
+ switch (QT.getTypePtr()->getTypeClass()) {
+ // `X<Some::Class>` gets canonicalized to `X<float, int>`. We disable
+ // canonicalization so that `printTag()` can see the template parameters as
+ // written.
+ case Type::TemplateSpecialization:
+ // `X<Some::Class>*` gets canonicalized to `X<float, int>*`. Disabling
+ // canonicalization of the pointer/array will canonicalize the pointee when
+ // it is is processed, resulting in `X<float>*`.
+ case Type::Pointer:
+ case Type::LValueReference:
+ case Type::RValueReference:
+ case Type::ConstantArray:
+ case Type::IncompleteArray:
+ case Type::VariableArray:
+ case Type::DependentSizedArray:
+ return QT.split();
+ default:
+ return QT.getCanonicalType().split();
+ }
}
void TypePrinter::print(QualType t, raw_ostream &OS, StringRef PlaceHolder) {
Index: lib/AST/NestedNameSpecifier.cpp
===================================================================
--- lib/AST/NestedNameSpecifier.cpp
+++ lib/AST/NestedNameSpecifier.cpp
@@ -271,8 +271,7 @@
/// Print this nested name specifier to the given output
/// stream.
-void NestedNameSpecifier::print(raw_ostream &OS, const PrintingPolicy &Policy,
- bool ResolveTemplateArguments) const {
+void NestedNameSpecifier::print(raw_ostream &OS, const PrintingPolicy &Policy) const {
if (getPrefix())
getPrefix()->print(OS, Policy);
@@ -305,15 +304,6 @@
LLVM_FALLTHROUGH;
case TypeSpec: {
- const auto *Record =
- dyn_cast_or_null<ClassTemplateSpecializationDecl>(getAsRecordDecl());
- if (ResolveTemplateArguments && Record) {
- // Print the type trait with resolved template parameters.
- Record->printName(OS);
- printTemplateArgumentList(OS, Record->getTemplateArgs().asArray(),
- Policy);
- break;
- }
const Type *T = getAsType();
PrintingPolicy InnerPolicy(Policy);
Index: include/clang/AST/NestedNameSpecifier.h
===================================================================
--- include/clang/AST/NestedNameSpecifier.h
+++ include/clang/AST/NestedNameSpecifier.h
@@ -212,12 +212,8 @@
/// parameter pack (for C++11 variadic templates).
bool containsUnexpandedParameterPack() const;
- /// Print this nested name specifier to the given output stream. If
- /// `ResolveTemplateArguments` is true, we'll print actual types, e.g.
- /// `ns::SomeTemplate<int, MyClass>` instead of
- /// `ns::SomeTemplate<Container::value_type, T>`.
- void print(raw_ostream &OS, const PrintingPolicy &Policy,
- bool ResolveTemplateArguments = false) const;
+ /// Print this nested name specifier to the given output stream.
+ void print(raw_ostream &OS, const PrintingPolicy &Policy) const;
void Profile(llvm::FoldingSetNodeID &ID) const {
ID.AddPointer(Prefix.getOpaqueValue());
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits