std::vector<VariableDeclaration> Declaration::GetVariableDeclarations() const { Assert(declSpecs->storageClass != SC_TYPEDEF); std::vector<VariableDeclaration> vars; for (unsigned int i = 0; i < declarators.size(); ++i) { if (declarators[i] == NULL) continue; Declarator *decl = declarators[i]; if (decl == NULL) // Ignore earlier errors continue; Symbol *sym = decl->GetSymbol(); if (dynamic_cast<const FunctionType *>(sym->type) != NULL) { // function declaration m->symbolTable->AddFunction(sym); } else { m->symbolTable->AddVariable(sym); vars.push_back(VariableDeclaration(sym, decl->initExpr)); } } return vars; }
void Declaration::DeclareFunctions() { Assert(declSpecs->storageClass != SC_TYPEDEF); for (unsigned int i = 0; i < declarators.size(); ++i) { Declarator *decl = declarators[i]; if (decl == NULL) { // Ignore earlier errors Assert(m->errorCount > 0); continue; } Symbol *sym = decl->GetSymbol(); if (sym == NULL || sym->type == NULL) { // Ignore errors Assert(m->errorCount > 0); continue; } sym->type = sym->type->ResolveUnboundVariability(Type::Varying); if (dynamic_cast<const FunctionType *>(sym->type) == NULL) continue; bool isInline = (declSpecs->typeQualifiers & TYPEQUAL_INLINE); m->AddFunctionDeclaration(sym, isInline); } }
std::vector<VariableDeclaration> Declaration::GetVariableDeclarations() const { Assert(declSpecs->storageClass != SC_TYPEDEF); std::vector<VariableDeclaration> vars; for (unsigned int i = 0; i < declarators.size(); ++i) { Declarator *decl = declarators[i]; if (decl == NULL) { // Ignore earlier errors Assert(m->errorCount > 0); continue; } Symbol *sym = decl->GetSymbol(); if (sym == NULL || sym->type == NULL) { // Ignore errors Assert(m->errorCount > 0); continue; } sym->type = sym->type->ResolveUnboundVariability(Type::Varying); if (sym->type == AtomicType::Void) Error(sym->pos, "\"void\" type variable illegal in declaration."); else if (dynamic_cast<const FunctionType *>(sym->type) == NULL) { m->symbolTable->AddVariable(sym); vars.push_back(VariableDeclaration(sym, decl->initExpr)); } } return vars; }
void Stream::ReadMembers(uint8* object, ClassType* pType) { for (uint i = 0; i < pType->m_pScope->m_orderedDecls.size(); i++) { Declarator* decl = pType->m_pScope->m_orderedDecls[i]; if (!decl->get_IsStatic() && !decl->get_IsTypedef()) { Type* pType = decl->m_pType->GetStripped(); Type_type kind = pType->get_Kind(); if (kind == type_array) { ASSERT(0); /* ArrayType* array = static_cast<ArrayType*>(decl->m_pType); uint count = array->get_ElemCount(); for (uint i = 0; i < count; i++) { WriteMember(object + decl->m_offset + i*array->get_ElemType()->get_sizeof(), array->get_ElemType(), stream); } */ } else if (kind != type_function) { ReadMember(object + decl->m_offset, pType); } } } }
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); }
/// CheckAllocatedType - Checks that a type is suitable as the allocated type /// in a new-expression. /// dimension off and stores the size expression in ArraySize. bool Sema::CheckAllocatedType(QualType AllocType, const Declarator &D) { // C++ 5.3.4p1: "[The] type shall be a complete object type, but not an // abstract class type or array thereof. if (AllocType->isFunctionType()) return Diag(D.getSourceRange().getBegin(), diag::err_bad_new_type) << AllocType << 0 << D.getSourceRange(); else if (AllocType->isReferenceType()) return Diag(D.getSourceRange().getBegin(), diag::err_bad_new_type) << AllocType << 1 << D.getSourceRange(); else if (!AllocType->isDependentType() && RequireCompleteType(D.getSourceRange().getBegin(), AllocType, diag::err_new_incomplete_type, D.getSourceRange())) return true; else if (RequireNonAbstractType(D.getSourceRange().getBegin(), AllocType, diag::err_allocation_of_abstract_type)) return true; // Every dimension shall be of constant size. unsigned i = 1; while (const ArrayType *Array = Context.getAsArrayType(AllocType)) { if (!Array->isConstantArrayType()) { Diag(D.getTypeObject(i).Loc, diag::err_new_array_nonconst) << static_cast<Expr*>(D.getTypeObject(i).Arr.NumElts)->getSourceRange(); return true; } AllocType = Array->getElementType(); ++i; } return false; }
void GetStructTypesNamesPositions(const std::vector<StructDeclaration *> &sd, llvm::SmallVector<const Type *, 8> *elementTypes, llvm::SmallVector<std::string, 8> *elementNames, llvm::SmallVector<SourcePos, 8> *elementPositions) { std::set<std::string> seenNames; for (unsigned int i = 0; i < sd.size(); ++i) { const Type *type = sd[i]->type; if (type == NULL) continue; // FIXME: making this fake little DeclSpecs here is really // disgusting DeclSpecs ds(type); if (Type::Equal(type, AtomicType::Void) == false) { if (type->IsUniformType()) ds.typeQualifiers |= TYPEQUAL_UNIFORM; else if (type->IsVaryingType()) ds.typeQualifiers |= TYPEQUAL_VARYING; else if (type->GetSOAWidth() != 0) ds.soaWidth = type->GetSOAWidth(); // FIXME: ds.vectorSize? } for (unsigned int j = 0; j < sd[i]->declarators->size(); ++j) { Declarator *d = (*sd[i]->declarators)[j]; d->InitFromDeclSpecs(&ds); if (Type::Equal(d->type, AtomicType::Void)) Error(d->pos, "\"void\" type illegal for struct member."); elementTypes->push_back(d->type); if (seenNames.find(d->name) != seenNames.end()) Error(d->pos, "Struct member \"%s\" has same name as a " "previously-declared member.", d->name.c_str()); else seenNames.insert(d->name); elementNames->push_back(d->name); elementPositions->push_back(d->pos); } } for (int i = 0; i < (int)elementTypes->size() - 1; ++i) { const ArrayType *arrayType = CastType<ArrayType>((*elementTypes)[i]); if (arrayType != NULL && arrayType->GetElementCount() == 0) Error((*elementPositions)[i], "Unsized arrays aren't allowed except " "for the last member in a struct definition."); } }
void GetStructTypesNamesPositions(const std::vector<StructDeclaration *> &sd, std::vector<const Type *> *elementTypes, std::vector<std::string> *elementNames, std::vector<SourcePos> *elementPositions) { std::set<std::string> seenNames; for (unsigned int i = 0; i < sd.size(); ++i) { const Type *type = sd[i]->type; if (type == NULL) continue; // FIXME: making this fake little DeclSpecs here is really // disgusting DeclSpecs ds(type); if (type->IsUniformType()) ds.typeQualifiers |= TYPEQUAL_UNIFORM; else if (type->IsVaryingType()) ds.typeQualifiers |= TYPEQUAL_VARYING; for (unsigned int j = 0; j < sd[i]->declarators->size(); ++j) { Declarator *d = (*sd[i]->declarators)[j]; d->InitFromDeclSpecs(&ds); Symbol *sym = d->GetSymbol(); if (sym->type == AtomicType::Void) Error(d->pos, "\"void\" type illegal for struct member."); const ArrayType *arrayType = dynamic_cast<const ArrayType *>(sym->type); if (arrayType != NULL && arrayType->GetElementCount() == 0) { Error(d->pos, "Unsized arrays aren't allowed in struct " "definitions."); elementTypes->push_back(NULL); } else elementTypes->push_back(sym->type); if (seenNames.find(sym->name) != seenNames.end()) Error(d->pos, "Struct member \"%s\" has same name as a " "previously-declared member.", sym->name.c_str()); else seenNames.insert(sym->name); elementNames->push_back(sym->name); elementPositions->push_back(sym->pos); } } }
Symbol * Declarator::GetFunctionInfo(DeclSpecs *ds, std::vector<Symbol *> *funArgs) { const FunctionType *type = dynamic_cast<const FunctionType *>(GetType(ds)); if (type == NULL) return NULL; Symbol *declSym = GetSymbol(); Assert(declSym != NULL); // Get the symbol for the function from the symbol table. (It should // already have been added to the symbol table by AddGlobal() by the // time we get here.) Symbol *funSym = m->symbolTable->LookupFunction(declSym->name.c_str(), type); if (funSym == NULL) // May be NULL due to error earlier in compilation Assert(m->errorCount > 0); else funSym->pos = pos; // Walk down to the declarator for the function. (We have to get past // the stuff that specifies the function's return type before we get to // the function's declarator.) Declarator *d = this; while (d != NULL && d->kind != DK_FUNCTION) d = d->child; Assert(d != NULL); for (unsigned int i = 0; i < d->functionParams.size(); ++i) { Symbol *sym = d->GetSymbolForFunctionParameter(i); if (sym->type == NULL) { Assert(m->errorCount > 0); continue; } else sym->type = sym->type->ResolveUnboundVariability(Type::Varying); funArgs->push_back(sym); } if (funSym != NULL) funSym->type = funSym->type->ResolveUnboundVariability(Type::Varying); return funSym; }
void Stream::WriteMembers(const uint8* object, ClassType* pType) { for (uint i = 0; i < pType->m_pScope->m_orderedDecls.size(); i++) { Declarator* decl = pType->m_pScope->m_orderedDecls[i]; if (!decl->get_IsStatic() && !decl->get_IsTypedef()) { Type* pType = decl->m_pType->GetStripped(); Type_type kind = pType->get_Kind(); if (kind == type_array) { ArrayType* array = static_cast<ArrayType*>(pType); size_t count = array->get_ElemCount(); for (size_t i = 0; i < count; ++i) { WriteMember(object + decl->m_offset + i*array->get_ElemType()->get_sizeof(), array->get_ElemType()); } } else if (kind != type_function) { WriteMember(object + decl->m_offset, pType); /* switch (kind) { case type_int: case type_long: case type_unsigned_int: case type_unsigned_long: case type_float: case type_double: case type_long_long: } */ } } } }
/// 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(); }
Sema::TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) { // C99 6.7.6: Type names have no identifier. This is already validated by // the parser. assert(D.getIdentifier() == 0 && "Type name should have no identifier!"); QualType T = GetTypeForDeclarator(D, S); if (T.isNull()) return true; // Check that there are no default arguments (C++ only). if (getLangOptions().CPlusPlus) CheckExtraCXXDefaultArguments(D); return T.getAsOpaquePtr(); }
/// 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; }
/// ActOnCXXNew - Parsed a C++ 'new' expression (C++ 5.3.4), as in e.g.: /// @code new (memory) int[size][4] @endcode /// or /// @code ::new Foo(23, "hello") @endcode /// For the interpretation of this heap of arguments, consult the base version. Action::OwningExprResult Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, SourceLocation PlacementLParen, MultiExprArg PlacementArgs, SourceLocation PlacementRParen, bool ParenTypeId, Declarator &D, SourceLocation ConstructorLParen, MultiExprArg ConstructorArgs, SourceLocation ConstructorRParen) { Expr *ArraySize = 0; unsigned Skip = 0; // If the specified type is an array, unwrap it and save the expression. if (D.getNumTypeObjects() > 0 && D.getTypeObject(0).Kind == DeclaratorChunk::Array) { DeclaratorChunk &Chunk = D.getTypeObject(0); if (Chunk.Arr.hasStatic) return ExprError(Diag(Chunk.Loc, diag::err_static_illegal_in_new) << D.getSourceRange()); if (!Chunk.Arr.NumElts) return ExprError(Diag(Chunk.Loc, diag::err_array_new_needs_size) << D.getSourceRange()); ArraySize = static_cast<Expr*>(Chunk.Arr.NumElts); Skip = 1; } QualType AllocType = GetTypeForDeclarator(D, /*Scope=*/0, Skip); if (D.getInvalidType()) return ExprError(); if (CheckAllocatedType(AllocType, D)) return ExprError(); QualType ResultType = AllocType->isDependentType() ? Context.DependentTy : Context.getPointerType(AllocType); // That every array dimension except the first is constant was already // checked by the type check above. // C++ 5.3.4p6: "The expression in a direct-new-declarator shall have integral // or enumeration type with a non-negative value." if (ArraySize && !ArraySize->isTypeDependent()) { QualType SizeType = ArraySize->getType(); if (!SizeType->isIntegralType() && !SizeType->isEnumeralType()) return ExprError(Diag(ArraySize->getSourceRange().getBegin(), diag::err_array_size_not_integral) << SizeType << ArraySize->getSourceRange()); // Let's see if this is a constant < 0. If so, we reject it out of hand. // We don't care about special rules, so we tell the machinery it's not // evaluated - it gives us a result in more cases. if (!ArraySize->isValueDependent()) { llvm::APSInt Value; if (ArraySize->isIntegerConstantExpr(Value, Context, 0, false)) { if (Value < llvm::APSInt( llvm::APInt::getNullValue(Value.getBitWidth()), false)) return ExprError(Diag(ArraySize->getSourceRange().getBegin(), diag::err_typecheck_negative_array_size) << ArraySize->getSourceRange()); } } } FunctionDecl *OperatorNew = 0; FunctionDecl *OperatorDelete = 0; Expr **PlaceArgs = (Expr**)PlacementArgs.get(); unsigned NumPlaceArgs = PlacementArgs.size(); if (!AllocType->isDependentType() && !Expr::hasAnyTypeDependentArguments(PlaceArgs, NumPlaceArgs) && FindAllocationFunctions(StartLoc, SourceRange(PlacementLParen, PlacementRParen), UseGlobal, AllocType, ArraySize, PlaceArgs, NumPlaceArgs, OperatorNew, OperatorDelete)) return ExprError(); bool Init = ConstructorLParen.isValid(); // --- Choosing a constructor --- // C++ 5.3.4p15 // 1) If T is a POD and there's no initializer (ConstructorLParen is invalid) // the object is not initialized. If the object, or any part of it, is // const-qualified, it's an error. // 2) If T is a POD and there's an empty initializer, the object is value- // initialized. // 3) If T is a POD and there's one initializer argument, the object is copy- // constructed. // 4) If T is a POD and there's more initializer arguments, it's an error. // 5) If T is not a POD, the initializer arguments are used as constructor // arguments. // // Or by the C++0x formulation: // 1) If there's no initializer, the object is default-initialized according // to C++0x rules. // 2) Otherwise, the object is direct-initialized. CXXConstructorDecl *Constructor = 0; Expr **ConsArgs = (Expr**)ConstructorArgs.get(); unsigned NumConsArgs = ConstructorArgs.size(); if (AllocType->isDependentType()) { // Skip all the checks. } // FIXME: Should check for primitive/aggregate here, not record. else if (const RecordType *RT = AllocType->getAsRecordType()) { // FIXME: This is incorrect for when there is an empty initializer and // no user-defined constructor. Must zero-initialize, not default-construct. Constructor = PerformInitializationByConstructor( AllocType, ConsArgs, NumConsArgs, D.getSourceRange().getBegin(), SourceRange(D.getSourceRange().getBegin(), ConstructorRParen), RT->getDecl()->getDeclName(), NumConsArgs != 0 ? IK_Direct : IK_Default); if (!Constructor) return ExprError(); } else { if (!Init) { // FIXME: Check that no subpart is const. if (AllocType.isConstQualified()) return ExprError(Diag(StartLoc, diag::err_new_uninitialized_const) << D.getSourceRange()); } else if (NumConsArgs == 0) { // Object is value-initialized. Do nothing. } else if (NumConsArgs == 1) { // Object is direct-initialized. // FIXME: WHAT DeclarationName do we pass in here? if (CheckInitializerTypes(ConsArgs[0], AllocType, StartLoc, DeclarationName() /*AllocType.getAsString()*/, /*DirectInit=*/true)) return ExprError(); } else { return ExprError(Diag(StartLoc, diag::err_builtin_direct_init_more_than_one_arg) << SourceRange(ConstructorLParen, ConstructorRParen)); } } // FIXME: Also check that the destructor is accessible. (C++ 5.3.4p16) PlacementArgs.release(); ConstructorArgs.release(); return Owned(new (Context) CXXNewExpr(UseGlobal, OperatorNew, PlaceArgs, NumPlaceArgs, ParenTypeId, ArraySize, Constructor, Init, ConsArgs, NumConsArgs, OperatorDelete, ResultType, StartLoc, Init ? ConstructorRParen : SourceLocation())); }
/// 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; }
void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, Declarator &ParamInfo, Scope *CurScope) { // Determine if we're within a context where we know that the lambda will // be dependent, because there are template parameters in scope. bool KnownDependent = false; if (Scope *TmplScope = CurScope->getTemplateParamParent()) if (!TmplScope->decl_empty()) KnownDependent = true; CXXRecordDecl *Class = createLambdaClosureType(Intro.Range, KnownDependent); // Determine the signature of the call operator. TypeSourceInfo *MethodTyInfo; bool ExplicitParams = true; bool ExplicitResultType = true; bool ContainsUnexpandedParameterPack = false; SourceLocation EndLoc; llvm::ArrayRef<ParmVarDecl *> Params; if (ParamInfo.getNumTypeObjects() == 0) { // C++11 [expr.prim.lambda]p4: // If a lambda-expression does not include a lambda-declarator, it is as // if the lambda-declarator were (). FunctionProtoType::ExtProtoInfo EPI; EPI.HasTrailingReturn = true; EPI.TypeQuals |= DeclSpec::TQ_const; QualType MethodTy = Context.getFunctionType(Context.DependentTy, /*Args=*/0, /*NumArgs=*/0, EPI); MethodTyInfo = Context.getTrivialTypeSourceInfo(MethodTy); ExplicitParams = false; ExplicitResultType = false; EndLoc = Intro.Range.getEnd(); } else { assert(ParamInfo.isFunctionDeclarator() && "lambda-declarator is a function"); DeclaratorChunk::FunctionTypeInfo &FTI = ParamInfo.getFunctionTypeInfo(); // C++11 [expr.prim.lambda]p5: // This function call operator is declared const (9.3.1) if and only if // the lambda-expression's parameter-declaration-clause is not followed // by mutable. It is neither virtual nor declared volatile. [...] if (!FTI.hasMutableQualifier()) FTI.TypeQuals |= DeclSpec::TQ_const; MethodTyInfo = GetTypeForDeclarator(ParamInfo, CurScope); assert(MethodTyInfo && "no type from lambda-declarator"); EndLoc = ParamInfo.getSourceRange().getEnd(); ExplicitResultType = MethodTyInfo->getType()->getAs<FunctionType>()->getResultType() != Context.DependentTy; TypeLoc TL = MethodTyInfo->getTypeLoc(); 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, MethodTyInfo, EndLoc, Params); if (ExplicitParams) CheckCXXDefaultArguments(Method); // Attributes on the lambda apply to the method. ProcessDeclAttributes(CurScope, Method, ParamInfo); // Introduce the function call operator as the current declaration context. PushDeclContext(CurScope, Method); // Introduce the lambda scope. LambdaScopeInfo *LSI = enterLambdaScope(Method, Intro.Range, Intro.Default, ExplicitParams, ExplicitResultType, (Method->getTypeQualifiers() & Qualifiers::Const) == 0); // Handle explicit captures. SourceLocation PrevCaptureLoc = Intro.Default == LCD_None? Intro.Range.getBegin() : Intro.DefaultLoc; for (llvm::SmallVector<LambdaCapture, 4>::const_iterator C = Intro.Captures.begin(), E = Intro.Captures.end(); C != E; PrevCaptureLoc = C->Loc, ++C) { if (C->Kind == LCK_This) { // C++11 [expr.prim.lambda]p8: // An identifier or this shall not appear more than once in a // lambda-capture. if (LSI->isCXXThisCaptured()) { Diag(C->Loc, diag::err_capture_more_than_once) << "'this'" << SourceRange(LSI->getCXXThisCapture().getLocation()) << FixItHint::CreateRemoval( SourceRange(PP.getLocForEndOfToken(PrevCaptureLoc), C->Loc)); continue; } // C++11 [expr.prim.lambda]p8: // If a lambda-capture includes a capture-default that is =, the // lambda-capture shall not contain this [...]. if (Intro.Default == LCD_ByCopy) { Diag(C->Loc, diag::err_this_capture_with_copy_default) << FixItHint::CreateRemoval( SourceRange(PP.getLocForEndOfToken(PrevCaptureLoc), C->Loc)); continue; } // C++11 [expr.prim.lambda]p12: // If this is captured by a local lambda expression, its nearest // enclosing function shall be a non-static member function. QualType ThisCaptureType = getCurrentThisType(); if (ThisCaptureType.isNull()) { Diag(C->Loc, diag::err_this_capture) << true; continue; } CheckCXXThisCapture(C->Loc, /*Explicit=*/true); continue; } assert(C->Id && "missing identifier for capture"); // C++11 [expr.prim.lambda]p8: // If a lambda-capture includes a capture-default that is &, the // identifiers in the lambda-capture shall not be preceded by &. // If a lambda-capture includes a capture-default that is =, [...] // each identifier it contains shall be preceded by &. if (C->Kind == LCK_ByRef && Intro.Default == LCD_ByRef) { Diag(C->Loc, diag::err_reference_capture_with_reference_default) << FixItHint::CreateRemoval( SourceRange(PP.getLocForEndOfToken(PrevCaptureLoc), C->Loc)); continue; } else if (C->Kind == LCK_ByCopy && Intro.Default == LCD_ByCopy) { Diag(C->Loc, diag::err_copy_capture_with_copy_default) << FixItHint::CreateRemoval( SourceRange(PP.getLocForEndOfToken(PrevCaptureLoc), C->Loc)); continue; } DeclarationNameInfo Name(C->Id, C->Loc); LookupResult R(*this, Name, LookupOrdinaryName); LookupName(R, CurScope); if (R.isAmbiguous()) continue; if (R.empty()) { // FIXME: Disable corrections that would add qualification? CXXScopeSpec ScopeSpec; DeclFilterCCC<VarDecl> Validator; if (DiagnoseEmptyLookup(CurScope, ScopeSpec, R, Validator)) continue; } // C++11 [expr.prim.lambda]p10: // The identifiers in a capture-list are looked up using the usual rules // for unqualified name lookup (3.4.1); each such lookup shall find a // variable with automatic storage duration declared in the reaching // scope of the local lambda expression. // // Note that the 'reaching scope' check happens in tryCaptureVariable(). VarDecl *Var = R.getAsSingle<VarDecl>(); if (!Var) { Diag(C->Loc, diag::err_capture_does_not_name_variable) << C->Id; continue; } if (!Var->hasLocalStorage()) { Diag(C->Loc, diag::err_capture_non_automatic_variable) << C->Id; Diag(Var->getLocation(), diag::note_previous_decl) << C->Id; continue; } // C++11 [expr.prim.lambda]p8: // An identifier or this shall not appear more than once in a // lambda-capture. if (LSI->isCaptured(Var)) { Diag(C->Loc, diag::err_capture_more_than_once) << C->Id << SourceRange(LSI->getCapture(Var).getLocation()) << FixItHint::CreateRemoval( SourceRange(PP.getLocForEndOfToken(PrevCaptureLoc), C->Loc)); continue; } // C++11 [expr.prim.lambda]p23: // A capture followed by an ellipsis is a pack expansion (14.5.3). SourceLocation EllipsisLoc; if (C->EllipsisLoc.isValid()) { if (Var->isParameterPack()) { EllipsisLoc = C->EllipsisLoc; } else { Diag(C->EllipsisLoc, diag::err_pack_expansion_without_parameter_packs) << SourceRange(C->Loc); // Just ignore the ellipsis. } } else if (Var->isParameterPack()) { ContainsUnexpandedParameterPack = true; } TryCaptureKind Kind = C->Kind == LCK_ByRef ? TryCapture_ExplicitByRef : TryCapture_ExplicitByVal; tryCaptureVariable(Var, C->Loc, Kind, EllipsisLoc); } finishLambdaExplicitCaptures(LSI); LSI->ContainsUnexpandedParameterPack = ContainsUnexpandedParameterPack; // Add lambda parameters into scope. addLambdaParameters(Method, CurScope); // Enter a new evaluation context to insulate the lambda from any // cleanups from the enclosing full-expression. PushExpressionEvaluationContext(PotentiallyEvaluated); }
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; }
/// ParseKNRParamDeclarations - Parse 'declaration-list[opt]' which provides /// types for a function with a K&R-style identifier list for arguments. void Parser::ParseKNRParamDeclarations(Declarator &D) { // We know that the top-level of this declarator is a function. DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun; // Enter function-declaration scope, limiting any declarators to the // function prototype scope, including parameter declarators. ParseScope PrototypeScope(this, Scope::FunctionPrototypeScope|Scope::DeclScope); // Read all the argument declarations. while (isDeclarationSpecifier()) { SourceLocation DSStart = Tok.getLocation(); // Parse the common declaration-specifiers piece. DeclSpec DS; ParseDeclarationSpecifiers(DS); // C99 6.9.1p6: 'each declaration in the declaration list shall have at // least one declarator'. // NOTE: GCC just makes this an ext-warn. It's not clear what it does with // the declarations though. It's trivial to ignore them, really hard to do // anything else with them. if (Tok.is(tok::semi)) { Diag(DSStart, diag::err_declaration_does_not_declare_param); ConsumeToken(); continue; } // C99 6.9.1p6: Declarations shall contain no storage-class specifiers other // than register. if (DS.getStorageClassSpec() != DeclSpec::SCS_unspecified && DS.getStorageClassSpec() != DeclSpec::SCS_register) { Diag(DS.getStorageClassSpecLoc(), diag::err_invalid_storage_class_in_func_decl); DS.ClearStorageClassSpecs(); } if (DS.isThreadSpecified()) { Diag(DS.getThreadSpecLoc(), diag::err_invalid_storage_class_in_func_decl); DS.ClearStorageClassSpecs(); } // Parse the first declarator attached to this declspec. Declarator ParmDeclarator(DS, Declarator::KNRTypeListContext); ParseDeclarator(ParmDeclarator); // Handle the full declarator list. while (1) { Action::AttrTy *AttrList; // If attributes are present, parse them. if (Tok.is(tok::kw___attribute)) // FIXME: attach attributes too. AttrList = ParseAttributes(); // Ask the actions module to compute the type for this declarator. Action::DeclPtrTy Param = Actions.ActOnParamDeclarator(CurScope, ParmDeclarator); if (Param && // A missing identifier has already been diagnosed. ParmDeclarator.getIdentifier()) { // Scan the argument list looking for the correct param to apply this // type. for (unsigned i = 0; ; ++i) { // C99 6.9.1p6: those declarators shall declare only identifiers from // the identifier list. if (i == FTI.NumArgs) { Diag(ParmDeclarator.getIdentifierLoc(), diag::err_no_matching_param) << ParmDeclarator.getIdentifier(); break; } if (FTI.ArgInfo[i].Ident == ParmDeclarator.getIdentifier()) { // Reject redefinitions of parameters. if (FTI.ArgInfo[i].Param) { Diag(ParmDeclarator.getIdentifierLoc(), diag::err_param_redefinition) << ParmDeclarator.getIdentifier(); } else { FTI.ArgInfo[i].Param = Param; } break; } } } // If we don't have a comma, it is either the end of the list (a ';') or // an error, bail out. if (Tok.isNot(tok::comma)) break; // Consume the comma. ConsumeToken(); // Parse the next declarator. ParmDeclarator.clear(); ParseDeclarator(ParmDeclarator); } if (Tok.is(tok::semi)) { ConsumeToken(); } else { Diag(Tok, diag::err_parse_error); // Skip to end of block or statement SkipUntil(tok::semi, true); if (Tok.is(tok::semi)) ConsumeToken(); } } // The actions module must verify that all arguments were declared. Actions.ActOnFinishKNRParamDeclarations(CurScope, D, Tok.getLocation()); }
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; }
/// 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); }