]> granicus.if.org Git - clang/commitdiff
Try to complete a type before looking for conversion functions within
authorDouglas Gregor <dgregor@apple.com>
Mon, 24 Aug 2009 15:23:48 +0000 (15:23 +0000)
committerDouglas Gregor <dgregor@apple.com>
Mon, 24 Aug 2009 15:23:48 +0000 (15:23 +0000)
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
lib/Sema/Sema.h
lib/Sema/SemaDeclCXX.cpp
lib/Sema/SemaOverload.cpp
lib/Sema/SemaTemplateInstantiate.cpp
lib/Sema/SemaType.cpp
test/SemaTemplate/instantiate-method.cpp

index 60db8c83349fbe84b79bdfe1dfef192ec56fbf3b..d09d054c08211c30f1ecb2329699c7249eb79156 100644 (file)
@@ -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<RecordType>(getTypeForDecl())->isBeingDefined()) &&
+           "getConversionFunctions() called on incomplete type");
     return &Conversions; 
   }
   const OverloadedFunctionDecl *getConversionFunctions() const { 
+    assert((this->isDefinition() || 
+            cast<RecordType>(getTypeForDecl())->isBeingDefined()) &&
+           "getConversionFunctions() called on incomplete type");
     return &Conversions; 
   }
 
index 1d61992d7c1cd1a7d0311307ef12d54f6a049816..b7b70bfc44ee6b389cb45e4dbcb74bc9fa11745e 100644 (file)
@@ -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,
index 462999b0a57581e2bb56699b1f6fb22d490dbc88..ea113301aa7cf9c8de9724e809d05b75ebbcbcd4 100644 (file)
@@ -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<CXXRecordDecl>(T2->getAs<RecordType>()->getDecl());
index 0a65a36b47bb17e8f80eeb8b553e13c8a8a1fd73..152d4adf88f7db4816ea0fefef70242f0fd606f3 100644 (file)
@@ -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<RecordType>()) {
     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<RecordType>()) {
+      if (SemaRef.RequireCompleteType(SourceLocation(), Ty, 0)) {
+        // No conversion functions in incomplete types.
+        return;
+      }
+      
       CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(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<CXXRecordDecl>(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<CXXRecordDecl>(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<PointerType>())
-      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<PointerType>())
+        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)) {
index 0f66c45b263ac437dbaff3e42130221f8cee78ee..1446d51ef7d667b437824cc5ac552d69d3113be1 100644 (file)
@@ -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<CXXRecordDecl>(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<ClassTemplateSpecializationDecl>(
                                          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!
index db01ad094eb3a127505ae823151552bf43786f8d..49946ac1c367b1070eb056c9928451262164c1fd 100644 (file)
@@ -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<CXXRecordDecl>(Record->getDecl())) {
@@ -1805,11 +1807,15 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, unsigned diag,
           Spec = dyn_cast<ClassTemplateSpecializationDecl>(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;
 
index daea7465dc121abc7105c8bb482100716cd01d3c..f7c09ef87900813841fc3c2f10370a93269ca5d8 100644 (file)
@@ -72,3 +72,12 @@ void test_converts_to(ConvertsTo<int> ci, ConvertsTo<int *> cip) {
   int i = ci;
   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}}
+}