1 //===- ConstructionContext.h - CFG constructor information ------*- C++ -*-===// 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 #ifndef LLVM_CLANG_ANALYSIS_CONSTRUCTIONCONTEXT_H 17 #define LLVM_CLANG_ANALYSIS_CONSTRUCTIONCONTEXT_H 18 19 #include "clang/Analysis/Support/BumpVector.h" 20 #include "clang/AST/ExprCXX.h" 21 #include "clang/AST/ExprObjC.h" 22 23 namespace clang { 24 25 /// Represents a single point (AST node) in the program that requires attention 26 /// during construction of an object. ConstructionContext would be represented 27 /// as a list of such items. 28 class ConstructionContextItem { 29 public: 30 enum ItemKind { 31 VariableKind, 32 NewAllocatorKind, 33 ReturnKind, 34 MaterializationKind, 35 TemporaryDestructorKind, 36 ElidedDestructorKind, 37 ElidableConstructorKind, 38 ArgumentKind, 39 STATEMENT_WITH_INDEX_KIND_BEGIN=ArgumentKind, 40 STATEMENT_WITH_INDEX_KIND_END=ArgumentKind, 41 STATEMENT_KIND_BEGIN = VariableKind, 42 STATEMENT_KIND_END = ArgumentKind, 43 InitializerKind, 44 INITIALIZER_KIND_BEGIN=InitializerKind, 45 INITIALIZER_KIND_END=InitializerKind 46 }; 47 getKindAsString(ItemKind K)48 LLVM_DUMP_METHOD static StringRef getKindAsString(ItemKind K) { 49 switch (K) { 50 case VariableKind: return "construct into local variable"; 51 case NewAllocatorKind: return "construct into new-allocator"; 52 case ReturnKind: return "construct into return address"; 53 case MaterializationKind: return "materialize temporary"; 54 case TemporaryDestructorKind: return "destroy temporary"; 55 case ElidedDestructorKind: return "elide destructor"; 56 case ElidableConstructorKind: return "elide constructor"; 57 case ArgumentKind: return "construct into argument"; 58 case InitializerKind: return "construct into member variable"; 59 }; 60 llvm_unreachable("Unknown ItemKind"); 61 } 62 63 private: 64 const void *const Data; 65 const ItemKind Kind; 66 const unsigned Index = 0; 67 hasStatement()68 bool hasStatement() const { 69 return Kind >= STATEMENT_KIND_BEGIN && 70 Kind <= STATEMENT_KIND_END; 71 } 72 hasIndex()73 bool hasIndex() const { 74 return Kind >= STATEMENT_WITH_INDEX_KIND_BEGIN && 75 Kind >= STATEMENT_WITH_INDEX_KIND_END; 76 } 77 hasInitializer()78 bool hasInitializer() const { 79 return Kind >= INITIALIZER_KIND_BEGIN && 80 Kind <= INITIALIZER_KIND_END; 81 } 82 83 public: 84 // ConstructionContextItem should be simple enough so that it was easy to 85 // re-construct it from the AST node it captures. For that reason we provide 86 // simple implicit conversions from all sorts of supported AST nodes. ConstructionContextItem(const DeclStmt * DS)87 ConstructionContextItem(const DeclStmt *DS) 88 : Data(DS), Kind(VariableKind) {} 89 ConstructionContextItem(const CXXNewExpr * NE)90 ConstructionContextItem(const CXXNewExpr *NE) 91 : Data(NE), Kind(NewAllocatorKind) {} 92 ConstructionContextItem(const ReturnStmt * RS)93 ConstructionContextItem(const ReturnStmt *RS) 94 : Data(RS), Kind(ReturnKind) {} 95 ConstructionContextItem(const MaterializeTemporaryExpr * MTE)96 ConstructionContextItem(const MaterializeTemporaryExpr *MTE) 97 : Data(MTE), Kind(MaterializationKind) {} 98 99 ConstructionContextItem(const CXXBindTemporaryExpr *BTE, 100 bool IsElided = false) Data(BTE)101 : Data(BTE), 102 Kind(IsElided ? ElidedDestructorKind : TemporaryDestructorKind) {} 103 ConstructionContextItem(const CXXConstructExpr * CE)104 ConstructionContextItem(const CXXConstructExpr *CE) 105 : Data(CE), Kind(ElidableConstructorKind) {} 106 ConstructionContextItem(const CallExpr * CE,unsigned Index)107 ConstructionContextItem(const CallExpr *CE, unsigned Index) 108 : Data(CE), Kind(ArgumentKind), Index(Index) {} 109 ConstructionContextItem(const CXXConstructExpr * CE,unsigned Index)110 ConstructionContextItem(const CXXConstructExpr *CE, unsigned Index) 111 : Data(CE), Kind(ArgumentKind), Index(Index) {} 112 ConstructionContextItem(const CXXInheritedCtorInitExpr * CE,unsigned Index)113 ConstructionContextItem(const CXXInheritedCtorInitExpr *CE, unsigned Index) 114 : Data(CE), Kind(ArgumentKind), Index(Index) {} 115 ConstructionContextItem(const ObjCMessageExpr * ME,unsigned Index)116 ConstructionContextItem(const ObjCMessageExpr *ME, unsigned Index) 117 : Data(ME), Kind(ArgumentKind), Index(Index) {} 118 119 // A polymorphic version of the previous calls with dynamic type check. ConstructionContextItem(const Expr * E,unsigned Index)120 ConstructionContextItem(const Expr *E, unsigned Index) 121 : Data(E), Kind(ArgumentKind), Index(Index) { 122 assert(isa<CallExpr>(E) || isa<CXXConstructExpr>(E) || 123 isa<CXXInheritedCtorInitExpr>(E) || isa<ObjCMessageExpr>(E)); 124 } 125 ConstructionContextItem(const CXXCtorInitializer * Init)126 ConstructionContextItem(const CXXCtorInitializer *Init) 127 : Data(Init), Kind(InitializerKind), Index(0) {} 128 getKind()129 ItemKind getKind() const { return Kind; } 130 getKindAsString()131 LLVM_DUMP_METHOD StringRef getKindAsString() const { 132 return getKindAsString(getKind()); 133 } 134 135 /// The construction site - the statement that triggered the construction 136 /// for one of its parts. For instance, stack variable declaration statement 137 /// triggers construction of itself or its elements if it's an array, 138 /// new-expression triggers construction of the newly allocated object(s). getStmt()139 const Stmt *getStmt() const { 140 assert(hasStatement()); 141 return static_cast<const Stmt *>(Data); 142 } 143 getStmtOrNull()144 const Stmt *getStmtOrNull() const { 145 return hasStatement() ? getStmt() : nullptr; 146 } 147 148 /// The construction site is not necessarily a statement. It may also be a 149 /// CXXCtorInitializer, which means that a member variable is being 150 /// constructed during initialization of the object that contains it. getCXXCtorInitializer()151 const CXXCtorInitializer *getCXXCtorInitializer() const { 152 assert(hasInitializer()); 153 return static_cast<const CXXCtorInitializer *>(Data); 154 } 155 156 /// If a single trigger statement triggers multiple constructors, they are 157 /// usually being enumerated. This covers function argument constructors 158 /// triggered by a call-expression and items in an initializer list triggered 159 /// by an init-list-expression. getIndex()160 unsigned getIndex() const { 161 // This is a fairly specific request. Let's make sure the user knows 162 // what he's doing. 163 assert(hasIndex()); 164 return Index; 165 } 166 Profile(llvm::FoldingSetNodeID & ID)167 void Profile(llvm::FoldingSetNodeID &ID) const { 168 ID.AddPointer(Data); 169 ID.AddInteger(Kind); 170 ID.AddInteger(Index); 171 } 172 173 bool operator==(const ConstructionContextItem &Other) const { 174 // For most kinds the Index comparison is trivially true, but 175 // checking kind separately doesn't seem to be less expensive 176 // than checking Index. Same in operator<(). 177 return std::make_tuple(Data, Kind, Index) == 178 std::make_tuple(Other.Data, Other.Kind, Other.Index); 179 } 180 181 bool operator<(const ConstructionContextItem &Other) const { 182 return std::make_tuple(Data, Kind, Index) < 183 std::make_tuple(Other.Data, Other.Kind, Other.Index); 184 } 185 }; 186 187 /// Construction context can be seen as a linked list of multiple layers. 188 /// Sometimes a single trigger is not enough to describe the construction 189 /// site. That's what causing us to have a chain of "partial" construction 190 /// context layers. Some examples: 191 /// - A constructor within in an aggregate initializer list within a variable 192 /// would have a construction context of the initializer list with 193 /// the parent construction context of a variable. 194 /// - A constructor for a temporary that needs to be both destroyed 195 /// and materialized into an elidable copy constructor would have a 196 /// construction context of a CXXBindTemporaryExpr with the parent 197 /// construction context of a MaterializeTemproraryExpr. 198 /// Not all of these are currently supported. 199 /// Layers are created gradually while traversing the AST, and layers that 200 /// represent the outmost AST nodes are built first, while the node that 201 /// immediately contains the constructor would be built last and capture the 202 /// previous layers as its parents. Construction context captures the last layer 203 /// (which has links to the previous layers) and classifies the seemingly 204 /// arbitrary chain of layers into one of the possible ways of constructing 205 /// an object in C++ for user-friendly experience. 206 class ConstructionContextLayer { 207 const ConstructionContextLayer *Parent = nullptr; 208 ConstructionContextItem Item; 209 ConstructionContextLayer(ConstructionContextItem Item,const ConstructionContextLayer * Parent)210 ConstructionContextLayer(ConstructionContextItem Item, 211 const ConstructionContextLayer *Parent) 212 : Parent(Parent), Item(Item) {} 213 214 public: 215 static const ConstructionContextLayer * 216 create(BumpVectorContext &C, const ConstructionContextItem &Item, 217 const ConstructionContextLayer *Parent = nullptr); 218 getItem()219 const ConstructionContextItem &getItem() const { return Item; } getParent()220 const ConstructionContextLayer *getParent() const { return Parent; } isLast()221 bool isLast() const { return !Parent; } 222 223 /// See if Other is a proper initial segment of this construction context 224 /// in terms of the parent chain - i.e. a few first parents coincide and 225 /// then the other context terminates but our context goes further - i.e., 226 /// we are providing the same context that the other context provides, 227 /// and a bit more above that. 228 bool isStrictlyMoreSpecificThan(const ConstructionContextLayer *Other) const; 229 }; 230 231 232 /// ConstructionContext's subclasses describe different ways of constructing 233 /// an object in C++. The context re-captures the essential parent AST nodes 234 /// of the CXXConstructExpr it is assigned to and presents these nodes 235 /// through easy-to-understand accessor methods. 236 class ConstructionContext { 237 public: 238 enum Kind { 239 SimpleVariableKind, 240 CXX17ElidedCopyVariableKind, 241 VARIABLE_BEGIN = SimpleVariableKind, 242 VARIABLE_END = CXX17ElidedCopyVariableKind, 243 SimpleConstructorInitializerKind, 244 CXX17ElidedCopyConstructorInitializerKind, 245 INITIALIZER_BEGIN = SimpleConstructorInitializerKind, 246 INITIALIZER_END = CXX17ElidedCopyConstructorInitializerKind, 247 NewAllocatedObjectKind, 248 SimpleTemporaryObjectKind, 249 ElidedTemporaryObjectKind, 250 TEMPORARY_BEGIN = SimpleTemporaryObjectKind, 251 TEMPORARY_END = ElidedTemporaryObjectKind, 252 SimpleReturnedValueKind, 253 CXX17ElidedCopyReturnedValueKind, 254 RETURNED_VALUE_BEGIN = SimpleReturnedValueKind, 255 RETURNED_VALUE_END = CXX17ElidedCopyReturnedValueKind, 256 ArgumentKind 257 }; 258 259 protected: 260 Kind K; 261 262 // Do not make public! These need to only be constructed 263 // via createFromLayers(). ConstructionContext(Kind K)264 explicit ConstructionContext(Kind K) : K(K) {} 265 266 private: 267 // A helper function for constructing an instance into a bump vector context. 268 template <typename T, typename... ArgTypes> create(BumpVectorContext & C,ArgTypes...Args)269 static T *create(BumpVectorContext &C, ArgTypes... Args) { 270 auto *CC = C.getAllocator().Allocate<T>(); 271 return new (CC) T(Args...); 272 } 273 274 // A sub-routine of createFromLayers() that deals with temporary objects 275 // that need to be materialized. The BTE argument is for the situation when 276 // the object also needs to be bound for destruction. 277 static const ConstructionContext *createMaterializedTemporaryFromLayers( 278 BumpVectorContext &C, const MaterializeTemporaryExpr *MTE, 279 const CXXBindTemporaryExpr *BTE, 280 const ConstructionContextLayer *ParentLayer); 281 282 // A sub-routine of createFromLayers() that deals with temporary objects 283 // that need to be bound for destruction. Automatically finds out if the 284 // object also needs to be materialized and delegates to 285 // createMaterializedTemporaryFromLayers() if necessary. 286 static const ConstructionContext * 287 createBoundTemporaryFromLayers( 288 BumpVectorContext &C, const CXXBindTemporaryExpr *BTE, 289 const ConstructionContextLayer *ParentLayer); 290 291 public: 292 /// Consume the construction context layer, together with its parent layers, 293 /// and wrap it up into a complete construction context. May return null 294 /// if layers do not form any supported construction context. 295 static const ConstructionContext * 296 createFromLayers(BumpVectorContext &C, 297 const ConstructionContextLayer *TopLayer); 298 getKind()299 Kind getKind() const { return K; } 300 }; 301 302 /// An abstract base class for local variable constructors. 303 class VariableConstructionContext : public ConstructionContext { 304 const DeclStmt *DS; 305 306 protected: VariableConstructionContext(ConstructionContext::Kind K,const DeclStmt * DS)307 VariableConstructionContext(ConstructionContext::Kind K, const DeclStmt *DS) 308 : ConstructionContext(K), DS(DS) { 309 assert(classof(this)); 310 assert(DS); 311 } 312 313 public: getDeclStmt()314 const DeclStmt *getDeclStmt() const { return DS; } 315 classof(const ConstructionContext * CC)316 static bool classof(const ConstructionContext *CC) { 317 return CC->getKind() >= VARIABLE_BEGIN && 318 CC->getKind() <= VARIABLE_END; 319 } 320 }; 321 322 /// Represents construction into a simple local variable, eg. T var(123);. 323 /// If a variable has an initializer, eg. T var = makeT();, then the final 324 /// elidable copy-constructor from makeT() into var would also be a simple 325 /// variable constructor handled by this class. 326 class SimpleVariableConstructionContext : public VariableConstructionContext { 327 friend class ConstructionContext; // Allows to create<>() itself. 328 SimpleVariableConstructionContext(const DeclStmt * DS)329 explicit SimpleVariableConstructionContext(const DeclStmt *DS) 330 : VariableConstructionContext(ConstructionContext::SimpleVariableKind, 331 DS) {} 332 333 public: classof(const ConstructionContext * CC)334 static bool classof(const ConstructionContext *CC) { 335 return CC->getKind() == SimpleVariableKind; 336 } 337 }; 338 339 /// Represents construction into a simple variable with an initializer syntax, 340 /// with a single constructor, eg. T var = makeT();. Such construction context 341 /// may only appear in C++17 because previously it was split into a temporary 342 /// object constructor and an elidable simple variable copy-constructor and 343 /// we were producing separate construction contexts for these constructors. 344 /// In C++17 we have a single construction context that combines both. 345 /// Note that if the object has trivial destructor, then this code is 346 /// indistinguishable from a simple variable constructor on the AST level; 347 /// in this case we provide a simple variable construction context. 348 class CXX17ElidedCopyVariableConstructionContext 349 : public VariableConstructionContext { 350 const CXXBindTemporaryExpr *BTE; 351 352 friend class ConstructionContext; // Allows to create<>() itself. 353 CXX17ElidedCopyVariableConstructionContext(const DeclStmt * DS,const CXXBindTemporaryExpr * BTE)354 explicit CXX17ElidedCopyVariableConstructionContext( 355 const DeclStmt *DS, const CXXBindTemporaryExpr *BTE) 356 : VariableConstructionContext(CXX17ElidedCopyVariableKind, DS), BTE(BTE) { 357 assert(BTE); 358 } 359 360 public: getCXXBindTemporaryExpr()361 const CXXBindTemporaryExpr *getCXXBindTemporaryExpr() const { return BTE; } 362 classof(const ConstructionContext * CC)363 static bool classof(const ConstructionContext *CC) { 364 return CC->getKind() == CXX17ElidedCopyVariableKind; 365 } 366 }; 367 368 // An abstract base class for constructor-initializer-based constructors. 369 class ConstructorInitializerConstructionContext : public ConstructionContext { 370 const CXXCtorInitializer *I; 371 372 protected: ConstructorInitializerConstructionContext(ConstructionContext::Kind K,const CXXCtorInitializer * I)373 explicit ConstructorInitializerConstructionContext( 374 ConstructionContext::Kind K, const CXXCtorInitializer *I) 375 : ConstructionContext(K), I(I) { 376 assert(classof(this)); 377 assert(I); 378 } 379 380 public: getCXXCtorInitializer()381 const CXXCtorInitializer *getCXXCtorInitializer() const { return I; } 382 classof(const ConstructionContext * CC)383 static bool classof(const ConstructionContext *CC) { 384 return CC->getKind() >= INITIALIZER_BEGIN && 385 CC->getKind() <= INITIALIZER_END; 386 } 387 }; 388 389 /// Represents construction into a field or a base class within a bigger object 390 /// via a constructor initializer, eg. T(): field(123) { ... }. 391 class SimpleConstructorInitializerConstructionContext 392 : public ConstructorInitializerConstructionContext { 393 friend class ConstructionContext; // Allows to create<>() itself. 394 SimpleConstructorInitializerConstructionContext(const CXXCtorInitializer * I)395 explicit SimpleConstructorInitializerConstructionContext( 396 const CXXCtorInitializer *I) 397 : ConstructorInitializerConstructionContext( 398 ConstructionContext::SimpleConstructorInitializerKind, I) {} 399 400 public: classof(const ConstructionContext * CC)401 static bool classof(const ConstructionContext *CC) { 402 return CC->getKind() == SimpleConstructorInitializerKind; 403 } 404 }; 405 406 /// Represents construction into a field or a base class within a bigger object 407 /// via a constructor initializer, with a single constructor, eg. 408 /// T(): field(Field(123)) { ... }. Such construction context may only appear 409 /// in C++17 because previously it was split into a temporary object constructor 410 /// and an elidable simple constructor-initializer copy-constructor and we were 411 /// producing separate construction contexts for these constructors. In C++17 412 /// we have a single construction context that combines both. Note that if the 413 /// object has trivial destructor, then this code is indistinguishable from 414 /// a simple constructor-initializer constructor on the AST level; in this case 415 /// we provide a simple constructor-initializer construction context. 416 class CXX17ElidedCopyConstructorInitializerConstructionContext 417 : public ConstructorInitializerConstructionContext { 418 const CXXBindTemporaryExpr *BTE; 419 420 friend class ConstructionContext; // Allows to create<>() itself. 421 CXX17ElidedCopyConstructorInitializerConstructionContext(const CXXCtorInitializer * I,const CXXBindTemporaryExpr * BTE)422 explicit CXX17ElidedCopyConstructorInitializerConstructionContext( 423 const CXXCtorInitializer *I, const CXXBindTemporaryExpr *BTE) 424 : ConstructorInitializerConstructionContext( 425 CXX17ElidedCopyConstructorInitializerKind, I), 426 BTE(BTE) { 427 assert(BTE); 428 } 429 430 public: getCXXBindTemporaryExpr()431 const CXXBindTemporaryExpr *getCXXBindTemporaryExpr() const { return BTE; } 432 classof(const ConstructionContext * CC)433 static bool classof(const ConstructionContext *CC) { 434 return CC->getKind() == CXX17ElidedCopyConstructorInitializerKind; 435 } 436 }; 437 438 /// Represents immediate initialization of memory allocated by operator new, 439 /// eg. new T(123);. 440 class NewAllocatedObjectConstructionContext : public ConstructionContext { 441 const CXXNewExpr *NE; 442 443 friend class ConstructionContext; // Allows to create<>() itself. 444 NewAllocatedObjectConstructionContext(const CXXNewExpr * NE)445 explicit NewAllocatedObjectConstructionContext(const CXXNewExpr *NE) 446 : ConstructionContext(ConstructionContext::NewAllocatedObjectKind), 447 NE(NE) { 448 assert(NE); 449 } 450 451 public: getCXXNewExpr()452 const CXXNewExpr *getCXXNewExpr() const { return NE; } 453 classof(const ConstructionContext * CC)454 static bool classof(const ConstructionContext *CC) { 455 return CC->getKind() == NewAllocatedObjectKind; 456 } 457 }; 458 459 /// Represents a temporary object, eg. T(123), that does not immediately cross 460 /// function boundaries "by value"; constructors that construct function 461 /// value-type arguments or values that are immediately returned from the 462 /// function that returns a value receive separate construction context kinds. 463 class TemporaryObjectConstructionContext : public ConstructionContext { 464 const CXXBindTemporaryExpr *BTE; 465 const MaterializeTemporaryExpr *MTE; 466 467 protected: TemporaryObjectConstructionContext(ConstructionContext::Kind K,const CXXBindTemporaryExpr * BTE,const MaterializeTemporaryExpr * MTE)468 explicit TemporaryObjectConstructionContext( 469 ConstructionContext::Kind K, const CXXBindTemporaryExpr *BTE, 470 const MaterializeTemporaryExpr *MTE) 471 : ConstructionContext(K), BTE(BTE), MTE(MTE) { 472 // Both BTE and MTE can be null here, all combinations possible. 473 // Even though for now at least one should be non-null, we simply haven't 474 // implemented the other case yet (this would be a temporary in the middle 475 // of nowhere that doesn't have a non-trivial destructor). 476 } 477 478 public: 479 /// CXXBindTemporaryExpr here is non-null as long as the temporary has 480 /// a non-trivial destructor. getCXXBindTemporaryExpr()481 const CXXBindTemporaryExpr *getCXXBindTemporaryExpr() const { 482 return BTE; 483 } 484 485 /// MaterializeTemporaryExpr is non-null as long as the temporary is actually 486 /// used after construction, eg. by binding to a reference (lifetime 487 /// extension), accessing a field, calling a method, or passing it into 488 /// a function (an elidable copy or move constructor would be a common 489 /// example) by reference. getMaterializedTemporaryExpr()490 const MaterializeTemporaryExpr *getMaterializedTemporaryExpr() const { 491 return MTE; 492 } 493 classof(const ConstructionContext * CC)494 static bool classof(const ConstructionContext *CC) { 495 return CC->getKind() >= TEMPORARY_BEGIN && CC->getKind() <= TEMPORARY_END; 496 } 497 }; 498 499 /// Represents a temporary object that is not constructed for the purpose of 500 /// being immediately copied/moved by an elidable copy/move-constructor. 501 /// This includes temporary objects "in the middle of nowhere" like T(123) and 502 /// lifetime-extended temporaries. 503 class SimpleTemporaryObjectConstructionContext 504 : public TemporaryObjectConstructionContext { 505 friend class ConstructionContext; // Allows to create<>() itself. 506 SimpleTemporaryObjectConstructionContext(const CXXBindTemporaryExpr * BTE,const MaterializeTemporaryExpr * MTE)507 explicit SimpleTemporaryObjectConstructionContext( 508 const CXXBindTemporaryExpr *BTE, const MaterializeTemporaryExpr *MTE) 509 : TemporaryObjectConstructionContext( 510 ConstructionContext::SimpleTemporaryObjectKind, BTE, MTE) {} 511 512 public: classof(const ConstructionContext * CC)513 static bool classof(const ConstructionContext *CC) { 514 return CC->getKind() == SimpleTemporaryObjectKind; 515 } 516 }; 517 518 /// Represents a temporary object that is constructed for the sole purpose 519 /// of being immediately copied by an elidable copy/move constructor. 520 /// For example, T t = T(123); includes a temporary T(123) that is immediately 521 /// copied to variable t. In such cases the elidable copy can (but not 522 /// necessarily should) be omitted ("elided") accodring to the rules of the 523 /// language; the constructor would then construct variable t directly. 524 /// This construction context contains information of the elidable constructor 525 /// and its respective construction context. 526 class ElidedTemporaryObjectConstructionContext 527 : public TemporaryObjectConstructionContext { 528 const CXXConstructExpr *ElidedCE; 529 const ConstructionContext *ElidedCC; 530 531 friend class ConstructionContext; // Allows to create<>() itself. 532 ElidedTemporaryObjectConstructionContext(const CXXBindTemporaryExpr * BTE,const MaterializeTemporaryExpr * MTE,const CXXConstructExpr * ElidedCE,const ConstructionContext * ElidedCC)533 explicit ElidedTemporaryObjectConstructionContext( 534 const CXXBindTemporaryExpr *BTE, const MaterializeTemporaryExpr *MTE, 535 const CXXConstructExpr *ElidedCE, const ConstructionContext *ElidedCC) 536 : TemporaryObjectConstructionContext( 537 ConstructionContext::ElidedTemporaryObjectKind, BTE, MTE), 538 ElidedCE(ElidedCE), ElidedCC(ElidedCC) { 539 // Elided constructor and its context should be either both specified 540 // or both unspecified. In the former case, the constructor must be 541 // elidable. 542 assert(ElidedCE && ElidedCE->isElidable() && ElidedCC); 543 } 544 545 public: getConstructorAfterElision()546 const CXXConstructExpr *getConstructorAfterElision() const { 547 return ElidedCE; 548 } 549 getConstructionContextAfterElision()550 const ConstructionContext *getConstructionContextAfterElision() const { 551 return ElidedCC; 552 } 553 classof(const ConstructionContext * CC)554 static bool classof(const ConstructionContext *CC) { 555 return CC->getKind() == ElidedTemporaryObjectKind; 556 } 557 }; 558 559 class ReturnedValueConstructionContext : public ConstructionContext { 560 const ReturnStmt *RS; 561 562 protected: ReturnedValueConstructionContext(ConstructionContext::Kind K,const ReturnStmt * RS)563 explicit ReturnedValueConstructionContext(ConstructionContext::Kind K, 564 const ReturnStmt *RS) 565 : ConstructionContext(K), RS(RS) { 566 assert(classof(this)); 567 assert(RS); 568 } 569 570 public: getReturnStmt()571 const ReturnStmt *getReturnStmt() const { return RS; } 572 classof(const ConstructionContext * CC)573 static bool classof(const ConstructionContext *CC) { 574 return CC->getKind() >= RETURNED_VALUE_BEGIN && 575 CC->getKind() <= RETURNED_VALUE_END; 576 } 577 }; 578 579 /// Represents a temporary object that is being immediately returned from a 580 /// function by value, eg. return t; or return T(123);. In this case there is 581 /// always going to be a constructor at the return site. However, the usual 582 /// temporary-related bureaucracy (CXXBindTemporaryExpr, 583 /// MaterializeTemporaryExpr) is normally located in the caller function's AST. 584 class SimpleReturnedValueConstructionContext 585 : public ReturnedValueConstructionContext { 586 friend class ConstructionContext; // Allows to create<>() itself. 587 SimpleReturnedValueConstructionContext(const ReturnStmt * RS)588 explicit SimpleReturnedValueConstructionContext(const ReturnStmt *RS) 589 : ReturnedValueConstructionContext( 590 ConstructionContext::SimpleReturnedValueKind, RS) {} 591 592 public: classof(const ConstructionContext * CC)593 static bool classof(const ConstructionContext *CC) { 594 return CC->getKind() == SimpleReturnedValueKind; 595 } 596 }; 597 598 /// Represents a temporary object that is being immediately returned from a 599 /// function by value, eg. return t; or return T(123); in C++17. 600 /// In C++17 there is not going to be an elidable copy constructor at the 601 /// return site. However, the usual temporary-related bureaucracy (CXXBindTemporaryExpr, 602 /// MaterializeTemporaryExpr) is normally located in the caller function's AST. 603 /// Note that if the object has trivial destructor, then this code is 604 /// indistinguishable from a simple returned value constructor on the AST level; 605 /// in this case we provide a simple returned value construction context. 606 class CXX17ElidedCopyReturnedValueConstructionContext 607 : public ReturnedValueConstructionContext { 608 const CXXBindTemporaryExpr *BTE; 609 610 friend class ConstructionContext; // Allows to create<>() itself. 611 CXX17ElidedCopyReturnedValueConstructionContext(const ReturnStmt * RS,const CXXBindTemporaryExpr * BTE)612 explicit CXX17ElidedCopyReturnedValueConstructionContext( 613 const ReturnStmt *RS, const CXXBindTemporaryExpr *BTE) 614 : ReturnedValueConstructionContext( 615 ConstructionContext::CXX17ElidedCopyReturnedValueKind, RS), 616 BTE(BTE) { 617 assert(BTE); 618 } 619 620 public: getCXXBindTemporaryExpr()621 const CXXBindTemporaryExpr *getCXXBindTemporaryExpr() const { return BTE; } 622 classof(const ConstructionContext * CC)623 static bool classof(const ConstructionContext *CC) { 624 return CC->getKind() == CXX17ElidedCopyReturnedValueKind; 625 } 626 }; 627 628 class ArgumentConstructionContext : public ConstructionContext { 629 // The call of which the context is an argument. 630 const Expr *CE; 631 632 // Which argument we're constructing. Note that when numbering between 633 // arguments and parameters is inconsistent (eg., operator calls), 634 // this is the index of the argument, not of the parameter. 635 unsigned Index; 636 637 // Whether the object needs to be destroyed. 638 const CXXBindTemporaryExpr *BTE; 639 640 friend class ConstructionContext; // Allows to create<>() itself. 641 ArgumentConstructionContext(const Expr * CE,unsigned Index,const CXXBindTemporaryExpr * BTE)642 explicit ArgumentConstructionContext(const Expr *CE, unsigned Index, 643 const CXXBindTemporaryExpr *BTE) 644 : ConstructionContext(ArgumentKind), CE(CE), 645 Index(Index), BTE(BTE) { 646 assert(isa<CallExpr>(CE) || isa<CXXConstructExpr>(CE) || 647 isa<ObjCMessageExpr>(CE)); 648 // BTE is optional. 649 } 650 651 public: getCallLikeExpr()652 const Expr *getCallLikeExpr() const { return CE; } getIndex()653 unsigned getIndex() const { return Index; } getCXXBindTemporaryExpr()654 const CXXBindTemporaryExpr *getCXXBindTemporaryExpr() const { return BTE; } 655 classof(const ConstructionContext * CC)656 static bool classof(const ConstructionContext *CC) { 657 return CC->getKind() == ArgumentKind; 658 } 659 }; 660 661 } // end namespace clang 662 663 #endif // LLVM_CLANG_ANALYSIS_CONSTRUCTIONCONTEXT_H 664