Vendor import of clang trunk r242221:
https://llvm.org/svn/llvm-project/cfe/trunk@242221
This commit is contained in:
parent
c192b3dcff
commit
51ece4aae5
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/vendor/clang/dist/; revision=286427 svn path=/vendor/clang/clang-trunk-r242221/; revision=286428; tag=vendor/clang/clang-trunk-r242221
@ -275,6 +275,9 @@ the configuration (without a prefix: ``Auto``).
|
||||
* ``BS_Linux`` (in configuration: ``Linux``)
|
||||
Like ``Attach``, but break before braces on function, namespace and
|
||||
class definitions.
|
||||
* ``BS_Mozilla`` (in configuration: ``Mozilla``)
|
||||
Like ``Attach``, but break before braces on enum, function, and record
|
||||
definitions.
|
||||
* ``BS_Stroustrup`` (in configuration: ``Stroustrup``)
|
||||
Like ``Attach``, but break before function definitions, and 'else'.
|
||||
* ``BS_Allman`` (in configuration: ``Allman``)
|
||||
@ -394,6 +397,12 @@ the configuration (without a prefix: ``Auto``).
|
||||
(https://developers.google.com/protocol-buffers/).
|
||||
|
||||
|
||||
**MacroBlockBegin** (``std::string``)
|
||||
A regular expression matching macros that start a block.
|
||||
|
||||
**MacroBlockEnd** (``std::string``)
|
||||
A regular expression matching macros that end a block.
|
||||
|
||||
**MaxEmptyLinesToKeep** (``unsigned``)
|
||||
The maximum number of consecutive empty lines to keep.
|
||||
|
||||
|
@ -92,7 +92,7 @@ will be assumed, which sets the defaults for the specified architecture.
|
||||
The system name is generally the OS (linux, darwin), but could be special
|
||||
like the bare-metal "none".
|
||||
|
||||
When a parameter is not important, they can be omitted, or you can
|
||||
When a parameter is not important, it can be omitted, or you can
|
||||
choose ``unknown`` and the defaults will be used. If you choose a parameter
|
||||
that Clang doesn't know, like ``blerg``, it'll ignore and assume
|
||||
``unknown``, which is not always desired, so be careful.
|
||||
|
@ -1991,10 +1991,10 @@ compile time. Partial unrolling replicates the loop body within the loop and
|
||||
reduces the trip count.
|
||||
|
||||
If ``unroll(full)`` is specified the unroller will attempt to fully unroll the
|
||||
loop if the trip count is known at compile time. If the loop count is not known
|
||||
or the fully unrolled code size is greater than the limit specified by the
|
||||
`-pragma-unroll-threshold` command line option the loop will be partially
|
||||
unrolled subject to the same limit.
|
||||
loop if the trip count is known at compile time. If the fully unrolled code size
|
||||
is greater than an internal limit the loop will be partially unrolled up to this
|
||||
limit. If the loop count is not known at compile time the loop will not be
|
||||
unrolled.
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
@ -2006,7 +2006,7 @@ unrolled subject to the same limit.
|
||||
The unroll count can be specified explicitly with ``unroll_count(_value_)`` where
|
||||
_value_ is a positive integer. If this value is greater than the trip count the
|
||||
loop will be fully unrolled. Otherwise the loop is partially unrolled subject
|
||||
to the `-pragma-unroll-threshold` limit.
|
||||
to the same code size limit as with ``unroll(full)``.
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
|
@ -124,20 +124,30 @@ section <pchinternals-chained>`.
|
||||
AST File Contents
|
||||
-----------------
|
||||
|
||||
Clang's AST files are organized into several different blocks, each of which
|
||||
contains the serialized representation of a part of Clang's internal
|
||||
An AST file produced by clang is an object file container with a ``clangast``
|
||||
(COFF) or ``__clangast`` (ELF and Mach-O) section containing the serialized AST.
|
||||
Other target-specific sections in the object file container are used to hold
|
||||
debug information for the data types defined in the AST. Tools built on top of
|
||||
libclang that do not need debug information may also produce raw AST files that
|
||||
only contain the serialized AST.
|
||||
|
||||
The ``clangast`` section is organized into several different blocks, each of
|
||||
which contains the serialized representation of a part of Clang's internal
|
||||
representation. Each of the blocks corresponds to either a block or a record
|
||||
within `LLVM's bitstream format <http://llvm.org/docs/BitCodeFormat.html>`_.
|
||||
The contents of each of these logical blocks are described below.
|
||||
|
||||
.. image:: PCHLayout.png
|
||||
|
||||
For a given AST file, the `llvm-bcanalyzer
|
||||
<http://llvm.org/docs/CommandGuide/llvm-bcanalyzer.html>`_ utility can be used
|
||||
to examine the actual structure of the bitstream for the AST file. This
|
||||
information can be used both to help understand the structure of the AST file
|
||||
and to isolate areas where AST files can still be optimized, e.g., through the
|
||||
introduction of abbreviations.
|
||||
The ``llvm-objdump`` utility provides a ``-raw-clang-ast`` option to extract the
|
||||
binary contents of the AST section from an object file container.
|
||||
|
||||
The `llvm-bcanalyzer <http://llvm.org/docs/CommandGuide/llvm-bcanalyzer.html>`_
|
||||
utility can be used to examine the actual structure of the bitstream for the AST
|
||||
section. This information can be used both to help understand the structure of
|
||||
the AST section and to isolate areas where the AST representation can still be
|
||||
optimized, e.g., through the introduction of abbreviations.
|
||||
|
||||
|
||||
Metadata Block
|
||||
^^^^^^^^^^^^^^
|
||||
|
@ -1488,6 +1488,45 @@ instrumentation:
|
||||
profile. As you make changes to your code, clang may no longer be able to
|
||||
use the profile data. It will warn you when this happens.
|
||||
|
||||
Profile generation and use can also be controlled by the GCC-compatible flags
|
||||
``-fprofile-generate`` and ``-fprofile-use``. Although these flags are
|
||||
semantically equivalent to their GCC counterparts, they *do not* handle
|
||||
GCC-compatible profiles. They are only meant to implement GCC's semantics
|
||||
with respect to profile creation and use.
|
||||
|
||||
.. option:: -fprofile-generate[=<dirname>]
|
||||
|
||||
Without any other arguments, ``-fprofile-generate`` behaves identically to
|
||||
``-fprofile-instr-generate``. When given a directory name, it generates the
|
||||
profile file ``default.profraw`` in the directory named ``dirname``. If
|
||||
``dirname`` does not exist, it will be created at runtime. The environment
|
||||
variable ``LLVM_PROFILE_FILE`` can be used to override the directory and
|
||||
filename for the profile file at runtime. For example,
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ clang++ -O2 -fprofile-generate=yyy/zzz code.cc -o code
|
||||
|
||||
When ``code`` is executed, the profile will be written to the file
|
||||
``yyy/zzz/default.profraw``. This can be altered at runtime via the
|
||||
``LLVM_PROFILE_FILE`` environment variable:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ LLVM_PROFILE_FILE=/tmp/myprofile/code.profraw ./code
|
||||
|
||||
The above invocation will produce the profile file
|
||||
``/tmp/myprofile/code.profraw`` instead of ``yyy/zzz/default.profraw``.
|
||||
Notice that ``LLVM_PROFILE_FILE`` overrides the directory *and* the file
|
||||
name for the profile file.
|
||||
|
||||
.. option:: -fprofile-use[=<pathname>]
|
||||
|
||||
Without any other arguments, ``-fprofile-use`` behaves identically to
|
||||
``-fprofile-instr-use``. Otherwise, if ``pathname`` is the full path to a
|
||||
profile file, it reads from that file. If ``pathname`` is a directory name,
|
||||
it reads from ``pathname/default.profdata``.
|
||||
|
||||
|
||||
Controlling Size of Debug Information
|
||||
-------------------------------------
|
||||
|
@ -73,7 +73,7 @@ clang_VirtualFileOverlay_setCaseSensitivity(CXVirtualFileOverlay,
|
||||
*
|
||||
* \param options is reserved, always pass 0.
|
||||
* \param out_buffer_ptr pointer to receive the buffer pointer, which should be
|
||||
* disposed using \c free().
|
||||
* disposed using \c clang_free().
|
||||
* \param out_buffer_size pointer to receive the buffer size.
|
||||
* \returns 0 for success, non-zero to indicate an error.
|
||||
*/
|
||||
@ -82,6 +82,14 @@ clang_VirtualFileOverlay_writeToBuffer(CXVirtualFileOverlay, unsigned options,
|
||||
char **out_buffer_ptr,
|
||||
unsigned *out_buffer_size);
|
||||
|
||||
/**
|
||||
* \brief free memory allocated by libclang, such as the buffer returned by
|
||||
* \c CXVirtualFileOverlay() or \c clang_ModuleMapDescriptor_writeToBuffer().
|
||||
*
|
||||
* \param buffer memory pointer to free.
|
||||
*/
|
||||
CINDEX_LINKAGE void clang_free(void *buffer);
|
||||
|
||||
/**
|
||||
* \brief Dispose a \c CXVirtualFileOverlay object.
|
||||
*/
|
||||
@ -122,7 +130,7 @@ clang_ModuleMapDescriptor_setUmbrellaHeader(CXModuleMapDescriptor,
|
||||
*
|
||||
* \param options is reserved, always pass 0.
|
||||
* \param out_buffer_ptr pointer to receive the buffer pointer, which should be
|
||||
* disposed using \c free().
|
||||
* disposed using \c clang_free().
|
||||
* \param out_buffer_size pointer to receive the buffer size.
|
||||
* \returns 0 for success, non-zero to indicate an error.
|
||||
*/
|
||||
|
@ -236,6 +236,12 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
QualType ObjCClassRedefinitionType;
|
||||
QualType ObjCSelRedefinitionType;
|
||||
|
||||
/// The identifier 'NSObject'.
|
||||
IdentifierInfo *NSObjectName = nullptr;
|
||||
|
||||
/// The identifier 'NSCopying'.
|
||||
IdentifierInfo *NSCopyingName = nullptr;
|
||||
|
||||
QualType ObjCConstantStringType;
|
||||
mutable RecordDecl *CFConstantStringTypeDecl;
|
||||
|
||||
@ -1189,9 +1195,15 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
QualType getObjCInterfaceType(const ObjCInterfaceDecl *Decl,
|
||||
ObjCInterfaceDecl *PrevDecl = nullptr) const;
|
||||
|
||||
/// Legacy interface: cannot provide type arguments or __kindof.
|
||||
QualType getObjCObjectType(QualType Base,
|
||||
ObjCProtocolDecl * const *Protocols,
|
||||
unsigned NumProtocols) const;
|
||||
|
||||
QualType getObjCObjectType(QualType Base,
|
||||
ArrayRef<QualType> typeArgs,
|
||||
ArrayRef<ObjCProtocolDecl *> protocols,
|
||||
bool isKindOf) const;
|
||||
|
||||
bool ObjCObjectAdoptsQTypeProtocols(QualType QT, ObjCInterfaceDecl *Decl);
|
||||
/// QIdProtocolsAdoptObjCObjectProtocols - Checks that protocols in
|
||||
@ -1351,6 +1363,24 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
ObjCSelRedefinitionType = RedefType;
|
||||
}
|
||||
|
||||
/// Retrieve the identifier 'NSObject'.
|
||||
IdentifierInfo *getNSObjectName() {
|
||||
if (!NSObjectName) {
|
||||
NSObjectName = &Idents.get("NSObject");
|
||||
}
|
||||
|
||||
return NSObjectName;
|
||||
}
|
||||
|
||||
/// Retrieve the identifier 'NSCopying'.
|
||||
IdentifierInfo *getNSCopyingName() {
|
||||
if (!NSCopyingName) {
|
||||
NSCopyingName = &Idents.get("NSCopying");
|
||||
}
|
||||
|
||||
return NSCopyingName;
|
||||
}
|
||||
|
||||
/// \brief Retrieve the Objective-C "instancetype" type, if already known;
|
||||
/// otherwise, returns a NULL type;
|
||||
QualType getObjCInstanceType() {
|
||||
|
@ -940,6 +940,9 @@ DEF_TRAVERSE_TYPE(ObjCObjectType, {
|
||||
// type is itself.
|
||||
if (T->getBaseType().getTypePtr() != T)
|
||||
TRY_TO(TraverseType(T->getBaseType()));
|
||||
for (auto typeArg : T->getTypeArgsAsWritten()) {
|
||||
TRY_TO(TraverseType(typeArg));
|
||||
}
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_TYPE(ObjCObjectPointerType,
|
||||
@ -1166,6 +1169,8 @@ DEF_TRAVERSE_TYPELOC(ObjCObjectType, {
|
||||
// type is itself.
|
||||
if (TL.getTypePtr()->getBaseType().getTypePtr() != TL.getTypePtr())
|
||||
TRY_TO(TraverseTypeLoc(TL.getBaseLoc()));
|
||||
for (unsigned i = 0, n = TL.getNumTypeArgs(); i != n; ++i)
|
||||
TRY_TO(TraverseTypeLoc(TL.getTypeArgTInfo(i)->getTypeLoc()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_TYPELOC(ObjCObjectPointerType,
|
||||
@ -1307,7 +1312,13 @@ DEF_TRAVERSE_DECL(ObjCCompatibleAliasDecl, {// FIXME: implement
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_DECL(ObjCCategoryDecl, {// FIXME: implement
|
||||
})
|
||||
if (ObjCTypeParamList *typeParamList = D->getTypeParamList()) {
|
||||
for (auto typeParam : *typeParamList) {
|
||||
TRY_TO(TraverseObjCTypeParamDecl(typeParam));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_DECL(ObjCCategoryImplDecl, {// FIXME: implement
|
||||
})
|
||||
@ -1316,7 +1327,16 @@ DEF_TRAVERSE_DECL(ObjCImplementationDecl, {// FIXME: implement
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_DECL(ObjCInterfaceDecl, {// FIXME: implement
|
||||
})
|
||||
if (ObjCTypeParamList *typeParamList = D->getTypeParamListAsWritten()) {
|
||||
for (auto typeParam : *typeParamList) {
|
||||
TRY_TO(TraverseObjCTypeParamDecl(typeParam));
|
||||
}
|
||||
}
|
||||
|
||||
if (TypeSourceInfo *superTInfo = D->getSuperClassTInfo()) {
|
||||
TRY_TO(TraverseTypeLoc(superTInfo->getTypeLoc()));
|
||||
}
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_DECL(ObjCProtocolDecl, {// FIXME: implement
|
||||
})
|
||||
@ -1335,6 +1355,15 @@ DEF_TRAVERSE_DECL(ObjCMethodDecl, {
|
||||
return true;
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_DECL(ObjCTypeParamDecl, {
|
||||
if (D->hasExplicitBound()) {
|
||||
TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc()));
|
||||
// We shouldn't traverse D->getTypeForDecl(); it's a result of
|
||||
// declaring the type alias, not something that was written in the
|
||||
// source.
|
||||
}
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_DECL(ObjCPropertyDecl, {
|
||||
if (D->getTypeSourceInfo())
|
||||
TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc()));
|
||||
|
@ -332,10 +332,14 @@ class ObjCMethodDecl : public NamedDecl, public DeclContext {
|
||||
SourceRange getReturnTypeSourceRange() const;
|
||||
|
||||
/// \brief Determine the type of an expression that sends a message to this
|
||||
/// function.
|
||||
QualType getSendResultType() const {
|
||||
return getReturnType().getNonLValueExprType(getASTContext());
|
||||
}
|
||||
/// function. This replaces the type parameters with the types they would
|
||||
/// get if the receiver was parameterless (e.g. it may replace the type
|
||||
/// parameter with 'id').
|
||||
QualType getSendResultType() const;
|
||||
|
||||
/// Determine the type of an expression that sends a message to this
|
||||
/// function with the given receiver type.
|
||||
QualType getSendResultType(QualType receiverType) const;
|
||||
|
||||
TypeSourceInfo *getReturnTypeSourceInfo() const { return ReturnTInfo; }
|
||||
void setReturnTypeSourceInfo(TypeSourceInfo *TInfo) { ReturnTInfo = TInfo; }
|
||||
@ -399,6 +403,11 @@ class ObjCMethodDecl : public NamedDecl, public DeclContext {
|
||||
/// have already been created.
|
||||
void createImplicitParams(ASTContext &Context, const ObjCInterfaceDecl *ID);
|
||||
|
||||
/// \return the type for \c self and set \arg selfIsPseudoStrong and
|
||||
/// \arg selfIsConsumed accordingly.
|
||||
QualType getSelfType(ASTContext &Context, const ObjCInterfaceDecl *OID,
|
||||
bool &selfIsPseudoStrong, bool &selfIsConsumed);
|
||||
|
||||
ImplicitParamDecl * getSelfDecl() const { return SelfDecl; }
|
||||
void setSelfDecl(ImplicitParamDecl *SD) { SelfDecl = SD; }
|
||||
ImplicitParamDecl * getCmdDecl() const { return CmdDecl; }
|
||||
@ -501,6 +510,183 @@ class ObjCMethodDecl : public NamedDecl, public DeclContext {
|
||||
friend class ASTDeclWriter;
|
||||
};
|
||||
|
||||
/// Describes the variance of a given generic parameter.
|
||||
enum class ObjCTypeParamVariance : uint8_t {
|
||||
/// The parameter is invariant: must match exactly.
|
||||
Invariant,
|
||||
/// The parameter is covariant, e.g., X<T> is a subtype of X<U> when
|
||||
/// the type parameter is covariant and T is a subtype of U.
|
||||
Covariant,
|
||||
/// The parameter is contravariant, e.g., X<T> is a subtype of X<U>
|
||||
/// when the type parameter is covariant and U is a subtype of T.
|
||||
Contravariant,
|
||||
};
|
||||
|
||||
/// Represents the declaration of an Objective-C type parameter.
|
||||
///
|
||||
/// \code
|
||||
/// @interface NSDictionary<Key : id<NSCopying>, Value>
|
||||
/// @end
|
||||
/// \endcode
|
||||
///
|
||||
/// In the example above, both \c Key and \c Value are represented by
|
||||
/// \c ObjCTypeParamDecl. \c Key has an explicit bound of \c id<NSCopying>,
|
||||
/// while \c Value gets an implicit bound of \c id.
|
||||
///
|
||||
/// Objective-C type parameters are typedef-names in the grammar,
|
||||
class ObjCTypeParamDecl : public TypedefNameDecl {
|
||||
void anchor() override;
|
||||
|
||||
/// Index of this type parameter in the type parameter list.
|
||||
unsigned Index : 14;
|
||||
|
||||
/// The variance of the type parameter.
|
||||
unsigned Variance : 2;
|
||||
|
||||
/// The location of the variance, if any.
|
||||
SourceLocation VarianceLoc;
|
||||
|
||||
/// The location of the ':', which will be valid when the bound was
|
||||
/// explicitly specified.
|
||||
SourceLocation ColonLoc;
|
||||
|
||||
ObjCTypeParamDecl(ASTContext &ctx, DeclContext *dc,
|
||||
ObjCTypeParamVariance variance, SourceLocation varianceLoc,
|
||||
unsigned index,
|
||||
SourceLocation nameLoc, IdentifierInfo *name,
|
||||
SourceLocation colonLoc, TypeSourceInfo *boundInfo)
|
||||
: TypedefNameDecl(ObjCTypeParam, ctx, dc, nameLoc, nameLoc, name,
|
||||
boundInfo),
|
||||
Index(index), Variance(static_cast<unsigned>(variance)),
|
||||
VarianceLoc(varianceLoc), ColonLoc(colonLoc) { }
|
||||
|
||||
public:
|
||||
static ObjCTypeParamDecl *Create(ASTContext &ctx, DeclContext *dc,
|
||||
ObjCTypeParamVariance variance,
|
||||
SourceLocation varianceLoc,
|
||||
unsigned index,
|
||||
SourceLocation nameLoc,
|
||||
IdentifierInfo *name,
|
||||
SourceLocation colonLoc,
|
||||
TypeSourceInfo *boundInfo);
|
||||
static ObjCTypeParamDecl *CreateDeserialized(ASTContext &ctx, unsigned ID);
|
||||
|
||||
SourceRange getSourceRange() const override LLVM_READONLY;
|
||||
|
||||
/// Determine the variance of this type parameter.
|
||||
ObjCTypeParamVariance getVariance() const {
|
||||
return static_cast<ObjCTypeParamVariance>(Variance);
|
||||
}
|
||||
|
||||
/// Set the variance of this type parameter.
|
||||
void setVariance(ObjCTypeParamVariance variance) {
|
||||
Variance = static_cast<unsigned>(variance);
|
||||
}
|
||||
|
||||
/// Retrieve the location of the variance keyword.
|
||||
SourceLocation getVarianceLoc() const { return VarianceLoc; }
|
||||
|
||||
/// Retrieve the index into its type parameter list.
|
||||
unsigned getIndex() const { return Index; }
|
||||
|
||||
/// Whether this type parameter has an explicitly-written type bound, e.g.,
|
||||
/// "T : NSView".
|
||||
bool hasExplicitBound() const { return ColonLoc.isValid(); }
|
||||
|
||||
/// Retrieve the location of the ':' separating the type parameter name
|
||||
/// from the explicitly-specified bound.
|
||||
SourceLocation getColonLoc() const { return ColonLoc; }
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classofKind(Kind K) { return K == ObjCTypeParam; }
|
||||
|
||||
friend class ASTDeclReader;
|
||||
friend class ASTDeclWriter;
|
||||
};
|
||||
|
||||
/// Stores a list of Objective-C type parameters for a parameterized class
|
||||
/// or a category/extension thereof.
|
||||
///
|
||||
/// \code
|
||||
/// @interface NSArray<T> // stores the <T>
|
||||
/// @end
|
||||
/// \endcode
|
||||
class ObjCTypeParamList {
|
||||
/// Stores the components of a SourceRange as a POD.
|
||||
struct PODSourceRange {
|
||||
unsigned Begin;
|
||||
unsigned End;
|
||||
};
|
||||
|
||||
union {
|
||||
/// Location of the left and right angle brackets.
|
||||
PODSourceRange Brackets;
|
||||
|
||||
// Used only for alignment.
|
||||
ObjCTypeParamDecl *AlignmentHack;
|
||||
};
|
||||
|
||||
/// The number of parameters in the list, which are tail-allocated.
|
||||
unsigned NumParams;
|
||||
|
||||
ObjCTypeParamList(SourceLocation lAngleLoc,
|
||||
ArrayRef<ObjCTypeParamDecl *> typeParams,
|
||||
SourceLocation rAngleLoc);
|
||||
|
||||
public:
|
||||
/// Create a new Objective-C type parameter list.
|
||||
static ObjCTypeParamList *create(ASTContext &ctx,
|
||||
SourceLocation lAngleLoc,
|
||||
ArrayRef<ObjCTypeParamDecl *> typeParams,
|
||||
SourceLocation rAngleLoc);
|
||||
|
||||
/// Iterate through the type parameters in the list.
|
||||
typedef ObjCTypeParamDecl **iterator;
|
||||
|
||||
iterator begin() { return reinterpret_cast<ObjCTypeParamDecl **>(this + 1); }
|
||||
|
||||
iterator end() { return begin() + size(); }
|
||||
|
||||
/// Determine the number of type parameters in this list.
|
||||
unsigned size() const { return NumParams; }
|
||||
|
||||
// Iterate through the type parameters in the list.
|
||||
typedef ObjCTypeParamDecl * const *const_iterator;
|
||||
|
||||
const_iterator begin() const {
|
||||
return reinterpret_cast<ObjCTypeParamDecl * const *>(this + 1);
|
||||
}
|
||||
|
||||
const_iterator end() const {
|
||||
return begin() + size();
|
||||
}
|
||||
|
||||
ObjCTypeParamDecl *front() const {
|
||||
assert(size() > 0 && "empty Objective-C type parameter list");
|
||||
return *begin();
|
||||
}
|
||||
|
||||
ObjCTypeParamDecl *back() const {
|
||||
assert(size() > 0 && "empty Objective-C type parameter list");
|
||||
return *(end() - 1);
|
||||
}
|
||||
|
||||
SourceLocation getLAngleLoc() const {
|
||||
return SourceLocation::getFromRawEncoding(Brackets.Begin);
|
||||
}
|
||||
SourceLocation getRAngleLoc() const {
|
||||
return SourceLocation::getFromRawEncoding(Brackets.End);
|
||||
}
|
||||
SourceRange getSourceRange() const {
|
||||
return SourceRange(getLAngleLoc(), getRAngleLoc());
|
||||
}
|
||||
|
||||
/// Gather the default set of type arguments to be substituted for
|
||||
/// these type parameters when dealing with an unspecialized type.
|
||||
void gatherDefaultTypeArgs(SmallVectorImpl<QualType> &typeArgs) const;
|
||||
};
|
||||
|
||||
/// ObjCContainerDecl - Represents a container for method declarations.
|
||||
/// Current sub-classes are ObjCInterfaceDecl, ObjCCategoryDecl,
|
||||
/// ObjCProtocolDecl, and ObjCImplDecl.
|
||||
@ -676,9 +862,9 @@ class ObjCInterfaceDecl : public ObjCContainerDecl
|
||||
/// declaration.
|
||||
ObjCInterfaceDecl *Definition;
|
||||
|
||||
/// Class's super class.
|
||||
ObjCInterfaceDecl *SuperClass;
|
||||
|
||||
/// When non-null, this is always an ObjCObjectType.
|
||||
TypeSourceInfo *SuperClassTInfo;
|
||||
|
||||
/// Protocols referenced in the \@interface declaration
|
||||
ObjCProtocolList ReferencedProtocols;
|
||||
|
||||
@ -719,16 +905,13 @@ class ObjCInterfaceDecl : public ObjCContainerDecl
|
||||
};
|
||||
/// One of the \c InheritedDesignatedInitializersState enumeratos.
|
||||
mutable unsigned InheritedDesignatedInitializers : 2;
|
||||
|
||||
/// \brief The location of the superclass, if any.
|
||||
SourceLocation SuperClassLoc;
|
||||
|
||||
/// \brief The location of the last location in this declaration, before
|
||||
/// the properties/methods. For example, this will be the '>', '}', or
|
||||
/// identifier,
|
||||
SourceLocation EndLoc;
|
||||
|
||||
DefinitionData() : Definition(), SuperClass(), CategoryList(), IvarList(),
|
||||
DefinitionData() : Definition(), SuperClassTInfo(), CategoryList(), IvarList(),
|
||||
ExternallyCompleted(),
|
||||
IvarListMissingImplementation(true),
|
||||
HasDesignatedInitializers(),
|
||||
@ -736,11 +919,15 @@ class ObjCInterfaceDecl : public ObjCContainerDecl
|
||||
};
|
||||
|
||||
ObjCInterfaceDecl(const ASTContext &C, DeclContext *DC, SourceLocation AtLoc,
|
||||
IdentifierInfo *Id, SourceLocation CLoc,
|
||||
ObjCInterfaceDecl *PrevDecl, bool IsInternal);
|
||||
IdentifierInfo *Id, ObjCTypeParamList *typeParamList,
|
||||
SourceLocation CLoc, ObjCInterfaceDecl *PrevDecl,
|
||||
bool IsInternal);
|
||||
|
||||
void LoadExternalDefinition() const;
|
||||
|
||||
/// The type parameters associated with this class, if any.
|
||||
ObjCTypeParamList *TypeParamList;
|
||||
|
||||
/// \brief Contains a pointer to the data associated with this class,
|
||||
/// which will be NULL if this class has not yet been defined.
|
||||
///
|
||||
@ -771,12 +958,33 @@ class ObjCInterfaceDecl : public ObjCContainerDecl
|
||||
static ObjCInterfaceDecl *Create(const ASTContext &C, DeclContext *DC,
|
||||
SourceLocation atLoc,
|
||||
IdentifierInfo *Id,
|
||||
ObjCTypeParamList *typeParamList,
|
||||
ObjCInterfaceDecl *PrevDecl,
|
||||
SourceLocation ClassLoc = SourceLocation(),
|
||||
bool isInternal = false);
|
||||
|
||||
static ObjCInterfaceDecl *CreateDeserialized(const ASTContext &C, unsigned ID);
|
||||
|
||||
/// Retrieve the type parameters of this class.
|
||||
///
|
||||
/// This function looks for a type parameter list for the given
|
||||
/// class; if the class has been declared (with \c \@class) but not
|
||||
/// defined (with \c \@interface), it will search for a declaration that
|
||||
/// has type parameters, skipping any declarations that do not.
|
||||
ObjCTypeParamList *getTypeParamList() const;
|
||||
|
||||
/// Set the type parameters of this class.
|
||||
///
|
||||
/// This function is used by the AST importer, which must import the type
|
||||
/// parameters after creating their DeclContext to avoid loops.
|
||||
void setTypeParamList(ObjCTypeParamList *TPL);
|
||||
|
||||
/// Retrieve the type parameters written on this particular declaration of
|
||||
/// the class.
|
||||
ObjCTypeParamList *getTypeParamListAsWritten() const {
|
||||
return TypeParamList;
|
||||
}
|
||||
|
||||
SourceRange getSourceRange() const override LLVM_READONLY {
|
||||
if (isThisDeclarationADefinition())
|
||||
return ObjCContainerDecl::getSourceRange();
|
||||
@ -1023,7 +1231,16 @@ class ObjCInterfaceDecl : public ObjCContainerDecl
|
||||
/// a forward declaration (\@class) to a definition (\@interface).
|
||||
void startDefinition();
|
||||
|
||||
ObjCInterfaceDecl *getSuperClass() const {
|
||||
/// Retrieve the superclass type.
|
||||
const ObjCObjectType *getSuperClassType() const {
|
||||
if (TypeSourceInfo *TInfo = getSuperClassTInfo())
|
||||
return TInfo->getType()->castAs<ObjCObjectType>();
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Retrieve the type source information for the superclass.
|
||||
TypeSourceInfo *getSuperClassTInfo() const {
|
||||
// FIXME: Should make sure no callers ever do this.
|
||||
if (!hasDefinition())
|
||||
return nullptr;
|
||||
@ -1031,13 +1248,15 @@ class ObjCInterfaceDecl : public ObjCContainerDecl
|
||||
if (data().ExternallyCompleted)
|
||||
LoadExternalDefinition();
|
||||
|
||||
return data().SuperClass;
|
||||
return data().SuperClassTInfo;
|
||||
}
|
||||
|
||||
void setSuperClass(ObjCInterfaceDecl * superCls) {
|
||||
data().SuperClass =
|
||||
(superCls && superCls->hasDefinition()) ? superCls->getDefinition()
|
||||
: superCls;
|
||||
// Retrieve the declaration for the superclass of this class, which
|
||||
// does not include any type arguments that apply to the superclass.
|
||||
ObjCInterfaceDecl *getSuperClass() const;
|
||||
|
||||
void setSuperClass(TypeSourceInfo *superClass) {
|
||||
data().SuperClassTInfo = superClass;
|
||||
}
|
||||
|
||||
/// \brief Iterator that walks over the list of categories, filtering out
|
||||
@ -1329,8 +1548,8 @@ class ObjCInterfaceDecl : public ObjCContainerDecl
|
||||
|
||||
void setEndOfDefinitionLoc(SourceLocation LE) { data().EndLoc = LE; }
|
||||
|
||||
void setSuperClassLoc(SourceLocation Loc) { data().SuperClassLoc = Loc; }
|
||||
SourceLocation getSuperClassLoc() const { return data().SuperClassLoc; }
|
||||
/// Retrieve the starting location of the superclass.
|
||||
SourceLocation getSuperClassLoc() const;
|
||||
|
||||
/// isImplicitInterfaceDecl - check that this is an implicitly declared
|
||||
/// ObjCInterfaceDecl node. This is for legacy objective-c \@implementation
|
||||
@ -1438,6 +1657,10 @@ class ObjCIvarDecl : public FieldDecl {
|
||||
void setSynthesize(bool synth) { Synthesized = synth; }
|
||||
bool getSynthesize() const { return Synthesized; }
|
||||
|
||||
/// Retrieve the type of this instance variable when viewed as a member of a
|
||||
/// specific object type.
|
||||
QualType getUsageType(QualType objectType) const;
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classofKind(Kind K) { return K == ObjCIvar; }
|
||||
@ -1719,6 +1942,9 @@ class ObjCCategoryDecl : public ObjCContainerDecl {
|
||||
/// Interface belonging to this category
|
||||
ObjCInterfaceDecl *ClassInterface;
|
||||
|
||||
/// The type parameters associated with this category, if any.
|
||||
ObjCTypeParamList *TypeParamList;
|
||||
|
||||
/// referenced protocols in this category.
|
||||
ObjCProtocolList ReferencedProtocols;
|
||||
|
||||
@ -1736,13 +1962,9 @@ class ObjCCategoryDecl : public ObjCContainerDecl {
|
||||
ObjCCategoryDecl(DeclContext *DC, SourceLocation AtLoc,
|
||||
SourceLocation ClassNameLoc, SourceLocation CategoryNameLoc,
|
||||
IdentifierInfo *Id, ObjCInterfaceDecl *IDecl,
|
||||
ObjCTypeParamList *typeParamList,
|
||||
SourceLocation IvarLBraceLoc=SourceLocation(),
|
||||
SourceLocation IvarRBraceLoc=SourceLocation())
|
||||
: ObjCContainerDecl(ObjCCategory, DC, Id, ClassNameLoc, AtLoc),
|
||||
ClassInterface(IDecl), NextClassCategory(nullptr),
|
||||
CategoryNameLoc(CategoryNameLoc),
|
||||
IvarLBraceLoc(IvarLBraceLoc), IvarRBraceLoc(IvarRBraceLoc) {
|
||||
}
|
||||
SourceLocation IvarRBraceLoc=SourceLocation());
|
||||
|
||||
public:
|
||||
|
||||
@ -1752,6 +1974,7 @@ class ObjCCategoryDecl : public ObjCContainerDecl {
|
||||
SourceLocation CategoryNameLoc,
|
||||
IdentifierInfo *Id,
|
||||
ObjCInterfaceDecl *IDecl,
|
||||
ObjCTypeParamList *typeParamList,
|
||||
SourceLocation IvarLBraceLoc=SourceLocation(),
|
||||
SourceLocation IvarRBraceLoc=SourceLocation());
|
||||
static ObjCCategoryDecl *CreateDeserialized(ASTContext &C, unsigned ID);
|
||||
@ -1759,6 +1982,17 @@ class ObjCCategoryDecl : public ObjCContainerDecl {
|
||||
ObjCInterfaceDecl *getClassInterface() { return ClassInterface; }
|
||||
const ObjCInterfaceDecl *getClassInterface() const { return ClassInterface; }
|
||||
|
||||
/// Retrieve the type parameter list associated with this category or
|
||||
/// extension.
|
||||
ObjCTypeParamList *getTypeParamList() const { return TypeParamList; }
|
||||
|
||||
/// Set the type parameters of this category.
|
||||
///
|
||||
/// This function is used by the AST importer, which must import the type
|
||||
/// parameters after creating their DeclContext to avoid loops.
|
||||
void setTypeParamList(ObjCTypeParamList *TPL);
|
||||
|
||||
|
||||
ObjCCategoryImplDecl *getImplementation() const;
|
||||
void setImplementation(ObjCCategoryImplDecl *ImplD);
|
||||
|
||||
@ -2275,6 +2509,10 @@ class ObjCPropertyDecl : public NamedDecl {
|
||||
DeclTypeSourceInfo = TSI;
|
||||
}
|
||||
|
||||
/// Retrieve the type when this property is used with a specific base object
|
||||
/// type.
|
||||
QualType getUsageType(QualType objectType) const;
|
||||
|
||||
PropertyAttributeKind getPropertyAttributes() const {
|
||||
return PropertyAttributeKind(PropertyAttributes);
|
||||
}
|
||||
|
@ -687,40 +687,7 @@ class ObjCPropertyRefExpr : public Expr {
|
||||
QualType getSuperReceiverType() const {
|
||||
return QualType(Receiver.get<const Type*>(), 0);
|
||||
}
|
||||
QualType getGetterResultType() const {
|
||||
QualType ResultType;
|
||||
if (isExplicitProperty()) {
|
||||
const ObjCPropertyDecl *PDecl = getExplicitProperty();
|
||||
if (const ObjCMethodDecl *Getter = PDecl->getGetterMethodDecl())
|
||||
ResultType = Getter->getReturnType();
|
||||
else
|
||||
ResultType = PDecl->getType();
|
||||
} else {
|
||||
const ObjCMethodDecl *Getter = getImplicitPropertyGetter();
|
||||
if (Getter)
|
||||
ResultType = Getter->getReturnType(); // with reference!
|
||||
}
|
||||
return ResultType;
|
||||
}
|
||||
|
||||
QualType getSetterArgType() const {
|
||||
QualType ArgType;
|
||||
if (isImplicitProperty()) {
|
||||
const ObjCMethodDecl *Setter = getImplicitPropertySetter();
|
||||
ObjCMethodDecl::param_const_iterator P = Setter->param_begin();
|
||||
ArgType = (*P)->getType();
|
||||
} else {
|
||||
if (ObjCPropertyDecl *PDecl = getExplicitProperty())
|
||||
if (const ObjCMethodDecl *Setter = PDecl->getSetterMethodDecl()) {
|
||||
ObjCMethodDecl::param_const_iterator P = Setter->param_begin();
|
||||
ArgType = (*P)->getType();
|
||||
}
|
||||
if (ArgType.isNull())
|
||||
ArgType = getType();
|
||||
}
|
||||
return ArgType;
|
||||
}
|
||||
|
||||
ObjCInterfaceDecl *getClassReceiver() const {
|
||||
return Receiver.get<ObjCInterfaceDecl*>();
|
||||
}
|
||||
@ -728,6 +695,9 @@ class ObjCPropertyRefExpr : public Expr {
|
||||
bool isSuperReceiver() const { return Receiver.is<const Type*>(); }
|
||||
bool isClassReceiver() const { return Receiver.is<ObjCInterfaceDecl*>(); }
|
||||
|
||||
/// Determine the type of the base, regardless of the kind of receiver.
|
||||
QualType getReceiverType(const ASTContext &ctx) const;
|
||||
|
||||
SourceLocation getLocStart() const LLVM_READONLY {
|
||||
return isObjectReceiver() ? getBase()->getLocStart() :getReceiverLocation();
|
||||
}
|
||||
|
@ -1008,6 +1008,9 @@ DEF_TRAVERSE_TYPE(ObjCObjectType, {
|
||||
// type is itself.
|
||||
if (T->getBaseType().getTypePtr() != T)
|
||||
TRY_TO(TraverseType(T->getBaseType()));
|
||||
for (auto typeArg : T->getTypeArgsAsWritten()) {
|
||||
TRY_TO(TraverseType(typeArg));
|
||||
}
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_TYPE(ObjCObjectPointerType,
|
||||
@ -1234,6 +1237,8 @@ DEF_TRAVERSE_TYPELOC(ObjCObjectType, {
|
||||
// type is itself.
|
||||
if (TL.getTypePtr()->getBaseType().getTypePtr() != TL.getTypePtr())
|
||||
TRY_TO(TraverseTypeLoc(TL.getBaseLoc()));
|
||||
for (unsigned i = 0, n = TL.getNumTypeArgs(); i != n; ++i)
|
||||
TRY_TO(TraverseTypeLoc(TL.getTypeArgTInfo(i)->getTypeLoc()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_TYPELOC(ObjCObjectPointerType,
|
||||
@ -1382,7 +1387,12 @@ DEF_TRAVERSE_DECL(ObjCCompatibleAliasDecl, {// FIXME: implement
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_DECL(ObjCCategoryDecl, {// FIXME: implement
|
||||
})
|
||||
if (ObjCTypeParamList *typeParamList = D->getTypeParamList()) {
|
||||
for (auto typeParam : *typeParamList) {
|
||||
TRY_TO(TraverseObjCTypeParamDecl(typeParam));
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_DECL(ObjCCategoryImplDecl, {// FIXME: implement
|
||||
})
|
||||
@ -1391,7 +1401,16 @@ DEF_TRAVERSE_DECL(ObjCImplementationDecl, {// FIXME: implement
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_DECL(ObjCInterfaceDecl, {// FIXME: implement
|
||||
})
|
||||
if (ObjCTypeParamList *typeParamList = D->getTypeParamListAsWritten()) {
|
||||
for (auto typeParam : *typeParamList) {
|
||||
TRY_TO(TraverseObjCTypeParamDecl(typeParam));
|
||||
}
|
||||
}
|
||||
|
||||
if (TypeSourceInfo *superTInfo = D->getSuperClassTInfo()) {
|
||||
TRY_TO(TraverseTypeLoc(superTInfo->getTypeLoc()));
|
||||
}
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_DECL(ObjCProtocolDecl, {// FIXME: implement
|
||||
})
|
||||
@ -1410,6 +1429,15 @@ DEF_TRAVERSE_DECL(ObjCMethodDecl, {
|
||||
return true;
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_DECL(ObjCTypeParamDecl, {
|
||||
if (D->hasExplicitBound()) {
|
||||
TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc()));
|
||||
// We shouldn't traverse D->getTypeForDecl(); it's a result of
|
||||
// declaring the type alias, not something that was written in the
|
||||
// source.
|
||||
}
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_DECL(ObjCPropertyDecl, {
|
||||
if (D->getTypeSourceInfo())
|
||||
TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc()));
|
||||
|
@ -533,6 +533,24 @@ struct SplitQualType {
|
||||
}
|
||||
};
|
||||
|
||||
/// The kind of type we are substituting Objective-C type arguments into.
|
||||
///
|
||||
/// The kind of substitution affects the replacement of type parameters when
|
||||
/// no concrete type information is provided, e.g., when dealing with an
|
||||
/// unspecialized type.
|
||||
enum class ObjCSubstitutionContext {
|
||||
/// An ordinary type.
|
||||
Ordinary,
|
||||
/// The result type of a method or function.
|
||||
Result,
|
||||
/// The parameter type of a method or function.
|
||||
Parameter,
|
||||
/// The type of a property.
|
||||
Property,
|
||||
/// The superclass of a type.
|
||||
Superclass,
|
||||
};
|
||||
|
||||
/// QualType - For efficiency, we don't store CV-qualified types as nodes on
|
||||
/// their own: instead each reference to a type stores the qualifiers. This
|
||||
/// greatly reduces the number of nodes we need to allocate for types (for
|
||||
@ -994,6 +1012,51 @@ class QualType {
|
||||
/// type other than void.
|
||||
bool isCForbiddenLValueType() const;
|
||||
|
||||
/// Substitute type arguments for the Objective-C type parameters used in the
|
||||
/// subject type.
|
||||
///
|
||||
/// \param ctx ASTContext in which the type exists.
|
||||
///
|
||||
/// \param typeArgs The type arguments that will be substituted for the
|
||||
/// Objective-C type parameters in the subject type, which are generally
|
||||
/// computed via \c Type::getObjCSubstitutions. If empty, the type
|
||||
/// parameters will be replaced with their bounds or id/Class, as appropriate
|
||||
/// for the context.
|
||||
///
|
||||
/// \param context The context in which the subject type was written.
|
||||
///
|
||||
/// \returns the resulting type.
|
||||
QualType substObjCTypeArgs(ASTContext &ctx,
|
||||
ArrayRef<QualType> typeArgs,
|
||||
ObjCSubstitutionContext context) const;
|
||||
|
||||
/// Substitute type arguments from an object type for the Objective-C type
|
||||
/// parameters used in the subject type.
|
||||
///
|
||||
/// This operation combines the computation of type arguments for
|
||||
/// substitution (\c Type::getObjCSubstitutions) with the actual process of
|
||||
/// substitution (\c QualType::substObjCTypeArgs) for the convenience of
|
||||
/// callers that need to perform a single substitution in isolation.
|
||||
///
|
||||
/// \param objectType The type of the object whose member type we're
|
||||
/// substituting into. For example, this might be the receiver of a message
|
||||
/// or the base of a property access.
|
||||
///
|
||||
/// \param dc The declaration context from which the subject type was
|
||||
/// retrieved, which indicates (for example) which type parameters should
|
||||
/// be substituted.
|
||||
///
|
||||
/// \param context The context in which the subject type was written.
|
||||
///
|
||||
/// \returns the subject type after replacing all of the Objective-C type
|
||||
/// parameters with their corresponding arguments.
|
||||
QualType substObjCMemberType(QualType objectType,
|
||||
const DeclContext *dc,
|
||||
ObjCSubstitutionContext context) const;
|
||||
|
||||
/// Strip Objective-C "__kindof" types from the given type.
|
||||
QualType stripObjCKindOfType(const ASTContext &ctx) const;
|
||||
|
||||
private:
|
||||
// These methods are implemented in a separate translation unit;
|
||||
// "static"-ize them to avoid creating temporary QualTypes in the
|
||||
@ -1288,10 +1351,17 @@ class Type : public ExtQualsTypeCommonBase {
|
||||
|
||||
unsigned : NumTypeBits;
|
||||
|
||||
/// The number of type arguments stored directly on this object type.
|
||||
unsigned NumTypeArgs : 7;
|
||||
|
||||
/// NumProtocols - The number of protocols stored directly on this
|
||||
/// object type.
|
||||
unsigned NumProtocols : 32 - NumTypeBits;
|
||||
unsigned NumProtocols : 6;
|
||||
|
||||
/// Whether this is a "kindof" type.
|
||||
unsigned IsKindOf : 1;
|
||||
};
|
||||
static_assert(NumTypeBits + 7 + 6 + 1 <= 32, "Does not fit in an unsigned");
|
||||
|
||||
class ReferenceTypeBitfields {
|
||||
friend class ReferenceType;
|
||||
@ -1585,7 +1655,28 @@ class Type : public ExtQualsTypeCommonBase {
|
||||
bool isObjCQualifiedClassType() const; // Class<foo>
|
||||
bool isObjCObjectOrInterfaceType() const;
|
||||
bool isObjCIdType() const; // id
|
||||
|
||||
/// Whether the type is Objective-C 'id' or a __kindof type of an
|
||||
/// object type, e.g., __kindof NSView * or __kindof id
|
||||
/// <NSCopying>.
|
||||
///
|
||||
/// \param bound Will be set to the bound on non-id subtype types,
|
||||
/// which will be (possibly specialized) Objective-C class type, or
|
||||
/// null for 'id.
|
||||
bool isObjCIdOrObjectKindOfType(const ASTContext &ctx,
|
||||
const ObjCObjectType *&bound) const;
|
||||
|
||||
bool isObjCClassType() const; // Class
|
||||
|
||||
/// Whether the type is Objective-C 'Class' or a __kindof type of an
|
||||
/// Class type, e.g., __kindof Class <NSCopying>.
|
||||
///
|
||||
/// Unlike \c isObjCIdOrObjectKindOfType, there is no relevant bound
|
||||
/// here because Objective-C's type system cannot express "a class
|
||||
/// object for a subclass of NSFoo".
|
||||
bool isObjCClassOrClassKindOfType() const;
|
||||
|
||||
bool isBlockCompatibleObjCPointerType(ASTContext &ctx) const;
|
||||
bool isObjCSelType() const; // Class
|
||||
bool isObjCBuiltinType() const; // 'id' or 'Class'
|
||||
bool isObjCARCBridgableType() const;
|
||||
@ -1697,6 +1788,7 @@ class Type : public ExtQualsTypeCommonBase {
|
||||
/// NOTE: getAs*ArrayType are methods on ASTContext.
|
||||
const RecordType *getAsUnionType() const;
|
||||
const ComplexType *getAsComplexIntegerType() const; // GCC complex int type.
|
||||
const ObjCObjectType *getAsObjCInterfaceType() const;
|
||||
// The following is a convenience method that returns an ObjCObjectPointerType
|
||||
// for object declared using an interface.
|
||||
const ObjCObjectPointerType *getAsObjCInterfacePointerType() const;
|
||||
@ -1832,6 +1924,28 @@ class Type : public ExtQualsTypeCommonBase {
|
||||
/// pointer type.
|
||||
bool canHaveNullability() const;
|
||||
|
||||
/// Retrieve the set of substitutions required when accessing a member
|
||||
/// of the Objective-C receiver type that is declared in the given context.
|
||||
///
|
||||
/// \c *this is the type of the object we're operating on, e.g., the
|
||||
/// receiver for a message send or the base of a property access, and is
|
||||
/// expected to be of some object or object pointer type.
|
||||
///
|
||||
/// \param dc The declaration context for which we are building up a
|
||||
/// substitution mapping, which should be an Objective-C class, extension,
|
||||
/// category, or method within.
|
||||
///
|
||||
/// \returns an array of type arguments that can be substituted for
|
||||
/// the type parameters of the given declaration context in any type described
|
||||
/// within that context, or an empty optional to indicate that no
|
||||
/// substitution is required.
|
||||
Optional<ArrayRef<QualType>>
|
||||
getObjCSubstitutions(const DeclContext *dc) const;
|
||||
|
||||
/// Determines if this is an ObjC interface type that may accept type
|
||||
/// parameters.
|
||||
bool acceptsObjCTypeParams() const;
|
||||
|
||||
const char *getTypeClassName() const;
|
||||
|
||||
QualType getCanonicalTypeInternal() const {
|
||||
@ -3497,6 +3611,7 @@ class AttributedType : public Type, public llvm::FoldingSetNode {
|
||||
attr_nonnull,
|
||||
attr_nullable,
|
||||
attr_null_unspecified,
|
||||
attr_objc_kindof,
|
||||
};
|
||||
|
||||
private:
|
||||
@ -4369,19 +4484,25 @@ class PackExpansionType : public Type, public llvm::FoldingSetNode {
|
||||
};
|
||||
|
||||
/// ObjCObjectType - Represents a class type in Objective C.
|
||||
/// Every Objective C type is a combination of a base type and a
|
||||
/// list of protocols.
|
||||
///
|
||||
/// Every Objective C type is a combination of a base type, a set of
|
||||
/// type arguments (optional, for parameterized classes) and a list of
|
||||
/// protocols.
|
||||
///
|
||||
/// Given the following declarations:
|
||||
/// \code
|
||||
/// \@class C;
|
||||
/// \@class C<T>;
|
||||
/// \@protocol P;
|
||||
/// \endcode
|
||||
///
|
||||
/// 'C' is an ObjCInterfaceType C. It is sugar for an ObjCObjectType
|
||||
/// with base C and no protocols.
|
||||
///
|
||||
/// 'C<P>' is an ObjCObjectType with base C and protocol list [P].
|
||||
/// 'C<P>' is an unspecialized ObjCObjectType with base C and protocol list [P].
|
||||
/// 'C<C*>' is a specialized ObjCObjectType with type arguments 'C*' and no
|
||||
/// protocol list.
|
||||
/// 'C<C*><P>' is a specialized ObjCObjectType with base C, type arguments 'C*',
|
||||
/// and protocol list [P].
|
||||
///
|
||||
/// 'id' is a TypedefType which is sugar for an ObjCObjectPointerType whose
|
||||
/// pointee is an ObjCObjectType with base BuiltinType::ObjCIdType
|
||||
@ -4391,8 +4512,10 @@ class PackExpansionType : public Type, public llvm::FoldingSetNode {
|
||||
/// with base BuiltinType::ObjCIdType and protocol list [P]. Eventually
|
||||
/// this should get its own sugar class to better represent the source.
|
||||
class ObjCObjectType : public Type {
|
||||
// ObjCObjectType.NumProtocols - the number of protocols stored
|
||||
// ObjCObjectType.NumTypeArgs - the number of type arguments stored
|
||||
// after the ObjCObjectPointerType node.
|
||||
// ObjCObjectType.NumProtocols - the number of protocols stored
|
||||
// after the type arguments of ObjCObjectPointerType node.
|
||||
//
|
||||
// These protocols are those written directly on the type. If
|
||||
// protocol qualifiers ever become additive, the iterators will need
|
||||
@ -4404,23 +4527,38 @@ class ObjCObjectType : public Type {
|
||||
/// Either a BuiltinType or an InterfaceType or sugar for either.
|
||||
QualType BaseType;
|
||||
|
||||
/// Cached superclass type.
|
||||
mutable llvm::PointerIntPair<const ObjCObjectType *, 1, bool>
|
||||
CachedSuperClassType;
|
||||
|
||||
ObjCProtocolDecl * const *getProtocolStorage() const {
|
||||
return const_cast<ObjCObjectType*>(this)->getProtocolStorage();
|
||||
}
|
||||
|
||||
QualType *getTypeArgStorage();
|
||||
const QualType *getTypeArgStorage() const {
|
||||
return const_cast<ObjCObjectType *>(this)->getTypeArgStorage();
|
||||
}
|
||||
|
||||
ObjCProtocolDecl **getProtocolStorage();
|
||||
|
||||
protected:
|
||||
ObjCObjectType(QualType Canonical, QualType Base,
|
||||
ObjCProtocolDecl * const *Protocols, unsigned NumProtocols);
|
||||
ArrayRef<QualType> typeArgs,
|
||||
ArrayRef<ObjCProtocolDecl *> protocols,
|
||||
bool isKindOf);
|
||||
|
||||
enum Nonce_ObjCInterface { Nonce_ObjCInterface };
|
||||
ObjCObjectType(enum Nonce_ObjCInterface)
|
||||
: Type(ObjCInterface, QualType(), false, false, false, false),
|
||||
BaseType(QualType(this_(), 0)) {
|
||||
ObjCObjectTypeBits.NumProtocols = 0;
|
||||
ObjCObjectTypeBits.NumTypeArgs = 0;
|
||||
ObjCObjectTypeBits.IsKindOf = 0;
|
||||
}
|
||||
|
||||
void computeSuperClassTypeSlow() const;
|
||||
|
||||
public:
|
||||
/// getBaseType - Gets the base type of this object type. This is
|
||||
/// always (possibly sugar for) one of:
|
||||
@ -4452,6 +4590,33 @@ class ObjCObjectType : public Type {
|
||||
/// really is an interface.
|
||||
ObjCInterfaceDecl *getInterface() const;
|
||||
|
||||
/// Determine whether this object type is "specialized", meaning
|
||||
/// that it has type arguments.
|
||||
bool isSpecialized() const;
|
||||
|
||||
/// Determine whether this object type was written with type arguments.
|
||||
bool isSpecializedAsWritten() const {
|
||||
return ObjCObjectTypeBits.NumTypeArgs > 0;
|
||||
}
|
||||
|
||||
/// Determine whether this object type is "unspecialized", meaning
|
||||
/// that it has no type arguments.
|
||||
bool isUnspecialized() const { return !isSpecialized(); }
|
||||
|
||||
/// Determine whether this object type is "unspecialized" as
|
||||
/// written, meaning that it has no type arguments.
|
||||
bool isUnspecializedAsWritten() const { return !isSpecializedAsWritten(); }
|
||||
|
||||
/// Retrieve the type arguments of this object type (semantically).
|
||||
ArrayRef<QualType> getTypeArgs() const;
|
||||
|
||||
/// Retrieve the type arguments of this object type as they were
|
||||
/// written.
|
||||
ArrayRef<QualType> getTypeArgsAsWritten() const {
|
||||
return ArrayRef<QualType>(getTypeArgStorage(),
|
||||
ObjCObjectTypeBits.NumTypeArgs);
|
||||
}
|
||||
|
||||
typedef ObjCProtocolDecl * const *qual_iterator;
|
||||
typedef llvm::iterator_range<qual_iterator> qual_range;
|
||||
|
||||
@ -4471,6 +4636,35 @@ class ObjCObjectType : public Type {
|
||||
return qual_begin()[I];
|
||||
}
|
||||
|
||||
/// Retrieve all of the protocol qualifiers.
|
||||
ArrayRef<ObjCProtocolDecl *> getProtocols() const {
|
||||
return ArrayRef<ObjCProtocolDecl *>(qual_begin(), getNumProtocols());
|
||||
}
|
||||
|
||||
/// Whether this is a "__kindof" type as written.
|
||||
bool isKindOfTypeAsWritten() const { return ObjCObjectTypeBits.IsKindOf; }
|
||||
|
||||
/// Whether this ia a "__kindof" type (semantically).
|
||||
bool isKindOfType() const;
|
||||
|
||||
/// Retrieve the type of the superclass of this object type.
|
||||
///
|
||||
/// This operation substitutes any type arguments into the
|
||||
/// superclass of the current class type, potentially producing a
|
||||
/// specialization of the superclass type. Produces a null type if
|
||||
/// there is no superclass.
|
||||
QualType getSuperClassType() const {
|
||||
if (!CachedSuperClassType.getInt())
|
||||
computeSuperClassTypeSlow();
|
||||
|
||||
assert(CachedSuperClassType.getInt() && "Superclass not set?");
|
||||
return QualType(CachedSuperClassType.getPointer(), 0);
|
||||
}
|
||||
|
||||
/// Strip off the Objective-C "kindof" type and (with it) any
|
||||
/// protocol qualifiers.
|
||||
QualType stripObjCKindOfTypeAndQuals(const ASTContext &ctx) const;
|
||||
|
||||
bool isSugared() const { return false; }
|
||||
QualType desugar() const { return QualType(this, 0); }
|
||||
|
||||
@ -4491,21 +4685,27 @@ class ObjCObjectTypeImpl : public ObjCObjectType, public llvm::FoldingSetNode {
|
||||
// will need to be modified.
|
||||
|
||||
ObjCObjectTypeImpl(QualType Canonical, QualType Base,
|
||||
ObjCProtocolDecl * const *Protocols,
|
||||
unsigned NumProtocols)
|
||||
: ObjCObjectType(Canonical, Base, Protocols, NumProtocols) {}
|
||||
ArrayRef<QualType> typeArgs,
|
||||
ArrayRef<ObjCProtocolDecl *> protocols,
|
||||
bool isKindOf)
|
||||
: ObjCObjectType(Canonical, Base, typeArgs, protocols, isKindOf) {}
|
||||
|
||||
public:
|
||||
void Profile(llvm::FoldingSetNodeID &ID);
|
||||
static void Profile(llvm::FoldingSetNodeID &ID,
|
||||
QualType Base,
|
||||
ObjCProtocolDecl *const *protocols,
|
||||
unsigned NumProtocols);
|
||||
ArrayRef<QualType> typeArgs,
|
||||
ArrayRef<ObjCProtocolDecl *> protocols,
|
||||
bool isKindOf);
|
||||
};
|
||||
|
||||
inline QualType *ObjCObjectType::getTypeArgStorage() {
|
||||
return reinterpret_cast<QualType *>(static_cast<ObjCObjectTypeImpl*>(this)+1);
|
||||
}
|
||||
|
||||
inline ObjCProtocolDecl **ObjCObjectType::getProtocolStorage() {
|
||||
return reinterpret_cast<ObjCProtocolDecl**>(
|
||||
static_cast<ObjCObjectTypeImpl*>(this) + 1);
|
||||
return reinterpret_cast<ObjCProtocolDecl**>(
|
||||
getTypeArgStorage() + ObjCObjectTypeBits.NumTypeArgs);
|
||||
}
|
||||
|
||||
/// ObjCInterfaceType - Interfaces are the core concept in Objective-C for
|
||||
@ -4556,9 +4756,14 @@ class ObjCInterfaceType : public ObjCObjectType {
|
||||
};
|
||||
|
||||
inline ObjCInterfaceDecl *ObjCObjectType::getInterface() const {
|
||||
if (const ObjCInterfaceType *T =
|
||||
getBaseType()->getAs<ObjCInterfaceType>())
|
||||
return T->getDecl();
|
||||
QualType baseType = getBaseType();
|
||||
while (const ObjCObjectType *ObjT = baseType->getAs<ObjCObjectType>()) {
|
||||
if (const ObjCInterfaceType *T = dyn_cast<ObjCInterfaceType>(ObjT))
|
||||
return T->getDecl();
|
||||
|
||||
baseType = ObjT->getBaseType();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -4575,7 +4780,11 @@ class ObjCObjectPointerType : public Type, public llvm::FoldingSetNode {
|
||||
QualType PointeeType;
|
||||
|
||||
ObjCObjectPointerType(QualType Canonical, QualType Pointee)
|
||||
: Type(ObjCObjectPointer, Canonical, false, false, false, false),
|
||||
: Type(ObjCObjectPointer, Canonical,
|
||||
Pointee->isDependentType(),
|
||||
Pointee->isInstantiationDependentType(),
|
||||
Pointee->isVariablyModifiedType(),
|
||||
Pointee->containsUnexpandedParameterPack()),
|
||||
PointeeType(Pointee) {}
|
||||
friend class ASTContext; // ASTContext creates these.
|
||||
|
||||
@ -4617,9 +4826,7 @@ class ObjCObjectPointerType : public Type, public llvm::FoldingSetNode {
|
||||
/// qualifiers on the interface are ignored.
|
||||
///
|
||||
/// \return null if the base type for this pointer is 'id' or 'Class'
|
||||
const ObjCInterfaceType *getInterfaceType() const {
|
||||
return getObjectType()->getBaseType()->getAs<ObjCInterfaceType>();
|
||||
}
|
||||
const ObjCInterfaceType *getInterfaceType() const;
|
||||
|
||||
/// getInterfaceDecl - If this pointer points to an Objective \@interface
|
||||
/// type, gets the declaration for that interface.
|
||||
@ -4641,6 +4848,12 @@ class ObjCObjectPointerType : public Type, public llvm::FoldingSetNode {
|
||||
return getObjectType()->isObjCUnqualifiedClass();
|
||||
}
|
||||
|
||||
/// isObjCIdOrClassType - True if this is equivalent to the 'id' or
|
||||
/// 'Class' type,
|
||||
bool isObjCIdOrClassType() const {
|
||||
return getObjectType()->isObjCUnqualifiedIdOrClass();
|
||||
}
|
||||
|
||||
/// isObjCQualifiedIdType - True if this is equivalent to 'id<P>' for some
|
||||
/// non-empty set of protocols.
|
||||
bool isObjCQualifiedIdType() const {
|
||||
@ -4653,6 +4866,34 @@ class ObjCObjectPointerType : public Type, public llvm::FoldingSetNode {
|
||||
return getObjectType()->isObjCQualifiedClass();
|
||||
}
|
||||
|
||||
/// Whether this is a "__kindof" type.
|
||||
bool isKindOfType() const { return getObjectType()->isKindOfType(); }
|
||||
|
||||
/// Whether this type is specialized, meaning that it has type arguments.
|
||||
bool isSpecialized() const { return getObjectType()->isSpecialized(); }
|
||||
|
||||
/// Whether this type is specialized, meaning that it has type arguments.
|
||||
bool isSpecializedAsWritten() const {
|
||||
return getObjectType()->isSpecializedAsWritten();
|
||||
}
|
||||
|
||||
/// Whether this type is unspecialized, meaning that is has no type arguments.
|
||||
bool isUnspecialized() const { return getObjectType()->isUnspecialized(); }
|
||||
|
||||
/// Determine whether this object type is "unspecialized" as
|
||||
/// written, meaning that it has no type arguments.
|
||||
bool isUnspecializedAsWritten() const { return !isSpecializedAsWritten(); }
|
||||
|
||||
/// Retrieve the type arguments for this type.
|
||||
ArrayRef<QualType> getTypeArgs() const {
|
||||
return getObjectType()->getTypeArgs();
|
||||
}
|
||||
|
||||
/// Retrieve the type arguments for this type.
|
||||
ArrayRef<QualType> getTypeArgsAsWritten() const {
|
||||
return getObjectType()->getTypeArgsAsWritten();
|
||||
}
|
||||
|
||||
/// An iterator over the qualifiers on the object type. Provided
|
||||
/// for convenience. This will always iterate over the full set of
|
||||
/// protocols on a type, not just those provided directly.
|
||||
@ -4683,6 +4924,19 @@ class ObjCObjectPointerType : public Type, public llvm::FoldingSetNode {
|
||||
bool isSugared() const { return false; }
|
||||
QualType desugar() const { return QualType(this, 0); }
|
||||
|
||||
/// Retrieve the type of the superclass of this object pointer type.
|
||||
///
|
||||
/// This operation substitutes any type arguments into the
|
||||
/// superclass of the current class type, potentially producing a
|
||||
/// pointer to a specialization of the superclass type. Produces a
|
||||
/// null type if there is no superclass.
|
||||
QualType getSuperClassType() const;
|
||||
|
||||
/// Strip off the Objective-C "kindof" type and (with it) any
|
||||
/// protocol qualifiers.
|
||||
const ObjCObjectPointerType *stripObjCKindOfTypeAndQuals(
|
||||
const ASTContext &ctx) const;
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID) {
|
||||
Profile(ID, getPointeeType());
|
||||
}
|
||||
|
@ -177,6 +177,9 @@ class TypeLoc {
|
||||
memcpy(getOpaqueData(), Other.getOpaqueData(), Size);
|
||||
}
|
||||
|
||||
/// Copies the other type loc into this one.
|
||||
void copy(TypeLoc other);
|
||||
|
||||
friend bool operator==(const TypeLoc &LHS, const TypeLoc &RHS) {
|
||||
return LHS.Ty == RHS.Ty && LHS.Data == RHS.Data;
|
||||
}
|
||||
@ -185,6 +188,10 @@ class TypeLoc {
|
||||
return !(LHS == RHS);
|
||||
}
|
||||
|
||||
/// Find the location of the nullability specifier (__nonnull,
|
||||
/// __nullable, or __null_unspecifier), if there is one.
|
||||
SourceLocation findNullabilityLoc() const;
|
||||
|
||||
private:
|
||||
static bool isKind(const TypeLoc&) {
|
||||
return true;
|
||||
@ -249,6 +256,10 @@ class QualifiedTypeLoc : public TypeLoc {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
void copyLocal(TypeLoc other) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
TypeLoc getNextTypeLoc() const {
|
||||
return getUnqualifiedLoc();
|
||||
}
|
||||
@ -339,6 +350,20 @@ class ConcreteTypeLoc : public Base {
|
||||
return size;
|
||||
}
|
||||
|
||||
void copyLocal(Derived other) {
|
||||
// Some subclasses have no data to copy.
|
||||
if (asDerived()->getLocalDataSize() == 0) return;
|
||||
|
||||
// Copy the fixed-sized local data.
|
||||
memcpy(getLocalData(), other.getLocalData(), sizeof(LocalData));
|
||||
|
||||
// Copy the variable-sized local data. We need to do this
|
||||
// separately because the padding in the source and the padding in
|
||||
// the destination might be different.
|
||||
memcpy(getExtraLocalData(), other.getExtraLocalData(),
|
||||
asDerived()->getExtraLocalDataSize());
|
||||
}
|
||||
|
||||
TypeLoc getNextTypeLoc() const {
|
||||
return getNextTypeLoc(asDerived()->getInnerType());
|
||||
}
|
||||
@ -799,9 +824,11 @@ class AttributedTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
|
||||
};
|
||||
|
||||
|
||||
struct ObjCProtocolListLocInfo {
|
||||
SourceLocation LAngleLoc;
|
||||
SourceLocation RAngleLoc;
|
||||
struct ObjCObjectTypeLocInfo {
|
||||
SourceLocation TypeArgsLAngleLoc;
|
||||
SourceLocation TypeArgsRAngleLoc;
|
||||
SourceLocation ProtocolLAngleLoc;
|
||||
SourceLocation ProtocolRAngleLoc;
|
||||
bool HasBaseTypeAsWritten;
|
||||
};
|
||||
|
||||
@ -813,25 +840,59 @@ struct ObjCProtocolListLocInfo {
|
||||
class ObjCObjectTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
|
||||
ObjCObjectTypeLoc,
|
||||
ObjCObjectType,
|
||||
ObjCProtocolListLocInfo> {
|
||||
// SourceLocations are stored after Info, one for each Protocol.
|
||||
ObjCObjectTypeLocInfo> {
|
||||
// TypeSourceInfo*'s are stored after Info, one for each type argument.
|
||||
TypeSourceInfo **getTypeArgLocArray() const {
|
||||
return (TypeSourceInfo**)this->getExtraLocalData();
|
||||
}
|
||||
|
||||
// SourceLocations are stored after the type argument information, one for
|
||||
// each Protocol.
|
||||
SourceLocation *getProtocolLocArray() const {
|
||||
return (SourceLocation*) this->getExtraLocalData();
|
||||
return (SourceLocation*)(getTypeArgLocArray() + getNumTypeArgs());
|
||||
}
|
||||
|
||||
public:
|
||||
SourceLocation getLAngleLoc() const {
|
||||
return this->getLocalData()->LAngleLoc;
|
||||
SourceLocation getTypeArgsLAngleLoc() const {
|
||||
return this->getLocalData()->TypeArgsLAngleLoc;
|
||||
}
|
||||
void setLAngleLoc(SourceLocation Loc) {
|
||||
this->getLocalData()->LAngleLoc = Loc;
|
||||
void setTypeArgsLAngleLoc(SourceLocation Loc) {
|
||||
this->getLocalData()->TypeArgsLAngleLoc = Loc;
|
||||
}
|
||||
|
||||
SourceLocation getRAngleLoc() const {
|
||||
return this->getLocalData()->RAngleLoc;
|
||||
SourceLocation getTypeArgsRAngleLoc() const {
|
||||
return this->getLocalData()->TypeArgsRAngleLoc;
|
||||
}
|
||||
void setRAngleLoc(SourceLocation Loc) {
|
||||
this->getLocalData()->RAngleLoc = Loc;
|
||||
void setTypeArgsRAngleLoc(SourceLocation Loc) {
|
||||
this->getLocalData()->TypeArgsRAngleLoc = Loc;
|
||||
}
|
||||
|
||||
unsigned getNumTypeArgs() const {
|
||||
return this->getTypePtr()->getTypeArgsAsWritten().size();
|
||||
}
|
||||
|
||||
TypeSourceInfo *getTypeArgTInfo(unsigned i) const {
|
||||
assert(i < getNumTypeArgs() && "Index is out of bounds!");
|
||||
return getTypeArgLocArray()[i];
|
||||
}
|
||||
|
||||
void setTypeArgTInfo(unsigned i, TypeSourceInfo *TInfo) {
|
||||
assert(i < getNumTypeArgs() && "Index is out of bounds!");
|
||||
getTypeArgLocArray()[i] = TInfo;
|
||||
}
|
||||
|
||||
SourceLocation getProtocolLAngleLoc() const {
|
||||
return this->getLocalData()->ProtocolLAngleLoc;
|
||||
}
|
||||
void setProtocolLAngleLoc(SourceLocation Loc) {
|
||||
this->getLocalData()->ProtocolLAngleLoc = Loc;
|
||||
}
|
||||
|
||||
SourceLocation getProtocolRAngleLoc() const {
|
||||
return this->getLocalData()->ProtocolRAngleLoc;
|
||||
}
|
||||
void setProtocolRAngleLoc(SourceLocation Loc) {
|
||||
this->getLocalData()->ProtocolRAngleLoc = Loc;
|
||||
}
|
||||
|
||||
unsigned getNumProtocols() const {
|
||||
@ -852,6 +913,11 @@ class ObjCObjectTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
|
||||
return *(this->getTypePtr()->qual_begin() + i);
|
||||
}
|
||||
|
||||
|
||||
ArrayRef<SourceLocation> getProtocolLocs() const {
|
||||
return llvm::makeArrayRef(getProtocolLocArray(), getNumProtocols());
|
||||
}
|
||||
|
||||
bool hasBaseTypeAsWritten() const {
|
||||
return getLocalData()->HasBaseTypeAsWritten;
|
||||
}
|
||||
@ -865,23 +931,27 @@ class ObjCObjectTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
|
||||
}
|
||||
|
||||
SourceRange getLocalSourceRange() const {
|
||||
return SourceRange(getLAngleLoc(), getRAngleLoc());
|
||||
SourceLocation start = getTypeArgsLAngleLoc();
|
||||
if (start.isInvalid())
|
||||
start = getProtocolLAngleLoc();
|
||||
SourceLocation end = getProtocolRAngleLoc();
|
||||
if (end.isInvalid())
|
||||
end = getTypeArgsRAngleLoc();
|
||||
return SourceRange(start, end);
|
||||
}
|
||||
|
||||
void initializeLocal(ASTContext &Context, SourceLocation Loc) {
|
||||
setHasBaseTypeAsWritten(true);
|
||||
setLAngleLoc(Loc);
|
||||
setRAngleLoc(Loc);
|
||||
for (unsigned i = 0, e = getNumProtocols(); i != e; ++i)
|
||||
setProtocolLoc(i, Loc);
|
||||
}
|
||||
void initializeLocal(ASTContext &Context, SourceLocation Loc);
|
||||
|
||||
unsigned getExtraLocalDataSize() const {
|
||||
return this->getNumProtocols() * sizeof(SourceLocation);
|
||||
return this->getNumTypeArgs() * sizeof(TypeSourceInfo *)
|
||||
+ this->getNumProtocols() * sizeof(SourceLocation);
|
||||
}
|
||||
|
||||
unsigned getExtraLocalDataAlignment() const {
|
||||
return llvm::alignOf<SourceLocation>();
|
||||
assert(llvm::alignOf<ObjCObjectTypeLoc>()
|
||||
>= llvm::alignOf<TypeSourceInfo *>() &&
|
||||
"not enough alignment for tail-allocated data");
|
||||
return llvm::alignOf<TypeSourceInfo *>();
|
||||
}
|
||||
|
||||
QualType getInnerType() const {
|
||||
|
@ -112,7 +112,7 @@ class BoundNodes {
|
||||
///
|
||||
/// FIXME: Do we want to support this now that we have bind()?
|
||||
template <typename T>
|
||||
internal::Matcher<T> id(const std::string &ID,
|
||||
internal::Matcher<T> id(StringRef ID,
|
||||
const internal::BindableMatcher<T> &InnerMatcher) {
|
||||
return InnerMatcher.bind(ID);
|
||||
}
|
||||
|
@ -140,8 +140,7 @@ class BoundNodesTreeBuilder {
|
||||
};
|
||||
|
||||
/// \brief Add a binding from an id to a node.
|
||||
void setBinding(const std::string &Id,
|
||||
const ast_type_traits::DynTypedNode &DynNode) {
|
||||
void setBinding(StringRef Id, const ast_type_traits::DynTypedNode &DynNode) {
|
||||
if (Bindings.empty())
|
||||
Bindings.emplace_back();
|
||||
for (BoundNodesMap &Binding : Bindings)
|
||||
|
@ -242,7 +242,7 @@ struct VariantMatcher::TypedMatcherOps final : VariantMatcher::MatcherOps {
|
||||
///
|
||||
/// Supported types:
|
||||
/// - \c unsigned
|
||||
/// - \c std::string
|
||||
/// - \c llvm::StringRef
|
||||
/// - \c VariantMatcher (\c DynTypedMatcher / \c Matcher<T>)
|
||||
class VariantValue {
|
||||
public:
|
||||
@ -254,7 +254,7 @@ class VariantValue {
|
||||
|
||||
/// \brief Specific constructors for each supported type.
|
||||
VariantValue(unsigned Unsigned);
|
||||
VariantValue(const std::string &String);
|
||||
VariantValue(StringRef String);
|
||||
VariantValue(const VariantMatcher &Matchers);
|
||||
|
||||
/// \brief Returns true iff this is not an empty value.
|
||||
@ -269,7 +269,7 @@ class VariantValue {
|
||||
/// \brief String value functions.
|
||||
bool isString() const;
|
||||
const std::string &getString() const;
|
||||
void setString(const std::string &String);
|
||||
void setString(StringRef String);
|
||||
|
||||
/// \brief Matcher value functions.
|
||||
bool isMatcher() const;
|
||||
|
@ -976,6 +976,11 @@ def TypeNullUnspecified : TypeAttr {
|
||||
let Documentation = [TypeNullUnspecifiedDocs];
|
||||
}
|
||||
|
||||
def ObjCKindOf : TypeAttr {
|
||||
let Spellings = [Keyword<"__kindof">];
|
||||
let Documentation = [Undocumented];
|
||||
}
|
||||
|
||||
def AssumeAligned : InheritableAttr {
|
||||
let Spellings = [GCC<"assume_aligned">];
|
||||
let Subjects = SubjectList<[ObjCMethod, Function]>;
|
||||
@ -1276,9 +1281,8 @@ def Pascal : InheritableAttr {
|
||||
def Target : InheritableAttr {
|
||||
let Spellings = [GCC<"target">];
|
||||
let Args = [StringArgument<"features">];
|
||||
let Subjects =
|
||||
SubjectList<[Function], ErrorDiag, "ExpectedFunctionMethodOrClass">;
|
||||
let Documentation = [Undocumented];
|
||||
let Subjects = SubjectList<[Function], ErrorDiag>;
|
||||
let Documentation = [TargetDocs];
|
||||
}
|
||||
|
||||
def TransparentUnion : InheritableAttr {
|
||||
|
@ -678,6 +678,25 @@ The semantics are as follows:
|
||||
}];
|
||||
}
|
||||
|
||||
def TargetDocs : Documentation {
|
||||
let Category = DocCatFunction;
|
||||
let Content = [{
|
||||
Clang supports the GNU style ``__attribute__((target("OPTIONS")))`` attribute.
|
||||
This attribute may be attached to a function definition and instructs
|
||||
the backend to use different code generation options than were passed on the
|
||||
command line.
|
||||
|
||||
The current set of options correspond to the existing "subtarget features" for
|
||||
the target with or without a "-mno-" in front corresponding to the absence
|
||||
of the feature, as well as ``arch="CPU"`` which will change the default "CPU"
|
||||
for the function.
|
||||
|
||||
Example "subtarget features" from the x86 backend include: "mmx", "sse", "sse4.2",
|
||||
"avx", "xop" and largely correspond to the machine specific options handled by
|
||||
the front end.
|
||||
}];
|
||||
}
|
||||
|
||||
def DocCatAMDGPURegisterAttributes :
|
||||
DocumentationCategory<"AMD GPU Register Attributes"> {
|
||||
let Content = [{
|
||||
|
@ -248,6 +248,11 @@ BUILTIN(__builtin_altivec_crypto_vpmsumh, "V8UsV8UsV8Us", "")
|
||||
BUILTIN(__builtin_altivec_crypto_vpmsumw, "V4UiV4UiV4Ui", "")
|
||||
BUILTIN(__builtin_altivec_crypto_vpmsumd, "V2ULLiV2ULLiV2ULLi", "")
|
||||
|
||||
BUILTIN(__builtin_altivec_vclzb, "V16UcV16Uc", "")
|
||||
BUILTIN(__builtin_altivec_vclzh, "V8UsV8Us", "")
|
||||
BUILTIN(__builtin_altivec_vclzw, "V4UiV4Ui", "")
|
||||
BUILTIN(__builtin_altivec_vclzd, "V2ULLiV2ULLi", "")
|
||||
|
||||
// VSX built-ins.
|
||||
|
||||
BUILTIN(__builtin_vsx_lxvd2x, "V2divC*", "")
|
||||
@ -279,6 +284,47 @@ BUILTIN(__builtin_vsx_xvcmpgesp, "V4UiV4fV4f", "")
|
||||
BUILTIN(__builtin_vsx_xvcmpgtdp, "V2ULLiV2dV2d", "")
|
||||
BUILTIN(__builtin_vsx_xvcmpgtsp, "V4UiV4fV4f", "")
|
||||
|
||||
BUILTIN(__builtin_vsx_xvrdpim, "V2dV2d", "")
|
||||
BUILTIN(__builtin_vsx_xvrspim, "V4fV4f", "")
|
||||
|
||||
BUILTIN(__builtin_vsx_xvrdpi, "V2dV2d", "")
|
||||
BUILTIN(__builtin_vsx_xvrspi, "V4fV4f", "")
|
||||
|
||||
BUILTIN(__builtin_vsx_xvrdpic, "V2dV2d", "")
|
||||
BUILTIN(__builtin_vsx_xvrspic, "V4fV4f", "")
|
||||
|
||||
BUILTIN(__builtin_vsx_xvrdpiz, "V2dV2d", "")
|
||||
BUILTIN(__builtin_vsx_xvrspiz, "V4fV4f", "")
|
||||
|
||||
BUILTIN(__builtin_vsx_xvmaddadp, "V2dV2dV2dV2d", "")
|
||||
BUILTIN(__builtin_vsx_xvmaddasp, "V4fV4fV4fV4f", "")
|
||||
|
||||
BUILTIN(__builtin_vsx_xvmsubadp, "V2dV2dV2dV2d", "")
|
||||
BUILTIN(__builtin_vsx_xvmsubasp, "V4fV4fV4fV4f", "")
|
||||
|
||||
BUILTIN(__builtin_vsx_xvmuldp, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_vsx_xvmulsp, "V4fV4fV4f", "")
|
||||
|
||||
BUILTIN(__builtin_vsx_xvnmaddadp, "V2dV2dV2dV2d", "")
|
||||
BUILTIN(__builtin_vsx_xvnmaddasp, "V4fV4fV4fV4f", "")
|
||||
|
||||
BUILTIN(__builtin_vsx_xvnmsubadp, "V2dV2dV2dV2d", "")
|
||||
BUILTIN(__builtin_vsx_xvnmsubasp, "V4fV4fV4fV4f", "")
|
||||
|
||||
BUILTIN(__builtin_vsx_xvredp, "V2dV2d", "")
|
||||
BUILTIN(__builtin_vsx_xvresp, "V4fV4f", "")
|
||||
|
||||
BUILTIN(__builtin_vsx_xvrsqrtedp, "V2dV2d", "")
|
||||
BUILTIN(__builtin_vsx_xvrsqrtesp, "V4fV4f", "")
|
||||
|
||||
BUILTIN(__builtin_vsx_xvsqrtdp, "V2dV2d", "")
|
||||
BUILTIN(__builtin_vsx_xvsqrtsp, "V4fV4f", "")
|
||||
|
||||
BUILTIN(__builtin_vsx_xxleqv, "V4UiV4UiV4Ui", "")
|
||||
|
||||
BUILTIN(__builtin_vsx_xvcpsgndp, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_vsx_xvcpsgnsp, "V4fV4fV4f", "")
|
||||
|
||||
// HTM builtins
|
||||
BUILTIN(__builtin_tbegin, "UiUIi", "")
|
||||
BUILTIN(__builtin_tend, "UiUIi", "")
|
||||
|
@ -1157,5 +1157,65 @@ BUILTIN(__builtin_ia32_vpconflictdi_512_mask, "V8LLiV8LLiV8LLiUc", "")
|
||||
BUILTIN(__builtin_ia32_vpconflictsi_512_mask, "V16iV16iV16iUs", "")
|
||||
BUILTIN(__builtin_ia32_vplzcntd_512_mask, "V16iV16iV16iUs", "")
|
||||
BUILTIN(__builtin_ia32_vplzcntq_512_mask, "V8LLiV8LLiV8LLiUc", "")
|
||||
BUILTIN(__builtin_ia32_blendmb_128_mask, "V16cV16cV16cUs", "")
|
||||
BUILTIN(__builtin_ia32_blendmb_256_mask, "V32cV32cV32cUi", "")
|
||||
BUILTIN(__builtin_ia32_blendmw_128_mask, "V8sV8sV8sUc", "")
|
||||
BUILTIN(__builtin_ia32_blendmw_256_mask, "V16sV16sV16sUs", "")
|
||||
BUILTIN(__builtin_ia32_pabsb128_mask, "V16cV16cV16cUs", "")
|
||||
BUILTIN(__builtin_ia32_pabsb256_mask, "V32cV32cV32cUi", "")
|
||||
BUILTIN(__builtin_ia32_pabsw128_mask, "V8sV8sV8sUc", "")
|
||||
BUILTIN(__builtin_ia32_pabsw256_mask, "V16sV16sV16sUs", "")
|
||||
BUILTIN(__builtin_ia32_packssdw128_mask, "V8sV4iV4iV8sUc", "")
|
||||
BUILTIN(__builtin_ia32_packssdw256_mask, "V16sV8iV8iV16sUs", "")
|
||||
BUILTIN(__builtin_ia32_packsswb128_mask, "V16cV8sV8sV16cUs", "")
|
||||
BUILTIN(__builtin_ia32_packsswb256_mask, "V32cV16sV16sV32cUi", "")
|
||||
BUILTIN(__builtin_ia32_packusdw128_mask, "V8sV4iV4iV8sUc", "")
|
||||
BUILTIN(__builtin_ia32_packusdw256_mask, "V16sV8iV8iV16sUs", "")
|
||||
BUILTIN(__builtin_ia32_packuswb128_mask, "V16cV8sV8sV16cUs", "")
|
||||
BUILTIN(__builtin_ia32_packuswb256_mask, "V32cV16sV16sV32cUi", "")
|
||||
BUILTIN(__builtin_ia32_paddsb128_mask, "V16cV16cV16cV16cUs", "")
|
||||
BUILTIN(__builtin_ia32_paddsb256_mask, "V32cV32cV32cV32cUi", "")
|
||||
BUILTIN(__builtin_ia32_paddsw128_mask, "V8sV8sV8sV8sUc", "")
|
||||
BUILTIN(__builtin_ia32_paddsw256_mask, "V16sV16sV16sV16sUs", "")
|
||||
BUILTIN(__builtin_ia32_paddusb128_mask, "V16cV16cV16cV16cUs", "")
|
||||
BUILTIN(__builtin_ia32_paddusb256_mask, "V32cV32cV32cV32cUi", "")
|
||||
BUILTIN(__builtin_ia32_paddusw128_mask, "V8sV8sV8sV8sUc", "")
|
||||
BUILTIN(__builtin_ia32_paddusw256_mask, "V16sV16sV16sV16sUs", "")
|
||||
BUILTIN(__builtin_ia32_pavgb128_mask, "V16cV16cV16cV16cUs", "")
|
||||
BUILTIN(__builtin_ia32_pavgb256_mask, "V32cV32cV32cV32cUi", "")
|
||||
BUILTIN(__builtin_ia32_pavgw128_mask, "V8sV8sV8sV8sUc", "")
|
||||
BUILTIN(__builtin_ia32_pavgw256_mask, "V16sV16sV16sV16sUs", "")
|
||||
BUILTIN(__builtin_ia32_pmaxsb128_mask, "V16cV16cV16cV16cUs", "")
|
||||
BUILTIN(__builtin_ia32_pmaxsb256_mask, "V32cV32cV32cV32cUi", "")
|
||||
BUILTIN(__builtin_ia32_pmaxsw128_mask, "V8sV8sV8sV8sUc", "")
|
||||
BUILTIN(__builtin_ia32_pmaxsw256_mask, "V16sV16sV16sV16sUs", "")
|
||||
BUILTIN(__builtin_ia32_pmaxub128_mask, "V16cV16cV16cV16cUs", "")
|
||||
BUILTIN(__builtin_ia32_pmaxub256_mask, "V32cV32cV32cV32cUi", "")
|
||||
BUILTIN(__builtin_ia32_pmaxuw128_mask, "V8sV8sV8sV8sUc", "")
|
||||
BUILTIN(__builtin_ia32_pmaxuw256_mask, "V16sV16sV16sV16sUs", "")
|
||||
BUILTIN(__builtin_ia32_pminsb128_mask, "V16cV16cV16cV16cUs", "")
|
||||
BUILTIN(__builtin_ia32_pminsb256_mask, "V32cV32cV32cV32cUi", "")
|
||||
BUILTIN(__builtin_ia32_pminsw128_mask, "V8sV8sV8sV8sUc", "")
|
||||
BUILTIN(__builtin_ia32_pminsw256_mask, "V16sV16sV16sV16sUs", "")
|
||||
BUILTIN(__builtin_ia32_pminub128_mask, "V16cV16cV16cV16cUs", "")
|
||||
BUILTIN(__builtin_ia32_pminub256_mask, "V32cV32cV32cV32cUi", "")
|
||||
BUILTIN(__builtin_ia32_pminuw128_mask, "V8sV8sV8sV8sUc", "")
|
||||
BUILTIN(__builtin_ia32_pminuw256_mask, "V16sV16sV16sV16sUs", "")
|
||||
BUILTIN(__builtin_ia32_pshufb128_mask, "V16cV16cV16cV16cUs", "")
|
||||
BUILTIN(__builtin_ia32_pshufb256_mask, "V32cV32cV32cV32cUi", "")
|
||||
BUILTIN(__builtin_ia32_psubsb128_mask, "V16cV16cV16cV16cUs", "")
|
||||
BUILTIN(__builtin_ia32_psubsb256_mask, "V32cV32cV32cV32cUi", "")
|
||||
BUILTIN(__builtin_ia32_psubsw128_mask, "V8sV8sV8sV8sUc", "")
|
||||
BUILTIN(__builtin_ia32_psubsw256_mask, "V16sV16sV16sV16sUs", "")
|
||||
BUILTIN(__builtin_ia32_psubusb128_mask, "V16cV16cV16cV16cUs", "")
|
||||
BUILTIN(__builtin_ia32_psubusb256_mask, "V32cV32cV32cV32cUi", "")
|
||||
BUILTIN(__builtin_ia32_psubusw128_mask, "V8sV8sV8sV8sUc", "")
|
||||
BUILTIN(__builtin_ia32_psubusw256_mask, "V16sV16sV16sV16sUs", "")
|
||||
BUILTIN(__builtin_ia32_vpermi2varhi128_mask, "V8sV8sV8sV8sUc", "")
|
||||
BUILTIN(__builtin_ia32_vpermi2varhi256_mask, "V16sV16sV16sV16sUs", "")
|
||||
BUILTIN(__builtin_ia32_vpermt2varhi128_mask, "V8sV8sV8sV8sUc", "")
|
||||
BUILTIN(__builtin_ia32_vpermt2varhi128_maskz, "V8sV8sV8sV8sUc", "")
|
||||
BUILTIN(__builtin_ia32_vpermt2varhi256_mask, "V16sV16sV16sV16sUs", "")
|
||||
BUILTIN(__builtin_ia32_vpermt2varhi256_maskz, "V16sV16sV16sV16sUs", "")
|
||||
|
||||
#undef BUILTIN
|
||||
|
@ -21,6 +21,7 @@ def Named : Decl<1>;
|
||||
def TypedefName : DDecl<Type, 1>;
|
||||
def Typedef : DDecl<TypedefName>;
|
||||
def TypeAlias : DDecl<TypedefName>;
|
||||
def ObjCTypeParam : DDecl<TypedefName>;
|
||||
def UnresolvedUsingTypename : DDecl<Type>;
|
||||
def Tag : DDecl<Type, 1>, DeclContext;
|
||||
def Enum : DDecl<Tag>;
|
||||
|
@ -179,6 +179,8 @@ def err_target_unsupported_fpmath : Error<
|
||||
"the '%0' unit is not supported with this instruction set">;
|
||||
def err_target_unsupported_unaligned : Error<
|
||||
"the %0 sub-architecture does not support unaligned accesses">;
|
||||
def err_opt_not_valid_with_opt : Error<
|
||||
"option '%0' cannot be specified with '%1'">;
|
||||
|
||||
// Source manager
|
||||
def err_cannot_open_file : Error<"cannot open file '%0': %1">, DefaultFatal;
|
||||
|
@ -69,8 +69,6 @@ def err_drv_no_module_support : Error<
|
||||
"'%0': unable to use module files with this tool">;
|
||||
def err_drv_clang_unsupported : Error<
|
||||
"the clang compiler does not support '%0'">;
|
||||
def err_drv_clang_unsupported_per_platform : Error<
|
||||
"the clang compiler does not support '%0' on this platform">;
|
||||
def err_drv_clang_unsupported_opt_cxx_darwin_i386 : Error<
|
||||
"the clang compiler does not support '%0' for C++ on Darwin/i386">;
|
||||
def err_drv_command_failed : Error<
|
||||
|
@ -280,6 +280,7 @@ def FunctionDefInObjCContainer : DiagGroup<"function-def-in-objc-container">;
|
||||
def BadFunctionCast : DiagGroup<"bad-function-cast">;
|
||||
def ObjCPropertyImpl : DiagGroup<"objc-property-implementation">;
|
||||
def ObjCPropertyNoAttribute : DiagGroup<"objc-property-no-attribute">;
|
||||
def ObjCProtocolQualifiers : DiagGroup<"objc-protocol-qualifiers">;
|
||||
def ObjCMissingSuperCalls : DiagGroup<"objc-missing-super-calls">;
|
||||
def ObjCDesignatedInit : DiagGroup<"objc-designated-initializers">;
|
||||
def ObjCRetainBlockProperty : DiagGroup<"objc-noncopy-retain-block-property">;
|
||||
|
@ -1004,10 +1004,6 @@ def err_pragma_invalid_keyword : Error<
|
||||
def warn_pragma_unroll_cuda_value_in_parens : Warning<
|
||||
"argument to '#pragma unroll' should not be in parentheses in CUDA C/C++">,
|
||||
InGroup<CudaCompat>;
|
||||
|
||||
def err_empty_attribute_block : Error<
|
||||
"Microsoft attribute block cannot be empty">;
|
||||
|
||||
} // end of Parse Issue category.
|
||||
|
||||
let CategoryName = "Modules Issue" in {
|
||||
@ -1017,4 +1013,16 @@ def err_module_expected_semi : Error<
|
||||
"expected ';' after module name">;
|
||||
}
|
||||
|
||||
let CategoryName = "Generics Issue" in {
|
||||
|
||||
def err_objc_expected_type_parameter : Error<
|
||||
"expected type parameter name">;
|
||||
|
||||
def err_objc_parameterized_implementation : Error<
|
||||
"@implementation cannot have type parameters">;
|
||||
|
||||
def err_objc_type_args_after_protocols : Error<
|
||||
"protocol qualifiers must precede type arguments">;
|
||||
}
|
||||
|
||||
} // end of Parser diagnostics
|
||||
|
@ -188,6 +188,8 @@ def ext_flexible_array_init : Extension<
|
||||
"flexible array initialization is a GNU extension">, InGroup<GNUFlexibleArrayInitializer>;
|
||||
|
||||
// Declarations.
|
||||
def err_redeclaration_different_type : Error<
|
||||
"redeclaration of %0 with a different type%diff{: $ vs $|}1,2">;
|
||||
def err_bad_variable_name : Error<
|
||||
"%0 cannot be the name of a variable or data member">;
|
||||
def err_bad_parameter_name : Error<
|
||||
@ -978,6 +980,12 @@ def warning_multiple_selectors: Warning<
|
||||
"several methods with selector %0 of mismatched types are found "
|
||||
"for the @selector expression">,
|
||||
InGroup<SelectorTypeMismatch>, DefaultIgnore;
|
||||
|
||||
def err_objc_kindof_nonobject : Error<
|
||||
"'__kindof' specifier cannot be applied to non-object type %0">;
|
||||
def err_objc_kindof_wrong_position : Error<
|
||||
"'__kindof' type specifier must precede the declarator">;
|
||||
|
||||
// C++ declarations
|
||||
def err_static_assert_expression_is_not_constant : Error<
|
||||
"static_assert expression is not an integral constant expression">;
|
||||
@ -2131,6 +2139,11 @@ def warn_concatenated_nsarray_literal : Warning<
|
||||
InGroup<ObjCStringConcatenation>;
|
||||
def note_objc_literal_comparison_isequal : Note<
|
||||
"use 'isEqual:' instead">;
|
||||
def warn_objc_collection_literal_element : Warning<
|
||||
"object of type %0 is not compatible with "
|
||||
"%select{array element type|dictionary key type|dictionary value type}1 %2">,
|
||||
InGroup<ObjCLiteralConversion>;
|
||||
|
||||
def err_attribute_argument_is_zero : Error<
|
||||
"%0 attribute must be greater than 0">;
|
||||
def warn_attribute_argument_n_negative : Warning<
|
||||
@ -2148,6 +2161,10 @@ def warn_objc_redundant_literal_use : Warning<
|
||||
def err_attr_tlsmodel_arg : Error<"tls_model must be \"global-dynamic\", "
|
||||
"\"local-dynamic\", \"initial-exec\" or \"local-exec\"">;
|
||||
|
||||
def err_tls_var_aligned_over_maximum : Error<
|
||||
"alignment (%0) of thread-local variable %1 is greater than the maximum supported "
|
||||
"alignment (%2) for a thread-local variable on this target">;
|
||||
|
||||
def err_only_annotate_after_access_spec : Error<
|
||||
"access specifier can only have annotation attributes">;
|
||||
|
||||
@ -4740,6 +4757,8 @@ def warn_division_by_zero : Warning<"division by zero is undefined">,
|
||||
InGroup<DivZero>;
|
||||
def warn_remainder_by_zero : Warning<"remainder by zero is undefined">,
|
||||
InGroup<DivZero>;
|
||||
def warn_shift_lhs_negative : Warning<"shifting a negative signed value is undefined">,
|
||||
InGroup<DiagGroup<"shift-negative-value">>;
|
||||
def warn_shift_negative : Warning<"shift count is negative">,
|
||||
InGroup<DiagGroup<"shift-count-negative">>;
|
||||
def warn_shift_gt_typewidth : Warning<"shift count >= width of type">,
|
||||
@ -5576,6 +5595,8 @@ def err_seh_try_outside_functions : Error<
|
||||
"cannot use SEH '__try' in blocks, captured regions, or Obj-C method decls">;
|
||||
def err_mixing_cxx_try_seh_try : Error<
|
||||
"cannot use C++ 'try' in the same function as SEH '__try'">;
|
||||
def err_seh_try_unsupported : Error<
|
||||
"SEH '__try' is not supported on this target">;
|
||||
def note_conflicting_try_here : Note<
|
||||
"conflicting %0 here">;
|
||||
def warn_jump_out_of_seh_finally : Warning<
|
||||
@ -7740,6 +7761,84 @@ def warn_nullability_missing : Warning<
|
||||
"type specifier (_Nonnull, _Nullable, or _Null_unspecified)">,
|
||||
InGroup<NullabilityCompleteness>;
|
||||
|
||||
def err_type_arg_explicit_nullability : Error<
|
||||
"type argument %0 cannot explicitly specify nullability">;
|
||||
|
||||
def err_type_param_bound_explicit_nullability : Error<
|
||||
"type parameter %0 bound %1 cannot explicitly specify nullability">;
|
||||
|
||||
}
|
||||
|
||||
let CategoryName = "Generics Issue" in {
|
||||
|
||||
def err_objc_type_param_bound_nonobject : Error<
|
||||
"type bound %0 for type parameter %1 is not an Objective-C pointer type">;
|
||||
|
||||
def err_objc_type_param_bound_missing_pointer : Error<
|
||||
"missing '*' in type bound %0 for type parameter %1">;
|
||||
|
||||
def err_objc_type_param_redecl : Error<
|
||||
"redeclaration of type parameter %0">;
|
||||
|
||||
def err_objc_type_param_arity_mismatch : Error<
|
||||
"%select{forward class declaration|class definition|category|extension}0 has "
|
||||
"too %select{few|many}1 type parameters (expected %2, have %3)">;
|
||||
|
||||
def err_objc_type_param_bound_conflict : Error<
|
||||
"type bound %0 for type parameter %1 conflicts with "
|
||||
"%select{implicit|previous}2 bound %3%select{for type parameter %5|}4">;
|
||||
|
||||
def err_objc_type_param_variance_conflict : Error<
|
||||
"%select{in|co|contra}0variant type parameter %1 conflicts with previous "
|
||||
"%select{in|co|contra}2variant type parameter %3">;
|
||||
|
||||
def note_objc_type_param_here : Note<"type parameter %0 declared here">;
|
||||
|
||||
def err_objc_type_param_bound_missing : Error<
|
||||
"missing type bound %0 for type parameter %1 in %select{@interface|@class}2">;
|
||||
|
||||
def err_objc_parameterized_category_nonclass : Error<
|
||||
"%select{extension|category}0 of non-parameterized class %1 cannot have type "
|
||||
"parameters">;
|
||||
|
||||
def err_objc_parameterized_forward_class : Error<
|
||||
"forward declaration of non-parameterized class %0 cannot have type "
|
||||
"parameters">;
|
||||
|
||||
def err_objc_parameterized_forward_class_first : Error<
|
||||
"class %0 previously declared with type parameters">;
|
||||
|
||||
def err_objc_type_arg_missing_star : Error<
|
||||
"type argument %0 must be a pointer (requires a '*')">;
|
||||
|
||||
def err_objc_type_arg_missing : Error<
|
||||
"no type or protocol named %0">;
|
||||
|
||||
def err_objc_type_args_and_protocols : Error<
|
||||
"angle brackets contain both a %select{type|protocol}0 (%1) and a "
|
||||
"%select{protocol|type}0 (%2)">;
|
||||
|
||||
def err_objc_type_args_non_class : Error<
|
||||
"type arguments cannot be applied to non-class type %0">;
|
||||
|
||||
def err_objc_type_args_non_parameterized_class : Error<
|
||||
"type arguments cannot be applied to non-parameterized class %0">;
|
||||
|
||||
def err_objc_type_args_specialized_class : Error<
|
||||
"type arguments cannot be applied to already-specialized class type %0">;
|
||||
|
||||
def err_objc_type_args_wrong_arity : Error<
|
||||
"too %select{many|few}0 type arguments for class %1 (have %2, expected %3)">;
|
||||
}
|
||||
|
||||
def err_objc_type_arg_not_id_compatible : Error<
|
||||
"type argument %0 is neither an Objective-C object nor a block type">;
|
||||
|
||||
def err_objc_type_arg_does_not_match_bound : Error<
|
||||
"type argument %0 does not satisfy the bound (%1) of type parameter %2">;
|
||||
|
||||
def warn_objc_redundant_qualified_class_type : Warning<
|
||||
"parameterized class %0 already conforms to the protocols listed; did you "
|
||||
"forget a '*'?">, InGroup<ObjCProtocolQualifiers>;
|
||||
|
||||
} // end of sema component.
|
||||
|
@ -49,7 +49,7 @@ class IdentifierInfo {
|
||||
// Objective-C keyword ('protocol' in '@protocol') or builtin (__builtin_inf).
|
||||
// First NUM_OBJC_KEYWORDS values are for Objective-C, the remaining values
|
||||
// are for builtins.
|
||||
unsigned ObjCOrBuiltinID :11;
|
||||
unsigned ObjCOrBuiltinID :13;
|
||||
bool HasMacro : 1; // True if there is a #define for this.
|
||||
bool HadMacro : 1; // True if there was a #define for this.
|
||||
bool IsExtension : 1; // True if identifier is a lang extension.
|
||||
@ -69,7 +69,7 @@ class IdentifierInfo {
|
||||
// stored externally.
|
||||
bool IsModulesImport : 1; // True if this is the 'import' contextual
|
||||
// keyword.
|
||||
// 32-bit word is filled.
|
||||
// 30 bit left in 64-bit word.
|
||||
|
||||
void *FETokenInfo; // Managed by the language front-end.
|
||||
llvm::StringMapEntry<IdentifierInfo*> *Entry;
|
||||
|
@ -161,6 +161,7 @@ LANGOPT(NativeHalfType , 1, 0, "Native half type support")
|
||||
LANGOPT(HalfArgsAndReturns, 1, 0, "half args and returns")
|
||||
LANGOPT(CUDA , 1, 0, "CUDA")
|
||||
LANGOPT(OpenMP , 1, 0, "OpenMP support")
|
||||
LANGOPT(OpenMPUseTLS , 1, 0, "Use TLS for threadprivates or runtime calls")
|
||||
LANGOPT(CUDAIsDevice , 1, 0, "Compiling for CUDA device")
|
||||
LANGOPT(CUDAAllowHostCallsFromHostDevice, 1, 0, "Allow host device functions to call host functions")
|
||||
LANGOPT(CUDADisableTargetCallChecks, 1, 0, "Disable checks for call targets (host, device, etc.)")
|
||||
|
@ -17,8 +17,7 @@
|
||||
|
||||
#include "clang/Basic/LLVM.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
@ -47,22 +46,28 @@ enum SanitizerOrdinal : uint64_t {
|
||||
}
|
||||
|
||||
struct SanitizerSet {
|
||||
SanitizerSet();
|
||||
SanitizerSet() : Mask(0) {}
|
||||
|
||||
/// \brief Check if a certain (single) sanitizer is enabled.
|
||||
bool has(SanitizerMask K) const;
|
||||
bool has(SanitizerMask K) const {
|
||||
assert(llvm::isPowerOf2_64(K));
|
||||
return Mask & K;
|
||||
}
|
||||
|
||||
/// \brief Check if one or more sanitizers are enabled.
|
||||
bool hasOneOf(SanitizerMask K) const;
|
||||
bool hasOneOf(SanitizerMask K) const { return Mask & K; }
|
||||
|
||||
/// \brief Enable or disable a certain (single) sanitizer.
|
||||
void set(SanitizerMask K, bool Value);
|
||||
void set(SanitizerMask K, bool Value) {
|
||||
assert(llvm::isPowerOf2_64(K));
|
||||
Mask = Value ? (Mask | K) : (Mask & ~K);
|
||||
}
|
||||
|
||||
/// \brief Disable all sanitizers.
|
||||
void clear();
|
||||
void clear() { Mask = 0; }
|
||||
|
||||
/// \brief Returns true if at least one sanitizer is enabled.
|
||||
bool empty() const;
|
||||
bool empty() const { return Mask == 0; }
|
||||
|
||||
/// \brief Bitmask of enabled sanitizers.
|
||||
SanitizerMask Mask;
|
||||
|
@ -70,6 +70,7 @@ class TargetInfo : public RefCountedBase<TargetInfo> {
|
||||
unsigned char MinGlobalAlign;
|
||||
unsigned char MaxAtomicPromoteWidth, MaxAtomicInlineWidth;
|
||||
unsigned short MaxVectorAlign;
|
||||
unsigned short MaxTLSAlign;
|
||||
unsigned short SimdDefaultAlign;
|
||||
const char *DescriptionString;
|
||||
const char *UserLabelPrefix;
|
||||
@ -809,6 +810,21 @@ class TargetInfo : public RefCountedBase<TargetInfo> {
|
||||
return TLSSupported;
|
||||
}
|
||||
|
||||
/// \brief Return the maximum alignment (in bits) of a TLS variable
|
||||
///
|
||||
/// Gets the maximum alignment (in bits) of a TLS variable on this target.
|
||||
/// Returns zero if there is no such constraint.
|
||||
unsigned short getMaxTLSAlign() const {
|
||||
return MaxTLSAlign;
|
||||
}
|
||||
|
||||
/// \brief Whether the target supports SEH __try.
|
||||
bool isSEHTrySupported() const {
|
||||
return getTriple().isOSWindows() &&
|
||||
(getTriple().getArch() == llvm::Triple::x86 ||
|
||||
getTriple().getArch() == llvm::Triple::x86_64);
|
||||
}
|
||||
|
||||
/// \brief Return true if {|} are normal characters in the asm string.
|
||||
///
|
||||
/// If this returns false (the default), then {abc|xyz} is syntax
|
||||
|
@ -526,6 +526,11 @@ KEYWORD(__bridge_transfer , KEYARC)
|
||||
KEYWORD(__bridge_retained , KEYARC)
|
||||
KEYWORD(__bridge_retain , KEYARC)
|
||||
|
||||
// Objective-C keywords.
|
||||
KEYWORD(__covariant , KEYOBJC2)
|
||||
KEYWORD(__contravariant , KEYOBJC2)
|
||||
KEYWORD(__kindof , KEYOBJC2)
|
||||
|
||||
// Alternate spelling for various tokens. There are GCC extensions in all
|
||||
// languages, but should not be disabled in strict conformance mode.
|
||||
ALIAS("__alignof__" , __alignof , KEYALL)
|
||||
|
43
include/clang/CodeGen/ObjectFilePCHContainerOperations.h
Normal file
43
include/clang/CodeGen/ObjectFilePCHContainerOperations.h
Normal file
@ -0,0 +1,43 @@
|
||||
//===-- CodeGen/ObjectFilePCHContainerOperations.h - ------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_CODEGEN_OBJECT_FILE_PCH_CONTAINER_OPERATIONS_H
|
||||
#define LLVM_CLANG_CODEGEN_OBJECT_FILE_PCH_CONTAINER_OPERATIONS_H
|
||||
|
||||
#include "clang/Frontend/PCHContainerOperations.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
/// \brief A PCHContainerOperations implementation that uses LLVM to
|
||||
/// wraps Clang modules inside a COFF, ELF, or Mach-O container.
|
||||
class ObjectFilePCHContainerOperations
|
||||
: public PCHContainerOperations {
|
||||
/// \brief Return an ASTConsumer that can be chained with a
|
||||
/// PCHGenerator that produces a wrapper file format
|
||||
/// that also contains full debug info for the module.
|
||||
std::unique_ptr<ASTConsumer>
|
||||
CreatePCHContainerGenerator(
|
||||
DiagnosticsEngine &Diags, const HeaderSearchOptions &HSO,
|
||||
const PreprocessorOptions &PPO, const TargetOptions &TO,
|
||||
const LangOptions &LO, const std::string &MainFileName,
|
||||
const std::string &OutputFileName, llvm::raw_pwrite_stream *OS,
|
||||
std::shared_ptr<PCHBuffer> Buffer) const override;
|
||||
|
||||
/// \brief Initialize an llvm::BitstreamReader with the serialized
|
||||
/// AST inside the PCH container Buffer.
|
||||
void ExtractPCH(llvm::MemoryBufferRef Buffer,
|
||||
llvm::BitstreamReader &StreamFile) const override;
|
||||
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
@ -41,6 +41,8 @@ class Action {
|
||||
enum ActionClass {
|
||||
InputClass = 0,
|
||||
BindArchClass,
|
||||
CudaDeviceClass,
|
||||
CudaHostClass,
|
||||
PreprocessJobClass,
|
||||
PrecompileJobClass,
|
||||
AnalyzeJobClass,
|
||||
@ -71,16 +73,16 @@ class Action {
|
||||
unsigned OwnsInputs : 1;
|
||||
|
||||
protected:
|
||||
Action(ActionClass _Kind, types::ID _Type)
|
||||
: Kind(_Kind), Type(_Type), OwnsInputs(true) {}
|
||||
Action(ActionClass _Kind, std::unique_ptr<Action> Input, types::ID _Type)
|
||||
: Kind(_Kind), Type(_Type), Inputs(1, Input.release()), OwnsInputs(true) {
|
||||
Action(ActionClass Kind, types::ID Type)
|
||||
: Kind(Kind), Type(Type), OwnsInputs(true) {}
|
||||
Action(ActionClass Kind, std::unique_ptr<Action> Input, types::ID Type)
|
||||
: Kind(Kind), Type(Type), Inputs(1, Input.release()), OwnsInputs(true) {
|
||||
}
|
||||
Action(ActionClass _Kind, std::unique_ptr<Action> Input)
|
||||
: Kind(_Kind), Type(Input->getType()), Inputs(1, Input.release()),
|
||||
Action(ActionClass Kind, std::unique_ptr<Action> Input)
|
||||
: Kind(Kind), Type(Input->getType()), Inputs(1, Input.release()),
|
||||
OwnsInputs(true) {}
|
||||
Action(ActionClass _Kind, const ActionList &_Inputs, types::ID _Type)
|
||||
: Kind(_Kind), Type(_Type), Inputs(_Inputs), OwnsInputs(true) {}
|
||||
Action(ActionClass Kind, const ActionList &Inputs, types::ID Type)
|
||||
: Kind(Kind), Type(Type), Inputs(Inputs), OwnsInputs(true) {}
|
||||
public:
|
||||
virtual ~Action();
|
||||
|
||||
@ -108,7 +110,7 @@ class InputAction : public Action {
|
||||
const llvm::opt::Arg &Input;
|
||||
|
||||
public:
|
||||
InputAction(const llvm::opt::Arg &_Input, types::ID _Type);
|
||||
InputAction(const llvm::opt::Arg &Input, types::ID Type);
|
||||
|
||||
const llvm::opt::Arg &getInputArg() const { return Input; }
|
||||
|
||||
@ -124,7 +126,7 @@ class BindArchAction : public Action {
|
||||
const char *ArchName;
|
||||
|
||||
public:
|
||||
BindArchAction(std::unique_ptr<Action> Input, const char *_ArchName);
|
||||
BindArchAction(std::unique_ptr<Action> Input, const char *ArchName);
|
||||
|
||||
const char *getArchName() const { return ArchName; }
|
||||
|
||||
@ -133,6 +135,41 @@ class BindArchAction : public Action {
|
||||
}
|
||||
};
|
||||
|
||||
class CudaDeviceAction : public Action {
|
||||
virtual void anchor();
|
||||
/// GPU architecture to bind -- e.g 'sm_35'.
|
||||
const char *GpuArchName;
|
||||
/// True when action results are not consumed by the host action (e.g when
|
||||
/// -fsyntax-only or --cuda-device-only options are used).
|
||||
bool AtTopLevel;
|
||||
|
||||
public:
|
||||
CudaDeviceAction(std::unique_ptr<Action> Input, const char *ArchName,
|
||||
bool AtTopLevel);
|
||||
|
||||
const char *getGpuArchName() const { return GpuArchName; }
|
||||
bool isAtTopLevel() const { return AtTopLevel; }
|
||||
|
||||
static bool classof(const Action *A) {
|
||||
return A->getKind() == CudaDeviceClass;
|
||||
}
|
||||
};
|
||||
|
||||
class CudaHostAction : public Action {
|
||||
virtual void anchor();
|
||||
ActionList DeviceActions;
|
||||
|
||||
public:
|
||||
CudaHostAction(std::unique_ptr<Action> Input,
|
||||
const ActionList &DeviceActions);
|
||||
~CudaHostAction() override;
|
||||
|
||||
ActionList &getDeviceActions() { return DeviceActions; }
|
||||
const ActionList &getDeviceActions() const { return DeviceActions; }
|
||||
|
||||
static bool classof(const Action *A) { return A->getKind() == CudaHostClass; }
|
||||
};
|
||||
|
||||
class JobAction : public Action {
|
||||
virtual void anchor();
|
||||
protected:
|
||||
|
@ -188,7 +188,7 @@ def _SLASH_EP : CLFlag<"EP">,
|
||||
def _SLASH_FA : CLFlag<"FA">,
|
||||
HelpText<"Output assembly code file during compilation">;
|
||||
def _SLASH_Fa : CLJoined<"Fa">,
|
||||
HelpText<"Output assembly code to this file during compilation">,
|
||||
HelpText<"Output assembly code to this file during compilation (with /FA)">,
|
||||
MetaVarName<"<file or directory>">;
|
||||
def _SLASH_fallback : CLCompileFlag<"fallback">,
|
||||
HelpText<"Fall back to cl.exe if clang-cl fails to compile">;
|
||||
@ -198,10 +198,10 @@ def _SLASH_Fe : CLJoined<"Fe">,
|
||||
HelpText<"Set output executable file or directory (ends in / or \\)">,
|
||||
MetaVarName<"<file or directory>">;
|
||||
def _SLASH_Fi : CLCompileJoined<"Fi">,
|
||||
HelpText<"Set preprocess output file name">,
|
||||
HelpText<"Set preprocess output file name (with /P)">,
|
||||
MetaVarName<"<file>">;
|
||||
def _SLASH_Fo : CLCompileJoined<"Fo">,
|
||||
HelpText<"Set output object file, or directory (ends in / or \\)">,
|
||||
HelpText<"Set output object file, or directory (ends in / or \\) (with /c)">,
|
||||
MetaVarName<"<file or directory>">;
|
||||
def _SLASH_LD : CLFlag<"LD">, HelpText<"Create DLL">;
|
||||
def _SLASH_LDd : CLFlag<"LDd">, HelpText<"Create debug DLL">;
|
||||
|
@ -405,12 +405,12 @@ class Driver {
|
||||
bool IsUsingLTO(const llvm::opt::ArgList &Args) const;
|
||||
|
||||
private:
|
||||
/// \brief Retrieves a ToolChain for a particular target triple.
|
||||
/// \brief Retrieves a ToolChain for a particular \p Target triple.
|
||||
///
|
||||
/// Will cache ToolChains for the life of the driver object, and create them
|
||||
/// on-demand.
|
||||
const ToolChain &getToolChain(const llvm::opt::ArgList &Args,
|
||||
StringRef DarwinArchName = "") const;
|
||||
const llvm::Triple &Target) const;
|
||||
|
||||
/// @}
|
||||
|
||||
|
@ -106,6 +106,9 @@ class Command {
|
||||
const char *getExecutable() const { return Executable; }
|
||||
|
||||
const llvm::opt::ArgStringList &getArguments() const { return Arguments; }
|
||||
|
||||
/// Print a command argument, and optionally quote it.
|
||||
static void printArg(llvm::raw_ostream &OS, const char *Arg, bool Quote);
|
||||
};
|
||||
|
||||
/// Like Command, but with a fallback which is executed in case
|
||||
|
@ -351,6 +351,12 @@ def cxx_isystem : JoinedOrSeparate<["-"], "cxx-isystem">, Group<clang_i_Group>,
|
||||
MetaVarName<"<directory>">;
|
||||
def c : Flag<["-"], "c">, Flags<[DriverOption]>,
|
||||
HelpText<"Only run preprocess, compile, and assemble steps">;
|
||||
def cuda_device_only : Flag<["--"], "cuda-device-only">,
|
||||
HelpText<"Do device-side CUDA compilation only">;
|
||||
def cuda_gpu_arch_EQ : Joined<["--"], "cuda-gpu-arch=">,
|
||||
Flags<[DriverOption, HelpHidden]>, HelpText<"CUDA GPU architecture">;
|
||||
def cuda_host_only : Flag<["--"], "cuda-host-only">,
|
||||
HelpText<"Do host-side CUDA compilation only">;
|
||||
def dA : Flag<["-"], "dA">, Group<d_Group>;
|
||||
def dD : Flag<["-"], "dD">, Group<d_Group>, Flags<[CC1Option]>,
|
||||
HelpText<"Print macro definitions in -E mode in addition to normal output">;
|
||||
@ -422,13 +428,24 @@ def fprofile_instr_generate : Flag<["-"], "fprofile-instr-generate">,
|
||||
def fprofile_instr_generate_EQ : Joined<["-"], "fprofile-instr-generate=">,
|
||||
Group<f_Group>, Flags<[CC1Option]>, MetaVarName<"<file>">,
|
||||
HelpText<"Generate instrumented code to collect execution counts into <file> (overridden by LLVM_PROFILE_FILE env var)">;
|
||||
def fprofile_instr_use : Flag<["-"], "fprofile-instr-use">, Group<f_Group>;
|
||||
def fprofile_instr_use : Flag<["-"], "fprofile-instr-use">, Group<f_Group>,
|
||||
Flags<[DriverOption]>;
|
||||
def fprofile_instr_use_EQ : Joined<["-"], "fprofile-instr-use=">,
|
||||
Group<f_Group>, Flags<[CC1Option]>,
|
||||
HelpText<"Use instrumentation data for profile-guided optimization">;
|
||||
def fcoverage_mapping : Flag<["-"], "fcoverage-mapping">,
|
||||
Group<f_Group>, Flags<[CC1Option]>,
|
||||
HelpText<"Generate coverage mapping to enable code coverage analysis">;
|
||||
def fprofile_generate : Flag<["-"], "fprofile-generate">,
|
||||
Alias<fprofile_instr_generate>;
|
||||
def fprofile_generate_EQ : Joined<["-"], "fprofile-generate=">,
|
||||
Group<f_Group>, Flags<[DriverOption]>, MetaVarName<"<directory>">,
|
||||
HelpText<"Generate instrumented code to collect execution counts into <directory>/default.profraw (overridden by LLVM_PROFILE_FILE env var)">;
|
||||
def fprofile_use : Flag<["-"], "fprofile-use">, Group<f_Group>,
|
||||
Alias<fprofile_instr_use>;
|
||||
def fprofile_use_EQ : Joined<["-"], "fprofile-use=">,
|
||||
Group<f_Group>, Flags<[DriverOption]>, MetaVarName<"<pathname>">,
|
||||
HelpText<"Use instrumentation data for profile-guided optimization. If pathname is a directory, it reads from <pathname>/default.profdata. Otherwise, it reads from file <pathname>.">;
|
||||
|
||||
def fblocks : Flag<["-"], "fblocks">, Group<f_Group>, Flags<[CC1Option]>,
|
||||
HelpText<"Enable the 'blocks' language feature">;
|
||||
@ -522,7 +539,8 @@ def fsanitize_EQ : CommaJoined<["-"], "fsanitize=">, Group<f_clang_Group>,
|
||||
Flags<[CC1Option, CoreOption]>, MetaVarName<"<check>">,
|
||||
HelpText<"Turn on runtime checks for various forms of undefined "
|
||||
"or suspicious behavior. See user manual for available checks ">;
|
||||
def fno_sanitize_EQ : CommaJoined<["-"], "fno-sanitize=">, Group<f_clang_Group>;
|
||||
def fno_sanitize_EQ : CommaJoined<["-"], "fno-sanitize=">, Group<f_clang_Group>,
|
||||
Flags<[CoreOption]>;
|
||||
def fsanitize_blacklist : Joined<["-"], "fsanitize-blacklist=">,
|
||||
Group<f_clang_Group>, Flags<[CC1Option, CoreOption]>,
|
||||
HelpText<"Path to blacklist file for sanitizers">;
|
||||
@ -547,24 +565,29 @@ def fsanitize_memory_track_origins : Flag<["-"], "fsanitize-memory-track-origins
|
||||
def fno_sanitize_memory_track_origins : Flag<["-"], "fno-sanitize-memory-track-origins">,
|
||||
Group<f_clang_Group>, Flags<[CC1Option]>,
|
||||
HelpText<"Disable origins tracking in MemorySanitizer">;
|
||||
def fsanitize_memory_use_after_dtor : Flag<["-"], "fsanitize-memory-use-after-dtor">,
|
||||
Group<f_clang_Group>, Flags<[CC1Option]>,
|
||||
HelpText<"Enable use-after-destroy detection in MemorySanitizer">;
|
||||
def fsanitize_address_field_padding : Joined<["-"], "fsanitize-address-field-padding=">,
|
||||
Group<f_clang_Group>, Flags<[CC1Option]>,
|
||||
HelpText<"Level of field padding for AddressSanitizer">;
|
||||
def fsanitize_recover : Flag<["-"], "fsanitize-recover">, Group<f_clang_Group>;
|
||||
def fsanitize_recover : Flag<["-"], "fsanitize-recover">, Group<f_clang_Group>,
|
||||
Flags<[CoreOption]>;
|
||||
def fno_sanitize_recover : Flag<["-"], "fno-sanitize-recover">,
|
||||
Group<f_clang_Group>;
|
||||
Group<f_clang_Group>, Flags<[CoreOption]>;
|
||||
def fsanitize_recover_EQ : CommaJoined<["-"], "fsanitize-recover=">,
|
||||
Group<f_clang_Group>,
|
||||
Flags<[CC1Option]>,
|
||||
Flags<[CC1Option, CoreOption]>,
|
||||
HelpText<"Enable recovery for specified sanitizers">;
|
||||
def fno_sanitize_recover_EQ
|
||||
: CommaJoined<["-"], "fno-sanitize-recover=">,
|
||||
Group<f_clang_Group>,
|
||||
Group<f_clang_Group>, Flags<[CoreOption]>,
|
||||
HelpText<"Disable recovery for specified sanitizers">;
|
||||
def fsanitize_trap_EQ : CommaJoined<["-"], "fsanitize-trap=">, Group<f_clang_Group>,
|
||||
Flags<[CC1Option, CoreOption]>,
|
||||
HelpText<"Enable trapping for specified sanitizers">;
|
||||
def fno_sanitize_trap_EQ : CommaJoined<["-"], "fno-sanitize-trap=">, Group<f_clang_Group>,
|
||||
Flags<[CoreOption]>,
|
||||
HelpText<"Disable trapping for specified sanitizers">;
|
||||
def fsanitize_undefined_trap_on_error : Flag<["-"], "fsanitize-undefined-trap-on-error">,
|
||||
Group<f_clang_Group>;
|
||||
@ -641,7 +664,7 @@ def flat__namespace : Flag<["-"], "flat_namespace">;
|
||||
def flax_vector_conversions : Flag<["-"], "flax-vector-conversions">, Group<f_Group>;
|
||||
def flimited_precision_EQ : Joined<["-"], "flimited-precision=">, Group<f_Group>;
|
||||
def flto_EQ : Joined<["-"], "flto=">, Group<clang_ignored_gcc_optimization_f_Group>;
|
||||
def flto : Flag<["-"], "flto">, Group<f_Group>;
|
||||
def flto : Flag<["-"], "flto">, Flags<[CC1Option]>, Group<f_Group>;
|
||||
def fno_lto : Flag<["-"], "fno-lto">, Group<f_Group>;
|
||||
def fmacro_backtrace_limit_EQ : Joined<["-"], "fmacro-backtrace-limit=">,
|
||||
Group<f_Group>, Flags<[DriverOption, CoreOption]>;
|
||||
@ -879,6 +902,8 @@ def fomit_frame_pointer : Flag<["-"], "fomit-frame-pointer">, Group<f_Group>;
|
||||
def fopenmp : Flag<["-"], "fopenmp">, Group<f_Group>, Flags<[CC1Option, NoArgumentUnused]>;
|
||||
def fno_openmp : Flag<["-"], "fno-openmp">, Group<f_Group>, Flags<[NoArgumentUnused]>;
|
||||
def fopenmp_EQ : Joined<["-"], "fopenmp=">, Group<f_Group>;
|
||||
def fopenmp_use_tls : Flag<["-"], "fopenmp-use-tls">, Group<f_Group>, Flags<[NoArgumentUnused]>;
|
||||
def fnoopenmp_use_tls : Flag<["-"], "fnoopenmp-use-tls">, Group<f_Group>, Flags<[CC1Option, NoArgumentUnused]>;
|
||||
def fno_optimize_sibling_calls : Flag<["-"], "fno-optimize-sibling-calls">, Group<f_Group>;
|
||||
def foptimize_sibling_calls : Flag<["-"], "foptimize-sibling-calls">, Group<f_Group>;
|
||||
def force__cpusubtype__ALL : Flag<["-"], "force_cpusubtype_ALL">;
|
||||
@ -904,7 +929,6 @@ def fpie : Flag<["-"], "fpie">, Group<f_Group>;
|
||||
def fno_pie : Flag<["-"], "fno-pie">, Group<f_Group>;
|
||||
def fprofile_arcs : Flag<["-"], "fprofile-arcs">, Group<f_Group>;
|
||||
def fno_profile_arcs : Flag<["-"], "fno-profile-arcs">, Group<f_Group>;
|
||||
def fprofile_generate : Flag<["-"], "fprofile-generate">, Group<f_Group>;
|
||||
def framework : Separate<["-"], "framework">, Flags<[LinkerInput]>;
|
||||
def frandom_seed_EQ : Joined<["-"], "frandom-seed=">, Group<clang_ignored_f_Group>;
|
||||
def freg_struct_return : Flag<["-"], "freg-struct-return">, Group<f_Group>, Flags<[CC1Option]>,
|
||||
@ -1518,7 +1542,8 @@ def print_libgcc_file_name : Flag<["-", "--"], "print-libgcc-file-name">,
|
||||
HelpText<"Print the library path for \"libgcc.a\"">;
|
||||
def print_multi_directory : Flag<["-", "--"], "print-multi-directory">;
|
||||
def print_multi_lib : Flag<["-", "--"], "print-multi-lib">;
|
||||
def print_multi_os_directory : Flag<["-", "--"], "print-multi-os-directory">;
|
||||
def print_multi_os_directory : Flag<["-", "--"], "print-multi-os-directory">,
|
||||
Flags<[Unsupported]>;
|
||||
def print_prog_name_EQ : Joined<["-", "--"], "print-prog-name=">,
|
||||
HelpText<"Print the full program path of <name>">, MetaVarName<"<name>">;
|
||||
def print_search_dirs : Flag<["-", "--"], "print-search-dirs">,
|
||||
@ -1527,6 +1552,7 @@ def private__bundle : Flag<["-"], "private_bundle">;
|
||||
def pthreads : Flag<["-"], "pthreads">;
|
||||
def pthread : Flag<["-"], "pthread">, Flags<[CC1Option]>,
|
||||
HelpText<"Support POSIX threads in generated code">;
|
||||
def no_pthread : Flag<["-"], "no-pthread">, Flags<[CC1Option]>;
|
||||
def p : Flag<["-"], "p">;
|
||||
def pie : Flag<["-"], "pie">;
|
||||
def read__only__relocs : Separate<["-"], "read_only_relocs">;
|
||||
@ -1793,8 +1819,6 @@ defm : BooleanFFlag<"keep-inline-functions">, Group<clang_ignored_gcc_optimizati
|
||||
|
||||
def fprofile_dir : Joined<["-"], "fprofile-dir=">, Group<clang_ignored_gcc_optimization_f_Group>;
|
||||
|
||||
defm profile_use : BooleanFFlag<"profile-use">, Group<clang_ignored_gcc_optimization_f_Group>;
|
||||
def fprofile_use_EQ : Joined<["-"], "fprofile-use=">, Group<clang_ignored_gcc_optimization_f_Group>;
|
||||
def fuse_ld_EQ : Joined<["-"], "fuse-ld=">, Group<f_Group>;
|
||||
|
||||
defm align_functions : BooleanFFlag<"align-functions">, Group<clang_ignored_gcc_optimization_f_Group>;
|
||||
|
@ -29,6 +29,7 @@ class SanitizerArgs {
|
||||
std::vector<std::string> BlacklistFiles;
|
||||
int CoverageFeatures;
|
||||
int MsanTrackOrigins;
|
||||
bool MsanUseAfterDtor;
|
||||
int AsanFieldPadding;
|
||||
bool AsanZeroBaseShadow;
|
||||
bool AsanSharedRuntime;
|
||||
|
@ -44,6 +44,7 @@ TYPE("c", C, PP_C, "c", "u")
|
||||
TYPE("cl", CL, PP_C, "cl", "u")
|
||||
TYPE("cuda-cpp-output", PP_CUDA, INVALID, "cui", "u")
|
||||
TYPE("cuda", CUDA, PP_CUDA, "cu", "u")
|
||||
TYPE("cuda", CUDA_DEVICE, PP_CUDA, "cu", "")
|
||||
TYPE("objective-c-cpp-output", PP_ObjC, INVALID, "mi", "u")
|
||||
TYPE("objc-cpp-output", PP_ObjC_Alias, INVALID, "mi", "u")
|
||||
TYPE("objective-c", ObjC, PP_ObjC, "m", "u")
|
||||
|
@ -63,6 +63,9 @@ namespace types {
|
||||
/// isCXX - Is this a "C++" input (C++ and Obj-C++ sources and headers).
|
||||
bool isCXX(ID Id);
|
||||
|
||||
/// isCuda - Is this a CUDA input.
|
||||
bool isCuda(ID Id);
|
||||
|
||||
/// isObjC - Is this an "ObjC" input (Obj-C and Obj-C++ sources and headers).
|
||||
bool isObjC(ID Id);
|
||||
|
||||
|
@ -166,6 +166,9 @@ struct FormatStyle {
|
||||
/// Like \c Attach, but break before braces on function, namespace and
|
||||
/// class definitions.
|
||||
BS_Linux,
|
||||
/// Like ``Attach``, but break before braces on enum, function, and record
|
||||
/// definitions.
|
||||
BS_Mozilla,
|
||||
/// Like \c Attach, but break before function definitions, and 'else'.
|
||||
BS_Stroustrup,
|
||||
/// Always break before braces.
|
||||
@ -290,6 +293,12 @@ struct FormatStyle {
|
||||
/// \brief Language, this format style is targeted at.
|
||||
LanguageKind Language;
|
||||
|
||||
/// \brief A regular expression matching macros that start a block.
|
||||
std::string MacroBlockBegin;
|
||||
|
||||
/// \brief A regular expression matching macros that end a block.
|
||||
std::string MacroBlockEnd;
|
||||
|
||||
/// \brief The maximum number of consecutive empty lines to keep.
|
||||
unsigned MaxEmptyLinesToKeep;
|
||||
|
||||
@ -479,6 +488,8 @@ struct FormatStyle {
|
||||
IndentWrappedFunctionNames == R.IndentWrappedFunctionNames &&
|
||||
KeepEmptyLinesAtTheStartOfBlocks ==
|
||||
R.KeepEmptyLinesAtTheStartOfBlocks &&
|
||||
MacroBlockBegin == R.MacroBlockBegin &&
|
||||
MacroBlockEnd == R.MacroBlockEnd &&
|
||||
MaxEmptyLinesToKeep == R.MaxEmptyLinesToKeep &&
|
||||
NamespaceIndentation == R.NamespaceIndentation &&
|
||||
ObjCBlockIndentWidth == R.ObjCBlockIndentWidth &&
|
||||
|
@ -67,6 +67,8 @@ CODEGENOPT(InstrumentFunctions , 1, 0) ///< Set when -finstrument-functions is
|
||||
CODEGENOPT(InstrumentForProfiling , 1, 0) ///< Set when -pg is enabled.
|
||||
CODEGENOPT(LessPreciseFPMAD , 1, 0) ///< Enable less precise MAD instructions to
|
||||
///< be generated.
|
||||
CODEGENOPT(PrepareForLTO , 1, 0) ///< Set when -flto is enabled on the
|
||||
///< compile step.
|
||||
CODEGENOPT(MergeAllConstants , 1, 1) ///< Merge identical constants.
|
||||
CODEGENOPT(MergeFunctions , 1, 0) ///< Set when -fmerge-functions is enabled.
|
||||
CODEGENOPT(MSVolatile , 1, 0) ///< Set when /volatile:ms is enabled.
|
||||
@ -110,6 +112,8 @@ CODEGENOPT(SanitizeAddressZeroBaseShadow , 1, 0) ///< Map shadow memory at zero
|
||||
///< offset in AddressSanitizer.
|
||||
CODEGENOPT(SanitizeMemoryTrackOrigins, 2, 0) ///< Enable tracking origins in
|
||||
///< MemorySanitizer
|
||||
CODEGENOPT(SanitizeMemoryUseAfterDtor, 1, 0) ///< Enable use-after-delete detection
|
||||
///< in MemorySanitizer
|
||||
CODEGENOPT(SanitizeCoverageType, 2, 0) ///< Type of sanitizer coverage
|
||||
///< instrumentation.
|
||||
CODEGENOPT(SanitizeCoverageIndirectCalls, 1, 0) ///< Enable sanitizer coverage
|
||||
|
@ -155,6 +155,7 @@ class CodeGenOptions : public CodeGenOptionsBase {
|
||||
std::vector<std::string> DependentLibraries;
|
||||
|
||||
/// Name of the profile file to use as output for -fprofile-instr-generate
|
||||
/// and -fprofile-generate.
|
||||
std::string InstrProfileOutput;
|
||||
|
||||
/// Name of the profile file to use with -fprofile-sample-use.
|
||||
|
@ -30,6 +30,7 @@
|
||||
namespace llvm {
|
||||
class raw_fd_ostream;
|
||||
class Timer;
|
||||
class TimerGroup;
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
@ -101,7 +102,10 @@ class CompilerInstance : public ModuleLoader {
|
||||
/// \brief The semantic analysis object.
|
||||
std::unique_ptr<Sema> TheSema;
|
||||
|
||||
/// \brief The frontend timer
|
||||
/// \brief The frontend timer group.
|
||||
std::unique_ptr<llvm::TimerGroup> FrontendTimerGroup;
|
||||
|
||||
/// \brief The frontend timer.
|
||||
std::unique_ptr<llvm::Timer> FrontendTimer;
|
||||
|
||||
/// \brief The ASTReader, if one exists.
|
||||
@ -157,9 +161,10 @@ class CompilerInstance : public ModuleLoader {
|
||||
std::string TempFilename;
|
||||
std::unique_ptr<raw_ostream> OS;
|
||||
|
||||
OutputFile(const std::string &filename, const std::string &tempFilename,
|
||||
OutputFile(std::string filename, std::string tempFilename,
|
||||
std::unique_ptr<raw_ostream> OS)
|
||||
: Filename(filename), TempFilename(tempFilename), OS(std::move(OS)) {}
|
||||
: Filename(std::move(filename)), TempFilename(std::move(tempFilename)),
|
||||
OS(std::move(OS)) {}
|
||||
OutputFile(OutputFile &&O)
|
||||
: Filename(std::move(O.Filename)),
|
||||
TempFilename(std::move(O.TempFilename)), OS(std::move(O.OS)) {}
|
||||
@ -614,7 +619,7 @@ class CompilerInstance : public ModuleLoader {
|
||||
///
|
||||
/// \return - The new object on success, or null on failure.
|
||||
static IntrusiveRefCntPtr<ASTReader> createPCHExternalASTSource(
|
||||
StringRef Path, const std::string &Sysroot, bool DisablePCHValidation,
|
||||
StringRef Path, StringRef Sysroot, bool DisablePCHValidation,
|
||||
bool AllowPCHWithCompilerErrors, Preprocessor &PP, ASTContext &Context,
|
||||
const PCHContainerOperations &PCHContainerOps,
|
||||
void *DeserializationListener, bool OwnDeserializationListener,
|
||||
@ -627,11 +632,9 @@ class CompilerInstance : public ModuleLoader {
|
||||
|
||||
/// Create a code completion consumer to print code completion results, at
|
||||
/// \p Filename, \p Line, and \p Column, to the given output stream \p OS.
|
||||
static CodeCompleteConsumer *
|
||||
createCodeCompletionConsumer(Preprocessor &PP, const std::string &Filename,
|
||||
unsigned Line, unsigned Column,
|
||||
const CodeCompleteOptions &Opts,
|
||||
raw_ostream &OS);
|
||||
static CodeCompleteConsumer *createCodeCompletionConsumer(
|
||||
Preprocessor &PP, StringRef Filename, unsigned Line, unsigned Column,
|
||||
const CodeCompleteOptions &Opts, raw_ostream &OS);
|
||||
|
||||
/// \brief Create the Sema object to be used for parsing.
|
||||
void createSema(TranslationUnitKind TUKind,
|
||||
|
@ -452,9 +452,13 @@ class ModuleMap {
|
||||
/// \param HomeDir The directory in which relative paths within this module
|
||||
/// map file will be resolved.
|
||||
///
|
||||
/// \param ExternModuleLoc The location of the "extern module" declaration
|
||||
/// that caused us to load this module map file, if any.
|
||||
///
|
||||
/// \returns true if an error occurred, false otherwise.
|
||||
bool parseModuleMapFile(const FileEntry *File, bool IsSystem,
|
||||
const DirectoryEntry *HomeDir);
|
||||
const DirectoryEntry *HomeDir,
|
||||
SourceLocation ExternModuleLoc = SourceLocation());
|
||||
|
||||
/// \brief Dump the contents of the module map, for debugging purposes.
|
||||
void dump();
|
||||
|
@ -786,6 +786,22 @@ class Preprocessor : public RefCountedBase<Preprocessor> {
|
||||
(!getLangOpts().Modules || (bool)getMacroDefinition(II));
|
||||
}
|
||||
|
||||
/// \brief Determine whether II is defined as a macro within the module M,
|
||||
/// if that is a module that we've already preprocessed. Does not check for
|
||||
/// macros imported into M.
|
||||
bool isMacroDefinedInLocalModule(const IdentifierInfo *II, Module *M) {
|
||||
if (!II->hasMacroDefinition())
|
||||
return false;
|
||||
auto I = Submodules.find(M);
|
||||
if (I == Submodules.end())
|
||||
return false;
|
||||
auto J = I->second.Macros.find(II);
|
||||
if (J == I->second.Macros.end())
|
||||
return false;
|
||||
auto *MD = J->second.getLatest();
|
||||
return MD && MD->isDefined();
|
||||
}
|
||||
|
||||
MacroDefinition getMacroDefinition(const IdentifierInfo *II) {
|
||||
if (!II->hasMacroDefinition())
|
||||
return MacroDefinition();
|
||||
|
@ -46,6 +46,8 @@ namespace clang {
|
||||
class PoisonSEHIdentifiersRAIIObject;
|
||||
class VersionTuple;
|
||||
class OMPClause;
|
||||
class ObjCTypeParamList;
|
||||
class ObjCTypeParameter;
|
||||
|
||||
/// Parser - This implements a parser for the C family of languages. After
|
||||
/// parsing units of the grammar, productions are invoked to handle whatever has
|
||||
@ -1246,6 +1248,13 @@ class Parser : public CodeCompletionHandler {
|
||||
DeclGroupPtrTy ParseObjCAtClassDeclaration(SourceLocation atLoc);
|
||||
Decl *ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
|
||||
ParsedAttributes &prefixAttrs);
|
||||
ObjCTypeParamList *parseObjCTypeParamList();
|
||||
ObjCTypeParamList *parseObjCTypeParamListOrProtocolRefs(
|
||||
SourceLocation &lAngleLoc,
|
||||
SmallVectorImpl<IdentifierLocPair> &protocolIdents,
|
||||
SourceLocation &rAngleLoc,
|
||||
bool mayBeProtocolList = true);
|
||||
|
||||
void HelperActionsForIvarDeclarations(Decl *interfaceDecl, SourceLocation atLoc,
|
||||
BalancedDelimiterTracker &T,
|
||||
SmallVectorImpl<Decl *> &AllIvarDecls,
|
||||
@ -1258,8 +1267,48 @@ class Parser : public CodeCompletionHandler {
|
||||
bool WarnOnDeclarations,
|
||||
bool ForObjCContainer,
|
||||
SourceLocation &LAngleLoc,
|
||||
SourceLocation &EndProtoLoc);
|
||||
bool ParseObjCProtocolQualifiers(DeclSpec &DS);
|
||||
SourceLocation &EndProtoLoc,
|
||||
bool consumeLastToken);
|
||||
|
||||
/// Parse the first angle-bracket-delimited clause for an
|
||||
/// Objective-C object or object pointer type, which may be either
|
||||
/// type arguments or protocol qualifiers.
|
||||
void parseObjCTypeArgsOrProtocolQualifiers(
|
||||
ParsedType baseType,
|
||||
SourceLocation &typeArgsLAngleLoc,
|
||||
SmallVectorImpl<ParsedType> &typeArgs,
|
||||
SourceLocation &typeArgsRAngleLoc,
|
||||
SourceLocation &protocolLAngleLoc,
|
||||
SmallVectorImpl<Decl *> &protocols,
|
||||
SmallVectorImpl<SourceLocation> &protocolLocs,
|
||||
SourceLocation &protocolRAngleLoc,
|
||||
bool consumeLastToken,
|
||||
bool warnOnIncompleteProtocols);
|
||||
|
||||
/// Parse either Objective-C type arguments or protocol qualifiers; if the
|
||||
/// former, also parse protocol qualifiers afterward.
|
||||
void parseObjCTypeArgsAndProtocolQualifiers(
|
||||
ParsedType baseType,
|
||||
SourceLocation &typeArgsLAngleLoc,
|
||||
SmallVectorImpl<ParsedType> &typeArgs,
|
||||
SourceLocation &typeArgsRAngleLoc,
|
||||
SourceLocation &protocolLAngleLoc,
|
||||
SmallVectorImpl<Decl *> &protocols,
|
||||
SmallVectorImpl<SourceLocation> &protocolLocs,
|
||||
SourceLocation &protocolRAngleLoc,
|
||||
bool consumeLastToken);
|
||||
|
||||
/// Parse a protocol qualifier type such as '<NSCopying>', which is
|
||||
/// an anachronistic way of writing 'id<NSCopying>'.
|
||||
TypeResult parseObjCProtocolQualifierType(SourceLocation &rAngleLoc);
|
||||
|
||||
/// Parse Objective-C type arguments and protocol qualifiers, extending the
|
||||
/// current type with the parsed result.
|
||||
TypeResult parseObjCTypeArgsAndProtocolQualifiers(SourceLocation loc,
|
||||
ParsedType type,
|
||||
bool consumeLastToken,
|
||||
SourceLocation &endLoc);
|
||||
|
||||
void ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey,
|
||||
Decl *CDecl);
|
||||
DeclGroupPtrTy ParseObjCAtProtocolDeclaration(SourceLocation atLoc,
|
||||
@ -2469,7 +2518,8 @@ class Parser : public CodeCompletionHandler {
|
||||
typedef SmallVector<ParsedTemplateArgument, 16> TemplateArgList;
|
||||
|
||||
bool ParseGreaterThanInTemplateList(SourceLocation &RAngleLoc,
|
||||
bool ConsumeLastToken);
|
||||
bool ConsumeLastToken,
|
||||
bool ObjCGenericList);
|
||||
bool ParseTemplateIdAfterTemplateName(TemplateTy Template,
|
||||
SourceLocation TemplateNameLoc,
|
||||
const CXXScopeSpec &SS,
|
||||
|
@ -765,11 +765,13 @@ class CodeCompletionResult {
|
||||
/// \param Allocator The allocator that will be used to allocate the
|
||||
/// string itself.
|
||||
CodeCompletionString *CreateCodeCompletionString(Sema &S,
|
||||
const CodeCompletionContext &CCContext,
|
||||
CodeCompletionAllocator &Allocator,
|
||||
CodeCompletionTUInfo &CCTUInfo,
|
||||
bool IncludeBriefComments);
|
||||
CodeCompletionString *CreateCodeCompletionString(ASTContext &Ctx,
|
||||
Preprocessor &PP,
|
||||
const CodeCompletionContext &CCContext,
|
||||
CodeCompletionAllocator &Allocator,
|
||||
CodeCompletionTUInfo &CCTUInfo,
|
||||
bool IncludeBriefComments);
|
||||
|
@ -373,14 +373,6 @@ class DeclSpec {
|
||||
// Scope specifier for the type spec, if applicable.
|
||||
CXXScopeSpec TypeScope;
|
||||
|
||||
// List of protocol qualifiers for objective-c classes. Used for
|
||||
// protocol-qualified interfaces "NString<foo>" and protocol-qualified id
|
||||
// "id<foo>".
|
||||
Decl * const *ProtocolQualifiers;
|
||||
unsigned NumProtocolQualifiers;
|
||||
SourceLocation ProtocolLAngleLoc;
|
||||
SourceLocation *ProtocolLocs;
|
||||
|
||||
// SourceLocation info. These are null if the item wasn't specified or if
|
||||
// the setting was synthesized.
|
||||
SourceRange Range;
|
||||
@ -442,16 +434,10 @@ class DeclSpec {
|
||||
Constexpr_specified(false),
|
||||
Concept_specified(false),
|
||||
Attrs(attrFactory),
|
||||
ProtocolQualifiers(nullptr),
|
||||
NumProtocolQualifiers(0),
|
||||
ProtocolLocs(nullptr),
|
||||
writtenBS(),
|
||||
ObjCQualifiers(nullptr) {
|
||||
}
|
||||
~DeclSpec() {
|
||||
delete [] ProtocolQualifiers;
|
||||
delete [] ProtocolLocs;
|
||||
}
|
||||
|
||||
// storage-class-specifier
|
||||
SCS getStorageClassSpec() const { return (SCS)StorageClassSpec; }
|
||||
TSCS getThreadStorageClassSpec() const {
|
||||
@ -490,6 +476,8 @@ class DeclSpec {
|
||||
bool isTypeAltiVecPixel() const { return TypeAltiVecPixel; }
|
||||
bool isTypeAltiVecBool() const { return TypeAltiVecBool; }
|
||||
bool isTypeSpecOwned() const { return TypeSpecOwned; }
|
||||
bool isTypeRep() const { return isTypeRep((TST) TypeSpecType); }
|
||||
|
||||
ParsedType getRepAsType() const {
|
||||
assert(isTypeRep((TST) TypeSpecType) && "DeclSpec does not store a type");
|
||||
return TypeRep;
|
||||
@ -751,19 +739,6 @@ class DeclSpec {
|
||||
Attrs.takeAllFrom(attrs);
|
||||
}
|
||||
|
||||
typedef Decl * const *ProtocolQualifierListTy;
|
||||
ProtocolQualifierListTy getProtocolQualifiers() const {
|
||||
return ProtocolQualifiers;
|
||||
}
|
||||
SourceLocation *getProtocolLocs() const { return ProtocolLocs; }
|
||||
unsigned getNumProtocolQualifiers() const {
|
||||
return NumProtocolQualifiers;
|
||||
}
|
||||
SourceLocation getProtocolLAngleLoc() const { return ProtocolLAngleLoc; }
|
||||
void setProtocolQualifiers(Decl * const *Protos, unsigned NP,
|
||||
SourceLocation *ProtoLocs,
|
||||
SourceLocation LAngleLoc);
|
||||
|
||||
/// Finish - This does final analysis of the declspec, issuing diagnostics for
|
||||
/// things like "_Imaginary" (lacking an FP type). After calling this method,
|
||||
/// DeclSpec is guaranteed self-consistent, even if an error occurred.
|
||||
|
@ -1387,7 +1387,8 @@ class Sema {
|
||||
|
||||
/// Determine if \p D has a visible definition. If not, suggest a declaration
|
||||
/// that should be made visible to expose the definition.
|
||||
bool hasVisibleDefinition(NamedDecl *D, NamedDecl **Suggested);
|
||||
bool hasVisibleDefinition(NamedDecl *D, NamedDecl **Suggested,
|
||||
bool OnlyNeedComplete = false);
|
||||
bool hasVisibleDefinition(const NamedDecl *D) {
|
||||
NamedDecl *Hidden;
|
||||
return hasVisibleDefinition(const_cast<NamedDecl*>(D), &Hidden);
|
||||
@ -1848,7 +1849,7 @@ class Sema {
|
||||
bool isAcceptableTagRedeclaration(const TagDecl *Previous,
|
||||
TagTypeKind NewTag, bool isDefinition,
|
||||
SourceLocation NewTagLoc,
|
||||
const IdentifierInfo &Name);
|
||||
const IdentifierInfo *Name);
|
||||
|
||||
enum TagUseKind {
|
||||
TUK_Reference, // Reference to a tag: 'struct foo *X;'
|
||||
@ -2187,6 +2188,7 @@ class Sema {
|
||||
void HandleFunctionTypeMismatch(PartialDiagnostic &PDiag,
|
||||
QualType FromType, QualType ToType);
|
||||
|
||||
void maybeExtendBlockObject(ExprResult &E);
|
||||
CastKind PrepareCastToObjCObjectPointer(ExprResult &E);
|
||||
bool CheckPointerConversion(Expr *From, QualType ToType,
|
||||
CastKind &Kind,
|
||||
@ -7088,16 +7090,44 @@ class Sema {
|
||||
};
|
||||
ObjCContainerKind getObjCContainerKind() const;
|
||||
|
||||
Decl *ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
|
||||
DeclResult actOnObjCTypeParam(Scope *S,
|
||||
ObjCTypeParamVariance variance,
|
||||
SourceLocation varianceLoc,
|
||||
unsigned index,
|
||||
IdentifierInfo *paramName,
|
||||
SourceLocation paramLoc,
|
||||
SourceLocation colonLoc,
|
||||
ParsedType typeBound);
|
||||
|
||||
ObjCTypeParamList *actOnObjCTypeParamList(Scope *S, SourceLocation lAngleLoc,
|
||||
ArrayRef<Decl *> typeParams,
|
||||
SourceLocation rAngleLoc);
|
||||
void popObjCTypeParamList(Scope *S, ObjCTypeParamList *typeParamList);
|
||||
|
||||
Decl *ActOnStartClassInterface(Scope *S,
|
||||
SourceLocation AtInterfaceLoc,
|
||||
IdentifierInfo *ClassName,
|
||||
SourceLocation ClassLoc,
|
||||
ObjCTypeParamList *typeParamList,
|
||||
IdentifierInfo *SuperName,
|
||||
SourceLocation SuperLoc,
|
||||
ArrayRef<ParsedType> SuperTypeArgs,
|
||||
SourceRange SuperTypeArgsRange,
|
||||
Decl * const *ProtoRefs,
|
||||
unsigned NumProtoRefs,
|
||||
const SourceLocation *ProtoLocs,
|
||||
SourceLocation EndProtoLoc,
|
||||
AttributeList *AttrList);
|
||||
|
||||
void ActOnSuperClassOfClassInterface(Scope *S,
|
||||
SourceLocation AtInterfaceLoc,
|
||||
ObjCInterfaceDecl *IDecl,
|
||||
IdentifierInfo *ClassName,
|
||||
SourceLocation ClassLoc,
|
||||
IdentifierInfo *SuperName,
|
||||
SourceLocation SuperLoc,
|
||||
ArrayRef<ParsedType> SuperTypeArgs,
|
||||
SourceRange SuperTypeArgsRange);
|
||||
|
||||
void ActOnTypedefedProtocols(SmallVectorImpl<Decl *> &ProtocolRefs,
|
||||
IdentifierInfo *SuperName,
|
||||
@ -7124,6 +7154,7 @@ class Sema {
|
||||
Decl *ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
|
||||
IdentifierInfo *ClassName,
|
||||
SourceLocation ClassLoc,
|
||||
ObjCTypeParamList *typeParamList,
|
||||
IdentifierInfo *CategoryName,
|
||||
SourceLocation CategoryLoc,
|
||||
Decl * const *ProtoRefs,
|
||||
@ -7147,9 +7178,10 @@ class Sema {
|
||||
ArrayRef<Decl *> Decls);
|
||||
|
||||
DeclGroupPtrTy ActOnForwardClassDeclaration(SourceLocation Loc,
|
||||
IdentifierInfo **IdentList,
|
||||
SourceLocation *IdentLocs,
|
||||
unsigned NumElts);
|
||||
IdentifierInfo **IdentList,
|
||||
SourceLocation *IdentLocs,
|
||||
ArrayRef<ObjCTypeParamList *> TypeParamLists,
|
||||
unsigned NumElts);
|
||||
|
||||
DeclGroupPtrTy ActOnForwardProtocolDeclaration(SourceLocation AtProtoclLoc,
|
||||
const IdentifierLocPair *IdentList,
|
||||
@ -7161,6 +7193,61 @@ class Sema {
|
||||
unsigned NumProtocols,
|
||||
SmallVectorImpl<Decl *> &Protocols);
|
||||
|
||||
/// Given a list of identifiers (and their locations), resolve the
|
||||
/// names to either Objective-C protocol qualifiers or type
|
||||
/// arguments, as appropriate.
|
||||
void actOnObjCTypeArgsOrProtocolQualifiers(
|
||||
Scope *S,
|
||||
ParsedType baseType,
|
||||
SourceLocation lAngleLoc,
|
||||
ArrayRef<IdentifierInfo *> identifiers,
|
||||
ArrayRef<SourceLocation> identifierLocs,
|
||||
SourceLocation rAngleLoc,
|
||||
SourceLocation &typeArgsLAngleLoc,
|
||||
SmallVectorImpl<ParsedType> &typeArgs,
|
||||
SourceLocation &typeArgsRAngleLoc,
|
||||
SourceLocation &protocolLAngleLoc,
|
||||
SmallVectorImpl<Decl *> &protocols,
|
||||
SourceLocation &protocolRAngleLoc,
|
||||
bool warnOnIncompleteProtocols);
|
||||
|
||||
/// Build a an Objective-C protocol-qualified 'id' type where no
|
||||
/// base type was specified.
|
||||
TypeResult actOnObjCProtocolQualifierType(
|
||||
SourceLocation lAngleLoc,
|
||||
ArrayRef<Decl *> protocols,
|
||||
ArrayRef<SourceLocation> protocolLocs,
|
||||
SourceLocation rAngleLoc);
|
||||
|
||||
/// Build a specialized and/or protocol-qualified Objective-C type.
|
||||
TypeResult actOnObjCTypeArgsAndProtocolQualifiers(
|
||||
Scope *S,
|
||||
SourceLocation Loc,
|
||||
ParsedType BaseType,
|
||||
SourceLocation TypeArgsLAngleLoc,
|
||||
ArrayRef<ParsedType> TypeArgs,
|
||||
SourceLocation TypeArgsRAngleLoc,
|
||||
SourceLocation ProtocolLAngleLoc,
|
||||
ArrayRef<Decl *> Protocols,
|
||||
ArrayRef<SourceLocation> ProtocolLocs,
|
||||
SourceLocation ProtocolRAngleLoc);
|
||||
|
||||
/// Build an Objective-C object pointer type.
|
||||
QualType BuildObjCObjectType(QualType BaseType,
|
||||
SourceLocation Loc,
|
||||
SourceLocation TypeArgsLAngleLoc,
|
||||
ArrayRef<TypeSourceInfo *> TypeArgs,
|
||||
SourceLocation TypeArgsRAngleLoc,
|
||||
SourceLocation ProtocolLAngleLoc,
|
||||
ArrayRef<ObjCProtocolDecl *> Protocols,
|
||||
ArrayRef<SourceLocation> ProtocolLocs,
|
||||
SourceLocation ProtocolRAngleLoc,
|
||||
bool FailOnError = false);
|
||||
|
||||
/// Check the application of the Objective-C '__kindof' qualifier to
|
||||
/// the given type.
|
||||
bool checkObjCKindOfType(QualType &type, SourceLocation loc);
|
||||
|
||||
/// Ensure attributes are consistent with type.
|
||||
/// \param [in, out] Attributes The attributes to check; they will
|
||||
/// be modified to be consistent with \p PropertyTy.
|
||||
@ -7610,13 +7697,13 @@ class Sema {
|
||||
void DestroyDataSharingAttributesStack();
|
||||
ExprResult VerifyPositiveIntegerConstantInClause(Expr *Op,
|
||||
OpenMPClauseKind CKind);
|
||||
/// \brief Checks if the specified variable is used in one of the private
|
||||
public:
|
||||
/// \brief Check if the specified variable is used in a private clause in
|
||||
/// Checks if the specified variable is used in one of the private
|
||||
/// clauses in OpenMP constructs.
|
||||
bool IsOpenMPCapturedVar(VarDecl *VD);
|
||||
|
||||
public:
|
||||
/// \brief Check if the specified variable is used in one of the private
|
||||
/// clauses in OpenMP constructs.
|
||||
/// OpenMP constructs.
|
||||
/// \param Level Relative level of nested OpenMP construct for that the check
|
||||
/// is performed.
|
||||
bool isOpenMPPrivateVar(VarDecl *VD, unsigned Level);
|
||||
|
@ -413,6 +413,7 @@ namespace clang {
|
||||
#define LINKAGESPEC(DERIVED, BASE)
|
||||
#define OBJCCOMPATIBLEALIAS(DERIVED, BASE)
|
||||
#define OBJCMETHOD(DERIVED, BASE)
|
||||
#define OBJCTYPEPARAM(DERIVED, BASE)
|
||||
#define OBJCIVAR(DERIVED, BASE)
|
||||
#define OBJCPROPERTY(DERIVED, BASE)
|
||||
#define OBJCPROPERTYIMPL(DERIVED, BASE)
|
||||
|
@ -1105,7 +1105,9 @@ namespace clang {
|
||||
/// \brief An OMPThreadPrivateDecl record.
|
||||
DECL_OMP_THREADPRIVATE,
|
||||
/// \brief An EmptyDecl record.
|
||||
DECL_EMPTY
|
||||
DECL_EMPTY,
|
||||
/// \brief An ObjCTypeParamDecl record.
|
||||
DECL_OBJC_TYPE_PARAM,
|
||||
};
|
||||
|
||||
/// \brief Record codes for each kind of statement or expression.
|
||||
|
@ -42,6 +42,7 @@
|
||||
#include "llvm/ADT/TinyPtrVector.h"
|
||||
#include "llvm/Bitcode/BitstreamReader.h"
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include "llvm/Support/Timer.h"
|
||||
#include <deque>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
@ -380,6 +381,9 @@ class ASTReader
|
||||
/// \brief The module manager which manages modules and their dependencies
|
||||
ModuleManager ModuleMgr;
|
||||
|
||||
/// \brief A timer used to track the time spent deserializing.
|
||||
std::unique_ptr<llvm::Timer> ReadTimer;
|
||||
|
||||
/// \brief The location where the module file will be considered as
|
||||
/// imported from. For non-module AST types it should be invalid.
|
||||
SourceLocation CurrentImportLoc;
|
||||
@ -976,12 +980,14 @@ class ASTReader
|
||||
MergedLookups;
|
||||
|
||||
typedef llvm::DenseMap<Decl *, SmallVector<serialization::DeclID, 2> >
|
||||
MergedDeclsMap;
|
||||
KeyDeclsMap;
|
||||
|
||||
/// \brief A mapping from canonical declarations to the set of additional
|
||||
/// (global, previously-canonical) declaration IDs that have been merged with
|
||||
/// that canonical declaration.
|
||||
MergedDeclsMap MergedDecls;
|
||||
/// \brief A mapping from canonical declarations to the set of global
|
||||
/// declaration IDs for key declaration that have been merged with that
|
||||
/// canonical declaration. A key declaration is a formerly-canonical
|
||||
/// declaration whose module did not import any other key declaration for that
|
||||
/// entity. These are the IDs that we use as keys when finding redecl chains.
|
||||
KeyDeclsMap KeyDecls;
|
||||
|
||||
/// \brief A mapping from DeclContexts to the semantic DeclContext that we
|
||||
/// are treating as the definition of the entity. This is used, for instance,
|
||||
@ -1054,6 +1060,36 @@ class ASTReader
|
||||
void ResolveImportedPath(ModuleFile &M, std::string &Filename);
|
||||
static void ResolveImportedPath(std::string &Filename, StringRef Prefix);
|
||||
|
||||
/// \brief Returns the first key declaration for the given declaration. This
|
||||
/// is one that is formerly-canonical (or still canonical) and whose module
|
||||
/// did not import any other key declaration of the entity.
|
||||
Decl *getKeyDeclaration(Decl *D) {
|
||||
D = D->getCanonicalDecl();
|
||||
if (D->isFromASTFile())
|
||||
return D;
|
||||
|
||||
auto I = KeyDecls.find(D);
|
||||
if (I == KeyDecls.end() || I->second.empty())
|
||||
return D;
|
||||
return GetExistingDecl(I->second[0]);
|
||||
}
|
||||
const Decl *getKeyDeclaration(const Decl *D) {
|
||||
return getKeyDeclaration(const_cast<Decl*>(D));
|
||||
}
|
||||
|
||||
/// \brief Run a callback on each imported key declaration of \p D.
|
||||
template <typename Fn>
|
||||
void forEachImportedKeyDecl(const Decl *D, Fn Visit) {
|
||||
D = D->getCanonicalDecl();
|
||||
if (D->isFromASTFile())
|
||||
Visit(D);
|
||||
|
||||
auto It = KeyDecls.find(const_cast<Decl*>(D));
|
||||
if (It != KeyDecls.end())
|
||||
for (auto ID : It->second)
|
||||
Visit(GetExistingDecl(ID));
|
||||
}
|
||||
|
||||
private:
|
||||
struct ImportedModule {
|
||||
ModuleFile *Mod;
|
||||
@ -1124,18 +1160,6 @@ class ASTReader
|
||||
/// merged into its redecl chain.
|
||||
Decl *getMostRecentExistingDecl(Decl *D);
|
||||
|
||||
template <typename Fn>
|
||||
void forEachFormerlyCanonicalImportedDecl(const Decl *D, Fn Visit) {
|
||||
D = D->getCanonicalDecl();
|
||||
if (D->isFromASTFile())
|
||||
Visit(D);
|
||||
|
||||
auto It = MergedDecls.find(const_cast<Decl*>(D));
|
||||
if (It != MergedDecls.end())
|
||||
for (auto ID : It->second)
|
||||
Visit(GetExistingDecl(ID));
|
||||
}
|
||||
|
||||
RecordLocation DeclCursorForID(serialization::DeclID ID,
|
||||
unsigned &RawLocation);
|
||||
void loadDeclUpdateRecords(serialization::DeclID ID, Decl *D);
|
||||
@ -1261,12 +1285,16 @@ class ASTReader
|
||||
///
|
||||
/// \param UseGlobalIndex If true, the AST reader will try to load and use
|
||||
/// the global module index.
|
||||
///
|
||||
/// \param ReadTimer If non-null, a timer used to track the time spent
|
||||
/// deserializing.
|
||||
ASTReader(Preprocessor &PP, ASTContext &Context,
|
||||
const PCHContainerOperations &PCHContainerOps,
|
||||
StringRef isysroot = "", bool DisableValidation = false,
|
||||
bool AllowASTWithCompilerErrors = false,
|
||||
bool AllowConfigurationMismatch = false,
|
||||
bool ValidateSystemInputs = false, bool UseGlobalIndex = true);
|
||||
bool ValidateSystemInputs = false, bool UseGlobalIndex = true,
|
||||
std::unique_ptr<llvm::Timer> ReadTimer = {});
|
||||
|
||||
~ASTReader() override;
|
||||
|
||||
@ -1690,7 +1718,7 @@ class ASTReader
|
||||
/// \brief Notify ASTReader that we started deserialization of
|
||||
/// a decl or type so until FinishedDeserializing is called there may be
|
||||
/// decls that are initializing. Must be paired with FinishedDeserializing.
|
||||
void StartedDeserializing() override { ++NumCurrentElementsDeserializing; }
|
||||
void StartedDeserializing() override;
|
||||
|
||||
/// \brief Notify ASTReader that we finished the deserialization of
|
||||
/// a decl or type. Must be paired with StartedDeserializing.
|
||||
|
@ -398,7 +398,7 @@ class ASTWriter : public ASTDeserializationListener,
|
||||
|
||||
/// \brief The set of declarations that may have redeclaration chains that
|
||||
/// need to be serialized.
|
||||
llvm::SmallSetVector<Decl *, 4> Redeclarations;
|
||||
llvm::SmallVector<const Decl *, 16> Redeclarations;
|
||||
|
||||
/// \brief Statements that we've encountered while serializing a
|
||||
/// declaration or type.
|
||||
|
@ -64,6 +64,9 @@
|
||||
#endif
|
||||
|
||||
namespace clang {
|
||||
class DiagnosticsEngine;
|
||||
class AnalyzerOptions;
|
||||
|
||||
namespace ento {
|
||||
|
||||
class CheckerOptInfo;
|
||||
@ -118,6 +121,10 @@ class CheckerRegistry {
|
||||
void initializeManager(CheckerManager &mgr,
|
||||
SmallVectorImpl<CheckerOptInfo> &opts) const;
|
||||
|
||||
/// Check if every option corresponds to a specific checker or package.
|
||||
void validateCheckerOptions(const AnalyzerOptions &opts,
|
||||
DiagnosticsEngine &diags) const;
|
||||
|
||||
/// Prints the name and description of all checkers in this registry.
|
||||
/// This output is not intended to be machine-parseable.
|
||||
void printHelp(raw_ostream &out, size_t maxNameChars = 30) const ;
|
||||
|
@ -1917,11 +1917,7 @@ void ASTContext::CollectInheritedProtocols(const Decl *CDecl,
|
||||
// We can use protocol_iterator here instead of
|
||||
// all_referenced_protocol_iterator since we are walking all categories.
|
||||
for (auto *Proto : OI->all_referenced_protocols()) {
|
||||
Protocols.insert(Proto->getCanonicalDecl());
|
||||
for (auto *P : Proto->protocols()) {
|
||||
Protocols.insert(P->getCanonicalDecl());
|
||||
CollectInheritedProtocols(P, Protocols);
|
||||
}
|
||||
CollectInheritedProtocols(Proto, Protocols);
|
||||
}
|
||||
|
||||
// Categories of this Interface.
|
||||
@ -1935,16 +1931,16 @@ void ASTContext::CollectInheritedProtocols(const Decl *CDecl,
|
||||
}
|
||||
} else if (const ObjCCategoryDecl *OC = dyn_cast<ObjCCategoryDecl>(CDecl)) {
|
||||
for (auto *Proto : OC->protocols()) {
|
||||
Protocols.insert(Proto->getCanonicalDecl());
|
||||
for (const auto *P : Proto->protocols())
|
||||
CollectInheritedProtocols(P, Protocols);
|
||||
CollectInheritedProtocols(Proto, Protocols);
|
||||
}
|
||||
} else if (const ObjCProtocolDecl *OP = dyn_cast<ObjCProtocolDecl>(CDecl)) {
|
||||
for (auto *Proto : OP->protocols()) {
|
||||
Protocols.insert(Proto->getCanonicalDecl());
|
||||
for (const auto *P : Proto->protocols())
|
||||
CollectInheritedProtocols(P, Protocols);
|
||||
}
|
||||
// Insert the protocol.
|
||||
if (!Protocols.insert(
|
||||
const_cast<ObjCProtocolDecl *>(OP->getCanonicalDecl())).second)
|
||||
return;
|
||||
|
||||
for (auto *Proto : OP->protocols())
|
||||
CollectInheritedProtocols(Proto, Protocols);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3618,45 +3614,89 @@ static void SortAndUniqueProtocols(ObjCProtocolDecl **Protocols,
|
||||
QualType ASTContext::getObjCObjectType(QualType BaseType,
|
||||
ObjCProtocolDecl * const *Protocols,
|
||||
unsigned NumProtocols) const {
|
||||
// If the base type is an interface and there aren't any protocols
|
||||
// to add, then the interface type will do just fine.
|
||||
if (!NumProtocols && isa<ObjCInterfaceType>(BaseType))
|
||||
return BaseType;
|
||||
return getObjCObjectType(BaseType, { },
|
||||
llvm::makeArrayRef(Protocols, NumProtocols),
|
||||
/*isKindOf=*/false);
|
||||
}
|
||||
|
||||
QualType ASTContext::getObjCObjectType(
|
||||
QualType baseType,
|
||||
ArrayRef<QualType> typeArgs,
|
||||
ArrayRef<ObjCProtocolDecl *> protocols,
|
||||
bool isKindOf) const {
|
||||
// If the base type is an interface and there aren't any protocols or
|
||||
// type arguments to add, then the interface type will do just fine.
|
||||
if (typeArgs.empty() && protocols.empty() && !isKindOf &&
|
||||
isa<ObjCInterfaceType>(baseType))
|
||||
return baseType;
|
||||
|
||||
// Look in the folding set for an existing type.
|
||||
llvm::FoldingSetNodeID ID;
|
||||
ObjCObjectTypeImpl::Profile(ID, BaseType, Protocols, NumProtocols);
|
||||
ObjCObjectTypeImpl::Profile(ID, baseType, typeArgs, protocols, isKindOf);
|
||||
void *InsertPos = nullptr;
|
||||
if (ObjCObjectType *QT = ObjCObjectTypes.FindNodeOrInsertPos(ID, InsertPos))
|
||||
return QualType(QT, 0);
|
||||
|
||||
// Build the canonical type, which has the canonical base type and
|
||||
// a sorted-and-uniqued list of protocols.
|
||||
QualType Canonical;
|
||||
bool ProtocolsSorted = areSortedAndUniqued(Protocols, NumProtocols);
|
||||
if (!ProtocolsSorted || !BaseType.isCanonical()) {
|
||||
if (!ProtocolsSorted) {
|
||||
SmallVector<ObjCProtocolDecl*, 8> Sorted(Protocols,
|
||||
Protocols + NumProtocols);
|
||||
unsigned UniqueCount = NumProtocols;
|
||||
// Determine the type arguments to be used for canonicalization,
|
||||
// which may be explicitly specified here or written on the base
|
||||
// type.
|
||||
ArrayRef<QualType> effectiveTypeArgs = typeArgs;
|
||||
if (effectiveTypeArgs.empty()) {
|
||||
if (auto baseObject = baseType->getAs<ObjCObjectType>())
|
||||
effectiveTypeArgs = baseObject->getTypeArgs();
|
||||
}
|
||||
|
||||
SortAndUniqueProtocols(&Sorted[0], UniqueCount);
|
||||
Canonical = getObjCObjectType(getCanonicalType(BaseType),
|
||||
&Sorted[0], UniqueCount);
|
||||
// Build the canonical type, which has the canonical base type and a
|
||||
// sorted-and-uniqued list of protocols and the type arguments
|
||||
// canonicalized.
|
||||
QualType canonical;
|
||||
bool typeArgsAreCanonical = std::all_of(effectiveTypeArgs.begin(),
|
||||
effectiveTypeArgs.end(),
|
||||
[&](QualType type) {
|
||||
return type.isCanonical();
|
||||
});
|
||||
bool protocolsSorted = areSortedAndUniqued(protocols.data(),
|
||||
protocols.size());
|
||||
if (!typeArgsAreCanonical || !protocolsSorted || !baseType.isCanonical()) {
|
||||
// Determine the canonical type arguments.
|
||||
ArrayRef<QualType> canonTypeArgs;
|
||||
SmallVector<QualType, 4> canonTypeArgsVec;
|
||||
if (!typeArgsAreCanonical) {
|
||||
canonTypeArgsVec.reserve(effectiveTypeArgs.size());
|
||||
for (auto typeArg : effectiveTypeArgs)
|
||||
canonTypeArgsVec.push_back(getCanonicalType(typeArg));
|
||||
canonTypeArgs = canonTypeArgsVec;
|
||||
} else {
|
||||
Canonical = getObjCObjectType(getCanonicalType(BaseType),
|
||||
Protocols, NumProtocols);
|
||||
canonTypeArgs = effectiveTypeArgs;
|
||||
}
|
||||
|
||||
ArrayRef<ObjCProtocolDecl *> canonProtocols;
|
||||
SmallVector<ObjCProtocolDecl*, 8> canonProtocolsVec;
|
||||
if (!protocolsSorted) {
|
||||
canonProtocolsVec.insert(canonProtocolsVec.begin(),
|
||||
protocols.begin(),
|
||||
protocols.end());
|
||||
unsigned uniqueCount = protocols.size();
|
||||
SortAndUniqueProtocols(&canonProtocolsVec[0], uniqueCount);
|
||||
canonProtocols = llvm::makeArrayRef(&canonProtocolsVec[0], uniqueCount);
|
||||
} else {
|
||||
canonProtocols = protocols;
|
||||
}
|
||||
|
||||
canonical = getObjCObjectType(getCanonicalType(baseType), canonTypeArgs,
|
||||
canonProtocols, isKindOf);
|
||||
|
||||
// Regenerate InsertPos.
|
||||
ObjCObjectTypes.FindNodeOrInsertPos(ID, InsertPos);
|
||||
}
|
||||
|
||||
unsigned Size = sizeof(ObjCObjectTypeImpl);
|
||||
Size += NumProtocols * sizeof(ObjCProtocolDecl *);
|
||||
void *Mem = Allocate(Size, TypeAlignment);
|
||||
unsigned size = sizeof(ObjCObjectTypeImpl);
|
||||
size += typeArgs.size() * sizeof(QualType);
|
||||
size += protocols.size() * sizeof(ObjCProtocolDecl *);
|
||||
void *mem = Allocate(size, TypeAlignment);
|
||||
ObjCObjectTypeImpl *T =
|
||||
new (Mem) ObjCObjectTypeImpl(Canonical, BaseType, Protocols, NumProtocols);
|
||||
new (mem) ObjCObjectTypeImpl(canonical, baseType, typeArgs, protocols,
|
||||
isKindOf);
|
||||
|
||||
Types.push_back(T);
|
||||
ObjCObjectTypes.InsertNode(T, InsertPos);
|
||||
@ -5623,13 +5663,8 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
|
||||
|
||||
case Type::ObjCInterface: {
|
||||
// Ignore protocol qualifiers when mangling at this level.
|
||||
T = T->castAs<ObjCObjectType>()->getBaseType();
|
||||
|
||||
// The assumption seems to be that this assert will succeed
|
||||
// because nested levels will have filtered out 'id' and 'Class'.
|
||||
const ObjCInterfaceType *OIT = T->castAs<ObjCInterfaceType>();
|
||||
// @encode(class_name)
|
||||
ObjCInterfaceDecl *OI = OIT->getDecl();
|
||||
ObjCInterfaceDecl *OI = T->castAs<ObjCObjectType>()->getInterface();
|
||||
S += '{';
|
||||
S += OI->getObjCRuntimeNameAsString();
|
||||
S += '=';
|
||||
@ -5921,7 +5956,7 @@ void ASTContext::getObjCEncodingForTypeQualifier(Decl::ObjCDeclQualifier QT,
|
||||
|
||||
TypedefDecl *ASTContext::getObjCIdDecl() const {
|
||||
if (!ObjCIdDecl) {
|
||||
QualType T = getObjCObjectType(ObjCBuiltinIdTy, nullptr, 0);
|
||||
QualType T = getObjCObjectType(ObjCBuiltinIdTy, { }, { });
|
||||
T = getObjCObjectPointerType(T);
|
||||
ObjCIdDecl = buildImplicitTypedef(T, "id");
|
||||
}
|
||||
@ -5938,7 +5973,7 @@ TypedefDecl *ASTContext::getObjCSelDecl() const {
|
||||
|
||||
TypedefDecl *ASTContext::getObjCClassDecl() const {
|
||||
if (!ObjCClassDecl) {
|
||||
QualType T = getObjCObjectType(ObjCBuiltinClassTy, nullptr, 0);
|
||||
QualType T = getObjCObjectType(ObjCBuiltinClassTy, { }, { });
|
||||
T = getObjCObjectPointerType(T);
|
||||
ObjCClassDecl = buildImplicitTypedef(T, "Class");
|
||||
}
|
||||
@ -5951,6 +5986,7 @@ ObjCInterfaceDecl *ASTContext::getObjCProtocolDecl() const {
|
||||
= ObjCInterfaceDecl::Create(*this, getTranslationUnitDecl(),
|
||||
SourceLocation(),
|
||||
&Idents.get("Protocol"),
|
||||
/*typeParamList=*/nullptr,
|
||||
/*PrevDecl=*/nullptr,
|
||||
SourceLocation(), true);
|
||||
}
|
||||
@ -6743,18 +6779,36 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCObjectPointerType *LHSOPT,
|
||||
RHS->isObjCUnqualifiedIdOrClass())
|
||||
return true;
|
||||
|
||||
if (LHS->isObjCQualifiedId() || RHS->isObjCQualifiedId())
|
||||
return ObjCQualifiedIdTypesAreCompatible(QualType(LHSOPT,0),
|
||||
QualType(RHSOPT,0),
|
||||
false);
|
||||
// Function object that propagates a successful result or handles
|
||||
// __kindof types.
|
||||
auto finish = [&](bool succeeded) -> bool {
|
||||
if (succeeded)
|
||||
return true;
|
||||
|
||||
if (!RHS->isKindOfType())
|
||||
return false;
|
||||
|
||||
// Strip off __kindof and protocol qualifiers, then check whether
|
||||
// we can assign the other way.
|
||||
return canAssignObjCInterfaces(RHSOPT->stripObjCKindOfTypeAndQuals(*this),
|
||||
LHSOPT->stripObjCKindOfTypeAndQuals(*this));
|
||||
};
|
||||
|
||||
if (LHS->isObjCQualifiedId() || RHS->isObjCQualifiedId()) {
|
||||
return finish(ObjCQualifiedIdTypesAreCompatible(QualType(LHSOPT,0),
|
||||
QualType(RHSOPT,0),
|
||||
false));
|
||||
}
|
||||
|
||||
if (LHS->isObjCQualifiedClass() && RHS->isObjCQualifiedClass())
|
||||
return ObjCQualifiedClassTypesAreCompatible(QualType(LHSOPT,0),
|
||||
QualType(RHSOPT,0));
|
||||
if (LHS->isObjCQualifiedClass() && RHS->isObjCQualifiedClass()) {
|
||||
return finish(ObjCQualifiedClassTypesAreCompatible(QualType(LHSOPT,0),
|
||||
QualType(RHSOPT,0)));
|
||||
}
|
||||
|
||||
// If we have 2 user-defined types, fall into that path.
|
||||
if (LHS->getInterface() && RHS->getInterface())
|
||||
return canAssignObjCInterfaces(LHS, RHS);
|
||||
if (LHS->getInterface() && RHS->getInterface()) {
|
||||
return finish(canAssignObjCInterfaces(LHS, RHS));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -6768,26 +6822,46 @@ bool ASTContext::canAssignObjCInterfacesInBlockPointer(
|
||||
const ObjCObjectPointerType *LHSOPT,
|
||||
const ObjCObjectPointerType *RHSOPT,
|
||||
bool BlockReturnType) {
|
||||
|
||||
// Function object that propagates a successful result or handles
|
||||
// __kindof types.
|
||||
auto finish = [&](bool succeeded) -> bool {
|
||||
if (succeeded)
|
||||
return true;
|
||||
|
||||
const ObjCObjectPointerType *Expected = BlockReturnType ? RHSOPT : LHSOPT;
|
||||
if (!Expected->isKindOfType())
|
||||
return false;
|
||||
|
||||
// Strip off __kindof and protocol qualifiers, then check whether
|
||||
// we can assign the other way.
|
||||
return canAssignObjCInterfacesInBlockPointer(
|
||||
RHSOPT->stripObjCKindOfTypeAndQuals(*this),
|
||||
LHSOPT->stripObjCKindOfTypeAndQuals(*this),
|
||||
BlockReturnType);
|
||||
};
|
||||
|
||||
if (RHSOPT->isObjCBuiltinType() || LHSOPT->isObjCIdType())
|
||||
return true;
|
||||
|
||||
if (LHSOPT->isObjCBuiltinType()) {
|
||||
return RHSOPT->isObjCBuiltinType() || RHSOPT->isObjCQualifiedIdType();
|
||||
return finish(RHSOPT->isObjCBuiltinType() ||
|
||||
RHSOPT->isObjCQualifiedIdType());
|
||||
}
|
||||
|
||||
if (LHSOPT->isObjCQualifiedIdType() || RHSOPT->isObjCQualifiedIdType())
|
||||
return ObjCQualifiedIdTypesAreCompatible(QualType(LHSOPT,0),
|
||||
QualType(RHSOPT,0),
|
||||
false);
|
||||
return finish(ObjCQualifiedIdTypesAreCompatible(QualType(LHSOPT,0),
|
||||
QualType(RHSOPT,0),
|
||||
false));
|
||||
|
||||
const ObjCInterfaceType* LHS = LHSOPT->getInterfaceType();
|
||||
const ObjCInterfaceType* RHS = RHSOPT->getInterfaceType();
|
||||
if (LHS && RHS) { // We have 2 user-defined types.
|
||||
if (LHS != RHS) {
|
||||
if (LHS->getDecl()->isSuperClassOf(RHS->getDecl()))
|
||||
return BlockReturnType;
|
||||
return finish(BlockReturnType);
|
||||
if (RHS->getDecl()->isSuperClassOf(LHS->getDecl()))
|
||||
return !BlockReturnType;
|
||||
return finish(!BlockReturnType);
|
||||
}
|
||||
else
|
||||
return true;
|
||||
@ -6795,78 +6869,253 @@ bool ASTContext::canAssignObjCInterfacesInBlockPointer(
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Comparison routine for Objective-C protocols to be used with
|
||||
/// llvm::array_pod_sort.
|
||||
static int compareObjCProtocolsByName(ObjCProtocolDecl * const *lhs,
|
||||
ObjCProtocolDecl * const *rhs) {
|
||||
return (*lhs)->getName().compare((*rhs)->getName());
|
||||
|
||||
}
|
||||
|
||||
/// getIntersectionOfProtocols - This routine finds the intersection of set
|
||||
/// of protocols inherited from two distinct objective-c pointer objects.
|
||||
/// of protocols inherited from two distinct objective-c pointer objects with
|
||||
/// the given common base.
|
||||
/// It is used to build composite qualifier list of the composite type of
|
||||
/// the conditional expression involving two objective-c pointer objects.
|
||||
static
|
||||
void getIntersectionOfProtocols(ASTContext &Context,
|
||||
const ObjCInterfaceDecl *CommonBase,
|
||||
const ObjCObjectPointerType *LHSOPT,
|
||||
const ObjCObjectPointerType *RHSOPT,
|
||||
SmallVectorImpl<ObjCProtocolDecl *> &IntersectionOfProtocols) {
|
||||
SmallVectorImpl<ObjCProtocolDecl *> &IntersectionSet) {
|
||||
|
||||
const ObjCObjectType* LHS = LHSOPT->getObjectType();
|
||||
const ObjCObjectType* RHS = RHSOPT->getObjectType();
|
||||
assert(LHS->getInterface() && "LHS must have an interface base");
|
||||
assert(RHS->getInterface() && "RHS must have an interface base");
|
||||
|
||||
llvm::SmallPtrSet<ObjCProtocolDecl *, 8> InheritedProtocolSet;
|
||||
unsigned LHSNumProtocols = LHS->getNumProtocols();
|
||||
if (LHSNumProtocols > 0)
|
||||
InheritedProtocolSet.insert(LHS->qual_begin(), LHS->qual_end());
|
||||
else {
|
||||
llvm::SmallPtrSet<ObjCProtocolDecl *, 8> LHSInheritedProtocols;
|
||||
Context.CollectInheritedProtocols(LHS->getInterface(),
|
||||
LHSInheritedProtocols);
|
||||
InheritedProtocolSet.insert(LHSInheritedProtocols.begin(),
|
||||
LHSInheritedProtocols.end());
|
||||
|
||||
// Add all of the protocols for the LHS.
|
||||
llvm::SmallPtrSet<ObjCProtocolDecl *, 8> LHSProtocolSet;
|
||||
|
||||
// Start with the protocol qualifiers.
|
||||
for (auto proto : LHS->quals()) {
|
||||
Context.CollectInheritedProtocols(proto, LHSProtocolSet);
|
||||
}
|
||||
|
||||
unsigned RHSNumProtocols = RHS->getNumProtocols();
|
||||
if (RHSNumProtocols > 0) {
|
||||
ObjCProtocolDecl **RHSProtocols =
|
||||
const_cast<ObjCProtocolDecl **>(RHS->qual_begin());
|
||||
for (unsigned i = 0; i < RHSNumProtocols; ++i)
|
||||
if (InheritedProtocolSet.count(RHSProtocols[i]))
|
||||
IntersectionOfProtocols.push_back(RHSProtocols[i]);
|
||||
} else {
|
||||
llvm::SmallPtrSet<ObjCProtocolDecl *, 8> RHSInheritedProtocols;
|
||||
Context.CollectInheritedProtocols(RHS->getInterface(),
|
||||
RHSInheritedProtocols);
|
||||
for (ObjCProtocolDecl *ProtDecl : RHSInheritedProtocols)
|
||||
if (InheritedProtocolSet.count(ProtDecl))
|
||||
IntersectionOfProtocols.push_back(ProtDecl);
|
||||
|
||||
// Also add the protocols associated with the LHS interface.
|
||||
Context.CollectInheritedProtocols(LHS->getInterface(), LHSProtocolSet);
|
||||
|
||||
// Add all of the protocls for the RHS.
|
||||
llvm::SmallPtrSet<ObjCProtocolDecl *, 8> RHSProtocolSet;
|
||||
|
||||
// Start with the protocol qualifiers.
|
||||
for (auto proto : RHS->quals()) {
|
||||
Context.CollectInheritedProtocols(proto, RHSProtocolSet);
|
||||
}
|
||||
|
||||
// Also add the protocols associated with the RHS interface.
|
||||
Context.CollectInheritedProtocols(RHS->getInterface(), RHSProtocolSet);
|
||||
|
||||
// Compute the intersection of the collected protocol sets.
|
||||
for (auto proto : LHSProtocolSet) {
|
||||
if (RHSProtocolSet.count(proto))
|
||||
IntersectionSet.push_back(proto);
|
||||
}
|
||||
|
||||
// Compute the set of protocols that is implied by either the common type or
|
||||
// the protocols within the intersection.
|
||||
llvm::SmallPtrSet<ObjCProtocolDecl *, 8> ImpliedProtocols;
|
||||
Context.CollectInheritedProtocols(CommonBase, ImpliedProtocols);
|
||||
|
||||
// Remove any implied protocols from the list of inherited protocols.
|
||||
if (!ImpliedProtocols.empty()) {
|
||||
IntersectionSet.erase(
|
||||
std::remove_if(IntersectionSet.begin(),
|
||||
IntersectionSet.end(),
|
||||
[&](ObjCProtocolDecl *proto) -> bool {
|
||||
return ImpliedProtocols.count(proto) > 0;
|
||||
}),
|
||||
IntersectionSet.end());
|
||||
}
|
||||
|
||||
// Sort the remaining protocols by name.
|
||||
llvm::array_pod_sort(IntersectionSet.begin(), IntersectionSet.end(),
|
||||
compareObjCProtocolsByName);
|
||||
}
|
||||
|
||||
/// Determine whether the first type is a subtype of the second.
|
||||
static bool canAssignObjCObjectTypes(ASTContext &ctx, QualType lhs,
|
||||
QualType rhs) {
|
||||
// Common case: two object pointers.
|
||||
const ObjCObjectPointerType *lhsOPT = lhs->getAs<ObjCObjectPointerType>();
|
||||
const ObjCObjectPointerType *rhsOPT = rhs->getAs<ObjCObjectPointerType>();
|
||||
if (lhsOPT && rhsOPT)
|
||||
return ctx.canAssignObjCInterfaces(lhsOPT, rhsOPT);
|
||||
|
||||
// Two block pointers.
|
||||
const BlockPointerType *lhsBlock = lhs->getAs<BlockPointerType>();
|
||||
const BlockPointerType *rhsBlock = rhs->getAs<BlockPointerType>();
|
||||
if (lhsBlock && rhsBlock)
|
||||
return ctx.typesAreBlockPointerCompatible(lhs, rhs);
|
||||
|
||||
// If either is an unqualified 'id' and the other is a block, it's
|
||||
// acceptable.
|
||||
if ((lhsOPT && lhsOPT->isObjCIdType() && rhsBlock) ||
|
||||
(rhsOPT && rhsOPT->isObjCIdType() && lhsBlock))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check that the given Objective-C type argument lists are equivalent.
|
||||
static bool sameObjCTypeArgs(ASTContext &ctx,
|
||||
const ObjCInterfaceDecl *iface,
|
||||
ArrayRef<QualType> lhsArgs,
|
||||
ArrayRef<QualType> rhsArgs,
|
||||
bool stripKindOf) {
|
||||
if (lhsArgs.size() != rhsArgs.size())
|
||||
return false;
|
||||
|
||||
ObjCTypeParamList *typeParams = iface->getTypeParamList();
|
||||
for (unsigned i = 0, n = lhsArgs.size(); i != n; ++i) {
|
||||
if (ctx.hasSameType(lhsArgs[i], rhsArgs[i]))
|
||||
continue;
|
||||
|
||||
switch (typeParams->begin()[i]->getVariance()) {
|
||||
case ObjCTypeParamVariance::Invariant:
|
||||
if (!stripKindOf ||
|
||||
!ctx.hasSameType(lhsArgs[i].stripObjCKindOfType(ctx),
|
||||
rhsArgs[i].stripObjCKindOfType(ctx))) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case ObjCTypeParamVariance::Covariant:
|
||||
if (!canAssignObjCObjectTypes(ctx, lhsArgs[i], rhsArgs[i]))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case ObjCTypeParamVariance::Contravariant:
|
||||
if (!canAssignObjCObjectTypes(ctx, rhsArgs[i], lhsArgs[i]))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// areCommonBaseCompatible - Returns common base class of the two classes if
|
||||
/// one found. Note that this is O'2 algorithm. But it will be called as the
|
||||
/// last type comparison in a ?-exp of ObjC pointer types before a
|
||||
/// warning is issued. So, its invokation is extremely rare.
|
||||
QualType ASTContext::areCommonBaseCompatible(
|
||||
const ObjCObjectPointerType *Lptr,
|
||||
const ObjCObjectPointerType *Rptr) {
|
||||
const ObjCObjectPointerType *Lptr,
|
||||
const ObjCObjectPointerType *Rptr) {
|
||||
const ObjCObjectType *LHS = Lptr->getObjectType();
|
||||
const ObjCObjectType *RHS = Rptr->getObjectType();
|
||||
const ObjCInterfaceDecl* LDecl = LHS->getInterface();
|
||||
const ObjCInterfaceDecl* RDecl = RHS->getInterface();
|
||||
if (!LDecl || !RDecl || (declaresSameEntity(LDecl, RDecl)))
|
||||
return QualType();
|
||||
|
||||
do {
|
||||
LHS = cast<ObjCInterfaceType>(getObjCInterfaceType(LDecl));
|
||||
if (canAssignObjCInterfaces(LHS, RHS)) {
|
||||
SmallVector<ObjCProtocolDecl *, 8> Protocols;
|
||||
getIntersectionOfProtocols(*this, Lptr, Rptr, Protocols);
|
||||
|
||||
QualType Result = QualType(LHS, 0);
|
||||
if (!LDecl || !RDecl)
|
||||
return QualType();
|
||||
|
||||
// Follow the left-hand side up the class hierarchy until we either hit a
|
||||
// root or find the RHS. Record the ancestors in case we don't find it.
|
||||
llvm::SmallDenseMap<const ObjCInterfaceDecl *, const ObjCObjectType *, 4>
|
||||
LHSAncestors;
|
||||
while (true) {
|
||||
// Record this ancestor. We'll need this if the common type isn't in the
|
||||
// path from the LHS to the root.
|
||||
LHSAncestors[LHS->getInterface()->getCanonicalDecl()] = LHS;
|
||||
|
||||
if (declaresSameEntity(LHS->getInterface(), RDecl)) {
|
||||
// Get the type arguments.
|
||||
ArrayRef<QualType> LHSTypeArgs = LHS->getTypeArgsAsWritten();
|
||||
bool anyChanges = false;
|
||||
if (LHS->isSpecialized() && RHS->isSpecialized()) {
|
||||
// Both have type arguments, compare them.
|
||||
if (!sameObjCTypeArgs(*this, LHS->getInterface(),
|
||||
LHS->getTypeArgs(), RHS->getTypeArgs(),
|
||||
/*stripKindOf=*/true))
|
||||
return QualType();
|
||||
} else if (LHS->isSpecialized() != RHS->isSpecialized()) {
|
||||
// If only one has type arguments, the result will not have type
|
||||
// arguments.
|
||||
LHSTypeArgs = { };
|
||||
anyChanges = true;
|
||||
}
|
||||
|
||||
// Compute the intersection of protocols.
|
||||
SmallVector<ObjCProtocolDecl *, 8> Protocols;
|
||||
getIntersectionOfProtocols(*this, LHS->getInterface(), Lptr, Rptr,
|
||||
Protocols);
|
||||
if (!Protocols.empty())
|
||||
Result = getObjCObjectType(Result, Protocols.data(), Protocols.size());
|
||||
Result = getObjCObjectPointerType(Result);
|
||||
return Result;
|
||||
anyChanges = true;
|
||||
|
||||
// If anything in the LHS will have changed, build a new result type.
|
||||
if (anyChanges) {
|
||||
QualType Result = getObjCInterfaceType(LHS->getInterface());
|
||||
Result = getObjCObjectType(Result, LHSTypeArgs, Protocols,
|
||||
LHS->isKindOfType());
|
||||
return getObjCObjectPointerType(Result);
|
||||
}
|
||||
|
||||
return getObjCObjectPointerType(QualType(LHS, 0));
|
||||
}
|
||||
} while ((LDecl = LDecl->getSuperClass()));
|
||||
|
||||
|
||||
// Find the superclass.
|
||||
QualType LHSSuperType = LHS->getSuperClassType();
|
||||
if (LHSSuperType.isNull())
|
||||
break;
|
||||
|
||||
LHS = LHSSuperType->castAs<ObjCObjectType>();
|
||||
}
|
||||
|
||||
// We didn't find anything by following the LHS to its root; now check
|
||||
// the RHS against the cached set of ancestors.
|
||||
while (true) {
|
||||
auto KnownLHS = LHSAncestors.find(RHS->getInterface()->getCanonicalDecl());
|
||||
if (KnownLHS != LHSAncestors.end()) {
|
||||
LHS = KnownLHS->second;
|
||||
|
||||
// Get the type arguments.
|
||||
ArrayRef<QualType> RHSTypeArgs = RHS->getTypeArgsAsWritten();
|
||||
bool anyChanges = false;
|
||||
if (LHS->isSpecialized() && RHS->isSpecialized()) {
|
||||
// Both have type arguments, compare them.
|
||||
if (!sameObjCTypeArgs(*this, LHS->getInterface(),
|
||||
LHS->getTypeArgs(), RHS->getTypeArgs(),
|
||||
/*stripKindOf=*/true))
|
||||
return QualType();
|
||||
} else if (LHS->isSpecialized() != RHS->isSpecialized()) {
|
||||
// If only one has type arguments, the result will not have type
|
||||
// arguments.
|
||||
RHSTypeArgs = { };
|
||||
anyChanges = true;
|
||||
}
|
||||
|
||||
// Compute the intersection of protocols.
|
||||
SmallVector<ObjCProtocolDecl *, 8> Protocols;
|
||||
getIntersectionOfProtocols(*this, RHS->getInterface(), Lptr, Rptr,
|
||||
Protocols);
|
||||
if (!Protocols.empty())
|
||||
anyChanges = true;
|
||||
|
||||
if (anyChanges) {
|
||||
QualType Result = getObjCInterfaceType(RHS->getInterface());
|
||||
Result = getObjCObjectType(Result, RHSTypeArgs, Protocols,
|
||||
RHS->isKindOfType());
|
||||
return getObjCObjectPointerType(Result);
|
||||
}
|
||||
|
||||
return getObjCObjectPointerType(QualType(RHS, 0));
|
||||
}
|
||||
|
||||
// Find the superclass of the RHS.
|
||||
QualType RHSSuperType = RHS->getSuperClassType();
|
||||
if (RHSSuperType.isNull())
|
||||
break;
|
||||
|
||||
RHS = RHSSuperType->castAs<ObjCObjectType>();
|
||||
}
|
||||
|
||||
return QualType();
|
||||
}
|
||||
|
||||
@ -6877,21 +7126,15 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCObjectType *LHS,
|
||||
|
||||
// Verify that the base decls are compatible: the RHS must be a subclass of
|
||||
// the LHS.
|
||||
if (!LHS->getInterface()->isSuperClassOf(RHS->getInterface()))
|
||||
ObjCInterfaceDecl *LHSInterface = LHS->getInterface();
|
||||
bool IsSuperClass = LHSInterface->isSuperClassOf(RHS->getInterface());
|
||||
if (!IsSuperClass)
|
||||
return false;
|
||||
|
||||
// RHS must have a superset of the protocols in the LHS. If the LHS is not
|
||||
// protocol qualified at all, then we are good.
|
||||
if (LHS->getNumProtocols() == 0)
|
||||
return true;
|
||||
|
||||
// Okay, we know the LHS has protocol qualifiers. But RHS may or may not.
|
||||
// More detailed analysis is required.
|
||||
// OK, if LHS is same or a superclass of RHS *and*
|
||||
// this LHS, or as RHS's super class is assignment compatible with LHS.
|
||||
bool IsSuperClass =
|
||||
LHS->getInterface()->isSuperClassOf(RHS->getInterface());
|
||||
if (IsSuperClass) {
|
||||
// If the LHS has protocol qualifiers, determine whether all of them are
|
||||
// satisfied by the RHS (i.e., the RHS has a superset of the protocols in the
|
||||
// LHS).
|
||||
if (LHS->getNumProtocols() > 0) {
|
||||
// OK if conversion of LHS to SuperClass results in narrowing of types
|
||||
// ; i.e., SuperClass may implement at least one of the protocols
|
||||
// in LHS's protocol list. Example, SuperObj<P1> = lhs<P1,P2> is ok.
|
||||
@ -6901,7 +7144,7 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCObjectType *LHS,
|
||||
// Also, if RHS has explicit quelifiers, include them for comparing with LHS's
|
||||
// qualifiers.
|
||||
for (auto *RHSPI : RHS->quals())
|
||||
SuperClassInheritedProtocols.insert(RHSPI->getCanonicalDecl());
|
||||
CollectInheritedProtocols(RHSPI, SuperClassInheritedProtocols);
|
||||
// If there is no protocols associated with RHS, it is not a match.
|
||||
if (SuperClassInheritedProtocols.empty())
|
||||
return false;
|
||||
@ -6916,9 +7159,26 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCObjectType *LHS,
|
||||
if (!SuperImplementsProtocol)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
// If the LHS is specialized, we may need to check type arguments.
|
||||
if (LHS->isSpecialized()) {
|
||||
// Follow the superclass chain until we've matched the LHS class in the
|
||||
// hierarchy. This substitutes type arguments through.
|
||||
const ObjCObjectType *RHSSuper = RHS;
|
||||
while (!declaresSameEntity(RHSSuper->getInterface(), LHSInterface))
|
||||
RHSSuper = RHSSuper->getSuperClassType()->castAs<ObjCObjectType>();
|
||||
|
||||
// If the RHS is specializd, compare type arguments.
|
||||
if (RHSSuper->isSpecialized() &&
|
||||
!sameObjCTypeArgs(*this, LHS->getInterface(),
|
||||
LHS->getTypeArgs(), RHSSuper->getTypeArgs(),
|
||||
/*stripKindOf=*/true)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ASTContext::areComparableObjCPointerTypes(QualType LHS, QualType RHS) {
|
||||
|
@ -125,12 +125,23 @@ break; \
|
||||
if (const PointerType *Ty = QT->getAs<PointerType>()) {
|
||||
QT = Context.getPointerType(Desugar(Context, Ty->getPointeeType(),
|
||||
ShouldAKA));
|
||||
} else if (const auto *Ty = QT->getAs<ObjCObjectPointerType>()) {
|
||||
QT = Context.getObjCObjectPointerType(Desugar(Context, Ty->getPointeeType(),
|
||||
ShouldAKA));
|
||||
} else if (const LValueReferenceType *Ty = QT->getAs<LValueReferenceType>()) {
|
||||
QT = Context.getLValueReferenceType(Desugar(Context, Ty->getPointeeType(),
|
||||
ShouldAKA));
|
||||
} else if (const RValueReferenceType *Ty = QT->getAs<RValueReferenceType>()) {
|
||||
QT = Context.getRValueReferenceType(Desugar(Context, Ty->getPointeeType(),
|
||||
ShouldAKA));
|
||||
} else if (const auto *Ty = QT->getAs<ObjCObjectType>()) {
|
||||
if (Ty->getBaseType().getTypePtr() != Ty && !ShouldAKA) {
|
||||
QualType BaseType = Desugar(Context, Ty->getBaseType(), ShouldAKA);
|
||||
QT = Context.getObjCObjectType(BaseType, Ty->getTypeArgsAsWritten(),
|
||||
llvm::makeArrayRef(Ty->qual_begin(),
|
||||
Ty->getNumProtocols()),
|
||||
Ty->isKindOfTypeAsWritten());
|
||||
}
|
||||
}
|
||||
|
||||
return QC.apply(Context, QT);
|
||||
@ -181,8 +192,8 @@ ConvertTypeToDiagnosticString(ASTContext &Context, QualType Ty,
|
||||
if (CompareCanTy == CanTy)
|
||||
continue; // Same canonical types
|
||||
std::string CompareS = CompareTy.getAsString(Context.getPrintingPolicy());
|
||||
bool aka;
|
||||
QualType CompareDesugar = Desugar(Context, CompareTy, aka);
|
||||
bool ShouldAKA = false;
|
||||
QualType CompareDesugar = Desugar(Context, CompareTy, ShouldAKA);
|
||||
std::string CompareDesugarStr =
|
||||
CompareDesugar.getAsString(Context.getPrintingPolicy());
|
||||
if (CompareS != S && CompareDesugarStr != S)
|
||||
|
@ -240,6 +240,9 @@ namespace {
|
||||
void dumpTemplateArgument(const TemplateArgument &A,
|
||||
SourceRange R = SourceRange());
|
||||
|
||||
// Objective-C utilities.
|
||||
void dumpObjCTypeParamList(const ObjCTypeParamList *typeParams);
|
||||
|
||||
// Types
|
||||
void VisitComplexType(const ComplexType *T) {
|
||||
dumpTypeAsChild(T->getElementType());
|
||||
@ -463,6 +466,7 @@ namespace {
|
||||
// ObjC Decls
|
||||
void VisitObjCIvarDecl(const ObjCIvarDecl *D);
|
||||
void VisitObjCMethodDecl(const ObjCMethodDecl *D);
|
||||
void VisitObjCTypeParamDecl(const ObjCTypeParamDecl *D);
|
||||
void VisitObjCCategoryDecl(const ObjCCategoryDecl *D);
|
||||
void VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D);
|
||||
void VisitObjCProtocolDecl(const ObjCProtocolDecl *D);
|
||||
@ -954,6 +958,18 @@ void ASTDumper::dumpTemplateArgument(const TemplateArgument &A, SourceRange R) {
|
||||
});
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Objective-C Utilities
|
||||
//===----------------------------------------------------------------------===//
|
||||
void ASTDumper::dumpObjCTypeParamList(const ObjCTypeParamList *typeParams) {
|
||||
if (!typeParams)
|
||||
return;
|
||||
|
||||
for (auto typeParam : *typeParams) {
|
||||
dumpDecl(typeParam);
|
||||
}
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Decl dumping methods.
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -1457,9 +1473,30 @@ void ASTDumper::VisitObjCMethodDecl(const ObjCMethodDecl *D) {
|
||||
dumpStmt(D->getBody());
|
||||
}
|
||||
|
||||
void ASTDumper::VisitObjCTypeParamDecl(const ObjCTypeParamDecl *D) {
|
||||
dumpName(D);
|
||||
switch (D->getVariance()) {
|
||||
case ObjCTypeParamVariance::Invariant:
|
||||
break;
|
||||
|
||||
case ObjCTypeParamVariance::Covariant:
|
||||
OS << " covariant";
|
||||
break;
|
||||
|
||||
case ObjCTypeParamVariance::Contravariant:
|
||||
OS << " contravariant";
|
||||
break;
|
||||
}
|
||||
|
||||
if (D->hasExplicitBound())
|
||||
OS << " bounded";
|
||||
dumpType(D->getUnderlyingType());
|
||||
}
|
||||
|
||||
void ASTDumper::VisitObjCCategoryDecl(const ObjCCategoryDecl *D) {
|
||||
dumpName(D);
|
||||
dumpDeclRef(D->getClassInterface());
|
||||
dumpObjCTypeParamList(D->getTypeParamList());
|
||||
dumpDeclRef(D->getImplementation());
|
||||
for (ObjCCategoryDecl::protocol_iterator I = D->protocol_begin(),
|
||||
E = D->protocol_end();
|
||||
@ -1482,6 +1519,7 @@ void ASTDumper::VisitObjCProtocolDecl(const ObjCProtocolDecl *D) {
|
||||
|
||||
void ASTDumper::VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) {
|
||||
dumpName(D);
|
||||
dumpObjCTypeParamList(D->getTypeParamListAsWritten());
|
||||
dumpDeclRef(D->getSuperClass(), "super");
|
||||
|
||||
dumpDeclRef(D->getImplementation());
|
||||
|
@ -150,9 +150,12 @@ namespace clang {
|
||||
Decl *VisitImplicitParamDecl(ImplicitParamDecl *D);
|
||||
Decl *VisitParmVarDecl(ParmVarDecl *D);
|
||||
Decl *VisitObjCMethodDecl(ObjCMethodDecl *D);
|
||||
Decl *VisitObjCTypeParamDecl(ObjCTypeParamDecl *D);
|
||||
Decl *VisitObjCCategoryDecl(ObjCCategoryDecl *D);
|
||||
Decl *VisitObjCProtocolDecl(ObjCProtocolDecl *D);
|
||||
Decl *VisitLinkageSpecDecl(LinkageSpecDecl *D);
|
||||
|
||||
ObjCTypeParamList *ImportObjCTypeParamList(ObjCTypeParamList *list);
|
||||
Decl *VisitObjCInterfaceDecl(ObjCInterfaceDecl *D);
|
||||
Decl *VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D);
|
||||
Decl *VisitObjCImplementationDecl(ObjCImplementationDecl *D);
|
||||
@ -1841,6 +1844,15 @@ QualType ASTNodeImporter::VisitObjCObjectType(const ObjCObjectType *T) {
|
||||
if (ToBaseType.isNull())
|
||||
return QualType();
|
||||
|
||||
SmallVector<QualType, 4> TypeArgs;
|
||||
for (auto TypeArg : T->getTypeArgsAsWritten()) {
|
||||
QualType ImportedTypeArg = Importer.Import(TypeArg);
|
||||
if (ImportedTypeArg.isNull())
|
||||
return QualType();
|
||||
|
||||
TypeArgs.push_back(ImportedTypeArg);
|
||||
}
|
||||
|
||||
SmallVector<ObjCProtocolDecl *, 4> Protocols;
|
||||
for (auto *P : T->quals()) {
|
||||
ObjCProtocolDecl *Protocol
|
||||
@ -1850,9 +1862,9 @@ QualType ASTNodeImporter::VisitObjCObjectType(const ObjCObjectType *T) {
|
||||
Protocols.push_back(Protocol);
|
||||
}
|
||||
|
||||
return Importer.getToContext().getObjCObjectType(ToBaseType,
|
||||
Protocols.data(),
|
||||
Protocols.size());
|
||||
return Importer.getToContext().getObjCObjectType(ToBaseType, TypeArgs,
|
||||
Protocols,
|
||||
T->isKindOfTypeAsWritten());
|
||||
}
|
||||
|
||||
QualType
|
||||
@ -3423,6 +3435,35 @@ Decl *ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
|
||||
return ToMethod;
|
||||
}
|
||||
|
||||
Decl *ASTNodeImporter::VisitObjCTypeParamDecl(ObjCTypeParamDecl *D) {
|
||||
// Import the major distinguishing characteristics of a category.
|
||||
DeclContext *DC, *LexicalDC;
|
||||
DeclarationName Name;
|
||||
SourceLocation Loc;
|
||||
NamedDecl *ToD;
|
||||
if (ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc))
|
||||
return nullptr;
|
||||
if (ToD)
|
||||
return ToD;
|
||||
|
||||
TypeSourceInfo *BoundInfo = Importer.Import(D->getTypeSourceInfo());
|
||||
if (!BoundInfo)
|
||||
return nullptr;
|
||||
|
||||
ObjCTypeParamDecl *Result = ObjCTypeParamDecl::Create(
|
||||
Importer.getToContext(), DC,
|
||||
D->getVariance(),
|
||||
Importer.Import(D->getVarianceLoc()),
|
||||
D->getIndex(),
|
||||
Importer.Import(D->getLocation()),
|
||||
Name.getAsIdentifierInfo(),
|
||||
Importer.Import(D->getColonLoc()),
|
||||
BoundInfo);
|
||||
Importer.Imported(D, Result);
|
||||
Result->setLexicalDeclContext(LexicalDC);
|
||||
return Result;
|
||||
}
|
||||
|
||||
Decl *ASTNodeImporter::VisitObjCCategoryDecl(ObjCCategoryDecl *D) {
|
||||
// Import the major distinguishing characteristics of a category.
|
||||
DeclContext *DC, *LexicalDC;
|
||||
@ -3450,11 +3491,16 @@ Decl *ASTNodeImporter::VisitObjCCategoryDecl(ObjCCategoryDecl *D) {
|
||||
Importer.Import(D->getCategoryNameLoc()),
|
||||
Name.getAsIdentifierInfo(),
|
||||
ToInterface,
|
||||
/*TypeParamList=*/nullptr,
|
||||
Importer.Import(D->getIvarLBraceLoc()),
|
||||
Importer.Import(D->getIvarRBraceLoc()));
|
||||
ToCategory->setLexicalDeclContext(LexicalDC);
|
||||
LexicalDC->addDeclInternal(ToCategory);
|
||||
Importer.Imported(D, ToCategory);
|
||||
// Import the type parameter list after calling Imported, to avoid
|
||||
// loops when bringing in their DeclContext.
|
||||
ToCategory->setTypeParamList(ImportObjCTypeParamList(
|
||||
D->getTypeParamList()));
|
||||
|
||||
// Import protocols
|
||||
SmallVector<ObjCProtocolDecl *, 4> Protocols;
|
||||
@ -3663,13 +3709,11 @@ bool ASTNodeImporter::ImportDefinition(ObjCInterfaceDecl *From,
|
||||
|
||||
// If this class has a superclass, import it.
|
||||
if (From->getSuperClass()) {
|
||||
ObjCInterfaceDecl *Super = cast_or_null<ObjCInterfaceDecl>(
|
||||
Importer.Import(From->getSuperClass()));
|
||||
if (!Super)
|
||||
TypeSourceInfo *SuperTInfo = Importer.Import(From->getSuperClassTInfo());
|
||||
if (!SuperTInfo)
|
||||
return true;
|
||||
|
||||
To->setSuperClass(Super);
|
||||
To->setSuperClassLoc(Importer.Import(From->getSuperClassLoc()));
|
||||
|
||||
To->setSuperClass(SuperTInfo);
|
||||
}
|
||||
|
||||
// Import protocols
|
||||
@ -3716,6 +3760,27 @@ bool ASTNodeImporter::ImportDefinition(ObjCInterfaceDecl *From,
|
||||
return false;
|
||||
}
|
||||
|
||||
ObjCTypeParamList *
|
||||
ASTNodeImporter::ImportObjCTypeParamList(ObjCTypeParamList *list) {
|
||||
if (!list)
|
||||
return nullptr;
|
||||
|
||||
SmallVector<ObjCTypeParamDecl *, 4> toTypeParams;
|
||||
for (auto fromTypeParam : *list) {
|
||||
auto toTypeParam = cast_or_null<ObjCTypeParamDecl>(
|
||||
Importer.Import(fromTypeParam));
|
||||
if (!toTypeParam)
|
||||
return nullptr;
|
||||
|
||||
toTypeParams.push_back(toTypeParam);
|
||||
}
|
||||
|
||||
return ObjCTypeParamList::create(Importer.getToContext(),
|
||||
Importer.Import(list->getLAngleLoc()),
|
||||
toTypeParams,
|
||||
Importer.Import(list->getRAngleLoc()));
|
||||
}
|
||||
|
||||
Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
|
||||
// If this class has a definition in the translation unit we're coming from,
|
||||
// but this particular declaration is not that definition, import the
|
||||
@ -3756,13 +3821,18 @@ Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
|
||||
if (!ToIface) {
|
||||
ToIface = ObjCInterfaceDecl::Create(Importer.getToContext(), DC,
|
||||
Importer.Import(D->getAtStartLoc()),
|
||||
Name.getAsIdentifierInfo(),
|
||||
Name.getAsIdentifierInfo(),
|
||||
/*TypeParamList=*/nullptr,
|
||||
/*PrevDecl=*/nullptr, Loc,
|
||||
D->isImplicitInterfaceDecl());
|
||||
ToIface->setLexicalDeclContext(LexicalDC);
|
||||
LexicalDC->addDeclInternal(ToIface);
|
||||
}
|
||||
Importer.Imported(D, ToIface);
|
||||
// Import the type parameter list after calling Imported, to avoid
|
||||
// loops when bringing in their DeclContext.
|
||||
ToIface->setTypeParamList(ImportObjCTypeParamList(
|
||||
D->getTypeParamListAsWritten()));
|
||||
|
||||
if (D->isThisDeclarationADefinition() && ImportDefinition(D, ToIface))
|
||||
return nullptr;
|
||||
@ -5313,7 +5383,7 @@ TypeSourceInfo *ASTImporter::Import(TypeSourceInfo *FromTSI) {
|
||||
return nullptr;
|
||||
|
||||
return ToContext.getTrivialTypeSourceInfo(T,
|
||||
FromTSI->getTypeLoc().getLocStart());
|
||||
Import(FromTSI->getTypeLoc().getLocStart()));
|
||||
}
|
||||
|
||||
Decl *ASTImporter::GetAlreadyImportedOrNull(Decl *FromD) {
|
||||
|
@ -1803,15 +1803,19 @@ void VarDecl::setStorageClass(StorageClass SC) {
|
||||
VarDecl::TLSKind VarDecl::getTLSKind() const {
|
||||
switch (VarDeclBits.TSCSpec) {
|
||||
case TSCS_unspecified:
|
||||
if (!hasAttr<ThreadAttr>())
|
||||
if (!hasAttr<ThreadAttr>() &&
|
||||
!(getASTContext().getLangOpts().OpenMPUseTLS &&
|
||||
getASTContext().getTargetInfo().isTLSSupported() &&
|
||||
hasAttr<OMPThreadPrivateDeclAttr>()))
|
||||
return TLS_None;
|
||||
return getASTContext().getLangOpts().isCompatibleWithMSVC(
|
||||
LangOptions::MSVC2015)
|
||||
return ((getASTContext().getLangOpts().isCompatibleWithMSVC(
|
||||
LangOptions::MSVC2015)) ||
|
||||
hasAttr<OMPThreadPrivateDeclAttr>())
|
||||
? TLS_Dynamic
|
||||
: TLS_Static;
|
||||
case TSCS___thread: // Fall through.
|
||||
case TSCS__Thread_local:
|
||||
return TLS_Static;
|
||||
return TLS_Static;
|
||||
case TSCS_thread_local:
|
||||
return TLS_Dynamic;
|
||||
}
|
||||
@ -2712,7 +2716,7 @@ bool FunctionDecl::isMSExternInline() const {
|
||||
|
||||
for (const FunctionDecl *FD = getMostRecentDecl(); FD;
|
||||
FD = FD->getPreviousDecl())
|
||||
if (FD->getStorageClass() == SC_Extern)
|
||||
if (!FD->isImplicit() && FD->getStorageClass() == SC_Extern)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
@ -2724,7 +2728,7 @@ static bool redeclForcesDefMSVC(const FunctionDecl *Redecl) {
|
||||
|
||||
for (const FunctionDecl *FD = Redecl->getPreviousDecl(); FD;
|
||||
FD = FD->getPreviousDecl())
|
||||
if (FD->getStorageClass() == SC_Extern)
|
||||
if (!FD->isImplicit() && FD->getStorageClass() == SC_Extern)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
@ -561,6 +561,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
|
||||
case TypeAliasTemplate:
|
||||
case UnresolvedUsingTypename:
|
||||
case TemplateTypeParm:
|
||||
case ObjCTypeParam:
|
||||
return IDNS_Ordinary | IDNS_Type;
|
||||
|
||||
case UsingShadow:
|
||||
|
@ -1272,7 +1272,7 @@ const CXXRecordDecl *CXXRecordDecl::getTemplateInstantiationPattern() const {
|
||||
break;
|
||||
CTD = NewCTD;
|
||||
}
|
||||
return CTD->getTemplatedDecl();
|
||||
return CTD->getTemplatedDecl()->getDefinition();
|
||||
}
|
||||
if (auto *CTPSD =
|
||||
From.dyn_cast<ClassTemplatePartialSpecializationDecl *>()) {
|
||||
@ -1281,7 +1281,7 @@ const CXXRecordDecl *CXXRecordDecl::getTemplateInstantiationPattern() const {
|
||||
break;
|
||||
CTPSD = NewCTPSD;
|
||||
}
|
||||
return CTPSD;
|
||||
return CTPSD->getDefinition();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1290,7 +1290,7 @@ const CXXRecordDecl *CXXRecordDecl::getTemplateInstantiationPattern() const {
|
||||
const CXXRecordDecl *RD = this;
|
||||
while (auto *NewRD = RD->getInstantiatedFromMemberClass())
|
||||
RD = NewRD;
|
||||
return RD;
|
||||
return RD->getDefinition();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -239,6 +239,62 @@ ObjCPropertyDecl *ObjCContainerDecl::FindPropertyDeclaration(
|
||||
|
||||
void ObjCInterfaceDecl::anchor() { }
|
||||
|
||||
ObjCTypeParamList *ObjCInterfaceDecl::getTypeParamList() const {
|
||||
// If this particular declaration has a type parameter list, return it.
|
||||
if (ObjCTypeParamList *written = getTypeParamListAsWritten())
|
||||
return written;
|
||||
|
||||
// If there is a definition, return its type parameter list.
|
||||
if (const ObjCInterfaceDecl *def = getDefinition())
|
||||
return def->getTypeParamListAsWritten();
|
||||
|
||||
// Otherwise, look at previous declarations to determine whether any
|
||||
// of them has a type parameter list, skipping over those
|
||||
// declarations that do not.
|
||||
for (auto decl = getMostRecentDecl(); decl; decl = decl->getPreviousDecl()) {
|
||||
if (ObjCTypeParamList *written = decl->getTypeParamListAsWritten())
|
||||
return written;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ObjCInterfaceDecl::setTypeParamList(ObjCTypeParamList *TPL) {
|
||||
TypeParamList = TPL;
|
||||
if (!TPL)
|
||||
return;
|
||||
// Set the declaration context of each of the type parameters.
|
||||
for (auto typeParam : *TypeParamList)
|
||||
typeParam->setDeclContext(this);
|
||||
}
|
||||
|
||||
ObjCInterfaceDecl *ObjCInterfaceDecl::getSuperClass() const {
|
||||
// FIXME: Should make sure no callers ever do this.
|
||||
if (!hasDefinition())
|
||||
return nullptr;
|
||||
|
||||
if (data().ExternallyCompleted)
|
||||
LoadExternalDefinition();
|
||||
|
||||
if (const ObjCObjectType *superType = getSuperClassType()) {
|
||||
if (ObjCInterfaceDecl *superDecl = superType->getInterface()) {
|
||||
if (ObjCInterfaceDecl *superDef = superDecl->getDefinition())
|
||||
return superDef;
|
||||
|
||||
return superDecl;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SourceLocation ObjCInterfaceDecl::getSuperClassLoc() const {
|
||||
if (TypeSourceInfo *superTInfo = getSuperClassTInfo())
|
||||
return superTInfo->getTypeLoc().getLocStart();
|
||||
|
||||
return SourceLocation();
|
||||
}
|
||||
|
||||
/// FindPropertyVisibleInPrimaryClass - Finds declaration of the property
|
||||
/// with name 'PropertyId' in the primary class; including those in protocols
|
||||
/// (direct or indirect) used by the primary class.
|
||||
@ -889,9 +945,13 @@ ObjCMethodFamily ObjCMethodDecl::getMethodFamily() const {
|
||||
return family;
|
||||
}
|
||||
|
||||
void ObjCMethodDecl::createImplicitParams(ASTContext &Context,
|
||||
const ObjCInterfaceDecl *OID) {
|
||||
QualType ObjCMethodDecl::getSelfType(ASTContext &Context,
|
||||
const ObjCInterfaceDecl *OID,
|
||||
bool &selfIsPseudoStrong,
|
||||
bool &selfIsConsumed) {
|
||||
QualType selfTy;
|
||||
selfIsPseudoStrong = false;
|
||||
selfIsConsumed = false;
|
||||
if (isInstanceMethod()) {
|
||||
// There may be no interface context due to error in declaration
|
||||
// of the interface (which has been reported). Recover gracefully.
|
||||
@ -904,9 +964,6 @@ void ObjCMethodDecl::createImplicitParams(ASTContext &Context,
|
||||
} else // we have a factory method.
|
||||
selfTy = Context.getObjCClassType();
|
||||
|
||||
bool selfIsPseudoStrong = false;
|
||||
bool selfIsConsumed = false;
|
||||
|
||||
if (Context.getLangOpts().ObjCAutoRefCount) {
|
||||
if (isInstanceMethod()) {
|
||||
selfIsConsumed = hasAttr<NSConsumesSelfAttr>();
|
||||
@ -930,7 +987,14 @@ void ObjCMethodDecl::createImplicitParams(ASTContext &Context,
|
||||
selfIsPseudoStrong = true;
|
||||
}
|
||||
}
|
||||
return selfTy;
|
||||
}
|
||||
|
||||
void ObjCMethodDecl::createImplicitParams(ASTContext &Context,
|
||||
const ObjCInterfaceDecl *OID) {
|
||||
bool selfIsPseudoStrong, selfIsConsumed;
|
||||
QualType selfTy =
|
||||
getSelfType(Context, OID, selfIsPseudoStrong, selfIsConsumed);
|
||||
ImplicitParamDecl *self
|
||||
= ImplicitParamDecl::Create(Context, this, SourceLocation(),
|
||||
&Context.Idents.get("self"), selfTy);
|
||||
@ -966,6 +1030,20 @@ SourceRange ObjCMethodDecl::getReturnTypeSourceRange() const {
|
||||
return SourceRange();
|
||||
}
|
||||
|
||||
QualType ObjCMethodDecl::getSendResultType() const {
|
||||
ASTContext &Ctx = getASTContext();
|
||||
return getReturnType().getNonLValueExprType(Ctx)
|
||||
.substObjCTypeArgs(Ctx, {}, ObjCSubstitutionContext::Result);
|
||||
}
|
||||
|
||||
QualType ObjCMethodDecl::getSendResultType(QualType receiverType) const {
|
||||
// FIXME: Handle related result types here.
|
||||
|
||||
return getReturnType().getNonLValueExprType(getASTContext())
|
||||
.substObjCMemberType(receiverType, getDeclContext(),
|
||||
ObjCSubstitutionContext::Result);
|
||||
}
|
||||
|
||||
static void CollectOverriddenMethodsRecurse(const ObjCContainerDecl *Container,
|
||||
const ObjCMethodDecl *Method,
|
||||
SmallVectorImpl<const ObjCMethodDecl *> &Methods,
|
||||
@ -1136,6 +1214,81 @@ ObjCMethodDecl::findPropertyDecl(bool CheckOverrides) const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// ObjCTypeParamDecl
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void ObjCTypeParamDecl::anchor() { }
|
||||
|
||||
ObjCTypeParamDecl *ObjCTypeParamDecl::Create(ASTContext &ctx, DeclContext *dc,
|
||||
ObjCTypeParamVariance variance,
|
||||
SourceLocation varianceLoc,
|
||||
unsigned index,
|
||||
SourceLocation nameLoc,
|
||||
IdentifierInfo *name,
|
||||
SourceLocation colonLoc,
|
||||
TypeSourceInfo *boundInfo) {
|
||||
return new (ctx, dc) ObjCTypeParamDecl(ctx, dc, variance, varianceLoc, index,
|
||||
nameLoc, name, colonLoc, boundInfo);
|
||||
}
|
||||
|
||||
ObjCTypeParamDecl *ObjCTypeParamDecl::CreateDeserialized(ASTContext &ctx,
|
||||
unsigned ID) {
|
||||
return new (ctx, ID) ObjCTypeParamDecl(ctx, nullptr,
|
||||
ObjCTypeParamVariance::Invariant,
|
||||
SourceLocation(), 0, SourceLocation(),
|
||||
nullptr, SourceLocation(), nullptr);
|
||||
}
|
||||
|
||||
SourceRange ObjCTypeParamDecl::getSourceRange() const {
|
||||
SourceLocation startLoc = VarianceLoc;
|
||||
if (startLoc.isInvalid())
|
||||
startLoc = getLocation();
|
||||
|
||||
if (hasExplicitBound()) {
|
||||
return SourceRange(startLoc,
|
||||
getTypeSourceInfo()->getTypeLoc().getEndLoc());
|
||||
}
|
||||
|
||||
return SourceRange(startLoc);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// ObjCTypeParamList
|
||||
//===----------------------------------------------------------------------===//
|
||||
ObjCTypeParamList::ObjCTypeParamList(SourceLocation lAngleLoc,
|
||||
ArrayRef<ObjCTypeParamDecl *> typeParams,
|
||||
SourceLocation rAngleLoc)
|
||||
: NumParams(typeParams.size())
|
||||
{
|
||||
Brackets.Begin = lAngleLoc.getRawEncoding();
|
||||
Brackets.End = rAngleLoc.getRawEncoding();
|
||||
std::copy(typeParams.begin(), typeParams.end(), begin());
|
||||
}
|
||||
|
||||
|
||||
ObjCTypeParamList *ObjCTypeParamList::create(
|
||||
ASTContext &ctx,
|
||||
SourceLocation lAngleLoc,
|
||||
ArrayRef<ObjCTypeParamDecl *> typeParams,
|
||||
SourceLocation rAngleLoc) {
|
||||
unsigned size = sizeof(ObjCTypeParamList)
|
||||
+ sizeof(ObjCTypeParamDecl *) * typeParams.size();
|
||||
static_assert(llvm::AlignOf<ObjCTypeParamList>::Alignment >=
|
||||
llvm::AlignOf<ObjCTypeParamDecl *>::Alignment,
|
||||
"type parameter list needs greater alignment");
|
||||
unsigned align = llvm::alignOf<ObjCTypeParamList>();
|
||||
void *mem = ctx.Allocate(size, align);
|
||||
return new (mem) ObjCTypeParamList(lAngleLoc, typeParams, rAngleLoc);
|
||||
}
|
||||
|
||||
void ObjCTypeParamList::gatherDefaultTypeArgs(
|
||||
SmallVectorImpl<QualType> &typeArgs) const {
|
||||
typeArgs.reserve(size());
|
||||
for (auto typeParam : *this)
|
||||
typeArgs.push_back(typeParam->getUnderlyingType());
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// ObjCInterfaceDecl
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -1144,11 +1297,13 @@ ObjCInterfaceDecl *ObjCInterfaceDecl::Create(const ASTContext &C,
|
||||
DeclContext *DC,
|
||||
SourceLocation atLoc,
|
||||
IdentifierInfo *Id,
|
||||
ObjCTypeParamList *typeParamList,
|
||||
ObjCInterfaceDecl *PrevDecl,
|
||||
SourceLocation ClassLoc,
|
||||
bool isInternal){
|
||||
ObjCInterfaceDecl *Result = new (C, DC)
|
||||
ObjCInterfaceDecl(C, DC, atLoc, Id, ClassLoc, PrevDecl, isInternal);
|
||||
ObjCInterfaceDecl(C, DC, atLoc, Id, typeParamList, ClassLoc, PrevDecl,
|
||||
isInternal);
|
||||
Result->Data.setInt(!C.getLangOpts().Modules);
|
||||
C.getObjCInterfaceType(Result, PrevDecl);
|
||||
return Result;
|
||||
@ -1159,6 +1314,7 @@ ObjCInterfaceDecl *ObjCInterfaceDecl::CreateDeserialized(const ASTContext &C,
|
||||
ObjCInterfaceDecl *Result = new (C, ID) ObjCInterfaceDecl(C, nullptr,
|
||||
SourceLocation(),
|
||||
nullptr,
|
||||
nullptr,
|
||||
SourceLocation(),
|
||||
nullptr, false);
|
||||
Result->Data.setInt(!C.getLangOpts().Modules);
|
||||
@ -1167,11 +1323,13 @@ ObjCInterfaceDecl *ObjCInterfaceDecl::CreateDeserialized(const ASTContext &C,
|
||||
|
||||
ObjCInterfaceDecl::ObjCInterfaceDecl(const ASTContext &C, DeclContext *DC,
|
||||
SourceLocation AtLoc, IdentifierInfo *Id,
|
||||
ObjCTypeParamList *typeParamList,
|
||||
SourceLocation CLoc,
|
||||
ObjCInterfaceDecl *PrevDecl,
|
||||
bool IsInternal)
|
||||
: ObjCContainerDecl(ObjCInterface, DC, Id, CLoc, AtLoc),
|
||||
redeclarable_base(C), TypeForDecl(nullptr), Data() {
|
||||
redeclarable_base(C), TypeForDecl(nullptr), TypeParamList(nullptr),
|
||||
Data() {
|
||||
setPreviousDecl(PrevDecl);
|
||||
|
||||
// Copy the 'data' pointer over.
|
||||
@ -1179,6 +1337,8 @@ ObjCInterfaceDecl::ObjCInterfaceDecl(const ASTContext &C, DeclContext *DC,
|
||||
Data = PrevDecl->Data;
|
||||
|
||||
setImplicit(IsInternal);
|
||||
|
||||
setTypeParamList(typeParamList);
|
||||
}
|
||||
|
||||
void ObjCInterfaceDecl::LoadExternalDefinition() const {
|
||||
@ -1492,6 +1652,11 @@ const ObjCInterfaceDecl *ObjCIvarDecl::getContainingInterface() const {
|
||||
}
|
||||
}
|
||||
|
||||
QualType ObjCIvarDecl::getUsageType(QualType objectType) const {
|
||||
return getType().substObjCMemberType(objectType, getDeclContext(),
|
||||
ObjCSubstitutionContext::Property);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// ObjCAtDefsFieldDecl
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -1648,17 +1813,34 @@ ObjCProtocolDecl::getObjCRuntimeNameAsString() const {
|
||||
|
||||
void ObjCCategoryDecl::anchor() { }
|
||||
|
||||
ObjCCategoryDecl::ObjCCategoryDecl(DeclContext *DC, SourceLocation AtLoc,
|
||||
SourceLocation ClassNameLoc,
|
||||
SourceLocation CategoryNameLoc,
|
||||
IdentifierInfo *Id, ObjCInterfaceDecl *IDecl,
|
||||
ObjCTypeParamList *typeParamList,
|
||||
SourceLocation IvarLBraceLoc,
|
||||
SourceLocation IvarRBraceLoc)
|
||||
: ObjCContainerDecl(ObjCCategory, DC, Id, ClassNameLoc, AtLoc),
|
||||
ClassInterface(IDecl), TypeParamList(nullptr),
|
||||
NextClassCategory(nullptr), CategoryNameLoc(CategoryNameLoc),
|
||||
IvarLBraceLoc(IvarLBraceLoc), IvarRBraceLoc(IvarRBraceLoc)
|
||||
{
|
||||
setTypeParamList(typeParamList);
|
||||
}
|
||||
|
||||
ObjCCategoryDecl *ObjCCategoryDecl::Create(ASTContext &C, DeclContext *DC,
|
||||
SourceLocation AtLoc,
|
||||
SourceLocation ClassNameLoc,
|
||||
SourceLocation CategoryNameLoc,
|
||||
IdentifierInfo *Id,
|
||||
ObjCInterfaceDecl *IDecl,
|
||||
ObjCTypeParamList *typeParamList,
|
||||
SourceLocation IvarLBraceLoc,
|
||||
SourceLocation IvarRBraceLoc) {
|
||||
ObjCCategoryDecl *CatDecl =
|
||||
new (C, DC) ObjCCategoryDecl(DC, AtLoc, ClassNameLoc, CategoryNameLoc, Id,
|
||||
IDecl, IvarLBraceLoc, IvarRBraceLoc);
|
||||
IDecl, typeParamList, IvarLBraceLoc,
|
||||
IvarRBraceLoc);
|
||||
if (IDecl) {
|
||||
// Link this category into its class's category list.
|
||||
CatDecl->NextClassCategory = IDecl->getCategoryListRaw();
|
||||
@ -1676,7 +1858,7 @@ ObjCCategoryDecl *ObjCCategoryDecl::CreateDeserialized(ASTContext &C,
|
||||
unsigned ID) {
|
||||
return new (C, ID) ObjCCategoryDecl(nullptr, SourceLocation(),
|
||||
SourceLocation(), SourceLocation(),
|
||||
nullptr, nullptr);
|
||||
nullptr, nullptr, nullptr);
|
||||
}
|
||||
|
||||
ObjCCategoryImplDecl *ObjCCategoryDecl::getImplementation() const {
|
||||
@ -1688,6 +1870,15 @@ void ObjCCategoryDecl::setImplementation(ObjCCategoryImplDecl *ImplD) {
|
||||
getASTContext().setObjCImplementation(this, ImplD);
|
||||
}
|
||||
|
||||
void ObjCCategoryDecl::setTypeParamList(ObjCTypeParamList *TPL) {
|
||||
TypeParamList = TPL;
|
||||
if (!TPL)
|
||||
return;
|
||||
// Set the declaration context of each of the type parameters.
|
||||
for (auto typeParam : *TypeParamList)
|
||||
typeParam->setDeclContext(this);
|
||||
}
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// ObjCCategoryImplDecl
|
||||
@ -1876,6 +2067,11 @@ ObjCPropertyDecl *ObjCPropertyDecl::CreateDeserialized(ASTContext &C,
|
||||
QualType(), nullptr, None);
|
||||
}
|
||||
|
||||
QualType ObjCPropertyDecl::getUsageType(QualType objectType) const {
|
||||
return DeclType.substObjCMemberType(objectType, getDeclContext(),
|
||||
ObjCSubstitutionContext::Property);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// ObjCPropertyImplDecl
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -44,6 +44,8 @@ namespace {
|
||||
void PrintObjCMethodType(ASTContext &Ctx, Decl::ObjCDeclQualifier Quals,
|
||||
QualType T);
|
||||
|
||||
void PrintObjCTypeParams(ObjCTypeParamList *Params);
|
||||
|
||||
public:
|
||||
DeclPrinter(raw_ostream &Out, const PrintingPolicy &Policy,
|
||||
unsigned Indentation = 0, bool PrintInstantiation = false)
|
||||
@ -962,6 +964,38 @@ void DeclPrinter::PrintObjCMethodType(ASTContext &Ctx,
|
||||
Out << ')';
|
||||
}
|
||||
|
||||
void DeclPrinter::PrintObjCTypeParams(ObjCTypeParamList *Params) {
|
||||
Out << "<";
|
||||
unsigned First = true;
|
||||
for (auto *Param : *Params) {
|
||||
if (First) {
|
||||
First = false;
|
||||
} else {
|
||||
Out << ", ";
|
||||
}
|
||||
|
||||
switch (Param->getVariance()) {
|
||||
case ObjCTypeParamVariance::Invariant:
|
||||
break;
|
||||
|
||||
case ObjCTypeParamVariance::Covariant:
|
||||
Out << "__covariant ";
|
||||
break;
|
||||
|
||||
case ObjCTypeParamVariance::Contravariant:
|
||||
Out << "__contravariant ";
|
||||
break;
|
||||
}
|
||||
|
||||
Out << Param->getDeclName().getAsString();
|
||||
|
||||
if (Param->hasExplicitBound()) {
|
||||
Out << " : " << Param->getUnderlyingType().getAsString(Policy);
|
||||
}
|
||||
}
|
||||
Out << ">";
|
||||
}
|
||||
|
||||
void DeclPrinter::VisitObjCMethodDecl(ObjCMethodDecl *OMD) {
|
||||
if (OMD->isInstanceMethod())
|
||||
Out << "- ";
|
||||
@ -1037,14 +1071,24 @@ void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) {
|
||||
ObjCInterfaceDecl *SID = OID->getSuperClass();
|
||||
|
||||
if (!OID->isThisDeclarationADefinition()) {
|
||||
Out << "@class " << I << ";";
|
||||
Out << "@class " << I;
|
||||
|
||||
if (auto TypeParams = OID->getTypeParamListAsWritten()) {
|
||||
PrintObjCTypeParams(TypeParams);
|
||||
}
|
||||
|
||||
Out << ";";
|
||||
return;
|
||||
}
|
||||
bool eolnOut = false;
|
||||
Out << "@interface " << I;
|
||||
|
||||
if (auto TypeParams = OID->getTypeParamListAsWritten()) {
|
||||
PrintObjCTypeParams(TypeParams);
|
||||
}
|
||||
|
||||
if (SID)
|
||||
Out << "@interface " << I << " : " << *SID;
|
||||
else
|
||||
Out << "@interface " << I;
|
||||
Out << " : " << OID->getSuperClass()->getName();
|
||||
|
||||
// Protocols?
|
||||
const ObjCList<ObjCProtocolDecl> &Protocols = OID->getReferencedProtocols();
|
||||
@ -1107,7 +1151,11 @@ void DeclPrinter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *PID) {
|
||||
}
|
||||
|
||||
void DeclPrinter::VisitObjCCategoryDecl(ObjCCategoryDecl *PID) {
|
||||
Out << "@interface " << *PID->getClassInterface() << '(' << *PID << ")\n";
|
||||
Out << "@interface " << *PID->getClassInterface();
|
||||
if (auto TypeParams = PID->getTypeParamList()) {
|
||||
PrintObjCTypeParams(TypeParams);
|
||||
}
|
||||
Out << "(" << *PID << ")\n";
|
||||
if (PID->ivar_size() > 0) {
|
||||
Out << "{\n";
|
||||
Indentation += Policy.Indentation;
|
||||
|
@ -3748,6 +3748,16 @@ ObjCInterfaceDecl *ObjCMessageExpr::getReceiverInterface() const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QualType ObjCPropertyRefExpr::getReceiverType(const ASTContext &ctx) const {
|
||||
if (isClassReceiver())
|
||||
return ctx.getObjCInterfaceType(getClassReceiver());
|
||||
|
||||
if (isSuperReceiver())
|
||||
return getSuperReceiverType();
|
||||
|
||||
return getBase()->getType();
|
||||
}
|
||||
|
||||
StringRef ObjCBridgedCastExpr::getBridgeKindName() const {
|
||||
switch (getBridgeKind()) {
|
||||
case OBC_Bridge:
|
||||
|
@ -2379,6 +2379,10 @@ void CXXNameMangler::mangleType(const ObjCInterfaceType *T) {
|
||||
}
|
||||
|
||||
void CXXNameMangler::mangleType(const ObjCObjectType *T) {
|
||||
// Treat __kindof as a vendor extended type qualifier.
|
||||
if (T->isKindOfType())
|
||||
Out << "U8__kindof";
|
||||
|
||||
if (!T->qual_empty()) {
|
||||
// Mangle protocol qualifiers.
|
||||
SmallString<64> QualStr;
|
||||
@ -2391,7 +2395,16 @@ void CXXNameMangler::mangleType(const ObjCObjectType *T) {
|
||||
QualOS.flush();
|
||||
Out << 'U' << QualStr.size() << QualStr;
|
||||
}
|
||||
|
||||
mangleType(T->getBaseType());
|
||||
|
||||
if (T->isSpecialized()) {
|
||||
// Mangle type arguments as I <type>+ E
|
||||
Out << 'I';
|
||||
for (auto typeArg : T->getTypeArgs())
|
||||
mangleType(typeArg);
|
||||
Out << 'E';
|
||||
}
|
||||
}
|
||||
|
||||
void CXXNameMangler::mangleType(const BlockPointerType *T) {
|
||||
|
1034
lib/AST/Type.cpp
1034
lib/AST/Type.cpp
File diff suppressed because it is too large
Load Diff
@ -19,6 +19,8 @@
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
using namespace clang;
|
||||
|
||||
static const unsigned TypeLocMaxDataAlign = llvm::alignOf<void *>();
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// TypeLoc Implementation
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -125,6 +127,46 @@ void TypeLoc::initializeImpl(ASTContext &Context, TypeLoc TL,
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
class TypeLocCopier : public TypeLocVisitor<TypeLocCopier> {
|
||||
TypeLoc Source;
|
||||
public:
|
||||
TypeLocCopier(TypeLoc source) : Source(source) { }
|
||||
|
||||
#define ABSTRACT_TYPELOC(CLASS, PARENT)
|
||||
#define TYPELOC(CLASS, PARENT) \
|
||||
void Visit##CLASS##TypeLoc(CLASS##TypeLoc dest) { \
|
||||
dest.copyLocal(Source.castAs<CLASS##TypeLoc>()); \
|
||||
}
|
||||
#include "clang/AST/TypeLocNodes.def"
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
void TypeLoc::copy(TypeLoc other) {
|
||||
assert(getFullDataSize() == other.getFullDataSize());
|
||||
|
||||
// If both data pointers are aligned to the maximum alignment, we
|
||||
// can memcpy because getFullDataSize() accurately reflects the
|
||||
// layout of the data.
|
||||
if (reinterpret_cast<uintptr_t>(Data)
|
||||
== llvm::RoundUpToAlignment(reinterpret_cast<uintptr_t>(Data),
|
||||
TypeLocMaxDataAlign) &&
|
||||
reinterpret_cast<uintptr_t>(other.Data)
|
||||
== llvm::RoundUpToAlignment(reinterpret_cast<uintptr_t>(other.Data),
|
||||
TypeLocMaxDataAlign)) {
|
||||
memcpy(Data, other.Data, getFullDataSize());
|
||||
return;
|
||||
}
|
||||
|
||||
// Copy each of the pieces.
|
||||
TypeLoc TL(getType(), Data);
|
||||
do {
|
||||
TypeLocCopier(other).Visit(TL);
|
||||
other = other.getNextTypeLoc();
|
||||
} while ((TL = TL.getNextTypeLoc()));
|
||||
}
|
||||
|
||||
SourceLocation TypeLoc::getBeginLoc() const {
|
||||
TypeLoc Cur = *this;
|
||||
TypeLoc LeftMost = Cur;
|
||||
@ -312,6 +354,33 @@ TypeLoc TypeLoc::IgnoreParensImpl(TypeLoc TL) {
|
||||
return TL;
|
||||
}
|
||||
|
||||
SourceLocation TypeLoc::findNullabilityLoc() const {
|
||||
if (auto attributedLoc = getAs<AttributedTypeLoc>()) {
|
||||
if (attributedLoc.getAttrKind() == AttributedType::attr_nullable ||
|
||||
attributedLoc.getAttrKind() == AttributedType::attr_nonnull ||
|
||||
attributedLoc.getAttrKind() == AttributedType::attr_null_unspecified)
|
||||
return attributedLoc.getAttrNameLoc();
|
||||
}
|
||||
|
||||
return SourceLocation();
|
||||
}
|
||||
|
||||
void ObjCObjectTypeLoc::initializeLocal(ASTContext &Context,
|
||||
SourceLocation Loc) {
|
||||
setHasBaseTypeAsWritten(true);
|
||||
setTypeArgsLAngleLoc(Loc);
|
||||
setTypeArgsRAngleLoc(Loc);
|
||||
for (unsigned i = 0, e = getNumTypeArgs(); i != e; ++i) {
|
||||
setTypeArgTInfo(i,
|
||||
Context.getTrivialTypeSourceInfo(
|
||||
getTypePtr()->getTypeArgsAsWritten()[i], Loc));
|
||||
}
|
||||
setProtocolLAngleLoc(Loc);
|
||||
setProtocolRAngleLoc(Loc);
|
||||
for (unsigned i = 0, e = getNumProtocols(); i != e; ++i)
|
||||
setProtocolLoc(i, Loc);
|
||||
}
|
||||
|
||||
void TypeOfTypeLoc::initializeLocal(ASTContext &Context,
|
||||
SourceLocation Loc) {
|
||||
TypeofLikeTypeLoc<TypeOfTypeLoc, TypeOfType, TypeOfTypeLocInfo>
|
||||
|
@ -1129,6 +1129,9 @@ void TypePrinter::printAttributedBefore(const AttributedType *T,
|
||||
T->getAttrKind() == AttributedType::attr_objc_ownership)
|
||||
return printBefore(T->getEquivalentType(), OS);
|
||||
|
||||
if (T->getAttrKind() == AttributedType::attr_objc_kindof)
|
||||
OS << "__kindof ";
|
||||
|
||||
printBefore(T->getModifiedType(), OS);
|
||||
|
||||
if (T->isMSTypeSpec()) {
|
||||
@ -1165,6 +1168,9 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
|
||||
T->getAttrKind() == AttributedType::attr_objc_ownership)
|
||||
return printAfter(T->getEquivalentType(), OS);
|
||||
|
||||
if (T->getAttrKind() == AttributedType::attr_objc_kindof)
|
||||
return;
|
||||
|
||||
// TODO: not all attributes are GCC-style attributes.
|
||||
if (T->isMSTypeSpec())
|
||||
return;
|
||||
@ -1310,59 +1316,61 @@ void TypePrinter::printObjCInterfaceAfter(const ObjCInterfaceType *T,
|
||||
|
||||
void TypePrinter::printObjCObjectBefore(const ObjCObjectType *T,
|
||||
raw_ostream &OS) {
|
||||
if (T->qual_empty())
|
||||
if (T->qual_empty() && T->isUnspecializedAsWritten() &&
|
||||
!T->isKindOfTypeAsWritten())
|
||||
return printBefore(T->getBaseType(), OS);
|
||||
|
||||
if (T->isKindOfTypeAsWritten())
|
||||
OS << "__kindof ";
|
||||
|
||||
print(T->getBaseType(), OS, StringRef());
|
||||
OS << '<';
|
||||
bool isFirst = true;
|
||||
for (const auto *I : T->quals()) {
|
||||
if (isFirst)
|
||||
isFirst = false;
|
||||
else
|
||||
OS << ',';
|
||||
OS << I->getName();
|
||||
|
||||
if (T->isSpecializedAsWritten()) {
|
||||
bool isFirst = true;
|
||||
OS << '<';
|
||||
for (auto typeArg : T->getTypeArgsAsWritten()) {
|
||||
if (isFirst)
|
||||
isFirst = false;
|
||||
else
|
||||
OS << ",";
|
||||
|
||||
print(typeArg, OS, StringRef());
|
||||
}
|
||||
OS << '>';
|
||||
}
|
||||
OS << '>';
|
||||
|
||||
if (!T->qual_empty()) {
|
||||
bool isFirst = true;
|
||||
OS << '<';
|
||||
for (const auto *I : T->quals()) {
|
||||
if (isFirst)
|
||||
isFirst = false;
|
||||
else
|
||||
OS << ',';
|
||||
OS << I->getName();
|
||||
}
|
||||
OS << '>';
|
||||
}
|
||||
|
||||
spaceBeforePlaceHolder(OS);
|
||||
}
|
||||
void TypePrinter::printObjCObjectAfter(const ObjCObjectType *T,
|
||||
raw_ostream &OS) {
|
||||
if (T->qual_empty())
|
||||
if (T->qual_empty() && T->isUnspecializedAsWritten() &&
|
||||
!T->isKindOfTypeAsWritten())
|
||||
return printAfter(T->getBaseType(), OS);
|
||||
}
|
||||
|
||||
void TypePrinter::printObjCObjectPointerBefore(const ObjCObjectPointerType *T,
|
||||
raw_ostream &OS) {
|
||||
T->getPointeeType().getLocalQualifiers().print(OS, Policy,
|
||||
/*appendSpaceIfNonEmpty=*/true);
|
||||
printBefore(T->getPointeeType(), OS);
|
||||
|
||||
assert(!T->isObjCSelType());
|
||||
|
||||
if (T->isObjCIdType() || T->isObjCQualifiedIdType())
|
||||
OS << "id";
|
||||
else if (T->isObjCClassType() || T->isObjCQualifiedClassType())
|
||||
OS << "Class";
|
||||
else
|
||||
OS << T->getInterfaceDecl()->getName();
|
||||
|
||||
if (!T->qual_empty()) {
|
||||
OS << '<';
|
||||
for (ObjCObjectPointerType::qual_iterator I = T->qual_begin(),
|
||||
E = T->qual_end();
|
||||
I != E; ++I) {
|
||||
OS << (*I)->getName();
|
||||
if (I+1 != E)
|
||||
OS << ',';
|
||||
}
|
||||
OS << '>';
|
||||
}
|
||||
|
||||
// If we need to print the pointer, print it now.
|
||||
if (!T->isObjCIdType() && !T->isObjCQualifiedIdType() &&
|
||||
!T->isObjCClassType() && !T->isObjCQualifiedClassType()) {
|
||||
OS << " *"; // Don't forget the implicit pointer.
|
||||
} else {
|
||||
spaceBeforePlaceHolder(OS);
|
||||
if (HasEmptyPlaceHolder)
|
||||
OS << ' ';
|
||||
OS << '*';
|
||||
}
|
||||
}
|
||||
void TypePrinter::printObjCObjectPointerAfter(const ObjCObjectPointerType *T,
|
||||
|
@ -20,21 +20,21 @@ namespace clang {
|
||||
namespace ast_matchers {
|
||||
namespace internal {
|
||||
|
||||
bool NotUnaryOperator(const ast_type_traits::DynTypedNode DynNode,
|
||||
bool NotUnaryOperator(const ast_type_traits::DynTypedNode &DynNode,
|
||||
ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder,
|
||||
ArrayRef<DynTypedMatcher> InnerMatchers);
|
||||
|
||||
bool AllOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode,
|
||||
bool AllOfVariadicOperator(const ast_type_traits::DynTypedNode &DynNode,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder,
|
||||
ArrayRef<DynTypedMatcher> InnerMatchers);
|
||||
|
||||
bool EachOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode,
|
||||
bool EachOfVariadicOperator(const ast_type_traits::DynTypedNode &DynNode,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder,
|
||||
ArrayRef<DynTypedMatcher> InnerMatchers);
|
||||
|
||||
bool AnyOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode,
|
||||
bool AnyOfVariadicOperator(const ast_type_traits::DynTypedNode &DynNode,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder,
|
||||
ArrayRef<DynTypedMatcher> InnerMatchers);
|
||||
@ -51,7 +51,7 @@ void BoundNodesTreeBuilder::visitMatches(Visitor *ResultVisitor) {
|
||||
namespace {
|
||||
|
||||
typedef bool (*VariadicOperatorFunction)(
|
||||
const ast_type_traits::DynTypedNode DynNode, ASTMatchFinder *Finder,
|
||||
const ast_type_traits::DynTypedNode &DynNode, ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder, ArrayRef<DynTypedMatcher> InnerMatchers);
|
||||
|
||||
template <VariadicOperatorFunction Func>
|
||||
@ -228,7 +228,7 @@ void BoundNodesTreeBuilder::addMatch(const BoundNodesTreeBuilder &Other) {
|
||||
Bindings.append(Other.Bindings.begin(), Other.Bindings.end());
|
||||
}
|
||||
|
||||
bool NotUnaryOperator(const ast_type_traits::DynTypedNode DynNode,
|
||||
bool NotUnaryOperator(const ast_type_traits::DynTypedNode &DynNode,
|
||||
ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder,
|
||||
ArrayRef<DynTypedMatcher> InnerMatchers) {
|
||||
if (InnerMatchers.size() != 1)
|
||||
@ -248,7 +248,7 @@ bool NotUnaryOperator(const ast_type_traits::DynTypedNode DynNode,
|
||||
return !InnerMatchers[0].matches(DynNode, Finder, &Discard);
|
||||
}
|
||||
|
||||
bool AllOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode,
|
||||
bool AllOfVariadicOperator(const ast_type_traits::DynTypedNode &DynNode,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder,
|
||||
ArrayRef<DynTypedMatcher> InnerMatchers) {
|
||||
@ -262,7 +262,7 @@ bool AllOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EachOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode,
|
||||
bool EachOfVariadicOperator(const ast_type_traits::DynTypedNode &DynNode,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder,
|
||||
ArrayRef<DynTypedMatcher> InnerMatchers) {
|
||||
@ -279,7 +279,7 @@ bool EachOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode,
|
||||
return Matched;
|
||||
}
|
||||
|
||||
bool AnyOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode,
|
||||
bool AnyOfVariadicOperator(const ast_type_traits::DynTypedNode &DynNode,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder,
|
||||
ArrayRef<DynTypedMatcher> InnerMatchers) {
|
||||
|
@ -216,7 +216,7 @@ class Parser::CodeTokenizer {
|
||||
if (Code[Length] == Marker) {
|
||||
Result->Kind = TokenInfo::TK_Literal;
|
||||
Result->Text = Code.substr(0, Length + 1);
|
||||
Result->Value = Code.substr(1, Length - 1).str();
|
||||
Result->Value = Code.substr(1, Length - 1);
|
||||
Code = Code.drop_front(Length + 1);
|
||||
return;
|
||||
}
|
||||
|
@ -249,7 +249,7 @@ VariantValue::VariantValue(unsigned Unsigned) : Type(VT_Nothing) {
|
||||
setUnsigned(Unsigned);
|
||||
}
|
||||
|
||||
VariantValue::VariantValue(const std::string &String) : Type(VT_Nothing) {
|
||||
VariantValue::VariantValue(StringRef String) : Type(VT_Nothing) {
|
||||
setString(String);
|
||||
}
|
||||
|
||||
@ -319,7 +319,7 @@ const std::string &VariantValue::getString() const {
|
||||
return *Value.String;
|
||||
}
|
||||
|
||||
void VariantValue::setString(const std::string &NewValue) {
|
||||
void VariantValue::setString(StringRef NewValue) {
|
||||
reset();
|
||||
Type = VT_String;
|
||||
Value.String = new std::string(NewValue);
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
#include "clang/Basic/FileManager.h"
|
||||
#include "clang/Basic/FileSystemStatCache.h"
|
||||
#include "clang/Frontend/PCHContainerOperations.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/Config/llvm-config.h"
|
||||
#include "llvm/Support/FileSystem.h"
|
||||
@ -585,3 +586,5 @@ void FileManager::PrintStats() const {
|
||||
|
||||
//llvm::errs() << PagesMapped << BytesOfPagesMapped << FSLookups;
|
||||
}
|
||||
|
||||
PCHContainerOperations::~PCHContainerOperations() {}
|
||||
|
@ -109,7 +109,8 @@ namespace {
|
||||
WCHARSUPPORT = 0x04000,
|
||||
HALFSUPPORT = 0x08000,
|
||||
KEYCONCEPTS = 0x10000,
|
||||
KEYALL = (0x1ffff & ~KEYNOMS18 &
|
||||
KEYOBJC2 = 0x20000,
|
||||
KEYALL = (0x3ffff & ~KEYNOMS18 &
|
||||
~KEYNOOPENCL) // KEYNOMS18 and KEYNOOPENCL are used to exclude.
|
||||
};
|
||||
|
||||
@ -144,6 +145,7 @@ static KeywordStatus getKeywordStatus(const LangOptions &LangOpts,
|
||||
// in non-arc mode.
|
||||
if (LangOpts.ObjC2 && (Flags & KEYARC)) return KS_Enabled;
|
||||
if (LangOpts.ConceptsTS && (Flags & KEYCONCEPTS)) return KS_Enabled;
|
||||
if (LangOpts.ObjC2 && (Flags & KEYOBJC2)) return KS_Enabled;
|
||||
if (LangOpts.CPlusPlus && (Flags & KEYCXX11)) return KS_Future;
|
||||
return KS_Disabled;
|
||||
}
|
||||
|
@ -82,10 +82,6 @@ bool Module::isAvailable(const LangOptions &LangOpts, const TargetInfo &Target,
|
||||
return true;
|
||||
|
||||
for (const Module *Current = this; Current; Current = Current->Parent) {
|
||||
if (!Current->MissingHeaders.empty()) {
|
||||
MissingHeader = Current->MissingHeaders.front();
|
||||
return false;
|
||||
}
|
||||
for (unsigned I = 0, N = Current->Requirements.size(); I != N; ++I) {
|
||||
if (hasFeature(Current->Requirements[I].first, LangOpts, Target) !=
|
||||
Current->Requirements[I].second) {
|
||||
@ -93,6 +89,10 @@ bool Module::isAvailable(const LangOptions &LangOpts, const TargetInfo &Target,
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!Current->MissingHeaders.empty()) {
|
||||
MissingHeader = Current->MissingHeaders.front();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
llvm_unreachable("could not find a reason why module is unavailable");
|
||||
@ -184,7 +184,11 @@ void Module::addRequirement(StringRef Feature, bool RequiredState,
|
||||
}
|
||||
|
||||
void Module::markUnavailable(bool MissingRequirement) {
|
||||
if (!IsAvailable)
|
||||
auto needUpdate = [MissingRequirement](Module *M) {
|
||||
return M->IsAvailable || (!M->IsMissingRequirement && MissingRequirement);
|
||||
};
|
||||
|
||||
if (!needUpdate(this))
|
||||
return;
|
||||
|
||||
SmallVector<Module *, 2> Stack;
|
||||
@ -193,7 +197,7 @@ void Module::markUnavailable(bool MissingRequirement) {
|
||||
Module *Current = Stack.back();
|
||||
Stack.pop_back();
|
||||
|
||||
if (!Current->IsAvailable)
|
||||
if (!needUpdate(Current))
|
||||
continue;
|
||||
|
||||
Current->IsAvailable = false;
|
||||
@ -201,7 +205,7 @@ void Module::markUnavailable(bool MissingRequirement) {
|
||||
for (submodule_iterator Sub = Current->submodule_begin(),
|
||||
SubEnd = Current->submodule_end();
|
||||
Sub != SubEnd; ++Sub) {
|
||||
if ((*Sub)->IsAvailable)
|
||||
if (needUpdate(*Sub))
|
||||
Stack.push_back(*Sub);
|
||||
}
|
||||
}
|
||||
|
@ -14,34 +14,9 @@
|
||||
#include "clang/Basic/LLVM.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ADT/StringSwitch.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
|
||||
using namespace clang;
|
||||
|
||||
SanitizerSet::SanitizerSet() : Mask(0) {}
|
||||
|
||||
bool SanitizerSet::has(SanitizerMask K) const {
|
||||
assert(llvm::countPopulation(K) == 1);
|
||||
return Mask & K;
|
||||
}
|
||||
|
||||
bool SanitizerSet::hasOneOf(SanitizerMask K) const {
|
||||
return Mask & K;
|
||||
}
|
||||
|
||||
void SanitizerSet::set(SanitizerMask K, bool Value) {
|
||||
assert(llvm::countPopulation(K) == 1);
|
||||
Mask = Value ? (Mask | K) : (Mask & ~K);
|
||||
}
|
||||
|
||||
void SanitizerSet::clear() {
|
||||
Mask = 0;
|
||||
}
|
||||
|
||||
bool SanitizerSet::empty() const {
|
||||
return Mask == 0;
|
||||
}
|
||||
|
||||
SanitizerMask clang::parseSanitizerValue(StringRef Value, bool AllowGroups) {
|
||||
SanitizerMask ParsedKind = llvm::StringSwitch<SanitizerMask>(Value)
|
||||
#define SANITIZER(NAME, ID) .Case(NAME, SanitizerKind::ID)
|
||||
|
@ -50,6 +50,7 @@ TargetInfo::TargetInfo(const llvm::Triple &T) : TargetOpts(), Triple(T) {
|
||||
LargeArrayAlign = 0;
|
||||
MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 0;
|
||||
MaxVectorAlign = 0;
|
||||
MaxTLSAlign = 0;
|
||||
SimdDefaultAlign = 0;
|
||||
SizeType = UnsignedLong;
|
||||
PtrDiffType = SignedLong;
|
||||
|
@ -580,6 +580,8 @@ class PS4OSTargetInfo : public OSTargetInfo<Target> {
|
||||
PS4OSTargetInfo(const llvm::Triple &Triple) : OSTargetInfo<Target>(Triple) {
|
||||
this->WCharType = this->UnsignedShort;
|
||||
|
||||
// On PS4, TLS variable cannot be aligned to more than 32 bytes (256 bits).
|
||||
this->MaxTLSAlign = 256;
|
||||
this->UserLabelPrefix = "";
|
||||
|
||||
switch (Triple.getArch()) {
|
||||
@ -863,6 +865,8 @@ class PPCTargetInfo : public TargetInfo {
|
||||
bool handleTargetFeatures(std::vector<std::string> &Features,
|
||||
DiagnosticsEngine &Diags) override;
|
||||
bool hasFeature(StringRef Feature) const override;
|
||||
void setFeatureEnabled(llvm::StringMap<bool> &Features, StringRef Name,
|
||||
bool Enabled) const override;
|
||||
|
||||
void getGCCRegNames(const char * const *&Names,
|
||||
unsigned &NumNames) const override;
|
||||
@ -1036,7 +1040,6 @@ bool PPCTargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
|
||||
|
||||
if (Feature == "power8-vector") {
|
||||
HasP8Vector = true;
|
||||
HasVSX = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -1047,7 +1050,6 @@ bool PPCTargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
|
||||
|
||||
if (Feature == "direct-move") {
|
||||
HasDirectMove = true;
|
||||
HasVSX = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -1064,6 +1066,15 @@ bool PPCTargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
|
||||
// TODO: Finish this list and add an assert that we've handled them
|
||||
// all.
|
||||
}
|
||||
if (!HasVSX && (HasP8Vector || HasDirectMove)) {
|
||||
if (HasP8Vector)
|
||||
Diags.Report(diag::err_opt_not_valid_with_opt) << "-mpower8-vector" <<
|
||||
"-mno-vsx";
|
||||
else if (HasDirectMove)
|
||||
Diags.Report(diag::err_opt_not_valid_with_opt) << "-mdirect-move" <<
|
||||
"-mno-vsx";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -1285,6 +1296,11 @@ void PPCTargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const {
|
||||
.Case("ppc64le", true)
|
||||
.Case("pwr8", true)
|
||||
.Default(false);
|
||||
Features["vsx"] = llvm::StringSwitch<bool>(CPU)
|
||||
.Case("ppc64le", true)
|
||||
.Case("pwr8", true)
|
||||
.Case("pwr7", true)
|
||||
.Default(false);
|
||||
}
|
||||
|
||||
bool PPCTargetInfo::hasFeature(StringRef Feature) const {
|
||||
@ -1301,6 +1317,39 @@ bool PPCTargetInfo::hasFeature(StringRef Feature) const {
|
||||
.Default(false);
|
||||
}
|
||||
|
||||
/* There is no clear way for the target to know which of the features in the
|
||||
final feature vector came from defaults and which are actually specified by
|
||||
the user. To that end, we use the fact that this function is not called on
|
||||
default features - only user specified ones. By the first time this
|
||||
function is called, the default features are populated.
|
||||
We then keep track of the features that the user specified so that we
|
||||
can ensure we do not override a user's request (only defaults).
|
||||
For example:
|
||||
-mcpu=pwr8 -mno-vsx (should disable vsx and everything that depends on it)
|
||||
-mcpu=pwr8 -mdirect-move -mno-vsx (should actually be diagnosed)
|
||||
|
||||
NOTE: Do not call this from PPCTargetInfo::getDefaultFeatures
|
||||
*/
|
||||
void PPCTargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features,
|
||||
StringRef Name, bool Enabled) const {
|
||||
static llvm::StringMap<bool> ExplicitFeatures;
|
||||
ExplicitFeatures[Name] = Enabled;
|
||||
|
||||
// At this point, -mno-vsx turns off the dependent features but we respect
|
||||
// the user's requests.
|
||||
if (!Enabled && Name == "vsx") {
|
||||
Features["direct-move"] = ExplicitFeatures["direct-move"];
|
||||
Features["power8-vector"] = ExplicitFeatures["power8-vector"];
|
||||
}
|
||||
if ((Enabled && Name == "power8-vector") ||
|
||||
(Enabled && Name == "direct-move")) {
|
||||
if (ExplicitFeatures.find("vsx") == ExplicitFeatures.end()) {
|
||||
Features["vsx"] = true;
|
||||
}
|
||||
}
|
||||
Features[Name] = Enabled;
|
||||
}
|
||||
|
||||
const char * const PPCTargetInfo::GCCRegNames[] = {
|
||||
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
|
||||
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
|
||||
@ -1472,7 +1521,7 @@ class PPC64TargetInfo : public PPCTargetInfo {
|
||||
BuiltinVaListKind getBuiltinVaListKind() const override {
|
||||
return TargetInfo::CharPtrBuiltinVaList;
|
||||
}
|
||||
// PPC64 Linux-specifc ABI options.
|
||||
// PPC64 Linux-specific ABI options.
|
||||
bool setABI(const std::string &Name) override {
|
||||
if (Name == "elfv1" || Name == "elfv1-qpx" || Name == "elfv2") {
|
||||
ABI = Name;
|
||||
@ -3996,14 +4045,8 @@ class ARMTargetInfo : public TargetInfo {
|
||||
FP_Neon
|
||||
} FPMath;
|
||||
|
||||
unsigned ArchISA;
|
||||
unsigned ArchKind;
|
||||
unsigned ArchProfile;
|
||||
unsigned ArchVersion;
|
||||
|
||||
unsigned FPU : 5;
|
||||
|
||||
unsigned ShouldUseInlineAtomic : 1;
|
||||
unsigned IsAAPCS : 1;
|
||||
unsigned IsThumb : 1;
|
||||
unsigned HWDiv : 2;
|
||||
@ -4025,6 +4068,37 @@ class ARMTargetInfo : public TargetInfo {
|
||||
|
||||
static const Builtin::Info BuiltinInfo[];
|
||||
|
||||
static bool shouldUseInlineAtomic(const llvm::Triple &T) {
|
||||
StringRef ArchName = T.getArchName();
|
||||
if (T.getArch() == llvm::Triple::arm ||
|
||||
T.getArch() == llvm::Triple::armeb) {
|
||||
StringRef VersionStr;
|
||||
if (ArchName.startswith("armv"))
|
||||
VersionStr = ArchName.substr(4, 1);
|
||||
else if (ArchName.startswith("armebv"))
|
||||
VersionStr = ArchName.substr(6, 1);
|
||||
else
|
||||
return false;
|
||||
unsigned Version;
|
||||
if (VersionStr.getAsInteger(10, Version))
|
||||
return false;
|
||||
return Version >= 6;
|
||||
}
|
||||
assert(T.getArch() == llvm::Triple::thumb ||
|
||||
T.getArch() == llvm::Triple::thumbeb);
|
||||
StringRef VersionStr;
|
||||
if (ArchName.startswith("thumbv"))
|
||||
VersionStr = ArchName.substr(6, 1);
|
||||
else if (ArchName.startswith("thumbebv"))
|
||||
VersionStr = ArchName.substr(8, 1);
|
||||
else
|
||||
return false;
|
||||
unsigned Version;
|
||||
if (VersionStr.getAsInteger(10, Version))
|
||||
return false;
|
||||
return Version >= 7;
|
||||
}
|
||||
|
||||
void setABIAAPCS() {
|
||||
IsAAPCS = true;
|
||||
|
||||
@ -4123,27 +4197,6 @@ class ARMTargetInfo : public TargetInfo {
|
||||
// FIXME: Override "preferred align" for double and long long.
|
||||
}
|
||||
|
||||
void setArchInfo(StringRef ArchName) {
|
||||
ArchISA = llvm::ARMTargetParser::parseArchISA(ArchName);
|
||||
ArchKind = llvm::ARMTargetParser::parseArch(ArchName);
|
||||
ArchProfile = llvm::ARMTargetParser::parseArchProfile(ArchName);
|
||||
ArchVersion = llvm::ARMTargetParser::parseArchVersion(ArchName);
|
||||
}
|
||||
|
||||
void setAtomic() {
|
||||
// Cortex M does not support 8 byte atomics, while general Thumb2 does.
|
||||
if (ArchProfile == llvm::ARM::PK_M) {
|
||||
MaxAtomicPromoteWidth = 32;
|
||||
if (ShouldUseInlineAtomic)
|
||||
MaxAtomicInlineWidth = 32;
|
||||
}
|
||||
else {
|
||||
MaxAtomicPromoteWidth = 64;
|
||||
if (ShouldUseInlineAtomic)
|
||||
MaxAtomicInlineWidth = 64;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
ARMTargetInfo(const llvm::Triple &Triple, bool IsBigEndian)
|
||||
: TargetInfo(Triple), CPU("arm1136j-s"), FPMath(FP_Default),
|
||||
@ -4159,27 +4212,12 @@ class ARMTargetInfo : public TargetInfo {
|
||||
break;
|
||||
}
|
||||
|
||||
// if subArch is not specified Arc Info is based on the default CPU
|
||||
if (Triple.getSubArch() == llvm::Triple::SubArchType::NoSubArch) {
|
||||
unsigned ArchKind = llvm::ARMTargetParser::parseCPUArch(CPU);
|
||||
setArchInfo(llvm::ARMTargetParser::getArchName(ArchKind));
|
||||
ShouldUseInlineAtomic = false;
|
||||
}
|
||||
else {
|
||||
setArchInfo(Triple.getArchName());
|
||||
// FIXME: Should't this be updated also when calling setCPU() ?
|
||||
// Doing so currently causes regressions
|
||||
ShouldUseInlineAtomic = (ArchISA == llvm::ARM::IK_ARM && ArchVersion >= 6) ||
|
||||
(ArchISA == llvm::ARM::IK_THUMB && ArchVersion >= 7);
|
||||
}
|
||||
|
||||
// {} in inline assembly are neon specifiers, not assembly variant
|
||||
// specifiers.
|
||||
NoAsmVariants = true;
|
||||
|
||||
// FIXME: Should't this be updated also when calling setCPU() ?
|
||||
// Doing so currently causes regressions
|
||||
IsThumb = (ArchISA == llvm::ARM::IK_THUMB);
|
||||
// FIXME: Should we just treat this as a feature?
|
||||
IsThumb = getTriple().getArchName().startswith("thumb");
|
||||
|
||||
// FIXME: This duplicates code from the driver that sets the -target-abi
|
||||
// option - this code is used if -target-abi isn't passed and should
|
||||
@ -4224,7 +4262,10 @@ class ARMTargetInfo : public TargetInfo {
|
||||
// ARM targets default to using the ARM C++ ABI.
|
||||
TheCXXABI.set(TargetCXXABI::GenericARM);
|
||||
|
||||
setAtomic();
|
||||
// ARM has atomics up to 8 bytes
|
||||
MaxAtomicPromoteWidth = 64;
|
||||
if (shouldUseInlineAtomic(getTriple()))
|
||||
MaxAtomicInlineWidth = 64;
|
||||
|
||||
// Do force alignment of members that follow zero length bitfields. If
|
||||
// the alignment of the zero-length bitfield is greater than the member
|
||||
@ -4255,6 +4296,11 @@ class ARMTargetInfo : public TargetInfo {
|
||||
|
||||
// FIXME: This should be based on Arch attributes, not CPU names.
|
||||
void getDefaultFeatures(llvm::StringMap<bool> &Features) const override {
|
||||
StringRef ArchName = getTriple().getArchName();
|
||||
unsigned ArchKind = llvm::ARMTargetParser::parseArch(ArchName);
|
||||
bool IsV8 = (ArchKind == llvm::ARM::AK_ARMV8A ||
|
||||
ArchKind == llvm::ARM::AK_ARMV8_1A);
|
||||
|
||||
if (CPU == "arm1136jf-s" || CPU == "arm1176jzf-s" || CPU == "mpcore")
|
||||
Features["vfp2"] = true;
|
||||
else if (CPU == "cortex-a8" || CPU == "cortex-a9") {
|
||||
@ -4279,7 +4325,7 @@ class ARMTargetInfo : public TargetInfo {
|
||||
Features["hwdiv-arm"] = true;
|
||||
Features["crc"] = true;
|
||||
Features["crypto"] = true;
|
||||
} else if (CPU == "cortex-r5" || CPU == "cortex-r7" || ArchVersion == 8) {
|
||||
} else if (CPU == "cortex-r5" || CPU == "cortex-r7" || IsV8) {
|
||||
Features["hwdiv"] = true;
|
||||
Features["hwdiv-arm"] = true;
|
||||
} else if (CPU == "cortex-m3" || CPU == "cortex-m4" || CPU == "cortex-m7" ||
|
||||
@ -4362,14 +4408,26 @@ class ARMTargetInfo : public TargetInfo {
|
||||
.Case("hwdiv-arm", HWDiv & HWDivARM)
|
||||
.Default(false);
|
||||
}
|
||||
const char *getCPUAttr() const {
|
||||
const char *CPUAttr;
|
||||
const char *getCPUDefineSuffix(StringRef Name) const {
|
||||
if(Name == "generic") {
|
||||
auto subarch = getTriple().getSubArch();
|
||||
switch (subarch) {
|
||||
case llvm::Triple::SubArchType::ARMSubArch_v8_1a:
|
||||
return "8_1A";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned ArchKind = llvm::ARMTargetParser::parseCPUArch(Name);
|
||||
if (ArchKind == llvm::ARM::AK_INVALID)
|
||||
return "";
|
||||
|
||||
// For most sub-arches, the build attribute CPU name is enough.
|
||||
// For Cortex variants, it's slightly different.
|
||||
switch(ArchKind) {
|
||||
default:
|
||||
CPUAttr = llvm::ARMTargetParser::getCPUAttr(ArchKind);
|
||||
return CPUAttr ? CPUAttr : "" ;
|
||||
return llvm::ARMTargetParser::getCPUAttr(ArchKind);
|
||||
case llvm::ARM::AK_ARMV6M:
|
||||
case llvm::ARM::AK_ARMV6SM:
|
||||
return "6M";
|
||||
@ -4389,8 +4447,23 @@ class ARMTargetInfo : public TargetInfo {
|
||||
return "8_1A";
|
||||
}
|
||||
}
|
||||
const char *getCPUProfile() const {
|
||||
switch(ArchProfile) {
|
||||
const char *getCPUProfile(StringRef Name) const {
|
||||
if(Name == "generic") {
|
||||
auto subarch = getTriple().getSubArch();
|
||||
switch (subarch) {
|
||||
case llvm::Triple::SubArchType::ARMSubArch_v8_1a:
|
||||
return "A";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned CPUArch = llvm::ARMTargetParser::parseCPUArch(Name);
|
||||
if (CPUArch == llvm::ARM::AK_INVALID)
|
||||
return "";
|
||||
|
||||
StringRef ArchName = llvm::ARMTargetParser::getArchName(CPUArch);
|
||||
switch(llvm::ARMTargetParser::parseArchProfile(ArchName)) {
|
||||
case llvm::ARM::PK_A:
|
||||
return "A";
|
||||
case llvm::ARM::PK_R:
|
||||
@ -4402,26 +4475,35 @@ class ARMTargetInfo : public TargetInfo {
|
||||
}
|
||||
}
|
||||
bool setCPU(const std::string &Name) override {
|
||||
unsigned ArchKind = llvm::ARMTargetParser::parseCPUArch(Name);
|
||||
if (ArchKind == llvm::ARM::AK_INVALID)
|
||||
if (!getCPUDefineSuffix(Name))
|
||||
return false;
|
||||
setArchInfo(llvm::ARMTargetParser::getArchName(ArchKind));
|
||||
setAtomic();
|
||||
|
||||
// Cortex M does not support 8 byte atomics, while general Thumb2 does.
|
||||
StringRef Profile = getCPUProfile(Name);
|
||||
if (Profile == "M" && MaxAtomicInlineWidth) {
|
||||
MaxAtomicPromoteWidth = 32;
|
||||
MaxAtomicInlineWidth = 32;
|
||||
}
|
||||
|
||||
CPU = Name;
|
||||
return true;
|
||||
}
|
||||
bool setFPMath(StringRef Name) override;
|
||||
bool supportsThumb(StringRef CPUAttr) const {
|
||||
return CPUAttr.count('T') || ArchVersion >= 6;
|
||||
bool supportsThumb(StringRef ArchName, StringRef CPUArch,
|
||||
unsigned CPUArchVer) const {
|
||||
return CPUArchVer >= 7 || (CPUArch.find('T') != StringRef::npos) ||
|
||||
(CPUArch.find('M') != StringRef::npos);
|
||||
}
|
||||
bool supportsThumb2(StringRef CPUAttr) const {
|
||||
return CPUAttr.equals("6T2") || ArchVersion >= 7;
|
||||
bool supportsThumb2(StringRef ArchName, StringRef CPUArch,
|
||||
unsigned CPUArchVer) const {
|
||||
// We check both CPUArchVer and ArchName because when only triple is
|
||||
// specified, the default CPU is arm1136j-s.
|
||||
return ArchName.endswith("v6t2") || ArchName.endswith("v7") ||
|
||||
ArchName.endswith("v8.1a") ||
|
||||
ArchName.endswith("v8") || CPUArch == "6T2" || CPUArchVer >= 7;
|
||||
}
|
||||
void getTargetDefines(const LangOptions &Opts,
|
||||
MacroBuilder &Builder) const override {
|
||||
StringRef CPUAttr = getCPUAttr();
|
||||
StringRef CPUProfile = getCPUProfile();
|
||||
|
||||
// Target identification.
|
||||
Builder.defineMacro("__arm");
|
||||
Builder.defineMacro("__arm__");
|
||||
@ -4429,12 +4511,19 @@ class ARMTargetInfo : public TargetInfo {
|
||||
// Target properties.
|
||||
Builder.defineMacro("__REGISTER_PREFIX__", "");
|
||||
|
||||
Builder.defineMacro("__ARM_ARCH_" + CPUAttr + "__");
|
||||
StringRef CPUArch = getCPUDefineSuffix(CPU);
|
||||
unsigned int CPUArchVer;
|
||||
if (CPUArch.substr(0, 1).getAsInteger<unsigned int>(10, CPUArchVer))
|
||||
llvm_unreachable("Invalid char for architecture version number");
|
||||
Builder.defineMacro("__ARM_ARCH_" + CPUArch + "__");
|
||||
|
||||
// ACLE 6.4.1 ARM/Thumb instruction set architecture
|
||||
StringRef CPUProfile = getCPUProfile(CPU);
|
||||
StringRef ArchName = getTriple().getArchName();
|
||||
|
||||
// __ARM_ARCH is defined as an integer value indicating the current ARM ISA
|
||||
Builder.defineMacro("__ARM_ARCH", std::to_string(ArchVersion));
|
||||
if (ArchVersion >= 8) {
|
||||
Builder.defineMacro("__ARM_ARCH", CPUArch.substr(0, 1));
|
||||
if (CPUArch[0] >= '8') {
|
||||
Builder.defineMacro("__ARM_FEATURE_NUMERIC_MAXMIN");
|
||||
Builder.defineMacro("__ARM_FEATURE_DIRECTED_ROUNDING");
|
||||
}
|
||||
@ -4448,9 +4537,9 @@ class ARMTargetInfo : public TargetInfo {
|
||||
// __ARM_ARCH_ISA_THUMB is defined to 1 if the core supporst the original
|
||||
// Thumb ISA (including v6-M). It is set to 2 if the core supports the
|
||||
// Thumb-2 ISA as found in the v6T2 architecture and all v7 architecture.
|
||||
if (supportsThumb2(CPUAttr))
|
||||
if (supportsThumb2(ArchName, CPUArch, CPUArchVer))
|
||||
Builder.defineMacro("__ARM_ARCH_ISA_THUMB", "2");
|
||||
else if (supportsThumb(CPUAttr))
|
||||
else if (supportsThumb(ArchName, CPUArch, CPUArchVer))
|
||||
Builder.defineMacro("__ARM_ARCH_ISA_THUMB", "1");
|
||||
|
||||
// __ARM_32BIT_STATE is defined to 1 if code is being generated for a 32-bit
|
||||
@ -4475,7 +4564,7 @@ class ARMTargetInfo : public TargetInfo {
|
||||
// FIXME: It's more complicated than this and we don't really support
|
||||
// interworking.
|
||||
// Windows on ARM does not "support" interworking
|
||||
if (5 <= ArchVersion && ArchVersion <= 8 && !getTriple().isOSWindows())
|
||||
if (5 <= CPUArchVer && CPUArchVer <= 8 && !getTriple().isOSWindows())
|
||||
Builder.defineMacro("__THUMB_INTERWORK__");
|
||||
|
||||
if (ABI == "aapcs" || ABI == "aapcs-linux" || ABI == "aapcs-vfp") {
|
||||
@ -4498,7 +4587,7 @@ class ARMTargetInfo : public TargetInfo {
|
||||
if (IsThumb) {
|
||||
Builder.defineMacro("__THUMBEL__");
|
||||
Builder.defineMacro("__thumb__");
|
||||
if (supportsThumb2(CPUAttr))
|
||||
if (supportsThumb2(ArchName, CPUArch, CPUArchVer))
|
||||
Builder.defineMacro("__thumb2__");
|
||||
}
|
||||
if (((HWDiv & HWDivThumb) && IsThumb) || ((HWDiv & HWDivARM) && !IsThumb))
|
||||
@ -4521,7 +4610,7 @@ class ARMTargetInfo : public TargetInfo {
|
||||
// the VFP define, hence the soft float and arch check. This is subtly
|
||||
// different from gcc, we follow the intent which was that it should be set
|
||||
// when Neon instructions are actually available.
|
||||
if ((FPU & NeonFPU) && !SoftFloat && ArchVersion >= 7) {
|
||||
if ((FPU & NeonFPU) && !SoftFloat && CPUArchVer >= 7) {
|
||||
Builder.defineMacro("__ARM_NEON");
|
||||
Builder.defineMacro("__ARM_NEON__");
|
||||
}
|
||||
@ -4538,18 +4627,18 @@ class ARMTargetInfo : public TargetInfo {
|
||||
if (Crypto)
|
||||
Builder.defineMacro("__ARM_FEATURE_CRYPTO");
|
||||
|
||||
if (ArchVersion >= 6 && CPUAttr != "6M") {
|
||||
if (CPUArchVer >= 6 && CPUArch != "6M") {
|
||||
Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1");
|
||||
Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2");
|
||||
Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4");
|
||||
Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8");
|
||||
}
|
||||
|
||||
bool is5EOrAbove = (ArchVersion >= 6 ||
|
||||
(ArchVersion == 5 && CPUAttr.count('E')));
|
||||
// FIXME: We are not getting all 32-bit ARM architectures
|
||||
bool is32Bit = (!IsThumb || supportsThumb2(CPUAttr));
|
||||
if (is5EOrAbove && is32Bit && (CPUProfile != "M" || CPUAttr == "7EM"))
|
||||
bool is5EOrAbove = (CPUArchVer >= 6 ||
|
||||
(CPUArchVer == 5 &&
|
||||
CPUArch.find('E') != StringRef::npos));
|
||||
bool is32Bit = (!IsThumb || supportsThumb2(ArchName, CPUArch, CPUArchVer));
|
||||
if (is5EOrAbove && is32Bit && (CPUProfile != "M" || CPUArch == "7EM"))
|
||||
Builder.defineMacro("__ARM_FEATURE_DSP");
|
||||
}
|
||||
void getTargetBuiltins(const Builtin::Info *&Records,
|
||||
@ -6632,6 +6721,19 @@ void PNaClTargetInfo::getGCCRegAliases(const GCCRegAlias *&Aliases,
|
||||
NumAliases = 0;
|
||||
}
|
||||
|
||||
// We attempt to use PNaCl (le32) frontend and Mips32EL backend.
|
||||
class NaClMips32ELTargetInfo : public Mips32ELTargetInfo {
|
||||
public:
|
||||
NaClMips32ELTargetInfo(const llvm::Triple &Triple) :
|
||||
Mips32ELTargetInfo(Triple) {
|
||||
MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 0;
|
||||
}
|
||||
|
||||
BuiltinVaListKind getBuiltinVaListKind() const override {
|
||||
return TargetInfo::PNaClABIBuiltinVaList;
|
||||
}
|
||||
};
|
||||
|
||||
class Le64TargetInfo : public TargetInfo {
|
||||
static const Builtin::Info BuiltinInfo[];
|
||||
|
||||
@ -7002,7 +7104,7 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple) {
|
||||
case llvm::Triple::NetBSD:
|
||||
return new NetBSDTargetInfo<Mips32ELTargetInfo>(Triple);
|
||||
case llvm::Triple::NaCl:
|
||||
return new NaClTargetInfo<Mips32ELTargetInfo>(Triple);
|
||||
return new NaClTargetInfo<NaClMips32ELTargetInfo>(Triple);
|
||||
default:
|
||||
return new Mips32ELTargetInfo(Triple);
|
||||
}
|
||||
|
@ -292,6 +292,7 @@ void EmitAssemblyHelper::CreatePasses() {
|
||||
PMBuilder.DisableUnitAtATime = !CodeGenOpts.UnitAtATime;
|
||||
PMBuilder.DisableUnrollLoops = !CodeGenOpts.UnrollLoops;
|
||||
PMBuilder.MergeFunctions = CodeGenOpts.MergeFunctions;
|
||||
PMBuilder.PrepareForLTO = CodeGenOpts.PrepareForLTO;
|
||||
PMBuilder.RerollLoops = CodeGenOpts.RerollLoops;
|
||||
|
||||
PMBuilder.addExtension(PassManagerBuilder::EP_EarlyAsPossible,
|
||||
@ -454,8 +455,6 @@ TargetMachine *EmitAssemblyHelper::CreateTargetMachine(bool MustCreateTM) {
|
||||
BackendArgs.push_back("-limit-float-precision");
|
||||
BackendArgs.push_back(CodeGenOpts.LimitFloatPrecision.c_str());
|
||||
}
|
||||
if (llvm::TimePassesIsEnabled)
|
||||
BackendArgs.push_back("-time-passes");
|
||||
for (unsigned i = 0, e = CodeGenOpts.BackendOptions.size(); i != e; ++i)
|
||||
BackendArgs.push_back(CodeGenOpts.BackendOptions[i].c_str());
|
||||
BackendArgs.push_back(nullptr);
|
||||
|
@ -93,6 +93,7 @@ namespace {
|
||||
BFI = OrigBFI;
|
||||
BFI.Offset = Offset;
|
||||
BFI.StorageSize = AtomicSizeInBits;
|
||||
BFI.StorageOffset += OffsetInChars;
|
||||
LVal = LValue::MakeBitfield(Addr, BFI, lvalue.getType(),
|
||||
lvalue.getAlignment());
|
||||
LVal.setTBAAInfo(lvalue.getTBAAInfo());
|
||||
|
@ -535,7 +535,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
|
||||
}
|
||||
case Builtin::BI__builtin_readcyclecounter: {
|
||||
Value *F = CGM.getIntrinsic(Intrinsic::readcyclecounter);
|
||||
return RValue::get(Builder.CreateCall(F, {}));
|
||||
return RValue::get(Builder.CreateCall(F));
|
||||
}
|
||||
case Builtin::BI__builtin___clear_cache: {
|
||||
Value *Begin = EmitScalarExpr(E->getArg(0));
|
||||
@ -923,7 +923,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
|
||||
}
|
||||
case Builtin::BI__builtin_unwind_init: {
|
||||
Value *F = CGM.getIntrinsic(Intrinsic::eh_unwind_init);
|
||||
return RValue::get(Builder.CreateCall(F, {}));
|
||||
return RValue::get(Builder.CreateCall(F));
|
||||
}
|
||||
case Builtin::BI__builtin_extend_pointer: {
|
||||
// Extends a pointer to the size of an _Unwind_Word, which is
|
||||
@ -962,7 +962,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
|
||||
|
||||
// Store the stack pointer to the setjmp buffer.
|
||||
Value *StackAddr =
|
||||
Builder.CreateCall(CGM.getIntrinsic(Intrinsic::stacksave), {});
|
||||
Builder.CreateCall(CGM.getIntrinsic(Intrinsic::stacksave));
|
||||
Value *StackSaveSlot =
|
||||
Builder.CreateGEP(Buf, ConstantInt::get(Int32Ty, 2));
|
||||
Builder.CreateStore(StackAddr, StackSaveSlot);
|
||||
@ -3399,7 +3399,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
|
||||
: InlineAsm::get(FTy, ".inst 0x" + utohexstr(ZExtValue), "",
|
||||
/*SideEffects=*/true);
|
||||
|
||||
return Builder.CreateCall(Emit, {});
|
||||
return Builder.CreateCall(Emit);
|
||||
}
|
||||
|
||||
if (BuiltinID == ARM::BI__builtin_arm_dbg) {
|
||||
@ -3543,7 +3543,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
|
||||
|
||||
if (BuiltinID == ARM::BI__builtin_arm_clrex) {
|
||||
Function *F = CGM.getIntrinsic(Intrinsic::arm_clrex);
|
||||
return Builder.CreateCall(F, {});
|
||||
return Builder.CreateCall(F);
|
||||
}
|
||||
|
||||
// CRC32
|
||||
@ -4339,7 +4339,7 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
|
||||
|
||||
if (BuiltinID == AArch64::BI__builtin_arm_clrex) {
|
||||
Function *F = CGM.getIntrinsic(Intrinsic::aarch64_clrex);
|
||||
return Builder.CreateCall(F, {});
|
||||
return Builder.CreateCall(F);
|
||||
}
|
||||
|
||||
// CRC32
|
||||
@ -6375,7 +6375,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
|
||||
break;
|
||||
}
|
||||
|
||||
Value *Call = Builder.CreateCall(CGM.getIntrinsic(ID), {});
|
||||
Value *Call = Builder.CreateCall(CGM.getIntrinsic(ID));
|
||||
Builder.CreateStore(Builder.CreateExtractValue(Call, 0), Ops[0]);
|
||||
return Builder.CreateExtractValue(Call, 1);
|
||||
}
|
||||
@ -6633,14 +6633,104 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID,
|
||||
llvm::Function *F = CGM.getIntrinsic(ID);
|
||||
return Builder.CreateCall(F, Ops, "");
|
||||
}
|
||||
case PPC::BI__builtin_vsx_xvrspip:
|
||||
case PPC::BI__builtin_vsx_xvrdpip:
|
||||
// Square root
|
||||
case PPC::BI__builtin_vsx_xvsqrtsp:
|
||||
case PPC::BI__builtin_vsx_xvsqrtdp: {
|
||||
llvm::Type *ResultType = ConvertType(E->getType());
|
||||
Value *X = EmitScalarExpr(E->getArg(0));
|
||||
ID = Intrinsic::ceil;
|
||||
ID = Intrinsic::sqrt;
|
||||
llvm::Function *F = CGM.getIntrinsic(ID, ResultType);
|
||||
return Builder.CreateCall(F, X);
|
||||
}
|
||||
// Count leading zeros
|
||||
case PPC::BI__builtin_altivec_vclzb:
|
||||
case PPC::BI__builtin_altivec_vclzh:
|
||||
case PPC::BI__builtin_altivec_vclzw:
|
||||
case PPC::BI__builtin_altivec_vclzd: {
|
||||
llvm::Type *ResultType = ConvertType(E->getType());
|
||||
Value *X = EmitScalarExpr(E->getArg(0));
|
||||
Value *Undef = ConstantInt::get(Builder.getInt1Ty(), false);
|
||||
Function *F = CGM.getIntrinsic(Intrinsic::ctlz, ResultType);
|
||||
return Builder.CreateCall(F, {X, Undef});
|
||||
}
|
||||
// Copy sign
|
||||
case PPC::BI__builtin_vsx_xvcpsgnsp:
|
||||
case PPC::BI__builtin_vsx_xvcpsgndp: {
|
||||
llvm::Type *ResultType = ConvertType(E->getType());
|
||||
Value *X = EmitScalarExpr(E->getArg(0));
|
||||
Value *Y = EmitScalarExpr(E->getArg(1));
|
||||
ID = Intrinsic::copysign;
|
||||
llvm::Function *F = CGM.getIntrinsic(ID, ResultType);
|
||||
return Builder.CreateCall(F, {X, Y});
|
||||
}
|
||||
// Rounding/truncation
|
||||
case PPC::BI__builtin_vsx_xvrspip:
|
||||
case PPC::BI__builtin_vsx_xvrdpip:
|
||||
case PPC::BI__builtin_vsx_xvrdpim:
|
||||
case PPC::BI__builtin_vsx_xvrspim:
|
||||
case PPC::BI__builtin_vsx_xvrdpi:
|
||||
case PPC::BI__builtin_vsx_xvrspi:
|
||||
case PPC::BI__builtin_vsx_xvrdpic:
|
||||
case PPC::BI__builtin_vsx_xvrspic:
|
||||
case PPC::BI__builtin_vsx_xvrdpiz:
|
||||
case PPC::BI__builtin_vsx_xvrspiz: {
|
||||
llvm::Type *ResultType = ConvertType(E->getType());
|
||||
Value *X = EmitScalarExpr(E->getArg(0));
|
||||
if (BuiltinID == PPC::BI__builtin_vsx_xvrdpim ||
|
||||
BuiltinID == PPC::BI__builtin_vsx_xvrspim)
|
||||
ID = Intrinsic::floor;
|
||||
else if (BuiltinID == PPC::BI__builtin_vsx_xvrdpi ||
|
||||
BuiltinID == PPC::BI__builtin_vsx_xvrspi)
|
||||
ID = Intrinsic::round;
|
||||
else if (BuiltinID == PPC::BI__builtin_vsx_xvrdpic ||
|
||||
BuiltinID == PPC::BI__builtin_vsx_xvrspic)
|
||||
ID = Intrinsic::nearbyint;
|
||||
else if (BuiltinID == PPC::BI__builtin_vsx_xvrdpip ||
|
||||
BuiltinID == PPC::BI__builtin_vsx_xvrspip)
|
||||
ID = Intrinsic::ceil;
|
||||
else if (BuiltinID == PPC::BI__builtin_vsx_xvrdpiz ||
|
||||
BuiltinID == PPC::BI__builtin_vsx_xvrspiz)
|
||||
ID = Intrinsic::trunc;
|
||||
llvm::Function *F = CGM.getIntrinsic(ID, ResultType);
|
||||
return Builder.CreateCall(F, X);
|
||||
}
|
||||
// FMA variations
|
||||
case PPC::BI__builtin_vsx_xvmaddadp:
|
||||
case PPC::BI__builtin_vsx_xvmaddasp:
|
||||
case PPC::BI__builtin_vsx_xvnmaddadp:
|
||||
case PPC::BI__builtin_vsx_xvnmaddasp:
|
||||
case PPC::BI__builtin_vsx_xvmsubadp:
|
||||
case PPC::BI__builtin_vsx_xvmsubasp:
|
||||
case PPC::BI__builtin_vsx_xvnmsubadp:
|
||||
case PPC::BI__builtin_vsx_xvnmsubasp: {
|
||||
llvm::Type *ResultType = ConvertType(E->getType());
|
||||
Value *X = EmitScalarExpr(E->getArg(0));
|
||||
Value *Y = EmitScalarExpr(E->getArg(1));
|
||||
Value *Z = EmitScalarExpr(E->getArg(2));
|
||||
Value *Zero = llvm::ConstantFP::getZeroValueForNegation(ResultType);
|
||||
llvm::Function *F = CGM.getIntrinsic(Intrinsic::fma, ResultType);
|
||||
switch (BuiltinID) {
|
||||
case PPC::BI__builtin_vsx_xvmaddadp:
|
||||
case PPC::BI__builtin_vsx_xvmaddasp:
|
||||
return Builder.CreateCall(F, {X, Y, Z});
|
||||
case PPC::BI__builtin_vsx_xvnmaddadp:
|
||||
case PPC::BI__builtin_vsx_xvnmaddasp:
|
||||
return Builder.CreateFSub(Zero,
|
||||
Builder.CreateCall(F, {X, Y, Z}), "sub");
|
||||
case PPC::BI__builtin_vsx_xvmsubadp:
|
||||
case PPC::BI__builtin_vsx_xvmsubasp:
|
||||
return Builder.CreateCall(F,
|
||||
{X, Y, Builder.CreateFSub(Zero, Z, "sub")});
|
||||
case PPC::BI__builtin_vsx_xvnmsubadp:
|
||||
case PPC::BI__builtin_vsx_xvnmsubasp:
|
||||
Value *FsubRes =
|
||||
Builder.CreateCall(F, {X, Y, Builder.CreateFSub(Zero, Z, "sub")});
|
||||
return Builder.CreateFSub(Zero, FsubRes, "sub");
|
||||
}
|
||||
llvm_unreachable("Unknown FMA operation");
|
||||
return nullptr; // Suppress no-return warning
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Emit an intrinsic that has 1 float or double.
|
||||
|
@ -912,20 +912,21 @@ static llvm::Value *CoerceIntOrPtrToIntOrPtr(llvm::Value *Val,
|
||||
|
||||
|
||||
/// CreateCoercedLoad - Create a load from \arg SrcPtr interpreted as
|
||||
/// a pointer to an object of type \arg Ty.
|
||||
/// a pointer to an object of type \arg Ty, known to be aligned to
|
||||
/// \arg SrcAlign bytes.
|
||||
///
|
||||
/// This safely handles the case when the src type is smaller than the
|
||||
/// destination type; in this situation the values of bits which not
|
||||
/// present in the src are undefined.
|
||||
static llvm::Value *CreateCoercedLoad(llvm::Value *SrcPtr,
|
||||
llvm::Type *Ty,
|
||||
llvm::Type *Ty, CharUnits SrcAlign,
|
||||
CodeGenFunction &CGF) {
|
||||
llvm::Type *SrcTy =
|
||||
cast<llvm::PointerType>(SrcPtr->getType())->getElementType();
|
||||
|
||||
// If SrcTy and Ty are the same, just do a load.
|
||||
if (SrcTy == Ty)
|
||||
return CGF.Builder.CreateLoad(SrcPtr);
|
||||
return CGF.Builder.CreateAlignedLoad(SrcPtr, SrcAlign.getQuantity());
|
||||
|
||||
uint64_t DstSize = CGF.CGM.getDataLayout().getTypeAllocSize(Ty);
|
||||
|
||||
@ -940,7 +941,8 @@ static llvm::Value *CreateCoercedLoad(llvm::Value *SrcPtr,
|
||||
// extension or truncation to the desired type.
|
||||
if ((isa<llvm::IntegerType>(Ty) || isa<llvm::PointerType>(Ty)) &&
|
||||
(isa<llvm::IntegerType>(SrcTy) || isa<llvm::PointerType>(SrcTy))) {
|
||||
llvm::LoadInst *Load = CGF.Builder.CreateLoad(SrcPtr);
|
||||
llvm::LoadInst *Load =
|
||||
CGF.Builder.CreateAlignedLoad(SrcPtr, SrcAlign.getQuantity());
|
||||
return CoerceIntOrPtrToIntOrPtr(Load, Ty, CGF);
|
||||
}
|
||||
|
||||
@ -954,23 +956,20 @@ static llvm::Value *CreateCoercedLoad(llvm::Value *SrcPtr,
|
||||
// to that information.
|
||||
llvm::Value *Casted =
|
||||
CGF.Builder.CreateBitCast(SrcPtr, llvm::PointerType::getUnqual(Ty));
|
||||
llvm::LoadInst *Load = CGF.Builder.CreateLoad(Casted);
|
||||
// FIXME: Use better alignment / avoid requiring aligned load.
|
||||
Load->setAlignment(1);
|
||||
return Load;
|
||||
return CGF.Builder.CreateAlignedLoad(Casted, SrcAlign.getQuantity());
|
||||
}
|
||||
|
||||
// Otherwise do coercion through memory. This is stupid, but
|
||||
// simple.
|
||||
llvm::Value *Tmp = CGF.CreateTempAlloca(Ty);
|
||||
llvm::AllocaInst *Tmp = CGF.CreateTempAlloca(Ty);
|
||||
Tmp->setAlignment(SrcAlign.getQuantity());
|
||||
llvm::Type *I8PtrTy = CGF.Builder.getInt8PtrTy();
|
||||
llvm::Value *Casted = CGF.Builder.CreateBitCast(Tmp, I8PtrTy);
|
||||
llvm::Value *SrcCasted = CGF.Builder.CreateBitCast(SrcPtr, I8PtrTy);
|
||||
// FIXME: Use better alignment.
|
||||
CGF.Builder.CreateMemCpy(Casted, SrcCasted,
|
||||
llvm::ConstantInt::get(CGF.IntPtrTy, SrcSize),
|
||||
1, false);
|
||||
return CGF.Builder.CreateLoad(Tmp);
|
||||
SrcAlign.getQuantity(), false);
|
||||
return CGF.Builder.CreateAlignedLoad(Tmp, SrcAlign.getQuantity());
|
||||
}
|
||||
|
||||
// Function to store a first-class aggregate into memory. We prefer to
|
||||
@ -979,39 +978,45 @@ static llvm::Value *CreateCoercedLoad(llvm::Value *SrcPtr,
|
||||
// FIXME: Do we need to recurse here?
|
||||
static void BuildAggStore(CodeGenFunction &CGF, llvm::Value *Val,
|
||||
llvm::Value *DestPtr, bool DestIsVolatile,
|
||||
bool LowAlignment) {
|
||||
CharUnits DestAlign) {
|
||||
// Prefer scalar stores to first-class aggregate stores.
|
||||
if (llvm::StructType *STy =
|
||||
dyn_cast<llvm::StructType>(Val->getType())) {
|
||||
const llvm::StructLayout *Layout =
|
||||
CGF.CGM.getDataLayout().getStructLayout(STy);
|
||||
|
||||
for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) {
|
||||
llvm::Value *EltPtr = CGF.Builder.CreateConstGEP2_32(STy, DestPtr, 0, i);
|
||||
llvm::Value *Elt = CGF.Builder.CreateExtractValue(Val, i);
|
||||
llvm::StoreInst *SI = CGF.Builder.CreateStore(Elt, EltPtr,
|
||||
DestIsVolatile);
|
||||
if (LowAlignment)
|
||||
SI->setAlignment(1);
|
||||
uint64_t EltOffset = Layout->getElementOffset(i);
|
||||
CharUnits EltAlign =
|
||||
DestAlign.alignmentAtOffset(CharUnits::fromQuantity(EltOffset));
|
||||
CGF.Builder.CreateAlignedStore(Elt, EltPtr, EltAlign.getQuantity(),
|
||||
DestIsVolatile);
|
||||
}
|
||||
} else {
|
||||
llvm::StoreInst *SI = CGF.Builder.CreateStore(Val, DestPtr, DestIsVolatile);
|
||||
if (LowAlignment)
|
||||
SI->setAlignment(1);
|
||||
CGF.Builder.CreateAlignedStore(Val, DestPtr, DestAlign.getQuantity(),
|
||||
DestIsVolatile);
|
||||
}
|
||||
}
|
||||
|
||||
/// CreateCoercedStore - Create a store to \arg DstPtr from \arg Src,
|
||||
/// where the source and destination may have different types.
|
||||
/// where the source and destination may have different types. The
|
||||
/// destination is known to be aligned to \arg DstAlign bytes.
|
||||
///
|
||||
/// This safely handles the case when the src type is larger than the
|
||||
/// destination type; the upper bits of the src will be lost.
|
||||
static void CreateCoercedStore(llvm::Value *Src,
|
||||
llvm::Value *DstPtr,
|
||||
bool DstIsVolatile,
|
||||
CharUnits DstAlign,
|
||||
CodeGenFunction &CGF) {
|
||||
llvm::Type *SrcTy = Src->getType();
|
||||
llvm::Type *DstTy =
|
||||
cast<llvm::PointerType>(DstPtr->getType())->getElementType();
|
||||
if (SrcTy == DstTy) {
|
||||
CGF.Builder.CreateStore(Src, DstPtr, DstIsVolatile);
|
||||
CGF.Builder.CreateAlignedStore(Src, DstPtr, DstAlign.getQuantity(),
|
||||
DstIsVolatile);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1027,7 +1032,8 @@ static void CreateCoercedStore(llvm::Value *Src,
|
||||
if ((isa<llvm::IntegerType>(SrcTy) || isa<llvm::PointerType>(SrcTy)) &&
|
||||
(isa<llvm::IntegerType>(DstTy) || isa<llvm::PointerType>(DstTy))) {
|
||||
Src = CoerceIntOrPtrToIntOrPtr(Src, DstTy, CGF);
|
||||
CGF.Builder.CreateStore(Src, DstPtr, DstIsVolatile);
|
||||
CGF.Builder.CreateAlignedStore(Src, DstPtr, DstAlign.getQuantity(),
|
||||
DstIsVolatile);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1037,8 +1043,7 @@ static void CreateCoercedStore(llvm::Value *Src,
|
||||
if (SrcSize <= DstSize) {
|
||||
llvm::Value *Casted =
|
||||
CGF.Builder.CreateBitCast(DstPtr, llvm::PointerType::getUnqual(SrcTy));
|
||||
// FIXME: Use better alignment / avoid requiring aligned store.
|
||||
BuildAggStore(CGF, Src, Casted, DstIsVolatile, true);
|
||||
BuildAggStore(CGF, Src, Casted, DstIsVolatile, DstAlign);
|
||||
} else {
|
||||
// Otherwise do coercion through memory. This is stupid, but
|
||||
// simple.
|
||||
@ -1049,15 +1054,15 @@ static void CreateCoercedStore(llvm::Value *Src,
|
||||
//
|
||||
// FIXME: Assert that we aren't truncating non-padding bits when have access
|
||||
// to that information.
|
||||
llvm::Value *Tmp = CGF.CreateTempAlloca(SrcTy);
|
||||
CGF.Builder.CreateStore(Src, Tmp);
|
||||
llvm::AllocaInst *Tmp = CGF.CreateTempAlloca(SrcTy);
|
||||
Tmp->setAlignment(DstAlign.getQuantity());
|
||||
CGF.Builder.CreateAlignedStore(Src, Tmp, DstAlign.getQuantity());
|
||||
llvm::Type *I8PtrTy = CGF.Builder.getInt8PtrTy();
|
||||
llvm::Value *Casted = CGF.Builder.CreateBitCast(Tmp, I8PtrTy);
|
||||
llvm::Value *DstCasted = CGF.Builder.CreateBitCast(DstPtr, I8PtrTy);
|
||||
// FIXME: Use better alignment.
|
||||
CGF.Builder.CreateMemCpy(DstCasted, Casted,
|
||||
llvm::ConstantInt::get(CGF.IntPtrTy, DstSize),
|
||||
1, false);
|
||||
DstAlign.getQuantity(), false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1506,7 +1511,7 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
|
||||
|
||||
const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(TargetDecl);
|
||||
if (FD) {
|
||||
if (const TargetAttr *TD = FD->getAttr<TargetAttr>()) {
|
||||
if (const auto *TD = FD->getAttr<TargetAttr>()) {
|
||||
StringRef FeaturesStr = TD->getFeatures();
|
||||
SmallVector<StringRef, 1> AttrFeatures;
|
||||
FeaturesStr.split(AttrFeatures, ",");
|
||||
@ -1514,9 +1519,13 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
|
||||
// Grab the various features and prepend a "+" to turn on the feature to
|
||||
// the backend and add them to our existing set of features.
|
||||
for (auto &Feature : AttrFeatures) {
|
||||
// Go ahead and trim whitespace rather than either erroring or
|
||||
// accepting it weirdly.
|
||||
Feature = Feature.trim();
|
||||
|
||||
// While we're here iterating check for a different target cpu.
|
||||
if (Feature.startswith("arch="))
|
||||
TargetCPU = Feature.split("=").second;
|
||||
TargetCPU = Feature.split("=").second.trim();
|
||||
else if (Feature.startswith("tune="))
|
||||
// We don't support cpu tuning this way currently.
|
||||
;
|
||||
@ -1992,6 +2001,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
|
||||
Alloca->setAlignment(AlignmentToUse);
|
||||
llvm::Value *V = Alloca;
|
||||
llvm::Value *Ptr = V; // Pointer to store into.
|
||||
CharUnits PtrAlign = CharUnits::fromQuantity(AlignmentToUse);
|
||||
|
||||
// If the value is offset in memory, apply the offset now.
|
||||
if (unsigned Offs = ArgI.getDirectOffset()) {
|
||||
@ -1999,6 +2009,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
|
||||
Ptr = Builder.CreateConstGEP1_32(Builder.getInt8Ty(), Ptr, Offs);
|
||||
Ptr = Builder.CreateBitCast(Ptr,
|
||||
llvm::PointerType::getUnqual(ArgI.getCoerceToType()));
|
||||
PtrAlign = PtrAlign.alignmentAtOffset(CharUnits::fromQuantity(Offs));
|
||||
}
|
||||
|
||||
// Fast-isel and the optimizer generally like scalar values better than
|
||||
@ -2043,7 +2054,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
|
||||
assert(NumIRArgs == 1);
|
||||
auto AI = FnArgs[FirstIRArg];
|
||||
AI->setName(Arg->getName() + ".coerce");
|
||||
CreateCoercedStore(AI, Ptr, /*DestIsVolatile=*/false, *this);
|
||||
CreateCoercedStore(AI, Ptr, /*DestIsVolatile=*/false, PtrAlign, *this);
|
||||
}
|
||||
|
||||
|
||||
@ -2411,15 +2422,17 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI,
|
||||
}
|
||||
} else {
|
||||
llvm::Value *V = ReturnValue;
|
||||
CharUnits Align = getContext().getTypeAlignInChars(RetTy);
|
||||
// If the value is offset in memory, apply the offset now.
|
||||
if (unsigned Offs = RetAI.getDirectOffset()) {
|
||||
V = Builder.CreateBitCast(V, Builder.getInt8PtrTy());
|
||||
V = Builder.CreateConstGEP1_32(Builder.getInt8Ty(), V, Offs);
|
||||
V = Builder.CreateBitCast(V,
|
||||
llvm::PointerType::getUnqual(RetAI.getCoerceToType()));
|
||||
Align = Align.alignmentAtOffset(CharUnits::fromQuantity(Offs));
|
||||
}
|
||||
|
||||
RV = CreateCoercedLoad(V, RetAI.getCoerceToType(), *this);
|
||||
RV = CreateCoercedLoad(V, RetAI.getCoerceToType(), Align, *this);
|
||||
}
|
||||
|
||||
// In ARC, end functions that return a retainable type with a call
|
||||
@ -3282,12 +3295,17 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
|
||||
|
||||
// FIXME: Avoid the conversion through memory if possible.
|
||||
llvm::Value *SrcPtr;
|
||||
CharUnits SrcAlign;
|
||||
if (RV.isScalar() || RV.isComplex()) {
|
||||
SrcPtr = CreateMemTemp(I->Ty, "coerce");
|
||||
SrcAlign = TypeAlign;
|
||||
LValue SrcLV = MakeAddrLValue(SrcPtr, I->Ty, TypeAlign);
|
||||
EmitInitStoreOfNonAggregate(*this, RV, SrcLV);
|
||||
} else
|
||||
} else {
|
||||
SrcPtr = RV.getAggregateAddr();
|
||||
// This alignment is guaranteed by EmitCallArg.
|
||||
SrcAlign = TypeAlign;
|
||||
}
|
||||
|
||||
// If the value is offset in memory, apply the offset now.
|
||||
if (unsigned Offs = ArgInfo.getDirectOffset()) {
|
||||
@ -3295,7 +3313,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
|
||||
SrcPtr = Builder.CreateConstGEP1_32(Builder.getInt8Ty(), SrcPtr, Offs);
|
||||
SrcPtr = Builder.CreateBitCast(SrcPtr,
|
||||
llvm::PointerType::getUnqual(ArgInfo.getCoerceToType()));
|
||||
|
||||
SrcAlign = SrcAlign.alignmentAtOffset(CharUnits::fromQuantity(Offs));
|
||||
}
|
||||
|
||||
// Fast-isel and the optimizer generally like scalar values better than
|
||||
@ -3334,7 +3352,8 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
|
||||
// In the simple case, just pass the coerced loaded value.
|
||||
assert(NumIRArgs == 1);
|
||||
IRCallArgs[FirstIRArg] =
|
||||
CreateCoercedLoad(SrcPtr, ArgInfo.getCoerceToType(), *this);
|
||||
CreateCoercedLoad(SrcPtr, ArgInfo.getCoerceToType(),
|
||||
SrcAlign, *this);
|
||||
}
|
||||
|
||||
break;
|
||||
@ -3531,12 +3550,13 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
|
||||
case TEK_Aggregate: {
|
||||
llvm::Value *DestPtr = ReturnValue.getValue();
|
||||
bool DestIsVolatile = ReturnValue.isVolatile();
|
||||
CharUnits DestAlign = getContext().getTypeAlignInChars(RetTy);
|
||||
|
||||
if (!DestPtr) {
|
||||
DestPtr = CreateMemTemp(RetTy, "agg.tmp");
|
||||
DestIsVolatile = false;
|
||||
}
|
||||
BuildAggStore(*this, CI, DestPtr, DestIsVolatile, false);
|
||||
BuildAggStore(*this, CI, DestPtr, DestIsVolatile, DestAlign);
|
||||
return RValue::getAggregate(DestPtr);
|
||||
}
|
||||
case TEK_Scalar: {
|
||||
@ -3553,6 +3573,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
|
||||
|
||||
llvm::Value *DestPtr = ReturnValue.getValue();
|
||||
bool DestIsVolatile = ReturnValue.isVolatile();
|
||||
CharUnits DestAlign = getContext().getTypeAlignInChars(RetTy);
|
||||
|
||||
if (!DestPtr) {
|
||||
DestPtr = CreateMemTemp(RetTy, "coerce");
|
||||
@ -3561,14 +3582,17 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
|
||||
|
||||
// If the value is offset in memory, apply the offset now.
|
||||
llvm::Value *StorePtr = DestPtr;
|
||||
CharUnits StoreAlign = DestAlign;
|
||||
if (unsigned Offs = RetAI.getDirectOffset()) {
|
||||
StorePtr = Builder.CreateBitCast(StorePtr, Builder.getInt8PtrTy());
|
||||
StorePtr =
|
||||
Builder.CreateConstGEP1_32(Builder.getInt8Ty(), StorePtr, Offs);
|
||||
StorePtr = Builder.CreateBitCast(StorePtr,
|
||||
llvm::PointerType::getUnqual(RetAI.getCoerceToType()));
|
||||
StoreAlign =
|
||||
StoreAlign.alignmentAtOffset(CharUnits::fromQuantity(Offs));
|
||||
}
|
||||
CreateCoercedStore(CI, StorePtr, DestIsVolatile, *this);
|
||||
CreateCoercedStore(CI, StorePtr, DestIsVolatile, StoreAlign, *this);
|
||||
|
||||
return convertTempToRValue(DestPtr, RetTy, SourceLocation());
|
||||
}
|
||||
|
@ -554,6 +554,20 @@ static bool isMemcpyEquivalentSpecialMember(const CXXMethodDecl *D) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static void EmitLValueForAnyFieldInitialization(CodeGenFunction &CGF,
|
||||
CXXCtorInitializer *MemberInit,
|
||||
LValue &LHS) {
|
||||
FieldDecl *Field = MemberInit->getAnyMember();
|
||||
if (MemberInit->isIndirectMemberInitializer()) {
|
||||
// If we are initializing an anonymous union field, drill down to the field.
|
||||
IndirectFieldDecl *IndirectField = MemberInit->getIndirectMember();
|
||||
for (const auto *I : IndirectField->chain())
|
||||
LHS = CGF.EmitLValueForFieldInitialization(LHS, cast<FieldDecl>(I));
|
||||
} else {
|
||||
LHS = CGF.EmitLValueForFieldInitialization(LHS, Field);
|
||||
}
|
||||
}
|
||||
|
||||
static void EmitMemberInitializer(CodeGenFunction &CGF,
|
||||
const CXXRecordDecl *ClassDecl,
|
||||
CXXCtorInitializer *MemberInit,
|
||||
@ -572,16 +586,7 @@ static void EmitMemberInitializer(CodeGenFunction &CGF,
|
||||
QualType RecordTy = CGF.getContext().getTypeDeclType(ClassDecl);
|
||||
LValue LHS = CGF.MakeNaturalAlignAddrLValue(ThisPtr, RecordTy);
|
||||
|
||||
if (MemberInit->isIndirectMemberInitializer()) {
|
||||
// If we are initializing an anonymous union field, drill down to
|
||||
// the field.
|
||||
IndirectFieldDecl *IndirectField = MemberInit->getIndirectMember();
|
||||
for (const auto *I : IndirectField->chain())
|
||||
LHS = CGF.EmitLValueForFieldInitialization(LHS, cast<FieldDecl>(I));
|
||||
FieldType = MemberInit->getIndirectMember()->getAnonField()->getType();
|
||||
} else {
|
||||
LHS = CGF.EmitLValueForFieldInitialization(LHS, Field);
|
||||
}
|
||||
EmitLValueForAnyFieldInitialization(CGF, MemberInit, LHS);
|
||||
|
||||
// Special case: if we are in a copy or move constructor, and we are copying
|
||||
// an array of PODs or classes with trivial copy constructors, ignore the
|
||||
@ -606,6 +611,11 @@ static void EmitMemberInitializer(CodeGenFunction &CGF,
|
||||
// Copy the aggregate.
|
||||
CGF.EmitAggregateCopy(LHS.getAddress(), Src.getAddress(), FieldType,
|
||||
LHS.isVolatileQualified());
|
||||
// Ensure that we destroy the objects if an exception is thrown later in
|
||||
// the constructor.
|
||||
QualType::DestructionKind dtorKind = FieldType.isDestructedType();
|
||||
if (CGF.needsEHCleanup(dtorKind))
|
||||
CGF.pushEHDestroy(dtorKind, LHS.getAddress(), FieldType);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -906,32 +916,18 @@ namespace {
|
||||
return;
|
||||
}
|
||||
|
||||
CharUnits Alignment;
|
||||
|
||||
uint64_t FirstByteOffset;
|
||||
if (FirstField->isBitField()) {
|
||||
const CGRecordLayout &RL =
|
||||
CGF.getTypes().getCGRecordLayout(FirstField->getParent());
|
||||
const CGBitFieldInfo &BFInfo = RL.getBitFieldInfo(FirstField);
|
||||
Alignment = CharUnits::fromQuantity(BFInfo.StorageAlignment);
|
||||
// FirstFieldOffset is not appropriate for bitfields,
|
||||
// it won't tell us what the storage offset should be and thus might not
|
||||
// be properly aligned.
|
||||
//
|
||||
// Instead calculate the storage offset using the offset of the field in
|
||||
// the struct type.
|
||||
const llvm::DataLayout &DL = CGF.CGM.getDataLayout();
|
||||
FirstByteOffset =
|
||||
DL.getStructLayout(RL.getLLVMType())
|
||||
->getElementOffsetInBits(RL.getLLVMFieldNo(FirstField));
|
||||
// we need to use the storage offset instead.
|
||||
FirstByteOffset = CGF.getContext().toBits(BFInfo.StorageOffset);
|
||||
} else {
|
||||
Alignment = CGF.getContext().getDeclAlign(FirstField);
|
||||
FirstByteOffset = FirstFieldOffset;
|
||||
}
|
||||
|
||||
assert((CGF.getContext().toCharUnitsFromBits(FirstByteOffset) %
|
||||
Alignment) == 0 && "Bad field alignment.");
|
||||
|
||||
CharUnits MemcpySize = getMemcpySize(FirstByteOffset);
|
||||
QualType RecordTy = CGF.getContext().getTypeDeclType(ClassDecl);
|
||||
llvm::Value *ThisPtr = CGF.LoadCXXThis();
|
||||
@ -941,6 +937,9 @@ namespace {
|
||||
LValue SrcLV = CGF.MakeNaturalAlignAddrLValue(SrcPtr, RecordTy);
|
||||
LValue Src = CGF.EmitLValueForFieldInitialization(SrcLV, FirstField);
|
||||
|
||||
CharUnits Offset = CGF.getContext().toCharUnitsFromBits(FirstByteOffset);
|
||||
CharUnits Alignment = DestLV.getAlignment().alignmentAtOffset(Offset);
|
||||
|
||||
emitMemcpyIR(Dest.isBitField() ? Dest.getBitFieldAddr() : Dest.getAddress(),
|
||||
Src.isBitField() ? Src.getBitFieldAddr() : Src.getAddress(),
|
||||
MemcpySize, Alignment);
|
||||
@ -1078,6 +1077,7 @@ namespace {
|
||||
CopyingValueRepresentation CVR(CGF);
|
||||
EmitMemberInitializer(CGF, ConstructorDecl->getParent(),
|
||||
AggregatedInits[0], ConstructorDecl, Args);
|
||||
AggregatedInits.clear();
|
||||
}
|
||||
reset();
|
||||
return;
|
||||
@ -1094,10 +1094,14 @@ namespace {
|
||||
LValue LHS = CGF.MakeNaturalAlignAddrLValue(ThisPtr, RecordTy);
|
||||
|
||||
for (unsigned i = 0; i < AggregatedInits.size(); ++i) {
|
||||
QualType FieldType = AggregatedInits[i]->getMember()->getType();
|
||||
CXXCtorInitializer *MemberInit = AggregatedInits[i];
|
||||
QualType FieldType = MemberInit->getAnyMember()->getType();
|
||||
QualType::DestructionKind dtorKind = FieldType.isDestructedType();
|
||||
if (CGF.needsEHCleanup(dtorKind))
|
||||
CGF.pushEHDestroy(dtorKind, LHS.getAddress(), FieldType);
|
||||
if (!CGF.needsEHCleanup(dtorKind))
|
||||
continue;
|
||||
LValue FieldLHS = LHS;
|
||||
EmitLValueForAnyFieldInitialization(CGF, MemberInit, FieldLHS);
|
||||
CGF.pushEHDestroy(dtorKind, FieldLHS.getAddress(), FieldType);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1363,6 +1367,25 @@ static bool CanSkipVTablePointerInitialization(ASTContext &Context,
|
||||
return true;
|
||||
}
|
||||
|
||||
// Generates function call for handling object poisoning, passing in
|
||||
// references to 'this' and its size as arguments.
|
||||
static void EmitDtorSanitizerCallback(CodeGenFunction &CGF,
|
||||
const CXXDestructorDecl *Dtor) {
|
||||
const ASTRecordLayout &Layout =
|
||||
CGF.getContext().getASTRecordLayout(Dtor->getParent());
|
||||
|
||||
llvm::Value *Args[] = {
|
||||
CGF.Builder.CreateBitCast(CGF.LoadCXXThis(), CGF.VoidPtrTy),
|
||||
llvm::ConstantInt::get(CGF.SizeTy, Layout.getSize().getQuantity())};
|
||||
llvm::Type *ArgTypes[] = {CGF.VoidPtrTy, CGF.SizeTy};
|
||||
|
||||
llvm::FunctionType *FnType =
|
||||
llvm::FunctionType::get(CGF.VoidTy, ArgTypes, false);
|
||||
llvm::Value *Fn =
|
||||
CGF.CGM.CreateRuntimeFunction(FnType, "__sanitizer_dtor_callback");
|
||||
CGF.EmitNounwindRuntimeCall(Fn, Args);
|
||||
}
|
||||
|
||||
/// EmitDestructorBody - Emits the body of the current destructor.
|
||||
void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
|
||||
const CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(CurGD.getDecl());
|
||||
@ -1450,6 +1473,10 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
|
||||
// Exit the try if applicable.
|
||||
if (isTryBody)
|
||||
ExitCXXTryStmt(*cast<CXXTryStmt>(Body), true);
|
||||
|
||||
// Insert memory-poisoning instrumentation.
|
||||
if (CGM.getCodeGenOpts().SanitizeMemoryUseAfterDtor)
|
||||
EmitDtorSanitizerCallback(*this, Dtor);
|
||||
}
|
||||
|
||||
void CodeGenFunction::emitImplicitAssignmentOperatorBody(FunctionArgList &Args) {
|
||||
@ -2202,8 +2229,7 @@ void CodeGenFunction::EmitVTablePtrCheck(const CXXRecordDecl *RD,
|
||||
llvm::Value *VTable,
|
||||
CFITypeCheckKind TCK,
|
||||
SourceLocation Loc) {
|
||||
// FIXME: Add blacklisting scheme.
|
||||
if (RD->isInStdNamespace())
|
||||
if (CGM.IsCFIBlacklistedRecord(RD))
|
||||
return;
|
||||
|
||||
SanitizerScope SanScope(this);
|
||||
|
@ -106,8 +106,6 @@ ApplyDebugLocation::~ApplyDebugLocation() {
|
||||
CGF.Builder.SetCurrentDebugLocation(std::move(OriginalLocation));
|
||||
}
|
||||
|
||||
/// ArtificialLocation - An RAII object that temporarily switches to
|
||||
/// an artificial debug location that has a valid scope, but no line
|
||||
void CGDebugInfo::setLocation(SourceLocation Loc) {
|
||||
// If the new location isn't valid return.
|
||||
if (Loc.isInvalid())
|
||||
@ -140,7 +138,6 @@ void CGDebugInfo::setLocation(SourceLocation Loc) {
|
||||
}
|
||||
}
|
||||
|
||||
/// getContextDescriptor - Get context info for the decl.
|
||||
llvm::DIScope *CGDebugInfo::getContextDescriptor(const Decl *Context) {
|
||||
if (!Context)
|
||||
return TheCU;
|
||||
@ -162,9 +159,6 @@ llvm::DIScope *CGDebugInfo::getContextDescriptor(const Decl *Context) {
|
||||
return TheCU;
|
||||
}
|
||||
|
||||
/// getFunctionName - Get function name for the given FunctionDecl. If the
|
||||
/// name is constructed on demand (e.g. C++ destructor) then the name
|
||||
/// is stored on the side.
|
||||
StringRef CGDebugInfo::getFunctionName(const FunctionDecl *FD) {
|
||||
assert(FD && "Invalid FunctionDecl!");
|
||||
IdentifierInfo *FII = FD->getIdentifier();
|
||||
@ -220,13 +214,10 @@ StringRef CGDebugInfo::getObjCMethodName(const ObjCMethodDecl *OMD) {
|
||||
return internString(OS.str());
|
||||
}
|
||||
|
||||
/// getSelectorName - Return selector name. This is used for debugging
|
||||
/// info.
|
||||
StringRef CGDebugInfo::getSelectorName(Selector S) {
|
||||
return internString(S.getAsString());
|
||||
}
|
||||
|
||||
/// getClassName - Get class name including template argument list.
|
||||
StringRef CGDebugInfo::getClassName(const RecordDecl *RD) {
|
||||
// quick optimization to avoid having to intern strings that are already
|
||||
// stored reliably elsewhere
|
||||
@ -244,7 +235,6 @@ StringRef CGDebugInfo::getClassName(const RecordDecl *RD) {
|
||||
return internString(Name);
|
||||
}
|
||||
|
||||
/// getOrCreateFile - Get the file debug info descriptor for the input location.
|
||||
llvm::DIFile *CGDebugInfo::getOrCreateFile(SourceLocation Loc) {
|
||||
if (!Loc.isValid())
|
||||
// If Location is not valid then use main input file.
|
||||
@ -274,13 +264,10 @@ llvm::DIFile *CGDebugInfo::getOrCreateFile(SourceLocation Loc) {
|
||||
return F;
|
||||
}
|
||||
|
||||
/// getOrCreateMainFile - Get the file info for main compile unit.
|
||||
llvm::DIFile *CGDebugInfo::getOrCreateMainFile() {
|
||||
return DBuilder.createFile(TheCU->getFilename(), TheCU->getDirectory());
|
||||
}
|
||||
|
||||
/// getLineNumber - Get line number for the location. If location is invalid
|
||||
/// then use current location.
|
||||
unsigned CGDebugInfo::getLineNumber(SourceLocation Loc) {
|
||||
if (Loc.isInvalid() && CurLoc.isInvalid())
|
||||
return 0;
|
||||
@ -289,7 +276,6 @@ unsigned CGDebugInfo::getLineNumber(SourceLocation Loc) {
|
||||
return PLoc.isValid() ? PLoc.getLine() : 0;
|
||||
}
|
||||
|
||||
/// getColumnNumber - Get column number for the location.
|
||||
unsigned CGDebugInfo::getColumnNumber(SourceLocation Loc, bool Force) {
|
||||
// We may not want column information at all.
|
||||
if (!Force && !CGM.getCodeGenOpts().DebugColumnInfo)
|
||||
@ -314,7 +300,6 @@ StringRef CGDebugInfo::getCurrentDirname() {
|
||||
return CWDName = internString(CWD);
|
||||
}
|
||||
|
||||
/// CreateCompileUnit - Create new compile unit.
|
||||
void CGDebugInfo::CreateCompileUnit() {
|
||||
|
||||
// Should we be asking the SourceManager for the main file name, instead of
|
||||
@ -385,8 +370,6 @@ void CGDebugInfo::CreateCompileUnit() {
|
||||
DebugKind != CodeGenOptions::LocTrackingOnly);
|
||||
}
|
||||
|
||||
/// CreateType - Get the Basic type from the cache or create a new
|
||||
/// one if necessary.
|
||||
llvm::DIType *CGDebugInfo::CreateType(const BuiltinType *BT) {
|
||||
llvm::dwarf::TypeKind Encoding;
|
||||
StringRef BTName;
|
||||
@ -537,8 +520,6 @@ llvm::DIType *CGDebugInfo::CreateType(const ComplexType *Ty) {
|
||||
return DBuilder.createBasicType("complex", Size, Align, Encoding);
|
||||
}
|
||||
|
||||
/// CreateCVRType - Get the qualified type from the cache or create
|
||||
/// a new one if necessary.
|
||||
llvm::DIType *CGDebugInfo::CreateQualifiedType(QualType Ty,
|
||||
llvm::DIFile *Unit) {
|
||||
QualifierCollector Qc;
|
||||
@ -627,6 +608,7 @@ static SmallString<256> getUniqueTagTypeName(const TagType *Ty,
|
||||
return FullName;
|
||||
}
|
||||
|
||||
/// \return the approproate DWARF tag for a composite type.
|
||||
static llvm::dwarf::Tag getTagForRecord(const RecordDecl *RD) {
|
||||
llvm::dwarf::Tag Tag;
|
||||
if (RD->isStruct() || RD->isInterface())
|
||||
@ -642,7 +624,6 @@ static llvm::dwarf::Tag getTagForRecord(const RecordDecl *RD) {
|
||||
return Tag;
|
||||
}
|
||||
|
||||
// Creates a forward declaration for a RecordDecl in the given context.
|
||||
llvm::DICompositeType *
|
||||
CGDebugInfo::getOrCreateRecordFwdDecl(const RecordType *Ty,
|
||||
llvm::DIScope *Ctx) {
|
||||
@ -705,9 +686,6 @@ llvm::DIType *CGDebugInfo::getOrCreateStructPtrType(StringRef Name,
|
||||
|
||||
llvm::DIType *CGDebugInfo::CreateType(const BlockPointerType *Ty,
|
||||
llvm::DIFile *Unit) {
|
||||
if (BlockLiteralGeneric)
|
||||
return BlockLiteralGeneric;
|
||||
|
||||
SmallVector<llvm::Metadata *, 8> EltTys;
|
||||
QualType FType;
|
||||
uint64_t FieldSize, FieldOffset;
|
||||
@ -723,10 +701,10 @@ llvm::DIType *CGDebugInfo::CreateType(const BlockPointerType *Ty,
|
||||
EltTys.clear();
|
||||
|
||||
unsigned Flags = llvm::DINode::FlagAppleBlock;
|
||||
unsigned LineNo = getLineNumber(CurLoc);
|
||||
unsigned LineNo = 0;
|
||||
|
||||
auto *EltTy =
|
||||
DBuilder.createStructType(Unit, "__block_descriptor", Unit, LineNo,
|
||||
DBuilder.createStructType(Unit, "__block_descriptor", nullptr, LineNo,
|
||||
FieldOffset, 0, Flags, nullptr, Elements);
|
||||
|
||||
// Bit size, align and offset of the type.
|
||||
@ -746,19 +724,22 @@ llvm::DIType *CGDebugInfo::CreateType(const BlockPointerType *Ty,
|
||||
FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
|
||||
FieldSize = CGM.getContext().getTypeSize(Ty);
|
||||
FieldAlign = CGM.getContext().getTypeAlign(Ty);
|
||||
EltTys.push_back(DBuilder.createMemberType(Unit, "__descriptor", Unit, LineNo,
|
||||
EltTys.push_back(DBuilder.createMemberType(Unit, "__descriptor", nullptr, LineNo,
|
||||
FieldSize, FieldAlign, FieldOffset,
|
||||
0, DescTy));
|
||||
|
||||
FieldOffset += FieldSize;
|
||||
Elements = DBuilder.getOrCreateArray(EltTys);
|
||||
|
||||
// The __block_literal_generic structs are marked with a special
|
||||
// DW_AT_APPLE_BLOCK attribute and are an implementation detail only
|
||||
// the debugger needs to know about. To allow type uniquing, emit
|
||||
// them without a name or a location.
|
||||
EltTy =
|
||||
DBuilder.createStructType(Unit, "__block_literal_generic", Unit, LineNo,
|
||||
DBuilder.createStructType(Unit, "", nullptr, LineNo,
|
||||
FieldOffset, 0, Flags, nullptr, Elements);
|
||||
|
||||
BlockLiteralGeneric = DBuilder.createPointerType(EltTy, Size);
|
||||
return BlockLiteralGeneric;
|
||||
return DBuilder.createPointerType(EltTy, Size);
|
||||
}
|
||||
|
||||
llvm::DIType *CGDebugInfo::CreateType(const TemplateSpecializationType *Ty,
|
||||
@ -871,7 +852,6 @@ llvm::DIType *CGDebugInfo::createFieldType(
|
||||
AlignInBits, offsetInBits, flags, debugType);
|
||||
}
|
||||
|
||||
/// CollectRecordLambdaFields - Helper for CollectRecordFields.
|
||||
void CGDebugInfo::CollectRecordLambdaFields(
|
||||
const CXXRecordDecl *CXXDecl, SmallVectorImpl<llvm::Metadata *> &elements,
|
||||
llvm::DIType *RecordTy) {
|
||||
@ -916,7 +896,6 @@ void CGDebugInfo::CollectRecordLambdaFields(
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper for CollectRecordFields.
|
||||
llvm::DIDerivedType *
|
||||
CGDebugInfo::CreateRecordStaticField(const VarDecl *Var, llvm::DIType *RecordTy,
|
||||
const RecordDecl *RD) {
|
||||
@ -946,7 +925,6 @@ CGDebugInfo::CreateRecordStaticField(const VarDecl *Var, llvm::DIType *RecordTy,
|
||||
return GV;
|
||||
}
|
||||
|
||||
/// CollectRecordNormalField - Helper for CollectRecordFields.
|
||||
void CGDebugInfo::CollectRecordNormalField(
|
||||
const FieldDecl *field, uint64_t OffsetInBits, llvm::DIFile *tunit,
|
||||
SmallVectorImpl<llvm::Metadata *> &elements, llvm::DIType *RecordTy,
|
||||
@ -971,8 +949,6 @@ void CGDebugInfo::CollectRecordNormalField(
|
||||
elements.push_back(fieldType);
|
||||
}
|
||||
|
||||
/// CollectRecordFields - A helper function to collect debug info for
|
||||
/// record fields. This is used while creating debug info entry for a Record.
|
||||
void CGDebugInfo::CollectRecordFields(
|
||||
const RecordDecl *record, llvm::DIFile *tunit,
|
||||
SmallVectorImpl<llvm::Metadata *> &elements,
|
||||
@ -1011,9 +987,6 @@ void CGDebugInfo::CollectRecordFields(
|
||||
}
|
||||
}
|
||||
|
||||
/// getOrCreateMethodType - CXXMethodDecl's type is a FunctionType. This
|
||||
/// function type is not updated to include implicit "this" pointer. Use this
|
||||
/// routine to get a method type which includes "this" pointer.
|
||||
llvm::DISubroutineType *
|
||||
CGDebugInfo::getOrCreateMethodType(const CXXMethodDecl *Method,
|
||||
llvm::DIFile *Unit) {
|
||||
@ -1088,8 +1061,6 @@ static bool isFunctionLocalClass(const CXXRecordDecl *RD) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/// CreateCXXMemberFunction - A helper function to create a subprogram for
|
||||
/// a single member function GlobalDecl.
|
||||
llvm::DISubprogram *CGDebugInfo::CreateCXXMemberFunction(
|
||||
const CXXMethodDecl *Method, llvm::DIFile *Unit, llvm::DIType *RecordTy) {
|
||||
bool IsCtorOrDtor =
|
||||
@ -1165,9 +1136,6 @@ llvm::DISubprogram *CGDebugInfo::CreateCXXMemberFunction(
|
||||
return SP;
|
||||
}
|
||||
|
||||
/// CollectCXXMemberFunctions - A helper function to collect debug info for
|
||||
/// C++ member functions. This is used while creating debug info entry for
|
||||
/// a Record.
|
||||
void CGDebugInfo::CollectCXXMemberFunctions(
|
||||
const CXXRecordDecl *RD, llvm::DIFile *Unit,
|
||||
SmallVectorImpl<llvm::Metadata *> &EltTys, llvm::DIType *RecordTy) {
|
||||
@ -1206,9 +1174,6 @@ void CGDebugInfo::CollectCXXMemberFunctions(
|
||||
}
|
||||
}
|
||||
|
||||
/// CollectCXXBases - A helper function to collect debug info for
|
||||
/// C++ base classes. This is used while creating debug info entry for
|
||||
/// a Record.
|
||||
void CGDebugInfo::CollectCXXBases(const CXXRecordDecl *RD, llvm::DIFile *Unit,
|
||||
SmallVectorImpl<llvm::Metadata *> &EltTys,
|
||||
llvm::DIType *RecordTy) {
|
||||
@ -1246,7 +1211,6 @@ void CGDebugInfo::CollectCXXBases(const CXXRecordDecl *RD, llvm::DIFile *Unit,
|
||||
}
|
||||
}
|
||||
|
||||
/// CollectTemplateParams - A helper function to collect template parameters.
|
||||
llvm::DINodeArray
|
||||
CGDebugInfo::CollectTemplateParams(const TemplateParameterList *TPList,
|
||||
ArrayRef<TemplateArgument> TAList,
|
||||
@ -1351,8 +1315,6 @@ CGDebugInfo::CollectTemplateParams(const TemplateParameterList *TPList,
|
||||
return DBuilder.getOrCreateArray(TemplateParams);
|
||||
}
|
||||
|
||||
/// CollectFunctionTemplateParams - A helper function to collect debug
|
||||
/// info for function template parameters.
|
||||
llvm::DINodeArray
|
||||
CGDebugInfo::CollectFunctionTemplateParams(const FunctionDecl *FD,
|
||||
llvm::DIFile *Unit) {
|
||||
@ -1367,8 +1329,6 @@ CGDebugInfo::CollectFunctionTemplateParams(const FunctionDecl *FD,
|
||||
return llvm::DINodeArray();
|
||||
}
|
||||
|
||||
/// CollectCXXTemplateParams - A helper function to collect debug info for
|
||||
/// template parameters.
|
||||
llvm::DINodeArray CGDebugInfo::CollectCXXTemplateParams(
|
||||
const ClassTemplateSpecializationDecl *TSpecial, llvm::DIFile *Unit) {
|
||||
// Always get the full list of parameters, not just the ones from
|
||||
@ -1379,7 +1339,6 @@ llvm::DINodeArray CGDebugInfo::CollectCXXTemplateParams(
|
||||
return CollectTemplateParams(TPList, TAList.asArray(), Unit);
|
||||
}
|
||||
|
||||
/// getOrCreateVTablePtrType - Return debug info descriptor for vtable.
|
||||
llvm::DIType *CGDebugInfo::getOrCreateVTablePtrType(llvm::DIFile *Unit) {
|
||||
if (VTablePtrType)
|
||||
return VTablePtrType;
|
||||
@ -1397,14 +1356,11 @@ llvm::DIType *CGDebugInfo::getOrCreateVTablePtrType(llvm::DIFile *Unit) {
|
||||
return VTablePtrType;
|
||||
}
|
||||
|
||||
/// getVTableName - Get vtable name for the given Class.
|
||||
StringRef CGDebugInfo::getVTableName(const CXXRecordDecl *RD) {
|
||||
// Copy the gdb compatible name on the side and use its reference.
|
||||
return internString("_vptr$", RD->getNameAsString());
|
||||
}
|
||||
|
||||
/// CollectVTableInfo - If the C++ class has vtable info then insert appropriate
|
||||
/// debug info entry in EltTys vector.
|
||||
void CGDebugInfo::CollectVTableInfo(const CXXRecordDecl *RD, llvm::DIFile *Unit,
|
||||
SmallVectorImpl<llvm::Metadata *> &EltTys) {
|
||||
const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD);
|
||||
@ -1424,7 +1380,6 @@ void CGDebugInfo::CollectVTableInfo(const CXXRecordDecl *RD, llvm::DIFile *Unit,
|
||||
EltTys.push_back(VPTR);
|
||||
}
|
||||
|
||||
/// getOrCreateRecordType - Emit record type's standalone debug info.
|
||||
llvm::DIType *CGDebugInfo::getOrCreateRecordType(QualType RTy,
|
||||
SourceLocation Loc) {
|
||||
assert(DebugKind >= CodeGenOptions::LimitedDebugInfo);
|
||||
@ -1432,8 +1387,6 @@ llvm::DIType *CGDebugInfo::getOrCreateRecordType(QualType RTy,
|
||||
return T;
|
||||
}
|
||||
|
||||
/// getOrCreateInterfaceType - Emit an objective c interface type standalone
|
||||
/// debug info.
|
||||
llvm::DIType *CGDebugInfo::getOrCreateInterfaceType(QualType D,
|
||||
SourceLocation Loc) {
|
||||
assert(DebugKind >= CodeGenOptions::LimitedDebugInfo);
|
||||
@ -1531,7 +1484,6 @@ static bool shouldOmitDefinition(CodeGenOptions::DebugInfoKind DebugKind,
|
||||
return false;
|
||||
}
|
||||
|
||||
/// CreateType - get structure or union type.
|
||||
llvm::DIType *CGDebugInfo::CreateType(const RecordType *Ty) {
|
||||
RecordDecl *RD = Ty->getDecl();
|
||||
llvm::DIType *T = cast_or_null<llvm::DIType>(getTypeOrNull(QualType(Ty, 0)));
|
||||
@ -1605,7 +1557,6 @@ llvm::DIType *CGDebugInfo::CreateTypeDefinition(const RecordType *Ty) {
|
||||
return FwdDecl;
|
||||
}
|
||||
|
||||
/// CreateType - get objective-c object type.
|
||||
llvm::DIType *CGDebugInfo::CreateType(const ObjCObjectType *Ty,
|
||||
llvm::DIFile *Unit) {
|
||||
// Ignore protocols.
|
||||
@ -1636,7 +1587,6 @@ static bool hasDefaultSetterName(const ObjCPropertyDecl *PD,
|
||||
Setter->getDeclName().getObjCSelector().getNameForSlot(0);
|
||||
}
|
||||
|
||||
/// CreateType - get objective-c interface type.
|
||||
llvm::DIType *CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
|
||||
llvm::DIFile *Unit) {
|
||||
ObjCInterfaceDecl *ID = Ty->getDecl();
|
||||
@ -1956,7 +1906,6 @@ llvm::DIType *CGDebugInfo::CreateType(const AtomicType *Ty, llvm::DIFile *U) {
|
||||
return getOrCreateType(Ty->getValueType(), U);
|
||||
}
|
||||
|
||||
/// CreateEnumType - get enumeration type.
|
||||
llvm::DIType *CGDebugInfo::CreateEnumType(const EnumType *Ty) {
|
||||
const EnumDecl *ED = Ty->getDecl();
|
||||
uint64_t Size = 0;
|
||||
@ -2076,8 +2025,6 @@ static QualType UnwrapTypeForDebugInfo(QualType T, const ASTContext &C) {
|
||||
} while (true);
|
||||
}
|
||||
|
||||
/// getType - Get the type from the cache or return null type if it doesn't
|
||||
/// exist.
|
||||
llvm::DIType *CGDebugInfo::getTypeOrNull(QualType Ty) {
|
||||
|
||||
// Unwrap the type as needed for debug information.
|
||||
@ -2104,8 +2051,6 @@ void CGDebugInfo::completeTemplateDefinition(
|
||||
RetainedTypes.push_back(CGM.getContext().getRecordType(&SD).getAsOpaquePtr());
|
||||
}
|
||||
|
||||
/// getOrCreateType - Get the type from the cache or create a new
|
||||
/// one if necessary.
|
||||
llvm::DIType *CGDebugInfo::getOrCreateType(QualType Ty, llvm::DIFile *Unit) {
|
||||
if (Ty.isNull())
|
||||
return nullptr;
|
||||
@ -2126,8 +2071,6 @@ llvm::DIType *CGDebugInfo::getOrCreateType(QualType Ty, llvm::DIFile *Unit) {
|
||||
return Res;
|
||||
}
|
||||
|
||||
/// Currently the checksum of an interface includes the number of
|
||||
/// ivars and property accessors.
|
||||
unsigned CGDebugInfo::Checksum(const ObjCInterfaceDecl *ID) {
|
||||
// The assumption is that the number of ivars can only increase
|
||||
// monotonically, so it is safe to just use their current number as
|
||||
@ -2152,7 +2095,6 @@ ObjCInterfaceDecl *CGDebugInfo::getObjCInterfaceDecl(QualType Ty) {
|
||||
}
|
||||
}
|
||||
|
||||
/// CreateTypeNode - Create a new debug type node.
|
||||
llvm::DIType *CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile *Unit) {
|
||||
// Handle qualifiers, which recursively handles what they refer to.
|
||||
if (Ty.hasLocalQualifiers())
|
||||
@ -2233,8 +2175,6 @@ llvm::DIType *CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile *Unit) {
|
||||
llvm_unreachable("type should have been unwrapped!");
|
||||
}
|
||||
|
||||
/// getOrCreateLimitedType - Get the type from the cache or create a new
|
||||
/// limited type if necessary.
|
||||
llvm::DIType *CGDebugInfo::getOrCreateLimitedType(const RecordType *Ty,
|
||||
llvm::DIFile *Unit) {
|
||||
QualType QTy(Ty, 0);
|
||||
@ -2328,7 +2268,6 @@ void CGDebugInfo::CollectContainingType(const CXXRecordDecl *RD,
|
||||
DBuilder.replaceVTableHolder(RealDecl, ContainingType);
|
||||
}
|
||||
|
||||
/// CreateMemberType - Create new member and increase Offset by FType's size.
|
||||
llvm::DIType *CGDebugInfo::CreateMemberType(llvm::DIFile *Unit, QualType FType,
|
||||
StringRef Name, uint64_t *Offset) {
|
||||
llvm::DIType *FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
|
||||
@ -2493,8 +2432,6 @@ llvm::DINode *CGDebugInfo::getDeclarationOrDefinition(const Decl *D) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// getFunctionDeclaration - Return debug info descriptor to describe method
|
||||
/// declaration for the given method definition.
|
||||
llvm::DISubprogram *CGDebugInfo::getFunctionDeclaration(const Decl *D) {
|
||||
if (!D || DebugKind <= CodeGenOptions::DebugLineTablesOnly)
|
||||
return nullptr;
|
||||
@ -2591,7 +2528,6 @@ llvm::DISubroutineType *CGDebugInfo::getOrCreateFunctionType(const Decl *D,
|
||||
return cast<llvm::DISubroutineType>(getOrCreateType(FnType, F));
|
||||
}
|
||||
|
||||
/// EmitFunctionStart - Constructs the debug code for entering a function.
|
||||
void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, SourceLocation Loc,
|
||||
SourceLocation ScopeLoc, QualType FnType,
|
||||
llvm::Function *Fn, CGBuilderTy &Builder) {
|
||||
@ -2667,9 +2603,6 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, SourceLocation Loc,
|
||||
RegionMap[D].reset(SP);
|
||||
}
|
||||
|
||||
/// EmitLocation - Emit metadata to indicate a change in line/column
|
||||
/// information in the source file. If the location is invalid, the
|
||||
/// previous location will be reused.
|
||||
void CGDebugInfo::EmitLocation(CGBuilderTy &Builder, SourceLocation Loc) {
|
||||
// Update our current location
|
||||
setLocation(Loc);
|
||||
@ -2682,8 +2615,6 @@ void CGDebugInfo::EmitLocation(CGBuilderTy &Builder, SourceLocation Loc) {
|
||||
getLineNumber(CurLoc), getColumnNumber(CurLoc), Scope));
|
||||
}
|
||||
|
||||
/// CreateLexicalBlock - Creates a new lexical block node and pushes it on
|
||||
/// the stack.
|
||||
void CGDebugInfo::CreateLexicalBlock(SourceLocation Loc) {
|
||||
llvm::MDNode *Back = nullptr;
|
||||
if (!LexicalBlockStack.empty())
|
||||
@ -2693,8 +2624,6 @@ void CGDebugInfo::CreateLexicalBlock(SourceLocation Loc) {
|
||||
getColumnNumber(CurLoc)));
|
||||
}
|
||||
|
||||
/// EmitLexicalBlockStart - Constructs the debug code for entering a declarative
|
||||
/// region - beginning of a DW_TAG_lexical_block.
|
||||
void CGDebugInfo::EmitLexicalBlockStart(CGBuilderTy &Builder,
|
||||
SourceLocation Loc) {
|
||||
// Set our current location.
|
||||
@ -2711,8 +2640,6 @@ void CGDebugInfo::EmitLexicalBlockStart(CGBuilderTy &Builder,
|
||||
CreateLexicalBlock(Loc);
|
||||
}
|
||||
|
||||
/// EmitLexicalBlockEnd - Constructs the debug code for exiting a declarative
|
||||
/// region - end of a DW_TAG_lexical_block.
|
||||
void CGDebugInfo::EmitLexicalBlockEnd(CGBuilderTy &Builder,
|
||||
SourceLocation Loc) {
|
||||
assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!");
|
||||
@ -2726,7 +2653,6 @@ void CGDebugInfo::EmitLexicalBlockEnd(CGBuilderTy &Builder,
|
||||
LexicalBlockStack.pop_back();
|
||||
}
|
||||
|
||||
/// EmitFunctionEnd - Constructs the debug code for exiting a function.
|
||||
void CGDebugInfo::EmitFunctionEnd(CGBuilderTy &Builder) {
|
||||
assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!");
|
||||
unsigned RCount = FnBeginRegionCount.back();
|
||||
@ -2741,8 +2667,6 @@ void CGDebugInfo::EmitFunctionEnd(CGBuilderTy &Builder) {
|
||||
FnBeginRegionCount.pop_back();
|
||||
}
|
||||
|
||||
// EmitTypeForVarWithBlocksAttr - Build up structure info for the byref.
|
||||
// See BuildByRefType.
|
||||
llvm::DIType *CGDebugInfo::EmitTypeForVarWithBlocksAttr(const VarDecl *VD,
|
||||
uint64_t *XOffset) {
|
||||
|
||||
@ -2816,7 +2740,6 @@ llvm::DIType *CGDebugInfo::EmitTypeForVarWithBlocksAttr(const VarDecl *VD,
|
||||
nullptr, Elements);
|
||||
}
|
||||
|
||||
/// EmitDeclare - Emit local variable declaration debug info.
|
||||
void CGDebugInfo::EmitDeclare(const VarDecl *VD, llvm::dwarf::Tag Tag,
|
||||
llvm::Value *Storage, unsigned ArgNo,
|
||||
CGBuilderTy &Builder) {
|
||||
@ -2944,12 +2867,6 @@ void CGDebugInfo::EmitDeclareOfAutoVariable(const VarDecl *VD,
|
||||
EmitDeclare(VD, llvm::dwarf::DW_TAG_auto_variable, Storage, 0, Builder);
|
||||
}
|
||||
|
||||
/// Look up the completed type for a self pointer in the TypeCache and
|
||||
/// create a copy of it with the ObjectPointer and Artificial flags
|
||||
/// set. If the type is not cached, a new one is created. This should
|
||||
/// never happen though, since creating a type for the implicit self
|
||||
/// argument implies that we already parsed the interface definition
|
||||
/// and the ivar declarations in the implementation.
|
||||
llvm::DIType *CGDebugInfo::CreateSelfType(const QualType &QualTy,
|
||||
llvm::DIType *Ty) {
|
||||
llvm::DIType *CachedTy = getTypeOrNull(QualTy);
|
||||
@ -3027,8 +2944,6 @@ void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable(
|
||||
Builder.GetInsertBlock());
|
||||
}
|
||||
|
||||
/// EmitDeclareOfArgVariable - Emit call to llvm.dbg.declare for an argument
|
||||
/// variable declaration.
|
||||
void CGDebugInfo::EmitDeclareOfArgVariable(const VarDecl *VD, llvm::Value *AI,
|
||||
unsigned ArgNo,
|
||||
CGBuilderTy &Builder) {
|
||||
@ -3192,8 +3107,6 @@ void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
|
||||
Builder.GetInsertBlock());
|
||||
}
|
||||
|
||||
/// If D is an out-of-class definition of a static data member of a class, find
|
||||
/// its corresponding in-class declaration.
|
||||
llvm::DIDerivedType *
|
||||
CGDebugInfo::getOrCreateStaticDataMemberDeclarationOrNull(const VarDecl *D) {
|
||||
if (!D->isStaticDataMember())
|
||||
@ -3213,9 +3126,6 @@ CGDebugInfo::getOrCreateStaticDataMemberDeclarationOrNull(const VarDecl *D) {
|
||||
return CreateRecordStaticField(D, Ctxt, cast<RecordDecl>(DC));
|
||||
}
|
||||
|
||||
/// Recursively collect all of the member fields of a global anonymous decl and
|
||||
/// create static variables for them. The first time this is called it needs
|
||||
/// to be on a union and then from there we can have additional unnamed fields.
|
||||
llvm::DIGlobalVariable *CGDebugInfo::CollectAnonRecordDecls(
|
||||
const RecordDecl *RD, llvm::DIFile *Unit, unsigned LineNo,
|
||||
StringRef LinkageName, llvm::GlobalVariable *Var, llvm::DIScope *DContext) {
|
||||
@ -3241,7 +3151,6 @@ llvm::DIGlobalVariable *CGDebugInfo::CollectAnonRecordDecls(
|
||||
return GV;
|
||||
}
|
||||
|
||||
/// EmitGlobalVariable - Emit information about a global variable.
|
||||
void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
|
||||
const VarDecl *D) {
|
||||
assert(DebugKind >= CodeGenOptions::LimitedDebugInfo);
|
||||
@ -3274,7 +3183,6 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
|
||||
DeclCache[D->getCanonicalDecl()].reset(static_cast<llvm::Metadata *>(GV));
|
||||
}
|
||||
|
||||
/// EmitGlobalVariable - Emit global variable's debug info.
|
||||
void CGDebugInfo::EmitGlobalVariable(const ValueDecl *VD,
|
||||
llvm::Constant *Init) {
|
||||
assert(DebugKind >= CodeGenOptions::LimitedDebugInfo);
|
||||
@ -3380,8 +3288,6 @@ CGDebugInfo::EmitNamespaceAlias(const NamespaceAliasDecl &NA) {
|
||||
return R;
|
||||
}
|
||||
|
||||
/// getOrCreateNamesSpace - Return namespace descriptor for the given
|
||||
/// namespace decl.
|
||||
llvm::DINamespace *
|
||||
CGDebugInfo::getOrCreateNameSpace(const NamespaceDecl *NSDecl) {
|
||||
NSDecl = NSDecl->getCanonicalDecl();
|
||||
|
@ -26,26 +26,26 @@
|
||||
#include "llvm/Support/Allocator.h"
|
||||
|
||||
namespace llvm {
|
||||
class MDNode;
|
||||
class MDNode;
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
class CXXMethodDecl;
|
||||
class VarDecl;
|
||||
class ObjCInterfaceDecl;
|
||||
class ObjCIvarDecl;
|
||||
class ClassTemplateSpecializationDecl;
|
||||
class GlobalDecl;
|
||||
class UsingDecl;
|
||||
class CXXMethodDecl;
|
||||
class VarDecl;
|
||||
class ObjCInterfaceDecl;
|
||||
class ObjCIvarDecl;
|
||||
class ClassTemplateSpecializationDecl;
|
||||
class GlobalDecl;
|
||||
class UsingDecl;
|
||||
|
||||
namespace CodeGen {
|
||||
class CodeGenModule;
|
||||
class CodeGenFunction;
|
||||
class CGBlockInfo;
|
||||
class CodeGenModule;
|
||||
class CodeGenFunction;
|
||||
class CGBlockInfo;
|
||||
|
||||
/// \brief This class gathers all debug information during compilation
|
||||
/// and is responsible for emitting to llvm globals or pass directly to
|
||||
/// the backend.
|
||||
/// This class gathers all debug information during compilation and is
|
||||
/// responsible for emitting to llvm globals or pass directly to the
|
||||
/// backend.
|
||||
class CGDebugInfo {
|
||||
friend class ApplyDebugLocation;
|
||||
friend class SaveAndRestoreLocation;
|
||||
@ -65,9 +65,8 @@ class CGDebugInfo {
|
||||
llvm::DIType *OCLImage2dArrayDITy = nullptr;
|
||||
llvm::DIType *OCLImage3dDITy = nullptr;
|
||||
llvm::DIType *OCLEventDITy = nullptr;
|
||||
llvm::DIType *BlockLiteralGeneric = nullptr;
|
||||
|
||||
/// \brief Cache of previously constructed Types.
|
||||
/// Cache of previously constructed Types.
|
||||
llvm::DenseMap<const void *, llvm::TrackingMDRef> TypeCache;
|
||||
|
||||
struct ObjCInterfaceCacheEntry {
|
||||
@ -79,41 +78,40 @@ class CGDebugInfo {
|
||||
: Type(Type), Decl(Decl), Unit(Unit) {}
|
||||
};
|
||||
|
||||
/// \brief Cache of previously constructed interfaces
|
||||
/// which may change.
|
||||
/// Cache of previously constructed interfaces which may change.
|
||||
llvm::SmallVector<ObjCInterfaceCacheEntry, 32> ObjCInterfaceCache;
|
||||
|
||||
/// \brief Cache of references to AST files such as PCHs or modules.
|
||||
/// Cache of references to AST files such as PCHs or modules.
|
||||
llvm::DenseMap<uint64_t, llvm::DIModule *> ModuleRefCache;
|
||||
|
||||
/// \brief list of interfaces we want to keep even if orphaned.
|
||||
/// List of interfaces we want to keep even if orphaned.
|
||||
std::vector<void *> RetainedTypes;
|
||||
|
||||
/// \brief Cache of forward declared types to RAUW at the end of
|
||||
/// Cache of forward declared types to RAUW at the end of
|
||||
/// compilation.
|
||||
std::vector<std::pair<const TagType *, llvm::TrackingMDRef>> ReplaceMap;
|
||||
|
||||
/// \brief Cache of replaceable forward declarartions (functions and
|
||||
/// Cache of replaceable forward declarartions (functions and
|
||||
/// variables) to RAUW at the end of compilation.
|
||||
std::vector<std::pair<const DeclaratorDecl *, llvm::TrackingMDRef>>
|
||||
FwdDeclReplaceMap;
|
||||
|
||||
// LexicalBlockStack - Keep track of our current nested lexical block.
|
||||
/// Keep track of our current nested lexical block.
|
||||
std::vector<llvm::TypedTrackingMDRef<llvm::DIScope>> LexicalBlockStack;
|
||||
llvm::DenseMap<const Decl *, llvm::TrackingMDRef> RegionMap;
|
||||
// FnBeginRegionCount - Keep track of LexicalBlockStack counter at the
|
||||
// beginning of a function. This is used to pop unbalanced regions at
|
||||
// the end of a function.
|
||||
/// Keep track of LexicalBlockStack counter at the beginning of a
|
||||
/// function. This is used to pop unbalanced regions at the end of a
|
||||
/// function.
|
||||
std::vector<unsigned> FnBeginRegionCount;
|
||||
|
||||
/// \brief This is a storage for names that are
|
||||
/// constructed on demand. For example, C++ destructors, C++ operators etc..
|
||||
/// This is a storage for names that are constructed on demand. For
|
||||
/// example, C++ destructors, C++ operators etc..
|
||||
llvm::BumpPtrAllocator DebugInfoNames;
|
||||
StringRef CWDName;
|
||||
|
||||
llvm::DenseMap<const char *, llvm::TrackingMDRef> DIFileCache;
|
||||
llvm::DenseMap<const FunctionDecl *, llvm::TrackingMDRef> SPCache;
|
||||
/// \brief Cache declarations relevant to DW_TAG_imported_declarations (C++
|
||||
/// Cache declarations relevant to DW_TAG_imported_declarations (C++
|
||||
/// using declarations) that aren't covered by other more specific caches.
|
||||
llvm::DenseMap<const Decl *, llvm::TrackingMDRef> DeclCache;
|
||||
llvm::DenseMap<const NamespaceDecl *, llvm::TrackingMDRef> NameSpaceCache;
|
||||
@ -122,6 +120,9 @@ class CGDebugInfo {
|
||||
llvm::DenseMap<const Decl *, llvm::TrackingMDRef> StaticDataMemberCache;
|
||||
|
||||
/// Helper functions for getOrCreateType.
|
||||
/// @{
|
||||
/// Currently the checksum of an interface includes the number of
|
||||
/// ivars and property accessors.
|
||||
unsigned Checksum(const ObjCInterfaceDecl *InterfaceDecl);
|
||||
llvm::DIType *CreateType(const BuiltinType *Ty);
|
||||
llvm::DIType *CreateType(const ComplexType *Ty);
|
||||
@ -133,14 +134,17 @@ class CGDebugInfo {
|
||||
llvm::DIType *CreateType(const PointerType *Ty, llvm::DIFile *F);
|
||||
llvm::DIType *CreateType(const BlockPointerType *Ty, llvm::DIFile *F);
|
||||
llvm::DIType *CreateType(const FunctionType *Ty, llvm::DIFile *F);
|
||||
/// Get structure or union type.
|
||||
llvm::DIType *CreateType(const RecordType *Tyg);
|
||||
llvm::DIType *CreateTypeDefinition(const RecordType *Ty);
|
||||
llvm::DICompositeType *CreateLimitedType(const RecordType *Ty);
|
||||
void CollectContainingType(const CXXRecordDecl *RD,
|
||||
llvm::DICompositeType *CT);
|
||||
/// Get Objective-C interface type.
|
||||
llvm::DIType *CreateType(const ObjCInterfaceType *Ty, llvm::DIFile *F);
|
||||
llvm::DIType *CreateTypeDefinition(const ObjCInterfaceType *Ty,
|
||||
llvm::DIFile *F);
|
||||
/// Get Objective-C object type.
|
||||
llvm::DIType *CreateType(const ObjCObjectType *Ty, llvm::DIFile *F);
|
||||
llvm::DIType *CreateType(const VectorType *Ty, llvm::DIFile *F);
|
||||
llvm::DIType *CreateType(const ArrayType *Ty, llvm::DIFile *F);
|
||||
@ -148,10 +152,25 @@ class CGDebugInfo {
|
||||
llvm::DIType *CreateType(const RValueReferenceType *Ty, llvm::DIFile *Unit);
|
||||
llvm::DIType *CreateType(const MemberPointerType *Ty, llvm::DIFile *F);
|
||||
llvm::DIType *CreateType(const AtomicType *Ty, llvm::DIFile *F);
|
||||
/// Get enumeration type.
|
||||
llvm::DIType *CreateEnumType(const EnumType *Ty);
|
||||
llvm::DIType *CreateTypeDefinition(const EnumType *Ty);
|
||||
/// Look up the completed type for a self pointer in the TypeCache and
|
||||
/// create a copy of it with the ObjectPointer and Artificial flags
|
||||
/// set. If the type is not cached, a new one is created. This should
|
||||
/// never happen though, since creating a type for the implicit self
|
||||
/// argument implies that we already parsed the interface definition
|
||||
/// and the ivar declarations in the implementation.
|
||||
llvm::DIType *CreateSelfType(const QualType &QualTy, llvm::DIType *Ty);
|
||||
/// @}
|
||||
|
||||
/// Get the type from the cache or return null type if it doesn't
|
||||
/// exist.
|
||||
llvm::DIType *getTypeOrNull(const QualType);
|
||||
/// Return the debug type for a C++ method.
|
||||
/// \arg CXXMethodDecl is of FunctionType. This function type is
|
||||
/// not updated to include implicit \c this pointer. Use this routine
|
||||
/// to get a method type which includes \c this pointer.
|
||||
llvm::DISubroutineType *getOrCreateMethodType(const CXXMethodDecl *Method,
|
||||
llvm::DIFile *F);
|
||||
llvm::DISubroutineType *
|
||||
@ -159,7 +178,9 @@ class CGDebugInfo {
|
||||
llvm::DIFile *Unit);
|
||||
llvm::DISubroutineType *
|
||||
getOrCreateFunctionType(const Decl *D, QualType FnType, llvm::DIFile *F);
|
||||
/// \return debug info descriptor for vtable.
|
||||
llvm::DIType *getOrCreateVTablePtrType(llvm::DIFile *F);
|
||||
/// \return namespace descriptor for the given namespace decl.
|
||||
llvm::DINamespace *getOrCreateNameSpace(const NamespaceDecl *N);
|
||||
llvm::DIType *getOrCreateTypeDeclaration(QualType PointeeTy, llvm::DIFile *F);
|
||||
llvm::DIType *CreatePointerLikeType(llvm::dwarf::Tag Tag, const Type *Ty,
|
||||
@ -168,23 +189,37 @@ class CGDebugInfo {
|
||||
llvm::Value *getCachedInterfaceTypeOrNull(const QualType Ty);
|
||||
llvm::DIType *getOrCreateStructPtrType(StringRef Name, llvm::DIType *&Cache);
|
||||
|
||||
/// A helper function to create a subprogram for a single member
|
||||
/// function GlobalDecl.
|
||||
llvm::DISubprogram *CreateCXXMemberFunction(const CXXMethodDecl *Method,
|
||||
llvm::DIFile *F,
|
||||
llvm::DIType *RecordTy);
|
||||
|
||||
/// A helper function to collect debug info for C++ member
|
||||
/// functions. This is used while creating debug info entry for a
|
||||
/// Record.
|
||||
void CollectCXXMemberFunctions(const CXXRecordDecl *Decl, llvm::DIFile *F,
|
||||
SmallVectorImpl<llvm::Metadata *> &E,
|
||||
llvm::DIType *T);
|
||||
|
||||
/// A helper function to collect debug info for C++ base
|
||||
/// classes. This is used while creating debug info entry for a
|
||||
/// Record.
|
||||
void CollectCXXBases(const CXXRecordDecl *Decl, llvm::DIFile *F,
|
||||
SmallVectorImpl<llvm::Metadata *> &EltTys,
|
||||
llvm::DIType *RecordTy);
|
||||
|
||||
/// A helper function to collect template parameters.
|
||||
llvm::DINodeArray CollectTemplateParams(const TemplateParameterList *TPList,
|
||||
ArrayRef<TemplateArgument> TAList,
|
||||
llvm::DIFile *Unit);
|
||||
/// A helper function to collect debug info for function template
|
||||
/// parameters.
|
||||
llvm::DINodeArray CollectFunctionTemplateParams(const FunctionDecl *FD,
|
||||
llvm::DIFile *Unit);
|
||||
|
||||
/// A helper function to collect debug info for template
|
||||
/// parameters.
|
||||
llvm::DINodeArray
|
||||
CollectCXXTemplateParams(const ClassTemplateSpecializationDecl *TS,
|
||||
llvm::DIFile *F);
|
||||
@ -195,7 +230,8 @@ class CGDebugInfo {
|
||||
llvm::DIFile *tunit, llvm::DIScope *scope,
|
||||
const RecordDecl *RD = nullptr);
|
||||
|
||||
// Helpers for collecting fields of a record.
|
||||
/// Helpers for collecting fields of a record.
|
||||
/// @{
|
||||
void CollectRecordLambdaFields(const CXXRecordDecl *CXXDecl,
|
||||
SmallVectorImpl<llvm::Metadata *> &E,
|
||||
llvm::DIType *RecordTy);
|
||||
@ -210,11 +246,13 @@ class CGDebugInfo {
|
||||
SmallVectorImpl<llvm::Metadata *> &E,
|
||||
llvm::DICompositeType *RecordTy);
|
||||
|
||||
/// If the C++ class has vtable info then insert appropriate debug
|
||||
/// info entry in EltTys vector.
|
||||
void CollectVTableInfo(const CXXRecordDecl *Decl, llvm::DIFile *F,
|
||||
SmallVectorImpl<llvm::Metadata *> &EltTys);
|
||||
/// @}
|
||||
|
||||
// CreateLexicalBlock - Create a new lexical block node and push it on
|
||||
// the stack.
|
||||
/// Create a new lexical block node and push it on the stack.
|
||||
void CreateLexicalBlock(SourceLocation Loc);
|
||||
|
||||
public:
|
||||
@ -223,86 +261,84 @@ class CGDebugInfo {
|
||||
|
||||
void finalize();
|
||||
|
||||
/// \brief Update the current source location. If \arg loc is
|
||||
/// invalid it is ignored.
|
||||
/// Update the current source location. If \arg loc is invalid it is
|
||||
/// ignored.
|
||||
void setLocation(SourceLocation Loc);
|
||||
|
||||
/// \brief Emit metadata to indicate a change in line/column
|
||||
/// information in the source file.
|
||||
/// Emit metadata to indicate a change in line/column information in
|
||||
/// the source file. If the location is invalid, the previous
|
||||
/// location will be reused.
|
||||
void EmitLocation(CGBuilderTy &Builder, SourceLocation Loc);
|
||||
|
||||
/// \brief Emit a call to llvm.dbg.function.start to indicate
|
||||
/// Emit a call to llvm.dbg.function.start to indicate
|
||||
/// start of a new function.
|
||||
/// \param Loc The location of the function header.
|
||||
/// \param ScopeLoc The location of the function body.
|
||||
void EmitFunctionStart(GlobalDecl GD,
|
||||
SourceLocation Loc, SourceLocation ScopeLoc,
|
||||
QualType FnType, llvm::Function *Fn,
|
||||
CGBuilderTy &Builder);
|
||||
void EmitFunctionStart(GlobalDecl GD, SourceLocation Loc,
|
||||
SourceLocation ScopeLoc, QualType FnType,
|
||||
llvm::Function *Fn, CGBuilderTy &Builder);
|
||||
|
||||
/// \brief Constructs the debug code for exiting a function.
|
||||
/// Constructs the debug code for exiting a function.
|
||||
void EmitFunctionEnd(CGBuilderTy &Builder);
|
||||
|
||||
/// \brief Emit metadata to indicate the beginning of a
|
||||
/// new lexical block and push the block onto the stack.
|
||||
/// Emit metadata to indicate the beginning of a new lexical block
|
||||
/// and push the block onto the stack.
|
||||
void EmitLexicalBlockStart(CGBuilderTy &Builder, SourceLocation Loc);
|
||||
|
||||
/// \brief Emit metadata to indicate the end of a new lexical
|
||||
/// block and pop the current block.
|
||||
/// Emit metadata to indicate the end of a new lexical block and pop
|
||||
/// the current block.
|
||||
void EmitLexicalBlockEnd(CGBuilderTy &Builder, SourceLocation Loc);
|
||||
|
||||
/// \brief Emit call to llvm.dbg.declare for an automatic
|
||||
/// variable declaration.
|
||||
/// Emit call to \c llvm.dbg.declare for an automatic variable
|
||||
/// declaration.
|
||||
void EmitDeclareOfAutoVariable(const VarDecl *Decl, llvm::Value *AI,
|
||||
CGBuilderTy &Builder);
|
||||
|
||||
/// \brief Emit call to llvm.dbg.declare for an
|
||||
/// imported variable declaration in a block.
|
||||
/// Emit call to \c llvm.dbg.declare for an imported variable
|
||||
/// declaration in a block.
|
||||
void EmitDeclareOfBlockDeclRefVariable(const VarDecl *variable,
|
||||
llvm::Value *storage,
|
||||
CGBuilderTy &Builder,
|
||||
const CGBlockInfo &blockInfo,
|
||||
llvm::Instruction *InsertPoint = 0);
|
||||
|
||||
/// \brief Emit call to llvm.dbg.declare for an argument
|
||||
/// variable declaration.
|
||||
/// Emit call to \c llvm.dbg.declare for an argument variable
|
||||
/// declaration.
|
||||
void EmitDeclareOfArgVariable(const VarDecl *Decl, llvm::Value *AI,
|
||||
unsigned ArgNo, CGBuilderTy &Builder);
|
||||
|
||||
/// \brief Emit call to
|
||||
/// llvm.dbg.declare for the block-literal argument to a block
|
||||
/// invocation function.
|
||||
/// Emit call to \c llvm.dbg.declare for the block-literal argument
|
||||
/// to a block invocation function.
|
||||
void EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
|
||||
llvm::Value *Arg, unsigned ArgNo,
|
||||
llvm::Value *LocalAddr,
|
||||
CGBuilderTy &Builder);
|
||||
|
||||
/// \brief Emit information about a global variable.
|
||||
/// Emit information about a global variable.
|
||||
void EmitGlobalVariable(llvm::GlobalVariable *GV, const VarDecl *Decl);
|
||||
|
||||
/// \brief Emit global variable's debug info.
|
||||
/// Emit global variable's debug info.
|
||||
void EmitGlobalVariable(const ValueDecl *VD, llvm::Constant *Init);
|
||||
|
||||
/// \brief Emit C++ using directive.
|
||||
/// Emit C++ using directive.
|
||||
void EmitUsingDirective(const UsingDirectiveDecl &UD);
|
||||
|
||||
/// \brief Emit the type explicitly casted to.
|
||||
/// Emit the type explicitly casted to.
|
||||
void EmitExplicitCastType(QualType Ty);
|
||||
|
||||
/// \brief Emit C++ using declaration.
|
||||
/// Emit C++ using declaration.
|
||||
void EmitUsingDecl(const UsingDecl &UD);
|
||||
|
||||
/// \brief Emit an @import declaration.
|
||||
/// Emit an @import declaration.
|
||||
void EmitImportDecl(const ImportDecl &ID);
|
||||
|
||||
/// \brief Emit C++ namespace alias.
|
||||
/// Emit C++ namespace alias.
|
||||
llvm::DIImportedEntity *EmitNamespaceAlias(const NamespaceAliasDecl &NA);
|
||||
|
||||
/// \brief Emit record type's standalone debug info.
|
||||
/// Emit record type's standalone debug info.
|
||||
llvm::DIType *getOrCreateRecordType(QualType Ty, SourceLocation L);
|
||||
|
||||
/// \brief Emit an objective c interface type standalone
|
||||
/// debug info.
|
||||
/// Emit an Objective-C interface type standalone debug info.
|
||||
llvm::DIType *getOrCreateInterfaceType(QualType Ty, SourceLocation Loc);
|
||||
|
||||
void completeType(const EnumDecl *ED);
|
||||
@ -313,120 +349,124 @@ class CGDebugInfo {
|
||||
void completeTemplateDefinition(const ClassTemplateSpecializationDecl &SD);
|
||||
|
||||
private:
|
||||
/// \brief Emit call to llvm.dbg.declare for a variable declaration.
|
||||
/// Emit call to llvm.dbg.declare for a variable declaration.
|
||||
/// Tag accepts custom types DW_TAG_arg_variable and DW_TAG_auto_variable,
|
||||
/// otherwise would be of type llvm::dwarf::Tag.
|
||||
void EmitDeclare(const VarDecl *decl, llvm::dwarf::Tag Tag, llvm::Value *AI,
|
||||
unsigned ArgNo, CGBuilderTy &Builder);
|
||||
|
||||
// EmitTypeForVarWithBlocksAttr - Build up structure info for the byref.
|
||||
// See BuildByRefType.
|
||||
/// Build up structure info for the byref. See \a BuildByRefType.
|
||||
llvm::DIType *EmitTypeForVarWithBlocksAttr(const VarDecl *VD,
|
||||
uint64_t *OffSet);
|
||||
|
||||
/// \brief Get context info for the decl.
|
||||
/// Get context info for the decl.
|
||||
llvm::DIScope *getContextDescriptor(const Decl *Decl);
|
||||
|
||||
llvm::DIScope *getCurrentContextDescriptor(const Decl *Decl);
|
||||
|
||||
/// \brief Create a forward decl for a RecordType in a given context.
|
||||
/// Create a forward decl for a RecordType in a given context.
|
||||
llvm::DICompositeType *getOrCreateRecordFwdDecl(const RecordType *,
|
||||
llvm::DIScope *);
|
||||
|
||||
/// \brief Return current directory name.
|
||||
/// Return current directory name.
|
||||
StringRef getCurrentDirname();
|
||||
|
||||
/// \brief Create new compile unit.
|
||||
/// Create new compile unit.
|
||||
void CreateCompileUnit();
|
||||
|
||||
/// \brief Get the file debug info descriptor for the input
|
||||
/// location.
|
||||
/// Get the file debug info descriptor for the input location.
|
||||
llvm::DIFile *getOrCreateFile(SourceLocation Loc);
|
||||
|
||||
/// \brief Get the file info for main compile unit.
|
||||
/// Get the file info for main compile unit.
|
||||
llvm::DIFile *getOrCreateMainFile();
|
||||
|
||||
/// \brief Get the type from the cache or create a new type if
|
||||
/// necessary.
|
||||
/// Get the type from the cache or create a new type if necessary.
|
||||
llvm::DIType *getOrCreateType(QualType Ty, llvm::DIFile *Fg);
|
||||
|
||||
/// \brief Get a reference to a clang module.
|
||||
/// Get a reference to a clang module.
|
||||
llvm::DIModule *
|
||||
getOrCreateModuleRef(ExternalASTSource::ASTSourceDescriptor Mod);
|
||||
|
||||
/// \brief Get the type from the cache or create a new
|
||||
/// partial type if necessary.
|
||||
/// Get the type from the cache or create a new partial type if
|
||||
/// necessary.
|
||||
llvm::DIType *getOrCreateLimitedType(const RecordType *Ty, llvm::DIFile *F);
|
||||
|
||||
/// \brief Create type metadata for a source language type.
|
||||
/// Create type metadata for a source language type.
|
||||
llvm::DIType *CreateTypeNode(QualType Ty, llvm::DIFile *Fg);
|
||||
|
||||
/// \brief return the underlying ObjCInterfaceDecl
|
||||
/// if Ty is an ObjCInterface or a pointer to one.
|
||||
ObjCInterfaceDecl* getObjCInterfaceDecl(QualType Ty);
|
||||
/// Return the underlying ObjCInterfaceDecl if \arg Ty is an
|
||||
/// ObjCInterface or a pointer to one.
|
||||
ObjCInterfaceDecl *getObjCInterfaceDecl(QualType Ty);
|
||||
|
||||
/// \brief Create new member and increase Offset by FType's size.
|
||||
/// Create new member and increase Offset by FType's size.
|
||||
llvm::DIType *CreateMemberType(llvm::DIFile *Unit, QualType FType,
|
||||
StringRef Name, uint64_t *Offset);
|
||||
|
||||
/// \brief Retrieve the DIDescriptor, if any, for the canonical form of this
|
||||
/// Retrieve the DIDescriptor, if any, for the canonical form of this
|
||||
/// declaration.
|
||||
llvm::DINode *getDeclarationOrDefinition(const Decl *D);
|
||||
|
||||
/// \brief Return debug info descriptor to describe method
|
||||
/// \return debug info descriptor to describe method
|
||||
/// declaration for the given method definition.
|
||||
llvm::DISubprogram *getFunctionDeclaration(const Decl *D);
|
||||
|
||||
/// Return debug info descriptor to describe in-class static data member
|
||||
/// declaration for the given out-of-class definition.
|
||||
/// \return debug info descriptor to describe in-class static data
|
||||
/// member declaration for the given out-of-class definition. If D
|
||||
/// is an out-of-class definition of a static data member of a
|
||||
/// class, find its corresponding in-class declaration.
|
||||
llvm::DIDerivedType *
|
||||
getOrCreateStaticDataMemberDeclarationOrNull(const VarDecl *D);
|
||||
|
||||
/// \brief Create a subprogram describing the forward
|
||||
/// decalration represented in the given FunctionDecl.
|
||||
/// Create a subprogram describing the forward declaration
|
||||
/// represented in the given FunctionDecl.
|
||||
llvm::DISubprogram *getFunctionForwardDeclaration(const FunctionDecl *FD);
|
||||
|
||||
/// \brief Create a global variable describing the forward decalration
|
||||
/// Create a global variable describing the forward decalration
|
||||
/// represented in the given VarDecl.
|
||||
llvm::DIGlobalVariable *
|
||||
getGlobalVariableForwardDeclaration(const VarDecl *VD);
|
||||
|
||||
/// Return a global variable that represents one of the collection of
|
||||
/// global variables created for an anonmyous union.
|
||||
/// \brief Return a global variable that represents one of the
|
||||
/// collection of global variables created for an anonmyous union.
|
||||
///
|
||||
/// Recursively collect all of the member fields of a global
|
||||
/// anonymous decl and create static variables for them. The first
|
||||
/// time this is called it needs to be on a union and then from
|
||||
/// there we can have additional unnamed fields.
|
||||
llvm::DIGlobalVariable *
|
||||
CollectAnonRecordDecls(const RecordDecl *RD, llvm::DIFile *Unit,
|
||||
unsigned LineNo, StringRef LinkageName,
|
||||
llvm::GlobalVariable *Var, llvm::DIScope *DContext);
|
||||
|
||||
/// \brief Get function name for the given FunctionDecl. If the
|
||||
/// name is constructed on demand (e.g. C++ destructor) then the name
|
||||
/// is stored on the side.
|
||||
/// Get function name for the given FunctionDecl. If the name is
|
||||
/// constructed on demand (e.g., C++ destructor) then the name is
|
||||
/// stored on the side.
|
||||
StringRef getFunctionName(const FunctionDecl *FD);
|
||||
|
||||
/// \brief Returns the unmangled name of an Objective-C method.
|
||||
/// Returns the unmangled name of an Objective-C method.
|
||||
/// This is the display name for the debugging info.
|
||||
StringRef getObjCMethodName(const ObjCMethodDecl *FD);
|
||||
|
||||
/// \brief Return selector name. This is used for debugging
|
||||
/// Return selector name. This is used for debugging
|
||||
/// info.
|
||||
StringRef getSelectorName(Selector S);
|
||||
|
||||
/// \brief Get class name including template argument list.
|
||||
/// Get class name including template argument list.
|
||||
StringRef getClassName(const RecordDecl *RD);
|
||||
|
||||
/// \brief Get vtable name for the given Class.
|
||||
/// Get the vtable name for the given class.
|
||||
StringRef getVTableName(const CXXRecordDecl *Decl);
|
||||
|
||||
/// \brief Get line number for the location. If location is invalid
|
||||
/// Get line number for the location. If location is invalid
|
||||
/// then use current location.
|
||||
unsigned getLineNumber(SourceLocation Loc);
|
||||
|
||||
/// \brief Get column number for the location. If location is
|
||||
/// Get column number for the location. If location is
|
||||
/// invalid then use current location.
|
||||
/// \param Force Assume DebugColumnInfo option is true.
|
||||
unsigned getColumnNumber(SourceLocation Loc, bool Force=false);
|
||||
unsigned getColumnNumber(SourceLocation Loc, bool Force = false);
|
||||
|
||||
/// \brief Collect various properties of a FunctionDecl.
|
||||
/// Collect various properties of a FunctionDecl.
|
||||
/// \param GD A GlobalDecl whose getDecl() must return a FunctionDecl.
|
||||
void collectFunctionDeclProps(GlobalDecl GD, llvm::DIFile *Unit,
|
||||
StringRef &Name, StringRef &LinkageName,
|
||||
@ -434,12 +474,12 @@ class CGDebugInfo {
|
||||
llvm::DINodeArray &TParamsArray,
|
||||
unsigned &Flags);
|
||||
|
||||
/// \brief Collect various properties of a VarDecl.
|
||||
/// Collect various properties of a VarDecl.
|
||||
void collectVarDeclProps(const VarDecl *VD, llvm::DIFile *&Unit,
|
||||
unsigned &LineNo, QualType &T, StringRef &Name,
|
||||
StringRef &LinkageName, llvm::DIScope *&VDContext);
|
||||
|
||||
/// \brief Allocate a copy of \p A using the DebugInfoNames allocator
|
||||
/// Allocate a copy of \p A using the DebugInfoNames allocator
|
||||
/// and return a reference to it. If multiple arguments are given the strings
|
||||
/// are concatenated.
|
||||
StringRef internString(StringRef A, StringRef B = StringRef()) {
|
||||
@ -450,7 +490,7 @@ class CGDebugInfo {
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief A scoped helper to set the current debug location to the specified
|
||||
/// A scoped helper to set the current debug location to the specified
|
||||
/// location or preferred location of the specified Expr.
|
||||
class ApplyDebugLocation {
|
||||
private:
|
||||
@ -460,55 +500,56 @@ class ApplyDebugLocation {
|
||||
|
||||
llvm::DebugLoc OriginalLocation;
|
||||
CodeGenFunction &CGF;
|
||||
public:
|
||||
|
||||
/// \brief Set the location to the (valid) TemporaryLocation.
|
||||
public:
|
||||
/// Set the location to the (valid) TemporaryLocation.
|
||||
ApplyDebugLocation(CodeGenFunction &CGF, SourceLocation TemporaryLocation);
|
||||
ApplyDebugLocation(CodeGenFunction &CGF, const Expr *E);
|
||||
ApplyDebugLocation(CodeGenFunction &CGF, llvm::DebugLoc Loc);
|
||||
|
||||
~ApplyDebugLocation();
|
||||
|
||||
/// \brief Apply TemporaryLocation if it is valid. Otherwise switch to an
|
||||
/// artificial debug location that has a valid scope, but no line information.
|
||||
/// \brief Apply TemporaryLocation if it is valid. Otherwise switch
|
||||
/// to an artificial debug location that has a valid scope, but no
|
||||
/// line information.
|
||||
///
|
||||
/// Artificial locations are useful when emitting compiler-generated helper
|
||||
/// functions that have no source location associated with them. The DWARF
|
||||
/// specification allows the compiler to use the special line number 0 to
|
||||
/// indicate code that can not be attributed to any source location. Note that
|
||||
/// passing an empty SourceLocation to CGDebugInfo::setLocation() will result
|
||||
/// in the last valid location being reused.
|
||||
/// Artificial locations are useful when emitting compiler-generated
|
||||
/// helper functions that have no source location associated with
|
||||
/// them. The DWARF specification allows the compiler to use the
|
||||
/// special line number 0 to indicate code that can not be
|
||||
/// attributed to any source location. Note that passing an empty
|
||||
/// SourceLocation to CGDebugInfo::setLocation() will result in the
|
||||
/// last valid location being reused.
|
||||
static ApplyDebugLocation CreateArtificial(CodeGenFunction &CGF) {
|
||||
return ApplyDebugLocation(CGF, false, SourceLocation());
|
||||
}
|
||||
/// \brief Apply TemporaryLocation if it is valid. Otherwise switch to an
|
||||
/// artificial debug location that has a valid scope, but no line information.
|
||||
static ApplyDebugLocation CreateDefaultArtificial(CodeGenFunction &CGF,
|
||||
SourceLocation TemporaryLocation) {
|
||||
/// \brief Apply TemporaryLocation if it is valid. Otherwise switch
|
||||
/// to an artificial debug location that has a valid scope, but no
|
||||
/// line information.
|
||||
static ApplyDebugLocation
|
||||
CreateDefaultArtificial(CodeGenFunction &CGF,
|
||||
SourceLocation TemporaryLocation) {
|
||||
return ApplyDebugLocation(CGF, false, TemporaryLocation);
|
||||
}
|
||||
|
||||
/// \brief Set the IRBuilder to not attach debug locations. Note that passing
|
||||
/// an empty SourceLocation to CGDebugInfo::setLocation() will result in the
|
||||
/// last valid location being reused. Note that all instructions that do not
|
||||
/// have a location at the beginning of a function are counted towards to
|
||||
/// funciton prologue.
|
||||
/// Set the IRBuilder to not attach debug locations. Note that
|
||||
/// passing an empty SourceLocation to \a CGDebugInfo::setLocation()
|
||||
/// will result in the last valid location being reused. Note that
|
||||
/// all instructions that do not have a location at the beginning of
|
||||
/// a function are counted towards to funciton prologue.
|
||||
static ApplyDebugLocation CreateEmpty(CodeGenFunction &CGF) {
|
||||
return ApplyDebugLocation(CGF, true, SourceLocation());
|
||||
}
|
||||
|
||||
/// \brief Apply TemporaryLocation if it is valid. Otherwise set the IRBuilder
|
||||
/// to not attach debug locations.
|
||||
static ApplyDebugLocation CreateDefaultEmpty(CodeGenFunction &CGF,
|
||||
SourceLocation TemporaryLocation) {
|
||||
static ApplyDebugLocation
|
||||
CreateDefaultEmpty(CodeGenFunction &CGF, SourceLocation TemporaryLocation) {
|
||||
return ApplyDebugLocation(CGF, true, TemporaryLocation);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
} // namespace CodeGen
|
||||
} // namespace clang
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -79,6 +79,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
|
||||
case Decl::Captured:
|
||||
case Decl::ClassScopeFunctionSpecialization:
|
||||
case Decl::UsingShadow:
|
||||
case Decl::ObjCTypeParam:
|
||||
llvm_unreachable("Declaration should not be in declstmts!");
|
||||
case Decl::Function: // void X();
|
||||
case Decl::Record: // struct/union/class X;
|
||||
@ -987,7 +988,7 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
|
||||
llvm::Value *Stack = CreateTempAlloca(Int8PtrTy, "saved_stack");
|
||||
|
||||
llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::stacksave);
|
||||
llvm::Value *V = Builder.CreateCall(F, {});
|
||||
llvm::Value *V = Builder.CreateCall(F);
|
||||
|
||||
Builder.CreateStore(V, Stack);
|
||||
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "clang/AST/StmtCXX.h"
|
||||
#include "clang/AST/StmtObjC.h"
|
||||
#include "clang/AST/StmtVisitor.h"
|
||||
#include "clang/Basic/TargetBuiltins.h"
|
||||
#include "llvm/IR/CallSite.h"
|
||||
#include "llvm/IR/Intrinsics.h"
|
||||
#include "llvm/IR/IntrinsicInst.h"
|
||||
@ -1279,14 +1280,6 @@ llvm::BasicBlock *CodeGenFunction::getEHResumeBlock(bool isCleanup) {
|
||||
}
|
||||
|
||||
void CodeGenFunction::EmitSEHTryStmt(const SEHTryStmt &S) {
|
||||
// FIXME: Implement SEH on other architectures.
|
||||
const llvm::Triple &T = CGM.getTarget().getTriple();
|
||||
if (T.getArch() != llvm::Triple::x86_64 ||
|
||||
!T.isKnownWindowsMSVCEnvironment()) {
|
||||
ErrorUnsupported(&S, "__try statement");
|
||||
return;
|
||||
}
|
||||
|
||||
EnterSEHTryStmt(S);
|
||||
{
|
||||
JumpDest TryExit = getJumpDestInCurrentScope("__try.__leave");
|
||||
@ -1311,24 +1304,27 @@ struct PerformSEHFinally : EHScopeStack::Cleanup {
|
||||
|
||||
void Emit(CodeGenFunction &CGF, Flags F) override {
|
||||
ASTContext &Context = CGF.getContext();
|
||||
QualType ArgTys[2] = {Context.UnsignedCharTy, Context.VoidPtrTy};
|
||||
FunctionProtoType::ExtProtoInfo EPI;
|
||||
const auto *FTP = cast<FunctionType>(
|
||||
Context.getFunctionType(Context.VoidTy, ArgTys, EPI));
|
||||
CodeGenModule &CGM = CGF.CGM;
|
||||
|
||||
CallArgList Args;
|
||||
|
||||
// Compute the two argument values.
|
||||
QualType ArgTys[2] = {Context.UnsignedCharTy, Context.VoidPtrTy};
|
||||
llvm::Value *LocalAddrFn = CGM.getIntrinsic(llvm::Intrinsic::localaddress);
|
||||
llvm::Value *FP = CGF.Builder.CreateCall(LocalAddrFn);
|
||||
llvm::Value *IsForEH =
|
||||
llvm::ConstantInt::get(CGF.ConvertType(ArgTys[0]), F.isForEHCleanup());
|
||||
Args.add(RValue::get(IsForEH), ArgTys[0]);
|
||||
|
||||
CodeGenModule &CGM = CGF.CGM;
|
||||
llvm::Value *Zero = llvm::ConstantInt::get(CGM.Int32Ty, 0);
|
||||
llvm::Value *FrameAddr = CGM.getIntrinsic(llvm::Intrinsic::frameaddress);
|
||||
llvm::Value *FP = CGF.Builder.CreateCall(FrameAddr, Zero);
|
||||
Args.add(RValue::get(FP), ArgTys[1]);
|
||||
|
||||
// Arrange a two-arg function info and type.
|
||||
FunctionProtoType::ExtProtoInfo EPI;
|
||||
const auto *FPT = cast<FunctionProtoType>(
|
||||
Context.getFunctionType(Context.VoidTy, ArgTys, EPI));
|
||||
const CGFunctionInfo &FnInfo =
|
||||
CGM.getTypes().arrangeFreeFunctionCall(Args, FTP, /*chainCall=*/false);
|
||||
CGM.getTypes().arrangeFreeFunctionCall(Args, FPT,
|
||||
/*chainCall=*/false);
|
||||
|
||||
CGF.EmitCall(FnInfo, OutlinedFinally, ReturnValueSlot(), Args);
|
||||
}
|
||||
};
|
||||
@ -1340,9 +1336,15 @@ struct CaptureFinder : ConstStmtVisitor<CaptureFinder> {
|
||||
CodeGenFunction &ParentCGF;
|
||||
const VarDecl *ParentThis;
|
||||
SmallVector<const VarDecl *, 4> Captures;
|
||||
llvm::Value *SEHCodeSlot = nullptr;
|
||||
CaptureFinder(CodeGenFunction &ParentCGF, const VarDecl *ParentThis)
|
||||
: ParentCGF(ParentCGF), ParentThis(ParentThis) {}
|
||||
|
||||
// Return true if we need to do any capturing work.
|
||||
bool foundCaptures() {
|
||||
return !Captures.empty() || SEHCodeSlot;
|
||||
}
|
||||
|
||||
void Visit(const Stmt *S) {
|
||||
// See if this is a capture, then recurse.
|
||||
ConstStmtVisitor<CaptureFinder>::Visit(S);
|
||||
@ -1366,27 +1368,106 @@ struct CaptureFinder : ConstStmtVisitor<CaptureFinder> {
|
||||
void VisitCXXThisExpr(const CXXThisExpr *E) {
|
||||
Captures.push_back(ParentThis);
|
||||
}
|
||||
|
||||
void VisitCallExpr(const CallExpr *E) {
|
||||
// We only need to add parent frame allocations for these builtins in x86.
|
||||
if (ParentCGF.getTarget().getTriple().getArch() != llvm::Triple::x86)
|
||||
return;
|
||||
|
||||
unsigned ID = E->getBuiltinCallee();
|
||||
switch (ID) {
|
||||
case Builtin::BI__exception_code:
|
||||
case Builtin::BI_exception_code:
|
||||
// This is the simple case where we are the outermost finally. All we
|
||||
// have to do here is make sure we escape this and recover it in the
|
||||
// outlined handler.
|
||||
if (!SEHCodeSlot)
|
||||
SEHCodeSlot = ParentCGF.SEHCodeSlotStack.back();
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
llvm::Value *CodeGenFunction::recoverAddrOfEscapedLocal(
|
||||
CodeGenFunction &ParentCGF, llvm::Value *ParentVar, llvm::Value *ParentFP) {
|
||||
llvm::CallInst *RecoverCall = nullptr;
|
||||
CGBuilderTy Builder(AllocaInsertPt);
|
||||
if (auto *ParentAlloca = dyn_cast<llvm::AllocaInst>(ParentVar)) {
|
||||
// Mark the variable escaped if nobody else referenced it and compute the
|
||||
// localescape index.
|
||||
auto InsertPair = ParentCGF.EscapedLocals.insert(
|
||||
std::make_pair(ParentAlloca, ParentCGF.EscapedLocals.size()));
|
||||
int FrameEscapeIdx = InsertPair.first->second;
|
||||
// call i8* @llvm.localrecover(i8* bitcast(@parentFn), i8* %fp, i32 N)
|
||||
llvm::Function *FrameRecoverFn = llvm::Intrinsic::getDeclaration(
|
||||
&CGM.getModule(), llvm::Intrinsic::localrecover);
|
||||
llvm::Constant *ParentI8Fn =
|
||||
llvm::ConstantExpr::getBitCast(ParentCGF.CurFn, Int8PtrTy);
|
||||
RecoverCall = Builder.CreateCall(
|
||||
FrameRecoverFn, {ParentI8Fn, ParentFP,
|
||||
llvm::ConstantInt::get(Int32Ty, FrameEscapeIdx)});
|
||||
|
||||
} else {
|
||||
// If the parent didn't have an alloca, we're doing some nested outlining.
|
||||
// Just clone the existing localrecover call, but tweak the FP argument to
|
||||
// use our FP value. All other arguments are constants.
|
||||
auto *ParentRecover =
|
||||
cast<llvm::IntrinsicInst>(ParentVar->stripPointerCasts());
|
||||
assert(ParentRecover->getIntrinsicID() == llvm::Intrinsic::localrecover &&
|
||||
"expected alloca or localrecover in parent LocalDeclMap");
|
||||
RecoverCall = cast<llvm::CallInst>(ParentRecover->clone());
|
||||
RecoverCall->setArgOperand(1, ParentFP);
|
||||
RecoverCall->insertBefore(AllocaInsertPt);
|
||||
}
|
||||
|
||||
// Bitcast the variable, rename it, and insert it in the local decl map.
|
||||
llvm::Value *ChildVar =
|
||||
Builder.CreateBitCast(RecoverCall, ParentVar->getType());
|
||||
ChildVar->setName(ParentVar->getName());
|
||||
return ChildVar;
|
||||
}
|
||||
|
||||
void CodeGenFunction::EmitCapturedLocals(CodeGenFunction &ParentCGF,
|
||||
const Stmt *OutlinedStmt,
|
||||
llvm::Value *ParentFP) {
|
||||
bool IsFilter) {
|
||||
// Find all captures in the Stmt.
|
||||
CaptureFinder Finder(ParentCGF, ParentCGF.CXXABIThisDecl);
|
||||
Finder.Visit(OutlinedStmt);
|
||||
|
||||
// Typically there are no captures and we can exit early.
|
||||
if (Finder.Captures.empty())
|
||||
// We can exit early on x86_64 when there are no captures. We just have to
|
||||
// save the exception code in filters so that __exception_code() works.
|
||||
if (!Finder.foundCaptures() &&
|
||||
CGM.getTarget().getTriple().getArch() != llvm::Triple::x86) {
|
||||
if (IsFilter)
|
||||
EmitSEHExceptionCodeSave(ParentCGF, nullptr, nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
// Prepare the first two arguments to llvm.framerecover.
|
||||
llvm::Function *FrameRecoverFn = llvm::Intrinsic::getDeclaration(
|
||||
&CGM.getModule(), llvm::Intrinsic::framerecover);
|
||||
llvm::Constant *ParentI8Fn =
|
||||
llvm::ConstantExpr::getBitCast(ParentCGF.CurFn, Int8PtrTy);
|
||||
llvm::Value *EntryEBP = nullptr;
|
||||
llvm::Value *ParentFP;
|
||||
if (IsFilter && CGM.getTarget().getTriple().getArch() == llvm::Triple::x86) {
|
||||
// 32-bit SEH filters need to be careful about FP recovery. The end of the
|
||||
// EH registration is passed in as the EBP physical register. We can
|
||||
// recover that with llvm.frameaddress(1), and adjust that to recover the
|
||||
// parent's true frame pointer.
|
||||
CGBuilderTy Builder(AllocaInsertPt);
|
||||
EntryEBP = Builder.CreateCall(
|
||||
CGM.getIntrinsic(llvm::Intrinsic::frameaddress), {Builder.getInt32(1)});
|
||||
llvm::Function *RecoverFPIntrin =
|
||||
CGM.getIntrinsic(llvm::Intrinsic::x86_seh_recoverfp);
|
||||
llvm::Constant *ParentI8Fn =
|
||||
llvm::ConstantExpr::getBitCast(ParentCGF.CurFn, Int8PtrTy);
|
||||
ParentFP = Builder.CreateCall(RecoverFPIntrin, {ParentI8Fn, EntryEBP});
|
||||
} else {
|
||||
// Otherwise, for x64 and 32-bit finally functions, the parent FP is the
|
||||
// second parameter.
|
||||
auto AI = CurFn->arg_begin();
|
||||
++AI;
|
||||
ParentFP = AI;
|
||||
}
|
||||
|
||||
// Create llvm.framerecover calls for all captures.
|
||||
// Create llvm.localrecover calls for all captures.
|
||||
for (const VarDecl *VD : Finder.Captures) {
|
||||
if (isa<ImplicitParamDecl>(VD)) {
|
||||
CGM.ErrorUnsupported(VD, "'this' captured by SEH");
|
||||
@ -1407,49 +1488,63 @@ void CodeGenFunction::EmitCapturedLocals(CodeGenFunction &ParentCGF,
|
||||
continue;
|
||||
llvm::Value *ParentVar = I->second;
|
||||
|
||||
llvm::CallInst *RecoverCall = nullptr;
|
||||
CGBuilderTy Builder(AllocaInsertPt);
|
||||
if (auto *ParentAlloca = dyn_cast<llvm::AllocaInst>(ParentVar)) {
|
||||
// Mark the variable escaped if nobody else referenced it and compute the
|
||||
// frameescape index.
|
||||
auto InsertPair =
|
||||
ParentCGF.EscapedLocals.insert(std::make_pair(ParentAlloca, -1));
|
||||
if (InsertPair.second)
|
||||
InsertPair.first->second = ParentCGF.EscapedLocals.size() - 1;
|
||||
int FrameEscapeIdx = InsertPair.first->second;
|
||||
// call i8* @llvm.framerecover(i8* bitcast(@parentFn), i8* %fp, i32 N)
|
||||
RecoverCall = Builder.CreateCall(
|
||||
FrameRecoverFn, {ParentI8Fn, ParentFP,
|
||||
llvm::ConstantInt::get(Int32Ty, FrameEscapeIdx)});
|
||||
|
||||
} else {
|
||||
// If the parent didn't have an alloca, we're doing some nested outlining.
|
||||
// Just clone the existing framerecover call, but tweak the FP argument to
|
||||
// use our FP value. All other arguments are constants.
|
||||
auto *ParentRecover =
|
||||
cast<llvm::IntrinsicInst>(ParentVar->stripPointerCasts());
|
||||
assert(ParentRecover->getIntrinsicID() == llvm::Intrinsic::framerecover &&
|
||||
"expected alloca or framerecover in parent LocalDeclMap");
|
||||
RecoverCall = cast<llvm::CallInst>(ParentRecover->clone());
|
||||
RecoverCall->setArgOperand(1, ParentFP);
|
||||
RecoverCall->insertBefore(AllocaInsertPt);
|
||||
}
|
||||
|
||||
// Bitcast the variable, rename it, and insert it in the local decl map.
|
||||
llvm::Value *ChildVar =
|
||||
Builder.CreateBitCast(RecoverCall, ParentVar->getType());
|
||||
ChildVar->setName(ParentVar->getName());
|
||||
LocalDeclMap[VD] = ChildVar;
|
||||
LocalDeclMap[VD] =
|
||||
recoverAddrOfEscapedLocal(ParentCGF, ParentVar, ParentFP);
|
||||
}
|
||||
|
||||
if (Finder.SEHCodeSlot) {
|
||||
SEHCodeSlotStack.push_back(
|
||||
recoverAddrOfEscapedLocal(ParentCGF, Finder.SEHCodeSlot, ParentFP));
|
||||
}
|
||||
|
||||
if (IsFilter)
|
||||
EmitSEHExceptionCodeSave(ParentCGF, ParentFP, EntryEBP);
|
||||
}
|
||||
|
||||
/// Arrange a function prototype that can be called by Windows exception
|
||||
/// handling personalities. On Win64, the prototype looks like:
|
||||
/// RetTy func(void *EHPtrs, void *ParentFP);
|
||||
void CodeGenFunction::startOutlinedSEHHelper(CodeGenFunction &ParentCGF,
|
||||
StringRef Name, QualType RetTy,
|
||||
FunctionArgList &Args,
|
||||
bool IsFilter,
|
||||
const Stmt *OutlinedStmt) {
|
||||
SourceLocation StartLoc = OutlinedStmt->getLocStart();
|
||||
|
||||
// Get the mangled function name.
|
||||
SmallString<128> Name;
|
||||
{
|
||||
llvm::raw_svector_ostream OS(Name);
|
||||
const Decl *ParentCodeDecl = ParentCGF.CurCodeDecl;
|
||||
const NamedDecl *Parent = dyn_cast_or_null<NamedDecl>(ParentCodeDecl);
|
||||
assert(Parent && "FIXME: handle unnamed decls (lambdas, blocks) with SEH");
|
||||
MangleContext &Mangler = CGM.getCXXABI().getMangleContext();
|
||||
if (IsFilter)
|
||||
Mangler.mangleSEHFilterExpression(Parent, OS);
|
||||
else
|
||||
Mangler.mangleSEHFinallyBlock(Parent, OS);
|
||||
}
|
||||
|
||||
FunctionArgList Args;
|
||||
if (CGM.getTarget().getTriple().getArch() != llvm::Triple::x86 || !IsFilter) {
|
||||
// All SEH finally functions take two parameters. Win64 filters take two
|
||||
// parameters. Win32 filters take no parameters.
|
||||
if (IsFilter) {
|
||||
Args.push_back(ImplicitParamDecl::Create(
|
||||
getContext(), nullptr, StartLoc,
|
||||
&getContext().Idents.get("exception_pointers"),
|
||||
getContext().VoidPtrTy));
|
||||
} else {
|
||||
Args.push_back(ImplicitParamDecl::Create(
|
||||
getContext(), nullptr, StartLoc,
|
||||
&getContext().Idents.get("abnormal_termination"),
|
||||
getContext().UnsignedCharTy));
|
||||
}
|
||||
Args.push_back(ImplicitParamDecl::Create(
|
||||
getContext(), nullptr, StartLoc,
|
||||
&getContext().Idents.get("frame_pointer"), getContext().VoidPtrTy));
|
||||
}
|
||||
|
||||
QualType RetTy = IsFilter ? getContext().LongTy : getContext().VoidTy;
|
||||
|
||||
llvm::Function *ParentFn = ParentCGF.CurFn;
|
||||
const CGFunctionInfo &FnInfo = CGM.getTypes().arrangeFreeFunctionDeclaration(
|
||||
RetTy, Args, FunctionType::ExtInfo(), /*isVariadic=*/false);
|
||||
@ -1474,10 +1569,7 @@ void CodeGenFunction::startOutlinedSEHHelper(CodeGenFunction &ParentCGF,
|
||||
OutlinedStmt->getLocStart(), OutlinedStmt->getLocStart());
|
||||
|
||||
CGM.SetLLVMFunctionAttributes(nullptr, FnInfo, CurFn);
|
||||
|
||||
auto AI = Fn->arg_begin();
|
||||
++AI;
|
||||
EmitCapturedLocals(ParentCGF, OutlinedStmt, &*AI);
|
||||
EmitCapturedLocals(ParentCGF, OutlinedStmt, IsFilter);
|
||||
}
|
||||
|
||||
/// Create a stub filter function that will ultimately hold the code of the
|
||||
@ -1487,37 +1579,7 @@ llvm::Function *
|
||||
CodeGenFunction::GenerateSEHFilterFunction(CodeGenFunction &ParentCGF,
|
||||
const SEHExceptStmt &Except) {
|
||||
const Expr *FilterExpr = Except.getFilterExpr();
|
||||
SourceLocation StartLoc = FilterExpr->getLocStart();
|
||||
|
||||
SEHPointersDecl = ImplicitParamDecl::Create(
|
||||
getContext(), nullptr, StartLoc,
|
||||
&getContext().Idents.get("exception_pointers"), getContext().VoidPtrTy);
|
||||
FunctionArgList Args;
|
||||
Args.push_back(SEHPointersDecl);
|
||||
Args.push_back(ImplicitParamDecl::Create(
|
||||
getContext(), nullptr, StartLoc,
|
||||
&getContext().Idents.get("frame_pointer"), getContext().VoidPtrTy));
|
||||
|
||||
// Get the mangled function name.
|
||||
SmallString<128> Name;
|
||||
{
|
||||
llvm::raw_svector_ostream OS(Name);
|
||||
const Decl *ParentCodeDecl = ParentCGF.CurCodeDecl;
|
||||
const NamedDecl *Parent = dyn_cast_or_null<NamedDecl>(ParentCodeDecl);
|
||||
assert(Parent && "FIXME: handle unnamed decls (lambdas, blocks) with SEH");
|
||||
CGM.getCXXABI().getMangleContext().mangleSEHFilterExpression(Parent, OS);
|
||||
}
|
||||
|
||||
startOutlinedSEHHelper(ParentCGF, Name, getContext().LongTy, Args,
|
||||
FilterExpr);
|
||||
|
||||
// Mark finally block calls as nounwind and noinline to make LLVM's job a
|
||||
// little easier.
|
||||
// FIXME: Remove these restrictions in the future.
|
||||
CurFn->addFnAttr(llvm::Attribute::NoUnwind);
|
||||
CurFn->addFnAttr(llvm::Attribute::NoInline);
|
||||
|
||||
EmitSEHExceptionCodeSave();
|
||||
startOutlinedSEHHelper(ParentCGF, true, FilterExpr);
|
||||
|
||||
// Emit the original filter expression, convert to i32, and return.
|
||||
llvm::Value *R = EmitScalarExpr(FilterExpr);
|
||||
@ -1534,29 +1596,13 @@ llvm::Function *
|
||||
CodeGenFunction::GenerateSEHFinallyFunction(CodeGenFunction &ParentCGF,
|
||||
const SEHFinallyStmt &Finally) {
|
||||
const Stmt *FinallyBlock = Finally.getBlock();
|
||||
SourceLocation StartLoc = FinallyBlock->getLocStart();
|
||||
startOutlinedSEHHelper(ParentCGF, false, FinallyBlock);
|
||||
|
||||
FunctionArgList Args;
|
||||
Args.push_back(ImplicitParamDecl::Create(
|
||||
getContext(), nullptr, StartLoc,
|
||||
&getContext().Idents.get("abnormal_termination"),
|
||||
getContext().UnsignedCharTy));
|
||||
Args.push_back(ImplicitParamDecl::Create(
|
||||
getContext(), nullptr, StartLoc,
|
||||
&getContext().Idents.get("frame_pointer"), getContext().VoidPtrTy));
|
||||
|
||||
// Get the mangled function name.
|
||||
SmallString<128> Name;
|
||||
{
|
||||
llvm::raw_svector_ostream OS(Name);
|
||||
const Decl *ParentCodeDecl = ParentCGF.CurCodeDecl;
|
||||
const NamedDecl *Parent = dyn_cast_or_null<NamedDecl>(ParentCodeDecl);
|
||||
assert(Parent && "FIXME: handle unnamed decls (lambdas, blocks) with SEH");
|
||||
CGM.getCXXABI().getMangleContext().mangleSEHFinallyBlock(Parent, OS);
|
||||
}
|
||||
|
||||
startOutlinedSEHHelper(ParentCGF, Name, getContext().VoidTy, Args,
|
||||
FinallyBlock);
|
||||
// Mark finally block calls as nounwind and noinline to make LLVM's job a
|
||||
// little easier.
|
||||
// FIXME: Remove these restrictions in the future.
|
||||
CurFn->addFnAttr(llvm::Attribute::NoUnwind);
|
||||
CurFn->addFnAttr(llvm::Attribute::NoInline);
|
||||
|
||||
// Emit the original filter expression, convert to i32, and return.
|
||||
EmitStmt(FinallyBlock);
|
||||
@ -1566,44 +1612,58 @@ CodeGenFunction::GenerateSEHFinallyFunction(CodeGenFunction &ParentCGF,
|
||||
return CurFn;
|
||||
}
|
||||
|
||||
void CodeGenFunction::EmitSEHExceptionCodeSave() {
|
||||
void CodeGenFunction::EmitSEHExceptionCodeSave(CodeGenFunction &ParentCGF,
|
||||
llvm::Value *ParentFP,
|
||||
llvm::Value *EntryEBP) {
|
||||
// Get the pointer to the EXCEPTION_POINTERS struct. This is returned by the
|
||||
// __exception_info intrinsic.
|
||||
if (CGM.getTarget().getTriple().getArch() != llvm::Triple::x86) {
|
||||
// On Win64, the info is passed as the first parameter to the filter.
|
||||
auto AI = CurFn->arg_begin();
|
||||
SEHInfo = AI;
|
||||
SEHCodeSlotStack.push_back(
|
||||
CreateMemTemp(getContext().IntTy, "__exception_code"));
|
||||
} else {
|
||||
// On Win32, the EBP on entry to the filter points to the end of an
|
||||
// exception registration object. It contains 6 32-bit fields, and the info
|
||||
// pointer is stored in the second field. So, GEP 20 bytes backwards and
|
||||
// load the pointer.
|
||||
SEHInfo = Builder.CreateConstInBoundsGEP1_32(Int8Ty, EntryEBP, -20);
|
||||
SEHInfo = Builder.CreateBitCast(SEHInfo, Int8PtrTy->getPointerTo());
|
||||
SEHInfo = Builder.CreateLoad(Int8PtrTy, SEHInfo);
|
||||
SEHCodeSlotStack.push_back(recoverAddrOfEscapedLocal(
|
||||
ParentCGF, ParentCGF.SEHCodeSlotStack.back(), ParentFP));
|
||||
}
|
||||
|
||||
// Save the exception code in the exception slot to unify exception access in
|
||||
// the filter function and the landing pad.
|
||||
// struct EXCEPTION_POINTERS {
|
||||
// EXCEPTION_RECORD *ExceptionRecord;
|
||||
// CONTEXT *ContextRecord;
|
||||
// };
|
||||
// void *exn.slot =
|
||||
// (void *)(uintptr_t)exception_pointers->ExceptionRecord->ExceptionCode;
|
||||
llvm::Value *Ptrs = Builder.CreateLoad(GetAddrOfLocalVar(SEHPointersDecl));
|
||||
// int exceptioncode = exception_pointers->ExceptionRecord->ExceptionCode;
|
||||
llvm::Type *RecordTy = CGM.Int32Ty->getPointerTo();
|
||||
llvm::Type *PtrsTy = llvm::StructType::get(RecordTy, CGM.VoidPtrTy, nullptr);
|
||||
Ptrs = Builder.CreateBitCast(Ptrs, PtrsTy->getPointerTo());
|
||||
llvm::Value *Ptrs = Builder.CreateBitCast(SEHInfo, PtrsTy->getPointerTo());
|
||||
llvm::Value *Rec = Builder.CreateStructGEP(PtrsTy, Ptrs, 0);
|
||||
Rec = Builder.CreateLoad(Rec);
|
||||
llvm::Value *Code = Builder.CreateLoad(Rec);
|
||||
Code = Builder.CreateZExt(Code, CGM.IntPtrTy);
|
||||
// FIXME: Change landing pads to produce {i32, i32} and make the exception
|
||||
// slot an i32.
|
||||
Code = Builder.CreateIntToPtr(Code, CGM.VoidPtrTy);
|
||||
Builder.CreateStore(Code, getExceptionSlot());
|
||||
assert(!SEHCodeSlotStack.empty() && "emitting EH code outside of __except");
|
||||
Builder.CreateStore(Code, SEHCodeSlotStack.back());
|
||||
}
|
||||
|
||||
llvm::Value *CodeGenFunction::EmitSEHExceptionInfo() {
|
||||
// Sema should diagnose calling this builtin outside of a filter context, but
|
||||
// don't crash if we screw up.
|
||||
if (!SEHPointersDecl)
|
||||
if (!SEHInfo)
|
||||
return llvm::UndefValue::get(Int8PtrTy);
|
||||
return Builder.CreateLoad(GetAddrOfLocalVar(SEHPointersDecl));
|
||||
assert(SEHInfo->getType() == Int8PtrTy);
|
||||
return SEHInfo;
|
||||
}
|
||||
|
||||
llvm::Value *CodeGenFunction::EmitSEHExceptionCode() {
|
||||
// If we're in a landing pad or filter function, the exception slot contains
|
||||
// the code.
|
||||
assert(ExceptionSlot);
|
||||
llvm::Value *Code =
|
||||
Builder.CreatePtrToInt(getExceptionFromSlot(), CGM.IntPtrTy);
|
||||
return Builder.CreateTrunc(Code, CGM.Int32Ty);
|
||||
assert(!SEHCodeSlotStack.empty() && "emitting EH code outside of __except");
|
||||
return Builder.CreateLoad(Int32Ty, SEHCodeSlotStack.back());
|
||||
}
|
||||
|
||||
llvm::Value *CodeGenFunction::EmitSEHAbnormalTermination() {
|
||||
@ -1616,9 +1676,11 @@ llvm::Value *CodeGenFunction::EmitSEHAbnormalTermination() {
|
||||
void CodeGenFunction::EnterSEHTryStmt(const SEHTryStmt &S) {
|
||||
CodeGenFunction HelperCGF(CGM, /*suppressNewContext=*/true);
|
||||
if (const SEHFinallyStmt *Finally = S.getFinallyHandler()) {
|
||||
// Push a cleanup for __finally blocks.
|
||||
// Outline the finally block.
|
||||
llvm::Function *FinallyFunc =
|
||||
HelperCGF.GenerateSEHFinallyFunction(*this, *Finally);
|
||||
|
||||
// Push a cleanup for __finally blocks.
|
||||
EHStack.pushCleanup<PerformSEHFinally>(NormalAndEHCleanup, FinallyFunc);
|
||||
return;
|
||||
}
|
||||
@ -1627,12 +1689,16 @@ void CodeGenFunction::EnterSEHTryStmt(const SEHTryStmt &S) {
|
||||
const SEHExceptStmt *Except = S.getExceptHandler();
|
||||
assert(Except);
|
||||
EHCatchScope *CatchScope = EHStack.pushCatch(1);
|
||||
SEHCodeSlotStack.push_back(
|
||||
CreateMemTemp(getContext().IntTy, "__exception_code"));
|
||||
|
||||
// If the filter is known to evaluate to 1, then we can use the clause "catch
|
||||
// i8* null".
|
||||
// If the filter is known to evaluate to 1, then we can use the clause
|
||||
// "catch i8* null". We can't do this on x86 because the filter has to save
|
||||
// the exception code.
|
||||
llvm::Constant *C =
|
||||
CGM.EmitConstantExpr(Except->getFilterExpr(), getContext().IntTy, this);
|
||||
if (C && C->isOneValue()) {
|
||||
if (CGM.getTarget().getTriple().getArch() != llvm::Triple::x86 && C &&
|
||||
C->isOneValue()) {
|
||||
CatchScope->setCatchAllHandler(0, createBasicBlock("__except"));
|
||||
return;
|
||||
}
|
||||
@ -1664,6 +1730,7 @@ void CodeGenFunction::ExitSEHTryStmt(const SEHTryStmt &S) {
|
||||
if (!CatchScope.hasEHBranches()) {
|
||||
CatchScope.clearHandlerBlocks();
|
||||
EHStack.popCatch();
|
||||
SEHCodeSlotStack.pop_back();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1683,9 +1750,20 @@ void CodeGenFunction::ExitSEHTryStmt(const SEHTryStmt &S) {
|
||||
|
||||
EmitBlockAfterUses(ExceptBB);
|
||||
|
||||
// On Win64, the exception pointer is the exception code. Copy it to the slot.
|
||||
if (CGM.getTarget().getTriple().getArch() != llvm::Triple::x86) {
|
||||
llvm::Value *Code =
|
||||
Builder.CreatePtrToInt(getExceptionFromSlot(), IntPtrTy);
|
||||
Code = Builder.CreateTrunc(Code, Int32Ty);
|
||||
Builder.CreateStore(Code, SEHCodeSlotStack.back());
|
||||
}
|
||||
|
||||
// Emit the __except body.
|
||||
EmitStmt(Except->getBlock());
|
||||
|
||||
// End the lifetime of the exception code.
|
||||
SEHCodeSlotStack.pop_back();
|
||||
|
||||
if (HaveInsertPoint())
|
||||
Builder.CreateBr(ContBB);
|
||||
|
||||
|
@ -1356,14 +1356,15 @@ RValue CodeGenFunction::EmitLoadOfLValue(LValue LV, SourceLocation Loc) {
|
||||
|
||||
RValue CodeGenFunction::EmitLoadOfBitfieldLValue(LValue LV) {
|
||||
const CGBitFieldInfo &Info = LV.getBitFieldInfo();
|
||||
CharUnits Align = LV.getAlignment().alignmentAtOffset(Info.StorageOffset);
|
||||
|
||||
// Get the output type.
|
||||
llvm::Type *ResLTy = ConvertType(LV.getType());
|
||||
|
||||
llvm::Value *Ptr = LV.getBitFieldAddr();
|
||||
llvm::Value *Val = Builder.CreateLoad(Ptr, LV.isVolatileQualified(),
|
||||
"bf.load");
|
||||
cast<llvm::LoadInst>(Val)->setAlignment(Info.StorageAlignment);
|
||||
llvm::Value *Val = Builder.CreateAlignedLoad(Ptr, Align.getQuantity(),
|
||||
LV.isVolatileQualified(),
|
||||
"bf.load");
|
||||
|
||||
if (Info.IsSigned) {
|
||||
assert(static_cast<unsigned>(Info.Offset + Info.Size) <= Info.StorageSize);
|
||||
@ -1559,6 +1560,7 @@ void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst,
|
||||
void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst,
|
||||
llvm::Value **Result) {
|
||||
const CGBitFieldInfo &Info = Dst.getBitFieldInfo();
|
||||
CharUnits Align = Dst.getAlignment().alignmentAtOffset(Info.StorageOffset);
|
||||
llvm::Type *ResLTy = ConvertTypeForMem(Dst.getType());
|
||||
llvm::Value *Ptr = Dst.getBitFieldAddr();
|
||||
|
||||
@ -1575,9 +1577,9 @@ void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst,
|
||||
// and mask together with source before storing.
|
||||
if (Info.StorageSize != Info.Size) {
|
||||
assert(Info.StorageSize > Info.Size && "Invalid bitfield size.");
|
||||
llvm::Value *Val = Builder.CreateLoad(Ptr, Dst.isVolatileQualified(),
|
||||
"bf.load");
|
||||
cast<llvm::LoadInst>(Val)->setAlignment(Info.StorageAlignment);
|
||||
llvm::Value *Val = Builder.CreateAlignedLoad(Ptr, Align.getQuantity(),
|
||||
Dst.isVolatileQualified(),
|
||||
"bf.load");
|
||||
|
||||
// Mask the source value as needed.
|
||||
if (!hasBooleanRepresentation(Dst.getType()))
|
||||
@ -1603,9 +1605,8 @@ void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst,
|
||||
}
|
||||
|
||||
// Write the new value back out.
|
||||
llvm::StoreInst *Store = Builder.CreateStore(SrcVal, Ptr,
|
||||
Dst.isVolatileQualified());
|
||||
Store->setAlignment(Info.StorageAlignment);
|
||||
Builder.CreateAlignedStore(SrcVal, Ptr, Align.getQuantity(),
|
||||
Dst.isVolatileQualified());
|
||||
|
||||
// Return the new value of the bit-field, if requested.
|
||||
if (Result) {
|
||||
@ -2415,8 +2416,7 @@ void CodeGenFunction::EmitTrapCheck(llvm::Value *Checked) {
|
||||
}
|
||||
|
||||
llvm::CallInst *CodeGenFunction::EmitTrapCall(llvm::Intrinsic::ID IntrID) {
|
||||
llvm::CallInst *TrapCall =
|
||||
Builder.CreateCall(CGM.getIntrinsic(IntrID), {});
|
||||
llvm::CallInst *TrapCall = Builder.CreateCall(CGM.getIntrinsic(IntrID));
|
||||
|
||||
if (!CGM.getCodeGenOpts().TrapFuncName.empty())
|
||||
TrapCall->addAttribute(llvm::AttributeSet::FunctionIndex,
|
||||
|
@ -31,10 +31,9 @@ using namespace CodeGen;
|
||||
typedef llvm::PointerIntPair<llvm::Value*,1,bool> TryEmitResult;
|
||||
static TryEmitResult
|
||||
tryEmitARCRetainScalarExpr(CodeGenFunction &CGF, const Expr *e);
|
||||
static RValue AdjustRelatedResultType(CodeGenFunction &CGF,
|
||||
QualType ET,
|
||||
const ObjCMethodDecl *Method,
|
||||
RValue Result);
|
||||
static RValue AdjustObjCObjectType(CodeGenFunction &CGF,
|
||||
QualType ET,
|
||||
RValue Result);
|
||||
|
||||
/// Given the address of a variable of pointer type, find the correct
|
||||
/// null to store into it.
|
||||
@ -248,23 +247,22 @@ llvm::Value *CodeGenFunction::EmitObjCProtocolExpr(const ObjCProtocolExpr *E) {
|
||||
return CGM.getObjCRuntime().GenerateProtocolRef(*this, E->getProtocol());
|
||||
}
|
||||
|
||||
/// \brief Adjust the type of the result of an Objective-C message send
|
||||
/// expression when the method has a related result type.
|
||||
static RValue AdjustRelatedResultType(CodeGenFunction &CGF,
|
||||
QualType ExpT,
|
||||
const ObjCMethodDecl *Method,
|
||||
RValue Result) {
|
||||
if (!Method)
|
||||
/// \brief Adjust the type of an Objective-C object that doesn't match up due
|
||||
/// to type erasure at various points, e.g., related result types or the use
|
||||
/// of parameterized classes.
|
||||
static RValue AdjustObjCObjectType(CodeGenFunction &CGF, QualType ExpT,
|
||||
RValue Result) {
|
||||
if (!ExpT->isObjCRetainableType())
|
||||
return Result;
|
||||
|
||||
if (!Method->hasRelatedResultType() ||
|
||||
CGF.getContext().hasSameType(ExpT, Method->getReturnType()) ||
|
||||
!Result.isScalar())
|
||||
// If the converted types are the same, we're done.
|
||||
llvm::Type *ExpLLVMTy = CGF.ConvertType(ExpT);
|
||||
if (ExpLLVMTy == Result.getScalarVal()->getType())
|
||||
return Result;
|
||||
|
||||
// We have applied a related result type. Cast the rvalue appropriately.
|
||||
|
||||
// We have applied a substitution. Cast the rvalue appropriately.
|
||||
return RValue::get(CGF.Builder.CreateBitCast(Result.getScalarVal(),
|
||||
CGF.ConvertType(ExpT)));
|
||||
ExpLLVMTy));
|
||||
}
|
||||
|
||||
/// Decide whether to extend the lifetime of the receiver of a
|
||||
@ -449,7 +447,7 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
|
||||
Builder.CreateStore(newSelf, selfAddr);
|
||||
}
|
||||
|
||||
return AdjustRelatedResultType(*this, E->getType(), method, result);
|
||||
return AdjustObjCObjectType(*this, E->getType(), result);
|
||||
}
|
||||
|
||||
namespace {
|
||||
@ -2011,7 +2009,7 @@ CodeGenFunction::EmitARCRetainAutoreleasedReturnValue(llvm::Value *value) {
|
||||
|
||||
// Call the marker asm if we made one, which we do only at -O0.
|
||||
if (marker)
|
||||
Builder.CreateCall(marker, {});
|
||||
Builder.CreateCall(marker);
|
||||
|
||||
return emitARCValueOperation(*this, value,
|
||||
CGM.getARCEntrypoints().objc_retainAutoreleasedReturnValue,
|
||||
|
@ -134,7 +134,7 @@ LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF,
|
||||
CGBitFieldInfo *Info = new (CGF.CGM.getContext()) CGBitFieldInfo(
|
||||
CGBitFieldInfo::MakeInfo(CGF.CGM.getTypes(), Ivar, BitOffset, BitFieldSize,
|
||||
CGF.CGM.getContext().toBits(StorageSize),
|
||||
Alignment.getQuantity()));
|
||||
CharUnits::fromQuantity(0)));
|
||||
|
||||
V = CGF.Builder.CreateBitCast(V,
|
||||
llvm::Type::getIntNPtrTy(CGF.getLLVMContext(),
|
||||
@ -160,7 +160,7 @@ namespace {
|
||||
|
||||
void Emit(CodeGenFunction &CGF, Flags flags) override {
|
||||
if (!MightThrow) {
|
||||
CGF.Builder.CreateCall(Fn, {})->setDoesNotThrow();
|
||||
CGF.Builder.CreateCall(Fn)->setDoesNotThrow();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -537,7 +537,7 @@ CGOpenMPRuntime::createRuntimeFunction(OpenMPRTLFunction Function) {
|
||||
break;
|
||||
}
|
||||
case OMPRTL__kmpc_barrier: {
|
||||
// Build void __kmpc_cancel_barrier(ident_t *loc, kmp_int32 global_tid);
|
||||
// Build void __kmpc_barrier(ident_t *loc, kmp_int32 global_tid);
|
||||
llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty};
|
||||
llvm::FunctionType *FnTy =
|
||||
llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false);
|
||||
@ -829,6 +829,15 @@ CGOpenMPRuntime::createRuntimeFunction(OpenMPRTLFunction Function) {
|
||||
RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_cancellationpoint");
|
||||
break;
|
||||
}
|
||||
case OMPRTL__kmpc_cancel: {
|
||||
// Build kmp_int32 __kmpc_cancel(ident_t *loc, kmp_int32 global_tid,
|
||||
// kmp_int32 cncl_kind)
|
||||
llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty, CGM.IntTy};
|
||||
llvm::FunctionType *FnTy =
|
||||
llvm::FunctionType::get(CGM.Int32Ty, TypeParams, /*isVarArg*/ false);
|
||||
RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_cancel");
|
||||
break;
|
||||
}
|
||||
}
|
||||
return RTLFn;
|
||||
}
|
||||
@ -923,6 +932,8 @@ llvm::Constant *CGOpenMPRuntime::createDispatchNextFunction(unsigned IVSize,
|
||||
|
||||
llvm::Constant *
|
||||
CGOpenMPRuntime::getOrCreateThreadPrivateCache(const VarDecl *VD) {
|
||||
assert(!CGM.getLangOpts().OpenMPUseTLS ||
|
||||
!CGM.getContext().getTargetInfo().isTLSSupported());
|
||||
// Lookup the entry, lazily creating it if necessary.
|
||||
return getOrCreateInternalVariable(CGM.Int8PtrPtrTy,
|
||||
Twine(CGM.getMangledName(VD)) + ".cache.");
|
||||
@ -932,6 +943,10 @@ llvm::Value *CGOpenMPRuntime::getAddrOfThreadPrivate(CodeGenFunction &CGF,
|
||||
const VarDecl *VD,
|
||||
llvm::Value *VDAddr,
|
||||
SourceLocation Loc) {
|
||||
if (CGM.getLangOpts().OpenMPUseTLS &&
|
||||
CGM.getContext().getTargetInfo().isTLSSupported())
|
||||
return VDAddr;
|
||||
|
||||
auto VarTy = VDAddr->getType()->getPointerElementType();
|
||||
llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc),
|
||||
CGF.Builder.CreatePointerCast(VDAddr, CGM.Int8PtrTy),
|
||||
@ -961,6 +976,10 @@ void CGOpenMPRuntime::emitThreadPrivateVarInit(
|
||||
llvm::Function *CGOpenMPRuntime::emitThreadPrivateVarDefinition(
|
||||
const VarDecl *VD, llvm::Value *VDAddr, SourceLocation Loc,
|
||||
bool PerformInit, CodeGenFunction *CGF) {
|
||||
if (CGM.getLangOpts().OpenMPUseTLS &&
|
||||
CGM.getContext().getTargetInfo().isTLSSupported())
|
||||
return nullptr;
|
||||
|
||||
VD = VD->getDefinition(CGM.getContext());
|
||||
if (VD && ThreadPrivateWithDefinition.count(VD) == 0) {
|
||||
ThreadPrivateWithDefinition.insert(VD);
|
||||
@ -2723,18 +2742,18 @@ void CGOpenMPRuntime::emitInlinedDirective(CodeGenFunction &CGF,
|
||||
CGF.CapturedStmtInfo->EmitBody(CGF, /*S=*/nullptr);
|
||||
}
|
||||
|
||||
void CGOpenMPRuntime::emitCancellationPointCall(
|
||||
CodeGenFunction &CGF, SourceLocation Loc,
|
||||
OpenMPDirectiveKind CancelRegion) {
|
||||
// Build call kmp_int32 OMPRTL__kmpc_cancellationpoint(ident_t *loc, kmp_int32
|
||||
// global_tid, kmp_int32 cncl_kind);
|
||||
enum {
|
||||
CancelNoreq = 0,
|
||||
CancelParallel = 1,
|
||||
CancelLoop = 2,
|
||||
CancelSections = 3,
|
||||
CancelTaskgroup = 4
|
||||
} CancelKind = CancelNoreq;
|
||||
namespace {
|
||||
enum RTCancelKind {
|
||||
CancelNoreq = 0,
|
||||
CancelParallel = 1,
|
||||
CancelLoop = 2,
|
||||
CancelSections = 3,
|
||||
CancelTaskgroup = 4
|
||||
};
|
||||
}
|
||||
|
||||
static RTCancelKind getCancellationKind(OpenMPDirectiveKind CancelRegion) {
|
||||
RTCancelKind CancelKind = CancelNoreq;
|
||||
if (CancelRegion == OMPD_parallel)
|
||||
CancelKind = CancelParallel;
|
||||
else if (CancelRegion == OMPD_for)
|
||||
@ -2745,14 +2764,22 @@ void CGOpenMPRuntime::emitCancellationPointCall(
|
||||
assert(CancelRegion == OMPD_taskgroup);
|
||||
CancelKind = CancelTaskgroup;
|
||||
}
|
||||
return CancelKind;
|
||||
}
|
||||
|
||||
void CGOpenMPRuntime::emitCancellationPointCall(
|
||||
CodeGenFunction &CGF, SourceLocation Loc,
|
||||
OpenMPDirectiveKind CancelRegion) {
|
||||
// Build call kmp_int32 __kmpc_cancellationpoint(ident_t *loc, kmp_int32
|
||||
// global_tid, kmp_int32 cncl_kind);
|
||||
if (auto *OMPRegionInfo =
|
||||
dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo)) {
|
||||
auto CancelDest =
|
||||
CGF.getOMPCancelDestination(OMPRegionInfo->getDirectiveKind());
|
||||
if (CancelDest.isValid()) {
|
||||
llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc),
|
||||
getThreadID(CGF, Loc),
|
||||
CGF.Builder.getInt32(CancelKind)};
|
||||
llvm::Value *Args[] = {
|
||||
emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc),
|
||||
CGF.Builder.getInt32(getCancellationKind(CancelRegion))};
|
||||
// Ignore return result until untied tasks are supported.
|
||||
auto *Result = CGF.EmitRuntimeCall(
|
||||
createRuntimeFunction(OMPRTL__kmpc_cancellationpoint), Args);
|
||||
@ -2774,3 +2801,36 @@ void CGOpenMPRuntime::emitCancellationPointCall(
|
||||
}
|
||||
}
|
||||
|
||||
void CGOpenMPRuntime::emitCancelCall(CodeGenFunction &CGF, SourceLocation Loc,
|
||||
OpenMPDirectiveKind CancelRegion) {
|
||||
// Build call kmp_int32 __kmpc_cancel(ident_t *loc, kmp_int32 global_tid,
|
||||
// kmp_int32 cncl_kind);
|
||||
if (auto *OMPRegionInfo =
|
||||
dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo)) {
|
||||
auto CancelDest =
|
||||
CGF.getOMPCancelDestination(OMPRegionInfo->getDirectiveKind());
|
||||
if (CancelDest.isValid()) {
|
||||
llvm::Value *Args[] = {
|
||||
emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc),
|
||||
CGF.Builder.getInt32(getCancellationKind(CancelRegion))};
|
||||
// Ignore return result until untied tasks are supported.
|
||||
auto *Result =
|
||||
CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__kmpc_cancel), Args);
|
||||
// if (__kmpc_cancel()) {
|
||||
// __kmpc_cancel_barrier();
|
||||
// exit from construct;
|
||||
// }
|
||||
auto *ExitBB = CGF.createBasicBlock(".cancel.exit");
|
||||
auto *ContBB = CGF.createBasicBlock(".cancel.continue");
|
||||
auto *Cmp = CGF.Builder.CreateIsNotNull(Result);
|
||||
CGF.Builder.CreateCondBr(Cmp, ExitBB, ContBB);
|
||||
CGF.EmitBlock(ExitBB);
|
||||
// __kmpc_cancel_barrier();
|
||||
emitBarrierCall(CGF, Loc, OMPD_unknown, /*CheckForCancel=*/false);
|
||||
// exit from construct;
|
||||
CGF.EmitBranchThroughCleanup(CancelDest);
|
||||
CGF.EmitBlock(ContBB, /*IsFinished=*/true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -151,6 +151,9 @@ class CGOpenMPRuntime {
|
||||
// Call to kmp_int32 __kmpc_cancellationpoint(ident_t *loc, kmp_int32
|
||||
// global_tid, kmp_int32 cncl_kind);
|
||||
OMPRTL__kmpc_cancellationpoint,
|
||||
// Call to kmp_int32 __kmpc_cancel(ident_t *loc, kmp_int32 global_tid,
|
||||
// kmp_int32 cncl_kind);
|
||||
OMPRTL__kmpc_cancel,
|
||||
};
|
||||
|
||||
/// \brief Values for bit flags used in the ident_t to describe the fields.
|
||||
@ -698,6 +701,12 @@ class CGOpenMPRuntime {
|
||||
virtual void emitCancellationPointCall(CodeGenFunction &CGF,
|
||||
SourceLocation Loc,
|
||||
OpenMPDirectiveKind CancelRegion);
|
||||
|
||||
/// \brief Emit code for 'cancel' construct.
|
||||
/// \param CancelRegion Region kind for which the cancel must be emitted.
|
||||
///
|
||||
virtual void emitCancelCall(CodeGenFunction &CGF, SourceLocation Loc,
|
||||
OpenMPDirectiveKind CancelRegion);
|
||||
};
|
||||
|
||||
} // namespace CodeGen
|
||||
|
@ -78,16 +78,16 @@ struct CGBitFieldInfo {
|
||||
/// bitfield.
|
||||
unsigned StorageSize;
|
||||
|
||||
/// The alignment which should be used when accessing the bitfield.
|
||||
unsigned StorageAlignment;
|
||||
/// The offset of the bitfield storage from the start of the struct.
|
||||
CharUnits StorageOffset;
|
||||
|
||||
CGBitFieldInfo()
|
||||
: Offset(), Size(), IsSigned(), StorageSize(), StorageAlignment() {}
|
||||
: Offset(), Size(), IsSigned(), StorageSize(), StorageOffset() {}
|
||||
|
||||
CGBitFieldInfo(unsigned Offset, unsigned Size, bool IsSigned,
|
||||
unsigned StorageSize, unsigned StorageAlignment)
|
||||
unsigned StorageSize, CharUnits StorageOffset)
|
||||
: Offset(Offset), Size(Size), IsSigned(IsSigned),
|
||||
StorageSize(StorageSize), StorageAlignment(StorageAlignment) {}
|
||||
StorageSize(StorageSize), StorageOffset(StorageOffset) {}
|
||||
|
||||
void print(raw_ostream &OS) const;
|
||||
void dump() const;
|
||||
@ -99,7 +99,7 @@ struct CGBitFieldInfo {
|
||||
const FieldDecl *FD,
|
||||
uint64_t Offset, uint64_t Size,
|
||||
uint64_t StorageSize,
|
||||
uint64_t StorageAlignment);
|
||||
CharUnits StorageOffset);
|
||||
};
|
||||
|
||||
/// CGRecordLayout - This class handles struct and union layout info while
|
||||
|
@ -228,11 +228,7 @@ void CGRecordLowering::setBitFieldInfo(
|
||||
Info.Offset = (unsigned)(getFieldBitOffset(FD) - Context.toBits(StartOffset));
|
||||
Info.Size = FD->getBitWidthValue(Context);
|
||||
Info.StorageSize = (unsigned)DataLayout.getTypeAllocSizeInBits(StorageType);
|
||||
// Here we calculate the actual storage alignment of the bits. E.g if we've
|
||||
// got an alignment >= 2 and the bitfield starts at offset 6 we've got an
|
||||
// alignment of 2.
|
||||
Info.StorageAlignment =
|
||||
Layout.getAlignment().alignmentAtOffset(StartOffset).getQuantity();
|
||||
Info.StorageOffset = StartOffset;
|
||||
if (Info.Size > Info.StorageSize)
|
||||
Info.Size = Info.StorageSize;
|
||||
// Reverse the bit offsets for big endian machines. Because we represent
|
||||
@ -651,7 +647,7 @@ CGBitFieldInfo CGBitFieldInfo::MakeInfo(CodeGenTypes &Types,
|
||||
const FieldDecl *FD,
|
||||
uint64_t Offset, uint64_t Size,
|
||||
uint64_t StorageSize,
|
||||
uint64_t StorageAlignment) {
|
||||
CharUnits StorageOffset) {
|
||||
// This function is vestigial from CGRecordLayoutBuilder days but is still
|
||||
// used in GCObjCRuntime.cpp. That usage has a "fixme" attached to it that
|
||||
// when addressed will allow for the removal of this function.
|
||||
@ -683,7 +679,7 @@ CGBitFieldInfo CGBitFieldInfo::MakeInfo(CodeGenTypes &Types,
|
||||
Offset = StorageSize - (Offset + Size);
|
||||
}
|
||||
|
||||
return CGBitFieldInfo(Offset, Size, IsSigned, StorageSize, StorageAlignment);
|
||||
return CGBitFieldInfo(Offset, Size, IsSigned, StorageSize, StorageOffset);
|
||||
}
|
||||
|
||||
CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D,
|
||||
@ -856,7 +852,7 @@ void CGBitFieldInfo::print(raw_ostream &OS) const {
|
||||
<< " Size:" << Size
|
||||
<< " IsSigned:" << IsSigned
|
||||
<< " StorageSize:" << StorageSize
|
||||
<< " StorageAlignment:" << StorageAlignment << ">";
|
||||
<< " StorageOffset:" << StorageOffset.getQuantity() << ">";
|
||||
}
|
||||
|
||||
void CGBitFieldInfo::dump() const {
|
||||
|
@ -1852,6 +1852,14 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
|
||||
std::vector<llvm::Value*> InOutArgs;
|
||||
std::vector<llvm::Type*> InOutArgTypes;
|
||||
|
||||
// An inline asm can be marked readonly if it meets the following conditions:
|
||||
// - it doesn't have any sideeffects
|
||||
// - it doesn't clobber memory
|
||||
// - it doesn't return a value by-reference
|
||||
// It can be marked readnone if it doesn't have any input memory constraints
|
||||
// in addition to meeting the conditions listed above.
|
||||
bool ReadOnly = true, ReadNone = true;
|
||||
|
||||
for (unsigned i = 0, e = S.getNumOutputs(); i != e; i++) {
|
||||
TargetInfo::ConstraintInfo &Info = OutputConstraintInfos[i];
|
||||
|
||||
@ -1915,6 +1923,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
|
||||
Args.push_back(Dest.getAddress());
|
||||
Constraints += "=*";
|
||||
Constraints += OutputConstraint;
|
||||
ReadOnly = ReadNone = false;
|
||||
}
|
||||
|
||||
if (Info.isReadWrite()) {
|
||||
@ -1959,6 +1968,9 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
|
||||
|
||||
TargetInfo::ConstraintInfo &Info = InputConstraintInfos[i];
|
||||
|
||||
if (Info.allowsMemory())
|
||||
ReadNone = false;
|
||||
|
||||
if (!Constraints.empty())
|
||||
Constraints += ',';
|
||||
|
||||
@ -2023,7 +2035,9 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
|
||||
for (unsigned i = 0, e = S.getNumClobbers(); i != e; i++) {
|
||||
StringRef Clobber = S.getClobber(i);
|
||||
|
||||
if (Clobber != "memory" && Clobber != "cc")
|
||||
if (Clobber == "memory")
|
||||
ReadOnly = ReadNone = false;
|
||||
else if (Clobber != "cc")
|
||||
Clobber = getTarget().getNormalizedGCCRegisterName(Clobber);
|
||||
|
||||
if (!Constraints.empty())
|
||||
@ -2063,6 +2077,16 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
|
||||
Result->addAttribute(llvm::AttributeSet::FunctionIndex,
|
||||
llvm::Attribute::NoUnwind);
|
||||
|
||||
// Attach readnone and readonly attributes.
|
||||
if (!HasSideEffect) {
|
||||
if (ReadNone)
|
||||
Result->addAttribute(llvm::AttributeSet::FunctionIndex,
|
||||
llvm::Attribute::ReadNone);
|
||||
else if (ReadOnly)
|
||||
Result->addAttribute(llvm::AttributeSet::FunctionIndex,
|
||||
llvm::Attribute::ReadOnly);
|
||||
}
|
||||
|
||||
// Slap the source location of the inline asm into a !srcloc metadata on the
|
||||
// call.
|
||||
if (const GCCAsmStmt *gccAsmStmt = dyn_cast<GCCAsmStmt>(&S)) {
|
||||
|
@ -2108,7 +2108,8 @@ void CodeGenFunction::EmitOMPCancellationPointDirective(
|
||||
}
|
||||
|
||||
void CodeGenFunction::EmitOMPCancelDirective(const OMPCancelDirective &S) {
|
||||
llvm_unreachable("CodeGen for 'omp cancel' is not supported yet.");
|
||||
CGM.getOpenMPRuntime().emitCancelCall(*this, S.getLocStart(),
|
||||
S.getCancelRegion());
|
||||
}
|
||||
|
||||
CodeGenFunction::JumpDest
|
||||
|
@ -364,7 +364,7 @@ void CodeGenFunction::EmitMustTailThunk(const CXXMethodDecl *MD,
|
||||
FinishFunction();
|
||||
}
|
||||
|
||||
void CodeGenFunction::GenerateThunk(llvm::Function *Fn,
|
||||
void CodeGenFunction::generateThunk(llvm::Function *Fn,
|
||||
const CGFunctionInfo &FnInfo,
|
||||
GlobalDecl GD, const ThunkInfo &Thunk) {
|
||||
StartThunk(Fn, GD, FnInfo);
|
||||
@ -376,13 +376,6 @@ void CodeGenFunction::GenerateThunk(llvm::Function *Fn,
|
||||
|
||||
// Make the call and return the result.
|
||||
EmitCallAndReturnForThunk(Callee, &Thunk);
|
||||
|
||||
// Set the right linkage.
|
||||
CGM.setFunctionLinkage(GD, Fn);
|
||||
|
||||
// Set the right visibility.
|
||||
const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
|
||||
setThunkVisibility(CGM, MD, Thunk, Fn);
|
||||
}
|
||||
|
||||
void CodeGenVTables::emitThunk(GlobalDecl GD, const ThunkInfo &Thunk,
|
||||
@ -455,11 +448,17 @@ void CodeGenVTables::emitThunk(GlobalDecl GD, const ThunkInfo &Thunk,
|
||||
CodeGenFunction(CGM).GenerateVarArgsThunk(ThunkFn, FnInfo, GD, Thunk);
|
||||
} else {
|
||||
// Normal thunk body generation.
|
||||
CodeGenFunction(CGM).GenerateThunk(ThunkFn, FnInfo, GD, Thunk);
|
||||
CodeGenFunction(CGM).generateThunk(ThunkFn, FnInfo, GD, Thunk);
|
||||
}
|
||||
|
||||
CGM.setFunctionLinkage(GD, ThunkFn);
|
||||
CGM.getCXXABI().setThunkLinkage(ThunkFn, ForVTable, GD,
|
||||
!Thunk.Return.isEmpty());
|
||||
|
||||
// Set the right visibility.
|
||||
const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
|
||||
setThunkVisibility(CGM, MD, Thunk, ThunkFn);
|
||||
|
||||
if (CGM.supportsCOMDAT() && ThunkFn->isWeakForLinker())
|
||||
ThunkFn->setComdat(CGM.getModule().getOrInsertComdat(ThunkFn->getName()));
|
||||
}
|
||||
@ -841,6 +840,11 @@ void CodeGenModule::EmitDeferredVTables() {
|
||||
DeferredVTables.clear();
|
||||
}
|
||||
|
||||
bool CodeGenModule::IsCFIBlacklistedRecord(const CXXRecordDecl *RD) {
|
||||
// FIXME: Make this user configurable.
|
||||
return RD->isInStdNamespace();
|
||||
}
|
||||
|
||||
void CodeGenModule::EmitVTableBitSetEntries(llvm::GlobalVariable *VTable,
|
||||
const VTableLayout &VTLayout) {
|
||||
if (!LangOpts.Sanitize.has(SanitizerKind::CFIVCall) &&
|
||||
@ -855,8 +859,7 @@ void CodeGenModule::EmitVTableBitSetEntries(llvm::GlobalVariable *VTable,
|
||||
std::vector<llvm::MDTuple *> BitsetEntries;
|
||||
// Create a bit set entry for each address point.
|
||||
for (auto &&AP : VTLayout.getAddressPoints()) {
|
||||
// FIXME: Add blacklisting scheme.
|
||||
if (AP.first.getBase()->isInStdNamespace())
|
||||
if (IsCFIBlacklistedRecord(AP.first.getBase()))
|
||||
continue;
|
||||
|
||||
BitsetEntries.push_back(CreateVTableBitSetEntry(
|
||||
|
@ -10,6 +10,7 @@ set(LLVM_LINK_COMPONENTS
|
||||
Linker
|
||||
MC
|
||||
ObjCARCOpts
|
||||
Object
|
||||
ProfileData
|
||||
ScalarOpts
|
||||
Support
|
||||
@ -71,6 +72,7 @@ add_clang_library(clangCodeGen
|
||||
ItaniumCXXABI.cpp
|
||||
MicrosoftCXXABI.cpp
|
||||
ModuleBuilder.cpp
|
||||
ObjectFilePCHContainerOperations.cpp
|
||||
SanitizerMetadata.cpp
|
||||
TargetInfo.cpp
|
||||
|
||||
|
@ -45,12 +45,12 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm, bool suppressNewContext)
|
||||
LambdaThisCaptureField(nullptr), NormalCleanupDest(nullptr),
|
||||
NextCleanupDestIndex(1), FirstBlockInfo(nullptr), EHResumeBlock(nullptr),
|
||||
ExceptionSlot(nullptr), EHSelectorSlot(nullptr),
|
||||
AbnormalTerminationSlot(nullptr), SEHPointersDecl(nullptr),
|
||||
DebugInfo(CGM.getModuleDebugInfo()), DisableDebugInfo(false),
|
||||
DidCallStackSave(false), IndirectBranch(nullptr), PGO(cgm),
|
||||
SwitchInsn(nullptr), SwitchWeights(nullptr), CaseRangeBlock(nullptr),
|
||||
UnreachableBlock(nullptr), NumReturnExprs(0), NumSimpleReturnExprs(0),
|
||||
CXXABIThisDecl(nullptr), CXXABIThisValue(nullptr), CXXThisValue(nullptr),
|
||||
DebugInfo(CGM.getModuleDebugInfo()),
|
||||
DisableDebugInfo(false), DidCallStackSave(false), IndirectBranch(nullptr),
|
||||
PGO(cgm), SwitchInsn(nullptr), SwitchWeights(nullptr),
|
||||
CaseRangeBlock(nullptr), UnreachableBlock(nullptr), NumReturnExprs(0),
|
||||
NumSimpleReturnExprs(0), CXXABIThisDecl(nullptr),
|
||||
CXXABIThisValue(nullptr), CXXThisValue(nullptr),
|
||||
CXXDefaultInitExprThis(nullptr), CXXStructorImplicitParamDecl(nullptr),
|
||||
CXXStructorImplicitParamValue(nullptr), OutermostConditional(nullptr),
|
||||
CurLexicalScope(nullptr), TerminateLandingPad(nullptr),
|
||||
@ -284,7 +284,7 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) {
|
||||
Builder.ClearInsertionPoint();
|
||||
}
|
||||
|
||||
// If some of our locals escaped, insert a call to llvm.frameescape in the
|
||||
// If some of our locals escaped, insert a call to llvm.localescape in the
|
||||
// entry block.
|
||||
if (!EscapedLocals.empty()) {
|
||||
// Invert the map from local to index into a simple vector. There should be
|
||||
@ -294,7 +294,7 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) {
|
||||
for (auto &Pair : EscapedLocals)
|
||||
EscapeArgs[Pair.second] = Pair.first;
|
||||
llvm::Function *FrameEscapeFn = llvm::Intrinsic::getDeclaration(
|
||||
&CGM.getModule(), llvm::Intrinsic::frameescape);
|
||||
&CGM.getModule(), llvm::Intrinsic::localescape);
|
||||
CGBuilderTy(AllocaInsertPt).CreateCall(FrameEscapeFn, EscapeArgs);
|
||||
}
|
||||
|
||||
|
@ -324,11 +324,13 @@ class CodeGenFunction : public CodeGenTypeCache {
|
||||
/// write the current selector value into this alloca.
|
||||
llvm::AllocaInst *EHSelectorSlot;
|
||||
|
||||
llvm::AllocaInst *AbnormalTerminationSlot;
|
||||
/// A stack of exception code slots. Entering an __except block pushes a slot
|
||||
/// on the stack and leaving pops one. The __exception_code() intrinsic loads
|
||||
/// a value from the top of the stack.
|
||||
SmallVector<llvm::Value *, 1> SEHCodeSlotStack;
|
||||
|
||||
/// The implicit parameter to SEH filter functions of type
|
||||
/// 'EXCEPTION_POINTERS*'.
|
||||
ImplicitParamDecl *SEHPointersDecl;
|
||||
/// Value returned by __exception_info intrinsic.
|
||||
llvm::Value *SEHInfo = nullptr;
|
||||
|
||||
/// Emits a landing pad for the current EH stack.
|
||||
llvm::BasicBlock *EmitLandingPad();
|
||||
@ -886,7 +888,7 @@ class CodeGenFunction : public CodeGenTypeCache {
|
||||
DeclMapTy LocalDeclMap;
|
||||
|
||||
/// Track escaped local variables with auto storage. Used during SEH
|
||||
/// outlining to produce a call to llvm.frameescape.
|
||||
/// outlining to produce a call to llvm.localescape.
|
||||
llvm::DenseMap<llvm::AllocaInst *, int> EscapedLocals;
|
||||
|
||||
/// LabelMap - This keeps track of the LLVM basic block for each C label.
|
||||
@ -1292,8 +1294,8 @@ class CodeGenFunction : public CodeGenTypeCache {
|
||||
void EmitMustTailThunk(const CXXMethodDecl *MD, llvm::Value *AdjustedThisPtr,
|
||||
llvm::Value *Callee);
|
||||
|
||||
/// GenerateThunk - Generate a thunk for the given method.
|
||||
void GenerateThunk(llvm::Function *Fn, const CGFunctionInfo &FnInfo,
|
||||
/// Generate a thunk for the given method.
|
||||
void generateThunk(llvm::Function *Fn, const CGFunctionInfo &FnInfo,
|
||||
GlobalDecl GD, const ThunkInfo &Thunk);
|
||||
|
||||
llvm::Function *GenerateVarArgsThunk(llvm::Function *Fn,
|
||||
@ -2048,8 +2050,7 @@ class CodeGenFunction : public CodeGenTypeCache {
|
||||
void EnterSEHTryStmt(const SEHTryStmt &S);
|
||||
void ExitSEHTryStmt(const SEHTryStmt &S);
|
||||
|
||||
void startOutlinedSEHHelper(CodeGenFunction &ParentCGF, StringRef Name,
|
||||
QualType RetTy, FunctionArgList &Args,
|
||||
void startOutlinedSEHHelper(CodeGenFunction &ParentCGF, bool IsFilter,
|
||||
const Stmt *OutlinedStmt);
|
||||
|
||||
llvm::Function *GenerateSEHFilterFunction(CodeGenFunction &ParentCGF,
|
||||
@ -2058,16 +2059,27 @@ class CodeGenFunction : public CodeGenTypeCache {
|
||||
llvm::Function *GenerateSEHFinallyFunction(CodeGenFunction &ParentCGF,
|
||||
const SEHFinallyStmt &Finally);
|
||||
|
||||
void EmitSEHExceptionCodeSave();
|
||||
void EmitSEHExceptionCodeSave(CodeGenFunction &ParentCGF,
|
||||
llvm::Value *ParentFP,
|
||||
llvm::Value *EntryEBP);
|
||||
llvm::Value *EmitSEHExceptionCode();
|
||||
llvm::Value *EmitSEHExceptionInfo();
|
||||
llvm::Value *EmitSEHAbnormalTermination();
|
||||
|
||||
/// Scan the outlined statement for captures from the parent function. For
|
||||
/// each capture, mark the capture as escaped and emit a call to
|
||||
/// llvm.framerecover. Insert the framerecover result into the LocalDeclMap.
|
||||
/// llvm.localrecover. Insert the localrecover result into the LocalDeclMap.
|
||||
void EmitCapturedLocals(CodeGenFunction &ParentCGF, const Stmt *OutlinedStmt,
|
||||
llvm::Value *ParentFP);
|
||||
bool IsFilter);
|
||||
|
||||
/// Recovers the address of a local in a parent function. ParentVar is the
|
||||
/// address of the variable used in the immediate parent function. It can
|
||||
/// either be an alloca or a call to llvm.localrecover if there are nested
|
||||
/// outlined functions. ParentFP is the frame pointer of the outermost parent
|
||||
/// frame.
|
||||
llvm::Value *recoverAddrOfEscapedLocal(CodeGenFunction &ParentCGF,
|
||||
llvm::Value *ParentVar,
|
||||
llvm::Value *ParentFP);
|
||||
|
||||
void EmitCXXForRangeStmt(const CXXForRangeStmt &S,
|
||||
ArrayRef<const Attr *> Attrs = None);
|
||||
@ -2931,6 +2943,26 @@ class CodeGenFunction : public CodeGenTypeCache {
|
||||
SourceLocation Loc);
|
||||
|
||||
public:
|
||||
#ifndef NDEBUG
|
||||
// Determine whether the given argument is an Objective-C method
|
||||
// that may have type parameters in its signature.
|
||||
static bool isObjCMethodWithTypeParams(const ObjCMethodDecl *method) {
|
||||
const DeclContext *dc = method->getDeclContext();
|
||||
if (const ObjCInterfaceDecl *classDecl= dyn_cast<ObjCInterfaceDecl>(dc)) {
|
||||
return classDecl->getTypeParamListAsWritten();
|
||||
}
|
||||
|
||||
if (const ObjCCategoryDecl *catDecl = dyn_cast<ObjCCategoryDecl>(dc)) {
|
||||
return catDecl->getTypeParamList();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static bool isObjCMethodWithTypeParams(const T *) { return false; }
|
||||
#endif
|
||||
|
||||
/// EmitCallArgs - Emit call arguments for a function.
|
||||
template <typename T>
|
||||
void EmitCallArgs(CallArgList &Args, const T *CallArgTypeInfo,
|
||||
@ -2944,18 +2976,25 @@ class CodeGenFunction : public CodeGenTypeCache {
|
||||
assert((ParamsToSkip == 0 || CallArgTypeInfo) &&
|
||||
"Can't skip parameters if type info is not provided");
|
||||
if (CallArgTypeInfo) {
|
||||
#ifndef NDEBUG
|
||||
bool isGenericMethod = isObjCMethodWithTypeParams(CallArgTypeInfo);
|
||||
#endif
|
||||
|
||||
// First, use the argument types that the type info knows about
|
||||
for (auto I = CallArgTypeInfo->param_type_begin() + ParamsToSkip,
|
||||
E = CallArgTypeInfo->param_type_end();
|
||||
I != E; ++I, ++Arg) {
|
||||
assert(Arg != ArgEnd && "Running over edge of argument list!");
|
||||
assert(
|
||||
((*I)->isVariablyModifiedType() ||
|
||||
getContext()
|
||||
.getCanonicalType((*I).getNonReferenceType())
|
||||
.getTypePtr() ==
|
||||
getContext().getCanonicalType(Arg->getType()).getTypePtr()) &&
|
||||
"type mismatch in call argument!");
|
||||
assert((isGenericMethod ||
|
||||
((*I)->isVariablyModifiedType() ||
|
||||
(*I).getNonReferenceType()->isObjCRetainableType() ||
|
||||
getContext()
|
||||
.getCanonicalType((*I).getNonReferenceType())
|
||||
.getTypePtr() ==
|
||||
getContext()
|
||||
.getCanonicalType(Arg->getType())
|
||||
.getTypePtr())) &&
|
||||
"type mismatch in call argument!");
|
||||
ArgTypes.push_back(*I);
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user