Add support for out-of-line definitions of conversion functions and member operators

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@61442 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Douglas Gregor 2008-12-26 15:00:45 +00:00
Родитель 4bcd44d3b3
Коммит 70316a065b
4 изменённых файлов: 51 добавлений и 39 удалений

Просмотреть файл

@ -1514,7 +1514,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
// If this identifier is followed by a '<', we may have a template-id. // If this identifier is followed by a '<', we may have a template-id.
DeclTy *Template; DeclTy *Template;
if (getLang().CPlusPlus && NextToken().is(tok::less) && if (NextToken().is(tok::less) &&
(Template = Actions.isTemplateName(*Tok.getIdentifierInfo(), (Template = Actions.isTemplateName(*Tok.getIdentifierInfo(),
CurScope))) { CurScope))) {
IdentifierInfo *II = Tok.getIdentifierInfo(); IdentifierInfo *II = Tok.getIdentifierInfo();
@ -1525,8 +1525,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
} }
// If this identifier is the name of the current class, it's a // If this identifier is the name of the current class, it's a
// constructor name. // constructor name.
else if (getLang().CPlusPlus && else if (Actions.isCurrentClassName(*Tok.getIdentifierInfo(), CurScope))
Actions.isCurrentClassName(*Tok.getIdentifierInfo(), CurScope))
D.setConstructor(Actions.isTypeName(*Tok.getIdentifierInfo(), D.setConstructor(Actions.isTypeName(*Tok.getIdentifierInfo(),
CurScope), CurScope),
Tok.getLocation()); Tok.getLocation());
@ -1535,9 +1534,21 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
D.SetIdentifier(Tok.getIdentifierInfo(), Tok.getLocation()); D.SetIdentifier(Tok.getIdentifierInfo(), Tok.getLocation());
ConsumeToken(); ConsumeToken();
goto PastIdentifier; goto PastIdentifier;
} } else if (Tok.is(tok::kw_operator)) {
SourceLocation OperatorLoc = Tok.getLocation();
if (Tok.is(tok::tilde)) { // First try the name of an overloaded operator
if (OverloadedOperatorKind Op = TryParseOperatorFunctionId()) {
D.setOverloadedOperator(Op, OperatorLoc);
} else {
// This must be a conversion function (C++ [class.conv.fct]).
if (TypeTy *ConvType = ParseConversionFunctionId())
D.setConversionFunction(ConvType, OperatorLoc);
else
D.SetIdentifier(0, Tok.getLocation());
}
goto PastIdentifier;
} else if (Tok.is(tok::tilde)) {
// This should be a C++ destructor. // This should be a C++ destructor.
SourceLocation TildeLoc = ConsumeToken(); SourceLocation TildeLoc = ConsumeToken();
if (Tok.is(tok::identifier)) { if (Tok.is(tok::identifier)) {
@ -1561,22 +1572,6 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
goto PastIdentifier; goto PastIdentifier;
} }
} }
if (Tok.is(tok::kw_operator)) {
SourceLocation OperatorLoc = Tok.getLocation();
// First try the name of an overloaded operator
if (OverloadedOperatorKind Op = TryParseOperatorFunctionId()) {
D.setOverloadedOperator(Op, OperatorLoc);
} else {
// This must be a conversion function (C++ [class.conv.fct]).
if (TypeTy *ConvType = ParseConversionFunctionId())
D.setConversionFunction(ConvType, OperatorLoc);
else
D.SetIdentifier(0, Tok.getLocation());
}
goto PastIdentifier;
}
} }
// If we reached this point, we are either in C/ObjC or the token didn't // If we reached this point, we are either in C/ObjC or the token didn't

Просмотреть файл

@ -1186,8 +1186,7 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl,
} else { } else {
InvalidDecl = InvalidDecl || CheckConversionDeclarator(D, R, SC); InvalidDecl = InvalidDecl || CheckConversionDeclarator(D, R, SC);
NewFD = CXXConversionDecl::Create(Context, NewFD = CXXConversionDecl::Create(Context, cast<CXXRecordDecl>(DC),
cast<CXXRecordDecl>(DC),
D.getIdentifierLoc(), Name, R, D.getIdentifierLoc(), Name, R,
isInline, isExplicit); isInline, isExplicit);

Просмотреть файл

@ -1230,21 +1230,6 @@ Sema::DeclTy *Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) {
// Make sure we aren't redeclaring the conversion function. // Make sure we aren't redeclaring the conversion function.
QualType ConvType = Context.getCanonicalType(Conversion->getConversionType()); QualType ConvType = Context.getCanonicalType(Conversion->getConversionType());
OverloadedFunctionDecl *Conversions = ClassDecl->getConversionFunctions();
for (OverloadedFunctionDecl::function_iterator Func
= Conversions->function_begin();
Func != Conversions->function_end(); ++Func) {
CXXConversionDecl *OtherConv = cast<CXXConversionDecl>(*Func);
if (ConvType == Context.getCanonicalType(OtherConv->getConversionType())) {
Diag(Conversion->getLocation(), diag::err_conv_function_redeclared);
Diag(OtherConv->getLocation(),
OtherConv->isThisDeclarationADefinition()?
diag::note_previous_definition
: diag::note_previous_declaration);
Conversion->setInvalidDecl();
return (DeclTy *)Conversion;
}
}
// C++ [class.conv.fct]p1: // C++ [class.conv.fct]p1:
// [...] A conversion function is never used to convert a // [...] A conversion function is never used to convert a
@ -1272,6 +1257,19 @@ Sema::DeclTy *Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) {
<< ClassType << ConvType; << ClassType << ConvType;
} }
if (Conversion->getPreviousDeclaration()) {
OverloadedFunctionDecl *Conversions = ClassDecl->getConversionFunctions();
for (OverloadedFunctionDecl::function_iterator
Conv = Conversions->function_begin(),
ConvEnd = Conversions->function_end();
Conv != ConvEnd; ++Conv) {
if (*Conv == Conversion->getPreviousDeclaration()) {
*Conv = Conversion;
return (DeclTy *)Conversion;
}
}
assert(Conversion->isInvalidDecl() && "Conversion should not get here.");
} else
ClassDecl->addConversionFunction(Context, Conversion); ClassDecl->addConversionFunction(Context, Conversion);
return (DeclTy *)Conversion; return (DeclTy *)Conversion;

Просмотреть файл

@ -103,3 +103,23 @@ namespace E {
} }
} }
} }
class Operators {
Operators operator+(const Operators&) const; // expected-note{{member declaration nearly matches}}
operator bool();
};
Operators Operators::operator+(const Operators&) { // expected-error{{out-of-line definition does not match any declaration in 'Operators'}}
Operators ops;
return ops;
}
Operators Operators::operator+(const Operators&) const {
Operators ops;
return ops;
}
Operators::operator bool() {
return true;
}