Collapse the three separate initialization paths in

TryStaticImplicitCast (for references, class types, and everything
else, respectively) into a single invocation of
InitializationSequence.

One of the paths (for class types) was the only client of
Sema::TryInitializationByConstructor, which I have eliminated. This
also simplified the interface for much of the cast-checking logic,
eliminating yet more code.

I've kept the representation of C++ functional casts with <> 1
arguments the same, despite the fact that I hate it. That fix will
come soon. To satisfy my paranoia, I've bootstrapped + tested Clang
with these changes.

llvm-svn: 101549
This commit is contained in:
Douglas Gregor 2010-04-16 22:09:46 +00:00
parent d43a12df56
commit b33eed0ced
10 changed files with 70 additions and 234 deletions

View File

@ -2161,12 +2161,6 @@ public:
/// it simply returns the passed in expression.
OwningExprResult MaybeBindToTemporary(Expr *E);
CXXConstructorDecl *
TryInitializationByConstructor(QualType ClassType,
Expr **Args, unsigned NumArgs,
SourceLocation Loc,
InitializationKind Kind);
bool CompleteConstructorCall(CXXConstructorDecl *Constructor,
MultiExprArg ArgsPtr,
SourceLocation Loc,
@ -4206,7 +4200,6 @@ public:
/// C semantics, or forward to CXXCheckCStyleCast in C++.
bool CheckCastTypes(SourceRange TyRange, QualType CastTy, Expr *&CastExpr,
CastExpr::CastKind &Kind,
CXXMethodDecl *& ConversionDecl,
bool FunctionalStyle = false);
// CheckVectorCast - check type constraints for vectors.
@ -4227,8 +4220,7 @@ public:
/// CXXCheckCStyleCast - Check constraints of a C-style or function-style
/// cast under C++ semantics.
bool CXXCheckCStyleCast(SourceRange R, QualType CastTy, Expr *&CastExpr,
CastExpr::CastKind &Kind, bool FunctionalStyle,
CXXMethodDecl *&ConversionDecl);
CastExpr::CastKind &Kind, bool FunctionalStyle);
/// CheckMessageArgumentTypes - Check types in an Obj-C message send.
/// \param Method - May be null.

View File

@ -46,8 +46,7 @@ static void CheckReinterpretCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
CastExpr::CastKind &Kind);
static void CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
const SourceRange &OpRange,
CastExpr::CastKind &Kind,
CXXMethodDecl *&ConversionDecl);
CastExpr::CastKind &Kind);
static void CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
const SourceRange &OpRange,
const SourceRange &DestRange,
@ -94,14 +93,12 @@ static TryCastResult TryStaticImplicitCast(Sema &Self, Expr *&SrcExpr,
QualType DestType, bool CStyle,
const SourceRange &OpRange,
unsigned &msg,
CastExpr::CastKind &Kind,
CXXMethodDecl *&ConversionDecl);
CastExpr::CastKind &Kind);
static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr,
QualType DestType, bool CStyle,
const SourceRange &OpRange,
unsigned &msg,
CastExpr::CastKind &Kind,
CXXMethodDecl *&ConversionDecl);
CastExpr::CastKind &Kind);
static TryCastResult TryConstCast(Sema &Self, Expr *SrcExpr, QualType DestType,
bool CStyle, unsigned &msg);
static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr,
@ -168,21 +165,8 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
}
case tok::kw_static_cast: {
CastExpr::CastKind Kind = CastExpr::CK_Unknown;
if (!TypeDependent) {
CXXMethodDecl *Method = 0;
CheckStaticCast(*this, Ex, DestType, OpRange, Kind, Method);
if (Method) {
OwningExprResult CastArg
= BuildCXXCastArgument(OpLoc, DestType.getNonReferenceType(),
Kind, Method, Owned(Ex));
if (CastArg.isInvalid())
return ExprError();
Ex = CastArg.takeAs<Expr>();
}
}
if (!TypeDependent)
CheckStaticCast(*this, Ex, DestType, OpRange, Kind);
return Owned(new (Context) CXXStaticCastExpr(DestType.getNonReferenceType(),
Kind, Ex, DestTInfo, OpLoc));
@ -447,8 +431,7 @@ CheckReinterpretCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
/// implicit conversions explicit and getting rid of data loss warnings.
void
CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
const SourceRange &OpRange, CastExpr::CastKind &Kind,
CXXMethodDecl *&ConversionDecl) {
const SourceRange &OpRange, CastExpr::CastKind &Kind) {
// This test is outside everything else because it's the only case where
// a non-lvalue-reference target type does not lead to decay.
// C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void".
@ -462,7 +445,7 @@ CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
unsigned msg = diag::err_bad_cxx_cast_generic;
if (TryStaticCast(Self, SrcExpr, DestType, /*CStyle*/false, OpRange, msg,
Kind, ConversionDecl)
Kind)
!= TC_Success && msg != 0)
Self.Diag(OpRange.getBegin(), msg) << CT_Static
<< SrcExpr->getType() << DestType << OpRange;
@ -474,8 +457,7 @@ CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr,
QualType DestType, bool CStyle,
const SourceRange &OpRange, unsigned &msg,
CastExpr::CastKind &Kind,
CXXMethodDecl *&ConversionDecl) {
CastExpr::CastKind &Kind) {
// The order the tests is not entirely arbitrary. There is one conversion
// that can be handled in two different ways. Given:
// struct A {};
@ -512,7 +494,7 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr,
// C++ 5.2.9p2: An expression e can be explicitly converted to a type T
// [...] if the declaration "T t(e);" is well-formed, [...].
tcr = TryStaticImplicitCast(Self, SrcExpr, DestType, CStyle, OpRange, msg,
Kind, ConversionDecl);
Kind);
if (tcr != TC_NotApplicable)
return tcr;
@ -900,8 +882,7 @@ TryStaticMemberPointerUpcast(Sema &Self, Expr *&SrcExpr, QualType SrcType,
TryCastResult
TryStaticImplicitCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
bool CStyle, const SourceRange &OpRange, unsigned &msg,
CastExpr::CastKind &Kind,
CXXMethodDecl *&ConversionDecl) {
CastExpr::CastKind &Kind) {
if (DestType->isRecordType()) {
if (Self.RequireCompleteType(OpRange.getBegin(), DestType,
diag::err_bad_dynamic_cast_incomplete)) {
@ -909,66 +890,33 @@ TryStaticImplicitCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
return TC_Failed;
}
}
if (DestType->isReferenceType()) {
// All reference bindings insert implicit casts above that do the actual
// casting.
Kind = CastExpr::CK_NoOp;
// At this point of CheckStaticCast, if the destination is a reference,
// this has to work. There is no other way that works.
// On the other hand, if we're checking a C-style cast, we've still got
// the reinterpret_cast way.
InitializedEntity Entity = InitializedEntity::InitializeTemporary(DestType);
InitializationKind InitKind = InitializationKind::CreateCast(OpRange,
CStyle);
InitializationSequence InitSeq(Self, Entity, InitKind, &SrcExpr, 1);
if (InitSeq.getKind() == InitializationSequence::FailedSequence && CStyle)
return TC_NotApplicable;
Sema::OwningExprResult Result
= InitSeq.Perform(Self, Entity, InitKind,
Action::MultiExprArg(Self, (void**)&SrcExpr, 1));
if (Result.isInvalid()) {
msg = 0;
return TC_Failed;
}
SrcExpr = Result.takeAs<Expr>();
return TC_Success;
}
if (DestType->isRecordType()) {
if (CXXConstructorDecl *Constructor
= Self.TryInitializationByConstructor(DestType, &SrcExpr, 1,
OpRange.getBegin(),
InitializationKind::CreateDirect(OpRange.getBegin(),
OpRange.getBegin(),
OpRange.getEnd()))) {
ConversionDecl = Constructor;
Kind = CastExpr::CK_ConstructorConversion;
return TC_Success;
}
return TC_NotApplicable;
}
// At this point of CheckStaticCast, if the destination is a reference,
// this has to work. There is no other way that works.
// On the other hand, if we're checking a C-style cast, we've still got
// the reinterpret_cast way.
InitializedEntity Entity = InitializedEntity::InitializeTemporary(DestType);
InitializationKind InitKind
= InitializationKind::CreateCast(/*FIXME:*/OpRange, CStyle);
= InitializationKind::CreateCast(/*FIXME:*/OpRange,
CStyle);
InitializationSequence InitSeq(Self, Entity, InitKind, &SrcExpr, 1);
if (InitSeq.getKind() == InitializationSequence::FailedSequence)
if (InitSeq.getKind() == InitializationSequence::FailedSequence &&
(CStyle || !DestType->isReferenceType()))
return TC_NotApplicable;
Sema::OwningExprResult Result
= InitSeq.Perform(Self, Entity, InitKind,
Action::MultiExprArg(Self, (void **)&SrcExpr, 1));
Kind = CastExpr::CK_NoOp;
= InitSeq.Perform(Self, Entity, InitKind,
Action::MultiExprArg(Self, (void**)&SrcExpr, 1));
if (Result.isInvalid()) {
msg = 0;
return TC_Failed;
}
if (InitSeq.isConstructorInitialization())
Kind = CastExpr::CK_ConstructorConversion;
else
Kind = CastExpr::CK_NoOp;
SrcExpr = Result.takeAs<Expr>();
return TC_Success;
}
@ -1234,8 +1182,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr,
}
bool Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, Expr *&CastExpr,
CastExpr::CastKind &Kind, bool FunctionalStyle,
CXXMethodDecl *&ConversionDecl) {
CastExpr::CastKind &Kind, bool FunctionalStyle) {
// This test is outside everything else because it's the only case where
// a non-lvalue-reference target type does not lead to decay.
// C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void".
@ -1270,8 +1217,7 @@ bool Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, Expr *&CastExpr,
if (tcr == TC_NotApplicable) {
// ... or if that is not possible, a static_cast, ignoring const, ...
tcr = TryStaticCast(*this, CastExpr, CastTy, /*CStyle*/true, R, msg,
Kind, ConversionDecl);
tcr = TryStaticCast(*this, CastExpr, CastTy, /*CStyle*/true, R, msg, Kind);
if (tcr == TC_NotApplicable) {
// ... and finally a reinterpret_cast, ignoring const.
tcr = TryReinterpretCast(*this, CastExpr, CastTy, /*CStyle*/true, R, msg,

View File

@ -409,9 +409,7 @@ bool Sema::SemaBuiltinAtomicOverloaded(CallExpr *TheCall) {
// GCC does an implicit conversion to the pointer or integer ValType. This
// can fail in some cases (1i -> int**), check for this error case now.
CastExpr::CastKind Kind = CastExpr::CK_Unknown;
CXXMethodDecl *ConversionDecl = 0;
if (CheckCastTypes(Arg->getSourceRange(), ValType, Arg, Kind,
ConversionDecl))
if (CheckCastTypes(Arg->getSourceRange(), ValType, Arg, Kind))
return true;
// Okay, we have something that *can* be converted to the right type. Check

View File

@ -4271,113 +4271,6 @@ void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl,
FinalizeVarWithDestructor(VDecl, Record);
}
/// \brief Add the applicable constructor candidates for an initialization
/// by constructor.
static void AddConstructorInitializationCandidates(Sema &SemaRef,
QualType ClassType,
Expr **Args,
unsigned NumArgs,
InitializationKind Kind,
OverloadCandidateSet &CandidateSet) {
// C++ [dcl.init]p14:
// If the initialization is direct-initialization, or if it is
// copy-initialization where the cv-unqualified version of the
// source type is the same class as, or a derived class of, the
// class of the destination, constructors are considered. The
// applicable constructors are enumerated (13.3.1.3), and the
// best one is chosen through overload resolution (13.3). The
// constructor so selected is called to initialize the object,
// with the initializer expression(s) as its argument(s). If no
// constructor applies, or the overload resolution is ambiguous,
// the initialization is ill-formed.
const RecordType *ClassRec = ClassType->getAs<RecordType>();
assert(ClassRec && "Can only initialize a class type here");
// FIXME: When we decide not to synthesize the implicitly-declared
// constructors, we'll need to make them appear here.
const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(ClassRec->getDecl());
DeclarationName ConstructorName
= SemaRef.Context.DeclarationNames.getCXXConstructorName(
SemaRef.Context.getCanonicalType(ClassType).getUnqualifiedType());
DeclContext::lookup_const_iterator Con, ConEnd;
for (llvm::tie(Con, ConEnd) = ClassDecl->lookup(ConstructorName);
Con != ConEnd; ++Con) {
DeclAccessPair FoundDecl = DeclAccessPair::make(*Con, (*Con)->getAccess());
// Find the constructor (which may be a template).
CXXConstructorDecl *Constructor = 0;
FunctionTemplateDecl *ConstructorTmpl= dyn_cast<FunctionTemplateDecl>(*Con);
if (ConstructorTmpl)
Constructor
= cast<CXXConstructorDecl>(ConstructorTmpl->getTemplatedDecl());
else
Constructor = cast<CXXConstructorDecl>(*Con);
if ((Kind.getKind() == InitializationKind::IK_Direct) ||
(Kind.getKind() == InitializationKind::IK_Value) ||
(Kind.getKind() == InitializationKind::IK_Copy &&
Constructor->isConvertingConstructor(/*AllowExplicit=*/false)) ||
((Kind.getKind() == InitializationKind::IK_Default) &&
Constructor->isDefaultConstructor())) {
if (ConstructorTmpl)
SemaRef.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl,
/*ExplicitArgs*/ 0,
Args, NumArgs, CandidateSet);
else
SemaRef.AddOverloadCandidate(Constructor, FoundDecl,
Args, NumArgs, CandidateSet);
}
}
}
/// \brief Attempt to perform initialization by constructor
/// (C++ [dcl.init]p14), which may occur as part of direct-initialization or
/// copy-initialization.
///
/// This routine determines whether initialization by constructor is possible,
/// but it does not emit any diagnostics in the case where the initialization
/// is ill-formed.
///
/// \param ClassType the type of the object being initialized, which must have
/// class type.
///
/// \param Args the arguments provided to initialize the object
///
/// \param NumArgs the number of arguments provided to initialize the object
///
/// \param Kind the type of initialization being performed
///
/// \returns the constructor used to initialize the object, if successful.
/// Otherwise, emits a diagnostic and returns NULL.
CXXConstructorDecl *
Sema::TryInitializationByConstructor(QualType ClassType,
Expr **Args, unsigned NumArgs,
SourceLocation Loc,
InitializationKind Kind) {
// Build the overload candidate set
OverloadCandidateSet CandidateSet(Loc);
AddConstructorInitializationCandidates(*this, ClassType, Args, NumArgs, Kind,
CandidateSet);
// Determine whether we found a constructor we can use.
OverloadCandidateSet::iterator Best;
switch (BestViableFunction(CandidateSet, Loc, Best)) {
case OR_Success:
case OR_Deleted:
// We found a constructor. Return it.
return cast<CXXConstructorDecl>(Best->Function);
case OR_No_Viable_Function:
case OR_Ambiguous:
// Overload resolution failed. Return nothing.
return 0;
}
// Silence GCC warning
return 0;
}
/// \brief Given a constructor and the set of arguments provided for the
/// constructor, convert the arguments and add any required default arguments
/// to form a proper call to this constructor.

View File

@ -3789,11 +3789,9 @@ static CastExpr::CastKind getScalarCastKind(ASTContext &Context,
/// CheckCastTypes - Check type constraints for casting between types.
bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr,
CastExpr::CastKind& Kind,
CXXMethodDecl *& ConversionDecl,
bool FunctionalStyle) {
if (getLangOptions().CPlusPlus)
return CXXCheckCStyleCast(TyR, castType, castExpr, Kind, FunctionalStyle,
ConversionDecl);
return CXXCheckCStyleCast(TyR, castType, castExpr, Kind, FunctionalStyle);
DefaultFunctionArrayLvalueConversion(castExpr);
@ -3953,25 +3951,12 @@ Sema::BuildCStyleCastExpr(SourceLocation LParenLoc, TypeSourceInfo *Ty,
SourceLocation RParenLoc, ExprArg Op) {
Expr *castExpr = static_cast<Expr*>(Op.get());
CXXMethodDecl *Method = 0;
CastExpr::CastKind Kind = CastExpr::CK_Unknown;
if (CheckCastTypes(SourceRange(LParenLoc, RParenLoc), Ty->getType(), castExpr,
Kind, Method))
Kind))
return ExprError();
if (Method) {
// FIXME: preserve type source info here
OwningExprResult CastArg = BuildCXXCastArgument(LParenLoc, Ty->getType(),
Kind, Method, move(Op));
if (CastArg.isInvalid())
return ExprError();
castExpr = CastArg.takeAs<Expr>();
} else {
Op.release();
}
Op.release();
return Owned(new (Context) CStyleCastExpr(Ty->getType().getNonReferenceType(),
Kind, castExpr, Ty,
LParenLoc, RParenLoc));

View File

@ -504,21 +504,10 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep,
//
if (NumExprs == 1) {
CastExpr::CastKind Kind = CastExpr::CK_Unknown;
CXXMethodDecl *Method = 0;
if (CheckCastTypes(TypeRange, Ty, Exprs[0], Kind, Method,
/*FunctionalStyle=*/true))
if (CheckCastTypes(TypeRange, Ty, Exprs[0], Kind, /*FunctionalStyle=*/true))
return ExprError();
exprs.release();
if (Method) {
OwningExprResult CastArg
= BuildCXXCastArgument(TypeRange.getBegin(), Ty.getNonReferenceType(),
Kind, Method, Owned(Exprs[0]));
if (CastArg.isInvalid())
return ExprError();
Exprs[0] = CastArg.takeAs<Expr>();
}
return Owned(new (Context) CXXFunctionalCastExpr(Ty.getNonReferenceType(),
TInfo, TyBeginLoc, Kind,

View File

@ -2036,6 +2036,10 @@ bool InitializationSequence::isAmbiguous() const {
return false;
}
bool InitializationSequence::isConstructorInitialization() const {
return !Steps.empty() && Steps.back().Kind == SK_ConstructorInitialization;
}
void InitializationSequence::AddAddressOverloadResolutionStep(
FunctionDecl *Function,
DeclAccessPair Found) {
@ -3510,6 +3514,7 @@ InitializationSequence::Perform(Sema &S,
}
case SK_ConstructorInitialization: {
unsigned NumArgs = Args.size();
CXXConstructorDecl *Constructor
= cast<CXXConstructorDecl>(Step->Function.Function);
@ -3523,8 +3528,9 @@ InitializationSequence::Perform(Sema &S,
Loc, ConstructorArgs))
return S.ExprError();
// Build the an expression that constructs a temporary.
// Build the expression that constructs a temporary.
if (Entity.getKind() == InitializedEntity::EK_Temporary &&
NumArgs != 1 && // FIXME: Hack to work around cast weirdness
(Kind.getKind() == InitializationKind::IK_Direct ||
Kind.getKind() == InitializationKind::IK_Value)) {
// An explicitly-constructed temporary, e.g., X(1, 2).

View File

@ -606,6 +606,10 @@ public:
/// \brief Determine whether this initialization failed due to an ambiguity.
bool isAmbiguous() const;
/// \brief Determine whether this initialization is direct call to a
/// constructor.
bool isConstructorInitialization() const;
/// \brief Add a new step in the initialization that resolves the address
/// of an overloaded function to a specific function declaration.
///

View File

@ -126,8 +126,12 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
Diag(Loc, diag::warn_unused_call) << R1 << R2 << "warn_unused_result";
return;
}
} else if (const CXXFunctionalCastExpr *FC
= dyn_cast<CXXFunctionalCastExpr>(E)) {
if (isa<CXXConstructExpr>(FC->getSubExpr()) ||
isa<CXXTemporaryObjectExpr>(FC->getSubExpr()))
return;
}
// Diagnose "(void*) blah" as a typo for "(void) blah".
else if (const CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(E)) {
TypeSourceInfo *TI = CE->getTypeInfoAsWritten();

View File

@ -193,3 +193,22 @@ namespace N12 {
void f0(int **a) { C::f0(a); }
}
namespace N13 {
class A{
A(const A&);
public:
~A();
A(int);
template<typename T> A &operator<<(const T&);
};
template<typename T>
void f(T t) {
A(17) << t;
}
template void f(int);
}