Merge remote-tracking branch 'origin/swift-3.1-branch' into stable
diff --git a/include/clang/APINotes/APINotesReader.h b/include/clang/APINotes/APINotesReader.h
index a09bcc7..f96c7b6 100644
--- a/include/clang/APINotes/APINotesReader.h
+++ b/include/clang/APINotes/APINotesReader.h
@@ -25,6 +25,20 @@
namespace clang {
namespace api_notes {
+/// Describes the role of a specific bit of versioned information.
+enum class VersionedInfoRole : unsigned {
+ /// Augment the AST, but do not override information explicitly specified
+ /// in the source code.
+ AugmentSource,
+
+ /// Replace information that may have been explicitly specified in the source
+ /// code.
+ ReplaceSource,
+
+ /// Describes an alternate version of this information.
+ Versioned,
+};
+
/// A class that reads API notes data from a binary file that was written by
/// the \c APINotesWriter.
class APINotesReader {
@@ -80,6 +94,9 @@
/// Swift version, or \c Results.size() if nothing matched.
unsigned Selected;
+ /// The role of the selected index.
+ VersionedInfoRole SelectedRole;
+
public:
/// Form an empty set of versioned information.
VersionedInfo(llvm::NoneType) : Selected(0) { }
@@ -105,6 +122,11 @@
return Selected;
}
+ /// Describes the role of the selected entity.
+ VersionedInfoRole getSelectedRole() const {
+ return SelectedRole;
+ }
+
/// Return the number of versioned results we know about.
unsigned size() const { return Results.size(); }
diff --git a/include/clang/APINotes/Types.h b/include/clang/APINotes/Types.h
index 9761510..4620bfd 100644
--- a/include/clang/APINotes/Types.h
+++ b/include/clang/APINotes/Types.h
@@ -127,26 +127,48 @@
/// The Swift type to which a given type is bridged.
///
/// Reflects the swift_bridge attribute.
- std::string SwiftBridge;
+ Optional<std::string> SwiftBridge;
/// The NS error domain for this type.
- std::string NSErrorDomain;
+ Optional<std::string> NSErrorDomain;
public:
CommonTypeInfo() : CommonEntityInfo() { }
- const std::string &getSwiftBridge() const { return SwiftBridge; }
- void setSwiftBridge(const std::string &swiftType) { SwiftBridge = swiftType; }
+ const Optional<std::string> &getSwiftBridge() const { return SwiftBridge; }
- const std::string &getNSErrorDomain() const { return NSErrorDomain; }
- void setNSErrorDomain(const std::string &domain) { NSErrorDomain = domain; }
+ void setSwiftBridge(const Optional<std::string> &swiftType) {
+ SwiftBridge = swiftType;
+ }
+
+ void setSwiftBridge(const Optional<StringRef> &swiftType) {
+ if (swiftType)
+ SwiftBridge = *swiftType;
+ else
+ SwiftBridge = None;
+ }
+
+ const Optional<std::string> &getNSErrorDomain() const {
+ return NSErrorDomain;
+ }
+
+ void setNSErrorDomain(const Optional<std::string> &domain) {
+ NSErrorDomain = domain;
+ }
+
+ void setNSErrorDomain(const Optional<StringRef> &domain) {
+ if (domain)
+ NSErrorDomain = *domain;
+ else
+ NSErrorDomain = None;
+ }
friend CommonTypeInfo &operator|=(CommonTypeInfo &lhs,
const CommonTypeInfo &rhs) {
static_cast<CommonEntityInfo &>(lhs) |= rhs;
- if (lhs.SwiftBridge.empty() && !rhs.SwiftBridge.empty())
+ if (!lhs.SwiftBridge && rhs.SwiftBridge)
lhs.SwiftBridge = rhs.SwiftBridge;
- if (lhs.NSErrorDomain.empty() && !rhs.NSErrorDomain.empty())
+ if (!lhs.NSErrorDomain && rhs.NSErrorDomain)
lhs.NSErrorDomain = rhs.NSErrorDomain;
return lhs;
}
@@ -308,24 +330,41 @@
/// Describes a function or method parameter.
class ParamInfo : public VariableInfo {
+ /// Whether noescape was specified.
+ unsigned NoEscapeSpecified : 1;
+
/// Whether the this parameter has the 'noescape' attribute.
unsigned NoEscape : 1;
public:
- ParamInfo() : VariableInfo(), NoEscape(false) { }
+ ParamInfo() : VariableInfo(), NoEscapeSpecified(false), NoEscape(false) { }
- bool isNoEscape() const { return NoEscape; }
- void setNoEscape(bool noescape) { NoEscape = noescape; }
+ Optional<bool> isNoEscape() const {
+ if (!NoEscapeSpecified) return None;
+ return NoEscape;
+ }
+ void setNoEscape(Optional<bool> noescape) {
+ if (noescape) {
+ NoEscapeSpecified = true;
+ NoEscape = *noescape;
+ } else {
+ NoEscapeSpecified = false;
+ NoEscape = false;
+ }
+ }
friend ParamInfo &operator|=(ParamInfo &lhs, const ParamInfo &rhs) {
static_cast<VariableInfo &>(lhs) |= rhs;
- if (!lhs.NoEscape && rhs.NoEscape)
- lhs.NoEscape = true;
+ if (!lhs.NoEscapeSpecified && rhs.NoEscapeSpecified) {
+ lhs.NoEscapeSpecified = true;
+ lhs.NoEscape = rhs.NoEscape;
+ }
return lhs;
}
friend bool operator==(const ParamInfo &lhs, const ParamInfo &rhs) {
return static_cast<const VariableInfo &>(lhs) == rhs &&
+ lhs.NoEscapeSpecified == rhs.NoEscapeSpecified &&
lhs.NoEscape == rhs.NoEscape;
}
diff --git a/include/clang/AST/AttrIterator.h b/include/clang/AST/AttrIterator.h
index fb9b049..5ef250c 100644
--- a/include/clang/AST/AttrIterator.h
+++ b/include/clang/AST/AttrIterator.h
@@ -108,6 +108,8 @@
specific_attr_iterator Right) {
return !(Left == Right);
}
+
+ Iterator getCurrent() const { return Current; }
};
template <typename SpecificAttr, typename Container>
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index bb6029d..980602d 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -3097,11 +3097,15 @@
/// method) or an Objective-C property attribute, rather than as an
/// underscored type specifier.
///
+ /// \param overrideExisting Whether to override an existing, locally-specified
+ /// nullability specifier rather than complaining about the conflict.
+ ///
/// \returns true if nullability cannot be applied, false otherwise.
bool checkNullabilityTypeSpecifier(QualType &type, NullabilityKind nullability,
SourceLocation nullabilityLoc,
bool isContextSensitive,
- bool implicit);
+ bool implicit,
+ bool overrideExisting = false);
/// \brief Stmt attributes - this routine is the top level dispatcher.
StmtResult ProcessStmtAttributes(Stmt *Stmt, AttributeList *Attrs,
diff --git a/lib/APINotes/APINotesFormat.h b/lib/APINotes/APINotesFormat.h
index 9b68cf2..6f7734b 100644
--- a/lib/APINotes/APINotesFormat.h
+++ b/lib/APINotes/APINotesFormat.h
@@ -36,7 +36,7 @@
/// API notes file minor version number.
///
/// When the format changes IN ANY WAY, this number should be incremented.
-const uint16_t VERSION_MINOR = 16; // versioned API notes.
+const uint16_t VERSION_MINOR = 17; // optional NSErrorDomain
using IdentifierID = PointerEmbeddedInt<unsigned, 31>;
using IdentifierIDField = BCVBR<16>;
diff --git a/lib/APINotes/APINotesReader.cpp b/lib/APINotes/APINotesReader.cpp
index dda721e..0e25409 100644
--- a/lib/APINotes/APINotesReader.cpp
+++ b/lib/APINotes/APINotesReader.cpp
@@ -126,15 +126,19 @@
unsigned swiftBridgeLength =
endian::readNext<uint16_t, little, unaligned>(data);
- info.setSwiftBridge(
- StringRef(reinterpret_cast<const char *>(data), swiftBridgeLength));
- data += swiftBridgeLength;
+ if (swiftBridgeLength > 0) {
+ info.setSwiftBridge(
+ std::string(reinterpret_cast<const char *>(data), swiftBridgeLength-1));
+ data += swiftBridgeLength-1;
+ }
unsigned errorDomainLength =
endian::readNext<uint16_t, little, unaligned>(data);
- info.setNSErrorDomain(
- StringRef(reinterpret_cast<const char *>(data), errorDomainLength));
- data += errorDomainLength;
+ if (errorDomainLength > 0) {
+ info.setNSErrorDomain(
+ std::string(reinterpret_cast<const char *>(data), errorDomainLength-1));
+ data += errorDomainLength-1;
+ }
}
/// Used to deserialize the on-disk identifier table.
@@ -303,8 +307,10 @@
if (payload & 0x01)
pi.setNullabilityAudited(static_cast<NullabilityKind>(nullabilityValue));
payload >>= 1;
- pi.setNoEscape(payload & 0x01);
- payload >>= 1; assert(payload == 0 && "Bad API notes");
+ if (payload & 0x01) {
+ pi.setNoEscape(payload & 0x02);
+ }
+ payload >>= 2; assert(payload == 0 && "Bad API notes");
info.Params.push_back(pi);
--numParams;
@@ -1451,9 +1457,14 @@
// Look for an exact version match.
Optional<unsigned> unversioned;
Selected = Results.size();
+ SelectedRole = VersionedInfoRole::Versioned;
+
for (unsigned i = 0, n = Results.size(); i != n; ++i) {
if (Results[i].first == version) {
Selected = i;
+
+ if (version) SelectedRole = VersionedInfoRole::ReplaceSource;
+ else SelectedRole = VersionedInfoRole::AugmentSource;
break;
}
@@ -1465,9 +1476,11 @@
// If we didn't find a match but we have an unversioned result, use the
// unversioned result.
- if (Selected == Results.size() && unversioned)
+ if (Selected == Results.size() && unversioned) {
Selected = *unversioned;
-}
+ SelectedRole = VersionedInfoRole::AugmentSource;
+ }
+ }
auto APINotesReader::lookupObjCClassID(StringRef name) -> Optional<ContextID> {
if (!Impl.ObjCContextIDTable)
diff --git a/lib/APINotes/APINotesWriter.cpp b/lib/APINotes/APINotesWriter.cpp
index 6debe99..2cd5776 100644
--- a/lib/APINotes/APINotesWriter.cpp
+++ b/lib/APINotes/APINotesWriter.cpp
@@ -343,8 +343,8 @@
// Retrieve the serialized size of the given CommonTypeInfo, for use
// in on-disk hash tables.
static unsigned getCommonTypeInfoSize(const CommonTypeInfo &info) {
- return 2 + info.getSwiftBridge().size() +
- 2 + info.getNSErrorDomain().size() +
+ return 2 + (info.getSwiftBridge() ? info.getSwiftBridge()->size() : 0) +
+ 2 + (info.getNSErrorDomain() ? info.getNSErrorDomain()->size() : 0) +
getCommonEntityInfoSize(info);
}
@@ -352,10 +352,18 @@
static void emitCommonTypeInfo(raw_ostream &out, const CommonTypeInfo &info) {
emitCommonEntityInfo(out, info);
endian::Writer<little> writer(out);
- writer.write<uint16_t>(info.getSwiftBridge().size());
- out.write(info.getSwiftBridge().c_str(), info.getSwiftBridge().size());
- writer.write<uint16_t>(info.getNSErrorDomain().size());
- out.write(info.getNSErrorDomain().c_str(), info.getNSErrorDomain().size());
+ if (auto swiftBridge = info.getSwiftBridge()) {
+ writer.write<uint16_t>(swiftBridge->size() + 1);
+ out.write(swiftBridge->c_str(), swiftBridge->size());
+ } else {
+ writer.write<uint16_t>(0);
+ }
+ if (auto nsErrorDomain = info.getNSErrorDomain()) {
+ writer.write<uint16_t>(nsErrorDomain->size() + 1);
+ out.write(nsErrorDomain->c_str(), info.getNSErrorDomain()->size());
+ } else {
+ writer.write<uint16_t>(0);
+ }
}
/// Used to serialize the on-disk Objective-C context table.
@@ -687,7 +695,12 @@
// Parameters.
writer.write<uint16_t>(info.Params.size());
for (const auto &pi : info.Params) {
- uint8_t payload = pi.isNoEscape();
+ uint8_t payload = 0;
+ if (auto noescape = pi.isNoEscape()) {
+ payload |= 0x01;
+ if (*noescape)
+ payload |= 0x02;
+ }
auto nullability = pi.getNullability();
payload = (payload << 1) | nullability.hasValue();
diff --git a/lib/APINotes/APINotesYAMLCompiler.cpp b/lib/APINotes/APINotesYAMLCompiler.cpp
index 8f1e5a2..69ed542 100644
--- a/lib/APINotes/APINotesYAMLCompiler.cpp
+++ b/lib/APINotes/APINotesYAMLCompiler.cpp
@@ -171,7 +171,7 @@
struct Param {
unsigned Position;
- bool NoEscape = false;
+ Optional<bool> NoEscape = false;
llvm::Optional<NullabilityKind> Nullability;
};
typedef std::vector<Param> ParamsSeq;
@@ -208,8 +208,8 @@
AvailabilityItem Availability;
bool SwiftPrivate = false;
StringRef SwiftName;
- StringRef SwiftBridge;
- StringRef NSErrorDomain;
+ Optional<StringRef> SwiftBridge;
+ Optional<StringRef> NSErrorDomain;
MethodsSeq Methods;
PropertiesSeq Properties;
};
@@ -248,8 +248,8 @@
AvailabilityItem Availability;
StringRef SwiftName;
bool SwiftPrivate = false;
- StringRef SwiftBridge;
- StringRef NSErrorDomain;
+ Optional<StringRef> SwiftBridge;
+ Optional<StringRef> NSErrorDomain;
};
typedef std::vector<Tag> TagsSeq;
@@ -258,8 +258,8 @@
AvailabilityItem Availability;
StringRef SwiftName;
bool SwiftPrivate = false;
- StringRef SwiftBridge;
- StringRef NSErrorDomain;
+ Optional<StringRef> SwiftBridge;
+ Optional<StringRef> NSErrorDomain;
};
typedef std::vector<Typedef> TypedefsSeq;
@@ -929,7 +929,6 @@
// Convert the versioned information.
for (const auto &versioned : TheModule.SwiftVersions) {
convertTopLevelItems(versioned.Items, versioned.Version);
-
}
if (!ErrorOccured)
@@ -1034,6 +1033,20 @@
return StringRef(reinterpret_cast<const char *>(ptr), string.size());
}
+ /// Copy an optional string into allocated memory so it does disappear on us.
+ Optional<StringRef> maybeCopyString(Optional<StringRef> string) {
+ if (!string) return None;
+
+ return copyString(*string);
+ }
+
+ /// Copy an optional string into allocated memory so it does disappear on us.
+ Optional<StringRef> maybeCopyString(Optional<std::string> string) {
+ if (!string) return None;
+
+ return copyString(*string);
+ }
+
template<typename T>
void handleCommon(T &record, const CommonEntityInfo &info) {
handleAvailability(record.Availability, info);
@@ -1044,8 +1057,8 @@
template<typename T>
void handleCommonType(T &record, const CommonTypeInfo &info) {
handleCommon(record, info);
- record.SwiftBridge = copyString(info.getSwiftBridge());
- record.NSErrorDomain = copyString(info.getNSErrorDomain());
+ record.SwiftBridge = maybeCopyString(info.getSwiftBridge());
+ record.NSErrorDomain = maybeCopyString(info.getNSErrorDomain());
}
/// Map Objective-C context info.
diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp
index d270121..d1c77bb 100644
--- a/lib/AST/DeclObjC.cpp
+++ b/lib/AST/DeclObjC.cpp
@@ -897,9 +897,13 @@
return MD;
}
- if (isRedeclaration())
- return cast<ObjCContainerDecl>(CtxD)->getMethod(getSelector(),
- isInstanceMethod());
+ if (isRedeclaration()) {
+ // It is possible that we have not done deserializing the ObjCMethod yet.
+ ObjCMethodDecl *MD =
+ cast<ObjCContainerDecl>(CtxD)->getMethod(getSelector(),
+ isInstanceMethod());
+ return MD ? MD : this;
+ }
return this;
}
diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp
index 7e78699..e599840 100644
--- a/lib/AST/DeclPrinter.cpp
+++ b/lib/AST/DeclPrinter.cpp
@@ -1137,6 +1137,9 @@
return;
}
bool eolnOut = false;
+ prettyPrintAttributes(OID);
+ if (OID->hasAttrs()) Out << "\n";
+
Out << "@interface " << I;
if (auto TypeParams = OID->getTypeParamListAsWritten()) {
@@ -1346,6 +1349,17 @@
if (D->hasTypename())
Out << "typename ";
D->getQualifier()->print(Out, Policy);
+
+ // Use the correct record name when the using declaration is used for
+ // inheriting constructors.
+ for (const auto *Shadow : D->shadows()) {
+ if (const auto *ConstructorShadow =
+ dyn_cast<ConstructorUsingShadowDecl>(Shadow)) {
+ assert(Shadow->getDeclContext() == ConstructorShadow->getDeclContext());
+ Out << *ConstructorShadow->getNominatedBaseClass();
+ return;
+ }
+ }
Out << *D;
}
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index 0cb09f1..8d1a817 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -5364,6 +5364,8 @@
const char Arg[] = "-fapinotes-cache-path=";
APINotesCachePath.insert(APINotesCachePath.begin(), Arg, Arg + strlen(Arg));
CmdArgs.push_back(Args.MakeArgString(APINotesCachePath));
+
+ Args.AddLastArg(CmdArgs, options::OPT_fapinotes_swift_version);
}
// -fblocks=0 is default.
diff --git a/lib/Sema/SemaAPINotes.cpp b/lib/Sema/SemaAPINotes.cpp
index 4a666cc..89cf5b6 100644
--- a/lib/Sema/SemaAPINotes.cpp
+++ b/lib/Sema/SemaAPINotes.cpp
@@ -15,6 +15,7 @@
#include "clang/AST/DeclObjC.h"
#include "clang/APINotes/APINotesReader.h"
using namespace clang;
+using clang::api_notes::VersionedInfoRole;
/// Determine whether this is a multi-level pointer type.
static bool isMultiLevelPointerType(QualType type) {
@@ -27,7 +28,23 @@
}
// Apply nullability to the given declaration.
-static void applyNullability(Sema &S, Decl *decl, NullabilityKind nullability) {
+static void applyNullability(Sema &S, Decl *decl, NullabilityKind nullability,
+ VersionedInfoRole role) {
+ bool overrideExisting;
+ switch (role) {
+ case VersionedInfoRole::AugmentSource:
+ overrideExisting = false;
+ break;
+
+ case VersionedInfoRole::ReplaceSource:
+ overrideExisting = true;
+ break;
+
+ case VersionedInfoRole::Versioned:
+ // FIXME: Record versioned info?
+ return;
+ }
+
QualType type;
// Nullability for a function/method appertains to the retain type.
@@ -47,7 +64,8 @@
QualType origType = type;
S.checkNullabilityTypeSpecifier(type, nullability, decl->getLocation(),
/*isContextSensitive=*/false,
- /*implicit=*/true);
+ /*implicit=*/true,
+ overrideExisting);
if (type.getTypePtr() == origType.getTypePtr())
return;
@@ -100,104 +118,198 @@
return StringRef(static_cast<char *>(mem), string.size());
}
-static void ProcessAPINotes(Sema &S, Decl *D,
- const api_notes::CommonEntityInfo &Info) {
- // Availability
- if (Info.Unavailable && !D->hasAttr<UnavailableAttr>()) {
- D->addAttr(UnavailableAttr::CreateImplicit(S.Context,
- CopyString(S.Context,
- Info.UnavailableMsg)));
- }
+namespace {
+ /// Handle an attribute introduced by API notes.
+ ///
+ /// \param shouldAddAttribute Whether we should add a new attribute
+ /// (otherwise, we might remove an existing attribute).
+ /// \param createAttr Create the new attribute to be added.
+ /// \param getExistingAttr Get an existing, matching attribute on the given
+ /// declaration.
+ template<typename A>
+ void handleAPINotedAttribute(
+ Sema &S, Decl *D, bool shouldAddAttribute,
+ VersionedInfoRole role,
+ llvm::function_ref<A *()> createAttr,
+ llvm::function_ref<specific_attr_iterator<A>(Decl *)> getExistingAttr =
+ [](Decl *decl) { return decl->specific_attr_begin<A>(); }) {
+ switch (role) {
+ case VersionedInfoRole::AugmentSource:
+ // If we're not adding an attribute, there's nothing to do.
+ if (!shouldAddAttribute) return;
- if (Info.UnavailableInSwift) {
- D->addAttr(AvailabilityAttr::CreateImplicit(
- S.Context,
- &S.Context.Idents.get("swift"),
- VersionTuple(),
- VersionTuple(),
- VersionTuple(),
- /*Unavailable=*/true,
- CopyString(S.Context, Info.UnavailableMsg),
- /*Strict=*/false,
- /*Replacement=*/StringRef()));
- }
+ // If the attribute is already present, we're done.
+ if (getExistingAttr(D) != D->specific_attr_end<A>()) return;
- // swift_private
- if (Info.SwiftPrivate && !D->hasAttr<SwiftPrivateAttr>()) {
- D->addAttr(SwiftPrivateAttr::CreateImplicit(S.Context));
- }
+ // Add the attribute.
+ if (auto attr = createAttr())
+ D->addAttr(attr);
+ break;
- // swift_name
- if (!Info.SwiftName.empty() && !D->hasAttr<SwiftNameAttr>()) {
- auto &APINoteName = S.getASTContext().Idents.get("SwiftName API Note");
-
- if (!S.DiagnoseSwiftName(D, Info.SwiftName, D->getLocation(),
- &APINoteName)) {
- return;
+ case VersionedInfoRole::ReplaceSource: {
+ auto end = D->specific_attr_end<A>();
+ auto existing = getExistingAttr(D);
+ if (existing != end) {
+ // Remove the existing attribute.
+ D->getAttrs().erase(existing.getCurrent());
+ }
+
+ // If we're supposed to add a new attribute, do so.
+ if (shouldAddAttribute) {
+ if (auto attr = createAttr()) {
+ D->addAttr(attr);
+ }
+ }
+ break;
}
- D->addAttr(SwiftNameAttr::CreateImplicit(S.Context,
- CopyString(S.Context, Info.SwiftName)));
+
+ case VersionedInfoRole::Versioned:
+ // FIXME: Retain versioned attributes separately.
+ break;
+ }
}
}
static void ProcessAPINotes(Sema &S, Decl *D,
- const api_notes::CommonTypeInfo &Info) {
+ const api_notes::CommonEntityInfo &info,
+ VersionedInfoRole role) {
+ // Availability
+ if (info.Unavailable) {
+ handleAPINotedAttribute<UnavailableAttr>(S, D, true, role,
+ [&] {
+ return UnavailableAttr::CreateImplicit(S.Context,
+ CopyString(S.Context,
+ info.UnavailableMsg));
+ });
+ }
+
+ if (info.UnavailableInSwift) {
+ handleAPINotedAttribute<AvailabilityAttr>(S, D, true, role, [&] {
+ return AvailabilityAttr::CreateImplicit(
+ S.Context,
+ &S.Context.Idents.get("swift"),
+ VersionTuple(),
+ VersionTuple(),
+ VersionTuple(),
+ /*Unavailable=*/true,
+ CopyString(S.Context, info.UnavailableMsg),
+ /*Strict=*/false,
+ /*Replacement=*/StringRef());
+ },
+ [](Decl *decl) {
+ auto existing = decl->specific_attr_begin<AvailabilityAttr>(),
+ end = decl->specific_attr_end<AvailabilityAttr>();
+ while (existing != end) {
+ if (auto platform = (*existing)->getPlatform()) {
+ if (platform->isStr("swift"))
+ break;
+ }
+
+ ++existing;
+ }
+
+ return existing;
+ });
+ }
+
+ // swift_private
+ if (info.SwiftPrivate) {
+ handleAPINotedAttribute<SwiftPrivateAttr>(S, D, true, role, [&] {
+ return SwiftPrivateAttr::CreateImplicit(S.Context);
+ });
+ }
+
+ // swift_name
+ if (!info.SwiftName.empty()) {
+ handleAPINotedAttribute<SwiftNameAttr>(S, D, true, role,
+ [&]() -> SwiftNameAttr * {
+ auto &APINoteName = S.getASTContext().Idents.get("SwiftName API Note");
+
+ if (!S.DiagnoseSwiftName(D, info.SwiftName, D->getLocation(),
+ &APINoteName)) {
+ return nullptr;
+ }
+
+ return SwiftNameAttr::CreateImplicit(S.Context,
+ CopyString(S.Context,
+ info.SwiftName));
+ });
+ }
+}
+
+static void ProcessAPINotes(Sema &S, Decl *D,
+ const api_notes::CommonTypeInfo &info,
+ VersionedInfoRole role) {
// swift_bridge
- if (!Info.getSwiftBridge().empty() &&
- !D->getAttr<SwiftBridgeAttr>()) {
- D->addAttr(
- SwiftBridgeAttr::CreateImplicit(S.Context,
- CopyString(S.Context,
- Info.getSwiftBridge())));
+ if (auto swiftBridge = info.getSwiftBridge()) {
+ handleAPINotedAttribute<SwiftBridgeAttr>(S, D, !swiftBridge->empty(), role,
+ [&] {
+ return SwiftBridgeAttr::CreateImplicit(S.Context,
+ CopyString(S.Context,
+ *swiftBridge));
+ });
}
// ns_error_domain
- if (!Info.getNSErrorDomain().empty() &&
- !D->getAttr<NSErrorDomainAttr>()) {
- D->addAttr(
- NSErrorDomainAttr::CreateImplicit(
- S.Context,
- &S.Context.Idents.get(Info.getNSErrorDomain())));
+ if (auto nsErrorDomain = info.getNSErrorDomain()) {
+ handleAPINotedAttribute<NSErrorDomainAttr>(S, D, !nsErrorDomain->empty(),
+ role, [&] {
+ return NSErrorDomainAttr::CreateImplicit(
+ S.Context,
+ &S.Context.Idents.get(*nsErrorDomain));
+ });
}
- ProcessAPINotes(S, D, static_cast<const api_notes::CommonEntityInfo &>(Info));
+ ProcessAPINotes(S, D, static_cast<const api_notes::CommonEntityInfo &>(info),
+ role);
}
/// Process API notes for a variable or property.
static void ProcessAPINotes(Sema &S, Decl *D,
- const api_notes::VariableInfo &Info) {
+ const api_notes::VariableInfo &info,
+ VersionedInfoRole role) {
// Nullability.
- if (auto Nullability = Info.getNullability()) {
- applyNullability(S, D, *Nullability);
+ if (auto Nullability = info.getNullability()) {
+ applyNullability(S, D, *Nullability, role);
}
// Handle common entity information.
- ProcessAPINotes(S, D, static_cast<const api_notes::CommonEntityInfo &>(Info));
+ ProcessAPINotes(S, D, static_cast<const api_notes::CommonEntityInfo &>(info),
+ role);
}
/// Process API notes for a parameter.
static void ProcessAPINotes(Sema &S, ParmVarDecl *D,
- const api_notes::ParamInfo &Info) {
+ const api_notes::ParamInfo &info,
+ VersionedInfoRole role) {
// noescape
- if (Info.isNoEscape() && !D->getAttr<NoEscapeAttr>())
- D->addAttr(NoEscapeAttr::CreateImplicit(S.Context));
+ if (auto noescape = info.isNoEscape()) {
+ handleAPINotedAttribute<NoEscapeAttr>(S, D, *noescape, role, [&] {
+ return NoEscapeAttr::CreateImplicit(S.Context);
+ });
+ }
// Handle common entity information.
- ProcessAPINotes(S, D, static_cast<const api_notes::VariableInfo &>(Info));
+ ProcessAPINotes(S, D, static_cast<const api_notes::VariableInfo &>(info),
+ role);
}
/// Process API notes for a global variable.
static void ProcessAPINotes(Sema &S, VarDecl *D,
- const api_notes::GlobalVariableInfo &Info) {
+ const api_notes::GlobalVariableInfo &info,
+ VersionedInfoRole role) {
// Handle common entity information.
- ProcessAPINotes(S, D, static_cast<const api_notes::VariableInfo &>(Info));
+ ProcessAPINotes(S, D, static_cast<const api_notes::VariableInfo &>(info),
+ role);
}
/// Process API notes for an Objective-C property.
static void ProcessAPINotes(Sema &S, ObjCPropertyDecl *D,
- const api_notes::ObjCPropertyInfo &Info) {
+ const api_notes::ObjCPropertyInfo &info,
+ VersionedInfoRole role) {
// Handle common entity information.
- ProcessAPINotes(S, D, static_cast<const api_notes::VariableInfo &>(Info));
+ ProcessAPINotes(S, D, static_cast<const api_notes::VariableInfo &>(info),
+ role);
}
namespace {
@@ -206,7 +318,8 @@
/// Process API notes for a function or method.
static void ProcessAPINotes(Sema &S, FunctionOrMethod AnyFunc,
- const api_notes::FunctionInfo &Info) {
+ const api_notes::FunctionInfo &info,
+ VersionedInfoRole role) {
// Find the declaration itself.
FunctionDecl *FD = AnyFunc.dyn_cast<FunctionDecl *>();
Decl *D = FD;
@@ -217,8 +330,8 @@
}
// Nullability of return type.
- if (Info.NullabilityAudited) {
- applyNullability(S, D, Info.getReturnTypeInfo());
+ if (info.NullabilityAudited) {
+ applyNullability(S, D, info.getReturnTypeInfo(), role);
}
// Parameters.
@@ -236,48 +349,57 @@
Param = MD->param_begin()[I];
// Nullability.
- if (Info.NullabilityAudited)
- applyNullability(S, Param, Info.getParamTypeInfo(I));
+ if (info.NullabilityAudited)
+ applyNullability(S, Param, info.getParamTypeInfo(I), role);
- if (I < Info.Params.size()) {
- ProcessAPINotes(S, Param, Info.Params[I]);
+ if (I < info.Params.size()) {
+ ProcessAPINotes(S, Param, info.Params[I], role);
}
}
// Handle common entity information.
- ProcessAPINotes(S, D, static_cast<const api_notes::CommonEntityInfo &>(Info));
+ ProcessAPINotes(S, D, static_cast<const api_notes::CommonEntityInfo &>(info),
+ role);
}
/// Process API notes for a global function.
static void ProcessAPINotes(Sema &S, FunctionDecl *D,
- const api_notes::GlobalFunctionInfo &Info) {
+ const api_notes::GlobalFunctionInfo &info,
+ VersionedInfoRole role) {
// Handle common function information.
ProcessAPINotes(S, FunctionOrMethod(D),
- static_cast<const api_notes::FunctionInfo &>(Info));
+ static_cast<const api_notes::FunctionInfo &>(info), role);
}
/// Process API notes for an enumerator.
static void ProcessAPINotes(Sema &S, EnumConstantDecl *D,
- const api_notes::EnumConstantInfo &Info) {
+ const api_notes::EnumConstantInfo &info,
+ VersionedInfoRole role) {
// Handle common information.
ProcessAPINotes(S, D,
- static_cast<const api_notes::CommonEntityInfo &>(Info));
+ static_cast<const api_notes::CommonEntityInfo &>(info),
+ role);
}
/// Process API notes for an Objective-C method.
static void ProcessAPINotes(Sema &S, ObjCMethodDecl *D,
- const api_notes::ObjCMethodInfo &Info) {
+ const api_notes::ObjCMethodInfo &info,
+ VersionedInfoRole role) {
// Designated initializers.
- if (Info.DesignatedInit && !D->getAttr<ObjCDesignatedInitializerAttr>()) {
- if (ObjCInterfaceDecl *IFace = D->getClassInterface()) {
- D->addAttr(ObjCDesignatedInitializerAttr::CreateImplicit(S.Context));
- IFace->setHasDesignatedInitializers();
- }
+ if (info.DesignatedInit) {
+ handleAPINotedAttribute<ObjCDesignatedInitializerAttr>(S, D, true, role, [&] {
+ if (ObjCInterfaceDecl *IFace = D->getClassInterface()) {
+ IFace->setHasDesignatedInitializers();
+ }
+ return ObjCDesignatedInitializerAttr::CreateImplicit(S.Context);
+ });
}
- if (Info.getFactoryAsInitKind()
+ // FIXME: This doesn't work well with versioned API notes.
+ if (role == VersionedInfoRole::AugmentSource &&
+ info.getFactoryAsInitKind()
== api_notes::FactoryAsInitKind::AsClassMethod &&
!D->getAttr<SwiftNameAttr>()) {
D->addAttr(SwiftSuppressFactoryAsInitAttr::CreateImplicit(S.Context));
@@ -285,36 +407,43 @@
// Handle common function information.
ProcessAPINotes(S, FunctionOrMethod(D),
- static_cast<const api_notes::FunctionInfo &>(Info));
+ static_cast<const api_notes::FunctionInfo &>(info), role);
}
/// Process API notes for a tag.
static void ProcessAPINotes(Sema &S, TagDecl *D,
- const api_notes::TagInfo &Info) {
+ const api_notes::TagInfo &info,
+ VersionedInfoRole role) {
// Handle common type information.
- ProcessAPINotes(S, D, static_cast<const api_notes::CommonTypeInfo &>(Info));
+ ProcessAPINotes(S, D, static_cast<const api_notes::CommonTypeInfo &>(info),
+ role);
}
/// Process API notes for a typedef.
static void ProcessAPINotes(Sema &S, TypedefNameDecl *D,
- const api_notes::TypedefInfo &Info) {
+ const api_notes::TypedefInfo &info,
+ VersionedInfoRole role) {
// Handle common type information.
- ProcessAPINotes(S, D, static_cast<const api_notes::CommonTypeInfo &>(Info));
+ ProcessAPINotes(S, D, static_cast<const api_notes::CommonTypeInfo &>(info),
+ role);
}
/// Process API notes for an Objective-C class or protocol.
static void ProcessAPINotes(Sema &S, ObjCContainerDecl *D,
- const api_notes::ObjCContextInfo &Info) {
+ const api_notes::ObjCContextInfo &info,
+ VersionedInfoRole role) {
// Handle common type information.
- ProcessAPINotes(S, D, static_cast<const api_notes::CommonTypeInfo &>(Info));
+ ProcessAPINotes(S, D, static_cast<const api_notes::CommonTypeInfo &>(info),
+ role);
}
/// Process API notes for an Objective-C class.
static void ProcessAPINotes(Sema &S, ObjCInterfaceDecl *D,
- const api_notes::ObjCContextInfo &Info) {
+ const api_notes::ObjCContextInfo &info,
+ VersionedInfoRole role) {
// Handle information common to Objective-C classes and protocols.
- ProcessAPINotes(S, static_cast<clang::ObjCContainerDecl *>(D), Info);
+ ProcessAPINotes(S, static_cast<clang::ObjCContainerDecl *>(D), info, role);
}
/// Process API notes that are associated with this declaration, mapping them
@@ -329,7 +458,7 @@
if (auto VD = dyn_cast<VarDecl>(D)) {
for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
if (auto Info = Reader->lookupGlobalVariable(VD->getName())) {
- ::ProcessAPINotes(*this, VD, *Info);
+ ::ProcessAPINotes(*this, VD, *Info, Info.getSelectedRole());
}
}
@@ -341,7 +470,7 @@
if (FD->getDeclName().isIdentifier()) {
for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
if (auto Info = Reader->lookupGlobalFunction(FD->getName())) {
- ::ProcessAPINotes(*this, FD, *Info);
+ ::ProcessAPINotes(*this, FD, *Info, Info.getSelectedRole());
}
}
}
@@ -353,7 +482,7 @@
if (auto Class = dyn_cast<ObjCInterfaceDecl>(D)) {
for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
if (auto Info = Reader->lookupObjCClassInfo(Class->getName())) {
- ::ProcessAPINotes(*this, Class, *Info);
+ ::ProcessAPINotes(*this, Class, *Info, Info.getSelectedRole());
}
}
@@ -364,7 +493,7 @@
if (auto Protocol = dyn_cast<ObjCProtocolDecl>(D)) {
for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
if (auto Info = Reader->lookupObjCProtocolInfo(Protocol->getName())) {
- ::ProcessAPINotes(*this, Protocol, *Info);
+ ::ProcessAPINotes(*this, Protocol, *Info, Info.getSelectedRole());
}
}
@@ -375,7 +504,7 @@
if (auto Tag = dyn_cast<TagDecl>(D)) {
for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
if (auto Info = Reader->lookupTag(Tag->getName())) {
- ::ProcessAPINotes(*this, Tag, *Info);
+ ::ProcessAPINotes(*this, Tag, *Info, Info.getSelectedRole());
}
}
@@ -386,7 +515,7 @@
if (auto Typedef = dyn_cast<TypedefNameDecl>(D)) {
for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
if (auto Info = Reader->lookupTypedef(Typedef->getName())) {
- ::ProcessAPINotes(*this, Typedef, *Info);
+ ::ProcessAPINotes(*this, Typedef, *Info, Info.getSelectedRole());
}
}
@@ -401,7 +530,7 @@
if (auto EnumConstant = dyn_cast<EnumConstantDecl>(D)) {
for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
if (auto Info = Reader->lookupEnumConstant(EnumConstant->getName())) {
- ::ProcessAPINotes(*this, EnumConstant, *Info);
+ ::ProcessAPINotes(*this, EnumConstant, *Info, Info.getSelectedRole());
}
}
@@ -472,7 +601,7 @@
if (auto Info = Reader->lookupObjCMethod(*Context, SelectorRef,
Method->isInstanceMethod())){
- ::ProcessAPINotes(*this, Method, *Info);
+ ::ProcessAPINotes(*this, Method, *Info, Info.getSelectedRole());
}
}
}
@@ -488,7 +617,7 @@
if (auto Info = Reader->lookupObjCProperty(*Context,
Property->getName(),
isInstanceProperty)) {
- ::ProcessAPINotes(*this, Property, *Info);
+ ::ProcessAPINotes(*this, Property, *Info, Info.getSelectedRole());
}
}
}
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index edfea14..e170b7e 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -5797,11 +5797,31 @@
return false;
}
+/// Rebuild an attributed type without the nullability attribute on it.
+static QualType rebuildAttributedTypeWithoutNullability(ASTContext &ctx,
+ QualType type) {
+ auto attributed = dyn_cast<AttributedType>(type.getTypePtr());
+ if (!attributed) return type;
+
+ // Skip the nullability attribute; we're done.
+ if (attributed->getImmediateNullability()) {
+ return attributed->getModifiedType();
+ }
+
+ // Build the modified type.
+ auto modified = rebuildAttributedTypeWithoutNullability(
+ ctx, attributed->getModifiedType());
+ assert(modified.getTypePtr() != attributed->getModifiedType().getTypePtr());
+ return ctx.getAttributedType(attributed->getAttrKind(), modified,
+ attributed->getEquivalentType());
+}
+
bool Sema::checkNullabilityTypeSpecifier(QualType &type,
NullabilityKind nullability,
SourceLocation nullabilityLoc,
bool isContextSensitive,
- bool implicit) {
+ bool implicit,
+ bool overrideExisting) {
if (!implicit) {
// We saw a nullability type specifier. If this is the first one for
// this file, note that.
@@ -5838,11 +5858,16 @@
break;
}
- // Conflicting nullability.
- Diag(nullabilityLoc, diag::err_nullability_conflicting)
- << DiagNullabilityKind(nullability, isContextSensitive)
- << DiagNullabilityKind(*existingNullability, false);
- return true;
+ if (!overrideExisting) {
+ // Conflicting nullability.
+ Diag(nullabilityLoc, diag::err_nullability_conflicting)
+ << DiagNullabilityKind(nullability, isContextSensitive)
+ << DiagNullabilityKind(*existingNullability, false);
+ return true;
+ }
+
+ // Rebuild the attributed type, dropping the existing nullability.
+ type = rebuildAttributedTypeWithoutNullability(Context, type);
}
desugared = attributed->getModifiedType();
diff --git a/test/APINotes/Inputs/Frameworks/SomeKit.framework/APINotes/SomeKit.apinotes b/test/APINotes/Inputs/Frameworks/SomeKit.framework/APINotes/SomeKit.apinotes
index 9c855c6..aa43d84 100644
--- a/test/APINotes/Inputs/Frameworks/SomeKit.framework/APINotes/SomeKit.apinotes
+++ b/test/APINotes/Inputs/Frameworks/SomeKit.framework/APINotes/SomeKit.apinotes
@@ -40,3 +40,10 @@
MethodKind: Instance
NullabilityOfRet: O
Nullability: [ O, S ]
+ Properties:
+ - Name: explicitNonnullInstance
+ PropertyKind: Instance
+ Nullability: O
+ - Name: explicitNullableInstance
+ PropertyKind: Instance
+ Nullability: N
diff --git a/test/APINotes/Inputs/Frameworks/SomeKit.framework/Headers/SomeKit.apinotes b/test/APINotes/Inputs/Frameworks/SomeKit.framework/Headers/SomeKit.apinotes
index 9c855c6..aa43d84 100644
--- a/test/APINotes/Inputs/Frameworks/SomeKit.framework/Headers/SomeKit.apinotes
+++ b/test/APINotes/Inputs/Frameworks/SomeKit.framework/Headers/SomeKit.apinotes
@@ -40,3 +40,10 @@
MethodKind: Instance
NullabilityOfRet: O
Nullability: [ O, S ]
+ Properties:
+ - Name: explicitNonnullInstance
+ PropertyKind: Instance
+ Nullability: O
+ - Name: explicitNullableInstance
+ PropertyKind: Instance
+ Nullability: N
diff --git a/test/APINotes/Inputs/Frameworks/SomeKit.framework/Headers/SomeKit.h b/test/APINotes/Inputs/Frameworks/SomeKit.framework/Headers/SomeKit.h
index eb25cc0..60d9afa 100644
--- a/test/APINotes/Inputs/Frameworks/SomeKit.framework/Headers/SomeKit.h
+++ b/test/APINotes/Inputs/Frameworks/SomeKit.framework/Headers/SomeKit.h
@@ -35,4 +35,6 @@
@property (class, nonatomic, readwrite, retain) A *nonnullABoth;
@end
+#import <SomeKit/SomeKitExplicitNullability.h>
+
#endif
diff --git a/test/APINotes/Inputs/Frameworks/VersionedKit.framework/Headers/VersionedKit.apinotes b/test/APINotes/Inputs/Frameworks/VersionedKit.framework/Headers/VersionedKit.apinotes
new file mode 100644
index 0000000..1fc6aa4
--- /dev/null
+++ b/test/APINotes/Inputs/Frameworks/VersionedKit.framework/Headers/VersionedKit.apinotes
@@ -0,0 +1,18 @@
+Name: SomeKit
+SwiftVersions:
+ - Version: 3.0
+ Classes:
+ - Name: MyReferenceType
+ SwiftBridge: ''
+ Functions:
+ - Name: moveToPoint
+ SwiftName: 'moveTo(a:b:)'
+ - Name: acceptClosure
+ Parameters:
+ - Position: 0
+ NoEscape: false
+ Tags:
+ - Name: MyErrorCode
+ NSErrorDomain: ''
+
+
\ No newline at end of file
diff --git a/test/APINotes/Inputs/Frameworks/VersionedKit.framework/Headers/VersionedKit.h b/test/APINotes/Inputs/Frameworks/VersionedKit.framework/Headers/VersionedKit.h
new file mode 100644
index 0000000..741bdaa
--- /dev/null
+++ b/test/APINotes/Inputs/Frameworks/VersionedKit.framework/Headers/VersionedKit.h
@@ -0,0 +1,15 @@
+void moveToPoint(double x, double y) __attribute__((swift_name("moveTo(x:y:)")));
+
+void acceptClosure(void (^ __attribute__((noescape)) block)(void));
+
+@class NSString;
+
+extern NSString *MyErrorDomain;
+
+enum __attribute__((ns_error_domain(MyErrorDomain))) MyErrorCode {
+ MyErrorCodeFailed = 1
+};
+
+__attribute__((swift_bridge("MyValueType")))
+@interface MyReferenceType
+@end
diff --git a/test/APINotes/Inputs/Frameworks/VersionedKit.framework/Modules/module.modulemap b/test/APINotes/Inputs/Frameworks/VersionedKit.framework/Modules/module.modulemap
new file mode 100644
index 0000000..6d957fd
--- /dev/null
+++ b/test/APINotes/Inputs/Frameworks/VersionedKit.framework/Modules/module.modulemap
@@ -0,0 +1,5 @@
+framework module VersionedKit {
+ umbrella header "VersionedKit.h"
+ export *
+ module * { export * }
+}
diff --git a/test/APINotes/Inputs/roundtrip.apinotes b/test/APINotes/Inputs/roundtrip.apinotes
index 13e08a1..7e2e68a 100644
--- a/test/APINotes/Inputs/roundtrip.apinotes
+++ b/test/APINotes/Inputs/roundtrip.apinotes
@@ -9,8 +9,6 @@
AvailabilityMsg: ''
SwiftPrivate: false
SwiftName: ''
- SwiftBridge: ''
- NSErrorDomain: ''
Methods:
- Selector: 'cellWithImage:'
MethodKind: Class
@@ -62,7 +60,6 @@
SwiftPrivate: false
SwiftName: ''
SwiftBridge: View
- NSErrorDomain: ''
Methods:
- Selector: 'addSubview:'
MethodKind: Instance
@@ -78,7 +75,6 @@
- Position: 0
NoEscape: false
- Position: 1
- NoEscape: false
- Position: 2
NoEscape: true
Nullability: [ N, N, O ]
@@ -136,14 +132,12 @@
AvailabilityMsg: ''
SwiftPrivate: false
SwiftName: SomeEnum
- SwiftBridge: ''
NSErrorDomain: some_error_domain
- Name: NSSomeStruct
Availability: available
AvailabilityMsg: ''
SwiftPrivate: false
SwiftName: SomeStruct
- SwiftBridge: ''
NSErrorDomain: ''
Typedefs:
- Name: NSTypedef
@@ -152,7 +146,6 @@
SwiftPrivate: false
SwiftName: Typedef
SwiftBridge: ''
- NSErrorDomain: ''
SwiftVersions:
- Version: 3.0
Classes:
@@ -162,7 +155,6 @@
SwiftPrivate: false
SwiftName: NSBox
SwiftBridge: ''
- NSErrorDomain: ''
Methods:
- Selector: init
MethodKind: Instance
diff --git a/test/APINotes/nullability.m b/test/APINotes/nullability.m
index c11cea5..f70c363 100644
--- a/test/APINotes/nullability.m
+++ b/test/APINotes/nullability.m
@@ -3,7 +3,7 @@
// Test with Swift version 3.0. This should only affect the few APIs that have an entry in the 3.0 tables.
-// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fapinotes-modules -fapinotes-cache-path=%t/APINotesCache -fapinotes-swift-version=3.0 -fsyntax-only -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -verify -DSWIFT_VERSION_3_0
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fapinotes-modules -fapinotes-cache-path=%t/APINotesCache -fapinotes-swift-version=3.0 -fsyntax-only -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -verify -DSWIFT_VERSION_3_0 -fmodules-ignore-macro=SWIFT_VERSION_3_0
#import <SomeKit/SomeKit.h>
@@ -29,6 +29,16 @@
[a setInternalProperty: 0]; // expected-warning{{null passed to a callee that requires a non-null argument}}
+#if SWIFT_VERSION_3_0
+ // Version 3 information overrides header information.
+ [a setExplicitNonnullInstance: 0]; // okay
+ [a setExplicitNullableInstance: 0]; // expected-warning{{null passed to a callee that requires a non-null argument}}
+#else
+ // Header information overrides unversioned information.
+ [a setExplicitNonnullInstance: 0]; // expected-warning{{null passed to a callee that requires a non-null argument}}
+ [a setExplicitNullableInstance: 0]; // okay
+#endif
+
return 0;
}
diff --git a/test/APINotes/versioned.m b/test/APINotes/versioned.m
new file mode 100644
index 0000000..53af333
--- /dev/null
+++ b/test/APINotes/versioned.m
@@ -0,0 +1,31 @@
+// RUN: rm -rf %t && mkdir -p %t
+
+// Build and check the unversioned module file.
+// RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache/Unversioned -fdisable-module-hash -fapinotes-modules -fapinotes-cache-path=%t/APINotesCache -fsyntax-only -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s
+// RUN: %clang_cc1 -ast-print %t/ModulesCache/Unversioned/VersionedKit.pcm | FileCheck -check-prefix=CHECK-UNVERSIONED %s
+
+// Build and check the versioned module file.
+// RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache/Versioned -fdisable-module-hash -fapinotes-modules -fapinotes-cache-path=%t/APINotesCache -fapinotes-swift-version=3.0 -fsyntax-only -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s
+// RUN: %clang_cc1 -ast-print %t/ModulesCache/Versioned/VersionedKit.pcm | FileCheck -check-prefix=CHECK-VERSIONED %s
+
+#import <VersionedKit/VersionedKit.h>
+
+// CHECK-UNVERSIONED: void moveToPoint(double x, double y) __attribute__((swift_name("moveTo(x:y:)")));
+// CHECK-VERSIONED: void moveToPoint(double x, double y) __attribute__((swift_name("moveTo(a:b:)")));
+
+// CHECK-UNVERSIONED: void acceptClosure(void (^block)(void) __attribute__((noescape)));
+// CHECK-VERSIONED: void acceptClosure(void (^block)(void));
+
+// CHECK-UNVERSIONED: enum MyErrorCode {
+// CHECK-UNVERSIONED-NEXT: MyErrorCodeFailed = 1
+// CHECK-UNVERSIONED-NEXT: } __attribute__((ns_error_domain(MyErrorDomain)));
+
+// CHECK-UNVERSIONED: __attribute__((swift_bridge("MyValueType")))
+// CHECK-UNVERSIONED: @interface MyReferenceType
+
+// CHECK-VERSIONED: enum MyErrorCode {
+// CHECK-VERSIONED-NEXT: MyErrorCodeFailed = 1
+// CHECK-VERSIONED-NEXT: };
+
+// CHECK-VERSIONED-NOT: __attribute__((swift_bridge("MyValueType")))
+// CHECK-VERSIONED: @interface MyReferenceType
diff --git a/test/Modules/Inputs/objc-method-redecl.h b/test/Modules/Inputs/objc-method-redecl.h
new file mode 100644
index 0000000..95c6533
--- /dev/null
+++ b/test/Modules/Inputs/objc-method-redecl.h
@@ -0,0 +1,4 @@
+@interface T
+- (void)test;
+- (void)test;
+@end
diff --git a/test/Modules/objc-method-redecl.m b/test/Modules/objc-method-redecl.m
new file mode 100644
index 0000000..f7acda5
--- /dev/null
+++ b/test/Modules/objc-method-redecl.m
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -x objective-c-header -emit-pch %S/Inputs/objc-method-redecl.h -o %t.pch -Wno-objc-root-class
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -x objective-c -include-pch %t.pch %s -verify -Wno-objc-root-class
+// expected-no-diagnostics
+
+@implementation T
+- (void)test {
+}
+@end
diff --git a/test/SemaCXX/cxx11-ast-print.cpp b/test/SemaCXX/cxx11-ast-print.cpp
index 1eeb67a..9c617af 100644
--- a/test/SemaCXX/cxx11-ast-print.cpp
+++ b/test/SemaCXX/cxx11-ast-print.cpp
@@ -43,6 +43,14 @@
// CHECK: const char *PR23120 = operator""_suffix<char32_t, 66615>();
const char *PR23120 = U"𐐷"_suffix;
+// PR28885
+struct A {
+ A();
+};
+struct B : A {
+ using A::A; // CHECK: using A::A;
+}; // CHECK-NEXT: };
+
// CHECK: ;
;
// CHECK-NOT: ;