diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/AST/ASTContext.cpp | 1 | ||||
-rw-r--r-- | clang/lib/AST/DeclBase.cpp | 150 | ||||
-rw-r--r-- | clang/lib/AST/ExprConstant.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Basic/CMakeLists.txt | 1 | ||||
-rw-r--r-- | clang/lib/Basic/TargetInfo.cpp | 4 | ||||
-rw-r--r-- | clang/lib/Basic/Targets.cpp | 15 | ||||
-rw-r--r-- | clang/lib/Basic/VersionTuple.cpp | 36 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGObjCMac.cpp | 10 | ||||
-rw-r--r-- | clang/lib/CodeGen/CodeGenModule.cpp | 6 | ||||
-rw-r--r-- | clang/lib/Parse/ParseDecl.cpp | 240 | ||||
-rw-r--r-- | clang/lib/Parse/Parser.cpp | 4 | ||||
-rw-r--r-- | clang/lib/Sema/AttributeList.cpp | 19 | ||||
-rw-r--r-- | clang/lib/Sema/CodeCompleteConsumer.cpp | 17 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclAttr.cpp | 81 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclObjC.cpp | 11 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 60 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExprCXX.cpp | 6 | ||||
-rw-r--r-- | clang/lib/Sema/SemaObjCProperty.cpp | 12 | ||||
-rw-r--r-- | clang/lib/Sema/SemaOverload.cpp | 26 | ||||
-rw-r--r-- | clang/lib/Serialization/ASTReader.cpp | 13 | ||||
-rw-r--r-- | clang/lib/Serialization/ASTWriter.cpp | 14 |
21 files changed, 643 insertions, 85 deletions
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index fd5fd0e54b2..e208bfdf1df 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -451,7 +451,6 @@ void ASTContext::eraseDeclAttrs(const Decl *D) { } } - MemberSpecializationInfo * ASTContext::getInstantiatedFromStaticDataMember(const VarDecl *Var) { assert(Var->isStaticDataMember() && "Not a static data member"); diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index 8d6a5412a55..11d28df4be7 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -25,6 +25,7 @@ #include "clang/AST/Stmt.h" #include "clang/AST/StmtCXX.h" #include "clang/AST/ASTMutationListener.h" +#include "clang/Basic/TargetInfo.h" #include "llvm/ADT/DenseMap.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> @@ -241,6 +242,155 @@ bool Decl::isUsed(bool CheckUsedAttr) const { return false; } +/// \brief Determine the availability of the given declaration based on +/// the target platform. +/// +/// When it returns an availability result other than \c AR_Available, +/// if the \p Message parameter is non-NULL, it will be set to a +/// string describing why the entity is unavailable. +/// +/// FIXME: Make these strings localizable, since they end up in +/// diagnostics. +static AvailabilityResult CheckAvailability(ASTContext &Context, + const AvailabilityAttr *A, + std::string *Message) { + llvm::StringRef TargetPlatform = Context.Target.getPlatformName(); + llvm::StringRef PrettyPlatformName + = AvailabilityAttr::getPrettyPlatformName(TargetPlatform); + if (PrettyPlatformName.empty()) + PrettyPlatformName = TargetPlatform; + + VersionTuple TargetMinVersion = Context.Target.getPlatformMinVersion(); + if (TargetMinVersion.empty()) + return AR_Available; + + // Match the platform name. + if (A->getPlatform()->getName() != TargetPlatform) + return AR_Available; + + // Make sure that this declaration has already been introduced. + if (!A->getIntroduced().empty() && + TargetMinVersion < A->getIntroduced()) { + if (Message) { + Message->clear(); + llvm::raw_string_ostream Out(*Message); + Out << "introduced in " << PrettyPlatformName << ' ' + << A->getIntroduced(); + } + + return AR_NotYetIntroduced; + } + + // Make sure that this declaration hasn't been obsoleted. + if (!A->getObsoleted().empty() && TargetMinVersion >= A->getObsoleted()) { + if (Message) { + Message->clear(); + llvm::raw_string_ostream Out(*Message); + Out << "obsoleted in " << PrettyPlatformName << ' ' + << A->getObsoleted(); + } + + return AR_Unavailable; + } + + // Make sure that this declaration hasn't been deprecated. + if (!A->getDeprecated().empty() && TargetMinVersion >= A->getDeprecated()) { + if (Message) { + Message->clear(); + llvm::raw_string_ostream Out(*Message); + Out << "first deprecated in " << PrettyPlatformName << ' ' + << A->getDeprecated(); + } + + return AR_Deprecated; + } + + return AR_Available; +} + +AvailabilityResult Decl::getAvailability(std::string *Message) const { + AvailabilityResult Result = AR_Available; + std::string ResultMessage; + + for (attr_iterator A = attr_begin(), AEnd = attr_end(); A != AEnd; ++A) { + if (DeprecatedAttr *Deprecated = dyn_cast<DeprecatedAttr>(*A)) { + if (Result >= AR_Deprecated) + continue; + + if (Message) + ResultMessage = Deprecated->getMessage(); + + Result = AR_Deprecated; + continue; + } + + if (UnavailableAttr *Unavailable = dyn_cast<UnavailableAttr>(*A)) { + if (Message) + *Message = Unavailable->getMessage(); + return AR_Unavailable; + } + + if (AvailabilityAttr *Availability = dyn_cast<AvailabilityAttr>(*A)) { + AvailabilityResult AR = CheckAvailability(getASTContext(), Availability, + Message); + + if (AR == AR_Unavailable) + return AR_Unavailable; + + if (AR > Result) { + Result = AR; + if (Message) + ResultMessage.swap(*Message); + } + continue; + } + } + + if (Message) + Message->swap(ResultMessage); + return Result; +} + +bool Decl::canBeWeakImported(bool &IsDefinition) const { + IsDefinition = false; + if (const VarDecl *Var = dyn_cast<VarDecl>(this)) { + if (!Var->hasExternalStorage() || Var->getInit()) { + IsDefinition = true; + return false; + } + } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(this)) { + if (FD->hasBody()) { + IsDefinition = true; + return false; + } + } else if (isa<ObjCPropertyDecl>(this) || isa<ObjCMethodDecl>(this)) + return false; + else if (!(getASTContext().getLangOptions().ObjCNonFragileABI && + isa<ObjCInterfaceDecl>(this))) + return false; + + return true; +} + +bool Decl::isWeakImported() const { + bool IsDefinition; + if (!canBeWeakImported(IsDefinition)) + return false; + + ASTContext &Context = getASTContext(); + for (attr_iterator A = attr_begin(), AEnd = attr_end(); A != AEnd; ++A) { + if (isa<WeakImportAttr>(*A)) + return true; + + if (AvailabilityAttr *Availability = dyn_cast<AvailabilityAttr>(*A)) { + if (CheckAvailability(getASTContext(), Availability, 0) + == AR_NotYetIntroduced) + return true; + } + } + + return false; +} unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { switch (DeclKind) { diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index b6ab33258d8..345c7fa8c07 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -175,7 +175,7 @@ static bool EvalPointerValueAsBool(LValue& Value, bool& Result) { const ValueDecl* Decl = DeclRef->getDecl(); if (Decl->hasAttr<WeakAttr>() || Decl->hasAttr<WeakRefAttr>() || - Decl->hasAttr<WeakImportAttr>()) + Decl->isWeakImported()) return false; return true; diff --git a/clang/lib/Basic/CMakeLists.txt b/clang/lib/Basic/CMakeLists.txt index 91e7deb078a..b23a156cba0 100644 --- a/clang/lib/Basic/CMakeLists.txt +++ b/clang/lib/Basic/CMakeLists.txt @@ -14,6 +14,7 @@ add_clang_library(clangBasic Targets.cpp TokenKinds.cpp Version.cpp + VersionTuple.cpp ) # Determine Subversion revision. diff --git a/clang/lib/Basic/TargetInfo.cpp b/clang/lib/Basic/TargetInfo.cpp index 1696cae840c..078452e9889 100644 --- a/clang/lib/Basic/TargetInfo.cpp +++ b/clang/lib/Basic/TargetInfo.cpp @@ -70,6 +70,10 @@ TargetInfo::TargetInfo(const std::string &T) : Triple(T) { // Default to an empty address space map. AddrSpaceMap = &DefaultAddrSpaceMap; + + // Default to an unknown platform name. + PlatformName = "unknown"; + PlatformMinVersion = VersionTuple(); } // Out of line virtual dtor for TargetInfo. diff --git a/clang/lib/Basic/Targets.cpp b/clang/lib/Basic/Targets.cpp index 653cf80688d..90b0ee0c87e 100644 --- a/clang/lib/Basic/Targets.cpp +++ b/clang/lib/Basic/Targets.cpp @@ -76,7 +76,9 @@ public: static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts, - const llvm::Triple &Triple) { + const llvm::Triple &Triple, + llvm::StringRef &PlatformName, + VersionTuple &PlatformMinVersion) { Builder.defineMacro("__APPLE_CC__", "5621"); Builder.defineMacro("__APPLE__"); Builder.defineMacro("__MACH__"); @@ -120,6 +122,9 @@ static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts, Str[4] = '0' + (Rev % 10); Str[5] = '\0'; Builder.defineMacro("__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__", Str); + + PlatformName = "ios"; + PlatformMinVersion = VersionTuple(Maj, Min, Rev); } else { // For historical reasons that make little sense, the version passed here is // the "darwin" version, which drops the 10 and offsets by 4. @@ -136,6 +141,9 @@ static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts, Str[3] = '0' + Rev; Str[4] = '\0'; Builder.defineMacro("__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__", Str); + + PlatformName = "macosx"; + PlatformMinVersion = VersionTuple(Maj, Min, Rev); } } @@ -145,7 +153,8 @@ class DarwinTargetInfo : public OSTargetInfo<Target> { protected: virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, MacroBuilder &Builder) const { - getDarwinDefines(Builder, Opts, Triple); + getDarwinDefines(Builder, Opts, Triple, this->PlatformName, + this->PlatformMinVersion); } public: @@ -2005,7 +2014,7 @@ class DarwinARMTargetInfo : protected: virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, MacroBuilder &Builder) const { - getDarwinDefines(Builder, Opts, Triple); + getDarwinDefines(Builder, Opts, Triple, PlatformName, PlatformMinVersion); } public: diff --git a/clang/lib/Basic/VersionTuple.cpp b/clang/lib/Basic/VersionTuple.cpp new file mode 100644 index 00000000000..d5cf126ff48 --- /dev/null +++ b/clang/lib/Basic/VersionTuple.cpp @@ -0,0 +1,36 @@ +//===- VersionTuple.cpp - Version Number Handling ---------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the VersionTuple class, which represents a version in +// the form major[.minor[.subminor]]. +// +//===----------------------------------------------------------------------===// +#include "clang/Basic/VersionTuple.h" +#include "llvm/Support/raw_ostream.h" + +using namespace clang; + +std::string VersionTuple::getAsString() const { + std::string Result; + { + llvm::raw_string_ostream Out(Result); + Out << *this; + } + return Result; +} + +llvm::raw_ostream& clang::operator<<(llvm::raw_ostream &Out, + const VersionTuple &V) { + Out << V.getMajor(); + if (llvm::Optional<unsigned> Minor = V.getMinor()) + Out << '.' << *Minor; + if (llvm::Optional<unsigned> Subminor = V.getSubminor()) + Out << '.' << *Subminor; + return Out; +} diff --git a/clang/lib/CodeGen/CGObjCMac.cpp b/clang/lib/CodeGen/CGObjCMac.cpp index 607df6d0b80..a4d95d443fa 100644 --- a/clang/lib/CodeGen/CGObjCMac.cpp +++ b/clang/lib/CodeGen/CGObjCMac.cpp @@ -5018,14 +5018,14 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) { while (const ObjCInterfaceDecl *Super = Root->getSuperClass()) Root = Super; IsAGV = GetClassGlobal(ObjCMetaClassName + Root->getNameAsString()); - if (Root->hasAttr<WeakImportAttr>()) + if (Root->isWeakImported()) IsAGV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage); // work on super class metadata symbol. std::string SuperClassName = ObjCMetaClassName + ID->getClassInterface()->getSuperClass()->getNameAsString(); SuperClassGV = GetClassGlobal(SuperClassName); - if (ID->getClassInterface()->getSuperClass()->hasAttr<WeakImportAttr>()) + if (ID->getClassInterface()->getSuperClass()->isWeakImported()) SuperClassGV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage); } llvm::GlobalVariable *CLASS_RO_GV = BuildClassRoTInitializer(flags, @@ -5055,7 +5055,7 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) { std::string RootClassName = ID->getClassInterface()->getSuperClass()->getNameAsString(); SuperClassGV = GetClassGlobal(ObjCClassName + RootClassName); - if (ID->getClassInterface()->getSuperClass()->hasAttr<WeakImportAttr>()) + if (ID->getClassInterface()->getSuperClass()->isWeakImported()) SuperClassGV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage); } GetClassSizeInfo(ID, InstanceStart, InstanceSize); @@ -5137,7 +5137,7 @@ void CGObjCNonFragileABIMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) { Values[0] = GetClassName(OCD->getIdentifier()); // meta-class entry symbol llvm::GlobalVariable *ClassGV = GetClassGlobal(ExtClassName); - if (Interface->hasAttr<WeakImportAttr>()) + if (Interface->isWeakImported()) ClassGV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage); Values[1] = ClassGV; @@ -5810,7 +5810,7 @@ llvm::Value *CGObjCNonFragileABIMac::EmitMetaClassRef(CGBuilderTy &Builder, /// decl. llvm::Value *CGObjCNonFragileABIMac::GetClass(CGBuilderTy &Builder, const ObjCInterfaceDecl *ID) { - if (ID->hasAttr<WeakImportAttr>()) { + if (ID->isWeakImported()) { std::string ClassName(getClassSymbolPrefix() + ID->getNameAsString()); llvm::GlobalVariable *ClassGV = GetClassGlobal(ClassName); ClassGV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage); diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 7eee83c928d..647dcc50a97 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -509,7 +509,7 @@ void CodeGenModule::SetFunctionAttributes(GlobalDecl GD, if (FD->hasAttr<DLLImportAttr>()) { F->setLinkage(llvm::Function::DLLImportLinkage); } else if (FD->hasAttr<WeakAttr>() || - FD->hasAttr<WeakImportAttr>()) { + FD->isWeakImported()) { // "extern_weak" is overloaded in LLVM; we probably should have // separate linkage types for this. F->setLinkage(llvm::Function::ExternalWeakLinkage); @@ -986,7 +986,7 @@ CodeGenModule::GetOrCreateLLVMGlobal(llvm::StringRef MangledName, } else { if (D->hasAttr<DLLImportAttr>()) GV->setLinkage(llvm::GlobalValue::DLLImportLinkage); - else if (D->hasAttr<WeakAttr>() || D->hasAttr<WeakImportAttr>()) + else if (D->hasAttr<WeakAttr>() || D->isWeakImported()) GV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage); // Set visibility on a declaration only if it's explicit. @@ -1530,7 +1530,7 @@ void CodeGenModule::EmitAliasDefinition(GlobalDecl GD) { } } else if (D->hasAttr<WeakAttr>() || D->hasAttr<WeakRefAttr>() || - D->hasAttr<WeakImportAttr>()) { + D->isWeakImported()) { GA->setLinkage(llvm::Function::WeakAnyLinkage); } diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index f27ff79f193..6928d0d6d0d 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -112,8 +112,11 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs, IdentifierInfo *AttrName = Tok.getIdentifierInfo(); SourceLocation AttrNameLoc = ConsumeToken(); + // Availability attributes have their own grammar. + if (AttrName->isStr("availability")) + ParseAvailabilityAttribute(*AttrName, AttrNameLoc, attrs, endLoc); // check if we have a "parameterized" attribute - if (Tok.is(tok::l_paren)) { + else if (Tok.is(tok::l_paren)) { ConsumeParen(); // ignore the left paren loc for now if (Tok.is(tok::identifier)) { @@ -362,6 +365,241 @@ void Parser::ParseOpenCLQualifiers(DeclSpec &DS) { } } +/// \brief Parse a version number. +/// +/// version: +/// simple-integer +/// simple-integer ',' simple-integer +/// simple-integer ',' simple-integer ',' simple-integer +VersionTuple Parser::ParseVersionTuple(SourceRange &Range) { + Range = Tok.getLocation(); + + if (!Tok.is(tok::numeric_constant)) { + Diag(Tok, diag::err_expected_version); + SkipUntil(tok::comma, tok::r_paren, true, true, true); + return VersionTuple(); + } + + // Parse the major (and possibly minor and subminor) versions, which + // are stored in the numeric constant. We utilize a quirk of the + // lexer, which is that it handles something like 1.2.3 as a single + // numeric constant, rather than two separate tokens. + llvm::SmallString<512> Buffer; + Buffer.resize(Tok.getLength()+1); + const char *ThisTokBegin = &Buffer[0]; + + // Get the spelling of the token, which eliminates trigraphs, etc. + bool Invalid = false; + unsigned ActualLength = PP.getSpelling(Tok, ThisTokBegin, &Invalid); + if (Invalid) + return VersionTuple(); + + // Parse the major version. + unsigned AfterMajor = 0; + unsigned Major = 0; + while (AfterMajor < ActualLength && isdigit(ThisTokBegin[AfterMajor])) { + Major = Major * 10 + ThisTokBegin[AfterMajor] - '0'; + ++AfterMajor; + } + + if (AfterMajor == 0) { + Diag(Tok, diag::err_expected_version); + SkipUntil(tok::comma, tok::r_paren, true, true, true); + return VersionTuple(); + } + + if (AfterMajor == ActualLength) { + ConsumeToken(); + + // We only had a single version component. + if (Major == 0) { + Diag(Tok, diag::err_zero_version); + return VersionTuple(); + } + + return VersionTuple(Major); + } + + if (ThisTokBegin[AfterMajor] != '.' || (AfterMajor + 1 == ActualLength)) { + Diag(Tok, diag::err_expected_version); + SkipUntil(tok::comma, tok::r_paren, true, true, true); + return VersionTuple(); + } + + // Parse the minor version. + unsigned AfterMinor = AfterMajor + 1; + unsigned Minor = 0; + while (AfterMinor < ActualLength && isdigit(ThisTokBegin[AfterMinor])) { + Minor = Minor * 10 + ThisTokBegin[AfterMinor] - '0'; + ++AfterMinor; + } + + if (AfterMinor == ActualLength) { + ConsumeToken(); + + // We had major.minor. + if (Major == 0 && Minor == 0) { + Diag(Tok, diag::err_zero_version); + return VersionTuple(); + } + + return VersionTuple(Major, Minor); + } + + // If what follows is not a '.', we have a problem. + if (ThisTokBegin[AfterMinor] != '.') { + Diag(Tok, diag::err_expected_version); + SkipUntil(tok::comma, tok::r_paren, true, true, true); + return VersionTuple(); + } + + // Parse the subminor version. + unsigned AfterSubminor = AfterMinor + 1; + unsigned Subminor = 0; + while (AfterSubminor < ActualLength && isdigit(ThisTokBegin[AfterSubminor])) { + Subminor = Subminor * 10 + ThisTokBegin[AfterSubminor] - '0'; + ++AfterSubminor; + } + + if (AfterSubminor != ActualLength) { + Diag(Tok, diag::err_expected_version); + SkipUntil(tok::comma, tok::r_paren, true, true, true); + return VersionTuple(); + } + ConsumeToken(); + return VersionTuple(Major, Minor, Subminor); +} + +/// \brief Parse the contents of the "availability" attribute. +/// +/// availability-attribute: +/// 'availability' '(' platform ',' version-arg-list ')' +/// +/// platform: +/// identifier +/// +/// version-arg-list: +/// version-arg +/// version-arg ',' version-arg-list +/// +/// version-arg: +/// 'introduced' '=' version +/// 'deprecated' '=' version +/// 'removed' = version +void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability, + SourceLocation AvailabilityLoc, + ParsedAttributes &attrs, + SourceLocation *endLoc) { + SourceLocation PlatformLoc; + IdentifierInfo *Platform = 0; + + enum { Introduced, Deprecated, Obsoleted, Unknown }; + AvailabilityChange Changes[Unknown]; + + // Opening '('. + SourceLocation LParenLoc; + if (!Tok.is(tok::l_paren)) { + Diag(Tok, diag::err_expected_lparen); + return; + } + LParenLoc = ConsumeParen(); + + // Parse the platform name, + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_availability_expected_platform); + SkipUntil(tok::r_paren); + return; + } + Platform = Tok.getIdentifierInfo(); + PlatformLoc = ConsumeToken(); + + // Parse the ',' following the platform name. + if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "", tok::r_paren)) + return; + + // If we haven't grabbed the pointers for the identifiers + // "introduced", "deprecated", and "obsoleted", do so now. + if (!Ident_introduced) { + Ident_introduced = PP.getIdentifierInfo("introduced"); + Ident_deprecated = PP.getIdentifierInfo("deprecated"); + Ident_obsoleted = PP.getIdentifierInfo("obsoleted"); + } + + // Parse the set of introductions/deprecations/removals. + do { + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_availability_expected_change); + SkipUntil(tok::r_paren); + return; + } + IdentifierInfo *Keyword = Tok.getIdentifierInfo(); + SourceLocation KeywordLoc = ConsumeToken(); + + if (Tok.isNot(tok::equal)) { + Diag(Tok, diag::err_expected_equal_after) + << Keyword; + SkipUntil(tok::r_paren); + return; + } + ConsumeToken(); + + SourceRange VersionRange; + VersionTuple Version = ParseVersionTuple(VersionRange); + + if (Version.empty()) { + SkipUntil(tok::r_paren); + return; + } + + unsigned Index; + if (Keyword == Ident_introduced) + Index = Introduced; + else if (Keyword == Ident_deprecated) + Index = Deprecated; + else if (Keyword == Ident_obsoleted) + Index = Obsoleted; + else + Index = Unknown; + + if (Index < Unknown) { + if (!Changes[Index].KeywordLoc.isInvalid()) { + Diag(KeywordLoc, diag::err_availability_redundant) + << Keyword + << SourceRange(Changes[Index].KeywordLoc, + Changes[Index].VersionRange.getEnd()); + } + + Changes[Index].KeywordLoc = KeywordLoc; + Changes[Index].Version = Version; + Changes[Index].VersionRange = VersionRange; + } else { + Diag(KeywordLoc, diag::err_availability_unknown_change) + << Keyword << VersionRange; + } + + if (Tok.isNot(tok::comma)) + break; + + ConsumeToken(); + } while (true); + + // Closing ')'. + SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); + if (RParenLoc.isInvalid()) + return; + + if (endLoc) + *endLoc = RParenLoc; + + // Record this attribute + attrs.add(AttrFactory.Create(&Availability, AvailabilityLoc, + 0, SourceLocation(), + Platform, PlatformLoc, + Changes[Introduced], + Changes[Deprecated], + Changes[Obsoleted], false, false)); +} + void Parser::DiagnoseProhibitedAttributes(ParsedAttributesWithRange &attrs) { Diag(attrs.Range.getBegin(), diag::err_attributes_not_allowed) << attrs.Range; diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index 60ca1d49e7c..f18531ebbab 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -422,6 +422,10 @@ void Parser::Initialize() { Ident_vector = &PP.getIdentifierTable().get("vector"); Ident_pixel = &PP.getIdentifierTable().get("pixel"); } + + Ident_introduced = 0; + Ident_deprecated = 0; + Ident_obsoleted = 0; } /// ParseTopLevelDecl - Parse one top-level declaration, return whatever the diff --git a/clang/lib/Sema/AttributeList.cpp b/clang/lib/Sema/AttributeList.cpp index a715989c685..ae5ea673eba 100644 --- a/clang/lib/Sema/AttributeList.cpp +++ b/clang/lib/Sema/AttributeList.cpp @@ -36,6 +36,24 @@ AttributeList::AttributeList(llvm::BumpPtrAllocator &Alloc, } } +AttributeList::AttributeList(llvm::BumpPtrAllocator &Alloc, + IdentifierInfo *AttrName, SourceLocation AttrLoc, + IdentifierInfo *ScopeName, SourceLocation ScopeLoc, + IdentifierInfo *ParmName, SourceLocation ParmLoc, + const AvailabilityChange &Introduced, + const AvailabilityChange &Deprecated, + const AvailabilityChange &Obsoleted, + bool declspec, bool cxx0x) + : AttrName(AttrName), AttrLoc(AttrLoc), ScopeName(ScopeName), + ScopeLoc(ScopeLoc), ParmName(ParmName), ParmLoc(ParmLoc), + Args(0), NumArgs(0), Next(0), + DeclspecAttribute(declspec), CXX0XAttribute(cxx0x), + AvailabilityIntroduced(Introduced), + AvailabilityDeprecated(Deprecated), + AvailabilityObsoleted(Obsoleted), + Invalid(false) { +} + AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) { llvm::StringRef AttrName = Name->getName(); @@ -83,6 +101,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) { .Case("may_alias", AT_may_alias) .Case("base_check", AT_base_check) .Case("deprecated", AT_deprecated) + .Case("availability", AT_availability) .Case("visibility", AT_visibility) .Case("destructor", AT_destructor) .Case("format_arg", AT_format_arg) diff --git a/clang/lib/Sema/CodeCompleteConsumer.cpp b/clang/lib/Sema/CodeCompleteConsumer.cpp index b7037ce83e7..2334ab5128a 100644 --- a/clang/lib/Sema/CodeCompleteConsumer.cpp +++ b/clang/lib/Sema/CodeCompleteConsumer.cpp @@ -375,12 +375,21 @@ void CodeCompletionResult::computeCursorKindAndAvailability() { switch (Kind) { case RK_Declaration: // Set the availability based on attributes. - Availability = CXAvailability_Available; - if (Declaration->getAttr<UnavailableAttr>()) - Availability = CXAvailability_NotAvailable; - else if (Declaration->getAttr<DeprecatedAttr>()) + switch (Declaration->getAvailability()) { + case AR_Available: + case AR_NotYetIntroduced: + Availability = CXAvailability_Available; + break; + + case AR_Deprecated: Availability = CXAvailability_Deprecated; + break; + case AR_Unavailable: + Availability = CXAvailability_NotAvailable; + break; + } + if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Declaration)) if (Function->isDeleted()) Availability = CXAvailability_NotAvailable; diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 3c1127784d4..3f33f144e48 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -1074,6 +1074,57 @@ static void HandleUnavailableAttr(Decl *d, const AttributeList &Attr, Sema &S) { d->addAttr(::new (S.Context) UnavailableAttr(Attr.getLoc(), S.Context, Str)); } +static void HandleAvailabilityAttr(Decl *d, const AttributeList &Attr, + Sema &S) { + IdentifierInfo *Platform = Attr.getParameterName(); + SourceLocation PlatformLoc = Attr.getParameterLoc(); + + llvm::StringRef PlatformName + = AvailabilityAttr::getPrettyPlatformName(Platform->getName()); + if (PlatformName.empty()) { + S.Diag(PlatformLoc, diag::warn_availability_unknown_platform) + << Platform; + + PlatformName = Platform->getName(); + } + + AvailabilityChange Introduced = Attr.getAvailabilityIntroduced(); + AvailabilityChange Deprecated = Attr.getAvailabilityDeprecated(); + AvailabilityChange Obsoleted = Attr.getAvailabilityObsoleted(); + + // Ensure that Introduced < Deprecated < Obsoleted (although not all + // of these steps are needed). + if (Introduced.isValid() && Deprecated.isValid() && + !(Introduced.Version < Deprecated.Version)) { + S.Diag(Introduced.KeywordLoc, diag::warn_availability_version_ordering) + << 1 << PlatformName << Deprecated.Version.getAsString() + << 0 << Introduced.Version.getAsString(); + return; + } + + if (Introduced.isValid() && Obsoleted.isValid() && + !(Introduced.Version < Obsoleted.Version)) { + S.Diag(Introduced.KeywordLoc, diag::warn_availability_version_ordering) + << 2 << PlatformName << Obsoleted.Version.getAsString() + << 0 << Introduced.Version.getAsString(); + return; + } + + if (Deprecated.isValid() && Obsoleted.isValid() && + !(Deprecated.Version < Obsoleted.Version)) { + S.Diag(Deprecated.KeywordLoc, diag::warn_availability_version_ordering) + << 2 << PlatformName << Obsoleted.Version.getAsString() + << 1 << Deprecated.Version.getAsString(); + return; + } + + d->addAttr(::new (S.Context) AvailabilityAttr(Attr.getLoc(), S.Context, + Platform, + Introduced.Version, + Deprecated.Version, + Obsoleted.Version)); +} + static void HandleVisibilityAttr(Decl *d, const AttributeList &Attr, Sema &S) { // check the attribute arguments. if (Attr.getNumArgs() != 1) { @@ -1380,27 +1431,18 @@ static void HandleWeakImportAttr(Decl *D, const AttributeList &Attr, Sema &S) { // weak_import only applies to variable & function declarations. bool isDef = false; - if (VarDecl *VD = dyn_cast<VarDecl>(D)) { - isDef = (!VD->hasExternalStorage() || VD->getInit()); - } else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { - isDef = FD->hasBody(); - } else if (isa<ObjCPropertyDecl>(D) || isa<ObjCMethodDecl>(D)) { - // We ignore weak import on properties and methods - return; - } else if (!(S.LangOpts.ObjCNonFragileABI && isa<ObjCInterfaceDecl>(D))) { - // Don't issue the warning for darwin as target; yet, ignore the attribute. - if (S.Context.Target.getTriple().getOS() != llvm::Triple::Darwin || - !isa<ObjCInterfaceDecl>(D)) + if (!D->canBeWeakImported(isDef)) { + if (isDef) + S.Diag(Attr.getLoc(), + diag::warn_attribute_weak_import_invalid_on_definition) + << "weak_import" << 2 /*variable and function*/; + else if (S.Context.Target.getTriple().getOS() != llvm::Triple::Darwin || + (!isa<ObjCInterfaceDecl>(D) && + !isa<ObjCPropertyDecl>(D) && + !isa<ObjCMethodDecl>(D))) S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << ExpectedVariableOrFunction; - return; - } - // Merge should handle any subsequent violations. - if (isDef) { - S.Diag(Attr.getLoc(), - diag::warn_attribute_weak_import_invalid_on_definition) - << "weak_import" << 2 /*variable and function*/; return; } @@ -2745,6 +2787,7 @@ static void ProcessInheritableDeclAttr(Scope *scope, Decl *D, case AttributeList::AT_analyzer_noreturn: HandleAnalyzerNoReturnAttr (D, Attr, S); break; case AttributeList::AT_annotate: HandleAnnotateAttr (D, Attr, S); break; + case AttributeList::AT_availability:HandleAvailabilityAttr(D, Attr, S); break; case AttributeList::AT_carries_dependency: HandleDependencyAttr (D, Attr, S); break; case AttributeList::AT_common: HandleCommonAttr (D, Attr, S); break; @@ -3058,7 +3101,7 @@ void Sema::DelayedDiagnostics::popParsingDecl(Sema &S, ParsingDeclState state, static bool isDeclDeprecated(Decl *D) { do { - if (D->hasAttr<DeprecatedAttr>()) + if (D->isDeprecated()) return true; } while ((D = cast_or_null<Decl>(D->getDeclContext()))); return false; diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp index 8717385b516..101ade72e3c 100644 --- a/clang/lib/Sema/SemaDeclObjC.cpp +++ b/clang/lib/Sema/SemaDeclObjC.cpp @@ -28,7 +28,7 @@ static void DiagnoseObjCImplementedDeprecations(Sema &S, NamedDecl *ND, SourceLocation ImplLoc, int select) { - if (ND && ND->getAttr<DeprecatedAttr>()) { + if (ND && ND->isDeprecated()) { S.Diag(ImplLoc, diag::warn_deprecated_def) << select; if (select == 0) S.Diag(ND->getLocation(), diag::note_method_declared_at); @@ -1369,15 +1369,14 @@ void Sema::AddMethodToGlobalPool(ObjCMethodDecl *Method, bool impl, PrevObjCMethod->setDefined(impl); // If a method is deprecated, push it in the global pool. // This is used for better diagnostics. - if (Method->getAttr<DeprecatedAttr>()) { - if (!PrevObjCMethod->getAttr<DeprecatedAttr>()) + if (Method->isDeprecated()) { + if (!PrevObjCMethod->isDeprecated()) List->Method = Method; } // If new method is unavailable, push it into global pool // unless previous one is deprecated. - if (Method->getAttr<UnavailableAttr>()) { - if (!PrevObjCMethod->getAttr<UnavailableAttr>() && - !PrevObjCMethod->getAttr<DeprecatedAttr>()) + if (Method->isUnavailable()) { + if (PrevObjCMethod->getAvailability() < AR_Deprecated) List->Method = Method; } return; diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index b8f0c729d17..c2f3a434b81 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -68,7 +68,7 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc, Diag(Suppressed[I].first, Suppressed[I].second); // Clear out the list of suppressed diagnostics, so that we don't emit - // them again for this specialization. However, we don't remove this + // them again for this specialization. However, we don't obsolete this // entry from the table, because we want to avoid ever emitting these // diagnostics again. Suppressed.clear(); @@ -82,13 +82,28 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc, return true; } - // See if the decl is deprecated. - if (const DeprecatedAttr *DA = D->getAttr<DeprecatedAttr>()) - EmitDeprecationWarning(D, DA->getMessage(), Loc, UnknownObjCClass); + // See if this is a deleted function. + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + if (FD->isDeleted()) { + Diag(Loc, diag::err_deleted_function_use); + Diag(D->getLocation(), diag::note_unavailable_here) << true; + return true; + } + } + + // See if this declaration is unavailable or deprecated. + std::string Message; + switch (D->getAvailability(&Message)) { + case AR_Available: + case AR_NotYetIntroduced: + break; - // See if the decl is unavailable - if (const UnavailableAttr *UA = D->getAttr<UnavailableAttr>()) { - if (UA->getMessage().empty()) { + case AR_Deprecated: + EmitDeprecationWarning(D, Message, Loc, UnknownObjCClass); + break; + + case AR_Unavailable: + if (Message.empty()) { if (!UnknownObjCClass) Diag(Loc, diag::err_unavailable) << D->getDeclName(); else @@ -97,17 +112,9 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc, } else Diag(Loc, diag::err_unavailable_message) - << D->getDeclName() << UA->getMessage(); - Diag(D->getLocation(), diag::note_unavailable_here) << 0; - } - - // See if this is a deleted function. - if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { - if (FD->isDeleted()) { - Diag(Loc, diag::err_deleted_function_use); - Diag(D->getLocation(), diag::note_unavailable_here) << true; - return true; - } + << D->getDeclName() << Message; + Diag(D->getLocation(), diag::note_unavailable_here) << 0; + break; } // Warn if this is used but marked unused. @@ -117,6 +124,23 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc, return false; } +/// \brief Retrieve the message suffix that should be added to a +/// diagnostic complaining about the given function being deleted or +/// unavailable. +std::string Sema::getDeletedOrUnavailableSuffix(const FunctionDecl *FD) { + // FIXME: C++0x implicitly-deleted special member functions could be + // detected here so that we could improve diagnostics to say, e.g., + // "base class 'A' had a deleted copy constructor". + if (FD->isDeleted()) + return std::string(); + + std::string Message; + if (FD->getAvailability(&Message)) + return ": " + Message; + + return std::string(); +} + /// DiagnoseSentinelCalls - This routine checks on method dispatch calls /// (and other functions in future), which have been declared with sentinel /// attribute. It warns if call does not have the sentinel argument. diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 8fa2a5d2e86..0a8bd8fb526 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -1388,16 +1388,16 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range, Candidates.NoteCandidates(*this, OCD_ViableCandidates, Args, NumArgs); return true; - case OR_Deleted: + case OR_Deleted: { Diag(StartLoc, diag::err_ovl_deleted_call) << Best->Function->isDeleted() << Name - << Best->Function->getMessageUnavailableAttr( - !Best->Function->isDeleted()) + << getDeletedOrUnavailableSuffix(Best->Function) << Range; Candidates.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs); return true; } + } assert(false && "Unreachable, bad result from BestViableFunction"); return true; } diff --git a/clang/lib/Sema/SemaObjCProperty.cpp b/clang/lib/Sema/SemaObjCProperty.cpp index 91de095ac7e..f607d658951 100644 --- a/clang/lib/Sema/SemaObjCProperty.cpp +++ b/clang/lib/Sema/SemaObjCProperty.cpp @@ -1138,10 +1138,14 @@ Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl, static void AddPropertyAttrs(Sema &S, ObjCMethodDecl *PropertyMethod, ObjCPropertyDecl *Property) { // Should we just clone all attributes over? - if (DeprecatedAttr *A = Property->getAttr<DeprecatedAttr>()) - PropertyMethod->addAttr(A->clone(S.Context)); - if (UnavailableAttr *A = Property->getAttr<UnavailableAttr>()) - PropertyMethod->addAttr(A->clone(S.Context)); + for (Decl::attr_iterator A = Property->attr_begin(), + AEnd = Property->attr_end(); + A != AEnd; ++A) { + if (isa<DeprecatedAttr>(*A) || + isa<UnavailableAttr>(*A) || + isa<AvailabilityAttr>(*A)) + PropertyMethod->addAttr((*A)->clone(S.Context)); + } } /// ProcessPropertyDecl - Make sure that any user-defined setter/getter methods diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 110f8cdc1cb..7a4e68d3cbb 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -6282,8 +6282,7 @@ OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc, // Best is the best viable function. if (Best->Function && - (Best->Function->isDeleted() || - Best->Function->getAttr<UnavailableAttr>())) + (Best->Function->isDeleted() || Best->Function->isUnavailable())) return OR_Deleted; return OR_Success; @@ -6735,7 +6734,7 @@ void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand, FunctionDecl *Fn = Cand->Function; // Note deleted candidates, but only if they're viable. - if (Cand->Viable && (Fn->isDeleted() || Fn->hasAttr<UnavailableAttr>())) { + if (Cand->Viable && (Fn->isDeleted() || Fn->isUnavailable())) { std::string FnDesc; OverloadCandidateKind FnKind = ClassifyOverloadCandidate(S, Fn, FnDesc); @@ -7744,8 +7743,7 @@ Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE, Diag(Fn->getSourceRange().getBegin(), diag::err_ovl_deleted_call) << Best->Function->isDeleted() << ULE->getName() - << Best->Function->getMessageUnavailableAttr( - !Best->Function->isDeleted()) + << getDeletedOrUnavailableSuffix(Best->Function) << Fn->getSourceRange(); CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs); } @@ -7928,8 +7926,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, Diag(OpLoc, diag::err_ovl_deleted_oper) << Best->Function->isDeleted() << UnaryOperator::getOpcodeStr(Opc) - << Best->Function->getMessageUnavailableAttr( - !Best->Function->isDeleted()) + << getDeletedOrUnavailableSuffix(Best->Function) << Input->getSourceRange(); CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs); return ExprError(); @@ -8199,8 +8196,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, Diag(OpLoc, diag::err_ovl_deleted_oper) << Best->Function->isDeleted() << BinaryOperator::getOpcodeStr(Opc) - << Best->Function->getMessageUnavailableAttr( - !Best->Function->isDeleted()) + << getDeletedOrUnavailableSuffix(Best->Function) << Args[0]->getSourceRange() << Args[1]->getSourceRange(); CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, 2); return ExprError(); @@ -8349,8 +8345,7 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, case OR_Deleted: Diag(LLoc, diag::err_ovl_deleted_oper) << Best->Function->isDeleted() << "[]" - << Best->Function->getMessageUnavailableAttr( - !Best->Function->isDeleted()) + << getDeletedOrUnavailableSuffix(Best->Function) << Args[0]->getSourceRange() << Args[1]->getSourceRange(); CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, 2, "[]", LLoc); @@ -8468,8 +8463,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, Diag(UnresExpr->getMemberLoc(), diag::err_ovl_deleted_member_call) << Best->Function->isDeleted() << DeclName - << Best->Function->getMessageUnavailableAttr( - !Best->Function->isDeleted()) + << getDeletedOrUnavailableSuffix(Best->Function) << MemExprE->getSourceRange(); CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs); // FIXME: Leaking incoming expressions! @@ -8643,8 +8637,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, diag::err_ovl_deleted_object_call) << Best->Function->isDeleted() << Object->getType() - << Best->Function->getMessageUnavailableAttr( - !Best->Function->isDeleted()) + << getDeletedOrUnavailableSuffix(Best->Function) << Object->getSourceRange(); CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs); break; @@ -8852,8 +8845,7 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc) { Diag(OpLoc, diag::err_ovl_deleted_oper) << Best->Function->isDeleted() << "->" - << Best->Function->getMessageUnavailableAttr( - !Best->Function->isDeleted()) + << getDeletedOrUnavailableSuffix(Best->Function) << Base->getSourceRange(); CandidateSet.NoteCandidates(*this, OCD_AllCandidates, &Base, 1); return ExprError(); diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index b34b62ab6f3..1b55f71c36b 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -37,6 +37,7 @@ #include "clang/Basic/FileSystemStatCache.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/Version.h" +#include "clang/Basic/VersionTuple.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Bitcode/BitstreamReader.h" #include "llvm/Support/MemoryBuffer.h" @@ -4870,6 +4871,18 @@ std::string ASTReader::ReadString(const RecordData &Record, unsigned &Idx) { return Result; } +VersionTuple ASTReader::ReadVersionTuple(const RecordData &Record, + unsigned &Idx) { + unsigned Major = Record[Idx++]; + unsigned Minor = Record[Idx++]; + unsigned Subminor = Record[Idx++]; + if (Minor == 0) + return VersionTuple(Major); + if (Subminor == 0) + return VersionTuple(Major, Minor - 1); + return VersionTuple(Major, Minor - 1, Subminor - 1); +} + CXXTemporary *ASTReader::ReadCXXTemporary(const RecordData &Record, unsigned &Idx) { CXXDestructorDecl *Decl = cast<CXXDestructorDecl>(GetDecl(Record[Idx++])); diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index 877650f9de3..482ce4bec7c 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -37,6 +37,7 @@ #include "clang/Basic/SourceManagerInternals.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/Version.h" +#include "clang/Basic/VersionTuple.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/StringExtras.h" @@ -2622,6 +2623,19 @@ void ASTWriter::AddString(llvm::StringRef Str, RecordDataImpl &Record) { Record.insert(Record.end(), Str.begin(), Str.end()); } +void ASTWriter::AddVersionTuple(const VersionTuple &Version, + RecordDataImpl &Record) { + Record.push_back(Version.getMajor()); + if (llvm::Optional<unsigned> Minor = Version.getMinor()) + Record.push_back(*Minor + 1); + else + Record.push_back(0); + if (llvm::Optional<unsigned> Subminor = Version.getSubminor()) + Record.push_back(*Subminor + 1); + else + Record.push_back(0); +} + /// \brief Note that the identifier II occurs at the given offset /// within the identifier table. void ASTWriter::SetIdentifierOffset(const IdentifierInfo *II, uint32_t Offset) { |