From: Douglas Gregor Date: Fri, 26 Dec 2008 15:00:45 +0000 (+0000) Subject: Add support for out-of-line definitions of conversion functions and member operators X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=70316a065bcf11c88143e22c88d530ebd320832f;p=clang 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 --- diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index e3fd6961bf..23c0c61517 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -1514,7 +1514,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) { // If this identifier is followed by a '<', we may have a template-id. DeclTy *Template; - if (getLang().CPlusPlus && NextToken().is(tok::less) && + if (NextToken().is(tok::less) && (Template = Actions.isTemplateName(*Tok.getIdentifierInfo(), CurScope))) { 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 // constructor name. - else if (getLang().CPlusPlus && - Actions.isCurrentClassName(*Tok.getIdentifierInfo(), CurScope)) + else if (Actions.isCurrentClassName(*Tok.getIdentifierInfo(), CurScope)) D.setConstructor(Actions.isTypeName(*Tok.getIdentifierInfo(), CurScope), Tok.getLocation()); @@ -1535,9 +1534,21 @@ void Parser::ParseDirectDeclarator(Declarator &D) { D.SetIdentifier(Tok.getIdentifierInfo(), Tok.getLocation()); ConsumeToken(); 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. SourceLocation TildeLoc = ConsumeToken(); if (Tok.is(tok::identifier)) { @@ -1561,22 +1572,6 @@ void Parser::ParseDirectDeclarator(Declarator &D) { 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 diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index bb0dd4d07c..1f6cbc4f32 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -1186,8 +1186,7 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl, } else { InvalidDecl = InvalidDecl || CheckConversionDeclarator(D, R, SC); - NewFD = CXXConversionDecl::Create(Context, - cast(DC), + NewFD = CXXConversionDecl::Create(Context, cast(DC), D.getIdentifierLoc(), Name, R, isInline, isExplicit); diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 48373369bc..5ba2850a3f 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -1230,21 +1230,6 @@ Sema::DeclTy *Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) { // Make sure we aren't redeclaring the conversion function. 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(*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: // [...] A conversion function is never used to convert a @@ -1272,7 +1257,20 @@ Sema::DeclTy *Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) { << ClassType << ConvType; } - ClassDecl->addConversionFunction(Context, Conversion); + 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); return (DeclTy *)Conversion; } diff --git a/test/SemaCXX/nested-name-spec.cpp b/test/SemaCXX/nested-name-spec.cpp index 7422066247..b48207345a 100644 --- a/test/SemaCXX/nested-name-spec.cpp +++ b/test/SemaCXX/nested-name-spec.cpp @@ -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; +}