]> granicus.if.org Git - clang/commitdiff
Whenever we're creating an expression that is typically an rvalue
authorDouglas Gregor <dgregor@apple.com>
Tue, 13 Jul 2010 18:40:04 +0000 (18:40 +0000)
committerDouglas Gregor <dgregor@apple.com>
Tue, 13 Jul 2010 18:40:04 +0000 (18:40 +0000)
(e.g., a call, cast, etc.), immediately adjust the expression's type
to strip cv-qualifiers off of all non-class types (in C++) or all
types (in C). This effectively extends my previous fix for PR7463,
which was restricted to calls, to other kinds of expressions within
similar characteristics. I've audited every use of
getNonReferenceType() in the code base, switching to the newly-renamed
getNonLValueExprType() where necessary.

Big thanks to Eli for pointing out just how incomplete my original fix
for PR7463 actually was. We've been handling cv-qualifiers on rvalues
wrong for a very, very long time. Fixes PR7463.

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

include/clang/AST/DeclObjC.h
include/clang/AST/Type.h
lib/AST/DeclTemplate.cpp
lib/AST/Type.cpp
lib/CodeGen/CGExprComplex.cpp
lib/Sema/SemaCXXCast.cpp
lib/Sema/SemaExpr.cpp
lib/Sema/SemaExprCXX.cpp
lib/Sema/SemaInit.cpp
lib/Sema/SemaOverload.cpp
test/SemaCXX/cv-unqual-rvalues.cpp [new file with mode: 0644]

index fb8596f50a0b3b90df596b729b0e6832a9c99f9f..30f63d895959a8b57e266e2f4280f12abfcdcb0f 100644 (file)
@@ -242,7 +242,7 @@ public:
   /// \brief Determine the type of an expression that sends a message to this 
   /// function.
   QualType getSendResultType() const {
-    return getResultType().getCallResultType(getASTContext());
+    return getResultType().getNonLValueExprType(getASTContext());
   }
   
   TypeSourceInfo *getResultTypeSourceInfo() const { return ResultTInfo; }
index a1a29e6fef6b8468a44de2228120ae452588676d..49dbd3ec2950bcec5a3f04a3147c4703d864372b 100644 (file)
@@ -629,13 +629,15 @@ public:
   bool isAtLeastAsQualifiedAs(QualType Other) const;
   QualType getNonReferenceType() const;
 
-  /// \brief Determine the type of an expression that calls a function of
-  /// with the given result type.
+  /// \brief Determine the type of a (typically non-lvalue) expression with the
+  /// specified result type.
   ///                       
-  /// This routine removes a top-level reference (since there are no 
+  /// This routine should be used for expressions for which the return type is
+  /// explicitly specified (e.g., in a cast or call) and isn't necessarily
+  /// an lvalue. It removes a top-level reference (since there are no 
   /// expressions of reference type) and deletes top-level cvr-qualifiers
   /// from non-class types (in C++) or all types (in C).
-  QualType getCallResultType(ASTContext &Context) const;
+  QualType getNonLValueExprType(ASTContext &Context) const;
   
   /// getDesugaredType - Return the specified type with any "sugar" removed from
   /// the type.  This takes off typedefs, typeof's etc.  If the outer level of
@@ -1907,7 +1909,7 @@ public:
   /// \brief Determine the type of an expression that calls a function of
   /// this type.
   QualType getCallResultType(ASTContext &Context) const { 
-    return getResultType().getCallResultType(Context);
+    return getResultType().getNonLValueExprType(Context);
   }
 
   static llvm::StringRef getNameForCallConv(CallingConv CC);
index f00eb0478a75ecddb849dd8fe1216500ab4a603f..9e1d79d79d6b06ae4196634f0de2bfffa15329b9 100644 (file)
@@ -223,7 +223,7 @@ ClassTemplateDecl::getInjectedClassNameSpecialization() {
     } else if (NonTypeTemplateParmDecl *NTTP =
                  dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
       Expr *E = new (Context) DeclRefExpr(NTTP,
-                                          NTTP->getType().getNonReferenceType(),
+                                  NTTP->getType().getNonLValueExprType(Context),
                                           NTTP->getLocation());
       TemplateArgs.push_back(TemplateArgument(E));
     } else {
index ebcf828ebf0e92b87fb6cdd4d78e4822e3b29a68..d7929304233ff33f3f9e80c7b7d4db37aee90c8d 100644 (file)
@@ -992,7 +992,7 @@ const char *BuiltinType::getName(const LangOptions &LO) const {
 
 void FunctionType::ANCHOR() {} // Key function for FunctionType.
 
-QualType QualType::getCallResultType(ASTContext &Context) const {
+QualType QualType::getNonLValueExprType(ASTContext &Context) const {
   if (const ReferenceType *RefType = getTypePtr()->getAs<ReferenceType>())
     return RefType->getPointeeType();
   
index 90b6446e0e655b87d91af35fa4a791a05ada334c..995c9b5c4507f92b4e7723ce872ae4e6930c8553 100644 (file)
@@ -572,8 +572,8 @@ ComplexPairTy ComplexExprEmitter::VisitBinAssign(const BinaryOperator *E) {
   TestAndClearIgnoreImag();
   bool ignreal = TestAndClearIgnoreRealAssign();
   bool ignimag = TestAndClearIgnoreImagAssign();
-  assert(CGF.getContext().getCanonicalType(E->getLHS()->getType()) ==
-         CGF.getContext().getCanonicalType(E->getRHS()->getType()) &&
+  assert(CGF.getContext().hasSameUnqualifiedType(E->getLHS()->getType(), 
+                                                 E->getRHS()->getType()) &&
          "Invalid assignment");
   // Emit the RHS.
   ComplexPairTy Val = Visit(E->getRHS());
index b7e855fb1caa5e6bef365571339fddd66375a3bf..911578622d23ac637e3082f0822e247ba9f7757f 100644 (file)
@@ -153,7 +153,8 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
   case tok::kw_const_cast:
     if (!TypeDependent)
       CheckConstCast(*this, Ex, DestType, OpRange, DestRange);
-    return Owned(new (Context) CXXConstCastExpr(DestType.getNonReferenceType(),
+    return Owned(new (Context) CXXConstCastExpr(
+                                        DestType.getNonLValueExprType(Context),
                                                 Ex, DestTInfo, OpLoc));
 
   case tok::kw_dynamic_cast: {
@@ -161,7 +162,8 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
     CXXBaseSpecifierArray BasePath;
     if (!TypeDependent)
       CheckDynamicCast(*this, Ex, DestType, OpRange, DestRange, Kind, BasePath);
-    return Owned(new (Context)CXXDynamicCastExpr(DestType.getNonReferenceType(),
+    return Owned(new (Context)CXXDynamicCastExpr(
+                                          DestType.getNonLValueExprType(Context),
                                                  Kind, Ex, BasePath, DestTInfo,
                                                  OpLoc));
   }
@@ -170,7 +172,7 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
     if (!TypeDependent)
       CheckReinterpretCast(*this, Ex, DestType, OpRange, DestRange, Kind);
     return Owned(new (Context) CXXReinterpretCastExpr(
-                                  DestType.getNonReferenceType(),
+                                  DestType.getNonLValueExprType(Context),
                                   Kind, Ex, CXXBaseSpecifierArray(), 
                                   DestTInfo, OpLoc));
   }
@@ -180,7 +182,8 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
     if (!TypeDependent)
       CheckStaticCast(*this, Ex, DestType, OpRange, Kind, BasePath);
     
-    return Owned(new (Context) CXXStaticCastExpr(DestType.getNonReferenceType(),
+    return Owned(new (Context) CXXStaticCastExpr(
+                                         DestType.getNonLValueExprType(Context),
                                                  Kind, Ex, BasePath,
                                                  DestTInfo, OpLoc));
   }
index ce3bf11caa00e2a430737b9eb323caf625140ba3..5d53ddeb98ebb4f3a59b525b02d91d00ac19e9cd 100644 (file)
@@ -475,6 +475,7 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, SourceLocation Loc,
     if (isa<NonTypeTemplateParmDecl>(VD)) {
       // Non-type template parameters can be referenced anywhere they are
       // visible.
+      Ty = Ty.getNonLValueExprType(Context);
     } else if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext)) {
       if (const FunctionDecl *FD = MD->getParent()->isLocalClass()) {
         if (VD->hasLocalStorage() && VD->getDeclContext() != CurContext) {
@@ -4008,7 +4009,8 @@ Sema::BuildCStyleCastExpr(SourceLocation LParenLoc, TypeSourceInfo *Ty,
     return ExprError();
 
   Op.release();
-  return Owned(new (Context) CStyleCastExpr(Ty->getType().getNonReferenceType(),
+  return Owned(new (Context) CStyleCastExpr(
+                                    Ty->getType().getNonLValueExprType(Context),
                                             Kind, castExpr, BasePath, Ty,
                                             LParenLoc, RParenLoc));
 }
@@ -4904,7 +4906,7 @@ Sema::CheckSingleAssignmentConstraints(QualType lhsType, Expr *&rExpr) {
   // The getNonReferenceType() call makes sure that the resulting expression
   // does not have reference type.
   if (result != Incompatible && rExpr->getType() != lhsType)
-    ImpCastExprToType(rExpr, lhsType.getNonReferenceType(),
+    ImpCastExprToType(rExpr, lhsType.getNonLValueExprType(Context),
                       CastExpr::CK_Unknown);
   return result;
 }
@@ -7348,7 +7350,8 @@ Sema::OwningExprResult Sema::ActOnVAArg(SourceLocation BuiltinLoc,
   // FIXME: Warn if a non-POD type is passed in.
 
   expr.release();
-  return Owned(new (Context) VAArgExpr(BuiltinLoc, E, T.getNonReferenceType(),
+  return Owned(new (Context) VAArgExpr(BuiltinLoc, E, 
+                                       T.getNonLValueExprType(Context),
                                        RPLoc));
 }
 
index a5abfe851b891f7becde9dece502d7c098eb40aa..090400fc4e235b4710ec97c3f9beac3333421a2b 100644 (file)
@@ -540,7 +540,8 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep,
 
     exprs.release();
 
-    return Owned(new (Context) CXXFunctionalCastExpr(Ty.getNonReferenceType(),
+    return Owned(new (Context) CXXFunctionalCastExpr(
+                                              Ty.getNonLValueExprType(Context),
                                                      TInfo, TyBeginLoc, Kind,
                                                      Exprs[0], BasePath,
                                                      RParenLoc));
@@ -1879,7 +1880,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
   case ICK_Qualification:
     // FIXME: Not sure about lvalue vs rvalue here in the presence of rvalue
     // references.
-    ImpCastExprToType(From, ToType.getNonReferenceType(),
+    ImpCastExprToType(From, ToType.getNonLValueExprType(Context),
                       CastExpr::CK_NoOp, ToType->isLValueReferenceType());
 
     if (SCS.DeprecatedStringLiteralToCharPtr)
index 7536289afc10d85f5bce6ffde5f4a676ad4c4feb..7ad177557ef4760da23701dd15f911ce13a3f8be 100644 (file)
@@ -523,8 +523,9 @@ void InitListChecker::CheckExplicitInitList(const InitializedEntity &Entity,
   StructuredList->setSyntacticForm(IList);
   CheckListElementTypes(Entity, IList, T, /*SubobjectIsDesignatorContext=*/true, 
                         Index, StructuredList, StructuredIndex, TopLevelObject);
-  IList->setType(T.getNonReferenceType());
-  StructuredList->setType(T.getNonReferenceType());
+  QualType ExprTy = T.getNonLValueExprType(SemaRef.Context);
+  IList->setType(ExprTy);
+  StructuredList->setType(ExprTy);
   if (hadError)
     return;
 
@@ -1716,7 +1717,7 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index,
                                          InitRange.getBegin(), 0, 0,
                                          InitRange.getEnd());
 
-  Result->setType(CurrentObjectType.getNonReferenceType());
+  Result->setType(CurrentObjectType.getNonLValueExprType(SemaRef.Context));
 
   // Pre-allocate storage for the structured initializer list.
   unsigned NumElements = 0;
@@ -2370,13 +2371,14 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S,
 
   // Add the user-defined conversion step.
   Sequence.AddUserConversionStep(Function, Best->FoundDecl,
-                                 T2.getNonReferenceType());
+                                 T2.getNonLValueExprType(S.Context));
 
   // Determine whether we need to perform derived-to-base or 
   // cv-qualification adjustments.
   bool NewDerivedToBase = false;
   Sema::ReferenceCompareResult NewRefRelationship
-    = S.CompareReferenceRelationship(DeclLoc, T1, T2.getNonReferenceType(),
+    = S.CompareReferenceRelationship(DeclLoc, T1, 
+                                     T2.getNonLValueExprType(S.Context),
                                      NewDerivedToBase);
   if (NewRefRelationship == Sema::Ref_Incompatible) {
     // If the type we've converted to is not reference-related to the
index ee4c479f728ee4db1fdf35780651643d4b64cd39..975ad0bfd4b8d6d089e47240c829071e2541a4b9 100644 (file)
@@ -3727,7 +3727,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
   // there are 0 arguments (i.e., nothing is allocated using ASTContext's
   // allocator).
   CallExpr Call(Context, &ConversionFn, 0, 0,
-                Conversion->getConversionType().getNonReferenceType(),
+                Conversion->getConversionType().getNonLValueExprType(Context),
                 From->getLocStart());
   ImplicitConversionSequence ICS =
     TryCopyInitialization(*this, &Call, ToType,
diff --git a/test/SemaCXX/cv-unqual-rvalues.cpp b/test/SemaCXX/cv-unqual-rvalues.cpp
new file mode 100644 (file)
index 0000000..ed76ced
--- /dev/null
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// PR7463: Make sure that when we have an rvalue, it does not have
+// cv-qualified non-class type.
+template <typename T_> void g (T_&); // expected-note 7{{not viable}}
+
+template<const int X> void h() { 
+  g(X); // expected-error{{no matching function for call to 'g'}}
+}
+
+template<typename T, T X> void h2() { 
+  g(X); // expected-error{{no matching function for call to 'g'}}
+}
+
+void a(__builtin_va_list x) {
+  g(__builtin_va_arg(x, const int)); // expected-error{{no matching function for call to 'g'}}
+  g((const int)0); // expected-error{{no matching function for call to 'g'}}
+  typedef const int cint;
+  g(cint(0)); // expected-error{{no matching function for call to 'g'}}
+  g(static_cast<const int>(1)); // expected-error{{no matching function for call to 'g'}}
+  g(reinterpret_cast<int *const>(0)); // expected-error{{no matching function for call to 'g'}}
+  h<0>(); 
+  h2<const int, 0>(); // expected-note{{instantiation of}}
+}