]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/Analysis/ConstructionContext.cpp
Vendor import of clang trunk r338150:
[FreeBSD/FreeBSD.git] / lib / Analysis / ConstructionContext.cpp
1 //===- ConstructionContext.cpp - CFG constructor information --------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file defines the ConstructionContext class and its sub-classes,
11 // which represent various different ways of constructing C++ objects
12 // with the additional information the users may want to know about
13 // the constructor.
14 //
15 //===----------------------------------------------------------------------===//
16
17 #include "clang/Analysis/ConstructionContext.h"
18
19 using namespace clang;
20
21 const ConstructionContextLayer *
22 ConstructionContextLayer::create(BumpVectorContext &C, TriggerTy Trigger,
23                                  const ConstructionContextLayer *Parent) {
24   ConstructionContextLayer *CC =
25       C.getAllocator().Allocate<ConstructionContextLayer>();
26   return new (CC) ConstructionContextLayer(Trigger, Parent);
27 }
28
29 bool ConstructionContextLayer::isStrictlyMoreSpecificThan(
30     const ConstructionContextLayer *Other) const {
31   const ConstructionContextLayer *Self = this;
32   while (true) {
33     if (!Other)
34       return Self;
35     if (!Self || !Self->isSameLayer(Other))
36       return false;
37     Self = Self->getParent();
38     Other = Other->getParent();
39   }
40   llvm_unreachable("The above loop can only be terminated via return!");
41 }
42
43 const ConstructionContext *ConstructionContext::createFromLayers(
44     BumpVectorContext &C, const ConstructionContextLayer *TopLayer) {
45   // Before this point all we've had was a stockpile of arbitrary layers.
46   // Now validate that it is shaped as one of the finite amount of expected
47   // patterns.
48   if (const Stmt *S = TopLayer->getTriggerStmt()) {
49     if (const auto *DS = dyn_cast<DeclStmt>(S)) {
50       assert(TopLayer->isLast());
51       return create<SimpleVariableConstructionContext>(C, DS);
52     }
53     if (const auto *NE = dyn_cast<CXXNewExpr>(S)) {
54       assert(TopLayer->isLast());
55       return create<NewAllocatedObjectConstructionContext>(C, NE);
56     }
57     if (const auto *BTE = dyn_cast<CXXBindTemporaryExpr>(S)) {
58       const MaterializeTemporaryExpr *MTE = nullptr;
59       assert(BTE->getType().getCanonicalType()
60                 ->getAsCXXRecordDecl()->hasNonTrivialDestructor());
61       // For temporaries with destructors, there may or may not be
62       // lifetime extension on the parent layer.
63       if (const ConstructionContextLayer *ParentLayer = TopLayer->getParent()) {
64         // C++17 *requires* elision of the constructor at the return site
65         // and at variable/member initialization site, while previous standards
66         // were allowing an optional elidable constructor.
67         // This is the C++17 copy-elided construction into a ctor initializer.
68         if (const CXXCtorInitializer *I = ParentLayer->getTriggerInit()) {
69           return create<
70               CXX17ElidedCopyConstructorInitializerConstructionContext>(C,
71                                                                         I, BTE);
72         }
73         assert(ParentLayer->getTriggerStmt() &&
74                "Non-statement-based layers have been handled above!");
75         // This is the normal, non-C++17 case: a temporary object which has
76         // both destruction and materialization info attached to it in the AST.
77         if ((MTE = dyn_cast<MaterializeTemporaryExpr>(
78                  ParentLayer->getTriggerStmt()))) {
79           if (MTE->getStorageDuration() != SD_FullExpression) {
80             // If the temporary is lifetime-extended, don't save the BTE,
81             // because we don't need a temporary destructor, but an automatic
82             // destructor.
83             BTE = nullptr;
84           }
85
86           // Handle pre-C++17 copy and move elision.
87           const CXXConstructExpr *ElidedCE = nullptr;
88           const ConstructionContext *ElidedCC = nullptr;
89           if (const ConstructionContextLayer *ElidedLayer =
90                   ParentLayer->getParent()) {
91             ElidedCE = cast<CXXConstructExpr>(ElidedLayer->getTriggerStmt());
92             assert(ElidedCE->isElidable());
93             // We're creating a construction context that might have already
94             // been created elsewhere. Maybe we should unique our construction
95             // contexts. That's what we often do, but in this case it's unlikely
96             // to bring any benefits.
97             ElidedCC = createFromLayers(C, ElidedLayer->getParent());
98             if (!ElidedCC) {
99               // We may fail to create the elided construction context.
100               // In this case, skip copy elision entirely.
101               return create<SimpleTemporaryObjectConstructionContext>(C, BTE,
102                                                                       MTE);
103             } else {
104               return create<ElidedTemporaryObjectConstructionContext>(
105                   C, BTE, MTE, ElidedCE, ElidedCC);
106             }
107           }
108           assert(ParentLayer->isLast());
109           return create<SimpleTemporaryObjectConstructionContext>(C, BTE, MTE);
110         }
111         assert(ParentLayer->isLast());
112
113         // This is a constructor into a function argument. Not implemented yet.
114         if (isa<CallExpr>(ParentLayer->getTriggerStmt()))
115           return nullptr;
116         // This is C++17 copy-elided construction into return statement.
117         if (auto *RS = dyn_cast<ReturnStmt>(ParentLayer->getTriggerStmt())) {
118           assert(!RS->getRetValue()->getType().getCanonicalType()
119                     ->getAsCXXRecordDecl()->hasTrivialDestructor());
120           return create<CXX17ElidedCopyReturnedValueConstructionContext>(C,
121                                                                        RS, BTE);
122         }
123         // This is C++17 copy-elided construction into a simple variable.
124         if (auto *DS = dyn_cast<DeclStmt>(ParentLayer->getTriggerStmt())) {
125           assert(!cast<VarDecl>(DS->getSingleDecl())->getType()
126                       .getCanonicalType()->getAsCXXRecordDecl()
127                       ->hasTrivialDestructor());
128           return create<CXX17ElidedCopyVariableConstructionContext>(C, DS, BTE);
129         }
130         llvm_unreachable("Unexpected construction context with destructor!");
131       }
132       // A temporary object that doesn't require materialization.
133       // In particular, it shouldn't require copy elision, because
134       // copy/move constructors take a reference, which requires
135       // materialization to obtain the glvalue.
136       return create<SimpleTemporaryObjectConstructionContext>(C, BTE,
137                                                               /*MTE=*/nullptr);
138     }
139     if (const auto *MTE = dyn_cast<MaterializeTemporaryExpr>(S)) {
140       // If the object requires destruction and is not lifetime-extended,
141       // then it must have a BTE within its MTE.
142       // FIXME: This should be an assertion.
143       if (!(MTE->getType().getCanonicalType()
144                 ->getAsCXXRecordDecl()->hasTrivialDestructor() ||
145              MTE->getStorageDuration() != SD_FullExpression))
146         return nullptr;
147
148       // Handle pre-C++17 copy and move elision.
149       const CXXConstructExpr *ElidedCE = nullptr;
150       const ConstructionContext *ElidedCC = nullptr;
151       if (const ConstructionContextLayer *ElidedLayer = TopLayer->getParent()) {
152         ElidedCE = cast<CXXConstructExpr>(ElidedLayer->getTriggerStmt());
153         assert(ElidedCE->isElidable());
154         // We're creating a construction context that might have already
155         // been created elsewhere. Maybe we should unique our construction
156         // contexts. That's what we often do, but in this case it's unlikely
157         // to bring any benefits.
158         ElidedCC = createFromLayers(C, ElidedLayer->getParent());
159         if (!ElidedCC) {
160           // We may fail to create the elided construction context.
161           // In this case, skip copy elision entirely.
162           return create<SimpleTemporaryObjectConstructionContext>(C, nullptr,
163                                                                   MTE);
164         }
165         return create<ElidedTemporaryObjectConstructionContext>(
166             C, nullptr, MTE, ElidedCE, ElidedCC);
167       }
168       assert(TopLayer->isLast());
169       return create<SimpleTemporaryObjectConstructionContext>(C, nullptr, MTE);
170     }
171     if (const auto *RS = dyn_cast<ReturnStmt>(S)) {
172       assert(TopLayer->isLast());
173       return create<SimpleReturnedValueConstructionContext>(C, RS);
174     }
175     // This is a constructor into a function argument. Not implemented yet.
176     if (isa<CallExpr>(TopLayer->getTriggerStmt()))
177       return nullptr;
178     llvm_unreachable("Unexpected construction context with statement!");
179   } else if (const CXXCtorInitializer *I = TopLayer->getTriggerInit()) {
180     assert(TopLayer->isLast());
181     return create<SimpleConstructorInitializerConstructionContext>(C, I);
182   }
183   llvm_unreachable("Unexpected construction context!");
184 }