aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaLambda.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema/SemaLambda.cpp')
-rw-r--r--lib/Sema/SemaLambda.cpp137
1 files changed, 137 insertions, 0 deletions
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