[cfe-commits] r58860 - in /cfe/trunk: include/clang/AST/DeclBase.h include/clang/AST/DeclCXX.h include/clang/Basic/DiagnosticKinds.def include/clang/Parse/Action.h include/clang/Parse/DeclSpec.h include/clang/Parse/Parser.h lib/AST/DeclBase.cpp lib/AST/DeclCXX.cpp lib/Parse/ParseDecl.cpp lib/Parse/ParseExprCXX.cpp lib/Sema/Sema.h lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclCXX.cpp test/SemaCXX/conversion-function.cpp

Douglas Gregor doug.gregor at gmail.com
Fri Nov 7 12:08:42 PST 2008


Author: dgregor
Date: Fri Nov  7 14:08:42 2008
New Revision: 58860

URL: http://llvm.org/viewvc/llvm-project?rev=58860&view=rev
Log:
Parsing, ASTs, and semantic analysis for the declaration of conversion
functions in C++, e.g.,

  struct X {
    operator bool() const;
  };

Note that these conversions don't actually do anything, since we don't
yet have the ability to use them for implicit or explicit conversions.


Added:
    cfe/trunk/test/SemaCXX/conversion-function.cpp   (with props)
Modified:
    cfe/trunk/include/clang/AST/DeclBase.h
    cfe/trunk/include/clang/AST/DeclCXX.h
    cfe/trunk/include/clang/Basic/DiagnosticKinds.def
    cfe/trunk/include/clang/Parse/Action.h
    cfe/trunk/include/clang/Parse/DeclSpec.h
    cfe/trunk/include/clang/Parse/Parser.h
    cfe/trunk/lib/AST/DeclBase.cpp
    cfe/trunk/lib/AST/DeclCXX.cpp
    cfe/trunk/lib/Parse/ParseDecl.cpp
    cfe/trunk/lib/Parse/ParseExprCXX.cpp
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp

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

==============================================================================
--- cfe/trunk/include/clang/AST/DeclBase.h (original)
+++ cfe/trunk/include/clang/AST/DeclBase.h Fri Nov  7 14:08:42 2008
@@ -68,6 +68,7 @@
                  CXXMethod,
                    CXXConstructor,
                    CXXDestructor,
+                   CXXConversion,
                Var,
                  ImplicitParam,
                  CXXClassVar,
@@ -91,7 +92,7 @@
     TagFirst       = Enum         , TagLast       = CXXRecord,
     RecordFirst    = Record       , RecordLast    = CXXRecord,
     ValueFirst     = EnumConstant , ValueLast     = ParmVar,
-    FunctionFirst  = Function     , FunctionLast  = CXXDestructor,
+    FunctionFirst  = Function     , FunctionLast  = CXXConversion,
     VarFirst       = Var          , VarLast       = ParmVar
   };
 

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

==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Fri Nov  7 14:08:42 2008
@@ -21,6 +21,7 @@
 class CXXRecordDecl;
 class CXXConstructorDecl;
 class CXXDestructorDecl;
+class CXXConversionDecl;
 
 /// OverloadedFunctionDecl - An instance of this class represents a
 /// set of overloaded functions. All of the functions have the same
@@ -53,8 +54,9 @@
   void addOverload(FunctionDecl *FD) {
     assert((!getNumFunctions() || (FD->getDeclContext() == getDeclContext())) &&
            "Overloaded functions must all be in the same context");
-    assert(FD->getIdentifier() == getIdentifier() &&
-           "Overloaded functions must have the same name.");
+    assert((FD->getIdentifier() == getIdentifier() ||
+            isa<CXXConversionDecl>(FD)) &&
+           "Overloaded functions must have the same name or be conversions.");
     Functions.push_back(FD);
   }
 
@@ -238,12 +240,18 @@
   // Destructor - The destructor of this C++ class.
   CXXDestructorDecl *Destructor;
 
+  /// 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.
+  OverloadedFunctionDecl Conversions;
+
   CXXRecordDecl(TagKind TK, DeclContext *DC,
                 SourceLocation L, IdentifierInfo *Id) 
     : RecordDecl(CXXRecord, TK, DC, L, Id), DeclContext(CXXRecord),
       UserDeclaredConstructor(false), UserDeclaredCopyConstructor(false),
       Aggregate(true), Polymorphic(false), Bases(0), NumBases(0),
-      Constructors(DC, Id), Destructor(0) { }
+      Constructors(DC, Id), Destructor(0), Conversions(DC, Id) { }
 
   ~CXXRecordDecl();
 
@@ -321,6 +329,19 @@
     this->Destructor = Destructor;
   }
 
+  /// getConversions - Retrieve the overload set containing all of the
+  /// conversion functions in this class.
+  OverloadedFunctionDecl *getConversionFunctions() { 
+    return &Conversions; 
+  }
+  const OverloadedFunctionDecl *getConversionFunctions() const { 
+    return &Conversions; 
+  }
+
+  /// addConversionFunction - Add a new conversion function to the
+  /// list of conversion functions.
+  void addConversionFunction(ASTContext &Context, CXXConversionDecl *ConvDecl);
+
   /// isAggregate - Whether this class is an aggregate (C++
   /// [dcl.init.aggr]), which is a class with no user-declared
   /// constructors, no private or protected non-static data members,
@@ -418,7 +439,7 @@
 
   // Implement isa/cast/dyncast/etc.
   static bool classof(const Decl *D) { 
-    return D->getKind() >= CXXMethod && D->getKind() <= CXXConstructor;
+    return D->getKind() >= CXXMethod && D->getKind() <= CXXConversion;
   }
   static bool classof(const CXXMethodDecl *D) { return true; }
 
@@ -720,6 +741,60 @@
   static CXXDestructorDecl* CreateImpl(llvm::Deserializer& D, ASTContext& C);
 };
 
+/// CXXConversionDecl - Represents a C++ conversion function within a
+/// class. For example:
+/// 
+/// @code
+/// class X {
+/// public:
+///   operator bool();
+/// };
+/// @endcode
+class CXXConversionDecl : public CXXMethodDecl {
+  /// Explicit - Whether this conversion function is marked
+  /// "explicit", meaning that it can only be applied when the user
+  /// explicitly wrote a cast. This is a C++0x feature.
+  bool Explicit : 1;
+
+  CXXConversionDecl(CXXRecordDecl *RD, SourceLocation L,
+                    IdentifierInfo *Id, QualType T, 
+                    bool isInline, bool isExplicit)
+    : CXXMethodDecl(CXXConversion, RD, L, Id, T, false, isInline, 
+                    /*PrevDecl=*/0),
+      Explicit(isExplicit) { }
+
+public:
+  static CXXConversionDecl *Create(ASTContext &C, CXXRecordDecl *RD,
+                                   SourceLocation L, IdentifierInfo *Id,
+                                   QualType T, bool isInline, 
+                                   bool isExplicit);
+
+  /// isExplicit - Whether this is an explicit conversion operator
+  /// (C++0x only). Explicit conversion operators are only considered
+  /// when the user has explicitly written a cast.
+  bool isExplicit() const { return Explicit; }
+
+  /// getConversionType - Returns the type that this conversion
+  /// function is converting to.
+  QualType getConversionType() const { 
+    return getType()->getAsFunctionType()->getResultType(); 
+  }
+
+  // Implement isa/cast/dyncast/etc.
+  static bool classof(const Decl *D) { 
+    return D->getKind() == CXXConversion;
+  }
+  static bool classof(const CXXConversionDecl *D) { return true; }
+
+  /// EmitImpl - Serialize this CXXConversionDecl.  Called by Decl::Emit.
+  // FIXME: Implement this.
+  //virtual void EmitImpl(llvm::Serializer& S) const;
+  
+  /// CreateImpl - Deserialize a CXXConversionDecl.  Called by Decl::Create.
+  // FIXME: Implement this.
+  static CXXConversionDecl* CreateImpl(llvm::Deserializer& D, ASTContext& C);
+};
+
 /// CXXClassVarDecl - Represents a static data member of a struct/union/class.
 class CXXClassVarDecl : public VarDecl {
 

Modified: cfe/trunk/include/clang/Basic/DiagnosticKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticKinds.def?rev=58860&r1=58859&r2=58860&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticKinds.def (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticKinds.def Fri Nov  7 14:08:42 2008
@@ -1309,6 +1309,31 @@
      "overloaded operator '%0' must be a non-static member function")
 DIAG(err_operator_overload_post_incdec_must_be_int, ERROR,
      "%0parameter of overloaded post-%1 operator must have type 'int' (not '%2')")
+DIAG(err_operator_missing_type_specifier, ERROR,
+     "missing type specifier after 'operator'")
+
+// C++ conversion functions
+DIAG(err_conv_function_not_member, ERROR,
+     "conversion function must be a non-static member function")
+DIAG(err_conv_function_return_type, ERROR,
+     "conversion function cannot have a return type")
+DIAG(err_conv_function_with_params, ERROR,
+     "conversion function cannot have any parameters")
+DIAG(err_conv_function_variadic, ERROR,
+     "conversion function cannot be variadic")
+DIAG(err_conv_function_to_array, ERROR,
+     "conversion function cannot convert to an array type")
+DIAG(err_conv_function_to_function, ERROR,
+     "conversion function cannot convert to a function type")
+DIAG(err_conv_function_redeclared, ERROR,
+     "conversion function cannot be redeclared")
+DIAG(warn_conv_to_self_not_used, WARNING,
+     "conversion function converting '%0' to itself will never be used")
+DIAG(warn_conv_to_base_not_used, WARNING,
+     "conversion function converting '%0' to its base class '%1' will never be used")
+DIAG(warn_conv_to_void_not_used, WARNING,
+     "conversion function converting '%0' to '%1' will never be used")
+
 
 DIAG(warn_not_compound_assign, WARNING,
      "use of unary operator that may be intended as compound assignment (%0=)")

Modified: cfe/trunk/include/clang/Parse/Action.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Action.h?rev=58860&r1=58859&r2=58860&view=diff

==============================================================================
--- cfe/trunk/include/clang/Parse/Action.h (original)
+++ cfe/trunk/include/clang/Parse/Action.h Fri Nov  7 14:08:42 2008
@@ -42,9 +42,10 @@
 /// the parser has just done or is about to do when the method is called.  They
 /// are not requests that the actions module do the specified action.
 ///
-/// All of the methods here are optional except isTypeName(), which must be
-/// specified in order for the parse to complete accurately.  The MinimalAction
-/// class does this bare-minimum of tracking to implement this functionality.
+/// All of the methods here are optional except isTypeName() and
+/// isCurrentClassName(), which must be specified in order for the
+/// parse to complete accurately.  The MinimalAction class does this
+/// bare-minimum of tracking to implement this functionality.
 class Action {
 public:
   /// Out-of-line virtual destructor to provide home for this class.
@@ -108,6 +109,14 @@
   /// name of the innermost C++ class type currently being defined.
   virtual bool isCurrentClassName(const IdentifierInfo &II, Scope *S) = 0;
 
+  /// getTypeAsString - Returns a string that describes the given
+  /// type. This callback is used in C++ to form identifiers for
+  /// special declarations that otherwise don't have simple names,
+  /// such as constructors, destructors, and conversion functions.
+  virtual std::string getTypeAsString(TypeTy *Type) {
+    return "<unknown type>";
+  }
+
   /// ActOnDeclarator - This callback is invoked when a declarator is parsed and
   /// 'Init' specifies the initializer if any.  This is for things like:
   /// "int X = 4" or "typedef int foo".

Modified: cfe/trunk/include/clang/Parse/DeclSpec.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/DeclSpec.h?rev=58860&r1=58859&r2=58860&view=diff

==============================================================================
--- cfe/trunk/include/clang/Parse/DeclSpec.h (original)
+++ cfe/trunk/include/clang/Parse/DeclSpec.h Fri Nov  7 14:08:42 2008
@@ -610,7 +610,9 @@
     DK_Abstract,         // An abstract declarator (has no identifier)
     DK_Normal,           // A normal declarator (has an identifier). 
     DK_Constructor,      // A C++ constructor (identifier is the class name)
-    DK_Destructor        // A C++ destructor  (has no identifier)
+    DK_Destructor,       // A C++ destructor  (identifier is ~class name)
+    DK_Conversion        // A C++ conversion function (identifier is 
+                         // "operator " then the type name)
   };
 
 private:
@@ -639,8 +641,9 @@
   /// AsmLabel - The asm label, if specified.
   Action::ExprTy *AsmLabel;
 
-  // When Kind is DK_Constructor or DK_Destructor, the type associated
-  // with the constructor or destructor.
+  // When Kind is DK_Constructor, DK_Destructor, or DK_Conversion, the
+  // type associated with the constructor, destructor, or conversion
+  // operator.
   Action::TypeTy *Type;
 
 public:
@@ -755,6 +758,16 @@
     Type = Ty;
   }
 
+  // SetConversionFunction - Set this declarator to be a C++
+  // conversion function declarator.
+  void SetConversionFunction(Action::TypeTy *Ty, IdentifierInfo *ID, 
+                             SourceLocation Loc) {
+    Identifier = ID;
+    IdentifierLoc = Loc;
+    Kind = DK_Conversion;
+    Type = Ty;
+  }
+
   void AddTypeInfo(const DeclaratorChunk &TI) {
     DeclTypeInfo.push_back(TI);
   }

Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=58860&r1=58859&r2=58860&view=diff

==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Fri Nov  7 14:08:42 2008
@@ -475,6 +475,8 @@
   /// simple-type-specifier.
   void ParseCXXSimpleTypeSpecifier(DeclSpec &DS);
 
+  bool ParseCXXTypeSpecifierSeq(DeclSpec &DS);
+
   //===--------------------------------------------------------------------===//
   // C++ if/switch/while/for condition expression.
   ExprResult ParseCXXCondition();
@@ -701,7 +703,7 @@
   
   /// ParseDeclarator - Parse and verify a newly-initialized declarator.
   void ParseDeclarator(Declarator &D);
-  void ParseDeclaratorInternal(Declarator &D);
+  void ParseDeclaratorInternal(Declarator &D, bool PtrOperator = false);
   void ParseTypeQualifierListOpt(DeclSpec &DS);
   void ParseDirectDeclarator(Declarator &D);
   void ParseParenDeclarator(Declarator &D);
@@ -737,6 +739,7 @@
   //===--------------------------------------------------------------------===//
   // C++ 13.5: Overloaded operators [over.oper]
   IdentifierInfo *MaybeParseOperatorFunctionId();
+  TypeTy *ParseConversionFunctionId();
 };
 
 }  // end namespace clang

Modified: cfe/trunk/lib/AST/DeclBase.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclBase.cpp?rev=58860&r1=58859&r2=58860&view=diff

==============================================================================
--- cfe/trunk/lib/AST/DeclBase.cpp (original)
+++ cfe/trunk/lib/AST/DeclBase.cpp Fri Nov  7 14:08:42 2008
@@ -239,6 +239,7 @@
   case CXXMethod:
   case CXXConstructor:
   case CXXDestructor:
+  case CXXConversion:
   case CXXClassVar:
     break;
   }

Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=58860&r1=58859&r2=58860&view=diff

==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Fri Nov  7 14:08:42 2008
@@ -48,6 +48,11 @@
   if (isDefinition())
     Destructor->Destroy(C);
 
+  for (OverloadedFunctionDecl::function_iterator func 
+         = Conversions.function_begin();
+       func != Conversions.function_end(); ++func)
+    (*func)->Destroy(C);
+
   RecordDecl::Destroy(C);
 }
 
@@ -101,6 +106,11 @@
   Constructors.addOverload(ConDecl);
 }
 
+void CXXRecordDecl::addConversionFunction(ASTContext &Context, 
+                                          CXXConversionDecl *ConvDecl) {
+  Conversions.addOverload(ConvDecl);
+}
+
 CXXMethodDecl *
 CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD,
                       SourceLocation L, IdentifierInfo *Id,
@@ -232,6 +242,14 @@
                                      isImplicitlyDeclared);
 }
 
+CXXConversionDecl *
+CXXConversionDecl::Create(ASTContext &C, CXXRecordDecl *RD,
+                          SourceLocation L, IdentifierInfo *Id,
+                          QualType T, bool isInline, bool isExplicit) {
+  void *Mem = C.getAllocator().Allocate<CXXConversionDecl>();
+  return new (Mem) CXXConversionDecl(RD, L, Id, T, isInline, isExplicit);
+}
+
 CXXClassVarDecl *CXXClassVarDecl::Create(ASTContext &C, CXXRecordDecl *RD,
                                    SourceLocation L, IdentifierInfo *Id,
                                    QualType T, ScopedDecl *PrevDecl) {

Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=58860&r1=58859&r2=58860&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Fri Nov  7 14:08:42 2008
@@ -1229,7 +1229,11 @@
   ParseDeclaratorInternal(D);
 }
 
-/// ParseDeclaratorInternal
+/// ParseDeclaratorInternal - Parse a C or C++ declarator. If
+/// PtrOperator is true, then this routine won't parse the final
+/// direct-declarator; therefore, it effectively parses the C++
+/// ptr-operator production.
+///
 ///       declarator: [C99 6.7.5]
 ///         pointer[opt] direct-declarator
 /// [C++]   '&' declarator [C++ 8p4, dcl.decl]
@@ -1239,13 +1243,21 @@
 ///         '*' type-qualifier-list[opt]
 ///         '*' type-qualifier-list[opt] pointer
 ///
-void Parser::ParseDeclaratorInternal(Declarator &D) {
+///       ptr-operator:
+///         '*' cv-qualifier-seq[opt]
+///         '&'
+/// [GNU]   '&' restrict[opt] attributes[opt]
+///         '::'[opt] nested-name-specifier '*' cv-qualifier-seq[opt] [TODO]
+void Parser::ParseDeclaratorInternal(Declarator &D, bool PtrOperator) {
   tok::TokenKind Kind = Tok.getKind();
 
   // Not a pointer, C++ reference, or block.
   if (Kind != tok::star && (Kind != tok::amp || !getLang().CPlusPlus) &&
-      (Kind != tok::caret || !getLang().Blocks))
-    return ParseDirectDeclarator(D);
+      (Kind != tok::caret || !getLang().Blocks)) {
+    if (!PtrOperator)
+      ParseDirectDeclarator(D);
+    return;
+  }
   
   // Otherwise, '*' -> pointer, '^' -> block, '&' -> reference.
   SourceLocation Loc = ConsumeToken();  // Eat the * or &.
@@ -1257,7 +1269,7 @@
     ParseTypeQualifierListOpt(DS);
   
     // Recursively parse the declarator.
-    ParseDeclaratorInternal(D);
+    ParseDeclaratorInternal(D, PtrOperator);
     if (Kind == tok::star)
       // Remember that we parsed a pointer type, and remember the type-quals.
       D.AddTypeInfo(DeclaratorChunk::getPointer(DS.getTypeQualifiers(), Loc,
@@ -1290,7 +1302,7 @@
     }
 
     // Recursively parse the declarator.
-    ParseDeclaratorInternal(D);
+    ParseDeclaratorInternal(D, PtrOperator);
 
     if (D.getNumTypeObjects() > 0) {
       // C++ [dcl.ref]p4: There shall be no references to references.
@@ -1382,7 +1394,13 @@
     if (IdentifierInfo *II = MaybeParseOperatorFunctionId()) {
       D.SetIdentifier(II, OperatorLoc);
     } else {
-      // This must be a user-defined conversion.
+      // This must be a conversion function (C++ [class.conv.fct]).
+      if (TypeTy *ConvType = ParseConversionFunctionId()) {
+        IdentifierInfo *II 
+          = &PP.getIdentifierTable().get(std::string("operator ") + 
+                                         Actions.getTypeAsString(ConvType));
+        D.SetConversionFunction(ConvType, II, OperatorLoc);
+      }
     }
   } else if (Tok.is(tok::l_paren)) {
     // direct-declarator: '(' declarator ')'

Modified: cfe/trunk/lib/Parse/ParseExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExprCXX.cpp?rev=58860&r1=58859&r2=58860&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/ParseExprCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExprCXX.cpp Fri Nov  7 14:08:42 2008
@@ -292,6 +292,32 @@
   DS.Finish(Diags, PP.getSourceManager(), getLang());
 }
 
+/// ParseCXXTypeSpecifierSeq - Parse a C++ type-specifier-seq (C++
+/// [dcl.name]), which is a non-empty sequence of type-specifiers,
+/// e.g., "const short int". Note that the DeclSpec is *not* finished
+/// by parsing the type-specifier-seq, because these sequences are
+/// typically followed by some form of declarator. Returns true and
+/// emits diagnostics if this is not a type-specifier-seq, false
+/// otherwise.
+///
+///   type-specifier-seq: [C++ 8.1]
+///     type-specifier type-specifier-seq[opt]
+///
+bool Parser::ParseCXXTypeSpecifierSeq(DeclSpec &DS) {
+  DS.SetRangeStart(Tok.getLocation());
+  const char *PrevSpec = 0;
+  int isInvalid = 0;
+
+  // Parse one or more of the type specifiers.
+  if (!MaybeParseTypeSpecifier(DS, isInvalid, PrevSpec)) {
+    Diag(Tok.getLocation(), diag::err_operator_missing_type_specifier);
+    return true;
+  }
+  while (MaybeParseTypeSpecifier(DS, isInvalid, PrevSpec));
+
+  return false;
+}
+
 /// MaybeParseOperatorFunctionId - Attempts to parse a C++ overloaded
 /// operator name (C++ [over.oper]). If successful, returns the
 /// predefined identifier that corresponds to that overloaded
@@ -365,3 +391,38 @@
     return &PP.getIdentifierTable().getOverloadedOperator(Op);
   }
 }
+
+/// ParseConversionFunctionId - Parse a C++ conversion-function-id,
+/// which expresses the name of a user-defined conversion operator
+/// (C++ [class.conv.fct]p1). Returns the type that this operator is
+/// specifying a conversion for, or NULL if there was an error.
+///
+///        conversion-function-id: [C++ 12.3.2]
+///                   operator conversion-type-id
+///
+///        conversion-type-id:
+///                   type-specifier-seq conversion-declarator[opt]
+///
+///        conversion-declarator:
+///                   ptr-operator conversion-declarator[opt]
+Parser::TypeTy *Parser::ParseConversionFunctionId() {
+  assert(Tok.is(tok::kw_operator) && "Expected 'operator' keyword");
+  ConsumeToken(); // 'operator'
+
+  // Parse the type-specifier-seq.
+  DeclSpec DS;
+  if (ParseCXXTypeSpecifierSeq(DS))
+    return 0;
+
+  // Parse the conversion-declarator, which is merely a sequence of
+  // ptr-operators.
+  Declarator D(DS, Declarator::TypeNameContext);
+  ParseDeclaratorInternal(D, /*PtrOperator=*/true);
+
+  // Finish up the type.
+  Action::TypeResult Result = Actions.ActOnTypeName(CurScope, D);
+  if (Result.isInvalid)
+    return 0;
+  else
+    return Result.Val;
+}

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

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Fri Nov  7 14:08:42 2008
@@ -271,6 +271,7 @@
   // Symbol table / Decl tracking callbacks: SemaDecl.cpp.
   //
   virtual TypeTy *isTypeName(const IdentifierInfo &II, Scope *S);
+  virtual std::string getTypeAsString(TypeTy *Type);
   virtual DeclTy *ActOnDeclarator(Scope *S, Declarator &D, DeclTy *LastInGroup);
   virtual DeclTy *ActOnParamDeclarator(Scope *S, Declarator &D);
   virtual void ActOnParamDefaultArgument(DeclTy *param, 
@@ -845,8 +846,11 @@
                                   FunctionDecl::StorageClass& SC);
   bool CheckDestructorDeclarator(Declarator &D, QualType &R,
                                  FunctionDecl::StorageClass& SC);
+  bool CheckConversionDeclarator(Declarator &D, QualType &R,
+                                 FunctionDecl::StorageClass& SC);
   DeclTy *ActOnConstructorDeclarator(CXXConstructorDecl *Constructor);
   DeclTy *ActOnDestructorDeclarator(CXXDestructorDecl *Destructor);
+  DeclTy *ActOnConversionDeclarator(CXXConversionDecl *Conversion);
 
   //===--------------------------------------------------------------------===//
   // C++ Derived Classes

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Fri Nov  7 14:08:42 2008
@@ -38,6 +38,11 @@
   return 0;
 }
 
+std::string Sema::getTypeAsString(TypeTy *Type) {
+  QualType Ty = QualType::getFromOpaquePtr(Type);
+  return Ty.getAsString();
+}
+
 DeclContext *Sema::getDCParent(DeclContext *DC) {
   // If CurContext is a ObjC method, getParent() will return NULL.
   if (isa<ObjCMethodDecl>(DC))
@@ -835,6 +840,22 @@
 
       if (isInvalidDecl)
         NewFD->setInvalidDecl();
+    } else if (D.getKind() == Declarator::DK_Conversion) {
+      if (D.getContext() != Declarator::MemberContext) {
+        Diag(D.getIdentifierLoc(),
+             diag::err_conv_function_not_member);
+        return 0;
+      } else {
+        bool isInvalidDecl = CheckConversionDeclarator(D, R, SC);
+
+        NewFD = CXXConversionDecl::Create(Context, 
+                                          cast<CXXRecordDecl>(CurContext),
+                                          D.getIdentifierLoc(), II, R,
+                                          isInline, isExplicit);
+        
+        if (isInvalidDecl)
+          NewFD->setInvalidDecl();
+      }
     } else if (D.getContext() == Declarator::MemberContext) {
       // This is a C++ method declaration.
       NewFD = CXXMethodDecl::Create(Context, cast<CXXRecordDecl>(CurContext),
@@ -931,6 +952,8 @@
       return ActOnConstructorDeclarator(Constructor);
     else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(NewFD))
       return ActOnDestructorDeclarator(Destructor);
+    else if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(NewFD))
+      return ActOnConversionDeclarator(Conversion);
 
     // Extra checking for C++ overloaded operators (C++ [over.oper]).
     if (NewFD->isOverloadedOperator() &&

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Fri Nov  7 14:08:42 2008
@@ -1004,6 +1004,82 @@
   return isInvalid;
 }
 
+/// CheckConversionDeclarator - Called by ActOnDeclarator to check the
+/// well-formednes of the conversion function declarator @p D with
+/// type @p R. If there are any errors in the declarator, this routine
+/// will emit diagnostics and return true. Otherwise, it will return
+/// false. Either way, the type @p R will be updated to reflect a
+/// well-formed type for the conversion operator.
+bool Sema::CheckConversionDeclarator(Declarator &D, QualType &R,
+                                     FunctionDecl::StorageClass& SC) {
+  bool isInvalid = false;
+
+  // C++ [class.conv.fct]p1:
+  //   Neither parameter types nor return type can be specified. The
+  //   type of a conversion function (8.3.5) is “function taking no
+  //   parameter returning conversion-type-id.” 
+  if (SC == FunctionDecl::Static) {
+    Diag(D.getIdentifierLoc(),
+         diag::err_conv_function_not_member,
+         "static",
+         SourceRange(D.getDeclSpec().getStorageClassSpecLoc()),
+         SourceRange(D.getIdentifierLoc()));
+    isInvalid = true;
+    SC = FunctionDecl::None;
+  }
+  if (D.getDeclSpec().hasTypeSpecifier()) {
+    // Conversion functions don't have return types, but the parser will
+    // happily parse something like:
+    //
+    //   class X {
+    //     float operator bool();
+    //   };
+    //
+    // The return type will be changed later anyway.
+    Diag(D.getIdentifierLoc(),
+         diag::err_conv_function_return_type,
+         SourceRange(D.getDeclSpec().getTypeSpecTypeLoc()),
+         SourceRange(D.getIdentifierLoc()));
+  }
+
+  // Make sure we don't have any parameters.
+  if (R->getAsFunctionTypeProto()->getNumArgs() > 0) {
+    Diag(D.getIdentifierLoc(), diag::err_conv_function_with_params);
+
+    // Delete the parameters.
+    DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun;
+    if (FTI.NumArgs) {
+      delete [] FTI.ArgInfo;
+      FTI.NumArgs = 0;
+      FTI.ArgInfo = 0;
+    }
+  }
+
+  // Make sure the conversion function isn't variadic.  
+  if (R->getAsFunctionTypeProto()->isVariadic())
+    Diag(D.getIdentifierLoc(), diag::err_conv_function_variadic);
+
+  // C++ [class.conv.fct]p4:
+  //   The conversion-type-id shall not represent a function type nor
+  //   an array type.
+  QualType ConvType = QualType::getFromOpaquePtr(D.getDeclaratorIdType());
+  if (ConvType->isArrayType()) {
+    Diag(D.getIdentifierLoc(), diag::err_conv_function_to_array);
+    ConvType = Context.getPointerType(ConvType);
+  } else if (ConvType->isFunctionType()) {
+    Diag(D.getIdentifierLoc(), diag::err_conv_function_to_function);
+    ConvType = Context.getPointerType(ConvType);
+  }
+
+  // Rebuild the function type "R" without any parameters (in case any
+  // of the errors above fired) and with the conversion type as the
+  // return type. 
+  R = Context.getFunctionType(ConvType, 0, 0, false, 
+                              R->getAsFunctionTypeProto()->getTypeQuals());
+
+  return isInvalid;
+}
+
 /// ActOnConstructorDeclarator - Called by ActOnDeclarator to complete
 /// the declaration of the given C++ constructor ConDecl that was
 /// built from declarator D. This routine is responsible for checking
@@ -1092,6 +1168,65 @@
   return (DeclTy *)Destructor;
 }
 
+/// ActOnConversionDeclarator - Called by ActOnDeclarator to complete
+/// the declaration of the given C++ conversion function. This routine
+/// is responsible for recording the conversion function in the C++
+/// class, if possible.
+Sema::DeclTy *Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) {
+  assert(Conversion && "Expected to receive a conversion function declaration");
+
+  CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(CurContext);
+
+  // Make sure we aren't redeclaring the conversion function.
+  QualType ConvType = Context.getCanonicalType(Conversion->getConversionType());
+  OverloadedFunctionDecl *Conversions = ClassDecl->getConversionFunctions();
+  for (OverloadedFunctionDecl::function_iterator Func 
+         = Conversions->function_begin();
+       Func != Conversions->function_end(); ++Func) {
+    CXXConversionDecl *OtherConv = cast<CXXConversionDecl>(*Func);
+    if (ConvType == Context.getCanonicalType(OtherConv->getConversionType())) {
+      Diag(Conversion->getLocation(), diag::err_conv_function_redeclared);
+      Diag(OtherConv->getLocation(),
+           OtherConv->isThisDeclarationADefinition()?
+              diag::err_previous_definition
+            : diag::err_previous_declaration);
+      Conversion->setInvalidDecl();
+      return (DeclTy *)Conversion;      
+    }
+  }
+
+  // C++ [class.conv.fct]p1:
+  //   [...] A conversion function is never used to convert a
+  //   (possibly cv-qualified) object to the (possibly cv-qualified)
+  //   same object type (or a reference to it), to a (possibly
+  //   cv-qualified) base class of that type (or a reference to it),
+  //   or to (possibly cv-qualified) void.
+  // FIXME: Suppress this warning if the conversion function ends up
+  // being a virtual function that overrides a virtual function in a 
+  // base class.
+  QualType ClassType 
+    = Context.getCanonicalType(Context.getTypeDeclType(ClassDecl));
+  if (const ReferenceType *ConvTypeRef = ConvType->getAsReferenceType())
+    ConvType = ConvTypeRef->getPointeeType();
+  if (ConvType->isRecordType()) {
+    ConvType = Context.getCanonicalType(ConvType).getUnqualifiedType();
+    if (ConvType == ClassType)
+      Diag(Conversion->getLocation(), diag::warn_conv_to_self_not_used,
+           ClassType.getAsString());
+    else if (IsDerivedFrom(ClassType, ConvType))
+      Diag(Conversion->getLocation(), diag::warn_conv_to_base_not_used,
+           ClassType.getAsString(),
+           ConvType.getAsString());
+  } else if (ConvType->isVoidType()) {
+    Diag(Conversion->getLocation(), diag::warn_conv_to_void_not_used,
+         ClassType.getAsString(), ConvType.getAsString());
+  }
+
+  ClassDecl->addConversionFunction(Context, Conversion);
+
+  return (DeclTy *)Conversion;
+}
+
 //===----------------------------------------------------------------------===//
 // Namespace Handling
 //===----------------------------------------------------------------------===//

Added: cfe/trunk/test/SemaCXX/conversion-function.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/conversion-function.cpp?rev=58860&view=auto

==============================================================================
--- cfe/trunk/test/SemaCXX/conversion-function.cpp (added)
+++ cfe/trunk/test/SemaCXX/conversion-function.cpp Fri Nov  7 14:08:42 2008
@@ -0,0 +1,42 @@
+// RUN: clang -fsyntax-only -verify %s 
+class X { 
+public:
+  operator bool();
+  operator int() const;
+};
+
+operator int(); // expected-error{{conversion function must be a non-static member function}}
+
+typedef int func_type(int);
+typedef int array_type[10];
+
+class Y {
+public:
+  void operator bool(int, ...) const; // expected-error{{conversion function cannot have a return type}} \
+  // expected-error{{conversion function cannot have any parameters}} \
+  // expected-error{{conversion function cannot be variadic}}
+  operator func_type(); // expected-error{{conversion function cannot convert to a function type}}
+  operator array_type(); // expected-error{{conversion function cannot convert to an array type}}
+};
+
+
+typedef int INT;
+typedef INT* INT_PTR;
+
+class Z { 
+  operator int(); // expected-error{{previous declaration is here}}
+  operator int**(); // expected-error{{previous declaration is here}}
+  
+  operator INT();  // expected-error{{conversion function cannot be redeclared}}
+  operator INT_PTR*(); // expected-error{{conversion function cannot be redeclared}}
+};
+
+
+class A { };
+
+class B : public A {
+public:
+  operator A&() const; // expected-warning{{conversion function converting 'class B' to its base class 'class A' will never be used}}
+  operator const void() const; // expected-warning{{conversion function converting 'class B' to 'void const' will never be used}}
+  operator const B(); // expected-warning{{conversion function converting 'class B' to itself will never be used}}
+};

Propchange: cfe/trunk/test/SemaCXX/conversion-function.cpp

------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/SemaCXX/conversion-function.cpp

------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/test/SemaCXX/conversion-function.cpp

------------------------------------------------------------------------------
    svn:mime-type = text/plain





More information about the cfe-commits mailing list