danix800 created this revision.
danix800 added a project: clang.
Herald added a project: All.
danix800 requested review of this revision.
Herald added a subscriber: cfe-commits.

For non-pure methods with no written `virtual`, `isVirtual()` tries to count 
size of overridden methods. For importing, size might not be correct before 
fully loaded.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D154701

Files:
  clang/lib/AST/DeclCXX.cpp
  clang/test/Analysis/ctu-astimport-virtual-assertion/Inputs/externalDefMap.txt
  clang/test/Analysis/ctu-astimport-virtual-assertion/Inputs/input.cpp
  clang/test/Analysis/ctu-astimport-virtual-assertion/Inputs/input.h
  clang/test/Analysis/ctu-astimport-virtual-assertion/main.cpp

Index: clang/test/Analysis/ctu-astimport-virtual-assertion/main.cpp
===================================================================
--- /dev/null
+++ clang/test/Analysis/ctu-astimport-virtual-assertion/main.cpp
@@ -0,0 +1,22 @@
+// RUN: rm -rf %t && mkdir %t
+// RUN: mkdir -p %t/ctudir
+
+// RUN: %clang --target=armv7a-linux-androideabi10000 -c -x c++ \
+// RUN:   -mthumb -std=gnu++17 %p/Inputs/input.cpp -emit-ast \
+// RUN:   -o %t/ctudir/input.cpp.ast
+
+// RUN: cp %p/Inputs/externalDefMap.txt %t/ctudir/externalDefMap.txt
+
+// RUN: %clang_analyze_cc1 -triple thumbv7-unknown-linux-android10000 \
+// RUN:   -std=gnu++17 \
+// RUN:   -analyzer-checker=core.DivideZero \
+// RUN:   -analyzer-opt-analyze-headers \
+// RUN:   -analyzer-config experimental-enable-naive-ctu-analysis=true \
+// RUN:   -analyzer-config display-ctu-progress=true \
+// RUN:   -analyzer-config ctu-dir=%t/ctudir \
+// RUN:   -fno-signed-char \
+// RUN:   -verify %s
+
+// expected-no-diagnostics
+
+#include "Inputs/input.h"
Index: clang/test/Analysis/ctu-astimport-virtual-assertion/Inputs/input.h
===================================================================
--- /dev/null
+++ clang/test/Analysis/ctu-astimport-virtual-assertion/Inputs/input.h
@@ -0,0 +1,25 @@
+#ifndef ART_COMPILER_OPTIMIZING_LOCATIONS_H_
+#define ART_COMPILER_OPTIMIZING_LOCATIONS_H_
+
+namespace std {
+
+template <typename _CharT>
+class basic_ostream {};
+
+typedef basic_ostream<char> ostream;
+
+} // namespace std
+
+namespace art {
+
+class Location;
+std::ostream &operator<<(std::ostream &os, const Location &location);
+
+class RegisterSet {
+public:
+  void Remove(std::ostream &OS, const Location &loc) { OS << loc; }
+};
+
+} // namespace art
+
+#endif // ART_COMPILER_OPTIMIZING_LOCATIONS_H_
Index: clang/test/Analysis/ctu-astimport-virtual-assertion/Inputs/input.cpp
===================================================================
--- /dev/null
+++ clang/test/Analysis/ctu-astimport-virtual-assertion/Inputs/input.cpp
@@ -0,0 +1,250 @@
+#include "input.h"
+
+typedef __SIZE_TYPE__ size_t;
+
+namespace std {
+template <typename _Tp, _Tp __v>
+struct integral_constant {
+  static constexpr _Tp value = __v;
+  typedef _Tp value_type;
+  typedef integral_constant<_Tp, __v> type;
+};
+using false_type = integral_constant<bool, false>;
+using true_type = integral_constant<bool, true>;
+
+template <typename _Base, typename _Derived>
+struct is_base_of
+    : public integral_constant<bool, __is_base_of(_Base, _Derived)> {};
+
+template <typename _Tp>
+struct is_enum : public integral_constant<bool, __is_enum(_Tp)> {};
+
+template <typename _Result, typename _Arg>
+struct __hash_base {
+  typedef _Result result_type;
+  typedef _Arg argument_type;
+};
+
+template <typename _Tp, bool = is_enum<_Tp>::value>
+struct __hash_enum {
+private:
+  // Private rather than deleted to be non-trivially-copyable.
+  __hash_enum(__hash_enum &&);
+  ~__hash_enum();
+};
+
+template <typename _Tp, bool = is_enum<_Tp>::value>
+struct __underlying_type_impl {
+  using type = __underlying_type(_Tp);
+};
+
+template <typename _Tp>
+struct __underlying_type_impl<_Tp, false> {};
+/// @endcond
+
+/// The underlying type of an enum.
+template <typename _Tp>
+struct underlying_type : public __underlying_type_impl<_Tp> {};
+
+/// Primary class template hash, usable for enum types only.
+// Use with non-enum types still SFINAES.
+template <typename _Tp>
+struct hash : __hash_enum<_Tp> {};
+
+// Helper struct for hash with enum types.
+template <typename _Tp>
+struct __hash_enum<_Tp, true> : public __hash_base<size_t, _Tp> {
+  size_t operator()(_Tp __val) const noexcept {
+    using __type = typename underlying_type<_Tp>::type;
+    return hash<__type>{}(static_cast<__type>(__val));
+  }
+};
+
+template <typename _Tp>
+struct hash<_Tp *> : public __hash_base<size_t, _Tp *> {
+  size_t operator()(_Tp *__p) const noexcept {
+    return reinterpret_cast<size_t>(__p);
+  }
+};
+
+template <typename _Tp, typename _Up>
+struct is_same : public false_type {};
+
+template <typename _Tp>
+struct is_same<_Tp, _Tp> : public true_type {};
+
+template <bool, typename _Tp = void>
+struct enable_if {};
+
+template <typename _Tp>
+struct enable_if<true, _Tp> {
+  typedef _Tp type;
+};
+
+} // namespace std
+
+namespace art {
+
+template <typename Derived, typename Tag = void>
+struct IntrusiveForwardListNode {};
+
+template <typename T>
+class IntrusiveForwardList;
+
+template <typename T>
+class IntrusiveForwardListIterator {
+private:
+  template <typename OtherT1, typename OtherT2>
+  friend
+      typename std::enable_if<std::is_same<const OtherT1, const OtherT2>::value,
+                              bool>::type
+      operator==(const IntrusiveForwardListIterator<OtherT1> &lhs,
+                 const IntrusiveForwardListIterator<OtherT2> &rhs);
+};
+
+template <typename T, typename OtherT>
+typename std::enable_if<std::is_same<const T, const OtherT>::value, bool>::type
+operator==(const IntrusiveForwardListIterator<T> &lhs,
+           const IntrusiveForwardListIterator<OtherT> &rhs) {
+  return false;
+}
+
+template <typename T, typename OtherT>
+typename std::enable_if<std::is_same<const T, const OtherT>::value, bool>::type
+operator!=(const IntrusiveForwardListIterator<T> &lhs,
+           const IntrusiveForwardListIterator<OtherT> &rhs) {
+  return false;
+}
+
+template <typename T>
+class IntrusiveForwardList {
+public:
+  typedef IntrusiveForwardListIterator<T> iterator;
+};
+
+} // namespace art
+
+namespace std {
+template <typename _Tp>
+struct numeric_limits {};
+
+template <>
+struct numeric_limits<unsigned short> {
+  static unsigned short max() { return __SHRT_MAX__ * 2U + 1; }
+};
+
+} // namespace std
+namespace art {
+namespace dex {
+
+template <typename T>
+class DexIndex {
+public:
+  T index_;
+
+  constexpr DexIndex() : index_(0) {}
+  explicit constexpr DexIndex(T idx) : index_(idx) {}
+
+  bool IsValid() const {
+    return index_ != std::numeric_limits<unsigned short>::max();
+  }
+  static constexpr DexIndex Invalid() { return DexIndex(0); }
+};
+
+class ProtoIndex : public DexIndex<unsigned short> {
+public:
+  ProtoIndex() {}
+  explicit constexpr ProtoIndex(unsigned short index)
+      : DexIndex<unsigned short>(index) {}
+  static constexpr ProtoIndex Invalid() { return ProtoIndex(0); }
+};
+
+} // namespace dex
+} // namespace art
+
+namespace std {
+
+template <typename>
+struct hash;
+
+template <>
+struct hash<unsigned short> : public __hash_base<size_t, unsigned short> {
+  size_t operator()(unsigned short __val) const noexcept {
+    return static_cast<size_t>(__val);
+  }
+};
+
+template <>
+struct hash<art::dex::ProtoIndex> {
+  size_t operator()(const art::dex::ProtoIndex &index) const {
+    return hash<decltype(index.index_)>()(index.index_);
+  }
+};
+
+} // namespace std
+
+namespace art {
+
+class HGraphVisitor;
+
+template <typename T>
+class HUseListNode : public IntrusiveForwardListNode<HUseListNode<T>> {};
+
+template <typename T>
+using HUseList = IntrusiveForwardList<HUseListNode<T>>;
+
+class HInstruction {
+public:
+  virtual ~HInstruction() {}
+
+  virtual void Accept(HGraphVisitor *visitor) = 0;
+  virtual const char *DebugName() const = 0;
+
+  bool IsVecOperation() const;
+  virtual bool InstructionDataEquals(const HInstruction *other) const {
+    return false;
+  }
+
+private:
+  void FixUpUserRecordsAfterUseInsertion(
+      HUseList<HInstruction *>::iterator fixup_end) {}
+};
+
+class HVecOperation : public HInstruction {
+public:
+  bool InstructionDataEquals(const HInstruction *other) const override {
+    other->IsVecOperation();
+    return false;
+  }
+};
+
+class HVecReduce final : public HVecOperation {
+public:
+  bool InstructionDataEquals(const HInstruction *other) const override {
+    return false;
+  }
+};
+
+class HGraphVisitor {
+public:
+  virtual ~HGraphVisitor() {}
+  virtual void VisitVecOperation(HVecOperation *instr) {}
+};
+
+inline bool HInstruction::IsVecOperation() const {
+  using BaseType = HVecOperation;
+  static constexpr bool results[] = {
+      std::is_base_of<BaseType, HVecReduce>::value,
+  };
+  return false;
+}
+
+} // namespace art
+
+namespace art {
+
+std::ostream &operator<<(std::ostream &os, const Location &location) {
+  return os;
+}
+
+} // namespace art
Index: clang/test/Analysis/ctu-astimport-virtual-assertion/Inputs/externalDefMap.txt
===================================================================
--- /dev/null
+++ clang/test/Analysis/ctu-astimport-virtual-assertion/Inputs/externalDefMap.txt
@@ -0,0 +1 @@
+71:c:@N@art@F@operator<<#&$@N@std@S@basic_ostream>#C#&1$@N@art@S@Location# input.cpp.ast
Index: clang/lib/AST/DeclCXX.cpp
===================================================================
--- clang/lib/AST/DeclCXX.cpp
+++ clang/lib/AST/DeclCXX.cpp
@@ -2455,7 +2455,6 @@
   assert(MD->isCanonicalDecl() && "Method is not canonical!");
   assert(!MD->getParent()->isDependentContext() &&
          "Can't add an overridden method to a class template!");
-  assert(MD->isVirtual() && "Method is not virtual!");
 
   getASTContext().addOverriddenMethod(this, MD);
 }
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to