Coverage Report

Created: 2019-07-24 05:18

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/clang/lib/Analysis/ConstructionContext.cpp
Line
Count
Source (jump to first uncovered line)
1
//===- ConstructionContext.cpp - CFG constructor information --------------===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
//
9
// This file defines the ConstructionContext class and its sub-classes,
10
// which represent various different ways of constructing C++ objects
11
// with the additional information the users may want to know about
12
// the constructor.
13
//
14
//===----------------------------------------------------------------------===//
15
16
#include "clang/Analysis/ConstructionContext.h"
17
#include "clang/AST/ExprObjC.h"
18
19
using namespace clang;
20
21
const ConstructionContextLayer *
22
ConstructionContextLayer::create(BumpVectorContext &C,
23
                                 const ConstructionContextItem &Item,
24
823k
                                 const ConstructionContextLayer *Parent) {
25
823k
  ConstructionContextLayer *CC =
26
823k
      C.getAllocator().Allocate<ConstructionContextLayer>();
27
823k
  return new (CC) ConstructionContextLayer(Item, Parent);
28
823k
}
29
30
bool ConstructionContextLayer::isStrictlyMoreSpecificThan(
31
0
    const ConstructionContextLayer *Other) const {
32
0
  const ConstructionContextLayer *Self = this;
33
0
  while (true) {
34
0
    if (!Other)
35
0
      return Self;
36
0
    if (!Self || !(Self->Item == Other->Item))
37
0
      return false;
38
0
    Self = Self->getParent();
39
0
    Other = Other->getParent();
40
0
  }
41
0
  llvm_unreachable("The above loop can only be terminated via return!");
42
0
}
43
44
const ConstructionContext *
45
ConstructionContext::createMaterializedTemporaryFromLayers(
46
    BumpVectorContext &C, const MaterializeTemporaryExpr *MTE,
47
    const CXXBindTemporaryExpr *BTE,
48
4.92k
    const ConstructionContextLayer *ParentLayer) {
49
4.92k
  assert(MTE);
50
4.92k
51
4.92k
  // If the object requires destruction and is not lifetime-extended,
52
4.92k
  // then it must have a BTE within its MTE, otherwise it shouldn't.
53
4.92k
  // FIXME: This should be an assertion.
54
4.92k
  if (!BTE && 
!(3.13k
MTE->getType().getCanonicalType()->getAsCXXRecordDecl()
55
3.13k
                    ->hasTrivialDestructor() ||
56
3.13k
                
MTE->getStorageDuration() != SD_FullExpression28
)) {
57
4
    return nullptr;
58
4
  }
59
4.92k
60
4.92k
  // If the temporary is lifetime-extended, don't save the BTE,
61
4.92k
  // because we don't need a temporary destructor, but an automatic
62
4.92k
  // destructor.
63
4.92k
  if (MTE->getStorageDuration() != SD_FullExpression) {
64
580
    BTE = nullptr;
65
580
  }
66
4.92k
67
4.92k
  // Handle pre-C++17 copy and move elision.
68
4.92k
  const CXXConstructExpr *ElidedCE = nullptr;
69
4.92k
  const ConstructionContext *ElidedCC = nullptr;
70
4.92k
  if (ParentLayer) {
71
2.59k
    const ConstructionContextItem &ElidedItem = ParentLayer->getItem();
72
2.59k
    assert(ElidedItem.getKind() ==
73
2.59k
           ConstructionContextItem::ElidableConstructorKind);
74
2.59k
    ElidedCE = cast<CXXConstructExpr>(ElidedItem.getStmt());
75
2.59k
    assert(ElidedCE->isElidable());
76
2.59k
    // We're creating a construction context that might have already
77
2.59k
    // been created elsewhere. Maybe we should unique our construction
78
2.59k
    // contexts. That's what we often do, but in this case it's unlikely
79
2.59k
    // to bring any benefits.
80
2.59k
    ElidedCC = createFromLayers(C, ParentLayer->getParent());
81
2.59k
    if (!ElidedCC) {
82
0
      // We may fail to create the elided construction context.
83
0
      // In this case, skip copy elision entirely.
84
0
      return create<SimpleTemporaryObjectConstructionContext>(C, BTE, MTE);
85
0
    }
86
2.59k
    return create<ElidedTemporaryObjectConstructionContext>(
87
2.59k
        C, BTE, MTE, ElidedCE, ElidedCC);
88
2.59k
  }
89
2.33k
90
2.33k
  // This is a normal temporary.
91
2.33k
  assert(!ParentLayer);
92
2.33k
  return create<SimpleTemporaryObjectConstructionContext>(C, BTE, MTE);
93
2.33k
}
94
95
const ConstructionContext *ConstructionContext::createBoundTemporaryFromLayers(
96
    BumpVectorContext &C, const CXXBindTemporaryExpr *BTE,
97
2.36k
    const ConstructionContextLayer *ParentLayer) {
98
2.36k
  if (!ParentLayer) {
99
250
    // A temporary object that doesn't require materialization.
100
250
    // In particular, it shouldn't require copy elision, because
101
250
    // copy/move constructors take a reference, which requires
102
250
    // materialization to obtain the glvalue.
103
250
    return create<SimpleTemporaryObjectConstructionContext>(C, BTE,
104
250
                                                            /*MTE=*/nullptr);
105
250
  }
106
2.11k
107
2.11k
  const ConstructionContextItem &ParentItem = ParentLayer->getItem();
108
2.11k
  switch (ParentItem.getKind()) {
109
2.11k
  case ConstructionContextItem::VariableKind: {
110
60
    const auto *DS = cast<DeclStmt>(ParentItem.getStmt());
111
60
    assert(!cast<VarDecl>(DS->getSingleDecl())->getType().getCanonicalType()
112
60
                            ->getAsCXXRecordDecl()->hasTrivialDestructor());
113
60
    return create<CXX17ElidedCopyVariableConstructionContext>(C, DS, BTE);
114
2.11k
  }
115
2.11k
  case ConstructionContextItem::NewAllocatorKind: {
116
0
    llvm_unreachable("This context does not accept a bound temporary!");
117
2.11k
  }
118
2.11k
  case ConstructionContextItem::ReturnKind: {
119
70
    assert(ParentLayer->isLast());
120
70
    const auto *RS = cast<ReturnStmt>(ParentItem.getStmt());
121
70
    assert(!RS->getRetValue()->getType().getCanonicalType()
122
70
              ->getAsCXXRecordDecl()->hasTrivialDestructor());
123
70
    return create<CXX17ElidedCopyReturnedValueConstructionContext>(C, RS,
124
70
                                                                   BTE);
125
2.11k
  }
126
2.11k
127
2.11k
  case ConstructionContextItem::MaterializationKind: {
128
1.79k
    // No assert. We may have an elidable copy on the grandparent layer.
129
1.79k
    const auto *MTE = cast<MaterializeTemporaryExpr>(ParentItem.getStmt());
130
1.79k
    return createMaterializedTemporaryFromLayers(C, MTE, BTE,
131
1.79k
                                                 ParentLayer->getParent());
132
2.11k
  }
133
2.11k
  case ConstructionContextItem::TemporaryDestructorKind: {
134
0
    llvm_unreachable("Duplicate CXXBindTemporaryExpr in the AST!");
135
2.11k
  }
136
2.11k
  case ConstructionContextItem::ElidedDestructorKind: {
137
0
    llvm_unreachable("Elided destructor items are not produced by the CFG!");
138
2.11k
  }
139
2.11k
  case ConstructionContextItem::ElidableConstructorKind: {
140
0
    llvm_unreachable("Materialization is necessary to put temporary into a "
141
2.11k
                     "copy or move constructor!");
142
2.11k
  }
143
2.11k
  case ConstructionContextItem::ArgumentKind: {
144
180
    assert(ParentLayer->isLast());
145
180
    const auto *E = cast<Expr>(ParentItem.getStmt());
146
180
    assert(isa<CallExpr>(E) || isa<CXXConstructExpr>(E) ||
147
180
           isa<ObjCMessageExpr>(E));
148
180
    return create<ArgumentConstructionContext>(C, E, ParentItem.getIndex(),
149
180
                                               BTE);
150
2.11k
  }
151
2.11k
  case ConstructionContextItem::InitializerKind: {
152
12
    assert(ParentLayer->isLast());
153
12
    const auto *I = ParentItem.getCXXCtorInitializer();
154
12
    assert(!I->getAnyMember()->getType().getCanonicalType()
155
12
             ->getAsCXXRecordDecl()->hasTrivialDestructor());
156
12
    return create<CXX17ElidedCopyConstructorInitializerConstructionContext>(
157
12
        C, I, BTE);
158
0
  }
159
0
  } // switch (ParentItem.getKind())
160
0
161
0
  llvm_unreachable("Unexpected construction context with destructor!");
162
0
}
163
164
const ConstructionContext *ConstructionContext::createFromLayers(
165
18.9k
    BumpVectorContext &C, const ConstructionContextLayer *TopLayer) {
166
18.9k
  // Before this point all we've had was a stockpile of arbitrary layers.
167
18.9k
  // Now validate that it is shaped as one of the finite amount of expected
168
18.9k
  // patterns.
169
18.9k
  const ConstructionContextItem &TopItem = TopLayer->getItem();
170
18.9k
  switch (TopItem.getKind()) {
171
18.9k
  case ConstructionContextItem::VariableKind: {
172
7.70k
    assert(TopLayer->isLast());
173
7.70k
    const auto *DS = cast<DeclStmt>(TopItem.getStmt());
174
7.70k
    return create<SimpleVariableConstructionContext>(C, DS);
175
18.9k
  }
176
18.9k
  case ConstructionContextItem::NewAllocatorKind: {
177
759
    assert(TopLayer->isLast());
178
759
    const auto *NE = cast<CXXNewExpr>(TopItem.getStmt());
179
759
    return create<NewAllocatedObjectConstructionContext>(C, NE);
180
18.9k
  }
181
18.9k
  case ConstructionContextItem::ReturnKind: {
182
1.22k
    assert(TopLayer->isLast());
183
1.22k
    const auto *RS = cast<ReturnStmt>(TopItem.getStmt());
184
1.22k
    return create<SimpleReturnedValueConstructionContext>(C, RS);
185
18.9k
  }
186
18.9k
  case ConstructionContextItem::MaterializationKind: {
187
3.13k
    const auto *MTE = cast<MaterializeTemporaryExpr>(TopItem.getStmt());
188
3.13k
    return createMaterializedTemporaryFromLayers(C, MTE, /*BTE=*/nullptr,
189
3.13k
                                                 TopLayer->getParent());
190
18.9k
  }
191
18.9k
  case ConstructionContextItem::TemporaryDestructorKind: {
192
2.36k
    const auto *BTE = cast<CXXBindTemporaryExpr>(TopItem.getStmt());
193
2.36k
    assert(BTE->getType().getCanonicalType()->getAsCXXRecordDecl()
194
2.36k
              ->hasNonTrivialDestructor());
195
2.36k
    return createBoundTemporaryFromLayers(C, BTE, TopLayer->getParent());
196
18.9k
  }
197
18.9k
  case ConstructionContextItem::ElidedDestructorKind: {
198
0
    llvm_unreachable("Elided destructor items are not produced by the CFG!");
199
18.9k
  }
200
18.9k
  case ConstructionContextItem::ElidableConstructorKind: {
201
0
    llvm_unreachable("The argument needs to be materialized first!");
202
18.9k
  }
203
18.9k
  case ConstructionContextItem::InitializerKind: {
204
2.20k
    assert(TopLayer->isLast());
205
2.20k
    const CXXCtorInitializer *I = TopItem.getCXXCtorInitializer();
206
2.20k
    return create<SimpleConstructorInitializerConstructionContext>(C, I);
207
18.9k
  }
208
18.9k
  case ConstructionContextItem::ArgumentKind: {
209
1.55k
    assert(TopLayer->isLast());
210
1.55k
    const auto *E = cast<Expr>(TopItem.getStmt());
211
1.55k
    return create<ArgumentConstructionContext>(C, E, TopItem.getIndex(),
212
1.55k
                                               /*BTE=*/nullptr);
213
0
  }
214
0
  } // switch (TopItem.getKind())
215
0
  llvm_unreachable("Unexpected construction context!");
216
0
}