Skip to content
This repository has been archived by the owner on Apr 23, 2020. It is now read-only.

Commit

Permalink
Implement a new 'availability' attribute, that allows one to specify
Browse files Browse the repository at this point in the history
which versions of an OS provide a certain facility. For example,

  void foo()
  __attribute__((availability(macosx,introduced=10.2,deprecated=10.4,obsoleted=10.6)));

says that the function "foo" was introduced in 10.2, deprecated in
10.4, and completely obsoleted in 10.6. This attribute ties in with
the deployment targets (e.g., -mmacosx-version-min=10.1 specifies that
we want to deploy back to Mac OS X 10.1). There are several concrete
behaviors that this attribute enables, as illustrated with the
function foo() above:

  - If we choose a deployment target >= Mac OS X 10.4, uses of "foo"
    will result in a deprecation warning, as if we had placed
    attribute((deprecated)) on it (but with a better diagnostic)
  - If we choose a deployment target >= Mac OS X 10.6, uses of "foo"
    will result in an "unavailable" warning (in C)/error (in C++), as
    if we had placed attribute((unavailable)) on it
  - If we choose a deployment target prior to 10.2, foo() is
    weak-imported (if it is a kind of entity that can be weak
    imported), as if we had placed the weak_import attribute on it.

Naturally, there can be multiple availability attributes on a
declaration, for different platforms; only the current platform
matters when checking availability attributes.

The only platforms this attribute currently works for are "ios" and
"macosx", since we already have -mxxxx-version-min flags for them and we
have experience there with macro tricks translating down to the
deprecated/unavailable/weak_import attributes. The end goal is to open
this up to other platforms, and even extension to other "platforms"
that are really libraries (say, through a #pragma clang
define_system), but that hasn't yet been designed and we may want to
shake out more issues with this narrower problem first.

Addresses <rdar://problem/6690412>.

As a drive-by bug-fix, if an entity is both deprecated and
unavailable, we only emit the "unavailable" diagnostic.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@128127 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
DougGregor committed Mar 23, 2011
1 parent 9a8ad9b commit 0a0d2b1
Show file tree
Hide file tree
Showing 45 changed files with 1,060 additions and 109 deletions.
1 change: 1 addition & 0 deletions include/clang/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
2 changes: 2 additions & 0 deletions include/clang/AST/Attr.h
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
8 changes: 0 additions & 8 deletions include/clang/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,14 +119,6 @@ class NamedDecl : public Decl {
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
Expand Down
55 changes: 55 additions & 0 deletions include/clang/AST/DeclBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,15 @@ template<>

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.
///
Expand Down Expand Up @@ -399,6 +408,52 @@ class Decl {

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' attribute, but may also be marked with an
/// '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.
///
Expand Down
16 changes: 16 additions & 0 deletions include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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"]>];
Expand Down
1 change: 1 addition & 0 deletions include/clang/Basic/DiagnosticGroups.td
Original file line number Diff line number Diff line change
Expand Up @@ -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">;
Expand Down
17 changes: 17 additions & 0 deletions include/clang/Basic/DiagnosticParseKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -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">;
Expand All @@ -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">;
Expand Down Expand Up @@ -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<
Expand Down
17 changes: 13 additions & 4 deletions include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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">;
Expand Down Expand Up @@ -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 :
Expand All @@ -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">;
Expand Down Expand Up @@ -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.

14 changes: 13 additions & 1 deletion include/clang/Basic/TargetInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -81,6 +82,9 @@ class TargetInfo : public llvm::RefCountedBase<TargetInfo> {
TargetCXXABI CXXABI;
const LangAS::Map *AddrSpaceMap;

mutable llvm::StringRef PlatformName;
mutable VersionTuple PlatformMinVersion;

unsigned HasAlignMac68kSupport : 1;
unsigned RealTypeUsesObjCFPRet : 3;

Expand Down Expand Up @@ -537,6 +541,14 @@ class TargetInfo : public llvm::RefCountedBase<TargetInfo> {
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;
Expand Down

0 comments on commit 0a0d2b1

Please sign in to comment.