courbet updated this revision to Diff 175667.
courbet added a comment.

clang-formant patch


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D54903/new/

https://reviews.llvm.org/D54903

Files:
  lib/Sema/SemaTemplate.cpp
  test/SemaCXX/static-assert.cpp

Index: test/SemaCXX/static-assert.cpp
===================================================================
--- test/SemaCXX/static-assert.cpp
+++ test/SemaCXX/static-assert.cpp
@@ -68,3 +68,44 @@
 };
 
 static_assert(first_trait<X>::value && second_trait<X>::value, "message"); // expected-error{{static_assert failed due to requirement 'second_trait<X>::value' "message"}}
+
+namespace std {
+
+template <class Tp, Tp v>
+struct integral_constant {
+  static const Tp value = v;
+  typedef Tp value_type;
+  typedef integral_constant type;
+};
+
+template <class Tp, Tp v>
+const Tp integral_constant<Tp, v>::value;
+
+typedef integral_constant<bool, true> true_type;
+typedef integral_constant<bool, false> false_type;
+
+template <class Tp>
+struct is_const : public false_type {};
+template <class Tp>
+struct is_const<Tp const> : public true_type {};
+
+// We do not define is_same in terms of integral_constant to check that both implementations are supported.
+template <typename T, typename U>
+struct is_same {
+  static const bool value = false;
+};
+
+template <typename T>
+struct is_same<T, T> {
+  static const bool value = true;
+};
+
+} // namespace std
+
+struct ExampleTypes {
+  using T = int;
+  using U = float;
+};
+
+static_assert(std::is_same<ExampleTypes::T, ExampleTypes::U>::value, "message"); // expected-error{{static_assert failed due to requirement 'std::is_same<int, float>::value' "message"}}
+static_assert(std::is_const<ExampleTypes::T>::value, "message");                 // expected-error{{static_assert failed due to requirement 'std::is_const<int>::value' "message"}}
Index: lib/Sema/SemaTemplate.cpp
===================================================================
--- lib/Sema/SemaTemplate.cpp
+++ lib/Sema/SemaTemplate.cpp
@@ -3052,6 +3052,67 @@
   return Cond;
 }
 
+// Returns true if `Name` is the name of an std type trait.
+static bool isTypeTraitName(const llvm::StringRef RecordName) {
+  return
+#define TYPE_TRAIT_1(Spelling, Name, Key) RecordName == (#Spelling + 2) ||
+#define TYPE_TRAIT_2(Spelling, Name, Key) RecordName == (#Spelling + 2) ||
+#define TYPE_TRAIT_N(Spelling, Name, Key) RecordName == (#Spelling + 2) ||
+#include "clang/Basic/TokenKinds.def"
+#undef TYPE_TRAIT_1
+#undef TYPE_TRAIT_2
+#undef TYPE_TRAIT_N
+      false;
+}
+
+// If `Record` is a type trait, pretty prints the condition with actual types
+// and returns true.
+static bool prettyPrintTypeTrait(const NestedNameSpecifier *NNS,
+                                 llvm::raw_string_ostream &OS,
+                                 const PrintingPolicy &PrintPolicy) {
+  // We are looking for a type.
+  if (NNS == nullptr || NNS->getKind() != NestedNameSpecifier::TypeSpec)
+    return false;
+  const RecordDecl *Record = NNS->getAsRecordDecl();
+  // In namespace "::std".
+  if (!Record->isInStdNamespace())
+    return false;
+  // Now check whether the record name is one of the known type traits.
+  if (!isTypeTraitName(Record->getName()))
+    return false;
+  // Print the type trait with resolved template parameters.
+  const auto *TmplDecl = dyn_cast<ClassTemplateSpecializationDecl>(Record);
+  assert(TmplDecl &&
+         "std type_traits should be ClassTemplateSpecializationDecl");
+  OS << "std::" << Record->getName() << "<";
+  ArrayRef<TemplateArgument> Args = TmplDecl->getTemplateArgs().asArray();
+  Args.front().print(PrintPolicy, OS);
+  for (const auto &Arg : Args.drop_front()) {
+    OS << ", ";
+    Arg.print(PrintPolicy, OS);
+  }
+  OS << ">";
+  return true;
+}
+
+// Print a diagnostic for the failing static_assert expression. Defaults to
+// pretty-printing the expression.
+static void
+prettyPrintFailedBooleanCondition(llvm::raw_string_ostream &OS,
+                                  const Expr *FailedCond,
+                                  const PrintingPolicy &PrintPolicy) {
+  if (const auto *DR = dyn_cast<DeclRefExpr>(FailedCond)) {
+    const auto *Var = dyn_cast<VarDecl>(DR->getDecl());
+    // This might be `std::some_type_trait<U,V>::value`.
+    if (Var && Var->isStaticDataMember() && Var->getName() == "value" &&
+        prettyPrintTypeTrait(DR->getQualifier(), OS, PrintPolicy)) {
+      OS << "::value";
+      return;
+    }
+  }
+  FailedCond->printPretty(OS, nullptr, PrintPolicy);
+}
+
 std::pair<Expr *, std::string>
 Sema::findFailedBooleanCondition(Expr *Cond, bool AllowTopLevelCond) {
   Cond = lookThroughRangesV3Condition(PP, Cond);
@@ -3093,7 +3154,7 @@
   std::string Description;
   {
     llvm::raw_string_ostream Out(Description);
-    FailedCond->printPretty(Out, nullptr, getPrintingPolicy());
+    prettyPrintFailedBooleanCondition(Out, FailedCond, getPrintingPolicy());
   }
   return { FailedCond, Description };
 }
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to