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.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@58860 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index d826588..58cc9e2 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -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 ')'
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index 3134ff8..5dc43ed 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -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;
+}