bool UnnecessaryIncludeFinder::VisitTemplateSpecializationTypeLoc ( TemplateSpecializationTypeLoc typeLoc) { CXXRecordDecl* pCXXRecordDecl = typeLoc.getTypePtr()->getAsCXXRecordDecl(); if (pCXXRecordDecl) { markUsed(pCXXRecordDecl->getLocation(), typeLoc.getTemplateNameLoc()); } return true; }
/** * Once the recursive visitor has completed, this routine analyzes the * MostDerivedTypeMap to find errors in the structure of the OMR classes */ void VerifyTypeStructure() { trace("Starting Structure Verification"); for (std::map<CXXRecordDecl*, bool>::iterator I = Types.begin(), E=Types.end(); I != E; ++I) { CXXRecordDecl * Type = I->first; bool extensible = I->second; trace(Type << " " << extensible << " " << getAssociatedConcreteType(Type)); if (extensible && !getAssociatedConcreteType(Type)) { trace("xxxx Issue diagnostic because there's no associated concrete type"); continue; } if (extensible) { //Extnsible type . trace("xxxx Verifying " << Type->getQualifiedNameAsString() << " has no non-extensible base classes." ); for (CXXRecordDecl::base_class_iterator BI = Type->bases_begin(), BE = Type->bases_end(); BI != BE; ++BI) { CXXRecordDecl * base_class = BI->getType()->getAsCXXRecordDecl(); if (base_class && !isExtensible(base_class) // Ensure extensible parent. && !isOMRRootType(Type)) { // OMR Root type can have non-extensible parents. //Base is not extensible, but an extensible type reaches it, with no concrete class in the middle. //Issue diagnostic. std::string diagnostic("OMR_EXTENSIBLE Type "); diagnostic += Type->getQualifiedNameAsString(); diagnostic += " derives from "; diagnostic += base_class->getQualifiedNameAsString(); diagnostic += " that is not marked as OMR_EXTENSIBLE.\n"; DiagnosticsEngine &diagEngine = Context->getDiagnostics(); unsigned diagID = diagEngine.getCustomDiagID(DiagnosticsEngine::Error, "%0"); diagEngine.Report(base_class->getLocation(), diagID) << diagnostic; } } } else { trace("xxxx Verifying " << Type->getQualifiedNameAsString() << " has no non-extensible base classes." ); for (CXXRecordDecl::base_class_iterator BI = Type->bases_begin(), BE = Type->bases_end(); BI != BE; ++BI) { CXXRecordDecl * base_class = BI->getType()->getAsCXXRecordDecl(); if (base_class && isExtensible(base_class) && !isOMRConcreteType(base_class)) { //Base is not extensible, but an extensible type reaches it, with no concrete class in the middle. //Issue diagnostic. std::string diagnostic("Type "); diagnostic += Type->getQualifiedNameAsString(); diagnostic += " derives from "; diagnostic += base_class->getQualifiedNameAsString(); diagnostic += " that is marked as OMR_EXTENSIBLE.\n"; DiagnosticsEngine &diagEngine = Context->getDiagnostics(); unsigned diagID = diagEngine.getCustomDiagID(DiagnosticsEngine::Error, "%0"); diagEngine.Report(Type->getLocation(), diagID) << diagnostic; } } } } //each most derived type }
void Sema::ActOnLambdaError(SourceLocation StartLoc, Scope *CurScope, bool IsInstantiation) { // Leave the expression-evaluation context. DiscardCleanupsInEvaluationContext(); PopExpressionEvaluationContext(); // Leave the context of the lambda. if (!IsInstantiation) PopDeclContext(); // Finalize the lambda. LambdaScopeInfo *LSI = getCurLambda(); CXXRecordDecl *Class = LSI->Lambda; Class->setInvalidDecl(); SmallVector<Decl*, 4> Fields(Class->field_begin(), Class->field_end()); ActOnFields(0, Class->getLocation(), Class, Fields, SourceLocation(), SourceLocation(), 0); CheckCompletedCXXClass(Class); PopFunctionScopeInfo(); }
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); }
ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body, Scope *CurScope, bool IsInstantiation) { // Collect information from the lambda scope. llvm::SmallVector<LambdaExpr::Capture, 4> Captures; llvm::SmallVector<Expr *, 4> CaptureInits; LambdaCaptureDefault CaptureDefault; CXXRecordDecl *Class; CXXMethodDecl *CallOperator; SourceRange IntroducerRange; bool ExplicitParams; bool ExplicitResultType; bool LambdaExprNeedsCleanups; bool ContainsUnexpandedParameterPack; llvm::SmallVector<VarDecl *, 4> ArrayIndexVars; llvm::SmallVector<unsigned, 4> ArrayIndexStarts; { LambdaScopeInfo *LSI = getCurLambda(); CallOperator = LSI->CallOperator; Class = LSI->Lambda; IntroducerRange = LSI->IntroducerRange; ExplicitParams = LSI->ExplicitParams; ExplicitResultType = !LSI->HasImplicitReturnType; LambdaExprNeedsCleanups = LSI->ExprNeedsCleanups; ContainsUnexpandedParameterPack = LSI->ContainsUnexpandedParameterPack; ArrayIndexVars.swap(LSI->ArrayIndexVars); ArrayIndexStarts.swap(LSI->ArrayIndexStarts); // Translate captures. for (unsigned I = 0, N = LSI->Captures.size(); I != N; ++I) { LambdaScopeInfo::Capture From = LSI->Captures[I]; assert(!From.isBlockCapture() && "Cannot capture __block variables"); bool IsImplicit = I >= LSI->NumExplicitCaptures; // Handle 'this' capture. if (From.isThisCapture()) { Captures.push_back(LambdaExpr::Capture(From.getLocation(), IsImplicit, LCK_This)); CaptureInits.push_back(new (Context) CXXThisExpr(From.getLocation(), getCurrentThisType(), /*isImplicit=*/true)); continue; } VarDecl *Var = From.getVariable(); LambdaCaptureKind Kind = From.isCopyCapture()? LCK_ByCopy : LCK_ByRef; Captures.push_back(LambdaExpr::Capture(From.getLocation(), IsImplicit, Kind, Var, From.getEllipsisLoc())); CaptureInits.push_back(From.getCopyExpr()); } switch (LSI->ImpCaptureStyle) { case CapturingScopeInfo::ImpCap_None: CaptureDefault = LCD_None; break; case CapturingScopeInfo::ImpCap_LambdaByval: CaptureDefault = LCD_ByCopy; break; case CapturingScopeInfo::ImpCap_LambdaByref: CaptureDefault = LCD_ByRef; break; case CapturingScopeInfo::ImpCap_Block: llvm_unreachable("block capture in lambda"); break; } // C++11 [expr.prim.lambda]p4: // If a lambda-expression does not include a // trailing-return-type, it is as if the trailing-return-type // denotes the following type: // FIXME: Assumes current resolution to core issue 975. if (LSI->HasImplicitReturnType) { deduceClosureReturnType(*LSI); // - if there are no return statements in the // compound-statement, or all return statements return // either an expression of type void or no expression or // braced-init-list, the type void; if (LSI->ReturnType.isNull()) { LSI->ReturnType = Context.VoidTy; } // Create a function type with the inferred return type. const FunctionProtoType *Proto = CallOperator->getType()->getAs<FunctionProtoType>(); QualType FunctionTy = Context.getFunctionType(LSI->ReturnType, Proto->arg_type_begin(), Proto->getNumArgs(), Proto->getExtProtoInfo()); CallOperator->setType(FunctionTy); } // C++ [expr.prim.lambda]p7: // The lambda-expression's compound-statement yields the // function-body (8.4) of the function call operator [...]. ActOnFinishFunctionBody(CallOperator, Body, IsInstantiation); CallOperator->setLexicalDeclContext(Class); Class->addDecl(CallOperator); PopExpressionEvaluationContext(); // C++11 [expr.prim.lambda]p6: // The closure type for a lambda-expression with no lambda-capture // has a public non-virtual non-explicit const conversion function // to pointer to function having the same parameter and return // types as the closure type's function call operator. if (Captures.empty() && CaptureDefault == LCD_None) addFunctionPointerConversion(*this, IntroducerRange, Class, CallOperator); // Objective-C++: // The closure type for a lambda-expression has a public non-virtual // non-explicit const conversion function to a block pointer having the // same parameter and return types as the closure type's function call // operator. if (getLangOpts().Blocks && getLangOpts().ObjC1) addBlockPointerConversion(*this, IntroducerRange, Class, CallOperator); // Finalize the lambda class. SmallVector<Decl*, 4> Fields; for (RecordDecl::field_iterator i = Class->field_begin(), e = Class->field_end(); i != e; ++i) Fields.push_back(*i); ActOnFields(0, Class->getLocation(), Class, Fields, SourceLocation(), SourceLocation(), 0); CheckCompletedCXXClass(Class); } if (LambdaExprNeedsCleanups) ExprNeedsCleanups = true; LambdaExpr *Lambda = LambdaExpr::Create(Context, Class, IntroducerRange, CaptureDefault, Captures, ExplicitParams, ExplicitResultType, CaptureInits, ArrayIndexVars, ArrayIndexStarts, Body->getLocEnd(), ContainsUnexpandedParameterPack); // C++11 [expr.prim.lambda]p2: // A lambda-expression shall not appear in an unevaluated operand // (Clause 5). if (!CurContext->isDependentContext()) { switch (ExprEvalContexts.back().Context) { case Unevaluated: // We don't actually diagnose this case immediately, because we // could be within a context where we might find out later that // the expression is potentially evaluated (e.g., for typeid). ExprEvalContexts.back().Lambdas.push_back(Lambda); break; case ConstantEvaluated: case PotentiallyEvaluated: case PotentiallyEvaluatedIfUsed: break; } } return MaybeBindToTemporary(Lambda); }
ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body, Scope *CurScope, llvm::Optional<unsigned> ManglingNumber, Decl *ContextDecl, bool IsInstantiation) { // Collect information from the lambda scope. llvm::SmallVector<LambdaExpr::Capture, 4> Captures; llvm::SmallVector<Expr *, 4> CaptureInits; LambdaCaptureDefault CaptureDefault; CXXRecordDecl *Class; CXXMethodDecl *CallOperator; SourceRange IntroducerRange; bool ExplicitParams; bool ExplicitResultType; bool LambdaExprNeedsCleanups; llvm::SmallVector<VarDecl *, 4> ArrayIndexVars; llvm::SmallVector<unsigned, 4> ArrayIndexStarts; { LambdaScopeInfo *LSI = getCurLambda(); CallOperator = LSI->CallOperator; Class = LSI->Lambda; IntroducerRange = LSI->IntroducerRange; ExplicitParams = LSI->ExplicitParams; ExplicitResultType = !LSI->HasImplicitReturnType; LambdaExprNeedsCleanups = LSI->ExprNeedsCleanups; ArrayIndexVars.swap(LSI->ArrayIndexVars); ArrayIndexStarts.swap(LSI->ArrayIndexStarts); // Translate captures. for (unsigned I = 0, N = LSI->Captures.size(); I != N; ++I) { LambdaScopeInfo::Capture From = LSI->Captures[I]; assert(!From.isBlockCapture() && "Cannot capture __block variables"); bool IsImplicit = I >= LSI->NumExplicitCaptures; // Handle 'this' capture. if (From.isThisCapture()) { Captures.push_back(LambdaExpr::Capture(From.getLocation(), IsImplicit, LCK_This)); CaptureInits.push_back(new (Context) CXXThisExpr(From.getLocation(), getCurrentThisType(), /*isImplicit=*/true)); continue; } VarDecl *Var = From.getVariable(); LambdaCaptureKind Kind = From.isCopyCapture()? LCK_ByCopy : LCK_ByRef; Captures.push_back(LambdaExpr::Capture(From.getLocation(), IsImplicit, Kind, Var, From.getEllipsisLoc())); CaptureInits.push_back(From.getCopyExpr()); } switch (LSI->ImpCaptureStyle) { case CapturingScopeInfo::ImpCap_None: CaptureDefault = LCD_None; break; case CapturingScopeInfo::ImpCap_LambdaByval: CaptureDefault = LCD_ByCopy; break; case CapturingScopeInfo::ImpCap_LambdaByref: CaptureDefault = LCD_ByRef; break; case CapturingScopeInfo::ImpCap_Block: llvm_unreachable("block capture in lambda"); break; } // C++11 [expr.prim.lambda]p4: // If a lambda-expression does not include a // trailing-return-type, it is as if the trailing-return-type // denotes the following type: // FIXME: Assumes current resolution to core issue 975. if (LSI->HasImplicitReturnType) { // - if there are no return statements in the // compound-statement, or all return statements return // either an expression of type void or no expression or // braced-init-list, the type void; if (LSI->ReturnType.isNull()) { LSI->ReturnType = Context.VoidTy; } else { // C++11 [expr.prim.lambda]p4: // - if the compound-statement is of the form // // { attribute-specifier-seq[opt] return expression ; } // // the type of the returned expression after // lvalue-to-rvalue conversion (4.1), array-to-pointer // conver- sion (4.2), and function-to-pointer conversion // (4.3); // // Since we're accepting the resolution to a post-C++11 core // issue with a non-trivial extension, provide a warning (by // default). CompoundStmt *CompoundBody = cast<CompoundStmt>(Body); if (!(CompoundBody->size() == 1 && isa<ReturnStmt>(*CompoundBody->body_begin())) && !Context.hasSameType(LSI->ReturnType, Context.VoidTy)) Diag(IntroducerRange.getBegin(), diag::ext_lambda_implies_void_return); } // Create a function type with the inferred return type. const FunctionProtoType *Proto = CallOperator->getType()->getAs<FunctionProtoType>(); QualType FunctionTy = Context.getFunctionType(LSI->ReturnType, Proto->arg_type_begin(), Proto->getNumArgs(), Proto->getExtProtoInfo()); CallOperator->setType(FunctionTy); } // C++ [expr.prim.lambda]p7: // The lambda-expression's compound-statement yields the // function-body (8.4) of the function call operator [...]. ActOnFinishFunctionBody(CallOperator, Body, IsInstantiation); CallOperator->setLexicalDeclContext(Class); Class->addDecl(CallOperator); PopExpressionEvaluationContext(); // C++11 [expr.prim.lambda]p6: // The closure type for a lambda-expression with no lambda-capture // has a public non-virtual non-explicit const conversion function // to pointer to function having the same parameter and return // types as the closure type's function call operator. if (Captures.empty() && CaptureDefault == LCD_None) addFunctionPointerConversion(*this, IntroducerRange, Class, CallOperator); // Objective-C++: // The closure type for a lambda-expression has a public non-virtual // non-explicit const conversion function to a block pointer having the // same parameter and return types as the closure type's function call // operator. if (getLangOpts().Blocks && getLangOpts().ObjC1) addBlockPointerConversion(*this, IntroducerRange, Class, CallOperator); // Finalize the lambda class. SmallVector<Decl*, 4> Fields(Class->field_begin(), Class->field_end()); ActOnFields(0, Class->getLocation(), Class, Fields, SourceLocation(), SourceLocation(), 0); CheckCompletedCXXClass(Class); } if (LambdaExprNeedsCleanups) ExprNeedsCleanups = true; // If we don't already have a mangling number for this lambda expression, // allocate one now. if (!ManglingNumber) { ContextDecl = ExprEvalContexts.back().LambdaContextDecl; enum ContextKind { Normal, DefaultArgument, DataMember, StaticDataMember } Kind = Normal; // Default arguments of member function parameters that appear in a class // definition, as well as the initializers of data members, receive special // treatment. Identify them. if (ContextDecl) { if (ParmVarDecl *Param = dyn_cast<ParmVarDecl>(ContextDecl)) { if (const DeclContext *LexicalDC = Param->getDeclContext()->getLexicalParent()) if (LexicalDC->isRecord()) Kind = DefaultArgument; } else if (VarDecl *Var = dyn_cast<VarDecl>(ContextDecl)) { if (Var->getDeclContext()->isRecord()) Kind = StaticDataMember; } else if (isa<FieldDecl>(ContextDecl)) { Kind = DataMember; } } switch (Kind) { case Normal: if (CurContext->isDependentContext() || isInInlineFunction(CurContext)) ManglingNumber = Context.getLambdaManglingNumber(CallOperator); else ManglingNumber = 0; // There is no special context for this lambda. ContextDecl = 0; break; case StaticDataMember: if (!CurContext->isDependentContext()) { ManglingNumber = 0; ContextDecl = 0; break; } // Fall through to assign a mangling number. case DataMember: case DefaultArgument: ManglingNumber = ExprEvalContexts.back().getLambdaMangleContext() .getManglingNumber(CallOperator); break; } } LambdaExpr *Lambda = LambdaExpr::Create(Context, Class, IntroducerRange, CaptureDefault, Captures, ExplicitParams, ExplicitResultType, CaptureInits, ArrayIndexVars, ArrayIndexStarts, Body->getLocEnd(), *ManglingNumber, ContextDecl); // C++11 [expr.prim.lambda]p2: // A lambda-expression shall not appear in an unevaluated operand // (Clause 5). if (!CurContext->isDependentContext()) { switch (ExprEvalContexts.back().Context) { case Unevaluated: // We don't actually diagnose this case immediately, because we // could be within a context where we might find out later that // the expression is potentially evaluated (e.g., for typeid). ExprEvalContexts.back().Lambdas.push_back(Lambda); break; case ConstantEvaluated: case PotentiallyEvaluated: case PotentiallyEvaluatedIfUsed: break; } } return MaybeBindToTemporary(Lambda); }