diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index aa24e395f04a..a09f18c5d973 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -2637,6 +2637,8 @@ def err_conv_function_to_array : Error< "conversion function cannot convert to an array type">; def err_conv_function_to_function : Error< "conversion function cannot convert to a function type">; +def err_conv_function_with_complex_decl : Error< + "must use a typedef to declare a conversion to %0">; def err_conv_function_redeclared : Error< "conversion function cannot be redeclared">; def warn_conv_to_self_not_used : Warning< diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index d83297805471..b1aa2e879a9f 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -2828,6 +2828,9 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R, D.setInvalidType(); SC = FunctionDecl::None; } + + QualType ConvType = GetTypeFromParser(D.getName().ConversionFunctionId); + if (D.getDeclSpec().hasTypeSpecifier() && !D.isInvalidType()) { // Conversion functions don't have return types, but the parser will // happily parse something like: @@ -2840,27 +2843,35 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R, Diag(D.getIdentifierLoc(), diag::err_conv_function_return_type) << SourceRange(D.getDeclSpec().getTypeSpecTypeLoc()) << SourceRange(D.getIdentifierLoc()); + D.setInvalidType(); } + const FunctionProtoType *Proto = R->getAs(); + // Make sure we don't have any parameters. - if (R->getAs()->getNumArgs() > 0) { + if (Proto->getNumArgs() > 0) { Diag(D.getIdentifierLoc(), diag::err_conv_function_with_params); // Delete the parameters. D.getTypeObject(0).Fun.freeArgs(); D.setInvalidType(); - } - - // Make sure the conversion function isn't variadic. - if (R->getAs()->isVariadic() && !D.isInvalidType()) { + } else if (Proto->isVariadic()) { Diag(D.getIdentifierLoc(), diag::err_conv_function_variadic); D.setInvalidType(); } + // Diagnose "&operator bool()" and other such nonsense. This + // is actually a gcc extension which we don't support. + if (Proto->getResultType() != ConvType) { + Diag(D.getIdentifierLoc(), diag::err_conv_function_with_complex_decl) + << Proto->getResultType(); + D.setInvalidType(); + ConvType = Proto->getResultType(); + } + // C++ [class.conv.fct]p4: // The conversion-type-id shall not represent a function type nor // an array type. - QualType ConvType = GetTypeFromParser(D.getName().ConversionFunctionId); if (ConvType->isArrayType()) { Diag(D.getIdentifierLoc(), diag::err_conv_function_to_array); ConvType = Context.getPointerType(ConvType); @@ -2874,14 +2885,15 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R, // Rebuild the function type "R" without any parameters (in case any // of the errors above fired) and with the conversion type as the // return type. - const FunctionProtoType *Proto = R->getAs(); - R = Context.getFunctionType(ConvType, 0, 0, false, - Proto->getTypeQuals(), - Proto->hasExceptionSpec(), - Proto->hasAnyExceptionSpec(), - Proto->getNumExceptions(), - Proto->exception_begin(), - Proto->getExtInfo()); + if (D.isInvalidType()) { + R = Context.getFunctionType(ConvType, 0, 0, false, + Proto->getTypeQuals(), + Proto->hasExceptionSpec(), + Proto->hasAnyExceptionSpec(), + Proto->getNumExceptions(), + Proto->exception_begin(), + Proto->getExtInfo()); + } // C++0x explicit conversion operators. if (D.getDeclSpec().isExplicitSpecified() && !getLangOptions().CPlusPlus0x) diff --git a/clang/test/SemaCXX/conversion-function.cpp b/clang/test/SemaCXX/conversion-function.cpp index 381cd60d40aa..972409ca5a3d 100644 --- a/clang/test/SemaCXX/conversion-function.cpp +++ b/clang/test/SemaCXX/conversion-function.cpp @@ -165,3 +165,14 @@ namespace source_locations { E2 e2i; // expected-note{{in instantiation}} } + +namespace crazy_declarators { + struct A { + (&operator bool())(); // expected-error {{must use a typedef to declare a conversion to 'bool (&)()'}} + + // FIXME: This diagnostic is misleading (the correct spelling + // would be 'operator int*'), but it's a corner case of a + // rarely-used syntax extension. + *operator int(); // expected-error {{must use a typedef to declare a conversion to 'int *'}} + }; +}