From 5842ba9fd482bb2fe5198b32c2ae549cd5474e6d Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Mon, 24 Aug 2009 15:23:48 +0000 Subject: [PATCH] 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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@79919 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/DeclCXX.h | 6 +++ lib/Sema/Sema.h | 5 +- lib/Sema/SemaDeclCXX.cpp | 3 +- lib/Sema/SemaOverload.cpp | 65 +++++++++++++++--------- lib/Sema/SemaTemplateInstantiate.cpp | 19 +++++-- lib/Sema/SemaType.cpp | 12 +++-- test/SemaTemplate/instantiate-method.cpp | 9 ++++ 7 files changed, 84 insertions(+), 35 deletions(-) diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index 60db8c8334..d09d054c08 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -549,9 +549,15 @@ public: /// getConversions - Retrieve the overload set containing all of the /// conversion functions in this class. OverloadedFunctionDecl *getConversionFunctions() { + assert((this->isDefinition() || + cast(getTypeForDecl())->isBeingDefined()) && + "getConversionFunctions() called on incomplete type"); return &Conversions; } const OverloadedFunctionDecl *getConversionFunctions() const { + assert((this->isDefinition() || + cast(getTypeForDecl())->isBeingDefined()) && + "getConversionFunctions() called on incomplete type"); return &Conversions; } diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 1d61992d7c..b7b70bfc44 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -2875,12 +2875,13 @@ public: InstantiateClass(SourceLocation PointOfInstantiation, CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern, const TemplateArgumentList &TemplateArgs, - bool ExplicitInstantiation); + bool ExplicitInstantiation, + bool Complain = true); bool InstantiateClassTemplateSpecialization( ClassTemplateSpecializationDecl *ClassTemplateSpec, - bool ExplicitInstantiation); + bool ExplicitInstantiation, bool Complain = true); void InstantiateClassMembers(SourceLocation PointOfInstantiation, CXXRecordDecl *Instantiation, diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 462999b0a5..ea113301aa 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -2847,7 +2847,8 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, // 92) (this conversion is selected by enumerating the // applicable conversion functions (13.3.1.6) and choosing // 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! CXXRecordDecl *T2RecordDecl = dyn_cast(T2->getAs()->getDecl()); diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 0a65a36b47..152d4adf88 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -1392,6 +1392,9 @@ bool Sema::IsUserDefinedConversion(Expr *From, QualType ToType, if (!AllowConversionFunctions) { // 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 = From->getType()->getAs()) { if (CXXRecordDecl *FromRecordDecl @@ -2699,6 +2702,10 @@ class BuiltinCandidateTypeSet { /// used in the built-in candidates. 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. ASTContext &Context; @@ -2709,7 +2716,8 @@ public: /// iterator - Iterates through the types that are part of the set. typedef TypeSet::iterator iterator; - BuiltinCandidateTypeSet(ASTContext &Context) : Context(Context) { } + BuiltinCandidateTypeSet(Sema &SemaRef) + : SemaRef(SemaRef), Context(SemaRef.Context) { } void AddTypesConvertedFrom(QualType Ty, bool AllowUserConversions, bool AllowExplicitConversions); @@ -2860,6 +2868,11 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty, EnumerationTypes.insert(Ty); } else if (AllowUserConversions) { if (const RecordType *TyRec = Ty->getAs()) { + if (SemaRef.RequireCompleteType(SourceLocation(), Ty, 0)) { + // No conversion functions in incomplete types. + return; + } + CXXRecordDecl *ClassDecl = cast(TyRec->getDecl()); // FIXME: Visit conversion functions in the base classes, too. OverloadedFunctionDecl *Conversions @@ -2942,7 +2955,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, // 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 // that make use of these types. - BuiltinCandidateTypeSet CandidateTypes(Context); + BuiltinCandidateTypeSet CandidateTypes(*this); if (Op == OO_Less || Op == OO_Greater || Op == OO_LessEqual || Op == OO_GreaterEqual || Op == OO_EqualEqual || Op == OO_ExclaimEqual || 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 // accessible base class provided the function is not hidden // within T by another intervening declaration. - // - // FIXME: Look in base classes for more conversion operators! - OverloadedFunctionDecl *Conversions - = cast(Record->getDecl())->getConversionFunctions(); - for (OverloadedFunctionDecl::function_iterator - Func = Conversions->function_begin(), - FuncEnd = Conversions->function_end(); - Func != FuncEnd; ++Func) { - CXXConversionDecl *Conv; - FunctionTemplateDecl *ConvTemplate; - GetFunctionAndTemplate(*Func, Conv, ConvTemplate); + + if (!RequireCompleteType(SourceLocation(), Object->getType(), 0)) { + // FIXME: Look in base classes for more conversion operators! + OverloadedFunctionDecl *Conversions + = cast(Record->getDecl())->getConversionFunctions(); + for (OverloadedFunctionDecl::function_iterator + Func = Conversions->function_begin(), + FuncEnd = Conversions->function_end(); + Func != FuncEnd; ++Func) { + CXXConversionDecl *Conv; + FunctionTemplateDecl *ConvTemplate; + GetFunctionAndTemplate(*Func, Conv, ConvTemplate); - // Skip over templated conversion functions; they aren't - // surrogates. - if (ConvTemplate) - continue; + // Skip over templated conversion functions; they aren't + // surrogates. + if (ConvTemplate) + continue; - // Strip the reference type (if any) and then the pointer type (if - // any) to get down to what might be a function type. - QualType ConvType = Conv->getConversionType().getNonReferenceType(); - if (const PointerType *ConvPtrType = ConvType->getAs()) - ConvType = ConvPtrType->getPointeeType(); + // Strip the reference type (if any) and then the pointer type (if + // any) to get down to what might be a function type. + QualType ConvType = Conv->getConversionType().getNonReferenceType(); + if (const PointerType *ConvPtrType = ConvType->getAs()) + ConvType = ConvPtrType->getPointeeType(); - if (const FunctionProtoType *Proto = ConvType->getAsFunctionProtoType()) - AddSurrogateCandidate(Conv, Proto, Object, Args, NumArgs, CandidateSet); + if (const FunctionProtoType *Proto = ConvType->getAsFunctionProtoType()) + AddSurrogateCandidate(Conv, Proto, Object, Args, NumArgs, CandidateSet); + } } - + // Perform overload resolution. OverloadCandidateSet::iterator Best; switch (BestViableFunction(CandidateSet, Object->getLocStart(), Best)) { diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 0f66c45b26..1446d51ef7 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -624,12 +624,19 @@ bool Sema::InstantiateTemplatePattern(SourceLocation PointOfInstantiation, /// \param TemplateArgs The template arguments to be substituted into /// 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. bool Sema::InstantiateClass(SourceLocation PointOfInstantiation, CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern, const TemplateArgumentList &TemplateArgs, - bool ExplicitInstantiation) { + bool ExplicitInstantiation, + bool Complain) { bool Invalid = false; // Lazily instantiate member templates here. @@ -639,7 +646,9 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, CXXRecordDecl *PatternDef = cast_or_null(Pattern->getDefinition(Context)); if (!PatternDef) { - if (Pattern == Instantiation->getInstantiatedFromMemberClass()) { + if (!Complain) { + // Say nothing + } else if (Pattern == Instantiation->getInstantiatedFromMemberClass()) { Diag(PointOfInstantiation, diag::err_implicit_instantiate_member_undefined) << Context.getTypeDeclType(Instantiation); @@ -713,7 +722,8 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, bool Sema::InstantiateClassTemplateSpecialization( ClassTemplateSpecializationDecl *ClassTemplateSpec, - bool ExplicitInstantiation) { + bool ExplicitInstantiation, + bool Complain) { // Perform the actual instantiation on the canonical declaration. ClassTemplateSpec = cast( ClassTemplateSpec->getCanonicalDecl()); @@ -791,7 +801,8 @@ Sema::InstantiateClassTemplateSpecialization( bool Result = InstantiateClass(ClassTemplateSpec->getLocation(), ClassTemplateSpec, Pattern, *TemplateArgs, - ExplicitInstantiation); + ExplicitInstantiation, + Complain); for (unsigned I = 0, N = Matched.size(); I != N; ++I) { // FIXME: Implement TemplateArgumentList::Destroy! diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index db01ad094e..49946ac1c3 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -1752,7 +1752,8 @@ void Sema::ProcessTypeAttributeList(QualType &Result, const AttributeList *AL) { /// /// @param diag The diagnostic value (e.g., /// @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 /// part of the "incomplete type" error message. @@ -1792,7 +1793,8 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, unsigned diag, if (Loc.isValid()) ClassTemplateSpec->setLocation(Loc); return InstantiateClassTemplateSpecialization(ClassTemplateSpec, - /*ExplicitInstantiation=*/false); + /*ExplicitInstantiation=*/false, + /*Complain=*/diag != 0); } } else if (CXXRecordDecl *Rec = dyn_cast(Record->getDecl())) { @@ -1805,11 +1807,15 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, unsigned diag, Spec = dyn_cast(Parent); assert(Spec && "Not a member of a class template specialization?"); return InstantiateClass(Loc, Rec, Pattern, Spec->getTemplateArgs(), - /*ExplicitInstantiation=*/false); + /*ExplicitInstantiation=*/false, + /*Complain=*/diag != 0); } } } + if (diag == 0) + return true; + if (PrintType.isNull()) PrintType = T; diff --git a/test/SemaTemplate/instantiate-method.cpp b/test/SemaTemplate/instantiate-method.cpp index daea7465dc..f7c09ef879 100644 --- a/test/SemaTemplate/instantiate-method.cpp +++ b/test/SemaTemplate/instantiate-method.cpp @@ -72,3 +72,12 @@ void test_converts_to(ConvertsTo ci, ConvertsTo cip) { int i = ci; int *ip = cip; } + +// PR4660 +template struct A0 { operator T*(); }; +template struct A1; + +int *a(A0 &x0, A1 &x1) { + int *y0 = x0; + int *y1 = x1; // expected-error{{initializing}} +} -- 2.40.0