diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Sema/SemaLambda.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Sema/SemaLambda.cpp | 316 |
1 files changed, 228 insertions, 88 deletions
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaLambda.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaLambda.cpp index 6ef8d88..6414c6f 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaLambda.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaLambda.cpp @@ -54,9 +54,7 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class, SourceRange IntroducerRange, TypeSourceInfo *MethodType, SourceLocation EndLoc, - llvm::ArrayRef<ParmVarDecl *> Params, - llvm::Optional<unsigned> ManglingNumber, - Decl *ContextDecl) { + llvm::ArrayRef<ParmVarDecl *> Params) { // C++11 [expr.prim.lambda]p5: // The closure type for a lambda-expression has a public inline function // call operator (13.5.4) whose parameters and return type are described by @@ -98,64 +96,76 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class, P != PEnd; ++P) (*P)->setOwningFunction(Method); } - - // 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(Method); - 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(Method); - break; + + // Allocate a mangling number for this lambda expression, if the ABI + // requires one. + Decl *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; } } - Class->setLambdaMangling(*ManglingNumber, ContextDecl); + // Itanium ABI [5.1.7]: + // In the following contexts [...] the one-definition rule requires closure + // types in different translation units to "correspond": + bool IsInNonspecializedTemplate = + !ActiveTemplateInstantiations.empty() || CurContext->isDependentContext(); + unsigned ManglingNumber; + switch (Kind) { + case Normal: + // -- the bodies of non-exported nonspecialized template functions + // -- the bodies of inline functions + if ((IsInNonspecializedTemplate && + !(ContextDecl && isa<ParmVarDecl>(ContextDecl))) || + isInInlineFunction(CurContext)) + ManglingNumber = Context.getLambdaManglingNumber(Method); + else + ManglingNumber = 0; + + // There is no special context for this lambda. + ContextDecl = 0; + break; + + case StaticDataMember: + // -- the initializers of nonspecialized static members of template classes + if (!IsInNonspecializedTemplate) { + ManglingNumber = 0; + ContextDecl = 0; + break; + } + // Fall through to assign a mangling number. + + case DataMember: + // -- the in-class initializers of class members + case DefaultArgument: + // -- default arguments appearing in class definitions + ManglingNumber = ExprEvalContexts.back().getLambdaMangleContext() + .getManglingNumber(Method); + break; + } + + Class->setLambdaMangling(ManglingNumber, ContextDecl); + return Method; } @@ -214,6 +224,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) { @@ -230,6 +375,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, TypeSourceInfo *MethodTyInfo; bool ExplicitParams = true; bool ExplicitResultType = true; + bool ContainsUnexpandedParameterPack = false; SourceLocation EndLoc; llvm::ArrayRef<ParmVarDecl *> Params; if (ParamInfo.getNumTypeObjects() == 0) { @@ -269,9 +415,13 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, FunctionProtoTypeLoc Proto = cast<FunctionProtoTypeLoc>(TL); Params = llvm::ArrayRef<ParmVarDecl *>(Proto.getParmArray(), Proto.getNumArgs()); + + // Check for unexpanded parameter packs in the method type. + if (MethodTyInfo->getType()->containsUnexpandedParameterPack()) + ContainsUnexpandedParameterPack = true; } - CXXMethodDecl *Method = startLambdaDefinition(Class, Intro.Range, + CXXMethodDecl *Method = startLambdaDefinition(Class, Intro.Range, MethodTyInfo, EndLoc, Params); if (ExplicitParams) @@ -287,7 +437,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, LambdaScopeInfo *LSI = enterLambdaScope(Method, Intro.Range, Intro.Default, ExplicitParams, ExplicitResultType, - (Method->getTypeQualifiers() & Qualifiers::Const) == 0); + !Method->isConst()); // Handle explicit captures. SourceLocation PrevCaptureLoc @@ -409,8 +559,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, // Just ignore the ellipsis. } } else if (Var->isParameterPack()) { - Diag(C->Loc, diag::err_lambda_unexpanded_pack); - continue; + ContainsUnexpandedParameterPack = true; } TryCaptureKind Kind = C->Kind == LCK_ByRef ? TryCapture_ExplicitByRef : @@ -419,6 +568,8 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, } finishLambdaExplicitCaptures(LSI); + LSI->ContainsUnexpandedParameterPack = ContainsUnexpandedParameterPack; + // Add lambda parameters into scope. addLambdaParameters(Method, CurScope); @@ -441,7 +592,10 @@ void Sema::ActOnLambdaError(SourceLocation StartLoc, Scope *CurScope, LambdaScopeInfo *LSI = getCurLambda(); CXXRecordDecl *Class = LSI->Lambda; Class->setInvalidDecl(); - SmallVector<Decl*, 4> Fields(Class->field_begin(), Class->field_end()); + 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); @@ -578,6 +732,7 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body, bool ExplicitParams; bool ExplicitResultType; bool LambdaExprNeedsCleanups; + bool ContainsUnexpandedParameterPack; llvm::SmallVector<VarDecl *, 4> ArrayIndexVars; llvm::SmallVector<unsigned, 4> ArrayIndexStarts; { @@ -588,6 +743,7 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body, ExplicitParams = LSI->ExplicitParams; ExplicitResultType = !LSI->HasImplicitReturnType; LambdaExprNeedsCleanups = LSI->ExprNeedsCleanups; + ContainsUnexpandedParameterPack = LSI->ContainsUnexpandedParameterPack; ArrayIndexVars.swap(LSI->ArrayIndexVars); ArrayIndexStarts.swap(LSI->ArrayIndexStarts); @@ -639,32 +795,14 @@ 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 // 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. @@ -704,7 +842,10 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body, addBlockPointerConversion(*this, IntroducerRange, Class, CallOperator); // Finalize the lambda class. - SmallVector<Decl*, 4> Fields(Class->field_begin(), Class->field_end()); + 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); @@ -717,7 +858,8 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body, CaptureDefault, Captures, ExplicitParams, ExplicitResultType, CaptureInits, ArrayIndexVars, - ArrayIndexStarts, Body->getLocEnd()); + ArrayIndexStarts, Body->getLocEnd(), + ContainsUnexpandedParameterPack); // C++11 [expr.prim.lambda]p2: // A lambda-expression shall not appear in an unevaluated operand @@ -807,9 +949,7 @@ ExprResult Sema::BuildBlockForLambdaConversion(SourceLocation CurrentLocation, // Add a fake function body to the block. IR generation is responsible // for filling in the actual body, which cannot be expressed as an AST. - Block->setBody(new (Context) CompoundStmt(Context, 0, 0, - ConvLocation, - ConvLocation)); + Block->setBody(new (Context) CompoundStmt(ConvLocation)); // Create the block literal expression. Expr *BuildBlock = new (Context) BlockExpr(Block, Conv->getConversionType()); |