diff options
author | Chris Lattner <sabre@nondot.org> | 2008-04-08 04:40:51 +0000 |
---|---|---|
committer | Chris Lattner <sabre@nondot.org> | 2008-04-08 04:40:51 +0000 |
commit | 04421087832a031c90bd58f128c7c0e741db8dd2 (patch) | |
tree | c80c38dcc7ecb4d31cf5c10faa49e00fc373ea81 /lib/Sema/SemaDecl.cpp | |
parent | 5db17c9b5edb43e12196e565389b73e91a4fcb65 (diff) |
Add support for C++ default arguments, and rework Parse-Sema
interaction for function parameters, fixing PR2046.
Patch by Doug Gregor!
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@49369 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaDecl.cpp')
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 224 |
1 files changed, 163 insertions, 61 deletions
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 0f464a0bc7..5451ec27c0 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -263,9 +263,10 @@ static void MergeAttributes(Decl *New, Decl *Old) { } } -/// MergeFunctionDecl - We just parsed a function 'New' which has the same name -/// and scope as a previous declaration 'Old'. Figure out how to resolve this -/// situation, merging decls or emitting diagnostics as appropriate. +/// MergeFunctionDecl - We just parsed a function 'New' from +/// declarator D which has the same name and scope as a previous +/// declaration 'Old'. Figure out how to resolve this situation, +/// merging decls or emitting diagnostics as appropriate. /// FunctionDecl *Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { // Verify the old decl was also a function. @@ -276,17 +277,24 @@ FunctionDecl *Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { Diag(OldD->getLocation(), diag::err_previous_definition); return New; } - + MergeAttributes(New, Old); - QualType OldQType = Context.getCanonicalType(Old->getType()); QualType NewQType = Context.getCanonicalType(New->getType()); - // Function types need to be compatible, not identical. This handles + // C++ [dcl.fct]p3: + // All declarations for a function shall agree exactly in both the + // return type and the parameter-type-list. + if (getLangOptions().CPlusPlus && OldQType == NewQType) + return MergeCXXFunctionDecl(New, Old); + + // C: Function types need to be compatible, not identical. This handles // duplicate function decls like "void f(int); void f(enum X);" properly. - if (Context.functionTypesAreCompatible(OldQType, NewQType)) + if (!getLangOptions().CPlusPlus && + Context.functionTypesAreCompatible(OldQType, NewQType)) { return New; + } // A function that has already been declared has been redeclared or defined // with a different type- show appropriate diagnostic @@ -295,7 +303,7 @@ FunctionDecl *Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { PrevDiag = diag::err_previous_definition; else if (Old->isImplicit()) PrevDiag = diag::err_previous_implicit_declaration; - else + else PrevDiag = diag::err_previous_declaration; // TODO: CHECK FOR CONFLICTS, multiple decls with same name in one scope. @@ -413,6 +421,49 @@ VarDecl *Sema::MergeVarDecl(VarDecl *New, Decl *OldD) { return New; } +/// CheckParmsForFunctionDef - Check that the parameters of the given +/// function are appropriate for the definition of a function. This +/// takes care of any checks that cannot be performed on the +/// declaration itself, e.g., that the types of each of the function +/// parameters are complete. +bool Sema::CheckParmsForFunctionDef(FunctionDecl *FD) { + bool HasInvalidParm = false; + for (unsigned p = 0, NumParams = FD->getNumParams(); p < NumParams; ++p) { + ParmVarDecl *Param = FD->getParamDecl(p); + + // C99 6.7.5.3p4: the parameters in a parameter type list in a + // function declarator that is part of a function definition of + // that function shall not have incomplete type. + if (Param->getType()->isIncompleteType() && + !Param->isInvalidDecl()) { + Diag(Param->getLocation(), diag::err_typecheck_decl_incomplete_type, + Param->getType().getAsString()); + Param->setInvalidDecl(); + HasInvalidParm = true; + } + } + + return HasInvalidParm; +} + +/// CreateImplicitParameter - Creates an implicit function parameter +/// in the scope S and with the given type. This routine is used, for +/// example, to create the implicit "self" parameter in an Objective-C +/// method. +ParmVarDecl * +Sema::CreateImplicitParameter(Scope *S, IdentifierInfo *Id, + SourceLocation IdLoc, QualType Type) { + ParmVarDecl *New = ParmVarDecl::Create(Context, CurContext, IdLoc, Id, Type, + VarDecl::None, 0, 0); + if (Id) { + New->setNext(Id->getFETokenInfo<ScopedDecl>()); + Id->setFETokenInfo(New); + S->AddDecl(New); + } + + return New; +} + /// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with /// no declarator (e.g. "struct foo;") is parsed. Sema::DeclTy *Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) { @@ -769,7 +820,38 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) { // Handle attributes. HandleDeclAttributes(NewFD, D.getDeclSpec().getAttributes(), D.getAttributes()); - + + // Copy the parameter declarations from the declarator D to + // the function declaration NewFD, if they are available. + if (D.getNumTypeObjects() > 0 && + D.getTypeObject(0).Fun.hasPrototype) { + DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun; + + // Create Decl objects for each parameter, adding them to the + // FunctionDecl. + llvm::SmallVector<ParmVarDecl*, 16> Params; + + // Check for C99 6.7.5.3p10 - foo(void) is a non-varargs + // function that takes no arguments, not a function that takes a + // single void argument. FIXME: Is this really the right place + // to check for this? C++ says that the parameter list (void) is + // the same as an empty parameter list, whereas the parameter + // list (T) (with T typedef'd to void) is not. For C++, this + // should be handled in the parser. Check C89 and C99 standards + // to see what the correct behavior is. + if (FTI.NumArgs == 1 && !FTI.isVariadic && FTI.ArgInfo[0].Ident == 0 && + FTI.ArgInfo[0].Param && + !((ParmVarDecl*)FTI.ArgInfo[0].Param)->getType().getCVRQualifiers() && + ((ParmVarDecl*)FTI.ArgInfo[0].Param)->getType()->isVoidType()) { + // empty arg list, don't push any params. + } else { + for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) + Params.push_back((ParmVarDecl *)FTI.ArgInfo[i].Param); + } + + NewFD->setParams(&Params[0], Params.size()); + } + // Merge the decl with the existing one if appropriate. Since C functions // are in a flat namespace, make sure we consider decls in outer scopes. if (PrevDecl) { @@ -777,6 +859,10 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) { if (NewFD == 0) return 0; } New = NewFD; + + // In C++, check default arguments now that we have merged decls. + if (getLangOptions().CPlusPlus) + CheckCXXDefaultArguments(NewFD); } else { if (R.getTypePtr()->isObjCInterfaceType()) { Diag(D.getIdentifierLoc(), diag::err_statically_allocated_object, @@ -982,20 +1068,47 @@ Sema::DeclTy *Sema::FinalizeDeclaratorGroup(Scope *S, DeclTy *group) { return NewGroup; } -// Called from Sema::ParseStartOfFunctionDef(). -ParmVarDecl * -Sema::ActOnParamDeclarator(struct DeclaratorChunk::ParamInfo &PI, - Scope *FnScope) { - IdentifierInfo *II = PI.Ident; +/// ActOnParamDeclarator - Called from Parser::ParseFunctionDeclarator() +/// to introduce parameters into function prototype scope. +Sema::DeclTy * +Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { + DeclSpec &DS = D.getDeclSpec(); + + // Verify C99 6.7.5.3p2: The only SCS allowed is '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(); + } + + + // In this context, we *do not* check D.getInvalidType(). If the declarator + // type was invalid, GetTypeForDeclarator() still returns a "valid" type, + // though it will not reflect the user specified type. + QualType parmDeclType = GetTypeForDeclarator(D, S); + + assert(!parmDeclType.isNull() && "GetTypeForDeclarator() returned null type"); + // TODO: CHECK FOR CONFLICTS, multiple decls with same name in one scope. // Can this happen for params? We already checked that they don't conflict // among each other. Here they can only shadow globals, which is ok. - if (/*Decl *PrevDecl = */LookupDecl(II, Decl::IDNS_Ordinary, FnScope)) { - + IdentifierInfo *II = D.getIdentifier(); + if (Decl *PrevDecl = LookupDecl(II, Decl::IDNS_Ordinary, S)) { + if (S->isDeclScope(PrevDecl)) { + Diag(D.getIdentifierLoc(), diag::err_param_redefinition, + dyn_cast<NamedDecl>(PrevDecl)->getName()); + + // Recover by removing the name + II = 0; + D.SetIdentifier(0, D.getIdentifierLoc()); + } } - - // FIXME: Handle storage class (auto, register). No declarator? - // TODO: Chain to previous parameter with the prevdeclarator chain? // Perform the default function/array conversion (C99 6.7.5.3p[7,8]). // Doing the promotion here has a win and a loss. The win is the type for @@ -1014,29 +1127,29 @@ Sema::ActOnParamDeclarator(struct DeclaratorChunk::ParamInfo &PI, // FIXME: If a source translation tool needs to see the original type, then // we need to consider storing both types (in ParmVarDecl)... // - QualType parmDeclType = QualType::getFromOpaquePtr(PI.TypeInfo); if (parmDeclType->isArrayType()) { // int x[restrict 4] -> int *restrict parmDeclType = Context.getArrayDecayedType(parmDeclType); } else if (parmDeclType->isFunctionType()) parmDeclType = Context.getPointerType(parmDeclType); - ParmVarDecl *New = ParmVarDecl::Create(Context, CurContext, PI.IdentLoc, II, - parmDeclType, - VarDecl::None, 0); + ParmVarDecl *New = ParmVarDecl::Create(Context, CurContext, + D.getIdentifierLoc(), II, + parmDeclType, VarDecl::None, + 0, 0); - if (PI.InvalidType) + if (D.getInvalidType()) New->setInvalidDecl(); - // If this has an identifier, add it to the scope stack. if (II) { New->setNext(II->getFETokenInfo<ScopedDecl>()); II->setFETokenInfo(New); - FnScope->AddDecl(New); + S->AddDecl(New); } - HandleDeclAttributes(New, PI.AttrList, 0); + HandleDeclAttributes(New, D.getAttributes(), 0); return New; + } Sema::DeclTy *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Declarator &D) { @@ -1044,17 +1157,23 @@ Sema::DeclTy *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Declarator &D) { assert(D.getTypeObject(0).Kind == DeclaratorChunk::Function && "Not a function declarator!"); DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun; - + // Verify 6.9.1p6: 'every identifier in the identifier list shall be declared' // for a K&R function. if (!FTI.hasPrototype) { for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) { - if (FTI.ArgInfo[i].TypeInfo == 0) { + if (FTI.ArgInfo[i].Param == 0) { Diag(FTI.ArgInfo[i].IdentLoc, diag::ext_param_not_declared, FTI.ArgInfo[i].Ident->getName()); // Implicitly declare the argument as type 'int' for lack of a better // type. - FTI.ArgInfo[i].TypeInfo = Context.IntTy.getAsOpaquePtr(); + DeclSpec DS; + const char* PrevSpec; // unused + DS.SetTypeSpecType(DeclSpec::TST_int, FTI.ArgInfo[i].IdentLoc, + PrevSpec); + Declarator ParamD(DS, Declarator::KNRTypeListContext); + ParamD.SetIdentifier(FTI.ArgInfo[i].Ident, FTI.ArgInfo[i].IdentLoc); + FTI.ArgInfo[i].Param = ActOnParamDeclarator(FnBodyScope, ParamD); } } @@ -1063,8 +1182,7 @@ Sema::DeclTy *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Declarator &D) { if (FTI.NumArgs) FTI.hasPrototype = true; } else { - // FIXME: Diagnose arguments without names in C. - + // FIXME: Diagnose arguments without names in C. } Scope *GlobalScope = FnBodyScope->getParent(); @@ -1083,37 +1201,21 @@ Sema::DeclTy *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Declarator &D) { FunctionDecl *FD = cast<FunctionDecl>(decl); CurFunctionDecl = FD; PushDeclContext(FD); - - // Create Decl objects for each parameter, adding them to the FunctionDecl. - llvm::SmallVector<ParmVarDecl*, 16> Params; - - // Check for C99 6.7.5.3p10 - foo(void) is a non-varargs function that takes - // no arguments, not a function that takes a single void argument. - if (FTI.NumArgs == 1 && !FTI.isVariadic && FTI.ArgInfo[0].Ident == 0 && - !QualType::getFromOpaquePtr(FTI.ArgInfo[0].TypeInfo).getCVRQualifiers() && - QualType::getFromOpaquePtr(FTI.ArgInfo[0].TypeInfo)->isVoidType()) { - // empty arg list, don't push any params. - } else { - for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) { - ParmVarDecl *parmDecl; - - parmDecl = ActOnParamDeclarator(D.getTypeObject(0).Fun.ArgInfo[i], - FnBodyScope); - // C99 6.7.5.3p4: the parameters in a parameter type list in a function - // declarator that is part of a function definition of that function - // shall not have incomplete type. - if (parmDecl->getType()->isIncompleteType() && - !parmDecl->isInvalidDecl()) { - Diag(parmDecl->getLocation(), diag::err_typecheck_decl_incomplete_type, - parmDecl->getType().getAsString()); - parmDecl->setInvalidDecl(); - } - Params.push_back(parmDecl); + + // Check the validity of our function parameters + CheckParmsForFunctionDef(FD); + + // Introduce our parameters into the function scope + for (unsigned p = 0, NumParams = FD->getNumParams(); p < NumParams; ++p) { + ParmVarDecl *Param = FD->getParamDecl(p); + // If this has an identifier, add it to the scope stack. + if (IdentifierInfo *II = Param->getIdentifier()) { + Param->setNext(II->getFETokenInfo<ScopedDecl>()); + II->setFETokenInfo(Param); + FnBodyScope->AddDecl(Param); } } - - FD->setParams(&Params[0], Params.size()); - + return FD; } |