Extract code dealing with declarators of function type into a separate function

Sema::ActOnFunctionDeclarator().  
No functionality change.  

llvm-svn: 62290
This commit is contained in:
Zhongxing Xu 2009-01-16 01:13:29 +00:00
parent c5ece68d16
commit bece5d61f6
2 changed files with 307 additions and 288 deletions

View File

@ -277,6 +277,10 @@ public:
}
DeclTy *ActOnDeclarator(Scope *S, Declarator &D, DeclTy *LastInGroup,
bool IsFunctionDefinition);
ScopedDecl* ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
QualType R, ScopedDecl *LastDeclarator,
Decl* PreDecl, bool IsFunctionDefinition,
bool& InvalidDecl);
virtual DeclTy *ActOnParamDeclarator(Scope *S, Declarator &D);
virtual void ActOnParamDefaultArgument(DeclTy *param,
SourceLocation EqualLoc,

View File

@ -1325,294 +1325,8 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl,
}
}
} else if (R.getTypePtr()->isFunctionType()) {
FunctionDecl::StorageClass SC = FunctionDecl::None;
switch (D.getDeclSpec().getStorageClassSpec()) {
default: assert(0 && "Unknown storage class!");
case DeclSpec::SCS_auto:
case DeclSpec::SCS_register:
case DeclSpec::SCS_mutable:
Diag(D.getIdentifierLoc(), diag::err_typecheck_sclass_func);
InvalidDecl = true;
break;
case DeclSpec::SCS_unspecified: SC = FunctionDecl::None; break;
case DeclSpec::SCS_extern: SC = FunctionDecl::Extern; break;
case DeclSpec::SCS_static: SC = FunctionDecl::Static; break;
case DeclSpec::SCS_private_extern: SC = FunctionDecl::PrivateExtern;break;
}
bool isInline = D.getDeclSpec().isInlineSpecified();
// bool isVirtual = D.getDeclSpec().isVirtualSpecified();
bool isExplicit = D.getDeclSpec().isExplicitSpecified();
FunctionDecl *NewFD;
if (D.getKind() == Declarator::DK_Constructor) {
// This is a C++ constructor declaration.
assert(DC->isRecord() &&
"Constructors can only be declared in a member context");
InvalidDecl = InvalidDecl || CheckConstructorDeclarator(D, R, SC);
// Create the new declaration
NewFD = CXXConstructorDecl::Create(Context,
cast<CXXRecordDecl>(DC),
D.getIdentifierLoc(), Name, R,
isExplicit, isInline,
/*isImplicitlyDeclared=*/false);
if (InvalidDecl)
NewFD->setInvalidDecl();
} else if (D.getKind() == Declarator::DK_Destructor) {
// This is a C++ destructor declaration.
if (DC->isRecord()) {
InvalidDecl = InvalidDecl || CheckDestructorDeclarator(D, R, SC);
NewFD = CXXDestructorDecl::Create(Context,
cast<CXXRecordDecl>(DC),
D.getIdentifierLoc(), Name, R,
isInline,
/*isImplicitlyDeclared=*/false);
if (InvalidDecl)
NewFD->setInvalidDecl();
} 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.getIdentifierLoc(),
Name, R, SC, isInline, LastDeclarator,
// FIXME: Move to DeclGroup...
D.getDeclSpec().getSourceRange().getBegin());
InvalidDecl = true;
NewFD->setInvalidDecl();
}
} else if (D.getKind() == Declarator::DK_Conversion) {
if (!DC->isRecord()) {
Diag(D.getIdentifierLoc(),
diag::err_conv_function_not_member);
return 0;
} else {
InvalidDecl = InvalidDecl || CheckConversionDeclarator(D, R, SC);
NewFD = CXXConversionDecl::Create(Context, cast<CXXRecordDecl>(DC),
D.getIdentifierLoc(), Name, R,
isInline, isExplicit);
if (InvalidDecl)
NewFD->setInvalidDecl();
}
} else if (DC->isRecord()) {
// This is a C++ method declaration.
NewFD = CXXMethodDecl::Create(Context, cast<CXXRecordDecl>(DC),
D.getIdentifierLoc(), Name, R,
(SC == FunctionDecl::Static), isInline,
LastDeclarator);
} else {
NewFD = FunctionDecl::Create(Context, DC,
D.getIdentifierLoc(),
Name, R, SC, isInline, LastDeclarator,
// FIXME: Move to DeclGroup...
D.getDeclSpec().getSourceRange().getBegin());
}
// Set the lexical context. If the declarator has a C++
// scope specifier, the lexical context will be different
// from the semantic context.
NewFD->setLexicalDeclContext(CurContext);
// Handle GNU asm-label extension (encoded as an attribute).
if (Expr *E = (Expr*) D.getAsmLabel()) {
// The parser guarantees this is a string.
StringLiteral *SE = cast<StringLiteral>(E);
NewFD->addAttr(new AsmLabelAttr(std::string(SE->getStrData(),
SE->getByteLength())));
}
// Copy the parameter declarations from the declarator D to
// the function declaration NewFD, if they are available.
if (D.getNumTypeObjects() > 0) {
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.
// We let through "const void" here because Sema::GetTypeForDeclarator
// already checks for that case.
if (FTI.NumArgs == 1 && !FTI.isVariadic && FTI.ArgInfo[0].Ident == 0 &&
FTI.ArgInfo[0].Param &&
((ParmVarDecl*)FTI.ArgInfo[0].Param)->getType()->isVoidType()) {
// empty arg list, don't push any params.
ParmVarDecl *Param = (ParmVarDecl*)FTI.ArgInfo[0].Param;
// In C++, the empty parameter-type-list must be spelled "void"; a
// typedef of void is not permitted.
if (getLangOptions().CPlusPlus &&
Param->getType().getUnqualifiedType() != Context.VoidTy) {
Diag(Param->getLocation(), diag::ext_param_typedef_of_void);
}
} else if (FTI.NumArgs > 0 && FTI.ArgInfo[0].Param != 0) {
for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i)
Params.push_back((ParmVarDecl *)FTI.ArgInfo[i].Param);
}
NewFD->setParams(Context, &Params[0], Params.size());
} else if (R->getAsTypedefType()) {
// When we're declaring a function with a typedef, as in the
// following example, we'll need to synthesize (unnamed)
// parameters for use in the declaration.
//
// @code
// typedef void fn(int);
// fn f;
// @endcode
const FunctionTypeProto *FT = R->getAsFunctionTypeProto();
if (!FT) {
// This is a typedef of a function with no prototype, so we
// don't need to do anything.
} else if ((FT->getNumArgs() == 0) ||
(FT->getNumArgs() == 1 && !FT->isVariadic() &&
FT->getArgType(0)->isVoidType())) {
// This is a zero-argument function. We don't need to do anything.
} else {
// Synthesize a parameter for each argument type.
llvm::SmallVector<ParmVarDecl*, 16> Params;
for (FunctionTypeProto::arg_type_iterator ArgType = FT->arg_type_begin();
ArgType != FT->arg_type_end(); ++ArgType) {
Params.push_back(ParmVarDecl::Create(Context, DC,
SourceLocation(), 0,
*ArgType, VarDecl::None,
0, 0));
}
NewFD->setParams(Context, &Params[0], Params.size());
}
}
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(NewFD))
InvalidDecl = InvalidDecl || CheckConstructor(Constructor);
else if (isa<CXXDestructorDecl>(NewFD)) {
CXXRecordDecl *Record = cast<CXXRecordDecl>(NewFD->getParent());
Record->setUserDeclaredDestructor(true);
// C++ [class]p4: A POD-struct is an aggregate class that has [...] no
// user-defined destructor.
Record->setPOD(false);
} else if (CXXConversionDecl *Conversion =
dyn_cast<CXXConversionDecl>(NewFD))
ActOnConversionDeclarator(Conversion);
// Extra checking for C++ overloaded operators (C++ [over.oper]).
if (NewFD->isOverloadedOperator() &&
CheckOverloadedOperatorDeclaration(NewFD))
NewFD->setInvalidDecl();
// 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 &&
(!getLangOptions().CPlusPlus||isDeclInScope(PrevDecl, DC, S))) {
bool Redeclaration = false;
// If C++, determine whether NewFD is an overload of PrevDecl or
// a declaration that requires merging. If it's an overload,
// there's no more work to do here; we'll just add the new
// function to the scope.
OverloadedFunctionDecl::function_iterator MatchedDecl;
if (!getLangOptions().CPlusPlus ||
!IsOverload(NewFD, PrevDecl, MatchedDecl)) {
Decl *OldDecl = PrevDecl;
// If PrevDecl was an overloaded function, extract the
// FunctionDecl that matched.
if (isa<OverloadedFunctionDecl>(PrevDecl))
OldDecl = *MatchedDecl;
// NewFD and PrevDecl represent declarations that need to be
// merged.
NewFD = MergeFunctionDecl(NewFD, OldDecl, Redeclaration);
if (NewFD == 0) return 0;
if (Redeclaration) {
NewFD->setPreviousDeclaration(cast<FunctionDecl>(OldDecl));
// An out-of-line member function declaration must also be a
// definition (C++ [dcl.meaning]p1).
if (!IsFunctionDefinition && D.getCXXScopeSpec().isSet() &&
!InvalidDecl) {
Diag(NewFD->getLocation(), diag::err_out_of_line_declaration)
<< D.getCXXScopeSpec().getRange();
NewFD->setInvalidDecl();
}
}
}
if (!Redeclaration && D.getCXXScopeSpec().isSet()) {
// The user tried to provide an out-of-line definition for a
// member function, but there was no such member function
// declared (C++ [class.mfct]p2). For example:
//
// class X {
// void f() const;
// };
//
// void X::f() { } // ill-formed
//
// Complain about this problem, and attempt to suggest close
// matches (e.g., those that differ only in cv-qualifiers and
// whether the parameter types are references).
Diag(D.getIdentifierLoc(), diag::err_member_def_does_not_match)
<< cast<CXXRecordDecl>(DC)->getDeclName()
<< D.getCXXScopeSpec().getRange();
InvalidDecl = true;
PrevDecl = LookupDecl(Name, Decl::IDNS_Ordinary, S, DC);
if (!PrevDecl) {
// Nothing to suggest.
} else if (OverloadedFunctionDecl *Ovl
= dyn_cast<OverloadedFunctionDecl>(PrevDecl)) {
for (OverloadedFunctionDecl::function_iterator
Func = Ovl->function_begin(),
FuncEnd = Ovl->function_end();
Func != FuncEnd; ++Func) {
if (isNearlyMatchingMemberFunction(Context, *Func, NewFD))
Diag((*Func)->getLocation(), diag::note_member_def_close_match);
}
} else if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(PrevDecl)) {
// Suggest this no matter how mismatched it is; it's the only
// thing we have.
unsigned diag;
if (isNearlyMatchingMemberFunction(Context, Method, NewFD))
diag = diag::note_member_def_close_match;
else if (Method->getBody())
diag = diag::note_previous_definition;
else
diag = diag::note_previous_declaration;
Diag(Method->getLocation(), diag);
}
PrevDecl = 0;
}
}
// Handle attributes. We need to have merged decls when handling attributes
// (for example to check for conflicts, etc).
ProcessDeclAttributes(NewFD, D);
New = NewFD;
if (getLangOptions().CPlusPlus) {
// In C++, check default arguments now that we have merged decls.
CheckCXXDefaultArguments(NewFD);
// An out-of-line member function declaration must also be a
// definition (C++ [dcl.meaning]p1).
if (!IsFunctionDefinition && D.getCXXScopeSpec().isSet() && !InvalidDecl) {
Diag(NewFD->getLocation(), diag::err_out_of_line_declaration)
<< D.getCXXScopeSpec().getRange();
InvalidDecl = true;
}
}
New = ActOnFunctionDeclarator(S, D, DC, R, LastDeclarator, PrevDecl,
IsFunctionDefinition, InvalidDecl);
} else {
// Check that there are no default arguments (C++ only).
if (getLangOptions().CPlusPlus)
@ -1714,6 +1428,9 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl,
}
New = NewVD;
}
if (New == 0)
return 0;
// Set the lexical context. If the declarator has a C++ scope specifier, the
// lexical context will be different from the semantic context.
@ -1729,6 +1446,304 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl,
return New;
}
ScopedDecl*
Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
QualType R, ScopedDecl *LastDeclarator,
Decl* PrevDecl, bool IsFunctionDefinition,
bool& InvalidDecl) {
assert(R.getTypePtr()->isFunctionType());
DeclarationName Name = GetNameForDeclarator(D);
FunctionDecl::StorageClass SC = FunctionDecl::None;
switch (D.getDeclSpec().getStorageClassSpec()) {
default: assert(0 && "Unknown storage class!");
case DeclSpec::SCS_auto:
case DeclSpec::SCS_register:
case DeclSpec::SCS_mutable:
Diag(D.getIdentifierLoc(), diag::err_typecheck_sclass_func);
InvalidDecl = true;
break;
case DeclSpec::SCS_unspecified: SC = FunctionDecl::None; break;
case DeclSpec::SCS_extern: SC = FunctionDecl::Extern; break;
case DeclSpec::SCS_static: SC = FunctionDecl::Static; break;
case DeclSpec::SCS_private_extern: SC = FunctionDecl::PrivateExtern;break;
}
bool isInline = D.getDeclSpec().isInlineSpecified();
// bool isVirtual = D.getDeclSpec().isVirtualSpecified();
bool isExplicit = D.getDeclSpec().isExplicitSpecified();
FunctionDecl *NewFD;
if (D.getKind() == Declarator::DK_Constructor) {
// This is a C++ constructor declaration.
assert(DC->isRecord() &&
"Constructors can only be declared in a member context");
InvalidDecl = InvalidDecl || CheckConstructorDeclarator(D, R, SC);
// Create the new declaration
NewFD = CXXConstructorDecl::Create(Context,
cast<CXXRecordDecl>(DC),
D.getIdentifierLoc(), Name, R,
isExplicit, isInline,
/*isImplicitlyDeclared=*/false);
if (InvalidDecl)
NewFD->setInvalidDecl();
} else if (D.getKind() == Declarator::DK_Destructor) {
// This is a C++ destructor declaration.
if (DC->isRecord()) {
InvalidDecl = InvalidDecl || CheckDestructorDeclarator(D, R, SC);
NewFD = CXXDestructorDecl::Create(Context,
cast<CXXRecordDecl>(DC),
D.getIdentifierLoc(), Name, R,
isInline,
/*isImplicitlyDeclared=*/false);
if (InvalidDecl)
NewFD->setInvalidDecl();
} 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.getIdentifierLoc(),
Name, R, SC, isInline, LastDeclarator,
// FIXME: Move to DeclGroup...
D.getDeclSpec().getSourceRange().getBegin());
InvalidDecl = true;
NewFD->setInvalidDecl();
}
} else if (D.getKind() == Declarator::DK_Conversion) {
if (!DC->isRecord()) {
Diag(D.getIdentifierLoc(),
diag::err_conv_function_not_member);
return 0;
} else {
InvalidDecl = InvalidDecl || CheckConversionDeclarator(D, R, SC);
NewFD = CXXConversionDecl::Create(Context, cast<CXXRecordDecl>(DC),
D.getIdentifierLoc(), Name, R,
isInline, isExplicit);
if (InvalidDecl)
NewFD->setInvalidDecl();
}
} else if (DC->isRecord()) {
// This is a C++ method declaration.
NewFD = CXXMethodDecl::Create(Context, cast<CXXRecordDecl>(DC),
D.getIdentifierLoc(), Name, R,
(SC == FunctionDecl::Static), isInline,
LastDeclarator);
} else {
NewFD = FunctionDecl::Create(Context, DC,
D.getIdentifierLoc(),
Name, R, SC, isInline, LastDeclarator,
// FIXME: Move to DeclGroup...
D.getDeclSpec().getSourceRange().getBegin());
}
// Set the lexical context. If the declarator has a C++
// scope specifier, the lexical context will be different
// from the semantic context.
NewFD->setLexicalDeclContext(CurContext);
// Handle GNU asm-label extension (encoded as an attribute).
if (Expr *E = (Expr*) D.getAsmLabel()) {
// The parser guarantees this is a string.
StringLiteral *SE = cast<StringLiteral>(E);
NewFD->addAttr(new AsmLabelAttr(std::string(SE->getStrData(),
SE->getByteLength())));
}
// Copy the parameter declarations from the declarator D to
// the function declaration NewFD, if they are available.
if (D.getNumTypeObjects() > 0) {
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.
// We let through "const void" here because Sema::GetTypeForDeclarator
// already checks for that case.
if (FTI.NumArgs == 1 && !FTI.isVariadic && FTI.ArgInfo[0].Ident == 0 &&
FTI.ArgInfo[0].Param &&
((ParmVarDecl*)FTI.ArgInfo[0].Param)->getType()->isVoidType()) {
// empty arg list, don't push any params.
ParmVarDecl *Param = (ParmVarDecl*)FTI.ArgInfo[0].Param;
// In C++, the empty parameter-type-list must be spelled "void"; a
// typedef of void is not permitted.
if (getLangOptions().CPlusPlus &&
Param->getType().getUnqualifiedType() != Context.VoidTy) {
Diag(Param->getLocation(), diag::ext_param_typedef_of_void);
}
} else if (FTI.NumArgs > 0 && FTI.ArgInfo[0].Param != 0) {
for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i)
Params.push_back((ParmVarDecl *)FTI.ArgInfo[i].Param);
}
NewFD->setParams(Context, &Params[0], Params.size());
} else if (R->getAsTypedefType()) {
// When we're declaring a function with a typedef, as in the
// following example, we'll need to synthesize (unnamed)
// parameters for use in the declaration.
//
// @code
// typedef void fn(int);
// fn f;
// @endcode
const FunctionTypeProto *FT = R->getAsFunctionTypeProto();
if (!FT) {
// This is a typedef of a function with no prototype, so we
// don't need to do anything.
} else if ((FT->getNumArgs() == 0) ||
(FT->getNumArgs() == 1 && !FT->isVariadic() &&
FT->getArgType(0)->isVoidType())) {
// This is a zero-argument function. We don't need to do anything.
} else {
// Synthesize a parameter for each argument type.
llvm::SmallVector<ParmVarDecl*, 16> Params;
for (FunctionTypeProto::arg_type_iterator ArgType = FT->arg_type_begin();
ArgType != FT->arg_type_end(); ++ArgType) {
Params.push_back(ParmVarDecl::Create(Context, DC,
SourceLocation(), 0,
*ArgType, VarDecl::None,
0, 0));
}
NewFD->setParams(Context, &Params[0], Params.size());
}
}
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(NewFD))
InvalidDecl = InvalidDecl || CheckConstructor(Constructor);
else if (isa<CXXDestructorDecl>(NewFD)) {
CXXRecordDecl *Record = cast<CXXRecordDecl>(NewFD->getParent());
Record->setUserDeclaredDestructor(true);
// C++ [class]p4: A POD-struct is an aggregate class that has [...] no
// user-defined destructor.
Record->setPOD(false);
} else if (CXXConversionDecl *Conversion =
dyn_cast<CXXConversionDecl>(NewFD))
ActOnConversionDeclarator(Conversion);
// Extra checking for C++ overloaded operators (C++ [over.oper]).
if (NewFD->isOverloadedOperator() &&
CheckOverloadedOperatorDeclaration(NewFD))
NewFD->setInvalidDecl();
// 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 &&
(!getLangOptions().CPlusPlus||isDeclInScope(PrevDecl, DC, S))) {
bool Redeclaration = false;
// If C++, determine whether NewFD is an overload of PrevDecl or
// a declaration that requires merging. If it's an overload,
// there's no more work to do here; we'll just add the new
// function to the scope.
OverloadedFunctionDecl::function_iterator MatchedDecl;
if (!getLangOptions().CPlusPlus ||
!IsOverload(NewFD, PrevDecl, MatchedDecl)) {
Decl *OldDecl = PrevDecl;
// If PrevDecl was an overloaded function, extract the
// FunctionDecl that matched.
if (isa<OverloadedFunctionDecl>(PrevDecl))
OldDecl = *MatchedDecl;
// NewFD and PrevDecl represent declarations that need to be
// merged.
NewFD = MergeFunctionDecl(NewFD, OldDecl, Redeclaration);
if (NewFD == 0) return 0;
if (Redeclaration) {
NewFD->setPreviousDeclaration(cast<FunctionDecl>(OldDecl));
// An out-of-line member function declaration must also be a
// definition (C++ [dcl.meaning]p1).
if (!IsFunctionDefinition && D.getCXXScopeSpec().isSet() &&
!InvalidDecl) {
Diag(NewFD->getLocation(), diag::err_out_of_line_declaration)
<< D.getCXXScopeSpec().getRange();
NewFD->setInvalidDecl();
}
}
}
if (!Redeclaration && D.getCXXScopeSpec().isSet()) {
// The user tried to provide an out-of-line definition for a
// member function, but there was no such member function
// declared (C++ [class.mfct]p2). For example:
//
// class X {
// void f() const;
// };
//
// void X::f() { } // ill-formed
//
// Complain about this problem, and attempt to suggest close
// matches (e.g., those that differ only in cv-qualifiers and
// whether the parameter types are references).
Diag(D.getIdentifierLoc(), diag::err_member_def_does_not_match)
<< cast<CXXRecordDecl>(DC)->getDeclName()
<< D.getCXXScopeSpec().getRange();
InvalidDecl = true;
PrevDecl = LookupDecl(Name, Decl::IDNS_Ordinary, S, DC);
if (!PrevDecl) {
// Nothing to suggest.
} else if (OverloadedFunctionDecl *Ovl
= dyn_cast<OverloadedFunctionDecl>(PrevDecl)) {
for (OverloadedFunctionDecl::function_iterator
Func = Ovl->function_begin(),
FuncEnd = Ovl->function_end();
Func != FuncEnd; ++Func) {
if (isNearlyMatchingMemberFunction(Context, *Func, NewFD))
Diag((*Func)->getLocation(), diag::note_member_def_close_match);
}
} else if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(PrevDecl)) {
// Suggest this no matter how mismatched it is; it's the only
// thing we have.
unsigned diag;
if (isNearlyMatchingMemberFunction(Context, Method, NewFD))
diag = diag::note_member_def_close_match;
else if (Method->getBody())
diag = diag::note_previous_definition;
else
diag = diag::note_previous_declaration;
Diag(Method->getLocation(), diag);
}
PrevDecl = 0;
}
}
// Handle attributes. We need to have merged decls when handling attributes
// (for example to check for conflicts, etc).
ProcessDeclAttributes(NewFD, D);
if (getLangOptions().CPlusPlus) {
// In C++, check default arguments now that we have merged decls.
CheckCXXDefaultArguments(NewFD);
// An out-of-line member function declaration must also be a
// definition (C++ [dcl.meaning]p1).
if (!IsFunctionDefinition && D.getCXXScopeSpec().isSet() && !InvalidDecl) {
Diag(NewFD->getLocation(), diag::err_out_of_line_declaration)
<< D.getCXXScopeSpec().getRange();
InvalidDecl = true;
}
}
return NewFD;
}
void Sema::InitializerElementNotConstant(const Expr *Init) {
Diag(Init->getExprLoc(), diag::err_init_element_not_constant)
<< Init->getSourceRange();