virtual Action::DeclPtrTy ActOnDeclarator(Scope *S, Declarator &D) { // Print names of global variables. Differentiating between // global variables and global functions is Hard in C, so this // is only an approximation. const DeclSpec& DS = D.getDeclSpec(); SourceLocation loc = D.getIdentifierLoc(); if ( // Only global declarations... D.getContext() == Declarator::FileContext // ...that aren't typedefs or `extern` declarations... && DS.getStorageClassSpec() != DeclSpec::SCS_extern && DS.getStorageClassSpec() != DeclSpec::SCS_typedef // ...and no functions... && !D.isFunctionDeclarator() // ...and in a user header && !pp.getSourceManager().isInSystemHeader(loc) ) { IdentifierInfo *II = D.getIdentifier(); std::cerr << "Found global user declarator " << II->getName() << std::endl; } return MinimalAction::ActOnDeclarator(S, D); }
/// ActOnCXXConditionDeclarationExpr - Parsed a condition declaration of a /// C++ if/switch/while/for statement. /// e.g: "if (int x = f()) {...}" Action::OwningExprResult Sema::ActOnCXXConditionDeclarationExpr(Scope *S, SourceLocation StartLoc, Declarator &D, SourceLocation EqualLoc, ExprArg AssignExprVal) { assert(AssignExprVal.get() && "Null assignment expression"); // C++ 6.4p2: // The declarator shall not specify a function or an array. // The type-specifier-seq shall not contain typedef and shall not declare a // new class or enumeration. assert(D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef && "Parser allowed 'typedef' as storage class of condition decl."); QualType Ty = GetTypeForDeclarator(D, S); if (Ty->isFunctionType()) { // The declarator shall not specify a function... // We exit without creating a CXXConditionDeclExpr because a FunctionDecl // would be created and CXXConditionDeclExpr wants a VarDecl. return ExprError(Diag(StartLoc, diag::err_invalid_use_of_function_type) << SourceRange(StartLoc, EqualLoc)); } else if (Ty->isArrayType()) { // ...or an array. Diag(StartLoc, diag::err_invalid_use_of_array_type) << SourceRange(StartLoc, EqualLoc); } else if (const RecordType *RT = Ty->getAsRecordType()) { RecordDecl *RD = RT->getDecl(); // The type-specifier-seq shall not declare a new class... if (RD->isDefinition() && (RD->getIdentifier() == 0 || S->isDeclScope(DeclPtrTy::make(RD)))) Diag(RD->getLocation(), diag::err_type_defined_in_condition); } else if (const EnumType *ET = Ty->getAsEnumType()) { EnumDecl *ED = ET->getDecl(); // ...or enumeration. if (ED->isDefinition() && (ED->getIdentifier() == 0 || S->isDeclScope(DeclPtrTy::make(ED)))) Diag(ED->getLocation(), diag::err_type_defined_in_condition); } DeclPtrTy Dcl = ActOnDeclarator(S, D, DeclPtrTy()); if (!Dcl) return ExprError(); AddInitializerToDecl(Dcl, move(AssignExprVal)); // Mark this variable as one that is declared within a conditional. // We know that the decl had to be a VarDecl because that is the only type of // decl that can be assigned and the grammar requires an '='. VarDecl *VD = cast<VarDecl>(Dcl.getAs<Decl>()); VD->setDeclaredInCondition(true); return Owned(new (Context) CXXConditionDeclExpr(StartLoc, EqualLoc, VD)); }
/// ActOnDeclarator - If this is a typedef declarator, we modify the /// IdentifierInfo::FETokenInfo field to keep track of this fact, until S is /// popped. Action::DeclPtrTy MinimalAction::ActOnDeclarator(Scope *S, Declarator &D) { IdentifierInfo *II = D.getIdentifier(); // If there is no identifier associated with this declarator, bail out. if (II == 0) return DeclPtrTy(); TypeNameInfo *weCurrentlyHaveTypeInfo = II->getFETokenInfo<TypeNameInfo>(); bool isTypeName = D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef; // this check avoids creating TypeNameInfo objects for the common case. // It does need to handle the uncommon case of shadowing a typedef name with a // non-typedef name. e.g. { typedef int a; a xx; { int a; } } if (weCurrentlyHaveTypeInfo || isTypeName) { // Allocate and add the 'TypeNameInfo' "decl". getTable(TypeNameInfoTablePtr)->AddEntry(isTypeName, II); // Remember that this needs to be removed when the scope is popped. S->AddDecl(DeclPtrTy::make(II)); } return DeclPtrTy(); }
bool Sema::containsUnexpandedParameterPacks(Declarator &D) { const DeclSpec &DS = D.getDeclSpec(); switch (DS.getTypeSpecType()) { case TST_typename: case TST_typeofType: case TST_underlyingType: case TST_atomic: { QualType T = DS.getRepAsType().get(); if (!T.isNull() && T->containsUnexpandedParameterPack()) return true; break; } case TST_typeofExpr: case TST_decltype: if (DS.getRepAsExpr() && DS.getRepAsExpr()->containsUnexpandedParameterPack()) return true; break; case TST_unspecified: case TST_void: case TST_char: case TST_wchar: case TST_char16: case TST_char32: case TST_int: case TST_int128: case TST_half: case TST_float: case TST_double: case TST_bool: case TST_decimal32: case TST_decimal64: case TST_decimal128: case TST_enum: case TST_union: case TST_struct: case TST_interface: case TST_class: case TST_auto: case TST_decltype_auto: case TST_unknown_anytype: case TST_error: break; } for (unsigned I = 0, N = D.getNumTypeObjects(); I != N; ++I) { const DeclaratorChunk &Chunk = D.getTypeObject(I); switch (Chunk.Kind) { case DeclaratorChunk::Pointer: case DeclaratorChunk::Reference: case DeclaratorChunk::Paren: case DeclaratorChunk::BlockPointer: // These declarator chunks cannot contain any parameter packs. break; case DeclaratorChunk::Array: if (Chunk.Arr.NumElts && Chunk.Arr.NumElts->containsUnexpandedParameterPack()) return true; break; case DeclaratorChunk::Function: for (unsigned i = 0, e = Chunk.Fun.NumParams; i != e; ++i) { ParmVarDecl *Param = cast<ParmVarDecl>(Chunk.Fun.Params[i].Param); QualType ParamTy = Param->getType(); assert(!ParamTy.isNull() && "Couldn't parse type?"); if (ParamTy->containsUnexpandedParameterPack()) return true; } if (Chunk.Fun.getExceptionSpecType() == EST_Dynamic) { for (unsigned i = 0; i != Chunk.Fun.NumExceptions; ++i) { if (Chunk.Fun.Exceptions[i] .Ty.get() ->containsUnexpandedParameterPack()) return true; } } else if (Chunk.Fun.getExceptionSpecType() == EST_ComputedNoexcept && Chunk.Fun.NoexceptExpr->containsUnexpandedParameterPack()) return true; if (Chunk.Fun.hasTrailingReturnType()) { QualType T = Chunk.Fun.getTrailingReturnType().get(); if (!T.isNull() && T->containsUnexpandedParameterPack()) return true; } break; case DeclaratorChunk::MemberPointer: if (Chunk.Mem.Scope().getScopeRep() && Chunk.Mem.Scope().getScopeRep()->containsUnexpandedParameterPack()) return true; break; } } return false; }
bool Sema::containsUnexpandedParameterPacks(Declarator &D) { const DeclSpec &DS = D.getDeclSpec(); switch (DS.getTypeSpecType()) { case TST_typename: case TST_typeofType: case TST_underlyingType: case TST_atomic: { QualType T = DS.getRepAsType().get(); if (!T.isNull() && T->containsUnexpandedParameterPack()) return true; break; } case TST_typeofExpr: case TST_decltype: if (DS.getRepAsExpr() && DS.getRepAsExpr()->containsUnexpandedParameterPack()) return true; break; case TST_unspecified: case TST_void: case TST_char: case TST_wchar: case TST_char16: case TST_char32: case TST_int: case TST_int128: case TST_half: case TST_float: case TST_double: case TST_bool: case TST_decimal32: case TST_decimal64: case TST_decimal128: case TST_enum: case TST_union: case TST_struct: case TST_interface: case TST_class: case TST_auto: case TST_unknown_anytype: case TST_image1d_t: case TST_image1d_array_t: case TST_image1d_buffer_t: case TST_image2d_t: case TST_image2d_array_t: case TST_image3d_t: case TST_sampler_t: case TST_event_t: case TST_error: break; } for (unsigned I = 0, N = D.getNumTypeObjects(); I != N; ++I) { const DeclaratorChunk &Chunk = D.getTypeObject(I); switch (Chunk.Kind) { case DeclaratorChunk::Pointer: case DeclaratorChunk::Reference: case DeclaratorChunk::Paren: // These declarator chunks cannot contain any parameter packs. break; case DeclaratorChunk::Array: case DeclaratorChunk::Function: case DeclaratorChunk::BlockPointer: // Syntactically, these kinds of declarator chunks all come after the // declarator-id (conceptually), so the parser should not invoke this // routine at this time. llvm_unreachable("Could not have seen this kind of declarator chunk"); case DeclaratorChunk::MemberPointer: if (Chunk.Mem.Scope().getScopeRep() && Chunk.Mem.Scope().getScopeRep()->containsUnexpandedParameterPack()) return true; break; } } return false; }
/// ParseCXXInlineMethodDef - We parsed and verified that the specified /// Declarator is a well formed C++ inline method definition. Now lex its body /// and store its tokens for parsing after the C++ class is complete. Parser::DeclPtrTy Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D, const ParsedTemplateInfo &TemplateInfo) { assert(D.getTypeObject(0).Kind == DeclaratorChunk::Function && "This isn't a function declarator!"); assert((Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try)) && "Current token not a '{', ':' or 'try'!"); Action::MultiTemplateParamsArg TemplateParams(Actions, TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->data() : 0, TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->size() : 0); DeclPtrTy FnD; if (D.getDeclSpec().isFriendSpecified()) // FIXME: Friend templates FnD = Actions.ActOnFriendFunctionDecl(CurScope, D, true, move(TemplateParams)); else // FIXME: pass template information through FnD = Actions.ActOnCXXMemberDeclarator(CurScope, AS, D, move(TemplateParams), 0, 0); HandleMemberFunctionDefaultArgs(D, FnD); // Consume the tokens and store them for later parsing. getCurrentClass().MethodDefs.push_back(LexedMethod(FnD)); getCurrentClass().MethodDefs.back().TemplateScope = CurScope->isTemplateParamScope(); CachedTokens &Toks = getCurrentClass().MethodDefs.back().Toks; tok::TokenKind kind = Tok.getKind(); // We may have a constructor initializer or function-try-block here. if (kind == tok::colon || kind == tok::kw_try) { // Consume everything up to (and including) the left brace. if (!ConsumeAndStoreUntil(tok::l_brace, tok::unknown, Toks, tok::semi)) { // We didn't find the left-brace we expected after the // constructor initializer. if (Tok.is(tok::semi)) { // We found a semicolon; complain, consume the semicolon, and // don't try to parse this method later. Diag(Tok.getLocation(), diag::err_expected_lbrace); ConsumeAnyToken(); getCurrentClass().MethodDefs.pop_back(); return FnD; } } } else { // Begin by storing the '{' token. Toks.push_back(Tok); ConsumeBrace(); } // Consume everything up to (and including) the matching right brace. ConsumeAndStoreUntil(tok::r_brace, tok::unknown, Toks); // If we're in a function-try-block, we need to store all the catch blocks. if (kind == tok::kw_try) { while (Tok.is(tok::kw_catch)) { ConsumeAndStoreUntil(tok::l_brace, tok::unknown, Toks); ConsumeAndStoreUntil(tok::r_brace, tok::unknown, Toks); } } return FnD; }
/// GetTypeForDeclarator - Convert the type for the specified /// declarator to Type instances. Skip the outermost Skip type /// objects. QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip) { bool OmittedReturnType = false; if (D.getContext() == Declarator::BlockLiteralContext && Skip == 0 && !D.getDeclSpec().hasTypeSpecifier() && (D.getNumTypeObjects() == 0 || (D.getNumTypeObjects() == 1 && D.getTypeObject(0).Kind == DeclaratorChunk::Function))) OmittedReturnType = true; // long long is a C99 feature. if (!getLangOptions().C99 && !getLangOptions().CPlusPlus0x && D.getDeclSpec().getTypeSpecWidth() == DeclSpec::TSW_longlong) Diag(D.getDeclSpec().getTypeSpecWidthLoc(), diag::ext_longlong); // Determine the type of the declarator. Not all forms of declarator // have a type. QualType T; switch (D.getKind()) { case Declarator::DK_Abstract: case Declarator::DK_Normal: case Declarator::DK_Operator: { const DeclSpec& DS = D.getDeclSpec(); if (OmittedReturnType) // We default to a dependent type initially. Can be modified by // the first return statement. T = Context.DependentTy; else { T = ConvertDeclSpecToType(DS); if (T.isNull()) return T; } break; } case Declarator::DK_Constructor: case Declarator::DK_Destructor: case Declarator::DK_Conversion: // Constructors and destructors don't have return types. Use // "void" instead. Conversion operators will check their return // types separately. T = Context.VoidTy; break; } // The name we're declaring, if any. DeclarationName Name; if (D.getIdentifier()) Name = D.getIdentifier(); // Walk the DeclTypeInfo, building the recursive type as we go. // DeclTypeInfos are ordered from the identifier out, which is // opposite of what we want :). for (unsigned i = Skip, e = D.getNumTypeObjects(); i != e; ++i) { DeclaratorChunk &DeclType = D.getTypeObject(e-i-1+Skip); switch (DeclType.Kind) { default: assert(0 && "Unknown decltype!"); case DeclaratorChunk::BlockPointer: // If blocks are disabled, emit an error. if (!LangOpts.Blocks) Diag(DeclType.Loc, diag::err_blocks_disable); if (DeclType.Cls.TypeQuals) Diag(D.getIdentifierLoc(), diag::err_qualified_block_pointer_type); if (!T.getTypePtr()->isFunctionType()) Diag(D.getIdentifierLoc(), diag::err_nonfunction_block_type); else T = Context.getBlockPointerType(T); break; case DeclaratorChunk::Pointer: T = BuildPointerType(T, DeclType.Ptr.TypeQuals, DeclType.Loc, Name); break; case DeclaratorChunk::Reference: T = BuildReferenceType(T, DeclType.Ref.LValueRef, DeclType.Ref.HasRestrict ? QualType::Restrict : 0, DeclType.Loc, Name); break; case DeclaratorChunk::Array: { DeclaratorChunk::ArrayTypeInfo &ATI = DeclType.Arr; Expr *ArraySize = static_cast<Expr*>(ATI.NumElts); ArrayType::ArraySizeModifier ASM; if (ATI.isStar) ASM = ArrayType::Star; else if (ATI.hasStatic) ASM = ArrayType::Static; else ASM = ArrayType::Normal; T = BuildArrayType(T, ASM, ArraySize, ATI.TypeQuals, DeclType.Loc, Name); break; } case DeclaratorChunk::Function: { // If the function declarator has a prototype (i.e. it is not () and // does not have a K&R-style identifier list), then the arguments are part // of the type, otherwise the argument list is (). const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun; // C99 6.7.5.3p1: The return type may not be a function or array type. if (T->isArrayType() || T->isFunctionType()) { Diag(DeclType.Loc, diag::err_func_returning_array_function) << T; T = Context.IntTy; D.setInvalidType(true); } if (FTI.NumArgs == 0) { if (getLangOptions().CPlusPlus) { // C++ 8.3.5p2: If the parameter-declaration-clause is empty, the // function takes no arguments. T = Context.getFunctionType(T, NULL, 0, FTI.isVariadic,FTI.TypeQuals); } else if (FTI.isVariadic) { // We allow a zero-parameter variadic function in C if the // function is marked with the "overloadable" // attribute. Scan for this attribute now. bool Overloadable = false; for (const AttributeList *Attrs = D.getAttributes(); Attrs; Attrs = Attrs->getNext()) { if (Attrs->getKind() == AttributeList::AT_overloadable) { Overloadable = true; break; } } if (!Overloadable) Diag(FTI.getEllipsisLoc(), diag::err_ellipsis_first_arg); T = Context.getFunctionType(T, NULL, 0, FTI.isVariadic, 0); } else { // Simple void foo(), where the incoming T is the result type. T = Context.getFunctionNoProtoType(T); } } else if (FTI.ArgInfo[0].Param == 0) { // C99 6.7.5.3p3: Reject int(x,y,z) when it's not a function definition. Diag(FTI.ArgInfo[0].IdentLoc, diag::err_ident_list_in_fn_declaration); } else { // Otherwise, we have a function with an argument list that is // potentially variadic. llvm::SmallVector<QualType, 16> ArgTys; for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) { ParmVarDecl *Param = cast<ParmVarDecl>(FTI.ArgInfo[i].Param.getAs<Decl>()); QualType ArgTy = Param->getType(); assert(!ArgTy.isNull() && "Couldn't parse type?"); // Adjust the parameter type. assert((ArgTy == adjustParameterType(ArgTy)) && "Unadjusted type?"); // Look for 'void'. void is allowed only as a single argument to a // function with no other parameters (C99 6.7.5.3p10). We record // int(void) as a FunctionProtoType with an empty argument list. if (ArgTy->isVoidType()) { // If this is something like 'float(int, void)', reject it. 'void' // is an incomplete type (C99 6.2.5p19) and function decls cannot // have arguments of incomplete type. if (FTI.NumArgs != 1 || FTI.isVariadic) { Diag(DeclType.Loc, diag::err_void_only_param); ArgTy = Context.IntTy; Param->setType(ArgTy); } else if (FTI.ArgInfo[i].Ident) { // Reject, but continue to parse 'int(void abc)'. Diag(FTI.ArgInfo[i].IdentLoc, diag::err_param_with_void_type); ArgTy = Context.IntTy; Param->setType(ArgTy); } else { // Reject, but continue to parse 'float(const void)'. if (ArgTy.getCVRQualifiers()) Diag(DeclType.Loc, diag::err_void_param_qualified); // Do not add 'void' to the ArgTys list. break; } } else if (!FTI.hasPrototype) { if (ArgTy->isPromotableIntegerType()) { ArgTy = Context.IntTy; } else if (const BuiltinType* BTy = ArgTy->getAsBuiltinType()) { if (BTy->getKind() == BuiltinType::Float) ArgTy = Context.DoubleTy; } } ArgTys.push_back(ArgTy); } T = Context.getFunctionType(T, &ArgTys[0], ArgTys.size(), FTI.isVariadic, FTI.TypeQuals); } break; } case DeclaratorChunk::MemberPointer: // The scope spec must refer to a class, or be dependent. DeclContext *DC = computeDeclContext(DeclType.Mem.Scope()); QualType ClsType; // FIXME: Extend for dependent types when it's actually supported. // See ActOnCXXNestedNameSpecifier. if (CXXRecordDecl *RD = dyn_cast_or_null<CXXRecordDecl>(DC)) { ClsType = Context.getTagDeclType(RD); } else { if (DC) { Diag(DeclType.Mem.Scope().getBeginLoc(), diag::err_illegal_decl_mempointer_in_nonclass) << (D.getIdentifier() ? D.getIdentifier()->getName() : "type name") << DeclType.Mem.Scope().getRange(); } D.setInvalidType(true); ClsType = Context.IntTy; } // C++ 8.3.3p3: A pointer to member shall not pointer to ... a member // with reference type, or "cv void." if (T->isReferenceType()) { Diag(DeclType.Loc, diag::err_illegal_decl_pointer_to_reference) << (D.getIdentifier() ? D.getIdentifier()->getName() : "type name"); D.setInvalidType(true); T = Context.IntTy; } if (T->isVoidType()) { Diag(DeclType.Loc, diag::err_illegal_decl_mempointer_to_void) << (D.getIdentifier() ? D.getIdentifier()->getName() : "type name"); T = Context.IntTy; } // Enforce C99 6.7.3p2: "Types other than pointer types derived from // object or incomplete types shall not be restrict-qualified." if ((DeclType.Mem.TypeQuals & QualType::Restrict) && !T->isIncompleteOrObjectType()) { Diag(DeclType.Loc, diag::err_typecheck_invalid_restrict_invalid_pointee) << T; DeclType.Mem.TypeQuals &= ~QualType::Restrict; } T = Context.getMemberPointerType(T, ClsType.getTypePtr()). getQualifiedType(DeclType.Mem.TypeQuals); break; } if (T.isNull()) { D.setInvalidType(true); T = Context.IntTy; } // See if there are any attributes on this declarator chunk. if (const AttributeList *AL = DeclType.getAttrs()) ProcessTypeAttributeList(T, AL); } if (getLangOptions().CPlusPlus && T->isFunctionType()) { const FunctionProtoType *FnTy = T->getAsFunctionProtoType(); assert(FnTy && "Why oh why is there not a FunctionProtoType here ?"); // C++ 8.3.5p4: A cv-qualifier-seq shall only be part of the function type // for a nonstatic member function, the function type to which a pointer // to member refers, or the top-level function type of a function typedef // declaration. if (FnTy->getTypeQuals() != 0 && D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef && ((D.getContext() != Declarator::MemberContext && (!D.getCXXScopeSpec().isSet() || !computeDeclContext(D.getCXXScopeSpec())->isRecord())) || D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static)) { if (D.isFunctionDeclarator()) Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_function_type); else Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_typedef_function_type_use); // Strip the cv-quals from the type. T = Context.getFunctionType(FnTy->getResultType(), FnTy->arg_type_begin(), FnTy->getNumArgs(), FnTy->isVariadic(), 0); } } // If there were any type attributes applied to the decl itself (not the // type, apply the type attribute to the type!) if (const AttributeList *Attrs = D.getAttributes()) ProcessTypeAttributeList(T, Attrs); return T; }
/// ParseFunctionDefinition - We parsed and verified that the specified /// Declarator is well formed. If this is a K&R-style function, read the /// parameters declaration-list, then start the compound-statement. /// /// function-definition: [C99 6.9.1] /// decl-specs declarator declaration-list[opt] compound-statement /// [C90] function-definition: [C99 6.7.1] - implicit int result /// [C90] decl-specs[opt] declarator declaration-list[opt] compound-statement /// [C++] function-definition: [C++ 8.4] /// decl-specifier-seq[opt] declarator ctor-initializer[opt] /// function-body /// [C++] function-definition: [C++ 8.4] /// decl-specifier-seq[opt] declarator function-try-block /// Parser::DeclPtrTy Parser::ParseFunctionDefinition(Declarator &D, const ParsedTemplateInfo &TemplateInfo) { const DeclaratorChunk &FnTypeInfo = D.getTypeObject(0); assert(FnTypeInfo.Kind == DeclaratorChunk::Function && "This isn't a function declarator!"); const DeclaratorChunk::FunctionTypeInfo &FTI = FnTypeInfo.Fun; // If this is C90 and the declspecs were completely missing, fudge in an // implicit int. We do this here because this is the only place where // declaration-specifiers are completely optional in the grammar. if (getLang().ImplicitInt && D.getDeclSpec().isEmpty()) { const char *PrevSpec; unsigned DiagID; D.getMutableDeclSpec().SetTypeSpecType(DeclSpec::TST_int, D.getIdentifierLoc(), PrevSpec, DiagID); D.SetRangeBegin(D.getDeclSpec().getSourceRange().getBegin()); } // If this declaration was formed with a K&R-style identifier list for the // arguments, parse declarations for all of the args next. // int foo(a,b) int a; float b; {} if (!FTI.hasPrototype && FTI.NumArgs != 0) ParseKNRParamDeclarations(D); // We should have either an opening brace or, in a C++ constructor, // we may have a colon. if (Tok.isNot(tok::l_brace) && Tok.isNot(tok::colon) && Tok.isNot(tok::kw_try)) { Diag(Tok, diag::err_expected_fn_body); // Skip over garbage, until we get to '{'. Don't eat the '{'. SkipUntil(tok::l_brace, true, true); // If we didn't find the '{', bail out. if (Tok.isNot(tok::l_brace)) return DeclPtrTy(); } // Enter a scope for the function body. ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope); // Tell the actions module that we have entered a function definition with the // specified Declarator for the function. DeclPtrTy Res = TemplateInfo.TemplateParams? Actions.ActOnStartOfFunctionTemplateDef(CurScope, Action::MultiTemplateParamsArg(Actions, TemplateInfo.TemplateParams->data(), TemplateInfo.TemplateParams->size()), D) : Actions.ActOnStartOfFunctionDef(CurScope, D); if (Tok.is(tok::kw_try)) return ParseFunctionTryBlock(Res); // If we have a colon, then we're probably parsing a C++ // ctor-initializer. if (Tok.is(tok::colon)) ParseConstructorInitializer(Res); else Actions.ActOnDefaultCtorInitializers(Res); return ParseFunctionStatementBody(Res); }