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