Try to complete a type before looking for conversion functions within

that type. Note that we do not produce a diagnostic if the type is
incomplete; rather, we just don't look for conversion functions. Fixes PR4660.

llvm-svn: 79919
This commit is contained in:
Douglas Gregor 2009-08-24 15:23:48 +00:00
parent 84605aeac9
commit 8a2e601917
7 changed files with 84 additions and 35 deletions

View File

@ -549,9 +549,15 @@ public:
/// getConversions - Retrieve the overload set containing all of the /// getConversions - Retrieve the overload set containing all of the
/// conversion functions in this class. /// conversion functions in this class.
OverloadedFunctionDecl *getConversionFunctions() { OverloadedFunctionDecl *getConversionFunctions() {
assert((this->isDefinition() ||
cast<RecordType>(getTypeForDecl())->isBeingDefined()) &&
"getConversionFunctions() called on incomplete type");
return &Conversions; return &Conversions;
} }
const OverloadedFunctionDecl *getConversionFunctions() const { const OverloadedFunctionDecl *getConversionFunctions() const {
assert((this->isDefinition() ||
cast<RecordType>(getTypeForDecl())->isBeingDefined()) &&
"getConversionFunctions() called on incomplete type");
return &Conversions; return &Conversions;
} }

View File

@ -2875,12 +2875,13 @@ public:
InstantiateClass(SourceLocation PointOfInstantiation, InstantiateClass(SourceLocation PointOfInstantiation,
CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern, CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern,
const TemplateArgumentList &TemplateArgs, const TemplateArgumentList &TemplateArgs,
bool ExplicitInstantiation); bool ExplicitInstantiation,
bool Complain = true);
bool bool
InstantiateClassTemplateSpecialization( InstantiateClassTemplateSpecialization(
ClassTemplateSpecializationDecl *ClassTemplateSpec, ClassTemplateSpecializationDecl *ClassTemplateSpec,
bool ExplicitInstantiation); bool ExplicitInstantiation, bool Complain = true);
void InstantiateClassMembers(SourceLocation PointOfInstantiation, void InstantiateClassMembers(SourceLocation PointOfInstantiation,
CXXRecordDecl *Instantiation, CXXRecordDecl *Instantiation,

View File

@ -2847,7 +2847,8 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
// 92) (this conversion is selected by enumerating the // 92) (this conversion is selected by enumerating the
// applicable conversion functions (13.3.1.6) and choosing // applicable conversion functions (13.3.1.6) and choosing
// the best one through overload resolution (13.3)), // the best one through overload resolution (13.3)),
if (!isRValRef && !SuppressUserConversions && T2->isRecordType()) { if (!isRValRef && !SuppressUserConversions && T2->isRecordType() &&
!RequireCompleteType(SourceLocation(), T2, 0)) {
// FIXME: Look for conversions in base classes! // FIXME: Look for conversions in base classes!
CXXRecordDecl *T2RecordDecl CXXRecordDecl *T2RecordDecl
= dyn_cast<CXXRecordDecl>(T2->getAs<RecordType>()->getDecl()); = dyn_cast<CXXRecordDecl>(T2->getAs<RecordType>()->getDecl());

View File

@ -1392,6 +1392,9 @@ bool Sema::IsUserDefinedConversion(Expr *From, QualType ToType,
if (!AllowConversionFunctions) { if (!AllowConversionFunctions) {
// Don't allow any conversion functions to enter the overload set. // Don't allow any conversion functions to enter the overload set.
} else if (RequireCompleteType(From->getLocStart(), From->getType(), 0,
From->getSourceRange())) {
// No conversion functions from incomplete types.
} else if (const RecordType *FromRecordType } else if (const RecordType *FromRecordType
= From->getType()->getAs<RecordType>()) { = From->getType()->getAs<RecordType>()) {
if (CXXRecordDecl *FromRecordDecl if (CXXRecordDecl *FromRecordDecl
@ -2699,6 +2702,10 @@ class BuiltinCandidateTypeSet {
/// used in the built-in candidates. /// used in the built-in candidates.
TypeSet EnumerationTypes; TypeSet EnumerationTypes;
/// Sema - The semantic analysis instance where we are building the
/// candidate type set.
Sema &SemaRef;
/// Context - The AST context in which we will build the type sets. /// Context - The AST context in which we will build the type sets.
ASTContext &Context; ASTContext &Context;
@ -2709,7 +2716,8 @@ public:
/// iterator - Iterates through the types that are part of the set. /// iterator - Iterates through the types that are part of the set.
typedef TypeSet::iterator iterator; typedef TypeSet::iterator iterator;
BuiltinCandidateTypeSet(ASTContext &Context) : Context(Context) { } BuiltinCandidateTypeSet(Sema &SemaRef)
: SemaRef(SemaRef), Context(SemaRef.Context) { }
void AddTypesConvertedFrom(QualType Ty, bool AllowUserConversions, void AddTypesConvertedFrom(QualType Ty, bool AllowUserConversions,
bool AllowExplicitConversions); bool AllowExplicitConversions);
@ -2860,6 +2868,11 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty,
EnumerationTypes.insert(Ty); EnumerationTypes.insert(Ty);
} else if (AllowUserConversions) { } else if (AllowUserConversions) {
if (const RecordType *TyRec = Ty->getAs<RecordType>()) { if (const RecordType *TyRec = Ty->getAs<RecordType>()) {
if (SemaRef.RequireCompleteType(SourceLocation(), Ty, 0)) {
// No conversion functions in incomplete types.
return;
}
CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(TyRec->getDecl()); CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(TyRec->getDecl());
// FIXME: Visit conversion functions in the base classes, too. // FIXME: Visit conversion functions in the base classes, too.
OverloadedFunctionDecl *Conversions OverloadedFunctionDecl *Conversions
@ -2942,7 +2955,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
// Find all of the types that the arguments can convert to, but only // Find all of the types that the arguments can convert to, but only
// if the operator we're looking at has built-in operator candidates // if the operator we're looking at has built-in operator candidates
// that make use of these types. // that make use of these types.
BuiltinCandidateTypeSet CandidateTypes(Context); BuiltinCandidateTypeSet CandidateTypes(*this);
if (Op == OO_Less || Op == OO_Greater || Op == OO_LessEqual || if (Op == OO_Less || Op == OO_Greater || Op == OO_LessEqual ||
Op == OO_GreaterEqual || Op == OO_EqualEqual || Op == OO_ExclaimEqual || Op == OO_GreaterEqual || Op == OO_EqualEqual || Op == OO_ExclaimEqual ||
Op == OO_Plus || (Op == OO_Minus && NumArgs == 2) || Op == OO_Equal || Op == OO_Plus || (Op == OO_Minus && NumArgs == 2) || Op == OO_Equal ||
@ -4612,33 +4625,35 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
// functions for each conversion function declared in an // functions for each conversion function declared in an
// accessible base class provided the function is not hidden // accessible base class provided the function is not hidden
// within T by another intervening declaration. // within T by another intervening declaration.
//
// FIXME: Look in base classes for more conversion operators! if (!RequireCompleteType(SourceLocation(), Object->getType(), 0)) {
OverloadedFunctionDecl *Conversions // FIXME: Look in base classes for more conversion operators!
= cast<CXXRecordDecl>(Record->getDecl())->getConversionFunctions(); OverloadedFunctionDecl *Conversions
for (OverloadedFunctionDecl::function_iterator = cast<CXXRecordDecl>(Record->getDecl())->getConversionFunctions();
Func = Conversions->function_begin(), for (OverloadedFunctionDecl::function_iterator
FuncEnd = Conversions->function_end(); Func = Conversions->function_begin(),
Func != FuncEnd; ++Func) { FuncEnd = Conversions->function_end();
CXXConversionDecl *Conv; Func != FuncEnd; ++Func) {
FunctionTemplateDecl *ConvTemplate; CXXConversionDecl *Conv;
GetFunctionAndTemplate(*Func, Conv, ConvTemplate); FunctionTemplateDecl *ConvTemplate;
GetFunctionAndTemplate(*Func, Conv, ConvTemplate);
// Skip over templated conversion functions; they aren't // Skip over templated conversion functions; they aren't
// surrogates. // surrogates.
if (ConvTemplate) if (ConvTemplate)
continue; continue;
// Strip the reference type (if any) and then the pointer type (if // Strip the reference type (if any) and then the pointer type (if
// any) to get down to what might be a function type. // any) to get down to what might be a function type.
QualType ConvType = Conv->getConversionType().getNonReferenceType(); QualType ConvType = Conv->getConversionType().getNonReferenceType();
if (const PointerType *ConvPtrType = ConvType->getAs<PointerType>()) if (const PointerType *ConvPtrType = ConvType->getAs<PointerType>())
ConvType = ConvPtrType->getPointeeType(); ConvType = ConvPtrType->getPointeeType();
if (const FunctionProtoType *Proto = ConvType->getAsFunctionProtoType()) if (const FunctionProtoType *Proto = ConvType->getAsFunctionProtoType())
AddSurrogateCandidate(Conv, Proto, Object, Args, NumArgs, CandidateSet); AddSurrogateCandidate(Conv, Proto, Object, Args, NumArgs, CandidateSet);
}
} }
// Perform overload resolution. // Perform overload resolution.
OverloadCandidateSet::iterator Best; OverloadCandidateSet::iterator Best;
switch (BestViableFunction(CandidateSet, Object->getLocStart(), Best)) { switch (BestViableFunction(CandidateSet, Object->getLocStart(), Best)) {

View File

@ -624,12 +624,19 @@ bool Sema::InstantiateTemplatePattern(SourceLocation PointOfInstantiation,
/// \param TemplateArgs The template arguments to be substituted into /// \param TemplateArgs The template arguments to be substituted into
/// the pattern. /// the pattern.
/// ///
/// \param ExplicitInstantiation whether this is an explicit instantiation
/// (otherwise, it is an implicit instantiation).
///
/// \param Complain whether to complain if the class cannot be instantiated due
/// to the lack of a definition.
///
/// \returns true if an error occurred, false otherwise. /// \returns true if an error occurred, false otherwise.
bool bool
Sema::InstantiateClass(SourceLocation PointOfInstantiation, Sema::InstantiateClass(SourceLocation PointOfInstantiation,
CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern, CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern,
const TemplateArgumentList &TemplateArgs, const TemplateArgumentList &TemplateArgs,
bool ExplicitInstantiation) { bool ExplicitInstantiation,
bool Complain) {
bool Invalid = false; bool Invalid = false;
// Lazily instantiate member templates here. // Lazily instantiate member templates here.
@ -639,7 +646,9 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
CXXRecordDecl *PatternDef CXXRecordDecl *PatternDef
= cast_or_null<CXXRecordDecl>(Pattern->getDefinition(Context)); = cast_or_null<CXXRecordDecl>(Pattern->getDefinition(Context));
if (!PatternDef) { if (!PatternDef) {
if (Pattern == Instantiation->getInstantiatedFromMemberClass()) { if (!Complain) {
// Say nothing
} else if (Pattern == Instantiation->getInstantiatedFromMemberClass()) {
Diag(PointOfInstantiation, Diag(PointOfInstantiation,
diag::err_implicit_instantiate_member_undefined) diag::err_implicit_instantiate_member_undefined)
<< Context.getTypeDeclType(Instantiation); << Context.getTypeDeclType(Instantiation);
@ -713,7 +722,8 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
bool bool
Sema::InstantiateClassTemplateSpecialization( Sema::InstantiateClassTemplateSpecialization(
ClassTemplateSpecializationDecl *ClassTemplateSpec, ClassTemplateSpecializationDecl *ClassTemplateSpec,
bool ExplicitInstantiation) { bool ExplicitInstantiation,
bool Complain) {
// Perform the actual instantiation on the canonical declaration. // Perform the actual instantiation on the canonical declaration.
ClassTemplateSpec = cast<ClassTemplateSpecializationDecl>( ClassTemplateSpec = cast<ClassTemplateSpecializationDecl>(
ClassTemplateSpec->getCanonicalDecl()); ClassTemplateSpec->getCanonicalDecl());
@ -791,7 +801,8 @@ Sema::InstantiateClassTemplateSpecialization(
bool Result = InstantiateClass(ClassTemplateSpec->getLocation(), bool Result = InstantiateClass(ClassTemplateSpec->getLocation(),
ClassTemplateSpec, Pattern, *TemplateArgs, ClassTemplateSpec, Pattern, *TemplateArgs,
ExplicitInstantiation); ExplicitInstantiation,
Complain);
for (unsigned I = 0, N = Matched.size(); I != N; ++I) { for (unsigned I = 0, N = Matched.size(); I != N; ++I) {
// FIXME: Implement TemplateArgumentList::Destroy! // FIXME: Implement TemplateArgumentList::Destroy!

View File

@ -1752,7 +1752,8 @@ void Sema::ProcessTypeAttributeList(QualType &Result, const AttributeList *AL) {
/// ///
/// @param diag The diagnostic value (e.g., /// @param diag The diagnostic value (e.g.,
/// @c diag::err_typecheck_decl_incomplete_type) that will be used /// @c diag::err_typecheck_decl_incomplete_type) that will be used
/// for the error message if @p T is incomplete. /// for the error message if @p T is incomplete. If 0, no diagnostic will be
/// emitted.
/// ///
/// @param Range1 An optional range in the source code that will be a /// @param Range1 An optional range in the source code that will be a
/// part of the "incomplete type" error message. /// part of the "incomplete type" error message.
@ -1792,7 +1793,8 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, unsigned diag,
if (Loc.isValid()) if (Loc.isValid())
ClassTemplateSpec->setLocation(Loc); ClassTemplateSpec->setLocation(Loc);
return InstantiateClassTemplateSpecialization(ClassTemplateSpec, return InstantiateClassTemplateSpecialization(ClassTemplateSpec,
/*ExplicitInstantiation=*/false); /*ExplicitInstantiation=*/false,
/*Complain=*/diag != 0);
} }
} else if (CXXRecordDecl *Rec } else if (CXXRecordDecl *Rec
= dyn_cast<CXXRecordDecl>(Record->getDecl())) { = dyn_cast<CXXRecordDecl>(Record->getDecl())) {
@ -1805,11 +1807,15 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, unsigned diag,
Spec = dyn_cast<ClassTemplateSpecializationDecl>(Parent); Spec = dyn_cast<ClassTemplateSpecializationDecl>(Parent);
assert(Spec && "Not a member of a class template specialization?"); assert(Spec && "Not a member of a class template specialization?");
return InstantiateClass(Loc, Rec, Pattern, Spec->getTemplateArgs(), return InstantiateClass(Loc, Rec, Pattern, Spec->getTemplateArgs(),
/*ExplicitInstantiation=*/false); /*ExplicitInstantiation=*/false,
/*Complain=*/diag != 0);
} }
} }
} }
if (diag == 0)
return true;
if (PrintType.isNull()) if (PrintType.isNull())
PrintType = T; PrintType = T;

View File

@ -72,3 +72,12 @@ void test_converts_to(ConvertsTo<int> ci, ConvertsTo<int *> cip) {
int i = ci; int i = ci;
int *ip = cip; int *ip = cip;
} }
// PR4660
template<class T> struct A0 { operator T*(); };
template<class T> struct A1;
int *a(A0<int> &x0, A1<int> &x1) {
int *y0 = x0;
int *y1 = x1; // expected-error{{initializing}}
}