@@ -1689,7 +1689,7 @@ void BuildLockset::handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD) {
1689
1689
CapExprSet ScopedExclusiveReqs, ScopedSharedReqs;
1690
1690
StringRef CapDiagKind = " mutex" ;
1691
1691
1692
- // Figure out if we're calling the constructor of scoped lockable class
1692
+ // Figure out if we're constructing an object of scoped lockable class
1693
1693
bool isScopedVar = false ;
1694
1694
if (VD) {
1695
1695
if (const CXXConstructorDecl *CD = dyn_cast<const CXXConstructorDecl>(D)) {
@@ -1991,22 +1991,68 @@ void BuildLockset::VisitCXXConstructExpr(CXXConstructExpr *Exp) {
1991
1991
// FIXME -- only handles constructors in DeclStmt below.
1992
1992
}
1993
1993
1994
+ static CXXConstructorDecl *
1995
+ findConstructorForByValueReturn (const CXXRecordDecl *RD) {
1996
+ // Prefer a move constructor over a copy constructor. If there's more than
1997
+ // one copy constructor or more than one move constructor, we arbitrarily
1998
+ // pick the first declared such constructor rather than trying to guess which
1999
+ // one is more appropriate.
2000
+ CXXConstructorDecl *CopyCtor = nullptr ;
2001
+ for (CXXConstructorDecl *Ctor : RD->ctors ()) {
2002
+ if (Ctor->isDeleted ())
2003
+ continue ;
2004
+ if (Ctor->isMoveConstructor ())
2005
+ return Ctor;
2006
+ if (!CopyCtor && Ctor->isCopyConstructor ())
2007
+ CopyCtor = Ctor;
2008
+ }
2009
+ return CopyCtor;
2010
+ }
2011
+
2012
+ static Expr *buildFakeCtorCall (CXXConstructorDecl *CD, ArrayRef<Expr *> Args,
2013
+ SourceLocation Loc) {
2014
+ ASTContext &Ctx = CD->getASTContext ();
2015
+ return CXXConstructExpr::Create (Ctx, Ctx.getRecordType (CD->getParent ()), Loc,
2016
+ CD, true , Args, false , false , false , false ,
2017
+ CXXConstructExpr::CK_Complete,
2018
+ SourceRange (Loc, Loc));
2019
+ }
2020
+
1994
2021
void BuildLockset::VisitDeclStmt (DeclStmt *S) {
1995
2022
// adjust the context
1996
2023
LVarCtx = Analyzer->LocalVarMap .getNextContext (CtxIndex, S, LVarCtx);
1997
2024
1998
2025
for (auto *D : S->getDeclGroup ()) {
1999
2026
if (VarDecl *VD = dyn_cast_or_null<VarDecl>(D)) {
2000
2027
Expr *E = VD->getInit ();
2028
+ if (!E)
2029
+ continue ;
2030
+ E = E->IgnoreParens ();
2031
+
2001
2032
// handle constructors that involve temporaries
2002
- if (ExprWithCleanups *EWC = dyn_cast_or_null <ExprWithCleanups>(E))
2033
+ if (auto *EWC = dyn_cast <ExprWithCleanups>(E))
2003
2034
E = EWC->getSubExpr ();
2035
+ if (auto *BTE = dyn_cast<CXXBindTemporaryExpr>(E))
2036
+ E = BTE->getSubExpr ();
2004
2037
2005
- if (CXXConstructExpr *CE = dyn_cast_or_null <CXXConstructExpr>(E)) {
2038
+ if (CXXConstructExpr *CE = dyn_cast <CXXConstructExpr>(E)) {
2006
2039
NamedDecl *CtorD = dyn_cast_or_null<NamedDecl>(CE->getConstructor ());
2007
2040
if (!CtorD || !CtorD->hasAttrs ())
2008
- return ;
2009
- handleCall (CE, CtorD, VD);
2041
+ continue ;
2042
+ handleCall (E, CtorD, VD);
2043
+ } else if (isa<CallExpr>(E) && E->isRValue ()) {
2044
+ // If the object is initialized by a function call that returns a
2045
+ // scoped lockable by value, use the attributes on the copy or move
2046
+ // constructor to figure out what effect that should have on the
2047
+ // lockset.
2048
+ // FIXME: Is this really the best way to handle this situation?
2049
+ auto *RD = E->getType ()->getAsCXXRecordDecl ();
2050
+ if (!RD || !RD->hasAttr <ScopedLockableAttr>())
2051
+ continue ;
2052
+ CXXConstructorDecl *CtorD = findConstructorForByValueReturn (RD);
2053
+ if (!CtorD || !CtorD->hasAttrs ())
2054
+ continue ;
2055
+ handleCall (buildFakeCtorCall (CtorD, {E}, E->getLocStart ()), CtorD, VD);
2010
2056
}
2011
2057
}
2012
2058
}
0 commit comments