]> granicus.if.org Git - clang/commitdiff
When instantiating a UnaryOperator, allow the resulting expression to
authorDouglas Gregor <dgregor@apple.com>
Thu, 5 Nov 2009 00:51:44 +0000 (00:51 +0000)
committerDouglas Gregor <dgregor@apple.com>
Thu, 5 Nov 2009 00:51:44 +0000 (00:51 +0000)
still be dependent or invoke an overloaded operator. Previously, we
only supported builtin operators.

BinaryOperator/CompoundAssignOperator didn't have this issue because
we always built a CXXOperatorCallExpr node, even when name lookup
didn't find any functions to save until instantiation time. Now, that
code builds a BinaryOperator or CompoundAssignOperator rather than a
CXXOperatorCallExpr, to save some space.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@86087 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/Sema.h
lib/Sema/SemaExpr.cpp
lib/Sema/SemaOverload.cpp
lib/Sema/TreeTransform.h
test/SemaTemplate/instantiate-expr-1.cpp

index b0aa7b747305cc31021418ae71913c47a893acba..e97417680b085f090ecd14dea97e13a5c0b30be9 100644 (file)
@@ -1667,6 +1667,8 @@ public:
   OwningExprResult CreateBuiltinUnaryOp(SourceLocation OpLoc,
                                         unsigned OpcIn,
                                         ExprArg InputArg);
+  OwningExprResult BuildUnaryOp(Scope *S, SourceLocation OpLoc,
+                                UnaryOperator::Opcode Opc, ExprArg input);
   virtual OwningExprResult ActOnUnaryOp(Scope *S, SourceLocation OpLoc,
                                         tok::TokenKind Op, ExprArg Input);
 
@@ -1792,6 +1794,9 @@ public:
   virtual OwningExprResult ActOnBinOp(Scope *S, SourceLocation TokLoc,
                                       tok::TokenKind Kind,
                                       ExprArg LHS, ExprArg RHS);
+  OwningExprResult BuildBinOp(Scope *S, SourceLocation OpLoc,
+                              BinaryOperator::Opcode Opc,
+                              Expr *lhs, Expr *rhs);
   OwningExprResult CreateBuiltinBinOp(SourceLocation TokLoc,
                                       unsigned Opc, Expr *lhs, Expr *rhs);
 
index ea8504549aae21d409474f978bb9b65e514e1406..c9a28a74ee03eb40e55a35f8f351e451d01ec489 100644 (file)
@@ -5509,6 +5509,12 @@ Action::OwningExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc,
   // Emit warnings for tricky precedence issues, e.g. "bitfield & 0x4 == 0"
   DiagnoseBinOpPrecedence(*this, Opc, TokLoc, lhs, rhs);
 
+  return BuildBinOp(S, TokLoc, Opc, lhs, rhs);
+}
+
+Action::OwningExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc,
+                                          BinaryOperator::Opcode Opc,
+                                          Expr *lhs, Expr *rhs) {
   if (getLangOptions().CPlusPlus &&
       (lhs->getType()->isOverloadableType() ||
        rhs->getType()->isOverloadableType())) {
@@ -5519,21 +5525,22 @@ Action::OwningExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc,
     FunctionSet Functions;
     OverloadedOperatorKind OverOp = BinaryOperator::getOverloadedOperator(Opc);
     if (OverOp != OO_None) {
-      LookupOverloadedOperatorName(OverOp, S, lhs->getType(), rhs->getType(),
-                                   Functions);
+      if (S)
+        LookupOverloadedOperatorName(OverOp, S, lhs->getType(), rhs->getType(),
+                                     Functions);
       Expr *Args[2] = { lhs, rhs };
       DeclarationName OpName
         = Context.DeclarationNames.getCXXOperatorName(OverOp);
       ArgumentDependentLookup(OpName, /*Operator*/true, Args, 2, Functions);
     }
-
+    
     // Build the (potentially-overloaded, potentially-dependent)
     // binary operation.
-    return CreateOverloadedBinOp(TokLoc, Opc, Functions, lhs, rhs);
+    return CreateOverloadedBinOp(OpLoc, Opc, Functions, lhs, rhs);
   }
-
+  
   // Build a built-in binary operation.
-  return CreateBuiltinBinOp(TokLoc, Opc, lhs, rhs);
+  return CreateBuiltinBinOp(OpLoc, Opc, lhs, rhs);
 }
 
 Action::OwningExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
@@ -5624,12 +5631,10 @@ Action::OwningExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
   return Owned(new (Context) UnaryOperator(Input, Opc, resultType, OpLoc));
 }
 
-// Unary Operators.  'Tok' is the token for the operator.
-Action::OwningExprResult Sema::ActOnUnaryOp(Scope *S, SourceLocation OpLoc,
-                                            tok::TokenKind Op, ExprArg input) {
+Action::OwningExprResult Sema::BuildUnaryOp(Scope *S, SourceLocation OpLoc,
+                                            UnaryOperator::Opcode Opc,
+                                            ExprArg input) {
   Expr *Input = (Expr*)input.get();
-  UnaryOperator::Opcode Opc = ConvertTokenKindToUnaryOpcode(Op);
-
   if (getLangOptions().CPlusPlus && Input->getType()->isOverloadableType()) {
     // Find all of the overloaded operators visible from this
     // point. We perform both an operator-name lookup from the local
@@ -5638,19 +5643,26 @@ Action::OwningExprResult Sema::ActOnUnaryOp(Scope *S, SourceLocation OpLoc,
     FunctionSet Functions;
     OverloadedOperatorKind OverOp = UnaryOperator::getOverloadedOperator(Opc);
     if (OverOp != OO_None) {
-      LookupOverloadedOperatorName(OverOp, S, Input->getType(), QualType(),
-                                   Functions);
+      if (S)
+        LookupOverloadedOperatorName(OverOp, S, Input->getType(), QualType(),
+                                     Functions);
       DeclarationName OpName
         = Context.DeclarationNames.getCXXOperatorName(OverOp);
       ArgumentDependentLookup(OpName, /*Operator*/true, &Input, 1, Functions);
     }
-
+    
     return CreateOverloadedUnaryOp(OpLoc, Opc, Functions, move(input));
   }
-
+  
   return CreateBuiltinUnaryOp(OpLoc, Opc, move(input));
 }
 
+// Unary Operators.  'Tok' is the token for the operator.
+Action::OwningExprResult Sema::ActOnUnaryOp(Scope *S, SourceLocation OpLoc,
+                                            tok::TokenKind Op, ExprArg input) {
+  return BuildUnaryOp(S, OpLoc, ConvertTokenKindToUnaryOpcode(Op), move(input));
+}
+
 /// ActOnAddrLabel - Parse the GNU address of label extension: "&&foo".
 Sema::OwningExprResult Sema::ActOnAddrLabel(SourceLocation OpLoc,
                                             SourceLocation LabLoc,
index dd009a062f009ab1b4c43c62358cbc5002705d7c..d2bdfb8e2cc8461c7c4eb94bc5bba0f2c6ec63ff 100644 (file)
@@ -4787,11 +4787,20 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
   // If either side is type-dependent, create an appropriate dependent
   // expression.
   if (Args[0]->isTypeDependent() || Args[1]->isTypeDependent()) {
-    // .* cannot be overloaded.
-    if (Opc == BinaryOperator::PtrMemD)
-      return Owned(new (Context) BinaryOperator(Args[0], Args[1], Opc,
-                                                Context.DependentTy, OpLoc));
-
+    if (Functions.empty()) {
+      // If there are no functions to store, just build a dependent 
+      // BinaryOperator or CompoundAssignment.
+      if (Opc <= BinaryOperator::Assign || Opc > BinaryOperator::OrAssign)
+        return Owned(new (Context) BinaryOperator(Args[0], Args[1], Opc,
+                                                  Context.DependentTy, OpLoc));
+      
+      return Owned(new (Context) CompoundAssignOperator(Args[0], Args[1], Opc,
+                                                        Context.DependentTy,
+                                                        Context.DependentTy,
+                                                        Context.DependentTy,
+                                                        OpLoc));
+    }
+    
     OverloadedFunctionDecl *Overloads
       = OverloadedFunctionDecl::Create(Context, CurContext, OpName);
     for (FunctionSet::iterator Func = Functions.begin(),
index 51393a37c05a5ec11fcb025dd87aa586b84294aa..767725a1f3182f7d2849751b1117598b6439880b 100644 (file)
@@ -877,7 +877,7 @@ public:
   OwningExprResult RebuildUnaryOperator(SourceLocation OpLoc,
                                         UnaryOperator::Opcode Opc,
                                         ExprArg SubExpr) {
-    return getSema().CreateBuiltinUnaryOp(OpLoc, Opc, move(SubExpr));
+    return getSema().BuildUnaryOp(/*Scope=*/0, OpLoc, Opc, move(SubExpr));
   }
 
   /// \brief Build a new sizeof or alignof expression with a type argument.
@@ -986,15 +986,8 @@ public:
   OwningExprResult RebuildBinaryOperator(SourceLocation OpLoc,
                                          BinaryOperator::Opcode Opc,
                                          ExprArg LHS, ExprArg RHS) {
-    OwningExprResult Result
-      = getSema().CreateBuiltinBinOp(OpLoc, Opc, (Expr *)LHS.get(),
-                                     (Expr *)RHS.get());
-    if (Result.isInvalid())
-      return SemaRef.ExprError();
-
-    LHS.release();
-    RHS.release();
-    return move(Result);
+    return getSema().BuildBinOp(/*Scope=*/0, OpLoc, Opc, 
+                                LHS.takeAs<Expr>(), RHS.takeAs<Expr>());
   }
 
   /// \brief Build a new conditional operator expression.
index 13ee3ab525ba69a2817db03e4c22097a086fa254..fb88213c401be1f0f5f1709f06955984bde148fc 100644 (file)
@@ -1,5 +1,4 @@
 // RUN: clang-cc -fsyntax-only -verify %s
-
 template<int I, int J>
 struct Bitfields {
   int simple : I; // expected-error{{bit-field 'simple' has zero width}}
@@ -69,3 +68,29 @@ void test_BitfieldNeg() {
   (void)sizeof(BitfieldNeg2<int, -5>); // okay
   (void)sizeof(BitfieldNeg2<int, 5>); // expected-note{{in instantiation of template class 'struct BitfieldNeg2<int, 5>' requested here}}
 }
+
+template<typename T>
+void increment(T &x) {
+  (void)++x;
+}
+
+struct Incrementable {
+  Incrementable &operator++();
+};
+
+void test_increment(Incrementable inc) {
+  increment(inc);
+}
+
+template<typename T>
+void add(const T &x) {
+  (void)(x + x);
+}
+
+struct Addable {
+  Addable operator+(const Addable&) const;
+};
+
+void test_add(Addable &a) {
+  add(a);
+}