mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-12-13 19:24:21 +00:00
Initial, partially-baked support for implicit user-defined conversions by conversion functions
llvm-svn: 58870
This commit is contained in:
parent
8467e2459a
commit
a1f013e8ed
@ -417,6 +417,9 @@ private:
|
|||||||
Expr **Args, unsigned NumArgs,
|
Expr **Args, unsigned NumArgs,
|
||||||
OverloadCandidateSet& CandidateSet,
|
OverloadCandidateSet& CandidateSet,
|
||||||
bool SuppressUserConversions = false);
|
bool SuppressUserConversions = false);
|
||||||
|
void AddConversionCandidate(CXXConversionDecl *Conversion,
|
||||||
|
Expr *From, QualType ToType,
|
||||||
|
OverloadCandidateSet& CandidateSet);
|
||||||
void AddOverloadCandidates(const OverloadedFunctionDecl *Ovl,
|
void AddOverloadCandidates(const OverloadedFunctionDecl *Ovl,
|
||||||
Expr **Args, unsigned NumArgs,
|
Expr **Args, unsigned NumArgs,
|
||||||
OverloadCandidateSet& CandidateSet,
|
OverloadCandidateSet& CandidateSet,
|
||||||
|
@ -893,7 +893,20 @@ bool Sema::IsUserDefinedConversion(Expr *From, QualType ToType,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: Implement support for user-defined conversion operators.
|
if (const CXXRecordType *FromRecordType
|
||||||
|
= dyn_cast_or_null<CXXRecordType>(From->getType()->getAsRecordType())) {
|
||||||
|
// Add all of the conversion functions as candidates.
|
||||||
|
// FIXME: Look for conversions in base classes!
|
||||||
|
CXXRecordDecl *FromRecordDecl = FromRecordType->getDecl();
|
||||||
|
OverloadedFunctionDecl *Conversions
|
||||||
|
= FromRecordDecl->getConversionFunctions();
|
||||||
|
for (OverloadedFunctionDecl::function_iterator Func
|
||||||
|
= Conversions->function_begin();
|
||||||
|
Func != Conversions->function_end(); ++Func) {
|
||||||
|
CXXConversionDecl *Conv = cast<CXXConversionDecl>(*Func);
|
||||||
|
AddConversionCandidate(Conv, From, ToType, CandidateSet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
OverloadCandidateSet::iterator Best;
|
OverloadCandidateSet::iterator Best;
|
||||||
switch (BestViableFunction(CandidateSet, Best)) {
|
switch (BestViableFunction(CandidateSet, Best)) {
|
||||||
@ -917,9 +930,30 @@ bool Sema::IsUserDefinedConversion(Expr *From, QualType ToType,
|
|||||||
= ThisType->getAsPointerType()->getPointeeType().getAsOpaquePtr();
|
= ThisType->getAsPointerType()->getPointeeType().getAsOpaquePtr();
|
||||||
User.After.ToTypePtr = ToType.getAsOpaquePtr();
|
User.After.ToTypePtr = ToType.getAsOpaquePtr();
|
||||||
return true;
|
return true;
|
||||||
|
} else if (CXXConversionDecl *Conversion
|
||||||
|
= dyn_cast<CXXConversionDecl>(Best->Function)) {
|
||||||
|
// C++ [over.ics.user]p1:
|
||||||
|
//
|
||||||
|
// [...] If the user-defined conversion is specified by a
|
||||||
|
// conversion function (12.3.2), the initial standard
|
||||||
|
// conversion sequence converts the source type to the
|
||||||
|
// implicit object parameter of the conversion function.
|
||||||
|
User.Before = Best->Conversions[0].Standard;
|
||||||
|
User.ConversionFunction = Conversion;
|
||||||
|
|
||||||
|
// C++ [over.ics.user]p2:
|
||||||
|
// The second standard conversion sequence converts the
|
||||||
|
// result of the user-defined conversion to the target type
|
||||||
|
// for the sequence. Since an implicit conversion sequence
|
||||||
|
// is an initialization, the special rules for
|
||||||
|
// initialization by user-defined conversion apply when
|
||||||
|
// selecting the best user-defined conversion for a
|
||||||
|
// user-defined conversion sequence (see 13.3.3 and
|
||||||
|
// 13.3.3.1).
|
||||||
|
User.After = Best->FinalConversion;
|
||||||
|
return true;
|
||||||
} else {
|
} else {
|
||||||
assert(false &&
|
assert(false && "Not a constructor or conversion function?");
|
||||||
"Cannot perform user-defined conversion via a conversion operator");
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1378,6 +1412,8 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
|
|||||||
const FunctionTypeProto* Proto
|
const FunctionTypeProto* Proto
|
||||||
= dyn_cast<FunctionTypeProto>(Function->getType()->getAsFunctionType());
|
= dyn_cast<FunctionTypeProto>(Function->getType()->getAsFunctionType());
|
||||||
assert(Proto && "Functions without a prototype cannot be overloaded");
|
assert(Proto && "Functions without a prototype cannot be overloaded");
|
||||||
|
assert(!isa<CXXConversionDecl>(Function) &&
|
||||||
|
"Use AddConversionCandidate for conversion functions");
|
||||||
|
|
||||||
// Add this candidate
|
// Add this candidate
|
||||||
CandidateSet.push_back(OverloadCandidate());
|
CandidateSet.push_back(OverloadCandidate());
|
||||||
@ -1433,6 +1469,76 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// AddConversionCandidate - Add a C++ conversion function as a
|
||||||
|
/// candidate in the candidate set (C++ [over.match.conv],
|
||||||
|
/// C++ [over.match.copy]). From is the expression we're converting from,
|
||||||
|
/// and ToType is the type that we're eventually trying to convert to
|
||||||
|
/// (which may or may not be the same type as the type that the
|
||||||
|
/// conversion function produces).
|
||||||
|
void
|
||||||
|
Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
|
||||||
|
Expr *From, QualType ToType,
|
||||||
|
OverloadCandidateSet& CandidateSet) {
|
||||||
|
// Add this candidate
|
||||||
|
CandidateSet.push_back(OverloadCandidate());
|
||||||
|
OverloadCandidate& Candidate = CandidateSet.back();
|
||||||
|
Candidate.Function = Conversion;
|
||||||
|
Candidate.FinalConversion.setAsIdentityConversion();
|
||||||
|
Candidate.FinalConversion.FromTypePtr
|
||||||
|
= Conversion->getConversionType().getAsOpaquePtr();
|
||||||
|
Candidate.FinalConversion.ToTypePtr = ToType.getAsOpaquePtr();
|
||||||
|
|
||||||
|
// Determine the implicit conversion sequences for each of the
|
||||||
|
// arguments.
|
||||||
|
Candidate.Viable = true;
|
||||||
|
Candidate.Conversions.resize(1);
|
||||||
|
|
||||||
|
// FIXME: We need to follow the rules for the implicit object
|
||||||
|
// parameter.
|
||||||
|
QualType ImplicitObjectType
|
||||||
|
= Context.getTypeDeclType(Conversion->getParent());
|
||||||
|
ImplicitObjectType
|
||||||
|
= ImplicitObjectType.getQualifiedType(Conversion->getTypeQualifiers());
|
||||||
|
ImplicitObjectType = Context.getReferenceType(ImplicitObjectType);
|
||||||
|
Candidate.Conversions[0] = TryCopyInitialization(From, ImplicitObjectType,
|
||||||
|
true);
|
||||||
|
if (Candidate.Conversions[0].ConversionKind
|
||||||
|
== ImplicitConversionSequence::BadConversion) {
|
||||||
|
Candidate.Viable = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// To determine what the conversion from the result of calling the
|
||||||
|
// conversion function to the type we're eventually trying to
|
||||||
|
// convert to (ToType), we need to synthesize a call to the
|
||||||
|
// conversion function and attempt copy initialization from it. This
|
||||||
|
// makes sure that we get the right semantics with respect to
|
||||||
|
// lvalues/rvalues and the type. Fortunately, we can allocate this
|
||||||
|
// call on the stack and we don't need its arguments to be
|
||||||
|
// well-formed.
|
||||||
|
DeclRefExpr ConversionRef(Conversion, Conversion->getType(),
|
||||||
|
SourceLocation());
|
||||||
|
ImplicitCastExpr ConversionFn(Context.getPointerType(Conversion->getType()),
|
||||||
|
&ConversionRef);
|
||||||
|
CallExpr Call(&ConversionFn, 0, 0,
|
||||||
|
Conversion->getConversionType().getNonReferenceType(),
|
||||||
|
SourceLocation());
|
||||||
|
ImplicitConversionSequence ICS = TryCopyInitialization(&Call, ToType, true);
|
||||||
|
switch (ICS.ConversionKind) {
|
||||||
|
case ImplicitConversionSequence::StandardConversion:
|
||||||
|
Candidate.FinalConversion = ICS.Standard;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ImplicitConversionSequence::BadConversion:
|
||||||
|
Candidate.Viable = false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert(false &&
|
||||||
|
"Can only end up with a standard conversion sequence or failure");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// AddOverloadCandidates - Add all of the function overloads in Ovl
|
/// AddOverloadCandidates - Add all of the function overloads in Ovl
|
||||||
/// to the candidate set.
|
/// to the candidate set.
|
||||||
void
|
void
|
||||||
@ -1494,6 +1600,32 @@ Sema::isBetterOverloadCandidate(const OverloadCandidate& Cand1,
|
|||||||
|
|
||||||
// FIXME: Several other bullets in (C++ 13.3.3p1) need to be implemented.
|
// FIXME: Several other bullets in (C++ 13.3.3p1) need to be implemented.
|
||||||
|
|
||||||
|
// C++ [over.match.best]p1b4:
|
||||||
|
//
|
||||||
|
// -- the context is an initialization by user-defined conversion
|
||||||
|
// (see 8.5, 13.3.1.5) and the standard conversion sequence
|
||||||
|
// from the return type of F1 to the destination type (i.e.,
|
||||||
|
// the type of the entity being initialized) is a better
|
||||||
|
// conversion sequence than the standard conversion sequence
|
||||||
|
// from the return type of F2 to the destination type.
|
||||||
|
if (isa<CXXConversionDecl>(Cand1.Function) &&
|
||||||
|
isa<CXXConversionDecl>(Cand2.Function)) {
|
||||||
|
switch (CompareStandardConversionSequences(Cand1.FinalConversion,
|
||||||
|
Cand2.FinalConversion)) {
|
||||||
|
case ImplicitConversionSequence::Better:
|
||||||
|
// Cand1 has a better conversion sequence.
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case ImplicitConversionSequence::Worse:
|
||||||
|
// Cand1 can't be better than Cand2.
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case ImplicitConversionSequence::Indistinguishable:
|
||||||
|
// Do nothing
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,6 +207,12 @@ namespace clang {
|
|||||||
|
|
||||||
/// Viable - True to indicate that this overload candidate is viable.
|
/// Viable - True to indicate that this overload candidate is viable.
|
||||||
bool Viable;
|
bool Viable;
|
||||||
|
|
||||||
|
/// FinalConversion - For a conversion function (where Function is
|
||||||
|
/// a CXXConversionDecl), the standard conversion that occurs
|
||||||
|
/// after the call to the overload candidate to convert the result
|
||||||
|
/// of calling the conversion function to the required type.
|
||||||
|
StandardConversionSequence FinalConversion;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// OverloadCandidateSet - A set of overload candidates, used in C++
|
/// OverloadCandidateSet - A set of overload candidates, used in C++
|
||||||
|
22
clang/test/SemaCXX/user-defined-conversions.cpp
Normal file
22
clang/test/SemaCXX/user-defined-conversions.cpp
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
// RUN: clang -fsyntax-only -verify %s
|
||||||
|
struct X {
|
||||||
|
operator bool();
|
||||||
|
};
|
||||||
|
|
||||||
|
int& f(bool);
|
||||||
|
float& f(int);
|
||||||
|
|
||||||
|
void f_test(X x) {
|
||||||
|
int& i1 = f(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Y {
|
||||||
|
operator short();
|
||||||
|
operator float();
|
||||||
|
};
|
||||||
|
|
||||||
|
void g(int);
|
||||||
|
|
||||||
|
void g_test(Y y) {
|
||||||
|
g(y);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user