]> granicus.if.org Git - clang/commitdiff
Support explicit C++ member operator syntax, from James Porter!
authorDouglas Gregor <dgregor@apple.com>
Mon, 31 Aug 2009 19:52:13 +0000 (19:52 +0000)
committerDouglas Gregor <dgregor@apple.com>
Mon, 31 Aug 2009 19:52:13 +0000 (19:52 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@80608 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Parse/Action.h
lib/Parse/ParseExpr.cpp
lib/Sema/Sema.h
lib/Sema/SemaExprCXX.cpp
test/SemaCXX/invalid-member-expr.cpp [new file with mode: 0644]
test/SemaCXX/member-operator-expr.cpp [new file with mode: 0644]

index 108d43d9e66799ae7a86f073b2cc001737146ec0..f3364352aa4ceb7728fea1f47f2e8b76f2f12e88 100644 (file)
@@ -1292,6 +1292,34 @@ public:
                                const CXXScopeSpec *SS = 0) {
     return ExprEmpty();
   }
+
+  /// ActOnOverloadedOperatorReferenceExpr - Parsed an overloaded operator
+  /// reference, for example:
+  ///
+  /// t.operator++();
+  virtual OwningExprResult
+  ActOnOverloadedOperatorReferenceExpr(Scope *S, ExprArg Base,
+                                       SourceLocation OpLoc,
+                                       tok::TokenKind OpKind,
+                                       SourceLocation ClassNameLoc,
+                                       OverloadedOperatorKind OverOpKind,
+                                       const CXXScopeSpec *SS = 0) {
+    return ExprEmpty();
+  }
+
+  /// ActOnConversionOperatorReferenceExpr - Parsed an overloaded conversion
+  /// function reference, for example:
+  ///
+  /// t.operator int();
+  virtual OwningExprResult
+  ActOnConversionOperatorReferenceExpr(Scope *S, ExprArg Base,
+                                       SourceLocation OpLoc,
+                                       tok::TokenKind OpKind,
+                                       SourceLocation ClassNameLoc,
+                                       TypeTy *Ty,
+                                       const CXXScopeSpec *SS = 0) {
+    return ExprEmpty();
+  }
   
   /// ActOnFinishFullExpr - Called whenever a full expression has been parsed.
   /// (C++ [intro.execution]p12).
index 80e701e17aee3815894720c9ca2c03e2352adbd7..d00d6d2e33d95a403619d09419d027a9913fc0f9 100644 (file)
@@ -939,6 +939,7 @@ Parser::ParsePostfixExpressionSuffix(OwningExprResult LHS) {
                                                  OpKind, Tok.getLocation(),
                                                  *Tok.getIdentifierInfo(),
                                                  ObjCImpDecl, &SS);
+        ConsumeToken();
       } else if (getLang().CPlusPlus && Tok.is(tok::tilde)) {
         // We have a C++ pseudo-destructor.
         
@@ -946,6 +947,8 @@ Parser::ParsePostfixExpressionSuffix(OwningExprResult LHS) {
         ConsumeToken();
         
         if (!Tok.is(tok::identifier)) {
+          if (getLang().CPlusPlus)
+            Actions.ActOnCXXExitMemberScope(CurScope, MemberSS);
           Diag(Tok, diag::err_expected_ident);
           return ExprError();
         }
@@ -956,15 +959,39 @@ Parser::ParsePostfixExpressionSuffix(OwningExprResult LHS) {
                                                      Tok.getLocation(), 
                                                      Tok.getIdentifierInfo(),
                                                      &SS);
+        ConsumeToken();
+      } else if (getLang().CPlusPlus && Tok.is(tok::kw_operator)) {
+        if (OverloadedOperatorKind Op = TryParseOperatorFunctionId()) {
+          if (!LHS.isInvalid())
+            LHS = Actions.ActOnOverloadedOperatorReferenceExpr(CurScope,
+                                                               move(LHS), OpLoc,
+                                                               OpKind,
+                                                           Tok.getLocation(),
+                                                               Op, &SS);
+          // TryParseOperatorFunctionId already consumed our token, so
+          // don't bother
+        } else if (TypeTy *ConvType = ParseConversionFunctionId()) {
+          if (!LHS.isInvalid())
+            LHS = Actions.ActOnConversionOperatorReferenceExpr(CurScope,
+                                                               move(LHS), OpLoc,
+                                                               OpKind,
+                                                           Tok.getLocation(),
+                                                               ConvType, &SS);
+        } else {
+          if (getLang().CPlusPlus)
+            Actions.ActOnCXXExitMemberScope(CurScope, MemberSS);
+          // Don't emit a diagnostic; ParseConversionFunctionId does it for us
+          return ExprError();
+        }
       } else {
+        if (getLang().CPlusPlus)
+          Actions.ActOnCXXExitMemberScope(CurScope, MemberSS);
         Diag(Tok, diag::err_expected_ident);
         return ExprError();
       }
 
       if (getLang().CPlusPlus)
         Actions.ActOnCXXExitMemberScope(CurScope, MemberSS);
-
-      ConsumeToken();
       break;
     }
     case tok::plusplus:    // postfix-expression: postfix-expression '++'
index 0e45fe7f15993fe092a47ef2d458997434973034..f9c893f0a04da889e130884f709bba40fab37408 100644 (file)
@@ -1956,6 +1956,21 @@ public:
                                SourceLocation ClassNameLoc,
                                IdentifierInfo *ClassName,
                                const CXXScopeSpec *SS = 0);
+
+  virtual OwningExprResult
+  ActOnOverloadedOperatorReferenceExpr(Scope *S, ExprArg Base,
+                                       SourceLocation OpLoc,
+                                       tok::TokenKind OpKind,
+                                       SourceLocation ClassNameLoc,
+                                       OverloadedOperatorKind OverOpKind,
+                                       const CXXScopeSpec *SS = 0);
+  virtual OwningExprResult
+  ActOnConversionOperatorReferenceExpr(Scope *S, ExprArg Base,
+                                       SourceLocation OpLoc,
+                                       tok::TokenKind OpKind,
+                                       SourceLocation ClassNameLoc,
+                                       TypeTy *Ty,
+                                       const CXXScopeSpec *SS = 0);
   
   /// MaybeCreateCXXExprWithTemporaries - If the list of temporaries is 
   /// non-empty, will create a new CXXExprWithTemporaries expression.
index 16e83e6514f9f4e1e31a7dbfc4bdee0dc6cbe526..35938260c6564f9b9579eaf1af7cb343c868e7de 100644 (file)
@@ -1794,6 +1794,43 @@ Sema::ActOnDestructorReferenceExpr(Scope *S, ExprArg Base,
                                   DtorName, DeclPtrTy(), SS);
 }
 
+Sema::OwningExprResult
+Sema::ActOnOverloadedOperatorReferenceExpr(Scope *S, ExprArg Base,
+                                           SourceLocation OpLoc,
+                                           tok::TokenKind OpKind,
+                                           SourceLocation ClassNameLoc,
+                                           OverloadedOperatorKind OverOpKind,
+                                           const CXXScopeSpec *SS) {
+  if (SS && SS->isInvalid())
+    return ExprError();
+
+  DeclarationName Name =
+    Context.DeclarationNames.getCXXOperatorName(OverOpKind);
+
+  return BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, ClassNameLoc,
+                                  Name, DeclPtrTy(), SS);
+}
+
+Sema::OwningExprResult
+Sema::ActOnConversionOperatorReferenceExpr(Scope *S, ExprArg Base,
+                                           SourceLocation OpLoc,
+                                           tok::TokenKind OpKind,
+                                           SourceLocation ClassNameLoc,
+                                           TypeTy *Ty,
+                                           const CXXScopeSpec *SS) {
+  if (SS && SS->isInvalid())
+    return ExprError();
+
+  //FIXME: Preserve type source info.
+  QualType ConvType = GetTypeFromParser(Ty);
+  CanQualType ConvTypeCanon = Context.getCanonicalType(ConvType);
+  DeclarationName ConvName =
+    Context.DeclarationNames.getCXXConversionFunctionName(ConvTypeCanon);
+
+  return BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, ClassNameLoc,
+                                  ConvName, DeclPtrTy(), SS);
+}
+
 Sema::OwningExprResult Sema::ActOnFinishFullExpr(ExprArg Arg) {
   Expr *FullExpr = Arg.takeAs<Expr>();
   if (FullExpr)
diff --git a/test/SemaCXX/invalid-member-expr.cpp b/test/SemaCXX/invalid-member-expr.cpp
new file mode 100644 (file)
index 0000000..90932ed
--- /dev/null
@@ -0,0 +1,21 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+class X {};
+
+void test() {
+  X x;
+
+  x.int; // expected-error{{expected identifier}}
+  x.~int(); // expected-error{{expected identifier}}
+  x.operator; // expected-error{{missing type specifier after 'operator'}}
+  x.operator typedef; // expected-error{{missing type specifier after 'operator'}}
+}
+
+void test2() {
+  X *x;
+
+  x->int; // expected-error{{expected identifier}}
+  x->~int(); // expected-error{{expected identifier}}
+  x->operator; // expected-error{{missing type specifier after 'operator'}}
+  x->operator typedef; // expected-error{{missing type specifier after 'operator'}}
+}
diff --git a/test/SemaCXX/member-operator-expr.cpp b/test/SemaCXX/member-operator-expr.cpp
new file mode 100644 (file)
index 0000000..4d0e00f
--- /dev/null
@@ -0,0 +1,29 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+class X {
+public:
+  int operator++();
+  operator int();
+};
+
+void test() {
+  X x;
+  int i;
+
+  i = x.operator++();
+  i = x.operator int();
+  x.operator--(); // expected-error{{no member named 'operator--'}}
+  x.operator float(); // expected-error{{no member named 'operator float'}}
+  x.operator; // expected-error{{missing type specifier after 'operator'}}
+}
+
+void test2() {
+  X *x;
+  int i;
+
+  i = x->operator++();
+  i = x->operator int();
+  x->operator--(); // expected-error{{no member named 'operator--'}}
+  x->operator float(); // expected-error{{no member named 'operator float'}}
+  x->operator; // expected-error{{missing type specifier after 'operator'}}
+}