Diagnose declarations of conversion functions with declarators other than '()'.

llvm-svn: 101098
This commit is contained in:
John McCall 2010-04-13 00:04:31 +00:00
parent 5dbefc6697
commit 212fa2efb7
3 changed files with 39 additions and 14 deletions

View File

@ -2637,6 +2637,8 @@ def err_conv_function_to_array : Error<
"conversion function cannot convert to an array type">; "conversion function cannot convert to an array type">;
def err_conv_function_to_function : Error< def err_conv_function_to_function : Error<
"conversion function cannot convert to a function type">; "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< def err_conv_function_redeclared : Error<
"conversion function cannot be redeclared">; "conversion function cannot be redeclared">;
def warn_conv_to_self_not_used : Warning< def warn_conv_to_self_not_used : Warning<

View File

@ -2828,6 +2828,9 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R,
D.setInvalidType(); D.setInvalidType();
SC = FunctionDecl::None; SC = FunctionDecl::None;
} }
QualType ConvType = GetTypeFromParser(D.getName().ConversionFunctionId);
if (D.getDeclSpec().hasTypeSpecifier() && !D.isInvalidType()) { if (D.getDeclSpec().hasTypeSpecifier() && !D.isInvalidType()) {
// Conversion functions don't have return types, but the parser will // Conversion functions don't have return types, but the parser will
// happily parse something like: // happily parse something like:
@ -2840,27 +2843,35 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R,
Diag(D.getIdentifierLoc(), diag::err_conv_function_return_type) Diag(D.getIdentifierLoc(), diag::err_conv_function_return_type)
<< SourceRange(D.getDeclSpec().getTypeSpecTypeLoc()) << SourceRange(D.getDeclSpec().getTypeSpecTypeLoc())
<< SourceRange(D.getIdentifierLoc()); << SourceRange(D.getIdentifierLoc());
D.setInvalidType();
} }
const FunctionProtoType *Proto = R->getAs<FunctionProtoType>();
// Make sure we don't have any parameters. // Make sure we don't have any parameters.
if (R->getAs<FunctionProtoType>()->getNumArgs() > 0) { if (Proto->getNumArgs() > 0) {
Diag(D.getIdentifierLoc(), diag::err_conv_function_with_params); Diag(D.getIdentifierLoc(), diag::err_conv_function_with_params);
// Delete the parameters. // Delete the parameters.
D.getTypeObject(0).Fun.freeArgs(); D.getTypeObject(0).Fun.freeArgs();
D.setInvalidType(); D.setInvalidType();
} } else if (Proto->isVariadic()) {
// Make sure the conversion function isn't variadic.
if (R->getAs<FunctionProtoType>()->isVariadic() && !D.isInvalidType()) {
Diag(D.getIdentifierLoc(), diag::err_conv_function_variadic); Diag(D.getIdentifierLoc(), diag::err_conv_function_variadic);
D.setInvalidType(); 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: // C++ [class.conv.fct]p4:
// The conversion-type-id shall not represent a function type nor // The conversion-type-id shall not represent a function type nor
// an array type. // an array type.
QualType ConvType = GetTypeFromParser(D.getName().ConversionFunctionId);
if (ConvType->isArrayType()) { if (ConvType->isArrayType()) {
Diag(D.getIdentifierLoc(), diag::err_conv_function_to_array); Diag(D.getIdentifierLoc(), diag::err_conv_function_to_array);
ConvType = Context.getPointerType(ConvType); ConvType = Context.getPointerType(ConvType);
@ -2874,7 +2885,7 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R,
// Rebuild the function type "R" without any parameters (in case any // Rebuild the function type "R" without any parameters (in case any
// of the errors above fired) and with the conversion type as the // of the errors above fired) and with the conversion type as the
// return type. // return type.
const FunctionProtoType *Proto = R->getAs<FunctionProtoType>(); if (D.isInvalidType()) {
R = Context.getFunctionType(ConvType, 0, 0, false, R = Context.getFunctionType(ConvType, 0, 0, false,
Proto->getTypeQuals(), Proto->getTypeQuals(),
Proto->hasExceptionSpec(), Proto->hasExceptionSpec(),
@ -2882,6 +2893,7 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R,
Proto->getNumExceptions(), Proto->getNumExceptions(),
Proto->exception_begin(), Proto->exception_begin(),
Proto->getExtInfo()); Proto->getExtInfo());
}
// C++0x explicit conversion operators. // C++0x explicit conversion operators.
if (D.getDeclSpec().isExplicitSpecified() && !getLangOptions().CPlusPlus0x) if (D.getDeclSpec().isExplicitSpecified() && !getLangOptions().CPlusPlus0x)

View File

@ -165,3 +165,14 @@ namespace source_locations {
E2<int&> e2i; // expected-note{{in instantiation}} E2<int&> 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 *'}}
};
}