MemMoveAnnotation.h (3062B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 #ifndef MemMoveAnnotation_h__ 6 #define MemMoveAnnotation_h__ 7 8 #include "CustomMatchers.h" 9 #include "CustomTypeAnnotation.h" 10 #include "Utils.h" 11 12 13 class MemMoveAnnotation final : public CustomTypeAnnotation { 14 public: 15 MemMoveAnnotation() 16 : CustomTypeAnnotation(moz_non_memmovable, "non-memmove()able") {} 17 18 virtual ~MemMoveAnnotation() {} 19 20 protected: 21 static bool is_trivially_relocatable(const TagDecl *D) { 22 if (auto RD = dyn_cast<CXXRecordDecl>(D)) { 23 // Trivially relocatable trait 24 if (RD->isCompleteDefinition() && 25 (RD->hasTrivialMoveConstructor() || 26 (!RD->hasMoveConstructor() && RD->hasTrivialCopyConstructor())) && 27 RD->hasTrivialDestructor()) { 28 return true; 29 } 30 // Extension for std::unique_ptr 31 if (auto *Spec = dyn_cast<ClassTemplateSpecializationDecl>(RD)) { 32 if (getDeclarationNamespace(D) == "std" && 33 (getNameChecked(D) == "unique_ptr")) { 34 unsigned ParameterIndex = 0; 35 const auto &TArgs = Spec->getTemplateArgs(); 36 if (TArgs.size() != 2) { 37 return false; // should not happen 38 } 39 // Skip the first parameter, it's used to store the pointer and 40 // doesn't force any requirement on the unique_ptr 41 const auto &Deleter = TArgs[1]; 42 if (Deleter.getKind() != TemplateArgument::Type) 43 return false; 44 QualType DeleterTy = Deleter.getAsType(); 45 if (const auto *TD = DeleterTy->getAsTagDecl()) { 46 return is_trivially_relocatable(TD); 47 } else { 48 return false; // should not happen 49 } 50 } 51 } 52 } 53 return false; 54 } 55 56 std::string getImplicitReason(const TagDecl *D, 57 VisitFlags &ToVisit) const override { 58 // Annotate everything in ::std, with a few exceptions; see bug 59 // 1201314 for discussion. 60 if (getDeclarationNamespace(D) != "std") { 61 return ""; 62 } 63 64 StringRef Name = getNameChecked(D); 65 66 // If the type has a trivial move constructor and destructor, it is safe to 67 // memmove, and we don't need to visit any fields. 68 if (is_trivially_relocatable(D)) { 69 ToVisit = VISIT_NONE; 70 return ""; 71 } 72 73 // This doesn't check that it's really ::std::pair and not 74 // ::std::something_else::pair, but should be good enough. 75 if (isNameExcepted(Name.data())) { 76 // If we're an excepted name, stop traversing within the type further, 77 // and only check template arguments for foreign types. 78 ToVisit = VISIT_TMPL_ARGS; 79 return ""; 80 } 81 return "it is an stl-provided type not guaranteed to be memmove-able"; 82 } 83 84 private: 85 bool isNameExcepted(StringRef Name) const { 86 return Name == "pair" || Name == "atomic" || Name == "tuple"; 87 } 88 }; 89 90 extern MemMoveAnnotation NonMemMovable; 91 92 #endif