diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp --- a/clang/lib/AST/DeclCXX.cpp +++ b/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); } diff --git a/clang/test/Analysis/ctu-astimport-virtual-assertion/Inputs/externalDefMap.txt b/clang/test/Analysis/ctu-astimport-virtual-assertion/Inputs/externalDefMap.txt new file mode 100644 --- /dev/null +++ b/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 diff --git a/clang/test/Analysis/ctu-astimport-virtual-assertion/Inputs/input.h b/clang/test/Analysis/ctu-astimport-virtual-assertion/Inputs/input.h new file mode 100644 --- /dev/null +++ b/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 +class basic_ostream {}; + +typedef basic_ostream 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_ diff --git a/clang/test/Analysis/ctu-astimport-virtual-assertion/Inputs/input.cpp b/clang/test/Analysis/ctu-astimport-virtual-assertion/Inputs/input.cpp new file mode 100644 --- /dev/null +++ b/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 +struct integral_constant { + static constexpr _Tp value = __v; + typedef _Tp value_type; + typedef integral_constant<_Tp, __v> type; +}; +using false_type = integral_constant; +using true_type = integral_constant; + +template +struct is_base_of + : public integral_constant {}; + +template +struct is_enum : public integral_constant {}; + +template +struct __hash_base { + typedef _Result result_type; + typedef _Arg argument_type; +}; + +template ::value> +struct __hash_enum { +private: + // Private rather than deleted to be non-trivially-copyable. + __hash_enum(__hash_enum &&); + ~__hash_enum(); +}; + +template ::value> +struct __underlying_type_impl { + using type = __underlying_type(_Tp); +}; + +template +struct __underlying_type_impl<_Tp, false> {}; +/// @endcond + +/// The underlying type of an enum. +template +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 +struct hash : __hash_enum<_Tp> {}; + +// Helper struct for hash with enum types. +template +struct __hash_enum<_Tp, true> : public __hash_base { + size_t operator()(_Tp __val) const noexcept { + using __type = typename underlying_type<_Tp>::type; + return hash<__type>{}(static_cast<__type>(__val)); + } +}; + +template +struct hash<_Tp *> : public __hash_base { + size_t operator()(_Tp *__p) const noexcept { + return reinterpret_cast(__p); + } +}; + +template +struct is_same : public false_type {}; + +template +struct is_same<_Tp, _Tp> : public true_type {}; + +template +struct enable_if {}; + +template +struct enable_if { + typedef _Tp type; +}; + +} // namespace std + +namespace art { + +template +struct IntrusiveForwardListNode {}; + +template +class IntrusiveForwardList; + +template +class IntrusiveForwardListIterator { +private: + template + friend + typename std::enable_if::value, + bool>::type + operator==(const IntrusiveForwardListIterator &lhs, + const IntrusiveForwardListIterator &rhs); +}; + +template +typename std::enable_if::value, bool>::type +operator==(const IntrusiveForwardListIterator &lhs, + const IntrusiveForwardListIterator &rhs) { + return false; +} + +template +typename std::enable_if::value, bool>::type +operator!=(const IntrusiveForwardListIterator &lhs, + const IntrusiveForwardListIterator &rhs) { + return false; +} + +template +class IntrusiveForwardList { +public: + typedef IntrusiveForwardListIterator iterator; +}; + +} // namespace art + +namespace std { +template +struct numeric_limits {}; + +template <> +struct numeric_limits { + static unsigned short max() { return __SHRT_MAX__ * 2U + 1; } +}; + +} // namespace std +namespace art { +namespace dex { + +template +class DexIndex { +public: + T index_; + + constexpr DexIndex() : index_(0) {} + explicit constexpr DexIndex(T idx) : index_(idx) {} + + bool IsValid() const { + return index_ != std::numeric_limits::max(); + } + static constexpr DexIndex Invalid() { return DexIndex(0); } +}; + +class ProtoIndex : public DexIndex { +public: + ProtoIndex() {} + explicit constexpr ProtoIndex(unsigned short index) + : DexIndex(index) {} + static constexpr ProtoIndex Invalid() { return ProtoIndex(0); } +}; + +} // namespace dex +} // namespace art + +namespace std { + +template +struct hash; + +template <> +struct hash : public __hash_base { + size_t operator()(unsigned short __val) const noexcept { + return static_cast(__val); + } +}; + +template <> +struct hash { + size_t operator()(const art::dex::ProtoIndex &index) const { + return hash()(index.index_); + } +}; + +} // namespace std + +namespace art { + +class HGraphVisitor; + +template +class HUseListNode : public IntrusiveForwardListNode> {}; + +template +using HUseList = IntrusiveForwardList>; + +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::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::value, + }; + return false; +} + +} // namespace art + +namespace art { + +std::ostream &operator<<(std::ostream &os, const Location &location) { + return os; +} + +} // namespace art diff --git a/clang/test/Analysis/ctu-astimport-virtual-assertion/main.cpp b/clang/test/Analysis/ctu-astimport-virtual-assertion/main.cpp new file mode 100644 --- /dev/null +++ b/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"