// TODO: Add classes with a finalize() method that specialize FinalizerTrait. bool RecordInfo::NeedsFinalization() { if (does_need_finalization_ == kNotComputed) { // Rely on hasNonTrivialDestructor(), but if the only // identifiable reason for it being true is the presence // of a safely ignorable class as a direct base, // or we're processing such an 'ignorable' class, then it does // not need finalization. does_need_finalization_ = record_->hasNonTrivialDestructor() ? kTrue : kFalse; if (!does_need_finalization_) return does_need_finalization_; CXXDestructorDecl* dtor = record_->getDestructor(); if (dtor && dtor->isUserProvided()) return does_need_finalization_; for (Fields::iterator it = GetFields().begin(); it != GetFields().end(); ++it) { if (it->second.edge()->NeedsFinalization()) return does_need_finalization_; } for (Bases::iterator it = GetBases().begin(); it != GetBases().end(); ++it) { if (it->second.info()->NeedsFinalization()) return does_need_finalization_; } // Destructor was non-trivial due to bases with destructors that // can be safely ignored. Hence, no need for finalization. does_need_finalization_ = kFalse; } return does_need_finalization_; }
bool BlinkGCPluginConsumer::HasNonEmptyFinalizer(RecordInfo* info) { CXXDestructorDecl* dtor = info->record()->getDestructor(); if (dtor && dtor->isUserProvided()) { if (!dtor->hasBody() || !EmptyStmtVisitor::isEmpty(dtor->getBody())) return true; } for (RecordInfo::Bases::iterator it = info->GetBases().begin(); it != info->GetBases().end(); ++it) { if (HasNonEmptyFinalizer(it->second.info())) return true; } for (RecordInfo::Fields::iterator it = info->GetFields().begin(); it != info->GetFields().end(); ++it) { if (it->second.edge()->NeedsFinalization()) return true; } return false; }
// TODO: Should we collect destructors similar to trace methods? void BlinkGCPluginConsumer::CheckFinalization(RecordInfo* info) { CXXDestructorDecl* dtor = info->record()->getDestructor(); // For finalized classes, check the finalization method if possible. if (info->IsGCFinalized()) { if (dtor && dtor->hasBody()) { CheckFinalizerVisitor visitor(&cache_, info->IsEagerlyFinalized()); visitor.TraverseCXXMethodDecl(dtor); if (!visitor.finalized_fields().empty()) { ReportFinalizerAccessesFinalizedFields( dtor, &visitor.finalized_fields()); } } return; } // Don't require finalization of a mixin that has not yet been "mixed in". if (info->IsGCMixin()) return; // Report the finalization error, and proceed to print possible causes for // the finalization requirement. ReportClassRequiresFinalization(info); if (dtor && dtor->isUserProvided()) NoteUserDeclaredDestructor(dtor); for (RecordInfo::Bases::iterator it = info->GetBases().begin(); it != info->GetBases().end(); ++it) { if (it->second.info()->NeedsFinalization()) NoteBaseRequiresFinalization(&it->second); } for (RecordInfo::Fields::iterator it = info->GetFields().begin(); it != info->GetFields().end(); ++it) { if (it->second.edge()->NeedsFinalization()) NoteField(&it->second, diag_field_requires_finalization_note_); } }
void VirtualCallsFromCTOR::VisitDecl(Decl *decl) { CXXConstructorDecl *ctorDecl = dyn_cast<CXXConstructorDecl>(decl); CXXDestructorDecl *dtorDecl = dyn_cast<CXXDestructorDecl>(decl); if (ctorDecl == nullptr && dtorDecl == nullptr) return; Stmt *ctorOrDtorBody = ctorDecl ? ctorDecl->getBody() : dtorDecl->getBody(); if (ctorOrDtorBody == nullptr) return; CXXRecordDecl *classDecl = ctorDecl ? ctorDecl->getParent() : dtorDecl->getParent(); std::vector<Stmt*> processedStmts; SourceLocation loc = containsVirtualCall(classDecl, ctorOrDtorBody, processedStmts); if (loc.isValid()) { if (ctorDecl != nullptr) { emitWarning(decl->getLocStart(), "Calling pure virtual function in CTOR"); } else { emitWarning(decl->getLocStart(), "Calling pure virtual function in DTOR"); } emitWarning(loc, "Called here"); } }
OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { SmallVector<Expr *, 8> Vars; for (ArrayRef<Expr *>::iterator I = VarList.begin(), E = VarList.end(); I != E; ++I) { assert(*I && "NULL expr in OpenMP firstprivate clause."); if (isa<DependentScopeDeclRefExpr>(*I)) { // It will be analyzed later. Vars.push_back(*I); continue; } SourceLocation ELoc = (*I)->getExprLoc(); // OpenMP [2.1, C/C++] // A list item is a variable name. // OpenMP [2.9.3.3, Restrictions, p.1] // A variable that is part of another variable (as an array or // structure element) cannot appear in a private clause. DeclRefExpr *DE = dyn_cast_or_null<DeclRefExpr>(*I); if (!DE || !isa<VarDecl>(DE->getDecl())) { Diag(ELoc, diag::err_omp_expected_var_name) << (*I)->getSourceRange(); continue; } Decl *D = DE->getDecl(); VarDecl *VD = cast<VarDecl>(D); QualType Type = VD->getType(); if (Type->isDependentType() || Type->isInstantiationDependentType()) { // It will be analyzed later. Vars.push_back(DE); continue; } // OpenMP [2.9.3.3, Restrictions, C/C++, p.3] // A variable that appears in a private clause must not have an incomplete // type or a reference type. if (RequireCompleteType(ELoc, Type, diag::err_omp_firstprivate_incomplete_type)) { continue; } if (Type->isReferenceType()) { Diag(ELoc, diag::err_omp_clause_ref_type_arg) << getOpenMPClauseName(OMPC_firstprivate) << Type; bool IsDecl = VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : diag::note_defined_here) << VD; continue; } // OpenMP [2.9.3.4, Restrictions, C/C++, p.1] // A variable of class type (or array thereof) that appears in a private // clause requires an accesible, unambiguous copy constructor for the // class type. Type = Context.getBaseElementType(Type); CXXRecordDecl *RD = getLangOpts().CPlusPlus ? Type.getNonReferenceType()->getAsCXXRecordDecl() : 0; if (RD) { CXXConstructorDecl *CD = LookupCopyingConstructor(RD, 0); PartialDiagnostic PD = PartialDiagnostic(PartialDiagnostic::NullDiagnostic()); if (!CD || CheckConstructorAccess(ELoc, CD, InitializedEntity::InitializeTemporary(Type), CD->getAccess(), PD) == AR_inaccessible || CD->isDeleted()) { Diag(ELoc, diag::err_omp_required_method) << getOpenMPClauseName(OMPC_firstprivate) << 1; bool IsDecl = VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : diag::note_defined_here) << VD; Diag(RD->getLocation(), diag::note_previous_decl) << RD; continue; } MarkFunctionReferenced(ELoc, CD); DiagnoseUseOfDecl(CD, ELoc); CXXDestructorDecl *DD = RD->getDestructor(); if (DD) { if (CheckDestructorAccess(ELoc, DD, PD) == AR_inaccessible || DD->isDeleted()) { Diag(ELoc, diag::err_omp_required_method) << getOpenMPClauseName(OMPC_firstprivate) << 4; bool IsDecl = VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : diag::note_defined_here) << VD; Diag(RD->getLocation(), diag::note_previous_decl) << RD; continue; } MarkFunctionReferenced(ELoc, DD); DiagnoseUseOfDecl(DD, ELoc); } } // If StartLoc and EndLoc are invalid - this is an implicit firstprivate // variable and it was checked already. if (StartLoc.isValid() && EndLoc.isValid()) { DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD); Type = Type.getNonReferenceType().getCanonicalType(); bool IsConstant = Type.isConstant(Context); Type = Context.getBaseElementType(Type); // OpenMP [2.4.13, Data-sharing Attribute Clauses] // A list item that specifies a given variable may not appear in more // than one clause on the same directive, except that a variable may be // specified in both firstprivate and lastprivate clauses. // TODO: add processing for lastprivate. if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_firstprivate && DVar.RefExpr) { Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind) << getOpenMPClauseName(OMPC_firstprivate); Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_explicit_dsa) << getOpenMPClauseName(DVar.CKind); continue; } // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced // in a Construct] // Variables with the predetermined data-sharing attributes may not be // listed in data-sharing attributes clauses, except for the cases // listed below. For these exceptions only, listing a predetermined // variable in a data-sharing attribute clause is allowed and overrides // the variable's predetermined data-sharing attributes. // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced // in a Construct, C/C++, p.2] // Variables with const-qualified type having no mutable member may be // listed in a firstprivate clause, even if they are static data members. if (!(IsConstant || VD->isStaticDataMember()) && !DVar.RefExpr && DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_shared) { Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind) << getOpenMPClauseName(OMPC_firstprivate); Diag(VD->getLocation(), diag::note_omp_predetermined_dsa) << getOpenMPClauseName(DVar.CKind); continue; } // OpenMP [2.9.3.4, Restrictions, p.2] // A list item that is private within a parallel region must not appear // in a firstprivate clause on a worksharing construct if any of the // worksharing regions arising from the worksharing construct ever bind // to any of the parallel regions arising from the parallel construct. // OpenMP [2.9.3.4, Restrictions, p.3] // A list item that appears in a reduction clause of a parallel construct // must not appear in a firstprivate clause on a worksharing or task // construct if any of the worksharing or task regions arising from the // worksharing or task construct ever bind to any of the parallel regions // arising from the parallel construct. // OpenMP [2.9.3.4, Restrictions, p.4] // A list item that appears in a reduction clause in worksharing // construct must not appear in a firstprivate clause in a task construct // encountered during execution of any of the worksharing regions arising // from the worksharing construct. // TODO: } DSAStack->addDSA(VD, DE, OMPC_firstprivate); Vars.push_back(DE); } if (Vars.empty()) return 0; return OMPFirstprivateClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars); }
OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { SmallVector<Expr *, 8> Vars; for (ArrayRef<Expr *>::iterator I = VarList.begin(), E = VarList.end(); I != E; ++I) { assert(*I && "NULL expr in OpenMP private clause."); if (isa<DependentScopeDeclRefExpr>(*I)) { // It will be analyzed later. Vars.push_back(*I); continue; } SourceLocation ELoc = (*I)->getExprLoc(); // OpenMP [2.1, C/C++] // A list item is a variable name. // OpenMP [2.9.3.3, Restrictions, p.1] // A variable that is part of another variable (as an array or // structure element) cannot appear in a private clause. DeclRefExpr *DE = dyn_cast_or_null<DeclRefExpr>(*I); if (!DE || !isa<VarDecl>(DE->getDecl())) { Diag(ELoc, diag::err_omp_expected_var_name) << (*I)->getSourceRange(); continue; } Decl *D = DE->getDecl(); VarDecl *VD = cast<VarDecl>(D); QualType Type = VD->getType(); if (Type->isDependentType() || Type->isInstantiationDependentType()) { // It will be analyzed later. Vars.push_back(DE); continue; } // OpenMP [2.9.3.3, Restrictions, C/C++, p.3] // A variable that appears in a private clause must not have an incomplete // type or a reference type. if (RequireCompleteType(ELoc, Type, diag::err_omp_private_incomplete_type)) { continue; } if (Type->isReferenceType()) { Diag(ELoc, diag::err_omp_clause_ref_type_arg) << getOpenMPClauseName(OMPC_private) << Type; bool IsDecl = VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : diag::note_defined_here) << VD; continue; } // OpenMP [2.9.3.3, Restrictions, C/C++, p.1] // A variable of class type (or array thereof) that appears in a private // clause requires an accesible, unambiguous default constructor for the // class type. while (Type.getNonReferenceType()->isArrayType()) { Type = cast<ArrayType>( Type.getNonReferenceType().getTypePtr())->getElementType(); } CXXRecordDecl *RD = getLangOpts().CPlusPlus ? Type.getNonReferenceType()->getAsCXXRecordDecl() : 0; if (RD) { CXXConstructorDecl *CD = LookupDefaultConstructor(RD); PartialDiagnostic PD = PartialDiagnostic(PartialDiagnostic::NullDiagnostic()); if (!CD || CheckConstructorAccess(ELoc, CD, InitializedEntity::InitializeTemporary(Type), CD->getAccess(), PD) == AR_inaccessible || CD->isDeleted()) { Diag(ELoc, diag::err_omp_required_method) << getOpenMPClauseName(OMPC_private) << 0; bool IsDecl = VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : diag::note_defined_here) << VD; Diag(RD->getLocation(), diag::note_previous_decl) << RD; continue; } MarkFunctionReferenced(ELoc, CD); DiagnoseUseOfDecl(CD, ELoc); CXXDestructorDecl *DD = RD->getDestructor(); if (DD) { if (CheckDestructorAccess(ELoc, DD, PD) == AR_inaccessible || DD->isDeleted()) { Diag(ELoc, diag::err_omp_required_method) << getOpenMPClauseName(OMPC_private) << 4; bool IsDecl = VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : diag::note_defined_here) << VD; Diag(RD->getLocation(), diag::note_previous_decl) << RD; continue; } MarkFunctionReferenced(ELoc, DD); DiagnoseUseOfDecl(DD, ELoc); } } // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced // in a Construct] // Variables with the predetermined data-sharing attributes may not be // listed in data-sharing attributes clauses, except for the cases // listed below. For these exceptions only, listing a predetermined // variable in a data-sharing attribute clause is allowed and overrides // the variable's predetermined data-sharing attributes. DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD); if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_private) { Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind) << getOpenMPClauseName(OMPC_private); if (DVar.RefExpr) { Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_explicit_dsa) << getOpenMPClauseName(DVar.CKind); } else { Diag(VD->getLocation(), diag::note_omp_predetermined_dsa) << getOpenMPClauseName(DVar.CKind); } continue; } DSAStack->addDSA(VD, DE, OMPC_private); Vars.push_back(DE); } if (Vars.empty()) return 0; return OMPPrivateClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars); }
bool isFunctionDef(const Decl* D){ string node = D->getDeclKindName(); CXXDestructorDecl* CD = (CXXDestructorDecl*) D; return ((node == "CXXConstructor" || node == "CXXDestructor" || node == "CXXMethod") && !CD->isImplicit()); }
/* this helper function is called when the traversal reaches a node of type Decl */ bool DeclHelper(Decl *D){ const Stmt* parent = getStmtParent(D, Context); //const Stmt* parentsParent = getStmtParent(parent, Context); //if it is part of the (init; condition; increment) of a for loop, we don't care about it if(isFlowControl(D, Context)){ return false; } //supresses the catch stmt's arguments if(parent != NULL && strcmp(parent->getStmtClassName(), "CXXCatchStmt") == 0){ return true; } string filename; if(!isInCurFile(Context, D, filename) && filename.size() != 0){ return false; }else if(filename.size() == 0){ return true; } string output = ""; //get the name of the node type string node = D->getDeclKindName(); //calculate the current level, nextLevel, and previousLevel int intLevel = getLevelDecl(D);int intNextLevel = intLevel+1; int intNextNextLevel = intLevel+2; int intPrevLevel = intLevel-1; //create string values for the levels to use as output string level; string nextLevel; string nextNextLevel; string prevLevel; stringstream ss; stringstream ss2; stringstream ss3; stringstream ss4; ss << intLevel; level = ss.str(); ss2 << intNextLevel; nextLevel = ss2.str(); ss3 << intPrevLevel; prevLevel = ss3.str(); ss4 << intNextNextLevel; nextNextLevel = ss4.str(); if(callStackDebug && !callStack.empty()){ cerr << "decl: call stack top: " << callStack.top()->getStmtClassName() << endl; } //if top of stack is no longer a parent while(!callStack.empty() && numClosingArgsNeeded > 0 && !isParentDecl(D, callStack.top()->getStmtClassName())){ if(debugPrint){ cerr << "adding args" << endl; } numClosingArgsNeeded--; output += "</args,1>\n"; callStack.pop(); if(callStackDebug){ cerr << "poping" << endl; printCallStack(); } } //add new calls to stack if(isParentDeclInCurFile(D,"CXXConstructExpr") && isParentDecl(D, "CXXConstructExpr")){ if(debugPrint){ cerr << "setting previousConstructorCall to true" << endl; } }else if(isParentDeclInCurFile(D,"CXXTemporaryObjectExpr") && isParentDecl(D, "CXXTemporaryObjectExpr")){ if(debugPrint){ cerr << "setting previousTempConstructorCallArg" << endl; } }else if(isParentDecl(D, "CallExpr")){ if(debugPrint){ cerr << "setting previousCallArgs to true" << endl; } }else if(isParentDecl(D, "CXXMemberCallExpr")){ if(debugPrint){ cerr << "setting previousMemberCallArg to true" << endl; } } if(isParentDecl(getDeclParent(D, Context), "Var")){ previousRhsDecl = true; if(debugPrint){ cout << "setting prev var to true" << endl; } }else if(previousRhsDecl && numClosingVarsNeeded > 0){ //if the current node is not a child of a variable declaration //but the previous node was a child of a variable declation //then we know to print a </decl> output +="</variableDecl,1>\n"; numClosingVarsNeeded--; previousRhsDecl = false; } if(node == "Var"){ output += "<variableDecl, " + prevLevel + ">"; numClosingVarsNeeded++; VarDecl* VD = (VarDecl*) D; if(!VD->hasInit()){ output +="\n</variableDecl,1>\n"; numClosingVarsNeeded--; } }else if(node == "Function"){ FunctionDecl* FD = (FunctionDecl*) D; output += "<functionDef," + level +">"; //add function name to the output output += "\n<name: " + FD->getNameInfo().getAsString() + "," + nextLevel + ">"; }else if(node == "CXXRecord"){ const Decl* parent = getDeclParent(D, Context); if(parent && strcmp(parent->getDeclKindName(), "CXXRecord") != 0){ CXXRecordDecl* CD = (CXXRecordDecl*) D; output += "<classDef," + level + ">"; output += "\n<name: " + CD->getNameAsString() + "," + nextLevel + ">"; output += "\n<bases," + nextLevel + ">"; //iterate over all bases and add them to the output CXXRecordDecl::base_class_iterator basesItr = CD->bases_begin(); while(basesItr != CD->bases_end()){ QualType qt = basesItr->getType(); output += "\n<base: " + qt.getBaseTypeIdentifier()->getName().str(); output += "," + nextNextLevel + ">"; basesItr++; } //iterate over all of the virtual bases and add them to the output auto vBasesItr = CD->vbases_begin(); while(vBasesItr != CD->vbases_end()){ QualType qt = vBasesItr->getType(); output += "\n<base: " + qt.getBaseTypeIdentifier()->getName().str(); output += "," + nextNextLevel + ">"; vBasesItr++; } } }else if(node == "CXXDestructor"){ CXXDestructorDecl* CD = (CXXDestructorDecl*) D; if(!CD->isImplicit()){ output += "<functionDef," + level +">"; //add function name to the output output += "\n<name: ~" + CD->getNameInfo().getAsString() + "," + nextLevel + ">"; } }else if(node == "CXXConstructor"){ CXXConstructorDecl* CD = (CXXConstructorDecl*) D; if(!CD->isImplicit()){ output += "<functionDef," + level +">"; //add function name to the output output += "\n<name: " + CD->getNameInfo().getAsString() + "," + nextLevel + ">"; } }else if(node == "CXXMethod"){ CXXMethodDecl* CM = (CXXMethodDecl*) D; if(!CM->isImplicit()){ output += "<functionDef," + level +">"; //add function name to the output output += "\n<name: " + CM->getNameInfo().getAsString() + "," + nextLevel + ">"; } }else{ if(debugPrint){ output += "<"; output += node; output += ">"; } } if(output.size() != 0){ cout << output << endl; } return true; }