Avoid using rvalue references with trivially copyable types.

Summary:
When the dereference operator returns a value that is trivially
copyable (like a pointer), copy it. After this change, modernize-loop-convert
check can be applied to the whole llvm source code without breaking any build
or test.

Reviewers: alexfh, klimek

Subscribers: alexfh, cfe-commits

Differential Revision: http://reviews.llvm.org/D12675

llvm-svn: 246989
diff --git a/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp b/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp
index b6cb64f..9af7979 100644
--- a/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp
@@ -375,7 +375,7 @@
 /// by reference.
 static bool usagesReturnRValues(const UsageResult &Usages) {
   for (const auto &U : Usages) {
-    if (!U.Expression->isRValue())
+    if (U.Expression && !U.Expression->isRValue())
       return false;
   }
   return true;
@@ -400,8 +400,7 @@
     ASTContext *Context, const VarDecl *IndexVar, const VarDecl *MaybeContainer,
     StringRef ContainerString, const UsageResult &Usages,
     const DeclStmt *AliasDecl, bool AliasUseRequired, bool AliasFromForInit,
-    const ForStmt *TheLoop, bool ContainerNeedsDereference, bool DerefByValue,
-    bool DerefByConstRef) {
+    const ForStmt *TheLoop, RangeDescriptor Descriptor) {
   auto Diag = diag(TheLoop->getForLoc(), "use range-based for loop instead");
 
   std::string VarName;
@@ -457,16 +456,17 @@
     // If an iterator's operator*() returns a 'T&' we can bind that to 'auto&'.
     // If operator*() returns 'T' we can bind that to 'auto&&' which will deduce
     // to 'T&&&'.
-    if (DerefByValue) {
-      AutoRefType = Context->getRValueReferenceType(AutoRefType);
+    if (Descriptor.DerefByValue) {
+      if (!Descriptor.IsTriviallyCopyable)
+        AutoRefType = Context->getRValueReferenceType(AutoRefType);
     } else {
-      if (DerefByConstRef)
+      if (Descriptor.DerefByConstRef)
         AutoRefType = Context->getConstType(AutoRefType);
       AutoRefType = Context->getLValueReferenceType(AutoRefType);
     }
   }
 
-  StringRef MaybeDereference = ContainerNeedsDereference ? "*" : "";
+  StringRef MaybeDereference = Descriptor.ContainerNeedsDereference ? "*" : "";
   std::string TypeString = AutoRefType.getAsString();
   std::string Range = ("(" + TypeString + " " + VarName + " : " +
                        MaybeDereference + ContainerString + ")")
@@ -518,11 +518,11 @@
 /// of the index variable and convert the loop if possible.
 void LoopConvertCheck::findAndVerifyUsages(
     ASTContext *Context, const VarDecl *LoopVar, const VarDecl *EndVar,
-    const Expr *ContainerExpr, const Expr *BoundExpr,
-    bool ContainerNeedsDereference, bool DerefByValue, bool DerefByConstRef,
-    const ForStmt *TheLoop, LoopFixerKind FixerKind) {
+    const Expr *ContainerExpr, const Expr *BoundExpr, const ForStmt *TheLoop,
+    LoopFixerKind FixerKind, RangeDescriptor Descriptor) {
   ForLoopIndexUseVisitor Finder(Context, LoopVar, EndVar, ContainerExpr,
-                                BoundExpr, ContainerNeedsDereference);
+                                BoundExpr,
+                                Descriptor.ContainerNeedsDereference);
 
   if (ContainerExpr) {
     ComponentFinderASTVisitor ComponentFinder;
@@ -544,15 +544,28 @@
         !isDirectMemberExpr(ContainerExpr))
       ConfidenceLevel.lowerTo(Confidence::CL_Risky);
   } else if (FixerKind == LFK_PseudoArray) {
-    if (!DerefByValue && !DerefByConstRef) {
+    if (!Descriptor.DerefByValue && !Descriptor.DerefByConstRef) {
       const UsageResult &Usages = Finder.getUsages();
       if (usagesAreConst(Usages)) {
-        // FIXME: check if the type is trivially copiable.
-        DerefByConstRef = true;
+        Descriptor.DerefByConstRef = true;
       } else if (usagesReturnRValues(Usages)) {
         // If the index usages (dereference, subscript, at) return RValues,
         // then we should not use a non-const reference.
-        DerefByValue = true;
+        Descriptor.DerefByValue = true;
+        // Try to find the type of the elements on the container from the
+        // usages.
+        for (const Usage &U : Usages) {
+          if (!U.Expression || U.Expression->getType().isNull())
+            continue;
+          QualType Type = U.Expression->getType().getCanonicalType();
+          if (U.IsArrow) {
+            if (!Type->isPointerType())
+              continue;
+            Type = Type->getPointeeType();
+          }
+          Descriptor.IsTriviallyCopyable =
+              Type.isTriviallyCopyableType(*Context);
+        }
       }
     }
   }
@@ -565,7 +578,7 @@
   doConversion(Context, LoopVar, getReferencedVariable(ContainerExpr),
                ContainerString, Finder.getUsages(), Finder.getAliasDecl(),
                Finder.aliasUseRequired(), Finder.aliasFromForInit(), TheLoop,
-               ContainerNeedsDereference, DerefByValue, DerefByConstRef);
+               Descriptor);
 }
 
 void LoopConvertCheck::registerMatchers(MatchFinder *Finder) {
@@ -618,15 +631,13 @@
     ConfidenceLevel.lowerTo(Confidence::CL_Reasonable);
 
   const Expr *ContainerExpr = nullptr;
-  bool DerefByValue = false;
-  bool DerefByConstRef = false;
-  bool ContainerNeedsDereference = false;
+  RangeDescriptor Descriptor{false, false, false, false};
   // FIXME: Try to put most of this logic inside a matcher. Currently, matchers
   // don't allow the ight-recursive checks in digThroughConstructors.
   if (FixerKind == LFK_Iterator) {
     ContainerExpr = findContainer(Context, LoopVar->getInit(),
                                   EndVar ? EndVar->getInit() : EndCall,
-                                  &ContainerNeedsDereference);
+                                  &Descriptor.ContainerNeedsDereference);
 
     QualType InitVarType = InitVar->getType();
     QualType CanonicalInitVarType = InitVarType.getCanonicalType();
@@ -643,6 +654,8 @@
       // un-qualified pointee types match otherwise we don't use auto.
       if (!Context->hasSameUnqualifiedType(InitPointeeType, BeginPointeeType))
         return;
+      Descriptor.IsTriviallyCopyable =
+          BeginPointeeType.isTriviallyCopyableType(*Context);
     } else {
       // Check for qualified types to avoid conversions from non-const to const
       // iterator types.
@@ -650,17 +663,19 @@
         return;
     }
 
-    DerefByValue = Nodes.getNodeAs<QualType>(DerefByValueResultName) != nullptr;
-    if (!DerefByValue) {
+    const auto *DerefByValueType =
+        Nodes.getNodeAs<QualType>(DerefByValueResultName);
+    Descriptor.DerefByValue = DerefByValueType;
+    if (!Descriptor.DerefByValue) {
       if (const auto *DerefType =
               Nodes.getNodeAs<QualType>(DerefByRefResultName)) {
         // A node will only be bound with DerefByRefResultName if we're dealing
         // with a user-defined iterator type. Test the const qualification of
         // the reference type.
-        DerefByConstRef = (*DerefType)
-                              ->getAs<ReferenceType>()
-                              ->getPointeeType()
-                              .isConstQualified();
+        Descriptor.DerefByConstRef = (*DerefType)
+                                         ->getAs<ReferenceType>()
+                                         ->getPointeeType()
+                                         .isConstQualified();
       } else {
         // By nature of the matcher this case is triggered only for built-in
         // iterator types (i.e. pointers).
@@ -671,12 +686,14 @@
         // If the initializer and variable have both the same type just use auto
         // otherwise we test for const qualification of the pointed-at type.
         if (!Context->hasSameType(InitPointeeType, BeginPointeeType))
-          DerefByConstRef = InitPointeeType.isConstQualified();
+          Descriptor.DerefByConstRef = InitPointeeType.isConstQualified();
       }
     } else {
       // If the dereference operator returns by value then test for the
       // canonical const qualification of the init variable type.
-      DerefByConstRef = CanonicalInitVarType.isConstQualified();
+      Descriptor.DerefByConstRef = CanonicalInitVarType.isConstQualified();
+      Descriptor.IsTriviallyCopyable =
+          DerefByValueType->isTriviallyCopyableType(*Context);
     }
   } else if (FixerKind == LFK_PseudoArray) {
     if (!EndCall)
@@ -685,7 +702,7 @@
     const auto *Member = dyn_cast<MemberExpr>(EndCall->getCallee());
     if (!Member)
       return;
-    ContainerNeedsDereference = Member->isArrow();
+    Descriptor.ContainerNeedsDereference = Member->isArrow();
   }
 
   // We must know the container or an array length bound.
@@ -696,8 +713,7 @@
     return;
 
   findAndVerifyUsages(Context, LoopVar, EndVar, ContainerExpr, BoundExpr,
-                      ContainerNeedsDereference, DerefByValue, DerefByConstRef,
-                      TheLoop, FixerKind);
+                      TheLoop, FixerKind, Descriptor);
 }
 
 } // namespace modernize