File: MemMoveAnnotation.h

package info (click to toggle)
firefox 147.0.4-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 4,683,532 kB
  • sloc: cpp: 7,607,356; javascript: 6,533,348; ansic: 3,775,236; python: 1,415,508; xml: 634,561; asm: 438,949; java: 186,241; sh: 62,760; makefile: 18,079; objc: 13,092; perl: 12,808; yacc: 4,583; cs: 3,846; pascal: 3,448; lex: 1,720; ruby: 1,003; php: 436; lisp: 258; awk: 247; sql: 66; sed: 54; csh: 10; exp: 6
file content (92 lines) | stat: -rw-r--r-- 3,062 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef MemMoveAnnotation_h__
#define MemMoveAnnotation_h__

#include "CustomMatchers.h"
#include "CustomTypeAnnotation.h"
#include "Utils.h"


class MemMoveAnnotation final : public CustomTypeAnnotation {
public:
  MemMoveAnnotation()
      : CustomTypeAnnotation(moz_non_memmovable, "non-memmove()able") {}

  virtual ~MemMoveAnnotation() {}

protected:
  static bool is_trivially_relocatable(const TagDecl *D) {
    if (auto RD = dyn_cast<CXXRecordDecl>(D)) {
      // Trivially relocatable trait
      if (RD->isCompleteDefinition() &&
          (RD->hasTrivialMoveConstructor() ||
           (!RD->hasMoveConstructor() && RD->hasTrivialCopyConstructor())) &&
          RD->hasTrivialDestructor()) {
        return true;
      }
      // Extension for std::unique_ptr
      if (auto *Spec = dyn_cast<ClassTemplateSpecializationDecl>(RD)) {
        if (getDeclarationNamespace(D) == "std" &&
            (getNameChecked(D) == "unique_ptr")) {
          unsigned ParameterIndex = 0;
          const auto &TArgs = Spec->getTemplateArgs();
          if (TArgs.size() != 2) {
            return false; // should not happen
          }
          // Skip the first parameter, it's used to store the pointer and
          // doesn't force any requirement on the unique_ptr
          const auto &Deleter = TArgs[1];
          if (Deleter.getKind() != TemplateArgument::Type)
            return false;
          QualType DeleterTy = Deleter.getAsType();
          if (const auto *TD = DeleterTy->getAsTagDecl()) {
            return is_trivially_relocatable(TD);
          } else {
            return false; // should not happen
          }
        }
      }
    }
    return false;
  }

  std::string getImplicitReason(const TagDecl *D,
                                VisitFlags &ToVisit) const override {
    // Annotate everything in ::std, with a few exceptions; see bug
    // 1201314 for discussion.
    if (getDeclarationNamespace(D) != "std") {
      return "";
    }

    StringRef Name = getNameChecked(D);

    // If the type has a trivial move constructor and destructor, it is safe to
    // memmove, and we don't need to visit any fields.
    if (is_trivially_relocatable(D)) {
      ToVisit = VISIT_NONE;
      return "";
    }

    // This doesn't check that it's really ::std::pair and not
    // ::std::something_else::pair, but should be good enough.
    if (isNameExcepted(Name.data())) {
      // If we're an excepted name, stop traversing within the type further,
      // and only check template arguments for foreign types.
      ToVisit = VISIT_TMPL_ARGS;
      return "";
    }
    return "it is an stl-provided type not guaranteed to be memmove-able";
  }

private:
  bool isNameExcepted(StringRef Name) const {
    return Name == "pair" || Name == "atomic" || Name == "tuple";
  }
};

extern MemMoveAnnotation NonMemMovable;

#endif