@@ -267,6 +267,11 @@ static bool isInStlNamespace(const Decl *D) {
267
267
return DC->isStdNamespace ();
268
268
}
269
269
270
+ static bool isPointerLikeType (QualType Type) {
271
+ return isRecordWithAttr<PointerAttr>(Type) || Type->isPointerType () ||
272
+ Type->isNullPtrType ();
273
+ }
274
+
270
275
// Returns true if the given Record decl is a form of `GSLOwner<Pointer>`
271
276
// type, e.g. std::vector<string_view>, std::optional<string_view>.
272
277
static bool isContainerOfPointer (const RecordDecl *Container) {
@@ -276,9 +281,19 @@ static bool isContainerOfPointer(const RecordDecl *Container) {
276
281
return false ;
277
282
const auto &TAs = CTSD->getTemplateArgs ();
278
283
return TAs.size () > 0 && TAs[0 ].getKind () == TemplateArgument::Type &&
279
- (isRecordWithAttr<PointerAttr>(TAs[0 ].getAsType ()) ||
280
- TAs[0 ].getAsType ()->isPointerType () ||
281
- TAs[0 ].getAsType ()->isNullPtrType ());
284
+ isPointerLikeType (TAs[0 ].getAsType ());
285
+ }
286
+ return false ;
287
+ }
288
+ // Returns true if the given Record is `std::initializer_list<pointer>`.
289
+ static bool isStdInitializerListOfPointer (const RecordDecl *RD) {
290
+ if (const auto *CTSD =
291
+ dyn_cast_if_present<ClassTemplateSpecializationDecl>(RD)) {
292
+ const auto &TAs = CTSD->getTemplateArgs ();
293
+ return isInStlNamespace (RD) && RD->getIdentifier () &&
294
+ RD->getName () == " initializer_list" && TAs.size () > 0 &&
295
+ TAs[0 ].getKind () == TemplateArgument::Type &&
296
+ isPointerLikeType (TAs[0 ].getAsType ());
282
297
}
283
298
return false ;
284
299
}
@@ -299,8 +314,7 @@ static bool shouldTrackImplicitObjectArg(const CXXMethodDecl *Callee) {
299
314
Callee->getFunctionObjectParameterType ()) &&
300
315
!isGSLOwner (Callee->getFunctionObjectParameterType ()))
301
316
return false ;
302
- if (Callee->getReturnType ()->isPointerType () ||
303
- isRecordWithAttr<PointerAttr>(Callee->getReturnType ())) {
317
+ if (isPointerLikeType (Callee->getReturnType ())) {
304
318
if (!Callee->getIdentifier ())
305
319
return false ;
306
320
return llvm::StringSwitch<bool >(Callee->getName ())
@@ -348,6 +362,30 @@ static bool shouldTrackFirstArgument(const FunctionDecl *FD) {
348
362
return false ;
349
363
}
350
364
365
+ // Returns true if we should perform the GSL analysis on the first argument for
366
+ // the given constructor.
367
+ static bool
368
+ shouldTrackFirstArgumentForConstructor (const CXXConstructExpr *Ctor) {
369
+ const auto *ClassD = Ctor->getConstructor ()->getParent ();
370
+
371
+ auto FirstArgType = Ctor->getArg (0 )->getType ();
372
+ // Case 1, construct a GSL pointer, e.g. std::string_view
373
+ if (ClassD->hasAttr <PointerAttr>())
374
+ return true ;
375
+
376
+ // case 2: construct a container of pointer (std::vector<std::string_view>)
377
+ // from an owner or a std::initilizer_list.
378
+ //
379
+ // std::initializer_list is a proxy object that provides access to the backing
380
+ // array. We perform analysis on it to determine if there are any dangling
381
+ // temporaries in the backing array.
382
+ if (Ctor->getConstructor ()->getNumParams () != 1 ||
383
+ !isContainerOfPointer (ClassD))
384
+ return false ;
385
+ return isGSLOwner (FirstArgType) ||
386
+ isStdInitializerListOfPointer (FirstArgType->getAsRecordDecl ());
387
+ }
388
+
351
389
// Return true if this is an "normal" assignment operator.
352
390
// We assuments that a normal assingment operator always returns *this, that is,
353
391
// an lvalue reference that is the same type as the implicit object parameter
@@ -493,14 +531,9 @@ static void visitFunctionCallArguments(IndirectLocalPath &Path, Expr *Call,
493
531
// Perform GSL analysis for the first argument
494
532
if (shouldTrackFirstArgument (Callee)) {
495
533
VisitGSLPointerArg (Callee, Args[0 ]);
496
- } else if (auto *Ctor = dyn_cast<CXXConstructExpr>(Call)) {
497
- const auto *ClassD = Ctor->getConstructor ()->getParent ();
498
- // Two cases:
499
- // a GSL pointer, e.g. std::string_view
500
- // a container of GSL pointer, e.g. std::vector<string_view>
501
- if (ClassD->hasAttr <PointerAttr>() ||
502
- (isContainerOfPointer (ClassD) && Callee->getNumParams () == 1 ))
503
- VisitGSLPointerArg (Ctor->getConstructor (), Args[0 ]);
534
+ } else if (auto *Ctor = dyn_cast<CXXConstructExpr>(Call);
535
+ Ctor && shouldTrackFirstArgumentForConstructor (Ctor)) {
536
+ VisitGSLPointerArg (Ctor->getConstructor (), Args[0 ]);
504
537
}
505
538
}
506
539
}
0 commit comments