[PATCH] D38810: [Analyzer] Support bodyfarming std::call_once for libstdc++
This revision was automatically updated to reflect the committed changes. Closed by commit rL315508: [Analyzer] Support bodyfarming libstdc++ implementation of std::call_once. (authored by george.karpenkov). Changed prior to commit: https://reviews.llvm.org/D38810?vs=118644=118686#toc Repository: rL LLVM https://reviews.llvm.org/D38810 Files: cfe/trunk/lib/Analysis/BodyFarm.cpp cfe/trunk/test/Analysis/call_once.cpp Index: cfe/trunk/test/Analysis/call_once.cpp === --- cfe/trunk/test/Analysis/call_once.cpp +++ cfe/trunk/test/Analysis/call_once.cpp @@ -1,15 +1,24 @@ -// RUN: %clang_analyze_cc1 -std=c++11 -fblocks -analyzer-checker=core,debug.ExprInspection -w -verify %s +// RUN: %clang_analyze_cc1 -std=c++11 -fblocks -analyzer-checker=core,debug.ExprInspection -verify %s +// RUN: %clang_analyze_cc1 -std=c++11 -fblocks -analyzer-checker=core,debug.ExprInspection -DEMULATE_LIBSTDCPP -verify %s void clang_analyzer_eval(bool); // Faking std::std::call_once implementation. namespace std { + +#ifndef EMULATE_LIBSTDCPP typedef struct once_flag_s { unsigned long __state_ = 0; } once_flag; +#else +typedef struct once_flag_s { + int _M_once = 0; +} once_flag; +#endif template void call_once(once_flag , Callable func, Args... args) {}; + } // namespace std // Check with Lambdas. Index: cfe/trunk/lib/Analysis/BodyFarm.cpp === --- cfe/trunk/lib/Analysis/BodyFarm.cpp +++ cfe/trunk/lib/Analysis/BodyFarm.cpp @@ -108,7 +108,7 @@ /// Returns a *first* member field of a record declaration with a given name. /// \return an nullptr if no member with such a name exists. - NamedDecl *findMemberField(const CXXRecordDecl *RD, StringRef Name); + ValueDecl *findMemberField(const RecordDecl *RD, StringRef Name); private: ASTContext @@ -234,7 +234,7 @@ OK_Ordinary); } -NamedDecl *ASTMaker::findMemberField(const CXXRecordDecl *RD, StringRef Name) { +ValueDecl *ASTMaker::findMemberField(const RecordDecl *RD, StringRef Name) { CXXBasePaths Paths( /* FindAmbiguities=*/false, @@ -246,7 +246,7 @@ DeclContextLookupResult Decls = RD->lookup(DeclName); for (NamedDecl *FoundDecl : Decls) if (!FoundDecl->getDeclContext()->isFunctionOrMethod()) - return FoundDecl; + return cast(FoundDecl); return nullptr; } @@ -328,25 +328,31 @@ const ParmVarDecl *Callback = D->getParamDecl(1); QualType CallbackType = Callback->getType().getNonReferenceType(); QualType FlagType = Flag->getType().getNonReferenceType(); - CXXRecordDecl *FlagCXXDecl = FlagType->getAsCXXRecordDecl(); - if (!FlagCXXDecl) { -DEBUG(llvm::dbgs() << "Flag field is not a CXX record: " - << "unknown std::call_once implementation." - << "Ignoring the call.\n"); + auto *FlagRecordDecl = dyn_cast_or_null(FlagType->getAsTagDecl()); + + if (!FlagRecordDecl) { +DEBUG(llvm::dbgs() << "Flag field is not a record: " + << "unknown std::call_once implementation, " + << "ignoring the call.\n"); return nullptr; } - // Note: here we are assuming libc++ implementation of call_once, - // which has a struct with a field `__state_`. - // Body farming might not work for other `call_once` implementations. - NamedDecl *FoundDecl = M.findMemberField(FlagCXXDecl, "__state_"); - ValueDecl *FieldDecl; - if (FoundDecl) { -FieldDecl = dyn_cast(FoundDecl); - } else { + // We initially assume libc++ implementation of call_once, + // where the once_flag struct has a field `__state_`. + ValueDecl *FlagFieldDecl = M.findMemberField(FlagRecordDecl, "__state_"); + + // Otherwise, try libstdc++ implementation, with a field + // `_M_once` + if (!FlagFieldDecl) { DEBUG(llvm::dbgs() << "No field __state_ found on std::once_flag struct, " - << "unable to synthesize call_once body, ignoring " - << "the call.\n"); + << "assuming libstdc++ implementation\n"); +FlagFieldDecl = M.findMemberField(FlagRecordDecl, "_M_once"); + } + + if (!FlagFieldDecl) { +DEBUG(llvm::dbgs() << "No field _M_once found on std::once flag struct: " + << "unknown std::call_once implementation, " + << "ignoring the call"); return nullptr; } @@ -383,7 +389,7 @@ /* GetNonReferenceType=*/true); - MemberExpr *Deref = M.makeMemberExpression(FlagDecl, FieldDecl); + MemberExpr *Deref = M.makeMemberExpression(FlagDecl, FlagFieldDecl); assert(Deref->isLValue()); QualType DerefType = Deref->getType(); ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D38810: [Analyzer] Support bodyfarming std::call_once for libstdc++
dcoughlin accepted this revision. dcoughlin added a comment. This revision is now accepted and ready to land. LGTM with the dyn_cast mentioned inline changed. Comment at: lib/Analysis/BodyFarm.cpp:359 + ValueDecl *FieldDecl = dyn_cast(FoundDecl); bool isLambdaCall = CallbackType->getAsCXXRecordDecl() && Should this be a cast<>() rather than a dyn_cast<>()? Do you expect this to fail? If so then you should check the result for null. If not then the idiom is to use cast<>(). An alternative would be to change findMemberField() to return a FieldDecl. https://reviews.llvm.org/D38810 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D38810: [Analyzer] Support bodyfarming std::call_once for libstdc++
george.karpenkov created this revision. Herald added subscribers: szepet, kristof.beyls, xazax.hun, javed.absar, aemerson. https://reviews.llvm.org/D38810 Files: lib/Analysis/BodyFarm.cpp test/Analysis/call_once.cpp Index: test/Analysis/call_once.cpp === --- test/Analysis/call_once.cpp +++ test/Analysis/call_once.cpp @@ -1,15 +1,24 @@ -// RUN: %clang_analyze_cc1 -std=c++11 -fblocks -analyzer-checker=core,debug.ExprInspection -w -verify %s +// RUN: %clang_analyze_cc1 -std=c++11 -fblocks -analyzer-checker=core,debug.ExprInspection -verify %s +// RUN: %clang_analyze_cc1 -std=c++11 -fblocks -analyzer-checker=core,debug.ExprInspection -DEMULATE_LIBSTDCPP -verify %s void clang_analyzer_eval(bool); // Faking std::std::call_once implementation. namespace std { + +#ifndef EMULATE_LIBSTDCPP typedef struct once_flag_s { unsigned long __state_ = 0; } once_flag; +#else +typedef struct once_flag_s { + int _M_once = 0; +} once_flag; +#endif template void call_once(once_flag , Callable func, Args... args) {}; + } // namespace std // Check with Lambdas. Index: lib/Analysis/BodyFarm.cpp === --- lib/Analysis/BodyFarm.cpp +++ lib/Analysis/BodyFarm.cpp @@ -108,7 +108,7 @@ /// Returns a *first* member field of a record declaration with a given name. /// \return an nullptr if no member with such a name exists. - NamedDecl *findMemberField(const CXXRecordDecl *RD, StringRef Name); + NamedDecl *findMemberField(const RecordDecl *RD, StringRef Name); private: ASTContext @@ -234,7 +234,7 @@ OK_Ordinary); } -NamedDecl *ASTMaker::findMemberField(const CXXRecordDecl *RD, StringRef Name) { +NamedDecl *ASTMaker::findMemberField(const RecordDecl *RD, StringRef Name) { CXXBasePaths Paths( /* FindAmbiguities=*/false, @@ -328,28 +328,35 @@ const ParmVarDecl *Callback = D->getParamDecl(1); QualType CallbackType = Callback->getType().getNonReferenceType(); QualType FlagType = Flag->getType().getNonReferenceType(); - CXXRecordDecl *FlagCXXDecl = FlagType->getAsCXXRecordDecl(); - if (!FlagCXXDecl) { -DEBUG(llvm::dbgs() << "Flag field is not a CXX record: " - << "unknown std::call_once implementation." - << "Ignoring the call.\n"); + auto *FlagRecordDecl = dyn_cast_or_null(FlagType->getAsTagDecl()); + + if (!FlagRecordDecl) { +DEBUG(llvm::dbgs() << "Flag field is not a record: " + << "unknown std::call_once implementation, " + << "ignoring the call.\n"); return nullptr; } - // Note: here we are assuming libc++ implementation of call_once, - // which has a struct with a field `__state_`. - // Body farming might not work for other `call_once` implementations. - NamedDecl *FoundDecl = M.findMemberField(FlagCXXDecl, "__state_"); - ValueDecl *FieldDecl; - if (FoundDecl) { -FieldDecl = dyn_cast(FoundDecl); - } else { + // We initially assume libc++ implementation of call_once, + // where the once_flag struct has a field `__state_`. + NamedDecl *FoundDecl = M.findMemberField(FlagRecordDecl, "__state_"); + + // Otherwise, try libstdc++ implementation, with a field + // `_M_once` + if (!FoundDecl) { DEBUG(llvm::dbgs() << "No field __state_ found on std::once_flag struct, " - << "unable to synthesize call_once body, ignoring " - << "the call.\n"); + << "trying libstdc++ implementation\n"); +FoundDecl = M.findMemberField(FlagRecordDecl, "_M_once"); + } + + if (!FoundDecl) { +DEBUG(llvm::dbgs() << "No field _M_once found on std::once flag struct: " + << "unknown std::call_once implementation, " + << "ignoring the call"); return nullptr; } + ValueDecl *FieldDecl = dyn_cast(FoundDecl); bool isLambdaCall = CallbackType->getAsCXXRecordDecl() && CallbackType->getAsCXXRecordDecl()->isLambda(); ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits