[cfe-commits] r62231 - in /cfe/trunk: include/clang/Basic/DiagnosticKinds.def lib/Sema/Sema.h lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaExprCXX.cpp lib/Sema/SemaInit.cpp lib/Sema/SemaOverload.cpp test/SemaCXX/condition.cpp www/cxx_status.html
Douglas Gregor
dgregor at apple.com
Wed Jan 14 07:45:32 PST 2009
Author: dgregor
Date: Wed Jan 14 09:45:31 2009
New Revision: 62231
URL: http://llvm.org/viewvc/llvm-project?rev=62231&view=rev
Log:
Introduce support for C++0x explicit conversion operators (N2437)
Small cleanup in the handling of user-defined conversions.
Also, implement an optimization when constructing a call. We avoid
recomputing implicit conversion sequences and instead use those
conversion sequences that we computed as part of overload resolution.
Modified:
cfe/trunk/include/clang/Basic/DiagnosticKinds.def
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/lib/Sema/SemaDeclCXX.cpp
cfe/trunk/lib/Sema/SemaExpr.cpp
cfe/trunk/lib/Sema/SemaExprCXX.cpp
cfe/trunk/lib/Sema/SemaInit.cpp
cfe/trunk/lib/Sema/SemaOverload.cpp
cfe/trunk/test/SemaCXX/condition.cpp
cfe/trunk/www/cxx_status.html
Modified: cfe/trunk/include/clang/Basic/DiagnosticKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticKinds.def?rev=62231&r1=62230&r2=62231&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticKinds.def (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticKinds.def Wed Jan 14 09:45:31 2009
@@ -1349,7 +1349,7 @@
DIAG(err_type_defined_in_condition, ERROR,
"types may not be defined in conditions")
DIAG(err_typecheck_bool_condition, ERROR,
- "expression must have bool type (or be convertible to bool) (%0 invalid)")
+ "value of type %0 is not contextually convertible to 'bool'")
DIAG(err_expected_class_or_namespace, ERROR,
"expected a class or namespace")
DIAG(err_invalid_declarator_scope, ERROR,
@@ -1582,6 +1582,10 @@
DIAG(warn_not_compound_assign, WARNING,
"use of unary operator that may be intended as compound assignment (%0=)")
+// C++0x explicit conversion operators
+DIAG(warn_explicit_conversion_functions, WARNING,
+ "explicit conversion functions are a C++0x extension")
+
// CHECK: printf format string errors
DIAG(warn_printf_not_string_constant, WARNING,
"format string is not a string literal (potentially insecure)")
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=62231&r1=62230&r2=62231&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Wed Jan 14 09:45:31 2009
@@ -281,7 +281,8 @@
virtual void ActOnParamUnparsedDefaultArgument(DeclTy *param,
SourceLocation EqualLoc);
virtual void ActOnParamDefaultArgumentError(DeclTy *param);
- void AddInitializerToDecl(DeclTy *dcl, ExprArg init);
+ virtual void AddInitializerToDecl(DeclTy *dcl, ExprArg init);
+ void AddInitializerToDecl(DeclTy *dcl, ExprArg init, bool DirectInit);
void ActOnUninitializedDecl(DeclTy *dcl);
virtual DeclTy *FinalizeDeclaratorGroup(Scope *S, DeclTy *Group);
@@ -390,7 +391,8 @@
OverloadedFunctionDecl::function_iterator &MatchedDecl);
ImplicitConversionSequence
TryImplicitConversion(Expr* From, QualType ToType,
- bool SuppressUserConversions = false);
+ bool SuppressUserConversions = false,
+ bool AllowExplicit = false);
bool IsStandardConversion(Expr *From, QualType ToType,
StandardConversionSequence& SCS);
bool IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType);
@@ -402,7 +404,8 @@
bool CheckPointerConversion(Expr *From, QualType ToType);
bool IsQualificationConversion(QualType FromType, QualType ToType);
bool IsUserDefinedConversion(Expr *From, QualType ToType,
- UserDefinedConversionSequence& User);
+ UserDefinedConversionSequence& User,
+ bool AllowExplicit = false);
ImplicitConversionSequence::CompareKind
CompareImplicitConversionSequences(const ImplicitConversionSequence& ICS1,
@@ -430,6 +433,9 @@
TryObjectArgumentInitialization(Expr *From, CXXMethodDecl *Method);
bool PerformObjectArgumentInitialization(Expr *&From, CXXMethodDecl *Method);
+ ImplicitConversionSequence TryContextuallyConvertToBool(Expr *From);
+ bool PerformContextuallyConvertToBool(Expr *&From);
+
/// OverloadingResult - Capture the result of performing overload
/// resolution.
enum OverloadingResult {
@@ -459,7 +465,8 @@
void AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
- bool IsAssignmentOperator = false);
+ bool IsAssignmentOperator = false,
+ unsigned NumContextualBoolArguments = 0);
void AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet);
@@ -497,7 +504,7 @@
ExprResult BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc,
SourceLocation MemberLoc,
IdentifierInfo &Member);
-
+
/// Helpers for dealing with function parameters.
bool CheckParmsForFunctionDef(FunctionDecl *FD);
void CheckCXXDefaultArguments(FunctionDecl *FD);
@@ -1360,6 +1367,9 @@
bool IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType);
bool PerformImplicitConversion(Expr *&From, QualType ToType,
+ const char *Flavor, bool AllowExplicit = false);
+ bool PerformImplicitConversion(Expr *&From, QualType ToType,
+ const ImplicitConversionSequence& ICS,
const char *Flavor);
bool PerformImplicitConversion(Expr *&From, QualType ToType,
const StandardConversionSequence& SCS,
@@ -1416,8 +1426,10 @@
/// type checking declaration initializers (C99 6.7.8)
friend class InitListChecker;
bool CheckInitializerTypes(Expr *&simpleInit_or_initList, QualType &declType,
- SourceLocation InitLoc,DeclarationName InitEntity);
- bool CheckSingleInitializer(Expr *&simpleInit, QualType declType);
+ SourceLocation InitLoc,DeclarationName InitEntity,
+ bool DirectInit);
+ bool CheckSingleInitializer(Expr *&simpleInit, QualType declType,
+ bool DirectInit);
bool CheckForConstantInitializer(Expr *e, QualType t);
bool CheckArithmeticConstantExpression(const Expr* e);
bool CheckAddressConstantExpression(const Expr* e);
@@ -1455,7 +1467,8 @@
bool CheckReferenceInit(Expr *&simpleInit_or_initList, QualType &declType,
ImplicitConversionSequence *ICS = 0,
- bool SuppressUserConversions = false);
+ bool SuppressUserConversions = false,
+ bool AllowExplicit = false);
/// CheckCastTypes - Check type constraints for casting between types.
bool CheckCastTypes(SourceRange TyRange, QualType CastTy, Expr *&CastExpr);
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=62231&r1=62230&r2=62231&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Wed Jan 14 09:45:31 2009
@@ -1120,13 +1120,22 @@
return Anon;
}
-bool Sema::CheckSingleInitializer(Expr *&Init, QualType DeclType) {
+bool Sema::CheckSingleInitializer(Expr *&Init, QualType DeclType,
+ bool DirectInit) {
// Get the type before calling CheckSingleAssignmentConstraints(), since
// it can promote the expression.
QualType InitType = Init->getType();
- if (getLangOptions().CPlusPlus)
- return PerformCopyInitialization(Init, DeclType, "initializing");
+ if (getLangOptions().CPlusPlus) {
+ // FIXME: I dislike this error message. A lot.
+ if (PerformImplicitConversion(Init, DeclType, "initializing", DirectInit))
+ return Diag(Init->getSourceRange().getBegin(),
+ diag::err_typecheck_convert_incompatible)
+ << DeclType << Init->getType() << "initializing"
+ << Init->getSourceRange();
+
+ return false;
+ }
AssignConvertType ConvTy = CheckSingleAssignmentConstraints(DeclType, Init);
return DiagnoseAssignmentResult(ConvTy, Init->getLocStart(), DeclType,
@@ -1169,7 +1178,8 @@
bool Sema::CheckInitializerTypes(Expr *&Init, QualType &DeclType,
SourceLocation InitLoc,
- DeclarationName InitEntity) {
+ DeclarationName InitEntity,
+ bool DirectInit) {
if (DeclType->isDependentType() || Init->isTypeDependent())
return false;
@@ -1178,7 +1188,7 @@
// (8.3.2), shall be initialized by an object, or function, of
// type T or by an object that can be converted into a T.
if (DeclType->isReferenceType())
- return CheckReferenceInit(Init, DeclType);
+ return CheckReferenceInit(Init, DeclType, 0, false, DirectInit);
// C99 6.7.8p3: The type of the entity to be initialized shall be an array
// of unknown size ("[]") or an object type that is not a variable array type.
@@ -1208,7 +1218,8 @@
CXXConstructorDecl *Constructor
= PerformInitializationByConstructor(DeclType, &Init, 1,
InitLoc, Init->getSourceRange(),
- InitEntity, IK_Copy);
+ InitEntity,
+ DirectInit? IK_Direct : IK_Copy);
return Constructor == 0;
}
@@ -1244,7 +1255,7 @@
return Diag(Init->getLocStart(), diag::err_array_init_list_required)
<< Init->getSourceRange();
- return CheckSingleInitializer(Init, DeclType);
+ return CheckSingleInitializer(Init, DeclType, DirectInit);
} else if (getLangOptions().CPlusPlus) {
// C++ [dcl.init]p14:
// [...] If the class is an aggregate (8.5.1), and the initializer
@@ -2366,6 +2377,13 @@
}
void Sema::AddInitializerToDecl(DeclTy *dcl, ExprArg init) {
+ AddInitializerToDecl(dcl, move(init), /*DirectInit=*/false);
+}
+
+/// AddInitializerToDecl - Adds the initializer Init to the
+/// declaration dcl. If DirectInit is true, this is C++ direct
+/// initialization rather than copy initialization.
+void Sema::AddInitializerToDecl(DeclTy *dcl, ExprArg init, bool DirectInit) {
Decl *RealDecl = static_cast<Decl *>(dcl);
Expr *Init = static_cast<Expr *>(init.release());
assert(Init && "missing initializer");
@@ -2394,7 +2412,7 @@
VDecl->setInvalidDecl();
} else if (!VDecl->isInvalidDecl()) {
if (CheckInitializerTypes(Init, DclT, VDecl->getLocation(),
- VDecl->getDeclName()))
+ VDecl->getDeclName(), DirectInit))
VDecl->setInvalidDecl();
// C++ 3.6.2p2, allow dynamic initialization of static initializers.
@@ -2408,7 +2426,7 @@
Diag(VDecl->getLocation(), diag::warn_extern_init);
if (!VDecl->isInvalidDecl())
if (CheckInitializerTypes(Init, DclT, VDecl->getLocation(),
- VDecl->getDeclName()))
+ VDecl->getDeclName(), DirectInit))
VDecl->setInvalidDecl();
// C++ 3.6.2p2, allow dynamic initialization of static initializers.
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=62231&r1=62230&r2=62231&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Wed Jan 14 09:45:31 2009
@@ -128,7 +128,8 @@
Expr *DefaultArgPtr = DefaultArg.get();
bool DefaultInitFailed = CheckInitializerTypes(DefaultArgPtr, ParamType,
EqualLoc,
- Param->getDeclName());
+ Param->getDeclName(),
+ /*DirectInit=*/false);
if (DefaultArgPtr != DefaultArg.get()) {
DefaultArg.take();
DefaultArg.reset(DefaultArgPtr);
@@ -1299,6 +1300,12 @@
R = Context.getFunctionType(ConvType, 0, 0, false,
R->getAsFunctionTypeProto()->getTypeQuals());
+ // C++0x explicit conversion operators.
+ if (D.getDeclSpec().isExplicitSpecified() && !getLangOptions().CPlusPlus0x)
+ Diag(D.getDeclSpec().getExplicitSpecLoc(),
+ diag::warn_explicit_conversion_functions)
+ << SourceRange(D.getDeclSpec().getExplicitSpecLoc());
+
return isInvalid;
}
@@ -1538,7 +1545,7 @@
assert(NumExprs == 1 && "Expected 1 expression");
// Set the init expression, handles conversions.
- AddInitializerToDecl(Dcl, ExprArg(*this, ExprTys[0]));
+ AddInitializerToDecl(Dcl, ExprArg(*this, ExprTys[0]), /*DirectInit=*/true);
}
/// PerformInitializationByConstructor - Perform initialization by
@@ -1677,10 +1684,13 @@
///
/// When @p SuppressUserConversions, user-defined conversions are
/// suppressed.
+/// When @p AllowExplicit, we also permit explicit user-defined
+/// conversion functions.
bool
Sema::CheckReferenceInit(Expr *&Init, QualType &DeclType,
ImplicitConversionSequence *ICS,
- bool SuppressUserConversions) {
+ bool SuppressUserConversions,
+ bool AllowExplicit) {
assert(DeclType->isReferenceType() && "Reference init needs a reference");
QualType T1 = DeclType->getAsReferenceType()->getPointeeType();
@@ -1780,7 +1790,8 @@
// If the conversion function doesn't return a reference type,
// it can't be considered for this conversion.
// FIXME: This will change when we support rvalue references.
- if (Conv->getConversionType()->isReferenceType())
+ if (Conv->getConversionType()->isReferenceType() &&
+ (AllowExplicit || !Conv->isExplicit()))
AddConversionCandidate(Conv, Init, DeclType, CandidateSet);
}
Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=62231&r1=62230&r2=62231&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Wed Jan 14 09:45:31 2009
@@ -1873,7 +1873,7 @@
}
if (CheckInitializerTypes(literalExpr, literalType, LParenLoc,
- DeclarationName()))
+ DeclarationName(), /*FIXME:DirectInit=*/false))
return true;
bool isFileScope = getCurFunctionOrMethodDecl() == 0;
@@ -3546,10 +3546,10 @@
// We matched a built-in operator. Convert the arguments, then
// break out so that we will build the appropriate built-in
// operator node.
- if (PerformCopyInitialization(lhs, Best->BuiltinTypes.ParamTypes[0],
- "passing") ||
- PerformCopyInitialization(rhs, Best->BuiltinTypes.ParamTypes[1],
- "passing"))
+ if (PerformImplicitConversion(lhs, Best->BuiltinTypes.ParamTypes[0],
+ Best->Conversions[0], "passing") ||
+ PerformImplicitConversion(rhs, Best->BuiltinTypes.ParamTypes[1],
+ Best->Conversions[1], "passing"))
return true;
break;
@@ -3644,8 +3644,8 @@
// We matched a built-in operator. Convert the arguments, then
// break out so that we will build the appropriate built-in
// operator node.
- if (PerformCopyInitialization(Input, Best->BuiltinTypes.ParamTypes[0],
- "passing"))
+ if (PerformImplicitConversion(Input, Best->BuiltinTypes.ParamTypes[0],
+ Best->Conversions[0], "passing"))
return true;
break;
Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=62231&r1=62230&r2=62231&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Wed Jan 14 09:45:31 2009
@@ -291,7 +291,8 @@
// Object is direct-initialized.
// FIXME: WHAT DeclarationName do we pass in here?
if (CheckInitializerTypes(ConsArgs[0], AllocType, StartLoc,
- DeclarationName() /*AllocType.getAsString()*/))
+ DeclarationName() /*AllocType.getAsString()*/,
+ /*DirectInit=*/true))
return true;
} else {
Diag(StartLoc, diag::err_builtin_direct_init_more_than_one_arg)
@@ -650,13 +651,7 @@
// The value of a condition that is an expression is the value of the
// expression, implicitly converted to bool.
//
- QualType Ty = CondExpr->getType(); // Save the type.
- AssignConvertType
- ConvTy = CheckSingleAssignmentConstraints(Context.BoolTy, CondExpr);
- if (ConvTy == Incompatible)
- return Diag(CondExpr->getLocStart(), diag::err_typecheck_bool_condition)
- << Ty << CondExpr->getSourceRange();
- return false;
+ return PerformContextuallyConvertToBool(CondExpr);
}
/// Helper function to determine whether this is the (deprecated) C++
@@ -694,12 +689,27 @@
/// expression From to the type ToType. Returns true if there was an
/// error, false otherwise. The expression From is replaced with the
/// converted expression. Flavor is the kind of conversion we're
-/// performing, used in the error message.
+/// performing, used in the error message. If @p AllowExplicit,
+/// explicit user-defined conversions are permitted.
bool
Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
- const char *Flavor)
+ const char *Flavor, bool AllowExplicit)
{
- ImplicitConversionSequence ICS = TryImplicitConversion(From, ToType);
+ ImplicitConversionSequence ICS = TryImplicitConversion(From, ToType, false,
+ AllowExplicit);
+ return PerformImplicitConversion(From, ToType, ICS, Flavor);
+}
+
+/// PerformImplicitConversion - Perform an implicit conversion of the
+/// expression From to the type ToType using the pre-computed implicit
+/// conversion sequence ICS. Returns true if there was an error, false
+/// otherwise. The expression From is replaced with the converted
+/// expression. Flavor is the kind of conversion we're performing,
+/// used in the error message.
+bool
+Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
+ const ImplicitConversionSequence &ICS,
+ const char* Flavor) {
switch (ICS.ConversionKind) {
case ImplicitConversionSequence::StandardConversion:
if (PerformImplicitConversion(From, ToType, ICS.Standard, Flavor))
@@ -710,7 +720,8 @@
// FIXME: This is, of course, wrong. We'll need to actually call
// the constructor or conversion operator, and then cope with the
// standard conversions.
- ImpCastExprToType(From, ToType);
+ ImpCastExprToType(From, ToType.getNonReferenceType(),
+ ToType->isReferenceType());
return false;
case ImplicitConversionSequence::EllipsisConversion:
@@ -734,8 +745,7 @@
bool
Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
const StandardConversionSequence& SCS,
- const char *Flavor)
-{
+ const char *Flavor) {
// Overall FIXME: we are recomputing too many types here and doing
// far too much extra work. What this means is that we need to keep
// track of more information that is computed when we try the
Modified: cfe/trunk/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=62231&r1=62230&r2=62231&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Wed Jan 14 09:45:31 2009
@@ -193,7 +193,7 @@
return;
}
Expr *savExpr = expr; // Might be promoted by CheckSingleInitializer.
- if (SemaRef->CheckSingleInitializer(expr, DeclType))
+ if (SemaRef->CheckSingleInitializer(expr, DeclType, false))
hadError = true; // types weren't compatible.
else if (savExpr != expr)
// The type was promoted, update initializer list.
Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=62231&r1=62230&r2=62231&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Wed Jan 14 09:45:31 2009
@@ -361,15 +361,18 @@
///
/// If @p SuppressUserConversions, then user-defined conversions are
/// not permitted.
+/// If @p AllowExplicit, then explicit user-defined conversions are
+/// permitted.
ImplicitConversionSequence
Sema::TryImplicitConversion(Expr* From, QualType ToType,
- bool SuppressUserConversions)
+ bool SuppressUserConversions,
+ bool AllowExplict)
{
ImplicitConversionSequence ICS;
if (IsStandardConversion(From, ToType, ICS.Standard))
ICS.ConversionKind = ImplicitConversionSequence::StandardConversion;
else if (!SuppressUserConversions &&
- IsUserDefinedConversion(From, ToType, ICS.UserDefined)) {
+ IsUserDefinedConversion(From, ToType, ICS.UserDefined, AllowExplict)) {
ICS.ConversionKind = ImplicitConversionSequence::UserDefinedConversion;
// C++ [over.ics.user]p4:
// A conversion of an expression of class type to the same class
@@ -1097,9 +1100,12 @@
/// exists, User will contain the user-defined conversion sequence
/// that performs such a conversion and this routine will return
/// true. Otherwise, this routine returns false and User is
-/// unspecified.
+/// unspecified. AllowExplicit is true if the conversion should
+/// consider C++0x "explicit" conversion functions as well as
+/// non-explicit conversion functions (C++0x [class.conv.fct]p2).
bool Sema::IsUserDefinedConversion(Expr *From, QualType ToType,
- UserDefinedConversionSequence& User)
+ UserDefinedConversionSequence& User,
+ bool AllowExplicit)
{
OverloadCandidateSet CandidateSet;
if (const CXXRecordType *ToRecordType
@@ -1137,7 +1143,8 @@
= Conversions->function_begin();
Func != Conversions->function_end(); ++Func) {
CXXConversionDecl *Conv = cast<CXXConversionDecl>(*Func);
- AddConversionCandidate(Conv, From, ToType, CandidateSet);
+ if (AllowExplicit || !Conv->isExplicit())
+ AddConversionCandidate(Conv, From, ToType, CandidateSet);
}
}
@@ -1748,6 +1755,24 @@
return false;
}
+/// TryContextuallyConvertToBool - Attempt to contextually convert the
+/// expression From to bool (C++0x [conv]p3).
+ImplicitConversionSequence Sema::TryContextuallyConvertToBool(Expr *From) {
+ return TryImplicitConversion(From, Context.BoolTy, false, true);
+}
+
+/// PerformContextuallyConvertToBool - Perform a contextual conversion
+/// of the expression From to bool (C++0x [conv]p3).
+bool Sema::PerformContextuallyConvertToBool(Expr *&From) {
+ ImplicitConversionSequence ICS = TryContextuallyConvertToBool(From);
+ if (!PerformImplicitConversion(From, Context.BoolTy, ICS, "converting"))
+ return false;
+
+ return Diag(From->getSourceRange().getBegin(),
+ diag::err_typecheck_bool_condition)
+ << From->getType() << From->getSourceRange();
+}
+
/// AddOverloadCandidate - Adds the given function to the set of
/// candidate functions, using the given function call arguments. If
/// @p SuppressUserConversions, then don't allow user-defined
@@ -2201,11 +2226,14 @@
/// of the built-in candidate, respectively. Args and NumArgs are the
/// arguments being passed to the candidate. IsAssignmentOperator
/// should be true when this built-in candidate is an assignment
-/// operator.
+/// operator. NumContextualBoolArguments is the number of arguments
+/// (at the beginning of the argument list) that will be contextually
+/// converted to bool.
void Sema::AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
- bool IsAssignmentOperator) {
+ bool IsAssignmentOperator,
+ unsigned NumContextualBoolArguments) {
// Add this candidate
CandidateSet.push_back(OverloadCandidate());
OverloadCandidate& Candidate = CandidateSet.back();
@@ -2233,9 +2261,15 @@
// conversions, since that is the only way that initialization of
// a reference to a non-class type can occur from something that
// is not of the same type.
- Candidate.Conversions[ArgIdx]
- = TryCopyInitialization(Args[ArgIdx], ParamTys[ArgIdx],
- ArgIdx == 0 && IsAssignmentOperator);
+ if (ArgIdx < NumContextualBoolArguments) {
+ assert(ParamTys[ArgIdx] == Context.BoolTy &&
+ "Contextual conversion to bool requires bool type");
+ Candidate.Conversions[ArgIdx] = TryContextuallyConvertToBool(Args[ArgIdx]);
+ } else {
+ Candidate.Conversions[ArgIdx]
+ = TryCopyInitialization(Args[ArgIdx], ParamTys[ArgIdx],
+ ArgIdx == 0 && IsAssignmentOperator);
+ }
if (Candidate.Conversions[ArgIdx].ConversionKind
== ImplicitConversionSequence::BadConversion) {
Candidate.Viable = false;
@@ -2309,7 +2343,8 @@
BuiltinCandidateTypeSet(ASTContext &Context) : Context(Context) { }
- void AddTypesConvertedFrom(QualType Ty, bool AllowUserConversions = true);
+ void AddTypesConvertedFrom(QualType Ty, bool AllowUserConversions,
+ bool AllowExplicitConversions);
/// pointer_begin - First pointer type found;
iterator pointer_begin() { return PointerTypes.begin(); }
@@ -2358,9 +2393,15 @@
/// AddTypesConvertedFrom - Add each of the types to which the type @p
/// Ty can be implicit converted to the given set of @p Types. We're
-/// primarily interested in pointer types, enumeration types,
-void BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty,
- bool AllowUserConversions) {
+/// primarily interested in pointer types and enumeration types.
+/// AllowUserConversions is true if we should look at the conversion
+/// functions of a class type, and AllowExplicitConversions if we
+/// should also include the explicit conversion functions of a class
+/// type.
+void
+BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty,
+ bool AllowUserConversions,
+ bool AllowExplicitConversions) {
// Only deal with canonical types.
Ty = Context.getCanonicalType(Ty);
@@ -2399,7 +2440,7 @@
// Add the pointer type, recursively, so that we get all of
// the indirect base classes, too.
- AddTypesConvertedFrom(Context.getPointerType(BaseTy), false);
+ AddTypesConvertedFrom(Context.getPointerType(BaseTy), false, false);
}
}
} else if (Ty->isEnumeralType()) {
@@ -2414,7 +2455,8 @@
= Conversions->function_begin();
Func != Conversions->function_end(); ++Func) {
CXXConversionDecl *Conv = cast<CXXConversionDecl>(*Func);
- AddTypesConvertedFrom(Conv->getConversionType(), false);
+ if (AllowExplicitConversions || !Conv->isExplicit())
+ AddTypesConvertedFrom(Conv->getConversionType(), false, false);
}
}
}
@@ -2461,7 +2503,11 @@
Op == OO_ArrowStar || Op == OO_PlusPlus || Op == OO_MinusMinus ||
(Op == OO_Star && NumArgs == 1)) {
for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx)
- CandidateTypes.AddTypesConvertedFrom(Args[ArgIdx]->getType());
+ CandidateTypes.AddTypesConvertedFrom(Args[ArgIdx]->getType(),
+ true,
+ (Op == OO_Exclaim ||
+ Op == OO_AmpAmp ||
+ Op == OO_PipePipe));
}
bool isComparison = false;
@@ -2811,14 +2857,14 @@
ParamTypes[0] = Context.getReferenceType(*Enum);
ParamTypes[1] = *Enum;
AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet,
- /*IsAssignmentOperator=*/true);
+ /*IsAssignmentOperator=*/false);
if (!Context.getCanonicalType(*Enum).isVolatileQualified()) {
// volatile T& operator=(volatile T&, T)
ParamTypes[0] = Context.getReferenceType((*Enum).withVolatile());
ParamTypes[1] = *Enum;
AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet,
- /*IsAssignmentOperator=*/true);
+ /*IsAssignmentOperator=*/false);
}
}
// Fall through.
@@ -2919,8 +2965,6 @@
ParamTypes[1] = ArithmeticTypes[Right];
// Add this built-in operator as a candidate (VQ is empty).
- // FIXME: We should be caching these declarations somewhere,
- // rather than re-building them every time.
ParamTypes[0] = Context.getReferenceType(ArithmeticTypes[Left]);
AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet);
@@ -2942,7 +2986,9 @@
// bool operator&&(bool, bool); [BELOW]
// bool operator||(bool, bool); [BELOW]
QualType ParamTy = Context.BoolTy;
- AddBuiltinCandidate(ParamTy, &ParamTy, Args, 1, CandidateSet);
+ AddBuiltinCandidate(ParamTy, &ParamTy, Args, 1, CandidateSet,
+ /*IsAssignmentOperator=*/false,
+ /*NumContextualBoolArguments=*/1);
break;
}
@@ -2956,7 +3002,9 @@
// bool operator&&(bool, bool);
// bool operator||(bool, bool);
QualType ParamTypes[2] = { Context.BoolTy, Context.BoolTy };
- AddBuiltinCandidate(Context.BoolTy, ParamTypes, Args, 2, CandidateSet);
+ AddBuiltinCandidate(Context.BoolTy, ParamTypes, Args, 2, CandidateSet,
+ /*IsAssignmentOperator=*/false,
+ /*NumContextualBoolArguments=*/2);
break;
}
Modified: cfe/trunk/test/SemaCXX/condition.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/condition.cpp?rev=62231&r1=62230&r2=62231&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/condition.cpp (original)
+++ cfe/trunk/test/SemaCXX/condition.cpp Wed Jan 14 09:45:31 2009
@@ -10,14 +10,14 @@
while (int f()=0) ; // expected-error {{a function type is not allowed here}}
struct S {} s;
- if (s) ++x; // expected-error {{expression must have bool type (or be convertible to bool) ('struct S' invalid)}}
- while (struct S x=s) ; // expected-error {{expression must have bool type (or be convertible to bool) ('struct S' invalid)}}
- do ; while (s); // expected-error {{expression must have bool type (or be convertible to bool) ('struct S' invalid)}}
- for (;s;) ; // expected-error {{expression must have bool type (or be convertible to bool) ('struct S' invalid)}}
+ if (s) ++x; // expected-error {{value of type 'struct S' is not contextually convertible to 'bool'}}
+ while (struct S x=s) ; // expected-error {{value of type 'struct S' is not contextually convertible to 'bool'}}
+ do ; while (s); // expected-error {{value of type 'struct S' is not contextually convertible to 'bool'}}
+ for (;s;) ; // expected-error {{value of type 'struct S' is not contextually convertible to 'bool'}}
switch (s) {} // expected-error {{statement requires expression of integer type ('struct S' invalid)}}
- while (struct S {} x=0) ; // expected-error {{types may not be defined in conditions}} expected-error {{cannot initialize 'x' with an rvalue of type 'int'}} expected-error {{expression must have bool type}}
- while (struct {} x=0) ; // expected-error {{types may not be defined in conditions}} expected-error {{cannot initialize 'x' with an rvalue of type 'int'}} expected-error {{expression must have bool type}}
+ while (struct S {} x=0) ; // expected-error {{types may not be defined in conditions}} expected-error {{cannot initialize 'x' with an rvalue of type 'int'}} expected-error {{value of type 'struct S' is not contextually convertible to 'bool'}}
+ while (struct {} x=0) ; // expected-error {{types may not be defined in conditions}} expected-error {{cannot initialize 'x' with an rvalue of type 'int'}} expected-error {{value of type 'struct <anonymous>' is not contextually convertible to 'bool'}}
switch (enum {E} x=0) ; // expected-error {{types may not be defined in conditions}} expected-error {{incompatible type}}
if (int x=0) { // expected-note {{previous definition is here}}
Modified: cfe/trunk/www/cxx_status.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_status.html?rev=62231&r1=62230&r2=62231&view=diff
==============================================================================
--- cfe/trunk/www/cxx_status.html (original)
+++ cfe/trunk/www/cxx_status.html Wed Jan 14 09:45:31 2009
@@ -1541,6 +1541,17 @@
<tr><td> D.4 [depr.string]</td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><td> D.5 [depr.c.headers]</td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><td>E [extendid]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr>
+ <td colspan="6" align="center" bgcolor="#ffffcc">C++0x Features</td>
+ <tr>
+ <td>Explicit conversion operators (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2437.pdf">N2437</a>)</td>
+ <td class="complete" align="center">✓</td>
+ <td class="medium" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td class="broken"></td>
+ <td>No name mangling; ASTs don't contain calls to conversion operators</td>
+</tr>
+
</table>
</div>
More information about the cfe-commits
mailing list