@@ -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
}
@@ -298,8 +313,7 @@ static bool shouldTrackImplicitObjectArg(const CXXMethodDecl *Callee) {
298
313
Callee->getFunctionObjectParameterType ()) &&
299
314
!isGSLOwner (Callee->getFunctionObjectParameterType ()))
300
315
return false ;
301
- if (Callee->getReturnType ()->isPointerType () ||
302
- isRecordWithAttr<PointerAttr>(Callee->getReturnType ())) {
316
+ if (isPointerLikeType (Callee->getReturnType ())) {
303
317
if (!Callee->getIdentifier ())
304
318
return false ;
305
319
return llvm::StringSwitch<bool >(Callee->getName ())
@@ -347,6 +361,30 @@ static bool shouldTrackFirstArgument(const FunctionDecl *FD) {
347
361
return false ;
348
362
}
349
363
364
+ // Returns true if we should perform the GSL analysis on the first argument for
365
+ // the given constructor.
366
+ static bool
367
+ shouldTrackFirstArgumentForConstructor (const CXXConstructExpr *Ctor) {
368
+ const auto *ClassD = Ctor->getConstructor ()->getParent ();
369
+
370
+ auto FirstArgType = Ctor->getArg (0 )->getType ();
371
+ // Case 1, construct a GSL pointer, e.g. std::string_view
372
+ if (ClassD->hasAttr <PointerAttr>())
373
+ return true ;
374
+
375
+ // case 2: construct a container of pointer (std::vector<std::string_view>)
376
+ // from an owner or a std::initilizer_list.
377
+ //
378
+ // std::initializer_list is a proxy object that provides access to the backing
379
+ // array. We perform analysis on it to determine if there are any dangling
380
+ // temporaries in the backing array.
381
+ if (Ctor->getConstructor ()->getNumParams () != 1 ||
382
+ !isContainerOfPointer (ClassD))
383
+ return false ;
384
+ return isGSLOwner (FirstArgType) ||
385
+ isStdInitializerListOfPointer (FirstArgType->getAsRecordDecl ());
386
+ }
387
+
350
388
// Return true if this is an "normal" assignment operator.
351
389
// We assuments that a normal assingment operator always returns *this, that is,
352
390
// an lvalue reference that is the same type as the implicit object parameter
@@ -492,14 +530,9 @@ static void visitFunctionCallArguments(IndirectLocalPath &Path, Expr *Call,
492
530
// Perform GSL analysis for the first argument
493
531
if (shouldTrackFirstArgument (Callee)) {
494
532
VisitGSLPointerArg (Callee, Args[0 ]);
495
- } else if (auto *Ctor = dyn_cast<CXXConstructExpr>(Call)) {
496
- const auto *ClassD = Ctor->getConstructor ()->getParent ();
497
- // Two cases:
498
- // a GSL pointer, e.g. std::string_view
499
- // a container of GSL pointer, e.g. std::vector<string_view>
500
- if (ClassD->hasAttr <PointerAttr>() ||
501
- (isContainerOfPointer (ClassD) && Callee->getNumParams () == 1 ))
502
- VisitGSLPointerArg (Ctor->getConstructor (), Args[0 ]);
533
+ } else if (auto *Ctor = dyn_cast<CXXConstructExpr>(Call);
534
+ Ctor && shouldTrackFirstArgumentForConstructor (Ctor)) {
535
+ VisitGSLPointerArg (Ctor->getConstructor (), Args[0 ]);
503
536
}
504
537
}
505
538
}
0 commit comments