diff options
45 files changed, 1060 insertions, 109 deletions
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 9e3d10f63b..1bf13f6437 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -19,6 +19,7 @@ #include "clang/Basic/LangOptions.h" #include "clang/Basic/OperatorKinds.h" #include "clang/Basic/PartialDiagnostic.h" +#include "clang/Basic/VersionTuple.h" #include "clang/AST/Decl.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/PrettyPrinter.h" diff --git a/include/clang/AST/Attr.h b/include/clang/AST/Attr.h index 502b9f775f..719023926b 100644 --- a/include/clang/AST/Attr.h +++ b/include/clang/AST/Attr.h @@ -17,9 +17,11 @@ #include "llvm/Support/Casting.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" #include "clang/Basic/AttrKinds.h" #include "clang/AST/Type.h" #include "clang/Basic/SourceLocation.h" +#include "clang/Basic/VersionTuple.h" #include <cassert> #include <cstring> #include <algorithm> diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index 08e4525f55..339074bde0 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -119,14 +119,6 @@ public: return getIdentifier() ? getIdentifier()->getName() : ""; } - llvm::StringRef getMessageUnavailableAttr(bool unavailable) const { - if (!unavailable) - return ""; - if (const UnavailableAttr *UA = getAttr<UnavailableAttr>()) - return UA->getMessage(); - return ""; - } - /// getNameAsString - Get a human-readable name for the declaration, even if /// it is one of the special kinds of names (C++ constructor, Objective-C /// selector, etc). Creating this name requires expensive string diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h index b35d134d05..caab56a0cd 100644 --- a/include/clang/AST/DeclBase.h +++ b/include/clang/AST/DeclBase.h @@ -62,6 +62,15 @@ public: namespace clang { + /// \brief Captures the result of checking the availability of a + /// declaration. + enum AvailabilityResult { + AR_Available = 0, + AR_NotYetIntroduced, + AR_Deprecated, + AR_Unavailable + }; + /// Decl - This represents one declaration (or definition), e.g. a variable, /// typedef, function, struct, etc. /// @@ -399,6 +408,52 @@ public: void setUsed(bool U = true) { Used = U; } + /// \brief Determine the availability of the given declaration. + /// + /// This routine will determine the most restrictive availability of + /// the given declaration (e.g., preferring 'unavailable' to + /// 'deprecated'). + /// + /// \param Message If non-NULL and the result is not \c + /// AR_Available, will be set to a (possibly empty) message + /// describing why the declaration has not been introduced, is + /// deprecated, or is unavailable. + AvailabilityResult getAvailability(std::string *Message = 0) const; + + /// \brief Determine whether this declaration is marked 'deprecated'. + /// + /// \param Message If non-NULL and the declaration is deprecated, + /// this will be set to the message describing why the declaration + /// was deprecated (which may be empty). + bool isDeprecated(std::string *Message = 0) const { + return getAvailability(Message) == AR_Deprecated; + } + + /// \brief Determine whether this declaration is marked 'unavailable'. + /// + /// \param Message If non-NULL and the declaration is unavailable, + /// this will be set to the message describing why the declaration + /// was made unavailable (which may be empty). + bool isUnavailable(std::string *Message = 0) const { + return getAvailability(Message) == AR_Unavailable; + } + + /// \brief Determine whether this is a weak-imported symbol. + /// + /// Weak-imported symbols are typically marked with the + /// 'weak_import' attr + /// 'availability' attribute where we're targing a platform prior to + /// the introduction of this feature. + bool isWeakImported() const; + + /// \brief Determines whether this symbol can be weak-imported, + /// e.g., whether it would be well-formed to add the weak_import + /// attribute. + /// + /// \param IsDefinition Set to \c true to indicate that this + /// declaration cannot be weak-imported because it has a definition. + bool canBeWeakImported(bool &IsDefinition) const; + /// \brief Retrieve the level of precompiled header from which this /// declaration was generated. /// diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td index 3579e2c6f1..6c3d5e5d0c 100644 --- a/include/clang/Basic/Attr.td +++ b/include/clang/Basic/Attr.td @@ -55,6 +55,9 @@ class TypeArgument<string name> : Argument<name>; class UnsignedArgument<string name> : Argument<name>; class VariadicUnsignedArgument<string name> : Argument<name>; +// A version of the form major.minor[.subminor]. +class VersionArgument<string name> : Argument<name>; + // This one's a doozy, so it gets its own special type // It can be an unsigned integer, or a type. Either can // be dependent. @@ -134,6 +137,19 @@ def AsmLabel : InheritableAttr { let Args = [StringArgument<"Label">]; } +def Availability : InheritableAttr { + let Spellings = ["availability"]; + let Args = [IdentifierArgument<"platform">, VersionArgument<"introduced">, + VersionArgument<"deprecated">, VersionArgument<"obsoleted">]; + let AdditionalMembers = +[{static llvm::StringRef getPrettyPlatformName(llvm::StringRef Platform) { + return llvm::StringSwitch<llvm::StringRef>(Platform) + .Case("ios", "iOS") + .Case("macosx", "Mac OS X") + .Default(llvm::StringRef()); +} }]; +} + def Blocks : InheritableAttr { let Spellings = ["blocks"]; let Args = [EnumArgument<"Type", "BlockType", ["byref"], ["ByRef"]>]; diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td index d3cc08319a..2b7c5de25c 100644 --- a/include/clang/Basic/DiagnosticGroups.td +++ b/include/clang/Basic/DiagnosticGroups.td @@ -24,6 +24,7 @@ def : DiagGroup<"aggregate-return">; def AmbigMemberTemplate : DiagGroup<"ambiguous-member-template">; def : DiagGroup<"attributes">; def : DiagGroup<"bad-function-cast">; +def Availability : DiagGroup<"availability">; def BoolConversions : DiagGroup<"bool-conversions">; def CXXCompat: DiagGroup<"c++-compat">; def CastAlign : DiagGroup<"cast-align">; diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index 0f011f5741..8f4414d3d4 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -119,6 +119,7 @@ def err_function_declared_typedef : Error< "function definition declared 'typedef'">; def err_iboutletcollection_builtintype : Error< "type argument of iboutletcollection attribute cannot be a builtin type">; + def err_expected_fn_body : Error< "expected function body after function declarator">; def err_expected_method_body : Error<"expected method body">; @@ -130,6 +131,7 @@ def err_expected_statement : Error<"expected statement">; def err_expected_lparen_after : Error<"expected '(' after '%0'">; def err_expected_lparen_after_id : Error<"expected '(' after %0">; def err_expected_less_after : Error<"expected '<' after '%0'">; +def err_expected_equal_after : Error<"expected '=' after %0">; def err_expected_comma : Error<"expected ','">; def err_expected_lbrace_in_compound_literal : Error< "expected '{' in compound literal">; @@ -431,6 +433,21 @@ def err_paren_sizeof_parameter_pack : Error< def err_sizeof_parameter_pack : Error< "expected parenthesized parameter pack name in 'sizeof...' expression">; +// Availability attribute +def err_expected_version : Error< + "expected a version of the form 'major[.minor[.subminor]]'">; +def err_zero_version : Error< + "version number must have non-zero major, minor, or sub-minor version">; +def err_availability_expected_platform : Error< + "expected a platform name, e.g., 'macosx'">; +def err_availability_expected_change : Error< + "expected 'introduced', 'deprecated', or 'obsoleted'">; +def err_availability_unknown_change : Error< + "%0 is not an availability stage; use 'introduced', 'deprecated', or " + "'obsoleted'">; +def err_availability_redundant : Error< + "redundant %0 availability change; only the last specified change will " "be used">; + // Language specific pragmas // - Generic warnings def warn_pragma_expected_lparen : Warning< diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 41feb7e019..fa66d51369 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -1148,6 +1148,14 @@ def err_regparm_mismatch : Error<"function declared with with regparm(%0) " "attribute was previously declared " "%plural{0:without the regparm|:with the regparm(%1)}1 attribute">; +// Availability attribute +def warn_availability_unknown_platform : Warning< + "unknown platform %0 in availability macro">; +def warn_availability_version_ordering : Warning< + "feature cannot be %select{introduced|deprecated|obsoleted}0 in %1 version " + "%2 before it was %select{introduced|deprecated|obsoleted}3 in version %4; " + "attribute ignored">; + def warn_impcast_vector_scalar : Warning< "implicit conversion turns vector to scalar: %0 to %1">, InGroup<DiagGroup<"conversion">>, DefaultIgnore; @@ -1339,11 +1347,11 @@ def err_ovl_no_viable_member_function_in_call : Error< def err_ovl_ambiguous_call : Error< "call to %0 is ambiguous">; def err_ovl_deleted_call : Error< - "call to %select{unavailable|deleted}0 function %1 %2">; + "call to %select{unavailable|deleted}0 function %1%2">; def err_ovl_ambiguous_member_call : Error< "call to member function %0 is ambiguous">; def err_ovl_deleted_member_call : Error< - "call to %select{unavailable|deleted}0 member function %1 %2">; + "call to %select{unavailable|deleted}0 member function %1%2">; def note_ovl_too_many_candidates : Note< "remaining %0 candidate%s0 omitted; " "pass -fshow-overloads=all to show them">; @@ -1495,7 +1503,7 @@ def err_ovl_ambiguous_oper_binary : Error< "use of overloaded operator '%0' is ambiguous (with operand types %1 and %2)">; def err_ovl_no_viable_oper : Error<"no viable overloaded '%0'">; def err_ovl_deleted_oper : Error< - "overload resolution selected %select{unavailable|deleted}0 operator '%1' %2">; + "overload resolution selected %select{unavailable|deleted}0 operator '%1'%2">; def err_ovl_no_viable_subscript : Error<"no viable overloaded operator[] for type %0">; def err_ovl_no_oper : @@ -1509,7 +1517,7 @@ def err_ovl_no_viable_object_call : Error< def err_ovl_ambiguous_object_call : Error< "call to object of type %0 is ambiguous">; def err_ovl_deleted_object_call : Error< - "call to %select{unavailable|deleted}0 function call operator in type %1 %2">; + "call to %select{unavailable|deleted}0 function call operator in type %1%2">; def note_ovl_surrogate_cand : Note<"conversion candidate of type %0">; def err_member_call_without_object : Error< "call to non-static member function without an object argument">; @@ -3831,5 +3839,6 @@ def err_sizeof_pack_no_pack_name_suggest : Error< def note_parameter_pack_here : Note<"parameter pack %0 declared here">; } // end of sema category + } // end of sema component. diff --git a/include/clang/Basic/TargetInfo.h b/include/clang/Basic/TargetInfo.h index af5fd5598a..b830bf2f82 100644 --- a/include/clang/Basic/TargetInfo.h +++ b/include/clang/Basic/TargetInfo.h @@ -16,17 +16,18 @@ #include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Triple.h" #include "llvm/Support/DataTypes.h" #include "clang/Basic/AddressSpaces.h" +#include "clang/Basic/VersionTuple.h" #include <cassert> #include <vector> #include <string> namespace llvm { struct fltSemantics; -class StringRef; } namespace clang { @@ -81,6 +82,9 @@ protected: TargetCXXABI CXXABI; const LangAS::Map *AddrSpaceMap; + mutable llvm::StringRef PlatformName; + mutable VersionTuple PlatformMinVersion; + unsigned HasAlignMac68kSupport : 1; unsigned RealTypeUsesObjCFPRet : 3; @@ -537,6 +541,14 @@ public: return *AddrSpaceMap; } + /// \brief Retrieve the name of the platform as it is used in the + /// availability attribute. + llvm::StringRef getPlatformName() const { return PlatformName; } + + /// \brief Retrieve the minimum desired version of the platform, to + /// which the program should be compiled. + VersionTuple getPlatformMinVersion() const { return PlatformMinVersion; } + protected: virtual uint64_t getPointerWidthV(unsigned AddrSpace) const { return PointerWidth; diff --git a/include/clang/Basic/VersionTuple.h b/include/clang/Basic/VersionTuple.h new file mode 100644 index 0000000000..91eb68eaad --- /dev/null +++ b/include/clang/Basic/VersionTuple.h @@ -0,0 +1,126 @@ +//===- VersionTuple.h - 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 header defines the VersionTuple class, which represents a version in +// the form major[.minor[.subminor]]. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_BASIC_VERSIONTUPLE_H +#define LLVM_CLANG_BASIC_VERSIONTUPLE_H + +#include "llvm/ADT/Optional.h" +#include <string> + +namespace llvm { + class raw_ostream; +} + +namespace clang { + +/// \brief Represents a version number in the form major[.minor[.subminor]]. +class VersionTuple { + unsigned Major; + unsigned Minor : 31; + unsigned Subminor : 31; + unsigned HasMinor : 1; + unsigned HasSubminor : 1; + +public: + VersionTuple() + : Major(0), Minor(0), Subminor(0), HasMinor(false), HasSubminor(false) { } + + explicit VersionTuple(unsigned Major) + : Major(Major), Minor(0), Subminor(0), HasMinor(false), HasSubminor(false) + { } + + explicit VersionTuple(unsigned Major, unsigned Minor) + : Major(Major), Minor(Minor), Subminor(0), HasMinor(true), + HasSubminor(false) + { } + + explicit VersionTuple(unsigned Major, unsigned Minor, unsigned Subminor) + : Major(Major), Minor(Minor), Subminor(Subminor), HasMinor(true), + HasSubminor(true) + { } + + /// \brief Determine whether this version information is empty + /// (e.g., all version components are zero). + bool empty() const { return Major == 0 && Minor == 0 && Subminor == 0; } + + /// \brief Retrieve the major version number. + unsigned getMajor() const { return Major; } + + /// \brief Retrieve the minor version number, if provided. + llvm::Optional<unsigned> getMinor() const { + if (!HasMinor) + return llvm::Optional<unsigned>(); + return Minor; + } + + /// \brief Retrieve the subminor version number, if provided. + llvm::Optional<unsigned> getSubminor() const { + if (!HasSubminor) + return llvm::Optional<unsigned>(); + return Subminor; + } + + /// \brief Determine if two version numbers are equivalent. If not + /// provided, minor and subminor version numbers are considered to be zero. + friend bool operator==(const VersionTuple& X, const VersionTuple &Y) { + return X.Major == Y.Major && X.Minor == Y.Minor && X.Subminor == Y.Subminor; + } + + /// \brief Determine if two version numbers are not equivalent. If + /// not provided, minor and subminor version numbers are considered to be + /// zero. + friend bool operator!=(const VersionTuple &X, const VersionTuple &Y) { + return !(X == Y); + } + + /// \brief Determine whether one version number precedes another. If not + /// provided, minor and subminor version numbers are considered to be zero. + friend bool operator<(const VersionTuple &X, const VersionTuple &Y) { + if (X.Major != Y.Major) + return X.Major < Y.Major; + + if (X.Minor != Y.Minor) + return X.Minor < Y.Minor; + + return X.Subminor < Y.Subminor; + } + + /// \brief Determine whether one version number follows another. If not + /// provided, minor and subminor version numbers are considered to be zero. + friend bool operator>(const VersionTuple &X, const VersionTuple &Y) { + return Y < X; + } + + /// \brief Determine whether one version number precedes or is + /// equivalent to another. If not provided, minor and subminor + /// version numbers are considered to be zero. + friend bool operator<=(const VersionTuple &X, const VersionTuple &Y) { + return !(Y < X); + } + + /// \brief Determine whether one version number follows or is + /// equivalent to another. If not provided, minor and subminor + /// version numbers are considered to be zero. + friend bool operator>=(const VersionTuple &X, const VersionTuple &Y) { + return !(X < Y); + } + + /// \brief Retrieve a string representation of the version number/ + std::string getAsString() const; +}; + +/// \brief Print a version number. +llvm::raw_ostream& operator<<(llvm::raw_ostream &Out, const VersionTuple &V); + +} // end namespace clang +#endif // LLVM_CLANG_BASIC_VERSIONTUPLE_H diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index d07f605270..b51632c6ac 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -33,7 +33,8 @@ namespace clang { class PragmaUnusedHandler; class ColonProtectionRAIIObject; class InMessageExpressionRAIIObject; - + class VersionTuple; + /// PrettyStackTraceParserEntry - If a crash happens while the parser is active, /// an entry is printed for it. class PrettyStackTraceParserEntry : public llvm::PrettyStackTraceEntry { @@ -111,6 +112,15 @@ class Parser : public CodeCompletionHandler { IdentifierInfo *Ident_vector; IdentifierInfo *Ident_pixel; + /// \brief Identifier for "introduced". + IdentifierInfo *Ident_introduced; + + /// \brief Identifier for "deprecated". + IdentifierInfo *Ident_deprecated; + + /// \brief Identifier for "obsoleted". + IdentifierInfo *Ident_obsoleted; + /// C++0x contextual keywords. mutable IdentifierInfo *Ident_final; mutable IdentifierInfo *Ident_override; @@ -1547,6 +1557,12 @@ private: void ParseOpenCLAttributes(ParsedAttributes &attrs); void ParseOpenCLQualifiers(DeclSpec &DS); + VersionTuple ParseVersionTuple(SourceRange &Range); + void ParseAvailabilityAttribute(IdentifierInfo &Availability, + SourceLocation AvailabilityLoc, + ParsedAttributes &attrs, + SourceLocation *endLoc); + void ParseTypeofSpecifier(DeclSpec &DS); void ParseDecltypeSpecifier(DeclSpec &DS); diff --git a/include/clang/Sema/AttributeList.h b/include/clang/Sema/AttributeList.h index 382e50494e..3657b44b02 100644 --- a/include/clang/Sema/AttributeList.h +++ b/include/clang/Sema/AttributeList.h @@ -18,6 +18,7 @@ #include "llvm/Support/Allocator.h" #include "clang/Sema/Ownership.h" #include "clang/Basic/SourceLocation.h" +#include "clang/Basic/VersionTuple.h" #include "clang/AST/Expr.h" #include <cassert> @@ -25,6 +26,23 @@ namespace clang { class IdentifierInfo; class Expr; +/// \brief Represents information about a change in availability for +/// an entity, which is part of the encoding of the 'availability' +/// attribute. +struct AvailabilityChange { + /// \brief The location of the keyword indicating the kind of change. + SourceLocation KeywordLoc; + + /// \brief The version number at which the change occurred. + VersionTuple Version; + + /// \brief The source range covering the version number. + SourceRange VersionRange; + + /// \brief Determine whether this availability change is valid. + bool isValid() const { return !Version.empty(); } +}; + /// AttributeList - Represents GCC's __attribute__ declaration. There are /// 4 forms of this construct...they are: /// @@ -48,6 +66,11 @@ private: AttributeList *Next; bool DeclspecAttribute, CXX0XAttribute; + // For the 'availability' attribute. + AvailabilityChange AvailabilityIntroduced; + AvailabilityChange AvailabilityDeprecated; + AvailabilityChange AvailabilityObsoleted; + /// True if already diagnosed as invalid. mutable bool Invalid; @@ -61,6 +84,15 @@ private: IdentifierInfo *ParmName, SourceLocation ParmLoc, Expr **args, unsigned numargs, bool declspec, bool cxx0x); + + 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); public: class Factory { llvm::BumpPtrAllocator Alloc; @@ -78,6 +110,20 @@ public: return Mem; } + AttributeList *Create(IdentifierInfo *AttrName, SourceLocation AttrLoc, + IdentifierInfo *ScopeName, SourceLocation ScopeLoc, + IdentifierInfo *ParmName, SourceLocation ParmLoc, + const AvailabilityChange &Introduced, + const AvailabilityChange &Deprecated, + const AvailabilityChange &Obsoleted, + bool declspec = false, bool cxx0x = false) { + AttributeList *Mem = Alloc.Allocate<AttributeList>(); + new (Mem) AttributeList(Alloc, AttrName, AttrLoc, ScopeName, ScopeLoc, + ParmName, ParmLoc, Introduced, Deprecated, + Obsoleted, declspec, cxx0x); + return Mem; + } + AttributeList* CreateIntegerAttribute(ASTContext &C, IdentifierInfo *Name, SourceLocation TokLoc, int Arg) { Expr* IArg = IntegerLiteral::Create(C, llvm::APInt(32, (uint64_t)Arg), @@ -96,6 +142,7 @@ public: AT_always_inline, AT_analyzer_noreturn, AT_annotate, + AT_availability, // Clang-specific A |