Merge pull request #11979 from slavapestov/versioned-attr-fixes

Fixes for @_versioned attribute
diff --git a/lib/Sema/DerivedConformanceCodable.cpp b/lib/Sema/DerivedConformanceCodable.cpp
index b3a53f1..a0b6b10 100644
--- a/lib/Sema/DerivedConformanceCodable.cpp
+++ b/lib/Sema/DerivedConformanceCodable.cpp
@@ -802,8 +802,7 @@
   }
 
   encodeDecl->setInterfaceType(interfaceType);
-  encodeDecl->setAccess(std::max(target->getFormalAccess(),
-                                 AccessLevel::Internal));
+  encodeDecl->setAccess(target->getFormalAccess());
 
   // If the type was not imported, the derived conformance is either from the
   // type itself or an extension, in which case we will emit the declaration
@@ -1149,8 +1148,7 @@
 
   initDecl->setInterfaceType(interfaceType);
   initDecl->setInitializerInterfaceType(initializerType);
-  initDecl->setAccess(std::max(target->getFormalAccess(),
-                               AccessLevel::Internal));
+  initDecl->setAccess(target->getFormalAccess());
 
   // If the type was not imported, the derived conformance is either from the
   // type itself or an extension, in which case we will emit the declaration
diff --git a/lib/Sema/DerivedConformanceCodingKey.cpp b/lib/Sema/DerivedConformanceCodingKey.cpp
index f9d0edc..8293912 100644
--- a/lib/Sema/DerivedConformanceCodingKey.cpp
+++ b/lib/Sema/DerivedConformanceCodingKey.cpp
@@ -181,8 +181,7 @@
   }
   initDecl->setInterfaceType(allocIfaceType);
   initDecl->setInitializerInterfaceType(initIfaceType);
-  initDecl->setAccess(std::max(AccessLevel::Internal,
-                               enumDecl->getFormalAccess()));
+  initDecl->setAccess(enumDecl->getFormalAccess());
 
   // If the enum was not imported, the derived conformance is either from the
   // enum itself or an extension, in which case we will emit the declaration
diff --git a/lib/Sema/DerivedConformanceEquatableHashable.cpp b/lib/Sema/DerivedConformanceEquatableHashable.cpp
index 746edbf..95578b2 100644
--- a/lib/Sema/DerivedConformanceEquatableHashable.cpp
+++ b/lib/Sema/DerivedConformanceEquatableHashable.cpp
@@ -296,11 +296,7 @@
                                     FunctionType::ExtInfo());
   }
   eqDecl->setInterfaceType(interfaceTy);
-
-  // Since we can't insert the == operator into the same FileUnit as the enum,
-  // itself, we have to give it at least internal access.
-  eqDecl->setAccess(std::max(enumDecl->getFormalAccess(),
-                             AccessLevel::Internal));
+  copyFormalAccess(eqDecl, enumDecl);
 
   // If the enum was not imported, the derived conformance is either from the
   // enum itself or an extension, in which case we will emit the declaration
@@ -430,8 +426,7 @@
                                       AnyFunctionType::ExtInfo());
   
   getterDecl->setInterfaceType(interfaceType);
-  getterDecl->setAccess(std::max(AccessLevel::Internal,
-                                 enumDecl->getFormalAccess()));
+  copyFormalAccess(getterDecl, enumDecl);
 
   // If the enum was not imported, the derived conformance is either from the
   // enum itself or an extension, in which case we will emit the declaration
@@ -447,7 +442,7 @@
   hashValueDecl->setInterfaceType(intType);
   hashValueDecl->makeComputed(SourceLoc(), getterDecl,
                               nullptr, nullptr, SourceLoc());
-  hashValueDecl->setAccess(getterDecl->getFormalAccess());
+  copyFormalAccess(hashValueDecl, enumDecl);
 
   Pattern *hashValuePat = new (C) NamedPattern(hashValueDecl, /*implicit*/true);
   hashValuePat->setType(intType);
diff --git a/lib/Sema/DerivedConformanceRawRepresentable.cpp b/lib/Sema/DerivedConformanceRawRepresentable.cpp
index a17f4e6..1c94786 100644
--- a/lib/Sema/DerivedConformanceRawRepresentable.cpp
+++ b/lib/Sema/DerivedConformanceRawRepresentable.cpp
@@ -318,8 +318,7 @@
   }
   initDecl->setInterfaceType(allocIfaceType);
   initDecl->setInitializerInterfaceType(initIfaceType);
-  initDecl->setAccess(std::max(AccessLevel::Internal,
-                               enumDecl->getFormalAccess()));
+  copyFormalAccess(initDecl, enumDecl);
 
   // If the enum was not imported, the derived conformance is either from the
   // enum itself or an extension, in which case we will emit the declaration
diff --git a/lib/Sema/DerivedConformances.cpp b/lib/Sema/DerivedConformances.cpp
index 8506b5a..f3a4033 100644
--- a/lib/Sema/DerivedConformances.cpp
+++ b/lib/Sema/DerivedConformances.cpp
@@ -171,8 +171,7 @@
     interfaceType = FunctionType::get({selfParam}, interfaceType,
                                       FunctionType::ExtInfo());
   getterDecl->setInterfaceType(interfaceType);
-  getterDecl->setAccess(std::max(typeDecl->getFormalAccess(),
-                                 AccessLevel::Internal));
+  copyFormalAccess(getterDecl, typeDecl);
 
   // If the enum was not imported, the derived conformance is either from the
   // enum itself or an extension, in which case we will emit the declaration
@@ -202,7 +201,7 @@
   propDecl->setImplicit();
   propDecl->makeComputed(SourceLoc(), getterDecl, nullptr, nullptr,
                          SourceLoc());
-  propDecl->setAccess(getterDecl->getFormalAccess());
+  copyFormalAccess(propDecl, typeDecl);
   propDecl->setInterfaceType(propertyInterfaceType);
 
   // If this is supposed to be a final property, mark it as such.
@@ -225,3 +224,14 @@
 
   return {propDecl, pbDecl};
 }
+
+void DerivedConformance::copyFormalAccess(ValueDecl *dest, ValueDecl *source) {
+  dest->setAccess(source->getFormalAccess());
+
+  // Inherit the @_versioned attribute.
+  if (source->getAttrs().hasAttribute<VersionedAttr>()) {
+    auto &ctx = source->getASTContext();
+    auto *clonedAttr = new (ctx) VersionedAttr(/*implicit=*/true);
+    dest->getAttrs().add(clonedAttr);
+  }
+}
diff --git a/lib/Sema/DerivedConformances.h b/lib/Sema/DerivedConformances.h
index 9b56a26..1d78a86 100644
--- a/lib/Sema/DerivedConformances.h
+++ b/lib/Sema/DerivedConformances.h
@@ -145,6 +145,9 @@
 /// Build a reference to the 'self' decl of a derived function.
 DeclRefExpr *createSelfDeclRef(AbstractFunctionDecl *fn);
 
+/// Copy access from the source decl to the destination decl.
+void copyFormalAccess(ValueDecl *dest, ValueDecl *source);
+
 }
   
 }
diff --git a/test/attr/accessibility_print.swift b/test/attr/accessibility_print.swift
index b4eb3a1..2785b7e 100644
--- a/test/attr/accessibility_print.swift
+++ b/test/attr/accessibility_print.swift
@@ -94,7 +94,7 @@
   case Foo, Bar
   // CHECK: internal init()
   init() { self = .Foo }
-  // CHECK: internal var hashValue
+  // CHECK: private var hashValue
 } // CHECK: {{^[}]}}
 
 // CHECK-LABEL: internal{{(\*/)?}} enum DB_InternalEnum {
diff --git a/test/attr/attr_versioned.swift b/test/attr/attr_versioned.swift
index 1a5682e..3a6fe43 100644
--- a/test/attr/attr_versioned.swift
+++ b/test/attr/attr_versioned.swift
@@ -45,3 +45,23 @@
   @_versioned func versionedRequirement() -> T
   // expected-error@-1 {{'@_versioned' attribute cannot be used in protocols}}
 }
+
+// Derived conformances had issues with @_versioned - rdar://problem/34342955
+@_versioned
+internal enum EqEnum {
+  case foo
+}
+
+@_versioned
+internal enum RawEnum : Int {
+  case foo = 0
+}
+
+@_inlineable
+public func usesEqEnum() -> Bool {
+  _ = (EqEnum.foo == .foo)
+  _ = EqEnum.foo.hashValue
+
+  _ = RawEnum.foo.rawValue
+  _ = RawEnum(rawValue: 0)
+}