[cfe-commits] r79919 - in /cfe/trunk: 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

Douglas Gregor dgregor at apple.com
Mon Aug 24 08:23:48 PDT 2009


Author: dgregor
Date: Mon Aug 24 10:23:48 2009
New Revision: 79919

URL: http://llvm.org/viewvc/llvm-project?rev=79919&view=rev
Log:
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.

Modified:
    cfe/trunk/include/clang/AST/DeclCXX.h
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
    cfe/trunk/lib/Sema/SemaType.cpp
    cfe/trunk/test/SemaTemplate/instantiate-method.cpp

Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=79919&r1=79918&r2=79919&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Mon Aug 24 10:23:48 2009
@@ -549,9 +549,15 @@
   /// 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; 
   }
 

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=79919&r1=79918&r2=79919&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Mon Aug 24 10:23:48 2009
@@ -2875,12 +2875,13 @@
   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,

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=79919&r1=79918&r2=79919&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Mon Aug 24 10:23:48 2009
@@ -2847,7 +2847,8 @@
   //          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());

Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=79919&r1=79918&r2=79919&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Mon Aug 24 10:23:48 2009
@@ -1392,6 +1392,9 @@
 
   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 @@
   /// 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 @@
   /// 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 @@
     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 @@
   // 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 @@
   //   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);
-
-    // Skip over templated conversion functions; they aren't
-    // surrogates.
-    if (ConvTemplate)
-      continue;
+  
+  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;
 
-    // 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)) {

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=79919&r1=79918&r2=79919&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Mon Aug 24 10:23:48 2009
@@ -624,12 +624,19 @@
 /// \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 @@
   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 @@
 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 @@
 
   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!

Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=79919&r1=79918&r2=79919&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Mon Aug 24 10:23:48 2009
@@ -1752,7 +1752,8 @@
 ///
 /// @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 @@
         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 @@
           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;
 

Modified: cfe/trunk/test/SemaTemplate/instantiate-method.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/instantiate-method.cpp?rev=79919&r1=79918&r2=79919&view=diff

==============================================================================
--- cfe/trunk/test/SemaTemplate/instantiate-method.cpp (original)
+++ cfe/trunk/test/SemaTemplate/instantiate-method.cpp Mon Aug 24 10:23:48 2009
@@ -72,3 +72,12 @@
   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}}
+}





More information about the cfe-commits mailing list