From: Kaelyn Uhrain Date: Tue, 11 Oct 2011 00:28:49 +0000 (+0000) Subject: Move a couple chunks of ActOnFunctionDeclarator to separate functions X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=d7e19ce8fbb9c6dfa2e634f36fd8f150c3268de2;p=clang Move a couple chunks of ActOnFunctionDeclarator to separate functions git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@141611 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 38f2384125..e0ef068ed0 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -4452,47 +4452,210 @@ static NamedDecl* DiagnoseInvalidRedeclaration( return Result; } -NamedDecl* -Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, - TypeSourceInfo *TInfo, LookupResult &Previous, - MultiTemplateParamsArg TemplateParamLists, - bool &AddToScope) { - QualType R = TInfo->getType(); - - assert(R.getTypePtr()->isFunctionType()); - - // TODO: consider using NameInfo for diagnostic. - DeclarationNameInfo NameInfo = GetNameForDeclarator(D); - DeclarationName Name = NameInfo.getName(); - FunctionDecl::StorageClass SC = SC_None; +static FunctionDecl::StorageClass getFunctionStorageClass(Sema &SemaRef, Declarator &D) { switch (D.getDeclSpec().getStorageClassSpec()) { default: llvm_unreachable("Unknown storage class!"); case DeclSpec::SCS_auto: case DeclSpec::SCS_register: case DeclSpec::SCS_mutable: - Diag(D.getDeclSpec().getStorageClassSpecLoc(), - diag::err_typecheck_sclass_func); + SemaRef.Diag(D.getDeclSpec().getStorageClassSpecLoc(), + diag::err_typecheck_sclass_func); D.setInvalidType(); break; - case DeclSpec::SCS_unspecified: SC = SC_None; break; - case DeclSpec::SCS_extern: SC = SC_Extern; break; + case DeclSpec::SCS_unspecified: break; + case DeclSpec::SCS_extern: return SC_Extern; case DeclSpec::SCS_static: { - if (CurContext->getRedeclContext()->isFunctionOrMethod()) { + if (SemaRef.CurContext->getRedeclContext()->isFunctionOrMethod()) { // C99 6.7.1p5: // The declaration of an identifier for a function that has // block scope shall have no explicit storage-class specifier // other than extern // See also (C++ [dcl.stc]p4). - Diag(D.getDeclSpec().getStorageClassSpecLoc(), - diag::err_static_block_func); - SC = SC_None; + SemaRef.Diag(D.getDeclSpec().getStorageClassSpecLoc(), + diag::err_static_block_func); + break; } else - SC = SC_Static; - break; + return SC_Static; + } + case DeclSpec::SCS_private_extern: return SC_PrivateExtern; } - case DeclSpec::SCS_private_extern: SC = SC_PrivateExtern; break; + + // No explicit storage class has already been returned + return SC_None; +} + +static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D, + DeclContext *DC, QualType &R, + TypeSourceInfo *TInfo, + FunctionDecl::StorageClass SC, + bool &IsVirtualOkay) { + DeclarationNameInfo NameInfo = SemaRef.GetNameForDeclarator(D); + DeclarationName Name = NameInfo.getName(); + + FunctionDecl *NewFD = 0; + bool isInline = D.getDeclSpec().isInlineSpecified(); + DeclSpec::SCS SCSpec = D.getDeclSpec().getStorageClassSpecAsWritten(); + FunctionDecl::StorageClass SCAsWritten + = StorageClassSpecToFunctionDeclStorageClass(SCSpec); + + if (!SemaRef.getLangOptions().CPlusPlus) { + // Determine whether the function was written with a + // prototype. This true when: + // - there is a prototype in the declarator, or + // - the type R of the function is some kind of typedef or other reference + // to a type name (which eventually refers to a function type). + bool HasPrototype = + (D.isFunctionDeclarator() && D.getFunctionTypeInfo().hasPrototype) || + (!isa(R.getTypePtr()) && R->isFunctionProtoType()); + + NewFD = FunctionDecl::Create(SemaRef.Context, DC, D.getSourceRange().getBegin(), + NameInfo, R, TInfo, SC, SCAsWritten, isInline, + HasPrototype); + if (D.isInvalidType()) + NewFD->setInvalidDecl(); + + // Set the lexical context. + NewFD->setLexicalDeclContext(SemaRef.CurContext); + + return NewFD; } + bool isExplicit = D.getDeclSpec().isExplicitSpecified(); + bool isConstexpr = D.getDeclSpec().isConstexprSpecified(); + + // Check that the return type is not an abstract class type. + // For record types, this is done by the AbstractClassUsageDiagnoser once + // the class has been completely parsed. + if (!DC->isRecord() && + SemaRef.RequireNonAbstractType(D.getIdentifierLoc(), + R->getAs()->getResultType(), + diag::err_abstract_type_in_decl, + SemaRef.AbstractReturnType)) + D.setInvalidType(); + + if (Name.getNameKind() == DeclarationName::CXXConstructorName) { + // This is a C++ constructor declaration. + assert(DC->isRecord() && + "Constructors can only be declared in a member context"); + + R = SemaRef.CheckConstructorDeclarator(D, R, SC); + return CXXConstructorDecl::Create(SemaRef.Context, cast(DC), + D.getSourceRange().getBegin(), NameInfo, + R, TInfo, isExplicit, isInline, + /*isImplicitlyDeclared=*/false, + isConstexpr); + + } else if (Name.getNameKind() == DeclarationName::CXXDestructorName) { + // This is a C++ destructor declaration. + if (DC->isRecord()) { + R = SemaRef.CheckDestructorDeclarator(D, R, SC); + CXXRecordDecl *Record = cast(DC); + CXXDestructorDecl *NewDD = CXXDestructorDecl::Create( + SemaRef.Context, Record, + D.getSourceRange().getBegin(), + NameInfo, R, TInfo, isInline, + /*isImplicitlyDeclared=*/false); + + // If the class is complete, then we now create the implicit exception + // specification. If the class is incomplete or dependent, we can't do + // it yet. + if (SemaRef.getLangOptions().CPlusPlus0x && !Record->isDependentType() && + Record->getDefinition() && !Record->isBeingDefined() && + R->getAs()->getExceptionSpecType() == EST_None) { + SemaRef.AdjustDestructorExceptionSpec(Record, NewDD); + } + + IsVirtualOkay = true; + return NewDD; + + } else { + SemaRef.Diag(D.getIdentifierLoc(), diag::err_destructor_not_member); + D.setInvalidType(); + + // Create a FunctionDecl to satisfy the function definition parsing + // code path. + return FunctionDecl::Create(SemaRef.Context, DC, + D.getSourceRange().getBegin(), + D.getIdentifierLoc(), Name, R, TInfo, + SC, SCAsWritten, isInline, + /*hasPrototype=*/true, isConstexpr); + } + + } else if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName) { + if (!DC->isRecord()) { + SemaRef.Diag(D.getIdentifierLoc(), + diag::err_conv_function_not_member); + return 0; + } + + SemaRef.CheckConversionDeclarator(D, R, SC); + IsVirtualOkay = true; + return CXXConversionDecl::Create(SemaRef.Context, cast(DC), + D.getSourceRange().getBegin(), NameInfo, + R, TInfo, isInline, isExplicit, + isConstexpr, SourceLocation()); + + } else if (DC->isRecord()) { + // If the name of the function is the same as the name of the record, + // then this must be an invalid constructor that has a return type. + // (The parser checks for a return type and makes the declarator a + // constructor if it has no return type). + if (Name.getAsIdentifierInfo() && + Name.getAsIdentifierInfo() == cast(DC)->getIdentifier()){ + SemaRef.Diag(D.getIdentifierLoc(), diag::err_constructor_return_type) + << SourceRange(D.getDeclSpec().getTypeSpecTypeLoc()) + << SourceRange(D.getIdentifierLoc()); + return 0; + } + + bool isStatic = SC == SC_Static; + + // [class.free]p1: + // Any allocation function for a class T is a static member + // (even if not explicitly declared static). + if (Name.getCXXOverloadedOperator() == OO_New || + Name.getCXXOverloadedOperator() == OO_Array_New) + isStatic = true; + + // [class.free]p6 Any deallocation function for a class X is a static member + // (even if not explicitly declared static). + if (Name.getCXXOverloadedOperator() == OO_Delete || + Name.getCXXOverloadedOperator() == OO_Array_Delete) + isStatic = true; + + IsVirtualOkay = !isStatic; + + // This is a C++ method declaration. + return CXXMethodDecl::Create(SemaRef.Context, cast(DC), + D.getSourceRange().getBegin(), NameInfo, R, + TInfo, isStatic, SCAsWritten, isInline, + isConstexpr, SourceLocation()); + + } else { + // Determine whether the function was written with a + // prototype. This true when: + // - we're in C++ (where every function has a prototype), + return FunctionDecl::Create(SemaRef.Context, DC, + D.getSourceRange().getBegin(), + NameInfo, R, TInfo, SC, SCAsWritten, isInline, + true/*HasPrototype*/, isConstexpr); + } +} + +NamedDecl* +Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, + TypeSourceInfo *TInfo, LookupResult &Previous, + MultiTemplateParamsArg TemplateParamLists, + bool &AddToScope) { + QualType R = TInfo->getType(); + + assert(R.getTypePtr()->isFunctionType()); + + // TODO: consider using NameInfo for diagnostic. + DeclarationNameInfo NameInfo = GetNameForDeclarator(D); + DeclarationName Name = NameInfo.getName(); + FunctionDecl::StorageClass SC = getFunctionStorageClass(*this, D); + if (D.getDeclSpec().isThreadSpecified()) Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread); @@ -4514,170 +4677,23 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, R = Context.getFunctionNoProtoType(T); } - FunctionDecl *NewFD; - bool isInline = D.getDeclSpec().isInlineSpecified(); bool isFriend = false; - DeclSpec::SCS SCSpec = D.getDeclSpec().getStorageClassSpecAsWritten(); - FunctionDecl::StorageClass SCAsWritten - = StorageClassSpecToFunctionDeclStorageClass(SCSpec); FunctionTemplateDecl *FunctionTemplate = 0; bool isExplicitSpecialization = false; bool isFunctionTemplateSpecialization = false; bool isDependentClassScopeExplicitSpecialization = false; + bool isVirtualOkay = false; - if (!getLangOptions().CPlusPlus) { - // Determine whether the function was written with a - // prototype. This true when: - // - there is a prototype in the declarator, or - // - the type R of the function is some kind of typedef or other reference - // to a type name (which eventually refers to a function type). - bool HasPrototype = - (D.isFunctionDeclarator() && D.getFunctionTypeInfo().hasPrototype) || - (!isa(R.getTypePtr()) && R->isFunctionProtoType()); - - NewFD = FunctionDecl::Create(Context, DC, D.getSourceRange().getBegin(), - NameInfo, R, TInfo, SC, SCAsWritten, isInline, - HasPrototype); - if (D.isInvalidType()) - NewFD->setInvalidDecl(); - - // Set the lexical context. - NewFD->setLexicalDeclContext(CurContext); - // Filter out previous declarations that don't match the scope. - FilterLookupForScope(Previous, DC, S, NewFD->hasLinkage(), - /*ExplicitInstantiationOrSpecialization=*/false); - } else { - isFriend = D.getDeclSpec().isFriendSpecified(); + FunctionDecl *NewFD = CreateNewFunctionDecl(*this, D, DC, R, TInfo, SC, + isVirtualOkay); + if (!NewFD) return 0; + + if (getLangOptions().CPlusPlus) { + bool isInline = D.getDeclSpec().isInlineSpecified(); bool isVirtual = D.getDeclSpec().isVirtualSpecified(); bool isExplicit = D.getDeclSpec().isExplicitSpecified(); bool isConstexpr = D.getDeclSpec().isConstexprSpecified(); - bool isVirtualOkay = false; - - // Check that the return type is not an abstract class type. - // For record types, this is done by the AbstractClassUsageDiagnoser once - // the class has been completely parsed. - if (!DC->isRecord() && - RequireNonAbstractType(D.getIdentifierLoc(), - R->getAs()->getResultType(), - diag::err_abstract_type_in_decl, - AbstractReturnType)) - D.setInvalidType(); - - if (Name.getNameKind() == DeclarationName::CXXConstructorName) { - // This is a C++ constructor declaration. - assert(DC->isRecord() && - "Constructors can only be declared in a member context"); - - R = CheckConstructorDeclarator(D, R, SC); - - // Create the new declaration - CXXConstructorDecl *NewCD = CXXConstructorDecl::Create( - Context, - cast(DC), - D.getSourceRange().getBegin(), - NameInfo, R, TInfo, - isExplicit, isInline, - /*isImplicitlyDeclared=*/false, - isConstexpr); - - NewFD = NewCD; - } else if (Name.getNameKind() == DeclarationName::CXXDestructorName) { - // This is a C++ destructor declaration. - if (DC->isRecord()) { - R = CheckDestructorDeclarator(D, R, SC); - CXXRecordDecl *Record = cast(DC); - - CXXDestructorDecl *NewDD = CXXDestructorDecl::Create(Context, Record, - D.getSourceRange().getBegin(), - NameInfo, R, TInfo, - isInline, - /*isImplicitlyDeclared=*/false); - NewFD = NewDD; - isVirtualOkay = true; - - // If the class is complete, then we now create the implicit exception - // specification. If the class is incomplete or dependent, we can't do - // it yet. - if (getLangOptions().CPlusPlus0x && !Record->isDependentType() && - Record->getDefinition() && !Record->isBeingDefined() && - R->getAs()->getExceptionSpecType() == EST_None) { - AdjustDestructorExceptionSpec(Record, NewDD); - } - - } else { - Diag(D.getIdentifierLoc(), diag::err_destructor_not_member); - - // Create a FunctionDecl to satisfy the function definition parsing - // code path. - NewFD = FunctionDecl::Create(Context, DC, D.getSourceRange().getBegin(), - D.getIdentifierLoc(), Name, R, TInfo, - SC, SCAsWritten, isInline, - /*hasPrototype=*/true, isConstexpr); - D.setInvalidType(); - } - } else if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName) { - if (!DC->isRecord()) { - Diag(D.getIdentifierLoc(), - diag::err_conv_function_not_member); - return 0; - } - - CheckConversionDeclarator(D, R, SC); - NewFD = CXXConversionDecl::Create(Context, cast(DC), - D.getSourceRange().getBegin(), - NameInfo, R, TInfo, - isInline, isExplicit, isConstexpr, - SourceLocation()); - - isVirtualOkay = true; - } else if (DC->isRecord()) { - // If the name of the function is the same as the name of the record, - // then this must be an invalid constructor that has a return type. - // (The parser checks for a return type and makes the declarator a - // constructor if it has no return type). - if (Name.getAsIdentifierInfo() && - Name.getAsIdentifierInfo() == cast(DC)->getIdentifier()){ - Diag(D.getIdentifierLoc(), diag::err_constructor_return_type) - << SourceRange(D.getDeclSpec().getTypeSpecTypeLoc()) - << SourceRange(D.getIdentifierLoc()); - return 0; - } - - bool isStatic = SC == SC_Static; - - // [class.free]p1: - // Any allocation function for a class T is a static member - // (even if not explicitly declared static). - if (Name.getCXXOverloadedOperator() == OO_New || - Name.getCXXOverloadedOperator() == OO_Array_New) - isStatic = true; - - // [class.free]p6 Any deallocation function for a class X is a static member - // (even if not explicitly declared static). - if (Name.getCXXOverloadedOperator() == OO_Delete || - Name.getCXXOverloadedOperator() == OO_Array_Delete) - isStatic = true; - - // This is a C++ method declaration. - CXXMethodDecl *NewMD = CXXMethodDecl::Create( - Context, cast(DC), - D.getSourceRange().getBegin(), - NameInfo, R, TInfo, - isStatic, SCAsWritten, isInline, - isConstexpr, - SourceLocation()); - NewFD = NewMD; - - isVirtualOkay = !isStatic; - } else { - // Determine whether the function was written with a - // prototype. This true when: - // - we're in C++ (where every function has a prototype), - NewFD = FunctionDecl::Create(Context, DC, D.getSourceRange().getBegin(), - NameInfo, R, TInfo, SC, SCAsWritten, isInline, - true/*HasPrototype*/, isConstexpr); - } - + isFriend = D.getDeclSpec().isFriendSpecified(); if (isFriend && !isInline && D.isFunctionDefinition()) { // C++ [class.friend]p5 // A function can be defined in a friend declaration of a @@ -4781,7 +4797,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, if (FunctionTemplate) FunctionTemplate->setInvalidDecl(); } - + // C++ [dcl.fct.spec]p5: // The virtual specifier shall only be used in declarations of // nonstatic class member functions that appear within a @@ -4818,7 +4834,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, << FixItHint::CreateRemoval(D.getDeclSpec().getInlineSpecLoc()); } } - + // C++ [dcl.fct.spec]p6: // The explicit specifier shall be used only in the declaration of a // constructor or conversion function within its class definition; see 12.3.1 @@ -4866,11 +4882,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, } } - // Filter out previous declarations that don't match the scope. - FilterLookupForScope(Previous, DC, S, NewFD->hasLinkage(), - isExplicitSpecialization || - isFunctionTemplateSpecialization); - if (isFriend) { // For now, claim that the objects have no previous declaration. if (FunctionTemplate) { @@ -4902,6 +4913,11 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc()); } } + + // Filter out previous declarations that don't match the scope. + FilterLookupForScope(Previous, DC, S, NewFD->hasLinkage(), + isExplicitSpecialization || + isFunctionTemplateSpecialization); // Handle GNU asm-label extension (encoded as an attribute). if (Expr *E = (Expr*) D.getAsmLabel()) {