diff options
Diffstat (limited to 'lib/Sema')
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 7 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 12 | ||||
-rw-r--r-- | lib/Sema/SemaLambda.cpp | 137 | ||||
-rw-r--r-- | lib/Sema/SemaStmt.cpp | 65 |
4 files changed, 174 insertions, 47 deletions
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index d63922ba32..99814911e0 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -7659,7 +7659,12 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(FD)) MarkVTableUsed(FD->getLocation(), Constructor->getParent()); - computeNRVO(Body, getCurFunction()); + // Try to apply the named return value optimization. We have to check + // if we can do this here because lambdas keep return statements around + // to deduce an implicit return type. + if (getLangOpts().CPlusPlus && FD->getResultType()->isRecordType() && + !FD->isDependentContext()) + computeNRVO(Body, getCurFunction()); } assert((FD == getCurFunctionDecl() || getCurLambda()->CallOperator == FD) && diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index e65c21d085..1f2850f6ec 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -9350,7 +9350,10 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, PopExpressionEvaluationContext(); BlockScopeInfo *BSI = cast<BlockScopeInfo>(FunctionScopes.back()); - + + if (BSI->HasImplicitReturnType) + deduceClosureReturnType(*BSI); + PopDeclContext(); QualType RetTy = Context.VoidTy; @@ -9423,7 +9426,12 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, BSI->TheDecl->setBody(cast<CompoundStmt>(Body)); - computeNRVO(Body, getCurBlock()); + // Try to apply the named return value optimization. We have to check again + // if we can do this, though, because blocks keep return statements around + // to deduce an implicit return type. + if (getLangOpts().CPlusPlus && RetTy->isRecordType() && + !BSI->TheDecl->isDependentContext()) + computeNRVO(Body, getCurBlock()); BlockExpr *Result = new (Context) BlockExpr(BSI->TheDecl, BlockTy); const AnalysisBasedWarnings::Policy &WP = AnalysisWarnings.getDefaultPolicy(); diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp index 07ee890562..6c78d83612 100644 --- a/lib/Sema/SemaLambda.cpp +++ b/lib/Sema/SemaLambda.cpp @@ -214,6 +214,141 @@ void Sema::addLambdaParameters(CXXMethodDecl *CallOperator, Scope *CurScope) { } } +static bool checkReturnValueType(const ASTContext &Ctx, const Expr *E, + QualType &DeducedType, + QualType &AlternateType) { + // Handle ReturnStmts with no expressions. + if (!E) { + if (AlternateType.isNull()) + AlternateType = Ctx.VoidTy; + + return Ctx.hasSameType(DeducedType, Ctx.VoidTy); + } + + QualType StrictType = E->getType(); + QualType LooseType = StrictType; + + // In C, enum constants have the type of their underlying integer type, + // not the enum. When inferring block return types, we should allow + // the enum type if an enum constant is used, unless the enum is + // anonymous (in which case there can be no variables of its type). + if (!Ctx.getLangOpts().CPlusPlus) { + const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts()); + if (DRE) { + const Decl *D = DRE->getDecl(); + if (const EnumConstantDecl *ECD = dyn_cast<EnumConstantDecl>(D)) { + const EnumDecl *Enum = cast<EnumDecl>(ECD->getDeclContext()); + if (Enum->getDeclName() || Enum->getTypedefNameForAnonDecl()) + LooseType = Ctx.getTypeDeclType(Enum); + } + } + } + + // Special case for the first return statement we find. + // The return type has already been tentatively set, but we might still + // have an alternate type we should prefer. + if (AlternateType.isNull()) + AlternateType = LooseType; + + if (Ctx.hasSameType(DeducedType, StrictType)) { + // FIXME: The loose type is different when there are constants from two + // different enums. We could consider warning here. + if (AlternateType != Ctx.DependentTy) + if (!Ctx.hasSameType(AlternateType, LooseType)) + AlternateType = Ctx.VoidTy; + return true; + } + + if (Ctx.hasSameType(DeducedType, LooseType)) { + // Use DependentTy to signal that we're using an alternate type and may + // need to add casts somewhere. + AlternateType = Ctx.DependentTy; + return true; + } + + if (Ctx.hasSameType(AlternateType, StrictType) || + Ctx.hasSameType(AlternateType, LooseType)) { + DeducedType = AlternateType; + // Use DependentTy to signal that we're using an alternate type and may + // need to add casts somewhere. + AlternateType = Ctx.DependentTy; + return true; + } + + return false; +} + +void Sema::deduceClosureReturnType(CapturingScopeInfo &CSI) { + assert(CSI.HasImplicitReturnType); + + // First case: no return statements, implicit void return type. + ASTContext &Ctx = getASTContext(); + if (CSI.Returns.empty()) { + // It's possible there were simply no /valid/ return statements. + // In this case, the first one we found may have at least given us a type. + if (CSI.ReturnType.isNull()) + CSI.ReturnType = Ctx.VoidTy; + return; + } + + // Second case: at least one return statement has dependent type. + // Delay type checking until instantiation. + assert(!CSI.ReturnType.isNull() && "We should have a tentative return type."); + if (CSI.ReturnType->isDependentType()) + return; + + // Third case: only one return statement. Don't bother doing extra work! + SmallVectorImpl<ReturnStmt*>::iterator I = CSI.Returns.begin(), + E = CSI.Returns.end(); + if (I+1 == E) + return; + + // General case: many return statements. + // Check that they all have compatible return types. + // For now, that means "identical", with an exception for enum constants. + // (In C, enum constants have the type of their underlying integer type, + // not the type of the enum. C++ uses the type of the enum.) + QualType AlternateType; + + // We require the return types to strictly match here. + for (; I != E; ++I) { + const ReturnStmt *RS = *I; + const Expr *RetE = RS->getRetValue(); + if (!checkReturnValueType(Ctx, RetE, CSI.ReturnType, AlternateType)) { + // FIXME: This is a poor diagnostic for ReturnStmts without expressions. + Diag(RS->getLocStart(), + diag::err_typecheck_missing_return_type_incompatible) + << (RetE ? RetE->getType() : Ctx.VoidTy) << CSI.ReturnType + << isa<LambdaScopeInfo>(CSI); + // Don't bother fixing up the return statements in the block if some of + // them are unfixable anyway. + AlternateType = Ctx.VoidTy; + // Continue iterating so that we keep emitting diagnostics. + } + } + + // If our return statements turned out to be compatible, but we needed to + // pick a different return type, go through and fix the ones that need it. + if (AlternateType == Ctx.DependentTy) { + for (SmallVectorImpl<ReturnStmt*>::iterator I = CSI.Returns.begin(), + E = CSI.Returns.end(); + I != E; ++I) { + ReturnStmt *RS = *I; + Expr *RetE = RS->getRetValue(); + if (RetE->getType() == CSI.ReturnType) + continue; + + // Right now we only support integral fixup casts. + assert(CSI.ReturnType->isIntegralOrUnscopedEnumerationType()); + assert(RetE->getType()->isIntegralOrUnscopedEnumerationType()); + ExprResult Casted = ImpCastExprToType(RetE, CSI.ReturnType, + CK_IntegralCast); + assert(Casted.isUsable()); + RS->setRetValue(Casted.take()); + } + } +} + void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, Declarator &ParamInfo, Scope *CurScope) { @@ -659,6 +794,8 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body, // 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 diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 999be9109d..62cd0d0d60 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -2120,40 +2120,22 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { // [expr.prim.lambda]p4 in C++11; block literals follow a superset of those // rules which allows multiple return statements. CapturingScopeInfo *CurCap = cast<CapturingScopeInfo>(getCurFunction()); + QualType FnRetType = CurCap->ReturnType; + + // For blocks/lambdas with implicit return types, we check each return + // statement individually, and deduce the common return type when the block + // or lambda is completed. if (CurCap->HasImplicitReturnType) { - QualType ReturnT; if (RetValExp && !isa<InitListExpr>(RetValExp)) { ExprResult Result = DefaultFunctionArrayLvalueConversion(RetValExp); if (Result.isInvalid()) return StmtError(); RetValExp = Result.take(); - if (!RetValExp->isTypeDependent()) { - ReturnT = RetValExp->getType(); - - // In C, enum constants have the type of their underlying integer type, - // not the enum. When inferring block return values, we should infer - // the enum type if an enum constant is used, unless the enum is - // anonymous (in which case there can be no variables of its type). - if (!getLangOpts().CPlusPlus) { - Expr *InsideExpr = RetValExp->IgnoreParenImpCasts(); - if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(InsideExpr)) { - Decl *D = DRE->getDecl(); - if (EnumConstantDecl *ECD = dyn_cast<EnumConstantDecl>(D)) { - EnumDecl *Enum = cast<EnumDecl>(ECD->getDeclContext()); - if (Enum->getDeclName() || Enum->getTypedefNameForAnonDecl()) { - ReturnT = Context.getTypeDeclType(Enum); - ExprResult Casted = ImpCastExprToType(RetValExp, ReturnT, - CK_IntegralCast); - assert(Casted.isUsable()); - RetValExp = Casted.take(); - } - } - } - } - } else { - ReturnT = Context.DependentTy; - } + if (!RetValExp->isTypeDependent()) + FnRetType = RetValExp->getType(); + else + FnRetType = CurCap->ReturnType = Context.DependentTy; } else { if (RetValExp) { // C++11 [expr.lambda.prim]p4 bans inferring the result from an @@ -2163,21 +2145,14 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { << RetValExp->getSourceRange(); } - ReturnT = Context.VoidTy; + FnRetType = Context.VoidTy; } - // We require the return types to strictly match here. - if (!CurCap->ReturnType.isNull() && - !CurCap->ReturnType->isDependentType() && - !ReturnT->isDependentType() && - !Context.hasSameType(ReturnT, CurCap->ReturnType)) { - Diag(ReturnLoc, diag::err_typecheck_missing_return_type_incompatible) - << ReturnT << CurCap->ReturnType - << (getCurLambda() != 0); - return StmtError(); - } - CurCap->ReturnType = ReturnT; + + // Although we'll properly infer the type of the block once it's completed, + // make sure we provide a return type now for better error recovery. + if (CurCap->ReturnType.isNull()) + CurCap->ReturnType = FnRetType; } - QualType FnRetType = CurCap->ReturnType; assert(!FnRetType.isNull()); if (BlockScopeInfo *CurBlock = dyn_cast<BlockScopeInfo>(CurCap)) { @@ -2245,10 +2220,12 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { ReturnStmt *Result = new (Context) ReturnStmt(ReturnLoc, RetValExp, NRVOCandidate); - // If we need to check for the named return value optimization, save the - // return statement in our scope for later processing. - if (getLangOpts().CPlusPlus && FnRetType->isRecordType() && - !CurContext->isDependentContext()) + // If we need to check for the named return value optimization, + // or if we need to infer the return type, + // save the return statement in our scope for later processing. + if (CurCap->HasImplicitReturnType || + (getLangOpts().CPlusPlus && FnRetType->isRecordType() && + !CurContext->isDependentContext())) FunctionScopes.back()->Returns.push_back(Result); return Owned(Result); |