forked from OSchip/llvm-project
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:
parent
84605aeac9
commit
8a2e601917
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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)) {
|
||||||
|
|
|
@ -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!
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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}}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue