[cfe-commits] r81576 - in /cfe/trunk: include/clang/AST/DeclCXX.h lib/AST/DeclCXX.cpp lib/Sema/SemaExprCXX.cpp test/SemaCXX/conversion-delete-expr.cpp

Douglas Gregor dgregor at apple.com
Fri Sep 11 15:37:06 PDT 2009


On Sep 11, 2009, at 2:44 PM, Fariborz Jahanian wrote:

> Author: fjahanian
> Date: Fri Sep 11 16:44:33 2009
> New Revision: 81576
>
> URL: http://llvm.org/viewvc/llvm-project?rev=81576&view=rev
> Log:
> Patch to build visible conversion function list lazily and make its
> first use in calling the conversion function on delete statements.

Cool.

> Added:
>    cfe/trunk/test/SemaCXX/conversion-delete-expr.cpp
> Modified:
>    cfe/trunk/include/clang/AST/DeclCXX.h
>    cfe/trunk/lib/AST/DeclCXX.cpp
>    cfe/trunk/lib/Sema/SemaExprCXX.cpp
>
> Modified: cfe/trunk/include/clang/AST/DeclCXX.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=81576&r1=81575&r2=81576&view=diff
>
> =
> =
> =
> =
> =
> =
> =
> =
> ======================================================================
> --- cfe/trunk/include/clang/AST/DeclCXX.h (original)
> +++ cfe/trunk/include/clang/AST/DeclCXX.h Fri Sep 11 16:44:33 2009
> @@ -367,9 +367,15 @@
>   /// Conversions - Overload set containing the conversion functions
>   /// of this C++ class (but not its inherited conversion
>   /// functions). Each of the entries in this overload set is a
> -  /// CXXConversionDecl.
> +  /// CXXConversionDecl.
>   OverloadedFunctionDecl Conversions;
>
> +  /// VisibleConversions - Overload set containing the conversion  
> functions
> +  /// of this C++ class and all those inherited conversion  
> functions that
> +  /// are visible in this class. Each of the entries in this  
> overload set is
> +  /// a CXXConversionDecl or a FunctionTemplateDecl.
> +  OverloadedFunctionDecl VisibleConversions;
> +
>   /// \brief The template or declaration that this declaration
>   /// describes or was instantiated from, respectively.
>   ///
> @@ -570,6 +576,20 @@
>     return &Conversions;
>   }
>
> +  /// getVisibleConversionFunctions - get all conversion functions  
> visible
> +  /// in current class; including conversion function templates.
> +  OverloadedFunctionDecl *getVisibleConversionFunctions(ASTContext  
> &Context,
> +                                                         
> CXXRecordDecl *RD);

The "RD" parameter is an implementation detail; it shouldn't leak into  
the interface. Please provide a version of  
getVisibleConversionFunctions that doesn't have this parameter, so  
that clients don't have to worry about it.

> +  /// addVisibleConversionFunction - Add a new conversion function  
> to the
> +  /// list of visible conversion functions.
> +  void addVisibleConversionFunction(ASTContext &Context,
> +                                    CXXConversionDecl *ConvDecl);
> +
> +  /// \brief Add a new conversion function template to the list of  
> visible
> +  /// conversion functions.
> +  void addVisibleConversionFunction(ASTContext &Context,
> +                                    FunctionTemplateDecl *ConvDecl);
> +

In all three of the new functions, you can remove the ASTContext  
parameter. Instead, use Decl::getASTContext().

> +/// getVisibleConversionFunctions - get all conversion functions  
> visible
> +/// in current class; including conversion function templates.
> +OverloadedFunctionDecl *
> +CXXRecordDecl::getVisibleConversionFunctions(ASTContext &Context,
> +                                             CXXRecordDecl *RD) {
> +  // If visible conversion list is already evaluated, return it.
> +  if (RD == this &&
> +      VisibleConversions.function_begin() !=  
> VisibleConversions.function_end())
> +    return &VisibleConversions;

Checking whether VisibleConversions is empty isn't the same as  
checking whether we've already tried to compute visible conversions.  
With this formulation, we could spend a lot of time traversing a class  
hierarchy that has no user-defined conversions anywhere in it. Why not  
have a ComputedVisibleConversions bit in the CXXRecordDecl?

> +  QualType ClassType = Context.getTypeDeclType(this);
> +  if (const RecordType *Record = ClassType->getAs<RecordType>()) {
> +    OverloadedFunctionDecl *Conversions
> +      = cast<CXXRecordDecl>(Record->getDecl())- 
> >getConversionFunctions();
> +    for (OverloadedFunctionDecl::function_iterator
> +         Func = Conversions->function_begin(),
> +         FuncEnd = Conversions->function_end();
> +         Func != FuncEnd; ++Func) {
> +      if (FunctionTemplateDecl *ConversionTemplate =
> +            dyn_cast<FunctionTemplateDecl>(*Func)) {
> +        RD->addVisibleConversionFunction(Context,  
> ConversionTemplate);
> +        continue;
> +      }

Conversion templates can shadow other conversion templates, too, e.g.,

   struct Base {
     template<typename T> operator T*() const;
   };

   struct Derived : Base {
     template<typename T> operator T*() const; // hides base conversion
   };

so we'll need to check that as well.

> +      CXXConversionDecl *Conv = cast<CXXConversionDecl>(*Func);
> +      bool Candidate = true;
> +      // Only those conversions not exact match of conversions in  
> current
> +      // class are candidateconversion routines.
> +      if (RD != this) {
> +        OverloadedFunctionDecl *TopConversions = RD- 
> >getConversionFunctions();
> +        QualType ConvType = Context.getCanonicalType(Conv->getType 
> ());
> +        for (OverloadedFunctionDecl::function_iterator
> +             TFunc = TopConversions->function_begin(),
> +             TFuncEnd = TopConversions->function_end();
> +             TFunc != TFuncEnd; ++TFunc) {
> +          CXXConversionDecl *TopConv = cast<CXXConversionDecl> 
> (*TFunc);

Can't *TFunc be a FunctionTemplateDecl? It looks like it from the code  
below, under

   if (Candidate)

> +          QualType TConvType = Context.getCanonicalType(TopConv- 
> >getType());
> +          if (ConvType == TConvType) {
> +            Candidate = false;
> +            break;
> +          }
> +        }
> +      }

This is an O(n^2) algorithm :(

Also, you'll need to check cv-qualifiers on the functions. For  
example, I don't think there's any hiding in this example:

   struct Base {
     operator int();
   };

   struct Derived : Base {
     operator int() const; // not the same function as Base's non- 
const operator int()
   };

Finally, there may be multiple bases with the same conversion. Both  
conversion functions need to show up, e.g.,

   struct Base1 {
     operator int();
   };

   struct Base2 {
     operator int();
   };

   struct Derived : Base1, Base2 {
     // two operator int()s are visible here
   };

   - Doug



More information about the cfe-commits mailing list