am 59b46b6b: am 21d56592: (-s ours) Cleaner way to create symlink clang++
* commit '59b46b6b8a0aba0120569f096b056f0ccf8e686c':
Cleaner way to create symlink clang++
diff --git a/Android.mk b/Android.mk
index d5495b3..4120a7c 100644
--- a/Android.mk
+++ b/Android.mk
@@ -1,5 +1,6 @@
LOCAL_PATH := $(call my-dir)
CLANG_ROOT_PATH := $(LOCAL_PATH)
+CLANG_ENABLE_ASSERTION := false
include $(CLEAR_VARS)
diff --git a/CODE_OWNERS.TXT b/CODE_OWNERS.TXT
index 96c9d03..3499093 100644
--- a/CODE_OWNERS.TXT
+++ b/CODE_OWNERS.TXT
@@ -23,7 +23,7 @@
N: Doug Gregor
E: dgregor@apple.com
-D: All parts of Clang not covered by someone else
+D: Emeritus owner
N: Reid Kleckner
E: rnk@google.com
@@ -47,4 +47,4 @@
N: Richard Smith
E: richard@metafoo.co.uk
-D: Clang Semantic Analysis (tools/clang/lib/Sema/* tools/clang/include/clang/Sema/*)
+D: All parts of Clang not covered by someone else
diff --git a/bindings/python/clang/cindex.py b/bindings/python/clang/cindex.py
index 5792eff..f5caca8 100644
--- a/bindings/python/clang/cindex.py
+++ b/bindings/python/clang/cindex.py
@@ -1476,6 +1476,18 @@
"""
return TokenGroup.get_tokens(self._tu, self.extent)
+ def get_field_offsetof(self):
+ """Returns the offsetof the FIELD_DECL pointed by this Cursor."""
+ return conf.lib.clang_Cursor_getOffsetOfField(self)
+
+ def is_anonymous(self):
+ """
+ Check if the record is anonymous.
+ """
+ if self.kind == CursorKind.FIELD_DECL:
+ return self.type.get_declaration().is_anonymous()
+ return conf.lib.clang_Cursor_isAnonymous(self)
+
def is_bitfield(self):
"""
Check if the field is a bitfield.
@@ -1884,6 +1896,21 @@
return RefQualifierKind.from_id(
conf.lib.clang_Type_getCXXRefQualifier(self))
+ def get_fields(self):
+ """Return an iterator for accessing the fields of this type."""
+
+ def visitor(field, children):
+ assert field != conf.lib.clang_getNullCursor()
+
+ # Create reference to TU so it isn't GC'd before Cursor.
+ field._tu = self._tu
+ fields.append(field)
+ return 1 # continue
+ fields = []
+ conf.lib.clang_Type_visitFields(self,
+ callbacks['fields_visit'](visitor), fields)
+ return iter(fields)
+
@property
def spelling(self):
"""Retrieve the spelling of this Type."""
@@ -2780,6 +2807,7 @@
callbacks['translation_unit_includes'] = CFUNCTYPE(None, c_object_p,
POINTER(SourceLocation), c_uint, py_object)
callbacks['cursor_visit'] = CFUNCTYPE(c_int, Cursor, Cursor, py_object)
+callbacks['fields_visit'] = CFUNCTYPE(c_int, Cursor, py_object)
# Functions strictly alphabetical order.
functionList = [
@@ -3367,6 +3395,10 @@
[Cursor, c_uint],
c_ulonglong),
+ ("clang_Cursor_isAnonymous",
+ [Cursor],
+ bool),
+
("clang_Cursor_isBitField",
[Cursor],
bool),
@@ -3381,6 +3413,10 @@
_CXString,
_CXString.from_result),
+ ("clang_Cursor_getOffsetOfField",
+ [Cursor],
+ c_longlong),
+
("clang_Type_getAlignOf",
[Type],
c_longlong),
@@ -3401,6 +3437,10 @@
("clang_Type_getCXXRefQualifier",
[Type],
c_uint),
+
+ ("clang_Type_visitFields",
+ [Type, callbacks['fields_visit'], py_object],
+ c_uint),
]
class LibclangError(Exception):
diff --git a/bindings/python/tests/cindex/test_type.py b/bindings/python/tests/cindex/test_type.py
index a02c06f..f3dadf9 100644
--- a/bindings/python/tests/cindex/test_type.py
+++ b/bindings/python/tests/cindex/test_type.py
@@ -363,6 +363,7 @@
"""Ensure Cursor.get_record_field_offset works in anonymous records"""
source="""
struct Test {
+ struct {int a;} typeanon;
struct {
int bariton;
union {
@@ -371,15 +372,23 @@
};
int bar;
};"""
- tries=[(['-target','i386-linux-gnu'],(4,16,0,32,64)),
- (['-target','nvptx64-unknown-unknown'],(8,24,0,32,64)),
- (['-target','i386-pc-win32'],(8,16,0,32,64)),
- (['-target','msp430-none-none'],(2,14,0,32,64))]
+ tries=[(['-target','i386-linux-gnu'],(4,16,0,32,64,96)),
+ (['-target','nvptx64-unknown-unknown'],(8,24,0,32,64,96)),
+ (['-target','i386-pc-win32'],(8,16,0,32,64,96)),
+ (['-target','msp430-none-none'],(2,14,0,32,64,96))]
for flags, values in tries:
- align,total,bariton,foo,bar = values
+ align,total,f1,bariton,foo,bar = values
tu = get_tu(source)
teststruct = get_cursor(tu, 'Test')
- fields = list(teststruct.get_children())
+ children = list(teststruct.get_children())
+ fields = list(teststruct.type.get_fields())
+ assert children[0].kind == CursorKind.STRUCT_DECL
+ assert children[0].spelling != "typeanon"
+ assert children[1].spelling == "typeanon"
+ assert fields[0].kind == CursorKind.FIELD_DECL
+ assert fields[1].kind == CursorKind.FIELD_DECL
+ assert fields[1].is_anonymous()
+ assert teststruct.type.get_offset("typeanon") == f1
assert teststruct.type.get_offset("bariton") == bariton
assert teststruct.type.get_offset("foo") == foo
assert teststruct.type.get_offset("bar") == bar
diff --git a/clang-device-build.mk b/clang-device-build.mk
index 0bd088e..28c7916 100644
--- a/clang-device-build.mk
+++ b/clang-device-build.mk
@@ -8,6 +8,13 @@
-Wno-sign-promo \
$(LOCAL_CPPFLAGS)
+ifeq ($(CLANG_ENABLE_ASSERTION),true)
+LOCAL_CFLAGS := \
+ $(LOCAL_CFLAGS) \
+ -D_DEBUG \
+ -UNDEBUG
+endif
+
# Make sure bionic is first so we can include system headers.
LOCAL_C_INCLUDES := \
$(CLANG_ROOT_PATH)/include \
diff --git a/clang-host-build.mk b/clang-host-build.mk
index 81e9b1e..3594cc4 100644
--- a/clang-host-build.mk
+++ b/clang-host-build.mk
@@ -8,6 +8,13 @@
-Wno-sign-promo \
$(LOCAL_CPPFLAGS)
+ifeq ($(CLANG_ENABLE_ASSERTION),true)
+LOCAL_CFLAGS := \
+ $(LOCAL_CFLAGS) \
+ -D_DEBUG \
+ -UNDEBUG
+endif
+
# Make sure bionic is first so we can include system headers.
LOCAL_C_INCLUDES := \
$(CLANG_ROOT_PATH)/include \
diff --git a/docs/ControlFlowIntegrity.rst b/docs/ControlFlowIntegrity.rst
index 51c9917..915385b 100644
--- a/docs/ControlFlowIntegrity.rst
+++ b/docs/ControlFlowIntegrity.rst
@@ -27,8 +27,8 @@
with CFI enabled, and are statically linked into the program. This may
preclude the use of shared libraries in some cases.
-Clang currently implements forward-edge CFI for virtual calls. More schemes
-are under development.
+Clang currently implements forward-edge CFI for member function calls and
+bad cast checking. More schemes are under development.
.. _gold plugin: http://llvm.org/docs/GoldPlugin.html
@@ -38,11 +38,11 @@
This scheme checks that virtual calls take place using a vptr of the correct
dynamic type; that is, the dynamic type of the called object must be a
derived class of the static type of the object used to make the call.
-This CFI scheme can be enabled on its own using ``-fsanitize=cfi-vptr``.
+This CFI scheme can be enabled on its own using ``-fsanitize=cfi-vcall``.
For this scheme to work, all translation units containing the definition
of a virtual member function (whether inline or not) must be compiled
-with ``-fsanitize=cfi-vptr`` enabled and be statically linked into the
+with ``-fsanitize=cfi-vcall`` enabled and be statically linked into the
program. Classes in the C++ standard library (under namespace ``std``) are
exempted from checking, and therefore programs may be linked against a
pre-built standard library, but this may change in the future.
@@ -95,6 +95,23 @@
may be linked against a pre-built standard library, but this may change in
the future.
+Non-Virtual Member Function Call Checking
+-----------------------------------------
+
+This scheme checks that non-virtual calls take place using an object of
+the correct dynamic type; that is, the dynamic type of the called object
+must be a derived class of the static type of the object used to make the
+call. The checks are currently only introduced where the object is of a
+polymorphic class type. This CFI scheme can be enabled on its own using
+``-fsanitize=cfi-nvcall``.
+
+For this scheme to work, all translation units containing the definition
+of a virtual member function (whether inline or not) must be compiled
+with ``-fsanitize=cfi-nvcall`` enabled and be statically linked into the
+program. Classes in the C++ standard library (under namespace ``std``) are
+exempted from checking, and therefore programs may be linked against a
+pre-built standard library, but this may change in the future.
+
.. _cfi-strictness:
Strictness
diff --git a/docs/UsersManual.rst b/docs/UsersManual.rst
index 29c4d4e..bf8ce78 100644
--- a/docs/UsersManual.rst
+++ b/docs/UsersManual.rst
@@ -974,7 +974,9 @@
dynamic type. Implies ``-flto``.
- ``-fsanitize=cfi-unrelated-cast``: Cast from ``void*`` or another
unrelated type to the wrong dynamic type. Implies ``-flto``.
- - ``-fsanitize=cfi-vptr``: Use of an object whose vptr is of the
+ - ``-fsanitize=cfi-nvcall``: Non-virtual call via an object whose vptr is of
+ the wrong dynamic type. Implies ``-flto``.
+ - ``-fsanitize=cfi-vcall``: Virtual call via an object whose vptr is of the
wrong dynamic type. Implies ``-flto``.
- ``-fsanitize=enum``: Load of a value of an enumerated type which
is not in the range of representable values for that enumerated
diff --git a/examples/PrintFunctionNames/PrintFunctionNames.cpp b/examples/PrintFunctionNames/PrintFunctionNames.cpp
index b554cae..39443f5 100644
--- a/examples/PrintFunctionNames/PrintFunctionNames.cpp
+++ b/examples/PrintFunctionNames/PrintFunctionNames.cpp
@@ -23,7 +23,7 @@
class PrintFunctionsConsumer : public ASTConsumer {
public:
- virtual bool HandleTopLevelDecl(DeclGroupRef DG) {
+ bool HandleTopLevelDecl(DeclGroupRef DG) override {
for (DeclGroupRef::iterator i = DG.begin(), e = DG.end(); i != e; ++i) {
const Decl *D = *i;
if (const NamedDecl *ND = dyn_cast<NamedDecl>(D))
@@ -37,12 +37,12 @@
class PrintFunctionNamesAction : public PluginASTAction {
protected:
std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
- llvm::StringRef) {
+ llvm::StringRef) override {
return llvm::make_unique<PrintFunctionsConsumer>();
}
bool ParseArgs(const CompilerInstance &CI,
- const std::vector<std::string>& args) {
+ const std::vector<std::string> &args) override {
for (unsigned i = 0, e = args.size(); i != e; ++i) {
llvm::errs() << "PrintFunctionNames arg = " << args[i] << "\n";
diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h
index ac8ce1c..693eef2 100644
--- a/include/clang-c/Index.h
+++ b/include/clang-c/Index.h
@@ -32,7 +32,7 @@
* compatible, thus CINDEX_VERSION_MAJOR is expected to remain stable.
*/
#define CINDEX_VERSION_MAJOR 0
-#define CINDEX_VERSION_MINOR 29
+#define CINDEX_VERSION_MINOR 30
#define CINDEX_VERSION_ENCODE(major, minor) ( \
((major) * 10000) \
@@ -3281,6 +3281,28 @@
*/
CINDEX_LINKAGE long long clang_Type_getOffsetOf(CXType T, const char *S);
+/**
+ * \brief Return the offset of the field represented by the Cursor.
+ *
+ * If the cursor is not a field declaration, -1 is returned.
+ * If the cursor semantic parent is not a record field declaration,
+ * CXTypeLayoutError_Invalid is returned.
+ * If the field's type declaration is an incomplete type,
+ * CXTypeLayoutError_Incomplete is returned.
+ * If the field's type declaration is a dependent type,
+ * CXTypeLayoutError_Dependent is returned.
+ * If the field's name S is not found,
+ * CXTypeLayoutError_InvalidFieldName is returned.
+ */
+CINDEX_LINKAGE long long clang_Cursor_getOffsetOfField(CXCursor C);
+
+/**
+ * \brief Determine whether the given cursor represents an anonymous record
+ * declaration.
+ */
+CINDEX_LINKAGE unsigned clang_Cursor_isAnonymous(CXCursor C);
+
+
enum CXRefQualifierKind {
/** \brief No ref-qualifier was provided. */
CXRefQualifier_None = 0,
@@ -5669,6 +5691,44 @@
CXSourceLocation clang_indexLoc_getCXSourceLocation(CXIdxLoc loc);
/**
+ * \brief Visitor invoked for each field found by a traversal.
+ *
+ * This visitor function will be invoked for each field found by
+ * \c clang_Type_visitFields. Its first argument is the cursor being
+ * visited, its second argument is the client data provided to
+ * \c clang_Type_visitFields.
+ *
+ * The visitor should return one of the \c CXVisitorResult values
+ * to direct \c clang_Type_visitFields.
+ */
+typedef enum CXVisitorResult (*CXFieldVisitor)(CXCursor C,
+ CXClientData client_data);
+
+/**
+ * \brief Visit the fields of a particular type.
+ *
+ * This function visits all the direct fields of the given cursor,
+ * invoking the given \p visitor function with the cursors of each
+ * visited field. The traversal may be ended prematurely, if
+ * the visitor returns \c CXFieldVisit_Break.
+ *
+ * \param T the record type whose field may be visited.
+ *
+ * \param visitor the visitor function that will be invoked for each
+ * field of \p T.
+ *
+ * \param client_data pointer data supplied by the client, which will
+ * be passed to the visitor each time it is invoked.
+ *
+ * \returns a non-zero value if the traversal was terminated
+ * prematurely by the visitor returning \c CXFieldVisit_Break.
+ */
+CINDEX_LINKAGE unsigned clang_Type_visitFields(CXType T,
+ CXFieldVisitor visitor,
+ CXClientData client_data);
+
+
+/**
* @}
*/
diff --git a/include/clang/AST/Attr.h b/include/clang/AST/Attr.h
index c3e7f2a..a854168 100644
--- a/include/clang/AST/Attr.h
+++ b/include/clang/AST/Attr.h
@@ -65,7 +65,7 @@
public:
// Forward so that the regular new and delete do not hide global ones.
void* operator new(size_t Bytes, ASTContext &C,
- size_t Alignment = 16) throw() {
+ size_t Alignment = 8) throw() {
return ::operator new(Bytes, C, Alignment);
}
void operator delete(void *Ptr, ASTContext &C,
diff --git a/include/clang/AST/AttrIterator.h b/include/clang/AST/AttrIterator.h
index 39ee81f..a0c8030 100644
--- a/include/clang/AST/AttrIterator.h
+++ b/include/clang/AST/AttrIterator.h
@@ -24,7 +24,7 @@
// Defined in ASTContext.h
void *operator new(size_t Bytes, const clang::ASTContext &C,
- size_t Alignment = 16);
+ size_t Alignment = 8);
// FIXME: Being forced to not have a default argument here due to redeclaration
// rules on default arguments sucks
void *operator new[](size_t Bytes, const clang::ASTContext &C,
diff --git a/include/clang/AST/DataRecursiveASTVisitor.h b/include/clang/AST/DataRecursiveASTVisitor.h
index 46d2f86..d3dde68 100644
--- a/include/clang/AST/DataRecursiveASTVisitor.h
+++ b/include/clang/AST/DataRecursiveASTVisitor.h
@@ -2519,6 +2519,18 @@
bool RecursiveASTVisitor<Derived>::VisitOMPLastprivateClause(
OMPLastprivateClause *C) {
TRY_TO(VisitOMPClauseList(C));
+ for (auto *E : C->private_copies()) {
+ TRY_TO(TraverseStmt(E));
+ }
+ for (auto *E : C->source_exprs()) {
+ TRY_TO(TraverseStmt(E));
+ }
+ for (auto *E : C->destination_exprs()) {
+ TRY_TO(TraverseStmt(E));
+ }
+ for (auto *E : C->assignment_ops()) {
+ TRY_TO(TraverseStmt(E));
+ }
return true;
}
@@ -2555,6 +2567,15 @@
template <typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPCopyinClause(OMPCopyinClause *C) {
TRY_TO(VisitOMPClauseList(C));
+ for (auto *E : C->source_exprs()) {
+ TRY_TO(TraverseStmt(E));
+ }
+ for (auto *E : C->destination_exprs()) {
+ TRY_TO(TraverseStmt(E));
+ }
+ for (auto *E : C->assignment_ops()) {
+ TRY_TO(TraverseStmt(E));
+ }
return true;
}
@@ -2580,6 +2601,15 @@
TRY_TO(TraverseNestedNameSpecifierLoc(C->getQualifierLoc()));
TRY_TO(TraverseDeclarationNameInfo(C->getNameInfo()));
TRY_TO(VisitOMPClauseList(C));
+ for (auto *E : C->lhs_exprs()) {
+ TRY_TO(TraverseStmt(E));
+ }
+ for (auto *E : C->rhs_exprs()) {
+ TRY_TO(TraverseStmt(E));
+ }
+ for (auto *E : C->reduction_ops()) {
+ TRY_TO(TraverseStmt(E));
+ }
return true;
}
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index 3e3d79f..f8e1726 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -1965,6 +1965,13 @@
return getType()->getAs<FunctionType>()->getCallResultType(getASTContext());
}
+ /// \brief Returns true if this function or its return type has the
+ /// warn_unused_result attribute. If the return type has the attribute and
+ /// this function is a method of the return type's class, then false will be
+ /// returned to avoid spurious warnings on member methods such as assignment
+ /// operators.
+ bool hasUnusedResultAttr() const;
+
/// \brief Returns the storage class as written in the source. For the
/// computed linkage of symbol, see getLinkage.
StorageClass getStorageClass() const { return StorageClass(SClass); }
diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h
index 39b5208..90cfb20 100644
--- a/include/clang/AST/DeclTemplate.h
+++ b/include/clang/AST/DeclTemplate.h
@@ -314,7 +314,7 @@
/// \brief The function template from which this function template
/// specialization was generated.
///
- /// The two bits are contain the top 4 values of TemplateSpecializationKind.
+ /// The two bits contain the top 4 values of TemplateSpecializationKind.
llvm::PointerIntPair<FunctionTemplateDecl *, 2> Template;
/// \brief The template arguments used to produce the function template
diff --git a/include/clang/AST/Mangle.h b/include/clang/AST/Mangle.h
index 23dde6b..1050e65 100644
--- a/include/clang/AST/Mangle.h
+++ b/include/clang/AST/Mangle.h
@@ -135,6 +135,9 @@
virtual void mangleSEHFilterExpression(const NamedDecl *EnclosingDecl,
raw_ostream &Out) = 0;
+ virtual void mangleSEHFinallyBlock(const NamedDecl *EnclosingDecl,
+ raw_ostream &Out) = 0;
+
/// Generates a unique string for an externally visible type for use with TBAA
/// or type uniquing.
/// TODO: Extend this to internal types by generating names that are unique
@@ -208,9 +211,8 @@
uint32_t NVOffset, int32_t VBPtrOffset,
uint32_t VBIndex, raw_ostream &Out) = 0;
- virtual void mangleCXXHandlerMapEntry(QualType T, bool IsConst,
- bool IsVolatile, bool IsReference,
- raw_ostream &Out) = 0;
+ virtual void mangleCXXCatchHandlerType(QualType T, uint32_t Flags,
+ raw_ostream &Out) = 0;
virtual void mangleCXXRTTIBaseClassDescriptor(
const CXXRecordDecl *Derived, uint32_t NVOffset, int32_t VBPtrOffset,
diff --git a/include/clang/AST/OpenMPClause.h b/include/clang/AST/OpenMPClause.h
index 5afe3e5..580fcea 100644
--- a/include/clang/AST/OpenMPClause.h
+++ b/include/clang/AST/OpenMPClause.h
@@ -1137,8 +1137,26 @@
/// \endcode
/// In this example directive '#pragma omp simd' has clause 'lastprivate'
/// with the variables 'a' and 'b'.
-///
class OMPLastprivateClause : public OMPVarListClause<OMPLastprivateClause> {
+ // There are 4 additional tail-allocated arrays at the end of the class:
+ // 1. Contains list of pseudo variables with the default initialization for
+ // each non-firstprivate variables. Used in codegen for initialization of
+ // lastprivate copies.
+ // 2. List of helper expressions for proper generation of assignment operation
+ // required for lastprivate clause. This list represents private variables
+ // (for arrays, single array element).
+ // 3. List of helper expressions for proper generation of assignment operation
+ // required for lastprivate clause. This list represents original variables
+ // (for arrays, single array element).
+ // 4. List of helper expressions that represents assignment operation:
+ // \code
+ // DstExprs = SrcExprs;
+ // \endcode
+ // Required for proper codegen of final assignment performed by the
+ // lastprivate clause.
+ //
+ friend class OMPClauseReader;
+
/// \brief Build clause with number of variables \a N.
///
/// \param StartLoc Starting location of the clause.
@@ -1160,6 +1178,56 @@
OMPC_lastprivate, SourceLocation(), SourceLocation(),
SourceLocation(), N) {}
+ /// \brief Get the list of helper expressions for initialization of private
+ /// copies for lastprivate variables.
+ MutableArrayRef<Expr *> getPrivateCopies() {
+ return MutableArrayRef<Expr *>(varlist_end(), varlist_size());
+ }
+ ArrayRef<const Expr *> getPrivateCopies() const {
+ return llvm::makeArrayRef(varlist_end(), varlist_size());
+ }
+
+ /// \brief Set list of helper expressions, required for proper codegen of the
+ /// clause. These expressions represent private variables (for arrays, single
+ /// array element) in the final assignment statement performed by the
+ /// lastprivate clause.
+ void setSourceExprs(ArrayRef<Expr *> SrcExprs);
+
+ /// \brief Get the list of helper source expressions.
+ MutableArrayRef<Expr *> getSourceExprs() {
+ return MutableArrayRef<Expr *>(getPrivateCopies().end(), varlist_size());
+ }
+ ArrayRef<const Expr *> getSourceExprs() const {
+ return llvm::makeArrayRef(getPrivateCopies().end(), varlist_size());
+ }
+
+ /// \brief Set list of helper expressions, required for proper codegen of the
+ /// clause. These expressions represent original variables (for arrays, single
+ /// array element) in the final assignment statement performed by the
+ /// lastprivate clause.
+ void setDestinationExprs(ArrayRef<Expr *> DstExprs);
+
+ /// \brief Get the list of helper destination expressions.
+ MutableArrayRef<Expr *> getDestinationExprs() {
+ return MutableArrayRef<Expr *>(getSourceExprs().end(), varlist_size());
+ }
+ ArrayRef<const Expr *> getDestinationExprs() const {
+ return llvm::makeArrayRef(getSourceExprs().end(), varlist_size());
+ }
+
+ /// \brief Set list of helper assignment expressions, required for proper
+ /// codegen of the clause. These expressions are assignment expressions that
+ /// assign private copy of the variable to original variable.
+ void setAssignmentOps(ArrayRef<Expr *> AssignmentOps);
+
+ /// \brief Get the list of helper assignment expressions.
+ MutableArrayRef<Expr *> getAssignmentOps() {
+ return MutableArrayRef<Expr *>(getDestinationExprs().end(), varlist_size());
+ }
+ ArrayRef<const Expr *> getAssignmentOps() const {
+ return llvm::makeArrayRef(getDestinationExprs().end(), varlist_size());
+ }
+
public:
/// \brief Creates clause with a list of variables \a VL.
///
@@ -1168,10 +1236,25 @@
/// \param LParenLoc Location of '('.
/// \param EndLoc Ending location of the clause.
/// \param VL List of references to the variables.
+ /// \param SrcExprs List of helper expressions for proper generation of
+ /// assignment operation required for lastprivate clause. This list represents
+ /// private variables (for arrays, single array element).
+ /// \param DstExprs List of helper expressions for proper generation of
+ /// assignment operation required for lastprivate clause. This list represents
+ /// original variables (for arrays, single array element).
+ /// \param AssignmentOps List of helper expressions that represents assignment
+ /// operation:
+ /// \code
+ /// DstExprs = SrcExprs;
+ /// \endcode
+ /// Required for proper codegen of final assignment performed by the
+ /// lastprivate clause.
+ ///
///
static OMPLastprivateClause *
Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc,
- SourceLocation EndLoc, ArrayRef<Expr *> VL);
+ SourceLocation EndLoc, ArrayRef<Expr *> VL, ArrayRef<Expr *> SrcExprs,
+ ArrayRef<Expr *> DstExprs, ArrayRef<Expr *> AssignmentOps);
/// \brief Creates an empty clause with the place for \a N variables.
///
/// \param C AST context.
@@ -1179,6 +1262,48 @@
///
static OMPLastprivateClause *CreateEmpty(const ASTContext &C, unsigned N);
+ typedef MutableArrayRef<Expr *>::iterator helper_expr_iterator;
+ typedef ArrayRef<const Expr *>::iterator helper_expr_const_iterator;
+ typedef llvm::iterator_range<helper_expr_iterator> helper_expr_range;
+ typedef llvm::iterator_range<helper_expr_const_iterator>
+ helper_expr_const_range;
+
+ /// \brief Set list of helper expressions, required for generation of private
+ /// copies of original lastprivate variables.
+ void setPrivateCopies(ArrayRef<Expr *> PrivateCopies);
+
+ helper_expr_const_range private_copies() const {
+ return helper_expr_const_range(getPrivateCopies().begin(),
+ getPrivateCopies().end());
+ }
+ helper_expr_range private_copies() {
+ return helper_expr_range(getPrivateCopies().begin(),
+ getPrivateCopies().end());
+ }
+ helper_expr_const_range source_exprs() const {
+ return helper_expr_const_range(getSourceExprs().begin(),
+ getSourceExprs().end());
+ }
+ helper_expr_range source_exprs() {
+ return helper_expr_range(getSourceExprs().begin(), getSourceExprs().end());
+ }
+ helper_expr_const_range destination_exprs() const {
+ return helper_expr_const_range(getDestinationExprs().begin(),
+ getDestinationExprs().end());
+ }
+ helper_expr_range destination_exprs() {
+ return helper_expr_range(getDestinationExprs().begin(),
+ getDestinationExprs().end());
+ }
+ helper_expr_const_range assignment_ops() const {
+ return helper_expr_const_range(getAssignmentOps().begin(),
+ getAssignmentOps().end());
+ }
+ helper_expr_range assignment_ops() {
+ return helper_expr_range(getAssignmentOps().begin(),
+ getAssignmentOps().end());
+ }
+
StmtRange children() {
return StmtRange(reinterpret_cast<Stmt **>(varlist_begin()),
reinterpret_cast<Stmt **>(varlist_end()));
@@ -1301,6 +1426,48 @@
/// \brief Sets the nested name specifier.
void setQualifierLoc(NestedNameSpecifierLoc NSL) { QualifierLoc = NSL; }
+ /// \brief Set list of helper expressions, required for proper codegen of the
+ /// clause. These expressions represent LHS expression in the final
+ /// reduction expression performed by the reduction clause.
+ void setLHSExprs(ArrayRef<Expr *> LHSExprs);
+
+ /// \brief Get the list of helper LHS expressions.
+ MutableArrayRef<Expr *> getLHSExprs() {
+ return MutableArrayRef<Expr *>(varlist_end(), varlist_size());
+ }
+ ArrayRef<const Expr *> getLHSExprs() const {
+ return llvm::makeArrayRef(varlist_end(), varlist_size());
+ }
+
+ /// \brief Set list of helper expressions, required for proper codegen of the
+ /// clause. These expressions represent RHS expression in the final
+ /// reduction expression performed by the reduction clause.
+ /// Also, variables in these expressions are used for proper initialization of
+ /// reduction copies.
+ void setRHSExprs(ArrayRef<Expr *> RHSExprs);
+
+ /// \brief Get the list of helper destination expressions.
+ MutableArrayRef<Expr *> getRHSExprs() {
+ return MutableArrayRef<Expr *>(getLHSExprs().end(), varlist_size());
+ }
+ ArrayRef<const Expr *> getRHSExprs() const {
+ return llvm::makeArrayRef(getLHSExprs().end(), varlist_size());
+ }
+
+ /// \brief Set list of helper reduction expressions, required for proper
+ /// codegen of the clause. These expressions are binary expressions or
+ /// operator/custom reduction call that calculates new value from source
+ /// helper expressions to destination helper expressions.
+ void setReductionOps(ArrayRef<Expr *> ReductionOps);
+
+ /// \brief Get the list of helper reduction expressions.
+ MutableArrayRef<Expr *> getReductionOps() {
+ return MutableArrayRef<Expr *>(getRHSExprs().end(), varlist_size());
+ }
+ ArrayRef<const Expr *> getReductionOps() const {
+ return llvm::makeArrayRef(getRHSExprs().end(), varlist_size());
+ }
+
public:
/// \brief Creates clause with a list of variables \a VL.
///
@@ -1311,12 +1478,30 @@
/// \param VL The variables in the clause.
/// \param QualifierLoc The nested-name qualifier with location information
/// \param NameInfo The full name info for reduction identifier.
+ /// \param LHSExprs List of helper expressions for proper generation of
+ /// assignment operation required for copyprivate clause. This list represents
+ /// LHSs of the reduction expressions.
+ /// \param RHSExprs List of helper expressions for proper generation of
+ /// assignment operation required for copyprivate clause. This list represents
+ /// RHSs of the reduction expressions.
+ /// Also, variables in these expressions are used for proper initialization of
+ /// reduction copies.
+ /// \param ReductionOps List of helper expressions that represents reduction
+ /// expressions:
+ /// \code
+ /// LHSExprs binop RHSExprs;
+ /// operator binop(LHSExpr, RHSExpr);
+ /// <CutomReduction>(LHSExpr, RHSExpr);
+ /// \endcode
+ /// Required for proper codegen of final reduction operation performed by the
+ /// reduction clause.
///
static OMPReductionClause *
Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc,
SourceLocation ColonLoc, SourceLocation EndLoc, ArrayRef<Expr *> VL,
NestedNameSpecifierLoc QualifierLoc,
- const DeclarationNameInfo &NameInfo);
+ const DeclarationNameInfo &NameInfo, ArrayRef<Expr *> LHSExprs,
+ ArrayRef<Expr *> RHSExprs, ArrayRef<Expr *> ReductionOps);
/// \brief Creates an empty clause with the place for \a N variables.
///
/// \param C AST context.
@@ -1331,6 +1516,33 @@
/// \brief Gets the nested name specifier.
NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; }
+ typedef MutableArrayRef<Expr *>::iterator helper_expr_iterator;
+ typedef ArrayRef<const Expr *>::iterator helper_expr_const_iterator;
+ typedef llvm::iterator_range<helper_expr_iterator> helper_expr_range;
+ typedef llvm::iterator_range<helper_expr_const_iterator>
+ helper_expr_const_range;
+
+ helper_expr_const_range lhs_exprs() const {
+ return helper_expr_const_range(getLHSExprs().begin(), getLHSExprs().end());
+ }
+ helper_expr_range lhs_exprs() {
+ return helper_expr_range(getLHSExprs().begin(), getLHSExprs().end());
+ }
+ helper_expr_const_range rhs_exprs() const {
+ return helper_expr_const_range(getRHSExprs().begin(), getRHSExprs().end());
+ }
+ helper_expr_range rhs_exprs() {
+ return helper_expr_range(getRHSExprs().begin(), getRHSExprs().end());
+ }
+ helper_expr_const_range reduction_ops() const {
+ return helper_expr_const_range(getReductionOps().begin(),
+ getReductionOps().end());
+ }
+ helper_expr_range reduction_ops() {
+ return helper_expr_range(getReductionOps().begin(),
+ getReductionOps().end());
+ }
+
StmtRange children() {
return StmtRange(reinterpret_cast<Stmt **>(varlist_begin()),
reinterpret_cast<Stmt **>(varlist_end()));
@@ -1614,6 +1826,20 @@
/// with the variables 'a' and 'b'.
///
class OMPCopyinClause : public OMPVarListClause<OMPCopyinClause> {
+ // Class has 3 additional tail allocated arrays:
+ // 1. List of helper expressions for proper generation of assignment operation
+ // required for copyin clause. This list represents sources.
+ // 2. List of helper expressions for proper generation of assignment operation
+ // required for copyin clause. This list represents destinations.
+ // 3. List of helper expressions that represents assignment operation:
+ // \code
+ // DstExprs = SrcExprs;
+ // \endcode
+ // Required for proper codegen of propagation of master's thread values of
+ // threadprivate variables to local instances of that variables in other
+ // implicit threads.
+
+ friend class OMPClauseReader;
/// \brief Build clause with number of variables \a N.
///
/// \param StartLoc Starting location of the clause.
@@ -1635,6 +1861,46 @@
SourceLocation(), SourceLocation(),
N) {}
+ /// \brief Set list of helper expressions, required for proper codegen of the
+ /// clause. These expressions represent source expression in the final
+ /// assignment statement performed by the copyin clause.
+ void setSourceExprs(ArrayRef<Expr *> SrcExprs);
+
+ /// \brief Get the list of helper source expressions.
+ MutableArrayRef<Expr *> getSourceExprs() {
+ return MutableArrayRef<Expr *>(varlist_end(), varlist_size());
+ }
+ ArrayRef<const Expr *> getSourceExprs() const {
+ return llvm::makeArrayRef(varlist_end(), varlist_size());
+ }
+
+ /// \brief Set list of helper expressions, required for proper codegen of the
+ /// clause. These expressions represent destination expression in the final
+ /// assignment statement performed by the copyin clause.
+ void setDestinationExprs(ArrayRef<Expr *> DstExprs);
+
+ /// \brief Get the list of helper destination expressions.
+ MutableArrayRef<Expr *> getDestinationExprs() {
+ return MutableArrayRef<Expr *>(getSourceExprs().end(), varlist_size());
+ }
+ ArrayRef<const Expr *> getDestinationExprs() const {
+ return llvm::makeArrayRef(getSourceExprs().end(), varlist_size());
+ }
+
+ /// \brief Set list of helper assignment expressions, required for proper
+ /// codegen of the clause. These expressions are assignment expressions that
+ /// assign source helper expressions to destination helper expressions
+ /// correspondingly.
+ void setAssignmentOps(ArrayRef<Expr *> AssignmentOps);
+
+ /// \brief Get the list of helper assignment expressions.
+ MutableArrayRef<Expr *> getAssignmentOps() {
+ return MutableArrayRef<Expr *>(getDestinationExprs().end(), varlist_size());
+ }
+ ArrayRef<const Expr *> getAssignmentOps() const {
+ return llvm::makeArrayRef(getDestinationExprs().end(), varlist_size());
+ }
+
public:
/// \brief Creates clause with a list of variables \a VL.
///
@@ -1643,10 +1909,25 @@
/// \param LParenLoc Location of '('.
/// \param EndLoc Ending location of the clause.
/// \param VL List of references to the variables.
+ /// \param SrcExprs List of helper expressions for proper generation of
+ /// assignment operation required for copyin clause. This list represents
+ /// sources.
+ /// \param DstExprs List of helper expressions for proper generation of
+ /// assignment operation required for copyin clause. This list represents
+ /// destinations.
+ /// \param AssignmentOps List of helper expressions that represents assignment
+ /// operation:
+ /// \code
+ /// DstExprs = SrcExprs;
+ /// \endcode
+ /// Required for proper codegen of propagation of master's thread values of
+ /// threadprivate variables to local instances of that variables in other
+ /// implicit threads.
///
- static OMPCopyinClause *Create(const ASTContext &C, SourceLocation StartLoc,
- SourceLocation LParenLoc,
- SourceLocation EndLoc, ArrayRef<Expr *> VL);
+ static OMPCopyinClause *
+ Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc,
+ SourceLocation EndLoc, ArrayRef<Expr *> VL, ArrayRef<Expr *> SrcExprs,
+ ArrayRef<Expr *> DstExprs, ArrayRef<Expr *> AssignmentOps);
/// \brief Creates an empty clause with \a N variables.
///
/// \param C AST context.
@@ -1654,6 +1935,36 @@
///
static OMPCopyinClause *CreateEmpty(const ASTContext &C, unsigned N);
+ typedef MutableArrayRef<Expr *>::iterator helper_expr_iterator;
+ typedef ArrayRef<const Expr *>::iterator helper_expr_const_iterator;
+ typedef llvm::iterator_range<helper_expr_iterator> helper_expr_range;
+ typedef llvm::iterator_range<helper_expr_const_iterator>
+ helper_expr_const_range;
+
+ helper_expr_const_range source_exprs() const {
+ return helper_expr_const_range(getSourceExprs().begin(),
+ getSourceExprs().end());
+ }
+ helper_expr_range source_exprs() {
+ return helper_expr_range(getSourceExprs().begin(), getSourceExprs().end());
+ }
+ helper_expr_const_range destination_exprs() const {
+ return helper_expr_const_range(getDestinationExprs().begin(),
+ getDestinationExprs().end());
+ }
+ helper_expr_range destination_exprs() {
+ return helper_expr_range(getDestinationExprs().begin(),
+ getDestinationExprs().end());
+ }
+ helper_expr_const_range assignment_ops() const {
+ return helper_expr_const_range(getAssignmentOps().begin(),
+ getAssignmentOps().end());
+ }
+ helper_expr_range assignment_ops() {
+ return helper_expr_range(getAssignmentOps().begin(),
+ getAssignmentOps().end());
+ }
+
StmtRange children() {
return StmtRange(reinterpret_cast<Stmt **>(varlist_begin()),
reinterpret_cast<Stmt **>(varlist_end()));
diff --git a/include/clang/AST/RecordLayout.h b/include/clang/AST/RecordLayout.h
index f9240f2..667f235 100644
--- a/include/clang/AST/RecordLayout.h
+++ b/include/clang/AST/RecordLayout.h
@@ -159,7 +159,7 @@
const BaseOffsetsMapTy& BaseOffsets,
const VBaseOffsetsMapTy& VBaseOffsets);
- ~ASTRecordLayout() {}
+ ~ASTRecordLayout() = default;
void Destroy(ASTContext &Ctx);
diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h
index 91b637c..235023d 100644
--- a/include/clang/AST/RecursiveASTVisitor.h
+++ b/include/clang/AST/RecursiveASTVisitor.h
@@ -2549,6 +2549,18 @@
bool RecursiveASTVisitor<Derived>::VisitOMPLastprivateClause(
OMPLastprivateClause *C) {
TRY_TO(VisitOMPClauseList(C));
+ for (auto *E : C->private_copies()) {
+ TRY_TO(TraverseStmt(E));
+ }
+ for (auto *E : C->source_exprs()) {
+ TRY_TO(TraverseStmt(E));
+ }
+ for (auto *E : C->destination_exprs()) {
+ TRY_TO(TraverseStmt(E));
+ }
+ for (auto *E : C->assignment_ops()) {
+ TRY_TO(TraverseStmt(E));
+ }
return true;
}
@@ -2585,6 +2597,15 @@
template <typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPCopyinClause(OMPCopyinClause *C) {
TRY_TO(VisitOMPClauseList(C));
+ for (auto *E : C->source_exprs()) {
+ TRY_TO(TraverseStmt(E));
+ }
+ for (auto *E : C->destination_exprs()) {
+ TRY_TO(TraverseStmt(E));
+ }
+ for (auto *E : C->assignment_ops()) {
+ TRY_TO(TraverseStmt(E));
+ }
return true;
}
@@ -2610,6 +2631,15 @@
TRY_TO(TraverseNestedNameSpecifierLoc(C->getQualifierLoc()));
TRY_TO(TraverseDeclarationNameInfo(C->getNameInfo()));
TRY_TO(VisitOMPClauseList(C));
+ for (auto *E : C->lhs_exprs()) {
+ TRY_TO(TraverseStmt(E));
+ }
+ for (auto *E : C->rhs_exprs()) {
+ TRY_TO(TraverseStmt(E));
+ }
+ for (auto *E : C->reduction_ops()) {
+ TRY_TO(TraverseStmt(E));
+ }
return true;
}
diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h
index 33f4aa0..445cd84 100644
--- a/include/clang/AST/Stmt.h
+++ b/include/clang/AST/Stmt.h
@@ -101,7 +101,7 @@
/// Stmt - This represents one statement.
///
-class Stmt {
+class LLVM_ALIGNAS(LLVM_PTR_SIZE) Stmt {
public:
enum StmtClass {
NoStmtClass = 0,
@@ -287,9 +287,6 @@
};
union {
- // FIXME: this is wasteful on 64-bit platforms.
- void *Aligner;
-
StmtBitfields StmtBits;
CompoundStmtBitfields CompoundStmtBits;
ExprBitfields ExprBits;
@@ -341,13 +338,12 @@
protected:
/// \brief Construct an empty statement.
- explicit Stmt(StmtClass SC, EmptyShell) {
- StmtBits.sClass = SC;
- if (StatisticsEnabled) Stmt::addStmtClass(SC);
- }
+ explicit Stmt(StmtClass SC, EmptyShell) : Stmt(SC) {}
public:
Stmt(StmtClass SC) {
+ static_assert(sizeof(*this) % llvm::AlignOf<void *>::Alignment == 0,
+ "Insufficient alignment!");
StmtBits.sClass = SC;
if (StatisticsEnabled) Stmt::addStmtClass(SC);
}
@@ -689,10 +685,10 @@
};
class CaseStmt : public SwitchCase {
+ SourceLocation EllipsisLoc;
enum { LHS, RHS, SUBSTMT, END_EXPR };
Stmt* SubExprs[END_EXPR]; // The expression for the RHS is Non-null for
// GNU "case 1 ... 4" extension
- SourceLocation EllipsisLoc;
public:
CaseStmt(Expr *lhs, Expr *rhs, SourceLocation caseLoc,
SourceLocation ellipsisLoc, SourceLocation colonLoc)
@@ -789,12 +785,16 @@
/// foo: return;
///
class LabelStmt : public Stmt {
+ SourceLocation IdentLoc;
LabelDecl *TheDecl;
Stmt *SubStmt;
- SourceLocation IdentLoc;
+
public:
LabelStmt(SourceLocation IL, LabelDecl *D, Stmt *substmt)
- : Stmt(LabelStmtClass), TheDecl(D), SubStmt(substmt), IdentLoc(IL) {
+ : Stmt(LabelStmtClass), IdentLoc(IL), TheDecl(D), SubStmt(substmt) {
+ static_assert(sizeof(LabelStmt) ==
+ 2 * sizeof(SourceLocation) + 2 * sizeof(void *),
+ "LabelStmt too big");
}
// \brief Build an empty label statement.
@@ -944,16 +944,14 @@
/// SwitchStmt - This represents a 'switch' stmt.
///
class SwitchStmt : public Stmt {
+ SourceLocation SwitchLoc;
enum { VAR, COND, BODY, END_EXPR };
Stmt* SubExprs[END_EXPR];
- // This points to a linked list of case and default statements.
- SwitchCase *FirstCase;
- SourceLocation SwitchLoc;
-
- /// If the SwitchStmt is a switch on an enum value, this records whether
- /// all the enum values were covered by CaseStmts. This value is meant to
- /// be a hint for possible clients.
- unsigned AllEnumCasesCovered : 1;
+ // This points to a linked list of case and default statements and, if the
+ // SwitchStmt is a switch on an enum value, records whether all the enum
+ // values were covered by CaseStmts. The coverage information value is meant
+ // to be a hint for possible clients.
+ llvm::PointerIntPair<SwitchCase *, 1, bool> FirstCase;
public:
SwitchStmt(const ASTContext &C, VarDecl *Var, Expr *cond);
@@ -981,16 +979,16 @@
const Expr *getCond() const { return reinterpret_cast<Expr*>(SubExprs[COND]);}
const Stmt *getBody() const { return SubExprs[BODY]; }
- const SwitchCase *getSwitchCaseList() const { return FirstCase; }
+ const SwitchCase *getSwitchCaseList() const { return FirstCase.getPointer(); }
Expr *getCond() { return reinterpret_cast<Expr*>(SubExprs[COND]);}
void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt *>(E); }
Stmt *getBody() { return SubExprs[BODY]; }
void setBody(Stmt *S) { SubExprs[BODY] = S; }
- SwitchCase *getSwitchCaseList() { return FirstCase; }
+ SwitchCase *getSwitchCaseList() { return FirstCase.getPointer(); }
/// \brief Set the case list for this switch statement.
- void setSwitchCaseList(SwitchCase *SC) { FirstCase = SC; }
+ void setSwitchCaseList(SwitchCase *SC) { FirstCase.setPointer(SC); }
SourceLocation getSwitchLoc() const { return SwitchLoc; }
void setSwitchLoc(SourceLocation L) { SwitchLoc = L; }
@@ -1002,21 +1000,17 @@
void addSwitchCase(SwitchCase *SC) {
assert(!SC->getNextSwitchCase()
&& "case/default already added to a switch");
- SC->setNextSwitchCase(FirstCase);
- FirstCase = SC;
+ SC->setNextSwitchCase(FirstCase.getPointer());
+ FirstCase.setPointer(SC);
}
/// Set a flag in the SwitchStmt indicating that if the 'switch (X)' is a
/// switch over an enum value then all cases have been explicitly covered.
- void setAllEnumCasesCovered() {
- AllEnumCasesCovered = 1;
- }
+ void setAllEnumCasesCovered() { FirstCase.setInt(true); }
/// Returns true if the SwitchStmt is a switch of an enum value and all cases
/// have been explicitly covered.
- bool isAllEnumCasesCovered() const {
- return (bool) AllEnumCasesCovered;
- }
+ bool isAllEnumCasesCovered() const { return FirstCase.getInt(); }
SourceLocation getLocStart() const LLVM_READONLY { return SwitchLoc; }
SourceLocation getLocEnd() const LLVM_READONLY {
@@ -1037,9 +1031,9 @@
/// WhileStmt - This represents a 'while' stmt.
///
class WhileStmt : public Stmt {
+ SourceLocation WhileLoc;
enum { VAR, COND, BODY, END_EXPR };
Stmt* SubExprs[END_EXPR];
- SourceLocation WhileLoc;
public:
WhileStmt(const ASTContext &C, VarDecl *Var, Expr *cond, Stmt *body,
SourceLocation WL);
@@ -1092,9 +1086,9 @@
/// DoStmt - This represents a 'do/while' stmt.
///
class DoStmt : public Stmt {
+ SourceLocation DoLoc;
enum { BODY, COND, END_EXPR };
Stmt* SubExprs[END_EXPR];
- SourceLocation DoLoc;
SourceLocation WhileLoc;
SourceLocation RParenLoc; // Location of final ')' in do stmt condition.
@@ -1143,9 +1137,9 @@
/// specified in the source.
///
class ForStmt : public Stmt {
+ SourceLocation ForLoc;
enum { INIT, CONDVAR, COND, INC, BODY, END_EXPR };
Stmt* SubExprs[END_EXPR]; // SubExprs[INIT] is an expression or declstmt.
- SourceLocation ForLoc;
SourceLocation LParenLoc, RParenLoc;
public:
@@ -1315,8 +1309,12 @@
///
class BreakStmt : public Stmt {
SourceLocation BreakLoc;
+
public:
- BreakStmt(SourceLocation BL) : Stmt(BreakStmtClass), BreakLoc(BL) {}
+ BreakStmt(SourceLocation BL) : Stmt(BreakStmtClass), BreakLoc(BL) {
+ static_assert(sizeof(BreakStmt) == 2 * sizeof(SourceLocation),
+ "BreakStmt too large");
+ }
/// \brief Build an empty break statement.
explicit BreakStmt(EmptyShell Empty) : Stmt(BreakStmtClass, Empty) { }
@@ -1346,18 +1344,16 @@
/// depend on the return type of the function and the presence of an argument.
///
class ReturnStmt : public Stmt {
- Stmt *RetExpr;
SourceLocation RetLoc;
+ Stmt *RetExpr;
const VarDecl *NRVOCandidate;
public:
- ReturnStmt(SourceLocation RL)
- : Stmt(ReturnStmtClass), RetExpr(nullptr), RetLoc(RL),
- NRVOCandidate(nullptr) {}
+ explicit ReturnStmt(SourceLocation RL) : ReturnStmt(RL, nullptr, nullptr) {}
ReturnStmt(SourceLocation RL, Expr *E, const VarDecl *NRVOCandidate)
- : Stmt(ReturnStmtClass), RetExpr((Stmt*) E), RetLoc(RL),
- NRVOCandidate(NRVOCandidate) {}
+ : Stmt(ReturnStmtClass), RetLoc(RL), RetExpr((Stmt *)E),
+ NRVOCandidate(NRVOCandidate) {}
/// \brief Build an empty return expression.
explicit ReturnStmt(EmptyShell Empty) : Stmt(ReturnStmtClass, Empty) { }
diff --git a/include/clang/AST/StmtCXX.h b/include/clang/AST/StmtCXX.h
index 837dc45..567a772 100644
--- a/include/clang/AST/StmtCXX.h
+++ b/include/clang/AST/StmtCXX.h
@@ -126,11 +126,11 @@
/// analysis of the constituent components. The original syntactic components
/// can be extracted using getLoopVariable and getRangeInit.
class CXXForRangeStmt : public Stmt {
+ SourceLocation ForLoc;
enum { RANGE, BEGINEND, COND, INC, LOOPVAR, BODY, END };
// SubExprs[RANGE] is an expression or declstmt.
// SubExprs[COND] and SubExprs[INC] are expressions.
Stmt *SubExprs[END];
- SourceLocation ForLoc;
SourceLocation ColonLoc;
SourceLocation RParenLoc;
public:
diff --git a/include/clang/AST/StmtObjC.h b/include/clang/AST/StmtObjC.h
index d0527e2..68fe3ef 100644
--- a/include/clang/AST/StmtObjC.h
+++ b/include/clang/AST/StmtObjC.h
@@ -118,12 +118,13 @@
/// \brief Represents Objective-C's \@finally statement
class ObjCAtFinallyStmt : public Stmt {
- Stmt *AtFinallyStmt;
SourceLocation AtFinallyLoc;
+ Stmt *AtFinallyStmt;
+
public:
ObjCAtFinallyStmt(SourceLocation atFinallyLoc, Stmt *atFinallyStmt)
- : Stmt(ObjCAtFinallyStmtClass),
- AtFinallyStmt(atFinallyStmt), AtFinallyLoc(atFinallyLoc) {}
+ : Stmt(ObjCAtFinallyStmtClass), AtFinallyLoc(atFinallyLoc),
+ AtFinallyStmt(atFinallyStmt) {}
explicit ObjCAtFinallyStmt(EmptyShell Empty) :
Stmt(ObjCAtFinallyStmtClass, Empty) { }
@@ -260,9 +261,9 @@
/// \endcode
class ObjCAtSynchronizedStmt : public Stmt {
private:
+ SourceLocation AtSynchronizedLoc;
enum { SYNC_EXPR, SYNC_BODY, END_EXPR };
Stmt* SubStmts[END_EXPR];
- SourceLocation AtSynchronizedLoc;
public:
ObjCAtSynchronizedStmt(SourceLocation atSynchronizedLoc, Stmt *synchExpr,
@@ -310,8 +311,9 @@
/// \brief Represents Objective-C's \@throw statement.
class ObjCAtThrowStmt : public Stmt {
- Stmt *Throw;
SourceLocation AtThrowLoc;
+ Stmt *Throw;
+
public:
ObjCAtThrowStmt(SourceLocation atThrowLoc, Stmt *throwExpr)
: Stmt(ObjCAtThrowStmtClass), Throw(throwExpr) {
@@ -341,13 +343,12 @@
/// \brief Represents Objective-C's \@autoreleasepool Statement
class ObjCAutoreleasePoolStmt : public Stmt {
- Stmt *SubStmt;
SourceLocation AtLoc;
+ Stmt *SubStmt;
+
public:
- ObjCAutoreleasePoolStmt(SourceLocation atLoc,
- Stmt *subStmt)
- : Stmt(ObjCAutoreleasePoolStmtClass),
- SubStmt(subStmt), AtLoc(atLoc) {}
+ ObjCAutoreleasePoolStmt(SourceLocation atLoc, Stmt *subStmt)
+ : Stmt(ObjCAutoreleasePoolStmtClass), AtLoc(atLoc), SubStmt(subStmt) {}
explicit ObjCAutoreleasePoolStmt(EmptyShell Empty) :
Stmt(ObjCAutoreleasePoolStmtClass, Empty) { }
diff --git a/include/clang/AST/StmtOpenMP.h b/include/clang/AST/StmtOpenMP.h
index 4bffbca..2238e34 100644
--- a/include/clang/AST/StmtOpenMP.h
+++ b/include/clang/AST/StmtOpenMP.h
@@ -1582,8 +1582,26 @@
///
class OMPAtomicDirective : public OMPExecutableDirective {
friend class ASTStmtReader;
- /// \brief Binary operator for update and capture constructs.
- BinaryOperatorKind OpKind;
+ /// \brief Used for 'atomic update' or 'atomic capture' constructs. They may
+ /// have atomic expressions of forms
+ /// \code
+ /// x = x binop expr;
+ /// x = expr binop x;
+ /// \endcode
+ /// This field is true for the first form of the expression and false for the
+ /// second. Required for correct codegen of non-associative operations (like
+ /// << or >>).
+ bool IsXLHSInRHSPart;
+ /// \brief Used for 'atomic update' or 'atomic capture' constructs. They may
+ /// have atomic expressions of forms
+ /// \code
+ /// v = x; <update x>;
+ /// <update x>; v = x;
+ /// \endcode
+ /// This field is true for the first(postfix) form of the expression and false
+ /// otherwise.
+ bool IsPostfixUpdate;
+
/// \brief Build directive with the given start and end location.
///
/// \param StartLoc Starting location of the directive kind.
@@ -1593,7 +1611,8 @@
OMPAtomicDirective(SourceLocation StartLoc, SourceLocation EndLoc,
unsigned NumClauses)
: OMPExecutableDirective(this, OMPAtomicDirectiveClass, OMPD_atomic,
- StartLoc, EndLoc, NumClauses, 5) {}
+ StartLoc, EndLoc, NumClauses, 5),
+ IsXLHSInRHSPart(false), IsPostfixUpdate(false) {}
/// \brief Build an empty directive.
///
@@ -1602,15 +1621,15 @@
explicit OMPAtomicDirective(unsigned NumClauses)
: OMPExecutableDirective(this, OMPAtomicDirectiveClass, OMPD_atomic,
SourceLocation(), SourceLocation(), NumClauses,
- 5) {}
+ 5),
+ IsXLHSInRHSPart(false), IsPostfixUpdate(false) {}
- /// \brief Set operator kind for update and capture atomic constructs.
- void setOpKind(const BinaryOperatorKind BOK) { OpKind = BOK; }
/// \brief Set 'x' part of the associated expression/statement.
void setX(Expr *X) { *std::next(child_begin()) = X; }
- /// \brief Set 'x' rvalue used in update and capture atomic constructs for
- /// proper update expression generation.
- void setXRVal(Expr *XRVal) { *std::next(child_begin(), 2) = XRVal; }
+ /// \brief Set helper expression of the form
+ /// 'OpaqueValueExpr(x) binop OpaqueValueExpr(expr)' or
+ /// 'OpaqueValueExpr(expr) binop OpaqueValueExpr(x)'.
+ void setUpdateExpr(Expr *UE) { *std::next(child_begin(), 2) = UE; }
/// \brief Set 'v' part of the associated expression/statement.
void setV(Expr *V) { *std::next(child_begin(), 3) = V; }
/// \brief Set 'expr' part of the associated expression/statement.
@@ -1626,19 +1645,20 @@
/// \param EndLoc Ending Location of the directive.
/// \param Clauses List of clauses.
/// \param AssociatedStmt Statement, associated with the directive.
- /// \param OpKind Binary operator used for updating of 'x' part of the
- /// expression in update and capture atomic constructs.
/// \param X 'x' part of the associated expression/statement.
- /// \param XRVal 'x' rvalue expression used in update and capture constructs
- /// for proper update expression generation. Used to read original value of
- /// the 'x' part of the expression.
/// \param V 'v' part of the associated expression/statement.
/// \param E 'expr' part of the associated expression/statement.
- ///
+ /// \param UE Helper expression of the form
+ /// 'OpaqueValueExpr(x) binop OpaqueValueExpr(expr)' or
+ /// 'OpaqueValueExpr(expr) binop OpaqueValueExpr(x)'.
+ /// \param IsXLHSInRHSPart true if \a UE has the first form and false if the
+ /// second.
+ /// \param IsPostfixUpdate true if original value of 'x' must be stored in
+ /// 'v', not an updated one.
static OMPAtomicDirective *
Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
- ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt,
- BinaryOperatorKind OpKind, Expr *X, Expr *XRVal, Expr *V, Expr *E);
+ ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt, Expr *X, Expr *V,
+ Expr *E, Expr *UE, bool IsXLHSInRHSPart, bool IsPostfixUpdate);
/// \brief Creates an empty directive with the place for \a NumClauses
/// clauses.
@@ -1649,19 +1669,27 @@
static OMPAtomicDirective *CreateEmpty(const ASTContext &C,
unsigned NumClauses, EmptyShell);
- /// \brief Get binary operation for update or capture atomic constructs.
- BinaryOperatorKind getOpKind() const { return OpKind; }
/// \brief Get 'x' part of the associated expression/statement.
Expr *getX() { return cast_or_null<Expr>(*std::next(child_begin())); }
const Expr *getX() const {
return cast_or_null<Expr>(*std::next(child_begin()));
}
- /// \brief Get 'x' rvalue used in update and capture atomic constructs for
- /// proper update expression generation.
- Expr *getXRVal() { return cast_or_null<Expr>(*std::next(child_begin(), 2)); }
- const Expr *getXRVal() const {
+ /// \brief Get helper expression of the form
+ /// 'OpaqueValueExpr(x) binop OpaqueValueExpr(expr)' or
+ /// 'OpaqueValueExpr(expr) binop OpaqueValueExpr(x)'.
+ Expr *getUpdateExpr() {
return cast_or_null<Expr>(*std::next(child_begin(), 2));
}
+ const Expr *getUpdateExpr() const {
+ return cast_or_null<Expr>(*std::next(child_begin(), 2));
+ }
+ /// \brief Return true if helper update expression has form
+ /// 'OpaqueValueExpr(x) binop OpaqueValueExpr(expr)' and false if it has form
+ /// 'OpaqueValueExpr(expr) binop OpaqueValueExpr(x)'.
+ bool isXLHSInRHSPart() const { return IsXLHSInRHSPart; }
+ /// \brief Return true if 'v' expression must be updated to original value of
+ /// 'x', false if 'v' must be updated to the new value of 'x'.
+ bool isPostfixUpdate() const { return IsPostfixUpdate; }
/// \brief Get 'v' part of the associated expression/statement.
Expr *getV() { return cast_or_null<Expr>(*std::next(child_begin(), 3)); }
const Expr *getV() const {
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h
index b252d48..ce8181b 100644
--- a/include/clang/AST/Type.h
+++ b/include/clang/AST/Type.h
@@ -1575,6 +1575,7 @@
bool isObjCLifetimeType() const; // (array of)* retainable type
bool isObjCIndirectLifetimeType() const; // (pointer to)* lifetime type
bool isObjCNSObjectType() const; // __attribute__((NSObject))
+ bool isObjCIndependentClassType() const; // __attribute__((objc_independent_class))
// FIXME: change this to 'raw' interface type, so we can used 'interface' type
// for the common case.
bool isObjCObjectType() const; // NSString or typeof(*(id)0)
diff --git a/include/clang/AST/VTableBuilder.h b/include/clang/AST/VTableBuilder.h
index 4e24bdd..ebfbb8a 100644
--- a/include/clang/AST/VTableBuilder.h
+++ b/include/clang/AST/VTableBuilder.h
@@ -333,7 +333,7 @@
public:
ItaniumVTableContext(ASTContext &Context);
- ~ItaniumVTableContext();
+ ~ItaniumVTableContext() override;
const VTableLayout &getVTableLayout(const CXXRecordDecl *RD) {
computeVTableRelatedInformation(RD);
@@ -511,7 +511,7 @@
MicrosoftVTableContext(ASTContext &Context)
: VTableContextBase(/*MS=*/true), Context(Context) {}
- ~MicrosoftVTableContext();
+ ~MicrosoftVTableContext() override;
const VPtrInfoVector &getVFPtrOffsets(const CXXRecordDecl *RD);
diff --git a/include/clang/ASTMatchers/ASTMatchersInternal.h b/include/clang/ASTMatchers/ASTMatchersInternal.h
index 20f1efa..2789223 100644
--- a/include/clang/ASTMatchers/ASTMatchersInternal.h
+++ b/include/clang/ASTMatchers/ASTMatchersInternal.h
@@ -209,7 +209,7 @@
template <typename T>
class MatcherInterface : public DynMatcherInterface {
public:
- virtual ~MatcherInterface() {}
+ ~MatcherInterface() override {}
/// \brief Returns true if 'Node' can be matched.
///
diff --git a/include/clang/ASTMatchers/Dynamic/Parser.h b/include/clang/ASTMatchers/Dynamic/Parser.h
index bd006b6..cdc259e 100644
--- a/include/clang/ASTMatchers/Dynamic/Parser.h
+++ b/include/clang/ASTMatchers/Dynamic/Parser.h
@@ -123,7 +123,7 @@
/// tokens.
class RegistrySema : public Parser::Sema {
public:
- virtual ~RegistrySema();
+ ~RegistrySema() override;
llvm::Optional<MatcherCtor>
lookupMatcherCtor(StringRef MatcherName) override;
diff --git a/include/clang/ASTMatchers/Dynamic/VariantValue.h b/include/clang/ASTMatchers/Dynamic/VariantValue.h
index ae22e37..78aa9dc 100644
--- a/include/clang/ASTMatchers/Dynamic/VariantValue.h
+++ b/include/clang/ASTMatchers/Dynamic/VariantValue.h
@@ -111,7 +111,7 @@
ArrayRef<VariantMatcher> InnerMatchers) const;
protected:
- ~MatcherOps() {}
+ ~MatcherOps() = default;
private:
ast_type_traits::ASTNodeKind NodeKind;
@@ -122,7 +122,7 @@
/// It follows a similar interface as VariantMatcher itself.
class Payload : public RefCountedBaseVPTR {
public:
- virtual ~Payload();
+ ~Payload() override;
virtual llvm::Optional<DynTypedMatcher> getSingleMatcher() const = 0;
virtual std::string getTypeAsString() const = 0;
virtual llvm::Optional<DynTypedMatcher>
diff --git a/include/clang/Analysis/Analyses/Dominators.h b/include/clang/Analysis/Analyses/Dominators.h
index fcef0fc..4524aeb 100644
--- a/include/clang/Analysis/Analyses/Dominators.h
+++ b/include/clang/Analysis/Analyses/Dominators.h
@@ -44,9 +44,7 @@
DT = new llvm::DominatorTreeBase<CFGBlock>(false);
}
- ~DominatorTree() {
- delete DT;
- }
+ ~DominatorTree() override { delete DT; }
llvm::DominatorTreeBase<CFGBlock>& getBase() { return *DT; }
diff --git a/include/clang/Analysis/Analyses/LiveVariables.h b/include/clang/Analysis/Analyses/LiveVariables.h
index c29dd40..e17f73a 100644
--- a/include/clang/Analysis/Analyses/LiveVariables.h
+++ b/include/clang/Analysis/Analyses/LiveVariables.h
@@ -44,8 +44,6 @@
llvm::ImmutableSet<const VarDecl *> LiveDecls)
: liveStmts(LiveStmts), liveDecls(LiveDecls) {}
- ~LivenessValues() {}
-
bool isLive(const Stmt *S) const;
bool isLive(const VarDecl *D) const;
@@ -66,11 +64,10 @@
/// Called when the live variables analysis registers
/// that a variable is killed.
virtual void observerKill(const DeclRefExpr *DR) {}
- };
+ };
+ ~LiveVariables() override;
- virtual ~LiveVariables();
-
/// Compute the liveness information for a given CFG.
static LiveVariables *computeLiveness(AnalysisDeclContext &analysisContext,
bool killAtAssign);
diff --git a/include/clang/Analysis/AnalysisContext.h b/include/clang/Analysis/AnalysisContext.h
index a20fc51..931190e 100644
--- a/include/clang/Analysis/AnalysisContext.h
+++ b/include/clang/Analysis/AnalysisContext.h
@@ -289,7 +289,7 @@
Block(blk), Index(idx) {}
public:
- ~StackFrameContext() {}
+ ~StackFrameContext() override {}
const Stmt *getCallSite() const { return CallSite; }
@@ -324,7 +324,7 @@
: LocationContext(Scope, ctx, parent), Enter(s) {}
public:
- ~ScopeContext() {}
+ ~ScopeContext() override {}
void Profile(llvm::FoldingSetNodeID &ID) override;
@@ -352,7 +352,7 @@
: LocationContext(Block, ctx, parent), BD(bd), ContextData(contextData) {}
public:
- ~BlockInvocationContext() {}
+ ~BlockInvocationContext() override {}
const BlockDecl *getBlockDecl() const { return BD; }
diff --git a/include/clang/Analysis/CFG.h b/include/clang/Analysis/CFG.h
index 3fddbb9..e7f6383 100644
--- a/include/clang/Analysis/CFG.h
+++ b/include/clang/Analysis/CFG.h
@@ -493,7 +493,6 @@
: Elements(C), Label(nullptr), Terminator(nullptr), LoopTarget(nullptr),
BlockID(blockid), Preds(C, 1), Succs(C, 1), HasNoReturnElement(false),
Parent(parent) {}
- ~CFGBlock() {}
// Statement iterators
typedef ElementList::iterator iterator;
diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td
index 61645a7..13e04d2 100644
--- a/include/clang/Basic/Attr.td
+++ b/include/clang/Basic/Attr.td
@@ -1063,6 +1063,11 @@
let Documentation = [Undocumented];
}
+def ObjCIndependentClass : InheritableAttr {
+ let Spellings = [GNU<"objc_independent_class">];
+ let Documentation = [Undocumented];
+}
+
def ObjCPreciseLifetime : InheritableAttr {
let Spellings = [GNU<"objc_precise_lifetime">];
let Subjects = SubjectList<[Var], ErrorDiag>;
diff --git a/include/clang/Basic/Builtins.def b/include/clang/Basic/Builtins.def
index a92d412..1927907 100644
--- a/include/clang/Basic/Builtins.def
+++ b/include/clang/Basic/Builtins.def
@@ -56,7 +56,8 @@
// I -> Required to constant fold to an integer constant expression.
//
// Types may be postfixed with the following modifiers:
-// * -> pointer (optionally followed by an address space number)
+// * -> pointer (optionally followed by an address space number, if no address
+// space is specified than any address space will be accepted)
// & -> reference (optionally followed by an address space number)
// C -> const
// D -> volatile
diff --git a/include/clang/Basic/Builtins.h b/include/clang/Basic/Builtins.h
index 3ce2255..27428ad 100644
--- a/include/clang/Basic/Builtins.h
+++ b/include/clang/Basic/Builtins.h
@@ -143,6 +143,12 @@
return strchr(GetRecord(ID).Attributes, 't') != nullptr;
}
+ /// \brief Determines whether this builtin has a result or any arguments which
+ /// are pointer types.
+ bool hasPtrArgsOrResult(unsigned ID) const {
+ return strchr(GetRecord(ID).Type, '*') != nullptr;
+ }
+
/// \brief Completely forget that the given ID was ever considered a builtin,
/// e.g., because the user provided a conflicting signature.
void ForgetBuiltin(unsigned ID, IdentifierTable &Table);
diff --git a/include/clang/Basic/BuiltinsPPC.def b/include/clang/Basic/BuiltinsPPC.def
index 8cc50db..0996818 100644
--- a/include/clang/Basic/BuiltinsPPC.def
+++ b/include/clang/Basic/BuiltinsPPC.def
@@ -283,6 +283,13 @@
BUILTIN(__builtin_ttest, "LUi", "")
+// Scalar built-ins
+BUILTIN(__builtin_divwe, "SiSiSi", "")
+BUILTIN(__builtin_divweu, "UiUiUi", "")
+BUILTIN(__builtin_divde, "SLLiSLLiSLLi", "")
+BUILTIN(__builtin_divdeu, "ULLiULLiULLi", "")
+BUILTIN(__builtin_bpermd, "SLLiSLLiSLLi", "")
+
// FIXME: Obviously incomplete.
#undef BUILTIN
diff --git a/include/clang/Basic/BuiltinsSystemZ.def b/include/clang/Basic/BuiltinsSystemZ.def
new file mode 100644
index 0000000..613e9de
--- /dev/null
+++ b/include/clang/Basic/BuiltinsSystemZ.def
@@ -0,0 +1,27 @@
+//===-- BuiltinsSystemZ.def - SystemZ Builtin function database -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the SystemZ-specific builtin function database. Users of
+// this file must define the BUILTIN macro to make use of this information.
+//
+//===----------------------------------------------------------------------===//
+
+// The format of this database matches clang/Basic/Builtins.def.
+
+// Transactional-memory intrinsics
+BUILTIN(__builtin_tbegin, "iv*", "j")
+BUILTIN(__builtin_tbegin_nofloat, "iv*", "j")
+BUILTIN(__builtin_tbeginc, "v", "nj")
+BUILTIN(__builtin_tabort, "vi", "r")
+BUILTIN(__builtin_tend, "i", "n")
+BUILTIN(__builtin_tx_nesting_depth, "i", "nc")
+BUILTIN(__builtin_tx_assist, "vi", "n")
+BUILTIN(__builtin_non_tx_store, "vULi*ULi", "")
+
+#undef BUILTIN
diff --git a/include/clang/Basic/BuiltinsX86.def b/include/clang/Basic/BuiltinsX86.def
index a60e442..b99e0f4 100644
--- a/include/clang/Basic/BuiltinsX86.def
+++ b/include/clang/Basic/BuiltinsX86.def
@@ -868,6 +868,12 @@
BUILTIN(__builtin_ia32_cvtpd2ps512_mask, "V8fV8dV8fUcIi", "")
BUILTIN(__builtin_ia32_vcvtps2ph512_mask, "V16sV16fIiV16sUs", "")
BUILTIN(__builtin_ia32_vcvtph2ps512_mask, "V16fV16sV16fUsIi", "")
+BUILTIN(__builtin_ia32_pandd512_mask, "V16iV16iV16iV16iUs", "")
+BUILTIN(__builtin_ia32_pandq512_mask, "V8LLiV8LLiV8LLiV8LLiUc", "")
+BUILTIN(__builtin_ia32_pord512_mask, "V16iV16iV16iV16iUs", "")
+BUILTIN(__builtin_ia32_porq512_mask, "V8LLiV8LLiV8LLiV8LLiUc", "")
+BUILTIN(__builtin_ia32_pxord512_mask, "V16iV16iV16iV16iUs", "")
+BUILTIN(__builtin_ia32_pxorq512_mask, "V8LLiV8LLiV8LLiV8LLiUc", "")
BUILTIN(__builtin_ia32_pabsd512_mask, "V16iV16iV16iUs", "")
BUILTIN(__builtin_ia32_pabsq512_mask, "V8LLiV8LLiV8LLiUc", "")
BUILTIN(__builtin_ia32_pmaxsd512_mask, "V16iV16iV16iV16iUs", "")
diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h
index f72809c..0f3831d 100644
--- a/include/clang/Basic/Diagnostic.h
+++ b/include/clang/Basic/Diagnostic.h
@@ -1371,7 +1371,7 @@
public:
ForwardingDiagnosticConsumer(DiagnosticConsumer &Target) : Target(Target) {}
- virtual ~ForwardingDiagnosticConsumer();
+ ~ForwardingDiagnosticConsumer() override;
void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
const Diagnostic &Info) override;
diff --git a/include/clang/Basic/DiagnosticDriverKinds.td b/include/clang/Basic/DiagnosticDriverKinds.td
index 9a055b8..7c0696a 100644
--- a/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/include/clang/Basic/DiagnosticDriverKinds.td
@@ -187,4 +187,11 @@
def warn_drv_invoking_fallback : Warning<"falling back to %0">,
InGroup<Fallback>;
+
+def warn_target_unsupported_nan2008 : Warning<
+ "ignoring '-mnan=2008' option because the '%0' architecture does not support it">,
+ InGroup<UnsupportedNan>;
+def warn_target_unsupported_nanlegacy : Warning<
+ "ignoring '-mnan=legacy' option because the '%0' architecture does not support it">,
+ InGroup<UnsupportedNan>;
}
diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td
index 6f4cce7..09c50a9 100644
--- a/include/clang/Basic/DiagnosticGroups.td
+++ b/include/clang/Basic/DiagnosticGroups.td
@@ -45,6 +45,7 @@
def EnumConversion : DiagGroup<"enum-conversion">;
def FloatConversion : DiagGroup<"float-conversion">;
def EnumTooLarge : DiagGroup<"enum-too-large">;
+def UnsupportedNan : DiagGroup<"unsupported-nan">;
def NonLiteralNullConversion : DiagGroup<"non-literal-null-conversion">;
def NullConversion : DiagGroup<"null-conversion">;
def ImplicitConversionFloatingPointToBool :
@@ -107,6 +108,8 @@
DocumentationDeprecatedSync]>;
def EmptyBody : DiagGroup<"empty-body">;
+def Exceptions : DiagGroup<"exceptions">;
+
def GNUEmptyInitializer : DiagGroup<"gnu-empty-initializer">;
def GNUEmptyStruct : DiagGroup<"gnu-empty-struct">;
def ExtraTokens : DiagGroup<"extra-tokens">;
@@ -220,7 +223,10 @@
def LiteralRange : DiagGroup<"literal-range">;
def LocalTypeTemplateArgs : DiagGroup<"local-type-template-args",
[CXX98CompatLocalTypeTemplateArgs]>;
-def LoopAnalysis : DiagGroup<"loop-analysis">;
+def RangeLoopAnalysis : DiagGroup<"range-loop-analysis">;
+def ForLoopAnalysis : DiagGroup<"for-loop-analysis">;
+def LoopAnalysis : DiagGroup<"loop-analysis", [ForLoopAnalysis,
+ RangeLoopAnalysis]>;
def MalformedWarningCheck : DiagGroup<"malformed-warning-check">;
def Main : DiagGroup<"main">;
def MainReturnType : DiagGroup<"main-return-type">;
@@ -388,6 +394,7 @@
def Pragmas : DiagGroup<"pragmas", [UnknownPragmas, IgnoredPragmas]>;
def UnknownWarningOption : DiagGroup<"unknown-warning-option">;
def NSobjectAttribute : DiagGroup<"NSObject-attribute">;
+def IndependentClassAttribute : DiagGroup<"IndependentClass-attribute">;
def UnknownAttributes : DiagGroup<"unknown-attributes">;
def IgnoredAttributes : DiagGroup<"ignored-attributes">;
def Attributes : DiagGroup<"attributes", [UnknownAttributes,
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 388069f..4ac4c19 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -24,13 +24,30 @@
def warn_variables_not_in_loop_body : Warning<
"variable%select{s| %1|s %1 and %2|s %1, %2, and %3|s %1, %2, %3, and %4}0 "
"used in loop condition not modified in loop body">,
- InGroup<LoopAnalysis>, DefaultIgnore;
+ InGroup<ForLoopAnalysis>, DefaultIgnore;
def warn_redundant_loop_iteration : Warning<
"variable %0 is %select{decremented|incremented}1 both in the loop header "
"and in the loop body">,
- InGroup<LoopAnalysis>, DefaultIgnore;
+ InGroup<ForLoopAnalysis>, DefaultIgnore;
def note_loop_iteration_here : Note<"%select{decremented|incremented}0 here">;
+def warn_for_range_const_reference_copy : Warning<
+ "loop variable %0 "
+ "%diff{has type $ but is initialized with type $"
+ "| is initialized with a value of a different type}1,2 resulting in a copy">,
+ InGroup<RangeLoopAnalysis>, DefaultIgnore;
+def note_use_type_or_non_reference : Note<
+ "use non-reference type %0 to keep the copy or type %1 to prevent copying">;
+def warn_for_range_variable_always_copy : Warning<
+ "loop variable %0 is always a copy because the range of type %1 does not "
+ "return a reference">,
+ InGroup<RangeLoopAnalysis>, DefaultIgnore;
+def note_use_non_reference_type : Note<"use non-reference type %0">;
+def warn_for_range_copy : Warning<
+ "loop variable %0 of type %1 creates a copy from type %2">,
+ InGroup<RangeLoopAnalysis>, DefaultIgnore;
+def note_use_reference_type : Note<"use reference type %0 to prevent copying">;
+
def warn_duplicate_enum_values : Warning<
"element %0 has been implicitly assigned %1 which another element has "
"been assigned">, InGroup<DiagGroup<"duplicate-enum">>, DefaultIgnore;
@@ -1553,7 +1570,7 @@
"block pointer variable %0 is uninitialized when captured by block">,
InGroup<Uninitialized>, DefaultIgnore;
def note_block_var_fixit_add_initialization : Note<
- "maybe you meant to use __block %0">;
+ "did you mean to use __block %0?">;
def note_in_omitted_aggregate_initializer : Note<
"in implicit initialization of %select{array element %1|field %1}0 "
"with omitted initializer">;
@@ -2134,6 +2151,8 @@
def err_alignment_not_power_of_two : Error<
"requested alignment is not a power of 2">;
+def err_alignment_dependent_typedef_name : Error<
+ "requested alignment is dependent but declaration is not dependent">;
def err_attribute_aligned_too_great : Error<
"requested alignment must be %0 bytes or smaller">;
@@ -2181,6 +2200,14 @@
def warn_nsobject_attribute : Warning<
"'NSObject' attribute may be put on a typedef only; attribute is ignored">,
InGroup<NSobjectAttribute>;
+def warn_independentclass_attribute : Warning<
+ "'objc_independent_class' attribute may be put on a typedef only; "
+ "attribute is ignored">,
+ InGroup<IndependentClassAttribute>;
+def warn_ptr_independentclass_attribute : Warning<
+ "'objc_independent_class' attribute may be put on Objective-C object "
+ "pointer type only; attribute is ignored">,
+ InGroup<IndependentClassAttribute>;
def warn_attribute_weak_on_local : Warning<
"__weak attribute cannot be specified on an automatic variable when ARC "
"is not enabled">,
@@ -2808,6 +2835,8 @@
"default arguments cannot be added to an out-of-line definition of a member "
"of a %select{class template|class template partial specialization|nested "
"class in a template}0">;
+def err_param_default_argument_on_parameter_pack : Error<
+ "parameter pack cannot have a default argument">;
def err_uninitialized_member_for_assign : Error<
"cannot define the implicit copy assignment operator for %0, because "
"non-static %select{reference|const}1 member %2 can't use copy "
@@ -3799,34 +3828,14 @@
"previous %select{template type|non-type template|template template}0 "
"parameter%select{| pack}1 declared here">;
-def err_unexpanded_parameter_pack_0 : Error<
+def err_unexpanded_parameter_pack : Error<
"%select{expression|base type|declaration type|data member type|bit-field "
"size|static assertion|fixed underlying type|enumerator value|"
"using declaration|friend declaration|qualifier|initializer|default argument|"
"non-type template parameter type|exception type|partial specialization|"
- "__if_exists name|__if_not_exists name|lambda|block}0 "
- "contains an unexpanded parameter pack">;
-def err_unexpanded_parameter_pack_1 : Error<
- "%select{expression|base type|declaration type|data member type|bit-field "
- "size|static assertion|fixed underlying type|enumerator value|"
- "using declaration|friend declaration|qualifier|initializer|default argument|"
- "non-type template parameter type|exception type|partial specialization|"
- "__if_exists name|__if_not_exists name|lambda|block}0 "
- "contains unexpanded parameter pack %1">;
-def err_unexpanded_parameter_pack_2 : Error<
- "%select{expression|base type|declaration type|data member type|bit-field "
- "size|static assertion|fixed underlying type|enumerator value|"
- "using declaration|friend declaration|qualifier|initializer|default argument|"
- "non-type template parameter type|exception type|partial specialization|"
- "__if_exists name|__if_not_exists name|lambda|block}0 "
- "contains unexpanded parameter packs %1 and %2">;
-def err_unexpanded_parameter_pack_3_or_more : Error<
- "%select{expression|base type|declaration type|data member type|bit-field "
- "size|static assertion|fixed underlying type|enumerator value|"
- "using declaration|friend declaration|qualifier|initializer|default argument|"
- "non-type template parameter type|exception type|partial specialization|"
- "__if_exists name|__if_not_exists name|lambda|block}0 "
- "contains unexpanded parameter packs %1, %2, ...">;
+ "__if_exists name|__if_not_exists name|lambda|block}0 contains"
+ "%plural{0: an|:}1 unexpanded parameter pack"
+ "%plural{0:|1: %2|2:s %2 and %3|:s %2, %3, ...}1">;
def err_pack_expansion_without_parameter_packs : Error<
"pack expansion does not contain any unexpanded parameter packs">;
@@ -4818,7 +4827,7 @@
def err_typecheck_member_reference_arrow : Error<
"member reference type %0 is not a pointer">;
def err_typecheck_member_reference_suggestion : Error<
- "member reference type %0 is %select{a|not a}1 pointer; maybe you meant to use '%select{->|.}1'?">;
+ "member reference type %0 is %select{a|not a}1 pointer; did you mean to use '%select{->|.}1'?">;
def note_typecheck_member_reference_suggestion : Note<
"did you mean to use '.' instead?">;
def note_member_reference_arrow_from_operator_arrow : Note<
@@ -5046,7 +5055,23 @@
"%select{comparison between %diff{ ($ and $)|}0,1"
"|arithmetic operation with operands of type %diff{ ($ and $)|}0,1}2"
" which are pointers to non-overlapping address spaces">;
-def err_typecheck_assign_const : Error<"read-only variable is not assignable">;
+
+def err_typecheck_assign_const : Error<
+ "%select{"
+ "cannot assign to return value because function %1 returns a const value|"
+ "cannot assign to variable %1 with const-qualified type %2|"
+ "cannot assign to %select{non-|}1static data member %2 "
+ "with const-qualified type %3|"
+ "cannot assign to non-static data member within const member function %1|"
+ "read-only variable is not assignable}0">;
+
+def note_typecheck_assign_const : Note<
+ "%select{"
+ "function %1 which returns const-qualified type %2 declared here|"
+ "variable %1 declared const here|"
+ "%select{non-|}1static data member %2 declared const here|"
+ "member function %q1 is declared const here}0">;
+
def warn_mixed_sign_comparison : Warning<
"comparison of integers of different signs: %0 and %1">,
InGroup<SignCompare>, DefaultIgnore;
@@ -5491,7 +5516,8 @@
"left hand operand to %0 must be a %select{|pointer to }1class "
"compatible with the right hand operand, but is %2">;
def warn_exception_caught_by_earlier_handler : Warning<
- "exception of type %0 will be caught by earlier handler">;
+ "exception of type %0 will be caught by earlier handler">,
+ InGroup<Exceptions>;
def note_previous_exception_handler : Note<"for type %0">;
def err_exceptions_disabled : Error<
"cannot use '%0' with exceptions disabled">;
@@ -6876,29 +6902,18 @@
def warn_missing_case_for_condition :
Warning<"no case matching constant switch condition '%0'">;
-def warn_def_missing_case1 : Warning<
- "enumeration value %0 not explicitly handled in switch">,
- InGroup<SwitchEnum>, DefaultIgnore;
-def warn_def_missing_case2 : Warning<
- "enumeration values %0 and %1 not explicitly handled in switch">,
- InGroup<SwitchEnum>, DefaultIgnore;
-def warn_def_missing_case3 : Warning<
- "enumeration values %0, %1, and %2 not explicitly handled in switch">,
- InGroup<SwitchEnum>, DefaultIgnore;
-def warn_def_missing_cases : Warning<
- "%0 enumeration values not explicitly handled in switch: %1, %2, %3...">,
+def warn_def_missing_case : Warning<"%plural{"
+ "1:enumeration value %1 not explicitly handled in switch|"
+ "2:enumeration values %1 and %2 not explicitly handled in switch|"
+ "3:enumeration values %1, %2, and %3 not explicitly handled in switch|"
+ ":%0 enumeration values not explicitly handled in switch: %1, %2, %3...}0">,
InGroup<SwitchEnum>, DefaultIgnore;
-def warn_missing_case1 : Warning<"enumeration value %0 not handled in switch">,
- InGroup<Switch>;
-def warn_missing_case2 : Warning<
- "enumeration values %0 and %1 not handled in switch">,
- InGroup<Switch>;
-def warn_missing_case3 : Warning<
- "enumeration values %0, %1, and %2 not handled in switch">,
- InGroup<Switch>;
-def warn_missing_cases : Warning<
- "%0 enumeration values not handled in switch: %1, %2, %3...">,
+def warn_missing_case : Warning<"%plural{"
+ "1:enumeration value %1 not handled in switch|"
+ "2:enumeration values %1 and %2 not handled in switch|"
+ "3:enumeration values %1, %2, and %3 not handled in switch|"
+ ":%0 enumeration values not handled in switch: %1, %2, %3...}0">,
InGroup<Switch>;
def warn_unannotated_fallthrough : Warning<
@@ -7069,6 +7084,12 @@
"consider using vld1q_%0%1() to initialize a vector from memory, or "
"vcombine_%0%1(vcreate_%0%1(), vcreate_%0%1()) to initialize from integer "
"constants">;
+def err_systemz_invalid_tabort_code : Error<
+ "invalid transaction abort code">;
+def err_64_bit_builtin_32_bit_tgt : Error<
+ "this builtin is only available on 64-bit targets">;
+def err_ppc_builtin_only_on_pwr7 : Error<
+ "this builtin is only valid on POWER7 or later CPUs">;
def err_builtin_longjmp_unsupported : Error<
"__builtin_longjmp is not supported for the current target">;
@@ -7471,7 +7492,7 @@
def err_omp_reduction_in_task : Error<
"reduction variables may not be accessed in an explicit task">;
def err_omp_reduction_id_not_compatible : Error<
- "variable of type %0 is not valid for specified reduction operation">;
+ "variable of type %0 is not valid for specified reduction operation: unable to provide default initialization value">;
def err_omp_prohibited_region : Error<
"region cannot be%select{| closely}0 nested inside '%1' region"
"%select{|; perhaps you forget to enclose 'omp %3' directive into a parallel region?|"
@@ -7524,6 +7545,8 @@
" '{v = x; x = x binop expr;}', '{v = x; x = expr binop x;}', '{x = x binop expr; v = x;}', '{x = expr binop x; v = x;}' or '{v = x; x = expr;}',"
" '{v = x; x++;}', '{v = x; ++x;}', '{++x; v = x;}', '{x++; v = x;}', '{v = x; x--;}', '{v = x; --x;}', '{--x; v = x;}', '{x--; v = x;}'"
" where x is an l-value expression with scalar type">;
+def note_omp_atomic_capture: Note<
+ "%select{expected assignment expression|expected compound statement|expected exactly two expression statements|expected in right hand side of the first expression}0">;
def err_omp_atomic_several_clauses : Error<
"directive '#pragma omp atomic' cannot contain more than one 'read', 'write', 'update' or 'capture' clause">;
def note_omp_atomic_previous_clause : Note<
diff --git a/include/clang/Basic/LLVM.h b/include/clang/Basic/LLVM.h
index 3e01d25..0e6ff92 100644
--- a/include/clang/Basic/LLVM.h
+++ b/include/clang/Basic/LLVM.h
@@ -45,6 +45,7 @@
class RefCountedBaseVPTR;
class raw_ostream;
+ class raw_pwrite_stream;
// TODO: DenseMap, ...
}
@@ -76,6 +77,7 @@
using llvm::RefCountedBaseVPTR;
using llvm::raw_ostream;
+ using llvm::raw_pwrite_stream;
} // end namespace clang.
#endif
diff --git a/include/clang/Basic/LangOptions.def b/include/clang/Basic/LangOptions.def
index 667165c..a09e964 100644
--- a/include/clang/Basic/LangOptions.def
+++ b/include/clang/Basic/LangOptions.def
@@ -163,6 +163,7 @@
LANGOPT(Renderscript , 1, 0, "RenderScript")
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.)")
LANGOPT(AssumeSaneOperatorNew , 1, 1, "implicit __attribute__((malloc)) for C++'s new operators")
LANGOPT(SizedDeallocation , 1, 0, "enable sized deallocation functions")
diff --git a/include/clang/Basic/Sanitizers.def b/include/clang/Basic/Sanitizers.def
index fa58a34..65ababd 100644
--- a/include/clang/Basic/Sanitizers.def
+++ b/include/clang/Basic/Sanitizers.def
@@ -82,8 +82,10 @@
SANITIZER("cfi-cast-strict", CFICastStrict)
SANITIZER("cfi-derived-cast", CFIDerivedCast)
SANITIZER("cfi-unrelated-cast", CFIUnrelatedCast)
-SANITIZER("cfi-vptr", CFIVptr)
-SANITIZER_GROUP("cfi", CFI, CFIDerivedCast | CFIUnrelatedCast | CFIVptr)
+SANITIZER("cfi-nvcall", CFINVCall)
+SANITIZER("cfi-vcall", CFIVCall)
+SANITIZER_GROUP("cfi", CFI,
+ CFIDerivedCast | CFIUnrelatedCast | CFINVCall | CFIVCall)
// -fsanitize=undefined-trap includes sanitizers from -fsanitize=undefined
// that can be used without runtime support, generally by providing extra
diff --git a/include/clang/Basic/SourceManager.h b/include/clang/Basic/SourceManager.h
index 4fa95c5..3aea5ea 100644
--- a/include/clang/Basic/SourceManager.h
+++ b/include/clang/Basic/SourceManager.h
@@ -82,7 +82,7 @@
/// \brief One instance of this struct is kept for every file loaded or used.
///
/// This object owns the MemoryBuffer object.
- class ContentCache {
+ class LLVM_ALIGNAS(8) ContentCache {
enum CCFlags {
/// \brief Whether the buffer is invalid.
InvalidFlag = 0x01,
@@ -90,15 +90,6 @@
DoNotFreeFlag = 0x02
};
- // Note that the first member of this class is an aligned character buffer
- // to ensure that this class has an alignment of 8 bytes. This wastes
- // 8 bytes for every ContentCache object, but each of these corresponds to
- // a file loaded into memory, so the 8 bytes doesn't seem terribly
- // important. It is quite awkward to fit this aligner into any other part
- // of the class due to the lack of portable ways to combine it with other
- // members.
- llvm::AlignedCharArray<8, 1> NonceAligner;
-
/// \brief The actual buffer containing the characters from the input
/// file.
///
@@ -142,14 +133,9 @@
/// \brief True if this content cache was initially created for a source
/// file considered as a system one.
unsigned IsSystemFile : 1;
-
- ContentCache(const FileEntry *Ent = nullptr)
- : Buffer(nullptr, false), OrigEntry(Ent), ContentsEntry(Ent),
- SourceLineCache(nullptr), NumLines(0), BufferOverridden(false),
- IsSystemFile(false) {
- (void)NonceAligner; // Silence warnings about unused member.
- }
-
+
+ ContentCache(const FileEntry *Ent = nullptr) : ContentCache(Ent, Ent) {}
+
ContentCache(const FileEntry *Ent, const FileEntry *contentEnt)
: Buffer(nullptr, false), OrigEntry(Ent), ContentsEntry(contentEnt),
SourceLineCache(nullptr), NumLines(0), BufferOverridden(false),
diff --git a/include/clang/Basic/SourceManagerInternals.h b/include/clang/Basic/SourceManagerInternals.h
index f31d604..27dea9f 100644
--- a/include/clang/Basic/SourceManagerInternals.h
+++ b/include/clang/Basic/SourceManagerInternals.h
@@ -88,17 +88,12 @@
/// at which they occur in the file).
std::map<FileID, std::vector<LineEntry> > LineEntries;
public:
- LineTableInfo() {
- }
-
void clear() {
FilenameIDs.clear();
FilenamesByID.clear();
LineEntries.clear();
}
- ~LineTableInfo() {}
-
unsigned getLineTableFilenameID(StringRef Str);
const char *getFilename(unsigned ID) const {
assert(ID < FilenamesByID.size() && "Invalid FilenameID");
diff --git a/include/clang/Basic/TargetBuiltins.h b/include/clang/Basic/TargetBuiltins.h
index e112c65..5c5d940 100644
--- a/include/clang/Basic/TargetBuiltins.h
+++ b/include/clang/Basic/TargetBuiltins.h
@@ -175,6 +175,15 @@
};
}
+ /// \brief SystemZ builtins
+ namespace SystemZ {
+ enum {
+ LastTIBuiltin = clang::Builtin::FirstTSBuiltin-1,
+#define BUILTIN(ID, TYPE, ATTRS) BI##ID,
+#include "clang/Basic/BuiltinsSystemZ.def"
+ LastTSBuiltin
+ };
+ }
} // end namespace clang.
#endif
diff --git a/include/clang/CodeGen/BackendUtil.h b/include/clang/CodeGen/BackendUtil.h
index 07c6183..8586e77 100644
--- a/include/clang/CodeGen/BackendUtil.h
+++ b/include/clang/CodeGen/BackendUtil.h
@@ -34,7 +34,7 @@
void EmitBackendOutput(DiagnosticsEngine &Diags, const CodeGenOptions &CGOpts,
const TargetOptions &TOpts, const LangOptions &LOpts,
StringRef TDesc, llvm::Module *M, BackendAction Action,
- raw_ostream *OS);
+ raw_pwrite_stream *OS);
}
#endif
diff --git a/include/clang/CodeGen/CodeGenAction.h b/include/clang/CodeGen/CodeGenAction.h
index f8fd561..264780d 100644
--- a/include/clang/CodeGen/CodeGenAction.h
+++ b/include/clang/CodeGen/CodeGenAction.h
@@ -45,7 +45,7 @@
void EndSourceFileAction() override;
public:
- ~CodeGenAction();
+ ~CodeGenAction() override;
/// setLinkModule - Set the link module to be used by this action. If a link
/// module is not provided, and CodeGenOptions::LinkBitcodeFile is non-empty,
diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td
index 6b785b4..12b4c65 100644
--- a/include/clang/Driver/CC1Options.td
+++ b/include/clang/Driver/CC1Options.td
@@ -403,6 +403,11 @@
HelpText<"Migrate source code">;
}
+def emit_llvm_uselists : Flag<["-"], "emit-llvm-uselists">,
+ HelpText<"Preserve order of LLVM use-lists when serializing">;
+def no_emit_llvm_uselists : Flag<["-"], "no-emit-llvm-uselists">,
+ HelpText<"Don't preserve order of LLVM use-lists when serializing">;
+
def mt_migrate_directory : Separate<["-"], "mt-migrate-directory">,
HelpText<"Directory for temporary files produced during ARC or ObjC migration">;
def arcmt_check : Flag<["-"], "arcmt-check">,
@@ -585,8 +590,6 @@
HelpText<"OpenCL only. Allow floating-point optimizations that assume arguments and results are not NaNs or +-Inf.">;
def cl_kernel_arg_info : Flag<["-"], "cl-kernel-arg-info">,
HelpText<"OpenCL only. Generate kernel argument metadata.">;
-def : Flag<["-"], "cl-no-signed-zeros">, Alias<fno_signed_zeros>,
- HelpText<"OpenCL only. Allow optimizations to ignore the signedness of the floating-point zero.">;
def cl_unsafe_math_optimizations : Flag<["-"], "cl-unsafe-math-optimizations">,
HelpText<"OpenCL only. Allow unsafe floating-point optimizations. Also implies -cl-no-signed-zeros and -cl-mad-enable">;
def cl_fast_relaxed_math : Flag<["-"], "cl-fast-relaxed-math">,
@@ -607,6 +610,9 @@
def fcuda_allow_host_calls_from_host_device : Flag<["-"],
"fcuda-allow-host-calls-from-host-device">,
HelpText<"Allow host device functions to call host functions">;
+def fcuda_disable_target_call_checks : Flag<["-"],
+ "fcuda-disable-target-call-checks">,
+ HelpText<"Disable all cross-target (host, device, etc.) call checks in CUDA">;
} // let Flags = [CC1Option]
diff --git a/include/clang/Driver/CLCompatOptions.td b/include/clang/Driver/CLCompatOptions.td
index 1d17fd6..e643c62 100644
--- a/include/clang/Driver/CLCompatOptions.td
+++ b/include/clang/Driver/CLCompatOptions.td
@@ -58,6 +58,11 @@
def _SLASH_D : CLJoinedOrSeparate<"D">, HelpText<"Define macro">,
MetaVarName<"<macro[=value]>">, Alias<D>;
def _SLASH_E : CLFlag<"E">, HelpText<"Preprocess to stdout">, Alias<E>;
+def _SLASH_fp_except : CLFlag<"fp:except">, HelpText<"">, Alias<ftrapping_math>;
+def _SLASH_fp_except_ : CLFlag<"fp:except-">, HelpText<"">, Alias<fno_trapping_math>;
+def _SLASH_fp_fast : CLFlag<"fp:fast">, HelpText<"">, Alias<ffast_math>;
+def _SLASH_fp_precise : CLFlag<"fp:precise">, HelpText<"">, Alias<fno_fast_math>;
+def _SLASH_fp_strict : CLFlag<"fp:strict">, HelpText<"">, Alias<fno_fast_math>;
def _SLASH_GR : CLFlag<"GR">, HelpText<"Enable emission of RTTI data">;
def _SLASH_GR_ : CLFlag<"GR-">, HelpText<"Disable emission of RTTI data">;
def _SLASH_GF_ : CLFlag<"GF-">, HelpText<"Disable string pooling">,
@@ -257,7 +262,6 @@
def _SLASH_FC : CLFlag<"FC">;
def _SLASH_F : CLFlag<"F">;
def _SLASH_Fm : CLJoined<"Fm">;
-def _SLASH_fp : CLJoined<"fp">;
def _SLASH_Fp : CLJoined<"Fp">;
def _SLASH_Fr : CLJoined<"Fr">;
def _SLASH_FR : CLJoined<"FR">;
diff --git a/include/clang/Driver/Job.h b/include/clang/Driver/Job.h
index b510676..bc7e3ec 100644
--- a/include/clang/Driver/Job.h
+++ b/include/clang/Driver/Job.h
@@ -175,7 +175,7 @@
public:
JobList();
- virtual ~JobList() {}
+ ~JobList() override {}
void Print(llvm::raw_ostream &OS, const char *Terminator,
bool Quote, CrashReportInfo *CrashInfo = nullptr) const override;
diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td
index 593969c..714943d 100644
--- a/include/clang/Driver/Options.td
+++ b/include/clang/Driver/Options.td
@@ -435,7 +435,8 @@
def fclasspath_EQ : Joined<["-"], "fclasspath=">, Group<f_Group>;
def fcolor_diagnostics : Flag<["-"], "fcolor-diagnostics">, Group<f_Group>,
Flags<[CoreOption, CC1Option]>, HelpText<"Use colors in diagnostics">;
-def fdiagnostics_color : Flag<["-"], "fdiagnostics-color">, Group<f_Group>;
+def fdiagnostics_color : Flag<["-"], "fdiagnostics-color">, Group<f_Group>,
+ Flags<[CoreOption, DriverOption]>;
def fdiagnostics_color_EQ : Joined<["-"], "fdiagnostics-color=">, Group<f_Group>;
def fansi_escape_codes : Flag<["-"], "fansi-escape-codes">, Group<f_Group>,
Flags<[CoreOption, CC1Option]>, HelpText<"Use ANSI escape codes for diagnostics">;
@@ -524,7 +525,7 @@
Group<f_clang_Group>,
HelpText<"Don't use blacklist file for sanitizers">;
def fsanitize_coverage : Joined<["-"], "fsanitize-coverage=">,
- Group<f_clang_Group>, Flags<[CC1Option]>,
+ Group<f_clang_Group>, Flags<[CC1Option, CoreOption]>,
HelpText<"Enable coverage instrumentation for Sanitizers">;
def fsanitize_memory_track_origins_EQ : Joined<["-"], "fsanitize-memory-track-origins=">,
Group<f_clang_Group>, Flags<[CC1Option]>,
@@ -561,7 +562,9 @@
Group<f_Group>;
def fassociative_math : Flag<["-"], "fassociative-math">, Group<f_Group>;
def fno_associative_math : Flag<["-"], "fno-associative-math">, Group<f_Group>;
-def freciprocal_math : Flag<["-"], "freciprocal-math">, Group<f_Group>;
+def freciprocal_math :
+ Flag<["-"], "freciprocal-math">, Group<f_Group>, Flags<[CC1Option]>,
+ HelpText<"Allow division operations to be reassociated">;
def fno_reciprocal_math : Flag<["-"], "fno-reciprocal-math">, Group<f_Group>;
def ffinite_math_only : Flag<["-"], "ffinite-math-only">, Group<f_Group>, Flags<[CC1Option]>;
def fno_finite_math_only : Flag<["-"], "fno-finite-math-only">, Group<f_Group>;
@@ -625,7 +628,7 @@
def flto : Flag<["-"], "flto">, Group<f_Group>;
def fno_lto : Flag<["-"], "fno-lto">, Group<f_Group>;
def fmacro_backtrace_limit_EQ : Joined<["-"], "fmacro-backtrace-limit=">,
- Group<f_Group>;
+ Group<f_Group>, Flags<[DriverOption, CoreOption]>;
def fmerge_all_constants : Flag<["-"], "fmerge-all-constants">, Group<f_Group>;
def fmessage_length_EQ : Joined<["-"], "fmessage-length=">, Group<f_Group>;
def fms_extensions : Flag<["-"], "fms-extensions">, Group<f_Group>, Flags<[CC1Option]>,
@@ -732,8 +735,10 @@
HelpText<"Disable implicit builtin knowledge of math functions">;
def fno_caret_diagnostics : Flag<["-"], "fno-caret-diagnostics">, Group<f_Group>,
Flags<[CC1Option]>;
-def fno_color_diagnostics : Flag<["-"], "fno-color-diagnostics">, Group<f_Group>;
-def fno_diagnostics_color : Flag<["-"], "fno-diagnostics-color">, Group<f_Group>;
+def fno_color_diagnostics : Flag<["-"], "fno-color-diagnostics">, Group<f_Group>,
+ Flags<[CoreOption, CC1Option]>;
+def fno_diagnostics_color : Flag<["-"], "fno-diagnostics-color">, Group<f_Group>,
+ Flags<[CoreOption, DriverOption]>;
def fno_common : Flag<["-"], "fno-common">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Compile common globals like normal definitions">;
def fno_constant_cfstrings : Flag<["-"], "fno-constant-cfstrings">, Group<f_Group>,
@@ -929,7 +934,8 @@
HelpText<"Enable optimizations based on the strict definition of an enum's "
"value range">;
def fstrict_overflow : Flag<["-"], "fstrict-overflow">, Group<f_Group>;
-def fsyntax_only : Flag<["-"], "fsyntax-only">, Flags<[DriverOption,CC1Option]>, Group<Action_Group>;
+def fsyntax_only : Flag<["-"], "fsyntax-only">,
+ Flags<[DriverOption,CoreOption,CC1Option]>, Group<Action_Group>;
def ftabstop_EQ : Joined<["-"], "ftabstop=">, Group<f_Group>;
def ftemplate_depth_EQ : Joined<["-"], "ftemplate-depth=">, Group<f_Group>;
def ftemplate_depth_ : Joined<["-"], "ftemplate-depth-">, Group<f_Group>;
@@ -1144,7 +1150,8 @@
def mfpmath_EQ : Joined<["-"], "mfpmath=">, Group<m_Group>;
def mfpu_EQ : Joined<["-"], "mfpu=">, Group<m_Group>;
def mhwdiv_EQ : Joined<["-"], "mhwdiv=">, Group<m_Group>;
-def mglobal_merge : Flag<["-"], "mglobal-merge">, Group<m_Group>;
+def mglobal_merge : Flag<["-"], "mglobal-merge">, Group<m_Group>, Flags<[CC1Option]>,
+ HelpText<"Enable merging of globals">;
def mhard_float : Flag<["-"], "mhard-float">, Group<m_Group>;
def miphoneos_version_min_EQ : Joined<["-"], "miphoneos-version-min=">, Group<m_Group>;
def mios_version_min_EQ : Joined<["-"], "mios-version-min=">,
@@ -1266,12 +1273,18 @@
Group<m_ppc_Features_Group>;
def mnopower8_crypto : Flag<["-"], "mno-crypto">,
Group<m_ppc_Features_Group>;
+def mdirect_move : Flag<["-"], "mdirect-move">,
+ Group<m_ppc_Features_Group>;
+def mnodirect_move : Flag<["-"], "mno-direct-move">,
+ Group<m_ppc_Features_Group>;
def mhtm : Flag<["-"], "mhtm">, Group<m_ppc_Features_Group>;
def mno_htm : Flag<["-"], "mno-htm">, Group<m_ppc_Features_Group>;
def mfprnd : Flag<["-"], "mfprnd">, Group<m_ppc_Features_Group>;
def mno_fprnd : Flag<["-"], "mno-fprnd">, Group<m_ppc_Features_Group>;
def mcmpb : Flag<["-"], "mcmpb">, Group<m_ppc_Features_Group>;
def mno_cmpb : Flag<["-"], "mno-cmpb">, Group<m_ppc_Features_Group>;
+def misel : Flag<["-"], "misel">, Group<m_ppc_Features_Group>;
+def mno_isel : Flag<["-"], "mno-isel">, Group<m_ppc_Features_Group>;
def mmfcrf : Flag<["-"], "mmfcrf">, Group<m_ppc_Features_Group>;
def mno_mfcrf : Flag<["-"], "mno-mfcrf">, Group<m_ppc_Features_Group>;
def mpopcntd : Flag<["-"], "mpopcntd">, Group<m_ppc_Features_Group>;
diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h
index 79adf59..238069d 100644
--- a/include/clang/Frontend/ASTUnit.h
+++ b/include/clang/Frontend/ASTUnit.h
@@ -484,8 +484,8 @@
}
};
friend class ConcurrencyCheck;
-
- ~ASTUnit();
+
+ ~ASTUnit() override;
bool isMainFileAST() const { return MainFileIsAST; }
diff --git a/include/clang/Frontend/CodeGenOptions.def b/include/clang/Frontend/CodeGenOptions.def
index 514716f..cd42c72 100644
--- a/include/clang/Frontend/CodeGenOptions.def
+++ b/include/clang/Frontend/CodeGenOptions.def
@@ -77,11 +77,11 @@
CODEGENOPT(FatalWarnings , 1, 0) ///< Set when -Wa,--fatal-warnings is
///< enabled.
CODEGENOPT(EnableSegmentedStacks , 1, 0) ///< Set when -fsplit-stack is enabled.
-CODEGENOPT(NoGlobalMerge , 1, 0) ///< Set when -mno-global-merge is enabled.
CODEGENOPT(NoImplicitFloat , 1, 0) ///< Set when -mno-implicit-float is enabled.
CODEGENOPT(NoInfsFPMath , 1, 0) ///< Assume FP arguments, results not +-Inf.
CODEGENOPT(NoSignedZeros , 1, 0) ///< Allow ignoring the signedness of FP zero
-CODEGENOPT(NoInline , 1, 0) ///< Set when -fno-inline is enabled.
+CODEGENOPT(ReciprocalMath , 1, 0) ///< Allow FP divisions to be reassociated.
+CODEGENOPT(NoInline , 1, 0) ///< Set when -fno-inline is enabled.
///< Disables use of the inline keyword.
CODEGENOPT(NoNaNsFPMath , 1, 0) ///< Assume FP arguments, results not NaN.
CODEGENOPT(NoZeroInitializedInBSS , 1, 0) ///< -fno-zero-initialized-in-bss.
@@ -145,6 +145,8 @@
CODEGENOPT(DebugColumnInfo, 1, 0) ///< Whether or not to use column information
///< in debug info.
+CODEGENOPT(EmitLLVMUseLists, 1, 0) ///< Control whether to serialize use-lists.
+
/// The user specified number of registers to be used for integral arguments,
/// or 0 if unspecified.
VALUE_CODEGENOPT(NumRegisterParameters, 32, 0)
diff --git a/include/clang/Frontend/CompilerInstance.h b/include/clang/Frontend/CompilerInstance.h
index ed01329..6251566 100644
--- a/include/clang/Frontend/CompilerInstance.h
+++ b/include/clang/Frontend/CompilerInstance.h
@@ -151,13 +151,21 @@
struct OutputFile {
std::string Filename;
std::string TempFilename;
- raw_ostream *OS;
+ std::unique_ptr<raw_ostream> OS;
OutputFile(const std::string &filename, const std::string &tempFilename,
- raw_ostream *os)
- : Filename(filename), TempFilename(tempFilename), OS(os) { }
+ std::unique_ptr<raw_ostream> OS)
+ : Filename(filename), TempFilename(tempFilename), OS(std::move(OS)) {}
+ OutputFile(OutputFile &&O)
+ : Filename(std::move(O.Filename)),
+ TempFilename(std::move(O.TempFilename)), OS(std::move(O.OS)) {}
};
+ /// If the output doesn't support seeking (terminal, pipe). we switch
+ /// the stream to a buffer_ostream. These are the buffer and the original
+ /// stream.
+ std::unique_ptr<llvm::raw_fd_ostream> NonSeekStream;
+
/// The list of active output files.
std::list<OutputFile> OutputFiles;
@@ -165,7 +173,7 @@
void operator=(const CompilerInstance &) = delete;
public:
explicit CompilerInstance(bool BuildingModule = false);
- ~CompilerInstance();
+ ~CompilerInstance() override;
/// @name High-Level Operations
/// {
@@ -518,7 +526,7 @@
/// addOutputFile - Add an output file onto the list of tracked output files.
///
/// \param OutFile - The output file info.
- void addOutputFile(const OutputFile &OutFile);
+ void addOutputFile(OutputFile &&OutFile);
/// clearOutputFiles - Clear the output file list, destroying the contained
/// output streams.
@@ -628,21 +636,19 @@
/// atomically replace the target output on success).
///
/// \return - Null on error.
- llvm::raw_fd_ostream *
- createDefaultOutputFile(bool Binary = true, StringRef BaseInput = "",
- StringRef Extension = "");
+ raw_pwrite_stream *createDefaultOutputFile(bool Binary = true,
+ StringRef BaseInput = "",
+ StringRef Extension = "");
/// Create a new output file and add it to the list of tracked output files,
/// optionally deriving the output path name.
///
/// \return - Null on error.
- llvm::raw_fd_ostream *
- createOutputFile(StringRef OutputPath,
- bool Binary, bool RemoveFileOnSignal,
- StringRef BaseInput,
- StringRef Extension,
- bool UseTemporary,
- bool CreateMissingDirectories = false);
+ raw_pwrite_stream *createOutputFile(StringRef OutputPath, bool Binary,
+ bool RemoveFileOnSignal,
+ StringRef BaseInput, StringRef Extension,
+ bool UseTemporary,
+ bool CreateMissingDirectories = false);
/// Create a new output file, optionally deriving the output path name.
///
@@ -669,7 +675,7 @@
/// stored here on success.
/// \param TempPathName [out] - If given, the temporary file path name
/// will be stored here on success.
- static llvm::raw_fd_ostream *
+ std::unique_ptr<raw_pwrite_stream>
createOutputFile(StringRef OutputPath, std::error_code &Error, bool Binary,
bool RemoveFileOnSignal, StringRef BaseInput,
StringRef Extension, bool UseTemporary,
diff --git a/include/clang/Frontend/DiagnosticRenderer.h b/include/clang/Frontend/DiagnosticRenderer.h
index 5becadf..84a0f50 100644
--- a/include/clang/Frontend/DiagnosticRenderer.h
+++ b/include/clang/Frontend/DiagnosticRenderer.h
@@ -155,8 +155,8 @@
DiagnosticNoteRenderer(const LangOptions &LangOpts,
DiagnosticOptions *DiagOpts)
: DiagnosticRenderer(LangOpts, DiagOpts) {}
-
- virtual ~DiagnosticNoteRenderer();
+
+ ~DiagnosticNoteRenderer() override;
void emitIncludeLocation(SourceLocation Loc, PresumedLoc PLoc,
const SourceManager &SM) override;
diff --git a/include/clang/Frontend/FrontendActions.h b/include/clang/Frontend/FrontendActions.h
index 850f87c..b150828 100644
--- a/include/clang/Frontend/FrontendActions.h
+++ b/include/clang/Frontend/FrontendActions.h
@@ -85,11 +85,10 @@
/// create the PCHGenerator instance returned by CreateASTConsumer.
///
/// \returns true if an error occurred, false otherwise.
- static bool ComputeASTConsumerArguments(CompilerInstance &CI,
- StringRef InFile,
- std::string &Sysroot,
- std::string &OutputFile,
- raw_ostream *&OS);
+ static raw_ostream *ComputeASTConsumerArguments(CompilerInstance &CI,
+ StringRef InFile,
+ std::string &Sysroot,
+ std::string &OutputFile);
};
class GenerateModuleAction : public ASTFrontendAction {
@@ -119,11 +118,10 @@
/// create the PCHGenerator instance returned by CreateASTConsumer.
///
/// \returns true if an error occurred, false otherwise.
- bool ComputeASTConsumerArguments(CompilerInstance &CI,
- StringRef InFile,
- std::string &Sysroot,
- std::string &OutputFile,
- raw_ostream *&OS);
+ raw_ostream *ComputeASTConsumerArguments(CompilerInstance &CI,
+ StringRef InFile,
+ std::string &Sysroot,
+ std::string &OutputFile);
};
class SyntaxOnlyAction : public ASTFrontendAction {
@@ -188,7 +186,7 @@
public:
ASTMergeAction(FrontendAction *AdaptedAction, ArrayRef<std::string> ASTFiles);
- virtual ~ASTMergeAction();
+ ~ASTMergeAction() override;
bool usesPreprocessorOnly() const override;
TranslationUnitKind getTranslationUnitKind() override;
diff --git a/include/clang/Frontend/MultiplexConsumer.h b/include/clang/Frontend/MultiplexConsumer.h
index 2553275..873af03 100644
--- a/include/clang/Frontend/MultiplexConsumer.h
+++ b/include/clang/Frontend/MultiplexConsumer.h
@@ -30,7 +30,7 @@
public:
// Takes ownership of the pointers in C.
MultiplexConsumer(std::vector<std::unique_ptr<ASTConsumer>> C);
- ~MultiplexConsumer();
+ ~MultiplexConsumer() override;
// ASTConsumer
void Initialize(ASTContext &Context) override;
diff --git a/include/clang/Frontend/TextDiagnostic.h b/include/clang/Frontend/TextDiagnostic.h
index 42c78af..d41f15a 100644
--- a/include/clang/Frontend/TextDiagnostic.h
+++ b/include/clang/Frontend/TextDiagnostic.h
@@ -40,8 +40,8 @@
const LangOptions &LangOpts,
DiagnosticOptions *DiagOpts);
- virtual ~TextDiagnostic();
-
+ ~TextDiagnostic() override;
+
/// \brief Print the diagonstic level to a raw_ostream.
///
/// This is a static helper that handles colorizing the level and formatting
diff --git a/include/clang/Frontend/TextDiagnosticPrinter.h b/include/clang/Frontend/TextDiagnosticPrinter.h
index f8a71fe..04a5705 100644
--- a/include/clang/Frontend/TextDiagnosticPrinter.h
+++ b/include/clang/Frontend/TextDiagnosticPrinter.h
@@ -40,7 +40,7 @@
public:
TextDiagnosticPrinter(raw_ostream &os, DiagnosticOptions *diags,
bool OwnsOutputStream = false);
- virtual ~TextDiagnosticPrinter();
+ ~TextDiagnosticPrinter() override;
/// setPrefix - Set the diagnostic printer prefix string, which will be
/// printed at the start of any diagnostics. If empty, no prefix string is
diff --git a/include/clang/Frontend/Utils.h b/include/clang/Frontend/Utils.h
index 4cd93b9..cd0ebf6 100644
--- a/include/clang/Frontend/Utils.h
+++ b/include/clang/Frontend/Utils.h
@@ -159,9 +159,8 @@
StringRef OutputPath = "",
bool ShowDepth = true, bool MSStyle = false);
-/// CacheTokens - Cache tokens for use with PCH. Note that this requires
-/// a seekable stream.
-void CacheTokens(Preprocessor &PP, llvm::raw_fd_ostream* OS);
+/// Cache tokens for use with PCH. Note that this requires a seekable stream.
+void CacheTokens(Preprocessor &PP, raw_pwrite_stream *OS);
/// The ChainedIncludesSource class converts headers to chained PCHs in
/// memory, mainly for testing.
diff --git a/include/clang/Frontend/VerifyDiagnosticConsumer.h b/include/clang/Frontend/VerifyDiagnosticConsumer.h
index aa0bcc9..475f07f 100644
--- a/include/clang/Frontend/VerifyDiagnosticConsumer.h
+++ b/include/clang/Frontend/VerifyDiagnosticConsumer.h
@@ -246,7 +246,7 @@
/// the currently-attached diagnostic client when a diagnostic does not match
/// what is expected (as indicated in the source file).
VerifyDiagnosticConsumer(DiagnosticsEngine &Diags);
- ~VerifyDiagnosticConsumer();
+ ~VerifyDiagnosticConsumer() override;
void BeginSourceFile(const LangOptions &LangOpts,
const Preprocessor *PP) override;
diff --git a/include/clang/Lex/LiteralSupport.h b/include/clang/Lex/LiteralSupport.h
index f60a152..5210e3f 100644
--- a/include/clang/Lex/LiteralSupport.h
+++ b/include/clang/Lex/LiteralSupport.h
@@ -57,13 +57,13 @@
NumericLiteralParser(StringRef TokSpelling,
SourceLocation TokLoc,
Preprocessor &PP);
- bool hadError;
- bool isUnsigned;
- bool isLong; // This is *not* set for long long.
- bool isLongLong;
- bool isFloat; // 1.0f
- bool isImaginary; // 1.0i
- uint8_t MicrosoftInteger; // Microsoft suffix extension i8, i16, i32, or i64.
+ bool hadError : 1;
+ bool isUnsigned : 1;
+ bool isLong : 1; // This is *not* set for long long.
+ bool isLongLong : 1;
+ bool isFloat : 1; // 1.0f
+ bool isImaginary : 1; // 1.0i
+ uint8_t MicrosoftInteger; // Microsoft suffix extension i8, i16, i32, or i64.
bool isIntegerLiteral() const {
return !saw_period && !saw_exponent;
diff --git a/include/clang/Lex/MacroArgs.h b/include/clang/Lex/MacroArgs.h
index d858ec2..243b143 100644
--- a/include/clang/Lex/MacroArgs.h
+++ b/include/clang/Lex/MacroArgs.h
@@ -56,7 +56,8 @@
MacroArgs(unsigned NumToks, bool varargsElided)
: NumUnexpArgTokens(NumToks), VarargsElided(varargsElided),
ArgCache(nullptr) {}
- ~MacroArgs() {}
+ ~MacroArgs() = default;
+
public:
/// MacroArgs ctor function - Create a new MacroArgs object with the specified
/// macro and argument info.
diff --git a/include/clang/Lex/MacroInfo.h b/include/clang/Lex/MacroInfo.h
index 8a113cb..253e662 100644
--- a/include/clang/Lex/MacroInfo.h
+++ b/include/clang/Lex/MacroInfo.h
@@ -109,7 +109,7 @@
// Only the Preprocessor gets to create and destroy these.
MacroInfo(SourceLocation DefLoc);
- ~MacroInfo() {}
+ ~MacroInfo() = default;
public:
/// \brief Return the location that the macro was defined at.
diff --git a/include/clang/Lex/PTHLexer.h b/include/clang/Lex/PTHLexer.h
index 75abf6b..904be79 100644
--- a/include/clang/Lex/PTHLexer.h
+++ b/include/clang/Lex/PTHLexer.h
@@ -64,8 +64,7 @@
PTHLexer(Preprocessor& pp, FileID FID, const unsigned char *D,
const unsigned char* ppcond, PTHManager &PM);
public:
-
- ~PTHLexer() {}
+ ~PTHLexer() override {}
/// Lex - Return the next token.
bool Lex(Token &Tok);
diff --git a/include/clang/Lex/PTHManager.h b/include/clang/Lex/PTHManager.h
index e36d3dd..a4198f8 100644
--- a/include/clang/Lex/PTHManager.h
+++ b/include/clang/Lex/PTHManager.h
@@ -113,7 +113,7 @@
// The current PTH version.
enum { Version = 10 };
- ~PTHManager();
+ ~PTHManager() override;
/// getOriginalSourceFile - Return the full path to the original header
/// file name that was used to generate the PTH cache.
diff --git a/include/clang/Lex/Pragma.h b/include/clang/Lex/Pragma.h
index 4123bae..70fcfda 100644
--- a/include/clang/Lex/Pragma.h
+++ b/include/clang/Lex/Pragma.h
@@ -93,7 +93,7 @@
llvm::StringMap<PragmaHandler*> Handlers;
public:
explicit PragmaNamespace(StringRef Name) : PragmaHandler(Name) {}
- virtual ~PragmaNamespace();
+ ~PragmaNamespace() override;
/// FindHandler - Check to see if there is already a handler for the
/// specified name. If not, return the handler for the null name if it
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index 0352c64..f4487c1 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -235,7 +235,7 @@
public:
Parser(Preprocessor &PP, Sema &Actions, bool SkipFunctionBodies);
- ~Parser();
+ ~Parser() override;
const LangOptions &getLangOpts() const { return PP.getLangOpts(); }
const TargetInfo &getTargetInfo() const { return PP.getTargetInfo(); }
@@ -887,7 +887,7 @@
class LateParsedClass : public LateParsedDeclaration {
public:
LateParsedClass(Parser *P, ParsingClass *C);
- virtual ~LateParsedClass();
+ ~LateParsedClass() override;
void ParseLexedMethodDeclarations() override;
void ParseLexedMemberInitializers() override;
diff --git a/include/clang/Rewrite/Frontend/FixItRewriter.h b/include/clang/Rewrite/Frontend/FixItRewriter.h
index 5994172..ad828e5 100644
--- a/include/clang/Rewrite/Frontend/FixItRewriter.h
+++ b/include/clang/Rewrite/Frontend/FixItRewriter.h
@@ -86,7 +86,7 @@
const LangOptions &LangOpts, FixItOptions *FixItOpts);
/// \brief Destroy the fix-it rewriter.
- ~FixItRewriter();
+ ~FixItRewriter() override;
/// \brief Check whether there are modifications for a given file.
bool IsModified(FileID ID) const {
diff --git a/include/clang/Rewrite/Frontend/FrontendActions.h b/include/clang/Rewrite/Frontend/FrontendActions.h
index c8ea8b2..6c290e4 100644
--- a/include/clang/Rewrite/Frontend/FrontendActions.h
+++ b/include/clang/Rewrite/Frontend/FrontendActions.h
@@ -43,7 +43,7 @@
public:
FixItAction();
- ~FixItAction();
+ ~FixItAction() override;
};
/// \brief Emits changes to temporary files and uses them for the original
diff --git a/include/clang/Sema/CodeCompleteConsumer.h b/include/clang/Sema/CodeCompleteConsumer.h
index d24a925..de65c43 100644
--- a/include/clang/Sema/CodeCompleteConsumer.h
+++ b/include/clang/Sema/CodeCompleteConsumer.h
@@ -449,7 +449,7 @@
const char **Annotations, unsigned NumAnnotations,
StringRef ParentName,
const char *BriefComment);
- ~CodeCompletionString() { }
+ ~CodeCompletionString() = default;
friend class CodeCompletionBuilder;
friend class CodeCompletionResult;
diff --git a/include/clang/Sema/DeclSpec.h b/include/clang/Sema/DeclSpec.h
index 03c3427..de39d83 100644
--- a/include/clang/Sema/DeclSpec.h
+++ b/include/clang/Sema/DeclSpec.h
@@ -1415,7 +1415,8 @@
static DeclaratorChunk getPointer(unsigned TypeQuals, SourceLocation Loc,
SourceLocation ConstQualLoc,
SourceLocation VolatileQualLoc,
- SourceLocation RestrictQualLoc) {
+ SourceLocation RestrictQualLoc,
+ SourceLocation AtomicQualLoc) {
DeclaratorChunk I;
I.Kind = Pointer;
I.Loc = Loc;
@@ -1423,6 +1424,7 @@
I.Ptr.ConstQualLoc = ConstQualLoc.getRawEncoding();
I.Ptr.VolatileQualLoc = VolatileQualLoc.getRawEncoding();
I.Ptr.RestrictQualLoc = RestrictQualLoc.getRawEncoding();
+ I.Ptr.AtomicQualLoc = AtomicQualLoc.getRawEncoding();
I.Ptr.AttrList = nullptr;
return I;
}
diff --git a/include/clang/Sema/ExternalSemaSource.h b/include/clang/Sema/ExternalSemaSource.h
index 430cef7..de4672f 100644
--- a/include/clang/Sema/ExternalSemaSource.h
+++ b/include/clang/Sema/ExternalSemaSource.h
@@ -55,7 +55,7 @@
ExternalASTSource::SemaSource = true;
}
- ~ExternalSemaSource();
+ ~ExternalSemaSource() override;
/// \brief Initialize the semantic source with the Sema instance
/// being used to perform semantic analysis on the abstract syntax
diff --git a/include/clang/Sema/MultiplexExternalSemaSource.h b/include/clang/Sema/MultiplexExternalSemaSource.h
index 5f71789..16646ba 100644
--- a/include/clang/Sema/MultiplexExternalSemaSource.h
+++ b/include/clang/Sema/MultiplexExternalSemaSource.h
@@ -51,7 +51,7 @@
///
MultiplexExternalSemaSource(ExternalSemaSource& s1, ExternalSemaSource& s2);
- ~MultiplexExternalSemaSource();
+ ~MultiplexExternalSemaSource() override;
///\brief Appends new source to the source list.
///
diff --git a/include/clang/Sema/ScopeInfo.h b/include/clang/Sema/ScopeInfo.h
index ec8e56b..504fe87 100644
--- a/include/clang/Sema/ScopeInfo.h
+++ b/include/clang/Sema/ScopeInfo.h
@@ -568,7 +568,7 @@
Kind = SK_Block;
}
- virtual ~BlockScopeInfo();
+ ~BlockScopeInfo() override;
static bool classof(const FunctionScopeInfo *FSI) {
return FSI->Kind == SK_Block;
@@ -599,7 +599,7 @@
Kind = SK_CapturedRegion;
}
- virtual ~CapturedRegionScopeInfo();
+ ~CapturedRegionScopeInfo() override;
/// \brief A descriptive name for the kind of captured region this is.
StringRef getRegionName() const {
@@ -698,13 +698,13 @@
LambdaScopeInfo(DiagnosticsEngine &Diag)
: CapturingScopeInfo(Diag, ImpCap_None), Lambda(nullptr),
CallOperator(nullptr), NumExplicitCaptures(0), Mutable(false),
- ExprNeedsCleanups(false), ContainsUnexpandedParameterPack(false),
- AutoTemplateParameterDepth(0), GLTemplateParameterList(nullptr)
- {
+ ExplicitParams(false), ExprNeedsCleanups(false),
+ ContainsUnexpandedParameterPack(false), AutoTemplateParameterDepth(0),
+ GLTemplateParameterList(nullptr) {
Kind = SK_Lambda;
}
- virtual ~LambdaScopeInfo();
+ ~LambdaScopeInfo() override;
/// \brief Note when all explicit captures have been added.
void finishedExplicitCaptures() {
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 88217b9..84302fa 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -1282,6 +1282,10 @@
/// 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(const NamedDecl *D) {
+ NamedDecl *Hidden;
+ return hasVisibleDefinition(const_cast<NamedDecl*>(D), &Hidden);
+ }
bool RequireCompleteType(SourceLocation Loc, QualType T,
TypeDiagnoser &Diagnoser);
@@ -2904,7 +2908,7 @@
/// optionally warns if there are multiple signatures.
ObjCMethodDecl *LookupMethodInGlobalPool(Selector Sel, SourceRange R,
bool receiverIdOrClass,
- bool warn, bool instance);
+ bool instance);
public:
/// \brief - Returns instance or factory methods in global method pool for
@@ -2914,8 +2918,13 @@
SmallVectorImpl<ObjCMethodDecl*>& Methods,
bool instance);
- bool AreMultipleMethodsInGlobalPool(Selector Sel,
- bool instance);
+ bool AreMultipleMethodsInGlobalPool(Selector Sel, ObjCMethodDecl *BestMethod,
+ SourceRange R,
+ bool receiverIdOrClass);
+
+ void DiagnoseMultipleMethodInGlobalPool(SmallVectorImpl<ObjCMethodDecl*> &Methods,
+ Selector Sel, SourceRange R,
+ bool receiverIdOrClass);
private:
/// \brief - Returns a selector which best matches given argument list or
@@ -2953,19 +2962,17 @@
/// LookupInstanceMethodInGlobalPool - Returns the method and warns if
/// there are multiple signatures.
ObjCMethodDecl *LookupInstanceMethodInGlobalPool(Selector Sel, SourceRange R,
- bool receiverIdOrClass=false,
- bool warn=true) {
+ bool receiverIdOrClass=false) {
return LookupMethodInGlobalPool(Sel, R, receiverIdOrClass,
- warn, /*instance*/true);
+ /*instance*/true);
}
/// LookupFactoryMethodInGlobalPool - Returns the method and warns if
/// there are multiple signatures.
ObjCMethodDecl *LookupFactoryMethodInGlobalPool(Selector Sel, SourceRange R,
- bool receiverIdOrClass=false,
- bool warn=true) {
+ bool receiverIdOrClass=false) {
return LookupMethodInGlobalPool(Sel, R, receiverIdOrClass,
- warn, /*instance*/false);
+ /*instance*/false);
}
const ObjCMethodDecl *SelectorsForTypoCorrection(Selector Sel,
@@ -7425,6 +7432,13 @@
/// \brief Initialization of captured region for OpenMP region.
void ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope);
+ /// \brief End of OpenMP region.
+ ///
+ /// \param S Statement associated with the current OpenMP region.
+ /// \param Clauses List of clauses for the current OpenMP region.
+ ///
+ /// \returns Statement for finished OpenMP region.
+ StmtResult ActOnOpenMPRegionEnd(StmtResult S, ArrayRef<OMPClause *> Clauses);
StmtResult ActOnOpenMPExecutableDirective(OpenMPDirectiveKind Kind,
const DeclarationNameInfo &DirName,
ArrayRef<OMPClause *> Clauses,
@@ -8454,8 +8468,10 @@
bool CheckAArch64BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
bool CheckMipsBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
+ bool CheckSystemZBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
bool CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
-
+ bool CheckPPCBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
+
bool SemaBuiltinVAStart(CallExpr *TheCall);
bool SemaBuiltinVAStartARM(CallExpr *Call);
bool SemaBuiltinUnorderedCompare(CallExpr *TheCall);
diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h
index c7c0c8c..8637000 100644
--- a/include/clang/Serialization/ASTBitCodes.h
+++ b/include/clang/Serialization/ASTBitCodes.h
@@ -543,9 +543,7 @@
/// macro definition.
MACRO_OFFSET = 47,
- /// \brief Mapping table from the identifier ID to the offset of the
- /// macro directive history for the identifier.
- MACRO_TABLE = 48,
+ // ID 48 used to be a table of macros.
/// \brief Record code for undefined but used functions and variables that
/// need a definition in this TU.
diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h
index f8366f7..3b3ae02 100644
--- a/include/clang/Serialization/ASTReader.h
+++ b/include/clang/Serialization/ASTReader.h
@@ -1323,7 +1323,7 @@
bool ValidateSystemInputs = false,
bool UseGlobalIndex = true);
- ~ASTReader();
+ ~ASTReader() override;
SourceManager &getSourceManager() const { return SourceMgr; }
FileManager &getFileManager() const { return FileMgr; }
diff --git a/include/clang/Serialization/ASTWriter.h b/include/clang/Serialization/ASTWriter.h
index d7a801d..bb2e554 100644
--- a/include/clang/Serialization/ASTWriter.h
+++ b/include/clang/Serialization/ASTWriter.h
@@ -559,7 +559,7 @@
/// \brief Create a new precompiled header writer that outputs to
/// the given bitstream.
ASTWriter(llvm::BitstreamWriter &Stream);
- ~ASTWriter();
+ ~ASTWriter() override;
const LangOptions &getLangOpts() const;
@@ -882,7 +882,7 @@
clang::Module *Module,
StringRef isysroot, raw_ostream *Out,
bool AllowASTWithErrors = false);
- ~PCHGenerator();
+ ~PCHGenerator() override;
void InitializeSema(Sema &S) override { SemaPtr = &S; }
void HandleTranslationUnit(ASTContext &Ctx) override;
ASTMutationListener *GetASTMutationListener() override;
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
index 8f8036e..308ac83 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
@@ -492,7 +492,7 @@
GRBugReporter(BugReporterData& d, ExprEngine& eng)
: BugReporter(d, GRBugReporterKind), Eng(eng) {}
- virtual ~GRBugReporter();
+ ~GRBugReporter() override;
/// getEngine - Return the analysis engine used to analyze a given
/// function or method.
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
index a5a9834..941d524 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
@@ -366,7 +366,7 @@
PathDiagnosticPiece(Kind k, DisplayHint hint = Below);
public:
- virtual ~PathDiagnosticPiece();
+ ~PathDiagnosticPiece() override;
StringRef getString() const { return str; }
@@ -482,7 +482,7 @@
public:
StackHintGeneratorForSymbol(SymbolRef S, StringRef M) : Sym(S), Msg(M) {}
- virtual ~StackHintGeneratorForSymbol() {}
+ ~StackHintGeneratorForSymbol() override {}
/// \brief Search the call expression for the symbol Sym and dispatch the
/// 'getMessageForX()' methods to construct a specific message.
@@ -515,7 +515,7 @@
: PathDiagnosticSpotPiece(pos, s, Event, addPosRange),
CallStackHint(stackHint) {}
- ~PathDiagnosticEventPiece();
+ ~PathDiagnosticEventPiece() override;
/// Mark the diagnostic piece as being potentially prunable. This
/// flag may have been previously set, at which point it will not
@@ -574,9 +574,9 @@
PathDiagnosticLocation callEnterWithin;
PathDiagnosticLocation callReturn;
PathPieces path;
-
- virtual ~PathDiagnosticCallPiece();
-
+
+ ~PathDiagnosticCallPiece() override;
+
const Decl *getCaller() const { return Caller; }
const Decl *getCallee() const { return Callee; }
@@ -635,7 +635,7 @@
LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
}
- ~PathDiagnosticControlFlowPiece();
+ ~PathDiagnosticControlFlowPiece() override;
PathDiagnosticLocation getStartLocation() const {
assert(!LPairs.empty() &&
@@ -690,7 +690,7 @@
PathDiagnosticMacroPiece(const PathDiagnosticLocation &pos)
: PathDiagnosticSpotPiece(pos, "", Macro) {}
- ~PathDiagnosticMacroPiece();
+ ~PathDiagnosticMacroPiece() override;
PathPieces subPieces;
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h
index dbc59cf..3e0913e 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h
@@ -55,8 +55,8 @@
AnalyzerOptions &Options,
CodeInjector* injector = nullptr);
- ~AnalysisManager();
-
+ ~AnalysisManager() override;
+
void ClearContexts() {
AnaCtxMgr.clear();
}
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
index 77b8f2a..d5822e2 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
@@ -367,7 +367,7 @@
EnclosingBldr->takeNodes(*I);
}
- virtual ~StmtNodeBuilder();
+ ~StmtNodeBuilder() override;
using NodeBuilder::generateNode;
using NodeBuilder::generateSink;
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h b/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h
index ba9715b..cc3779d 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h
@@ -106,7 +106,6 @@
public:
EnvironmentManager(llvm::BumpPtrAllocator& Allocator) : F(Allocator) {}
- ~EnvironmentManager() {}
Environment getInitialEnvironment() {
return Environment(F.getEmptyMap());
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
index c4eabb8..cfb1b92 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
@@ -127,8 +127,6 @@
: Location(loc), State(state), Succs(IsSink) {
assert(isSink() == IsSink);
}
-
- ~ExplodedNode() {}
/// getLocation - Returns the edge associated with the given node.
ProgramPoint getLocation() const { return Location; }
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
index 247bf0c..d8f1c34 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
@@ -102,7 +102,7 @@
FunctionSummariesTy *FS,
InliningModes HowToInlineIn);
- ~ExprEngine();
+ ~ExprEngine() override;
/// Returns true if there is still simulation state on the worklist.
bool ExecuteWorkList(const LocationContext *L, unsigned Steps = 150000) {
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
index 1be7a26..4f07129 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
@@ -609,7 +609,7 @@
AnalysisDeclContext *getAnalysisDeclContext() const { return AC; }
- virtual void dumpToStream(raw_ostream &os) const override;
+ void dumpToStream(raw_ostream &os) const override;
void Profile(llvm::FoldingSetNodeID& ID) const override;
@@ -704,7 +704,7 @@
};
/// SymbolicRegion - A special, "non-concrete" region. Unlike other region
-/// clases, SymbolicRegion represents a region that serves as an alias for
+/// classes, SymbolicRegion represents a region that serves as an alias for
/// either a real region, a NULL pointer, etc. It essentially is used to
/// map the concept of symbolic values into the domain of regions. Symbolic
/// regions do not need to be typed.
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
index fbeaae4..1ca96a2 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
@@ -109,7 +109,7 @@
SymbolData(Kind k, SymbolID sym) : SymExpr(k), Sym(sym) {}
public:
- virtual ~SymbolData() {}
+ ~SymbolData() override {}
SymbolID getSymbolID() const { return Sym; }
@@ -589,8 +589,6 @@
: LCtx(Ctx), Loc(s), SymMgr(symmgr),
reapedStore(nullptr, storeMgr) {}
- ~SymbolReaper() {}
-
const LocationContext *getLocationContext() const { return LCtx; }
bool isLive(SymbolRef sym);
diff --git a/include/clang/Tooling/CompilationDatabase.h b/include/clang/Tooling/CompilationDatabase.h
index 27c1652..e5b95af 100644
--- a/include/clang/Tooling/CompilationDatabase.h
+++ b/include/clang/Tooling/CompilationDatabase.h
@@ -178,7 +178,7 @@
/// \param Argv Points to the command line arguments.
/// \param Directory The base directory used in the FixedCompilationDatabase.
static FixedCompilationDatabase *loadFromCommandLine(int &Argc,
- const char **Argv,
+ const char *const *Argv,
Twine Directory = ".");
/// \brief Constructs a compilation data base from a specified directory
diff --git a/include/clang/Tooling/Tooling.h b/include/clang/Tooling/Tooling.h
index 393cc1d..ca187b1 100644
--- a/include/clang/Tooling/Tooling.h
+++ b/include/clang/Tooling/Tooling.h
@@ -40,6 +40,7 @@
#include "clang/Tooling/CompilationDatabase.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/Twine.h"
+#include "llvm/Option/Option.h"
#include <memory>
#include <string>
#include <vector>
@@ -78,7 +79,7 @@
/// process each translation unit.
class FrontendActionFactory : public ToolAction {
public:
- virtual ~FrontendActionFactory();
+ ~FrontendActionFactory() override;
/// \brief Invokes the compiler with a FrontendAction created by create().
bool runInvocation(clang::CompilerInvocation *Invocation, FileManager *Files,
@@ -383,6 +384,11 @@
/// \param File Either an absolute or relative path.
std::string getAbsolutePath(StringRef File);
+/// \brief Creates a \c CompilerInvocation.
+clang::CompilerInvocation *newInvocation(
+ clang::DiagnosticsEngine *Diagnostics,
+ const llvm::opt::ArgStringList &CC1Args);
+
} // end namespace tooling
} // end namespace clang
diff --git a/include/clang/module.modulemap b/include/clang/module.modulemap
index 29fa008..196a1fd 100644
--- a/include/clang/module.modulemap
+++ b/include/clang/module.modulemap
@@ -34,6 +34,7 @@
textual header "Basic/BuiltinsNVPTX.def"
textual header "Basic/BuiltinsPPC.def"
textual header "Basic/BuiltinsR600.def"
+ textual header "Basic/BuiltinsSystemZ.def"
textual header "Basic/BuiltinsX86.def"
textual header "Basic/BuiltinsXCore.def"
textual header "Basic/DiagnosticOptions.def"
diff --git a/lib/ARCMigrate/ARCMT.cpp b/lib/ARCMigrate/ARCMT.cpp
index dddc886..0a61cfe 100644
--- a/lib/ARCMigrate/ARCMT.cpp
+++ b/lib/ARCMigrate/ARCMT.cpp
@@ -124,7 +124,7 @@
}
}
- virtual ~CaptureDiagnosticConsumer() {
+ ~CaptureDiagnosticConsumer() override {
assert(!HasBegunSourceFile && "FinishCapture not called!");
}
@@ -465,7 +465,7 @@
if (Listener)
Listener->start(ctx);
}
- ~RewritesApplicator() {
+ ~RewritesApplicator() override {
if (Listener)
Listener->finish();
}
diff --git a/lib/ARCMigrate/ObjCMT.cpp b/lib/ARCMigrate/ObjCMT.cpp
index 38ff72a..9e7be20 100644
--- a/lib/ARCMigrate/ObjCMT.cpp
+++ b/lib/ARCMigrate/ObjCMT.cpp
@@ -48,7 +48,7 @@
};
void migrateDecl(Decl *D);
- void migrateObjCInterfaceDecl(ASTContext &Ctx, ObjCContainerDecl *D);
+ void migrateObjCContainerDecl(ASTContext &Ctx, ObjCContainerDecl *D);
void migrateProtocolConformance(ASTContext &Ctx,
const ObjCImplementationDecl *ImpDecl);
void CacheObjCNSIntegerTypedefed(const TypedefDecl *TypedefDcl);
@@ -578,7 +578,7 @@
return false;
}
-void ObjCMigrateASTConsumer::migrateObjCInterfaceDecl(ASTContext &Ctx,
+void ObjCMigrateASTConsumer::migrateObjCContainerDecl(ASTContext &Ctx,
ObjCContainerDecl *D) {
if (D->isDeprecated() || IsCategoryNameWithDeprecatedSuffix(D))
return;
@@ -1790,9 +1790,7 @@
: SourceMgr(SM), OS(OS) {
OS << "[\n";
}
- ~JSONEditWriter() {
- OS << "]\n";
- }
+ ~JSONEditWriter() override { OS << "]\n"; }
private:
struct EntryWriter {
@@ -1876,13 +1874,16 @@
if (ObjCInterfaceDecl *CDecl = dyn_cast<ObjCInterfaceDecl>(*D))
if (canModify(CDecl))
- migrateObjCInterfaceDecl(Ctx, CDecl);
+ migrateObjCContainerDecl(Ctx, CDecl);
if (ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(*D)) {
if (canModify(CatDecl))
- migrateObjCInterfaceDecl(Ctx, CatDecl);
+ migrateObjCContainerDecl(Ctx, CatDecl);
}
- else if (ObjCProtocolDecl *PDecl = dyn_cast<ObjCProtocolDecl>(*D))
+ else if (ObjCProtocolDecl *PDecl = dyn_cast<ObjCProtocolDecl>(*D)) {
ObjCProtocolDecls.insert(PDecl->getCanonicalDecl());
+ if (canModify(PDecl))
+ migrateObjCContainerDecl(Ctx, PDecl);
+ }
else if (const ObjCImplementationDecl *ImpDecl =
dyn_cast<ObjCImplementationDecl>(*D)) {
if ((ASTMigrateActions & FrontendOptions::ObjCMT_ProtocolConformance) &&
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 57621a7..899f8c5 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -3358,7 +3358,7 @@
(void)CheckT;
}
- T = new (*this) ElaboratedType(Keyword, NNS, NamedType, Canon);
+ T = new (*this, TypeAlignment) ElaboratedType(Keyword, NNS, NamedType, Canon);
Types.push_back(T);
ElaboratedTypes.InsertNode(T, InsertPos);
return QualType(T, 0);
@@ -3382,7 +3382,7 @@
(void)CheckT;
}
- T = new (*this) ParenType(InnerType, Canon);
+ T = new (*this, TypeAlignment) ParenType(InnerType, Canon);
Types.push_back(T);
ParenTypes.InsertNode(T, InsertPos);
return QualType(T, 0);
@@ -3411,7 +3411,7 @@
if (T)
return QualType(T, 0);
- T = new (*this) DependentNameType(Keyword, NNS, Name, Canon);
+ T = new (*this, TypeAlignment) DependentNameType(Keyword, NNS, Name, Canon);
Types.push_back(T);
DependentNameTypes.InsertNode(T, InsertPos);
return QualType(T, 0);
@@ -3513,7 +3513,8 @@
}
}
- T = new (*this) PackExpansionType(Pattern, Canon, NumExpansions);
+ T = new (*this, TypeAlignment)
+ PackExpansionType(Pattern, Canon, NumExpansions);
Types.push_back(T);
PackExpansionTypes.InsertNode(T, InsertPos);
return QualType(T, 0);
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index 2442e8e..eb9b00a 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -67,6 +67,7 @@
// FIXME: DependentDecltypeType
QualType VisitRecordType(const RecordType *T);
QualType VisitEnumType(const EnumType *T);
+ QualType VisitAttributedType(const AttributedType *T);
// FIXME: TemplateTypeParmType
// FIXME: SubstTemplateTypeParmType
QualType VisitTemplateSpecializationType(const TemplateSpecializationType *T);
@@ -1724,6 +1725,27 @@
return Importer.getToContext().getTagDeclType(ToDecl);
}
+QualType ASTNodeImporter::VisitAttributedType(const AttributedType *T) {
+ QualType FromModifiedType = T->getModifiedType();
+ QualType FromEquivalentType = T->getEquivalentType();
+ QualType ToModifiedType;
+ QualType ToEquivalentType;
+
+ if (!FromModifiedType.isNull()) {
+ ToModifiedType = Importer.Import(FromModifiedType);
+ if (ToModifiedType.isNull())
+ return QualType();
+ }
+ if (!FromEquivalentType.isNull()) {
+ ToEquivalentType = Importer.Import(FromEquivalentType);
+ if (ToEquivalentType.isNull())
+ return QualType();
+ }
+
+ return Importer.getToContext().getAttributedType(T->getAttrKind(),
+ ToModifiedType, ToEquivalentType);
+}
+
QualType ASTNodeImporter::VisitTemplateSpecializationType(
const TemplateSpecializationType *T) {
TemplateName ToTemplate = Importer.Import(T->getTemplateName());
diff --git a/lib/AST/CommentLexer.cpp b/lib/AST/CommentLexer.cpp
index 06a08bd..98b7e36 100644
--- a/lib/AST/CommentLexer.cpp
+++ b/lib/AST/CommentLexer.cpp
@@ -514,6 +514,12 @@
if (CommentState == LCS_InsideCComment)
skipLineStartingDecorations();
+ if (BufferPtr == CommentEnd) {
+ formTokenWithChars(T, BufferPtr, tok::verbatim_block_line);
+ T.setVerbatimBlockText("");
+ return;
+ }
+
lexVerbatimBlockFirstLine(T);
}
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index ba6fd2e..628c9b0 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -1737,8 +1737,7 @@
if (NumTPLists > 0) {
TemplParamLists = new (Context) TemplateParameterList*[NumTPLists];
NumTemplParamLists = NumTPLists;
- for (unsigned i = NumTPLists; i-- > 0; )
- TemplParamLists[i] = TPLists[i];
+ std::copy(TPLists, TPLists + NumTPLists, TemplParamLists);
}
}
@@ -1878,9 +1877,8 @@
VarDecl *VarDecl::getCanonicalDecl() { return getFirstDecl(); }
-VarDecl::DefinitionKind VarDecl::isThisDeclarationADefinition(
- ASTContext &C) const
-{
+VarDecl::DefinitionKind
+VarDecl::isThisDeclarationADefinition(ASTContext &C) const {
// C++ [basic.def]p2:
// A declaration is a definition unless [...] it contains the 'extern'
// specifier or a linkage-specification and neither an initializer [...],
@@ -1917,7 +1915,7 @@
if (hasInit())
return Definition;
- if (hasAttr<AliasAttr>())
+ if (hasAttr<AliasAttr>() || hasAttr<SelectAnyAttr>())
return Definition;
// A variable template specialization (other than a static data member
@@ -2823,6 +2821,18 @@
return RTRange;
}
+bool FunctionDecl::hasUnusedResultAttr() const {
+ QualType RetType = getReturnType();
+ if (RetType->isRecordType()) {
+ const CXXRecordDecl *Ret = RetType->getAsCXXRecordDecl();
+ const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(this);
+ if (Ret && Ret->hasAttr<WarnUnusedResultAttr>() &&
+ !(MD && MD->getCorrespondingMethodInClass(Ret, true)))
+ return true;
+ }
+ return hasAttr<WarnUnusedResultAttr>();
+}
+
/// \brief For an inline function definition in C, or for a gnu_inline function
/// in C++, determine whether the definition will be externally visible.
///
@@ -3104,6 +3114,8 @@
DependentFunctionTemplateSpecializationInfo(const UnresolvedSetImpl &Ts,
const TemplateArgumentListInfo &TArgs)
: AngleLocs(TArgs.getLAngleLoc(), TArgs.getRAngleLoc()) {
+ static_assert(sizeof(*this) % llvm::AlignOf<void *>::Alignment == 0,
+ "Trailing data is unaligned!");
d.NumTemplates = Ts.size();
d.NumArgs = TArgs.size();
diff --git a/lib/AST/DeclGroup.cpp b/lib/AST/DeclGroup.cpp
index 9861f22..512837f 100644
--- a/lib/AST/DeclGroup.cpp
+++ b/lib/AST/DeclGroup.cpp
@@ -18,6 +18,8 @@
using namespace clang;
DeclGroup* DeclGroup::Create(ASTContext &C, Decl **Decls, unsigned NumDecls) {
+ static_assert(sizeof(DeclGroup) % llvm::AlignOf<void *>::Alignment == 0,
+ "Trailing data is unaligned!");
assert(NumDecls > 1 && "Invalid DeclGroup");
unsigned Size = sizeof(DeclGroup) + sizeof(Decl*) * NumDecls;
void* Mem = C.Allocate(Size, llvm::AlignOf<DeclGroup>::Alignment);
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index d13a11c..76a4da2 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -2161,12 +2161,16 @@
// If this is a direct call, get the callee.
const CallExpr *CE = cast<CallExpr>(this);
if (const Decl *FD = CE->getCalleeDecl()) {
+ const FunctionDecl *Func = dyn_cast<FunctionDecl>(FD);
+ bool HasWarnUnusedResultAttr = Func ? Func->hasUnusedResultAttr()
+ : FD->hasAttr<WarnUnusedResultAttr>();
+
// If the callee has attribute pure, const, or warn_unused_result, warn
// about it. void foo() { strlen("bar"); } should warn.
//
// Note: If new cases are added here, DiagnoseUnusedExprResult should be
// updated to match for QoI.
- if (FD->hasAttr<WarnUnusedResultAttr>() ||
+ if (HasWarnUnusedResultAttr ||
FD->hasAttr<PureAttr>() || FD->hasAttr<ConstAttr>()) {
WarnE = this;
Loc = CE->getCallee()->getLocStart();
@@ -2942,11 +2946,19 @@
case CXXOperatorCallExprClass:
case CXXMemberCallExprClass:
case CUDAKernelCallExprClass:
+ case UserDefinedLiteralClass: {
+ // We don't know a call definitely has side effects, except for calls
+ // to pure/const functions that definitely don't.
+ // If the call itself is considered side-effect free, check the operands.
+ const Decl *FD = cast<CallExpr>(this)->getCalleeDecl();
+ bool IsPure = FD && (FD->hasAttr<ConstAttr>() || FD->hasAttr<PureAttr>());
+ if (IsPure || !IncludePossibleEffects)
+ break;
+ return true;
+ }
+
case BlockExprClass:
case CXXBindTemporaryExprClass:
- case UserDefinedLiteralClass:
- // We don't know a call definitely has side effects, but we can check the
- // call's operands.
if (!IncludePossibleEffects)
break;
return true;
diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp
index f890719..6e55655 100644
--- a/lib/AST/ItaniumMangle.cpp
+++ b/lib/AST/ItaniumMangle.cpp
@@ -166,6 +166,8 @@
raw_ostream &Out) override;
void mangleSEHFilterExpression(const NamedDecl *EnclosingDecl,
raw_ostream &Out) override;
+ void mangleSEHFinallyBlock(const NamedDecl *EnclosingDecl,
+ raw_ostream &Out) override;
void mangleItaniumThreadLocalInit(const VarDecl *D, raw_ostream &) override;
void mangleItaniumThreadLocalWrapper(const VarDecl *D,
raw_ostream &) override;
@@ -3967,6 +3969,16 @@
Mangler.getStream() << EnclosingDecl->getName();
}
+void ItaniumMangleContextImpl::mangleSEHFinallyBlock(
+ const NamedDecl *EnclosingDecl, raw_ostream &Out) {
+ CXXNameMangler Mangler(*this, Out);
+ Mangler.getStream() << "__fin_";
+ if (shouldMangleDeclName(EnclosingDecl))
+ Mangler.mangle(EnclosingDecl);
+ else
+ Mangler.getStream() << EnclosingDecl->getName();
+}
+
void ItaniumMangleContextImpl::mangleItaniumThreadLocalInit(const VarDecl *D,
raw_ostream &Out) {
// <special-name> ::= TH <object name>
diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp
index 563ea7f..3689102 100644
--- a/lib/AST/MicrosoftMangle.cpp
+++ b/lib/AST/MicrosoftMangle.cpp
@@ -94,6 +94,7 @@
llvm::DenseMap<const NamedDecl *, unsigned> Uniquifier;
llvm::DenseMap<const CXXRecordDecl *, unsigned> LambdaIds;
llvm::DenseMap<const NamedDecl *, unsigned> SEHFilterIds;
+ llvm::DenseMap<const NamedDecl *, unsigned> SEHFinallyIds;
public:
MicrosoftMangleContextImpl(ASTContext &Context, DiagnosticsEngine &Diags)
@@ -122,8 +123,8 @@
CXXCtorType CT, uint32_t Size, uint32_t NVOffset,
int32_t VBPtrOffset, uint32_t VBIndex,
raw_ostream &Out) override;
- void mangleCXXHandlerMapEntry(QualType T, bool IsConst, bool IsVolatile,
- bool IsReference, raw_ostream &Out) override;
+ void mangleCXXCatchHandlerType(QualType T, uint32_t Flags,
+ raw_ostream &Out) override;
void mangleCXXRTTI(QualType T, raw_ostream &Out) override;
void mangleCXXRTTIName(QualType T, raw_ostream &Out) override;
void mangleCXXRTTIBaseClassDescriptor(const CXXRecordDecl *Derived,
@@ -151,6 +152,8 @@
raw_ostream &Out) override;
void mangleSEHFilterExpression(const NamedDecl *EnclosingDecl,
raw_ostream &Out) override;
+ void mangleSEHFinallyBlock(const NamedDecl *EnclosingDecl,
+ raw_ostream &Out) override;
void mangleStringLiteral(const StringLiteral *SL, raw_ostream &Out) override;
void mangleCXXVTableBitSet(const CXXRecordDecl *RD,
raw_ostream &Out) override;
@@ -1677,7 +1680,7 @@
Out << 'X';
} else {
// Happens for function pointer type arguments for example.
- for (const QualType Arg : Proto->param_types())
+ for (const QualType &Arg : Proto->param_types())
mangleArgumentType(Arg, Range);
// <builtin-type> ::= Z # ellipsis
if (Proto->isVariadic())
@@ -2345,20 +2348,13 @@
Mangler.mangleType(T, SourceRange(), MicrosoftCXXNameMangler::QMM_Result);
}
-void MicrosoftMangleContextImpl::mangleCXXHandlerMapEntry(QualType T,
- bool IsConst,
- bool IsVolatile,
- bool IsReference,
- raw_ostream &Out) {
+void MicrosoftMangleContextImpl::mangleCXXCatchHandlerType(QualType T,
+ uint32_t Flags,
+ raw_ostream &Out) {
MicrosoftCXXNameMangler Mangler(*this, Out);
- Mangler.getStream() << "llvm.eh.handlermapentry.";
- if (IsConst)
- Mangler.getStream() << "const.";
- if (IsVolatile)
- Mangler.getStream() << "volatile.";
- if (IsReference)
- Mangler.getStream() << "reference.";
+ Mangler.getStream() << "llvm.eh.handlertype.";
Mangler.mangleType(T, SourceRange(), MicrosoftCXXNameMangler::QMM_Result);
+ Mangler.getStream() << '.' << Flags;
}
void MicrosoftMangleContextImpl::mangleCXXThrowInfo(QualType T,
@@ -2476,6 +2472,17 @@
Mangler.mangleName(EnclosingDecl);
}
+void MicrosoftMangleContextImpl::mangleSEHFinallyBlock(
+ const NamedDecl *EnclosingDecl, raw_ostream &Out) {
+ MicrosoftCXXNameMangler Mangler(*this, Out);
+ // The function body is in the same comdat as the function with the handler,
+ // so the numbering here doesn't have to be the same across TUs.
+ //
+ // <mangled-name> ::= ?fin$ <filter-number> @0
+ Mangler.getStream() << "\01?fin$" << SEHFinallyIds[EnclosingDecl]++ << "@0@";
+ Mangler.mangleName(EnclosingDecl);
+}
+
void MicrosoftMangleContextImpl::mangleTypeName(QualType T, raw_ostream &Out) {
// This is just a made up unique string for the purposes of tbaa. undname
// does *not* know how to demangle it.
diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp
index 8c76009..0e8652f 100644
--- a/lib/AST/Stmt.cpp
+++ b/lib/AST/Stmt.cpp
@@ -940,8 +940,7 @@
}
SwitchStmt::SwitchStmt(const ASTContext &C, VarDecl *Var, Expr *cond)
- : Stmt(SwitchStmtClass), FirstCase(nullptr), AllEnumCasesCovered(0)
-{
+ : Stmt(SwitchStmtClass), FirstCase(nullptr, false) {
setConditionVariable(C, Var);
SubExprs[COND] = cond;
SubExprs[BODY] = nullptr;
@@ -1247,17 +1246,47 @@
return new (Mem) OMPFirstprivateClause(N);
}
-OMPLastprivateClause *OMPLastprivateClause::Create(const ASTContext &C,
- SourceLocation StartLoc,
- SourceLocation LParenLoc,
- SourceLocation EndLoc,
- ArrayRef<Expr *> VL) {
+void OMPLastprivateClause::setPrivateCopies(ArrayRef<Expr *> PrivateCopies) {
+ assert(PrivateCopies.size() == varlist_size() &&
+ "Number of private copies is not the same as the preallocated buffer");
+ std::copy(PrivateCopies.begin(), PrivateCopies.end(), varlist_end());
+}
+
+void OMPLastprivateClause::setSourceExprs(ArrayRef<Expr *> SrcExprs) {
+ assert(SrcExprs.size() == varlist_size() && "Number of source expressions is "
+ "not the same as the "
+ "preallocated buffer");
+ std::copy(SrcExprs.begin(), SrcExprs.end(), getPrivateCopies().end());
+}
+
+void OMPLastprivateClause::setDestinationExprs(ArrayRef<Expr *> DstExprs) {
+ assert(DstExprs.size() == varlist_size() && "Number of destination "
+ "expressions is not the same as "
+ "the preallocated buffer");
+ std::copy(DstExprs.begin(), DstExprs.end(), getSourceExprs().end());
+}
+
+void OMPLastprivateClause::setAssignmentOps(ArrayRef<Expr *> AssignmentOps) {
+ assert(AssignmentOps.size() == varlist_size() &&
+ "Number of assignment expressions is not the same as the preallocated "
+ "buffer");
+ std::copy(AssignmentOps.begin(), AssignmentOps.end(),
+ getDestinationExprs().end());
+}
+
+OMPLastprivateClause *OMPLastprivateClause::Create(
+ const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc,
+ SourceLocation EndLoc, ArrayRef<Expr *> VL, ArrayRef<Expr *> SrcExprs,
+ ArrayRef<Expr *> DstExprs, ArrayRef<Expr *> AssignmentOps) {
void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPLastprivateClause),
llvm::alignOf<Expr *>()) +
- sizeof(Expr *) * VL.size());
+ 5 * sizeof(Expr *) * VL.size());
OMPLastprivateClause *Clause =
new (Mem) OMPLastprivateClause(StartLoc, LParenLoc, EndLoc, VL.size());
Clause->setVarRefs(VL);
+ Clause->setSourceExprs(SrcExprs);
+ Clause->setDestinationExprs(DstExprs);
+ Clause->setAssignmentOps(AssignmentOps);
return Clause;
}
@@ -1265,7 +1294,7 @@
unsigned N) {
void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPLastprivateClause),
llvm::alignOf<Expr *>()) +
- sizeof(Expr *) * N);
+ 5 * sizeof(Expr *) * N);
return new (Mem) OMPLastprivateClause(N);
}
@@ -1366,17 +1395,41 @@
return new (Mem) OMPAlignedClause(NumVars);
}
-OMPCopyinClause *OMPCopyinClause::Create(const ASTContext &C,
- SourceLocation StartLoc,
- SourceLocation LParenLoc,
- SourceLocation EndLoc,
- ArrayRef<Expr *> VL) {
+void OMPCopyinClause::setSourceExprs(ArrayRef<Expr *> SrcExprs) {
+ assert(SrcExprs.size() == varlist_size() && "Number of source expressions is "
+ "not the same as the "
+ "preallocated buffer");
+ std::copy(SrcExprs.begin(), SrcExprs.end(), varlist_end());
+}
+
+void OMPCopyinClause::setDestinationExprs(ArrayRef<Expr *> DstExprs) {
+ assert(DstExprs.size() == varlist_size() && "Number of destination "
+ "expressions is not the same as "
+ "the preallocated buffer");
+ std::copy(DstExprs.begin(), DstExprs.end(), getSourceExprs().end());
+}
+
+void OMPCopyinClause::setAssignmentOps(ArrayRef<Expr *> AssignmentOps) {
+ assert(AssignmentOps.size() == varlist_size() &&
+ "Number of assignment expressions is not the same as the preallocated "
+ "buffer");
+ std::copy(AssignmentOps.begin(), AssignmentOps.end(),
+ getDestinationExprs().end());
+}
+
+OMPCopyinClause *OMPCopyinClause::Create(
+ const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc,
+ SourceLocation EndLoc, ArrayRef<Expr *> VL, ArrayRef<Expr *> SrcExprs,
+ ArrayRef<Expr *> DstExprs, ArrayRef<Expr *> AssignmentOps) {
void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPCopyinClause),
llvm::alignOf<Expr *>()) +
- sizeof(Expr *) * VL.size());
+ 4 * sizeof(Expr *) * VL.size());
OMPCopyinClause *Clause = new (Mem) OMPCopyinClause(StartLoc, LParenLoc,
EndLoc, VL.size());
Clause->setVarRefs(VL);
+ Clause->setSourceExprs(SrcExprs);
+ Clause->setDestinationExprs(DstExprs);
+ Clause->setAssignmentOps(AssignmentOps);
return Clause;
}
@@ -1384,7 +1437,7 @@
unsigned N) {
void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPCopyinClause),
llvm::alignOf<Expr *>()) +
- sizeof(Expr *) * N);
+ 4 * sizeof(Expr *) * N);
return new (Mem) OMPCopyinClause(N);
}
@@ -1458,16 +1511,42 @@
std::copy(A.begin(), A.end(), getFinals().begin());
}
+void OMPReductionClause::setLHSExprs(ArrayRef<Expr *> LHSExprs) {
+ assert(
+ LHSExprs.size() == varlist_size() &&
+ "Number of LHS expressions is not the same as the preallocated buffer");
+ std::copy(LHSExprs.begin(), LHSExprs.end(), varlist_end());
+}
+
+void OMPReductionClause::setRHSExprs(ArrayRef<Expr *> RHSExprs) {
+ assert(
+ RHSExprs.size() == varlist_size() &&
+ "Number of RHS expressions is not the same as the preallocated buffer");
+ std::copy(RHSExprs.begin(), RHSExprs.end(), getLHSExprs().end());
+}
+
+void OMPReductionClause::setReductionOps(ArrayRef<Expr *> ReductionOps) {
+ assert(ReductionOps.size() == varlist_size() && "Number of reduction "
+ "expressions is not the same "
+ "as the preallocated buffer");
+ std::copy(ReductionOps.begin(), ReductionOps.end(), getRHSExprs().end());
+}
+
OMPReductionClause *OMPReductionClause::Create(
const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc,
SourceLocation EndLoc, SourceLocation ColonLoc, ArrayRef<Expr *> VL,
- NestedNameSpecifierLoc QualifierLoc, const DeclarationNameInfo &NameInfo) {
+ NestedNameSpecifierLoc QualifierLoc, const DeclarationNameInfo &NameInfo,
+ ArrayRef<Expr *> LHSExprs, ArrayRef<Expr *> RHSExprs,
+ ArrayRef<Expr *> ReductionOps) {
void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPReductionClause),
llvm::alignOf<Expr *>()) +
- sizeof(Expr *) * VL.size());
+ 4 * sizeof(Expr *) * VL.size());
OMPReductionClause *Clause = new (Mem) OMPReductionClause(
StartLoc, LParenLoc, EndLoc, ColonLoc, VL.size(), QualifierLoc, NameInfo);
Clause->setVarRefs(VL);
+ Clause->setLHSExprs(LHSExprs);
+ Clause->setRHSExprs(RHSExprs);
+ Clause->setReductionOps(ReductionOps);
return Clause;
}
@@ -1475,7 +1554,7 @@
unsigned N) {
void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPReductionClause),
llvm::alignOf<Expr *>()) +
- sizeof(Expr *) * N);
+ 4 * sizeof(Expr *) * N);
return new (Mem) OMPReductionClause(N);
}
@@ -2007,24 +2086,24 @@
return new (Mem) OMPOrderedDirective();
}
-OMPAtomicDirective *
-OMPAtomicDirective::Create(const ASTContext &C, SourceLocation StartLoc,
- SourceLocation EndLoc, ArrayRef<OMPClause *> Clauses,
- Stmt *AssociatedStmt, BinaryOperatorKind OpKind,
- Expr *X, Expr *XRVal, Expr *V, Expr *E) {
+OMPAtomicDirective *OMPAtomicDirective::Create(
+ const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
+ ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt, Expr *X, Expr *V,
+ Expr *E, Expr *UE, bool IsXLHSInRHSPart, bool IsPostfixUpdate) {
unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPAtomicDirective),
llvm::alignOf<OMPClause *>());
void *Mem = C.Allocate(Size + sizeof(OMPClause *) * Clauses.size() +
5 * sizeof(Stmt *));
OMPAtomicDirective *Dir =
new (Mem) OMPAtomicDirective(StartLoc, EndLoc, Clauses.size());
- Dir->setOpKind(OpKind);
Dir->setClauses(Clauses);
Dir->setAssociatedStmt(AssociatedStmt);
Dir->setX(X);
- Dir->setXRVal(X);
Dir->setV(V);
Dir->setExpr(E);
+ Dir->setUpdateExpr(UE);
+ Dir->IsXLHSInRHSPart = IsXLHSInRHSPart;
+ Dir->IsPostfixUpdate = IsPostfixUpdate;
return Dir;
}
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index 8f0edd0..b68f3a3 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -1622,6 +1622,15 @@
const TemplateArgumentList *Args =
cast<FunctionDecl>(DRE->getDecl())->getTemplateSpecializationArgs();
assert(Args);
+
+ if (Args->size() != 1) {
+ OS << "operator \"\" " << Node->getUDSuffix()->getName();
+ TemplateSpecializationType::PrintTemplateArgumentList(
+ OS, Args->data(), Args->size(), Policy);
+ OS << "()";
+ return;
+ }
+
const TemplateArgument &Pack = Args->get(0);
for (const auto &P : Pack.pack_elements()) {
char C = (char)P.getAsIntegral().getZExtValue();
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index f29f6a8..f6df1ca 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -346,6 +346,15 @@
void
OMPClauseProfiler::VisitOMPLastprivateClause(const OMPLastprivateClause *C) {
VisitOMPClauseList(C);
+ for (auto *E : C->source_exprs()) {
+ Profiler->VisitStmt(E);
+ }
+ for (auto *E : C->destination_exprs()) {
+ Profiler->VisitStmt(E);
+ }
+ for (auto *E : C->assignment_ops()) {
+ Profiler->VisitStmt(E);
+ }
}
void OMPClauseProfiler::VisitOMPSharedClause(const OMPSharedClause *C) {
VisitOMPClauseList(C);
@@ -356,6 +365,15 @@
C->getQualifierLoc().getNestedNameSpecifier());
Profiler->VisitName(C->getNameInfo().getName());
VisitOMPClauseList(C);
+ for (auto *E : C->lhs_exprs()) {
+ Profiler->VisitStmt(E);
+ }
+ for (auto *E : C->rhs_exprs()) {
+ Profiler->VisitStmt(E);
+ }
+ for (auto *E : C->reduction_ops()) {
+ Profiler->VisitStmt(E);
+ }
}
void OMPClauseProfiler::VisitOMPLinearClause(const OMPLinearClause *C) {
VisitOMPClauseList(C);
@@ -377,6 +395,15 @@
}
void OMPClauseProfiler::VisitOMPCopyinClause(const OMPCopyinClause *C) {
VisitOMPClauseList(C);
+ for (auto *E : C->source_exprs()) {
+ Profiler->VisitStmt(E);
+ }
+ for (auto *E : C->destination_exprs()) {
+ Profiler->VisitStmt(E);
+ }
+ for (auto *E : C->assignment_ops()) {
+ Profiler->VisitStmt(E);
+ }
}
void
OMPClauseProfiler::VisitOMPCopyprivateClause(const OMPCopyprivateClause *C) {
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 0e8b1e8..0eb5d8c 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -2371,6 +2371,11 @@
return typedefType->getDecl()->hasAttr<ObjCNSObjectAttr>();
return false;
}
+bool Type::isObjCIndependentClassType() const {
+ if (const TypedefType *typedefType = dyn_cast<TypedefType>(this))
+ return typedefType->getDecl()->hasAttr<ObjCIndependentClassAttr>();
+ return false;
+}
bool Type::isObjCRetainableType() const {
return isObjCObjectPointerType() ||
isBlockPointerType() ||
diff --git a/lib/ASTMatchers/ASTMatchFinder.cpp b/lib/ASTMatchers/ASTMatchFinder.cpp
index fa7968a..c5f3063 100644
--- a/lib/ASTMatchers/ASTMatchFinder.cpp
+++ b/lib/ASTMatchers/ASTMatchFinder.cpp
@@ -300,7 +300,7 @@
const MatchFinder::MatchFinderOptions &Options)
: Matchers(Matchers), Options(Options), ActiveASTContext(nullptr) {}
- ~MatchASTVisitor() {
+ ~MatchASTVisitor() override {
if (Options.CheckProfiling) {
Options.CheckProfiling->Records = std::move(TimeByBucket);
}
diff --git a/lib/ASTMatchers/Dynamic/Marshallers.h b/lib/ASTMatchers/Dynamic/Marshallers.h
index b78bc03..36a6415 100644
--- a/lib/ASTMatchers/Dynamic/Marshallers.h
+++ b/lib/ASTMatchers/Dynamic/Marshallers.h
@@ -181,18 +181,20 @@
ArgKinds(ArgKinds.begin(), ArgKinds.end()) {}
VariantMatcher create(const SourceRange &NameRange,
- ArrayRef<ParserValue> Args, Diagnostics *Error) const {
+ ArrayRef<ParserValue> Args,
+ Diagnostics *Error) const override {
return Marshaller(Func, MatcherName, NameRange, Args, Error);
}
- bool isVariadic() const { return false; }
- unsigned getNumArgs() const { return ArgKinds.size(); }
+ bool isVariadic() const override { return false; }
+ unsigned getNumArgs() const override { return ArgKinds.size(); }
void getArgKinds(ast_type_traits::ASTNodeKind ThisKind, unsigned ArgNo,
- std::vector<ArgKind> &Kinds) const {
+ std::vector<ArgKind> &Kinds) const override {
Kinds.push_back(ArgKinds[ArgNo]);
}
- bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind, unsigned *Specificity,
- ast_type_traits::ASTNodeKind *LeastDerivedKind) const {
+ bool isConvertibleTo(
+ ast_type_traits::ASTNodeKind Kind, unsigned *Specificity,
+ ast_type_traits::ASTNodeKind *LeastDerivedKind) const override {
return isRetKindConvertibleTo(RetKinds, Kind, Specificity,
LeastDerivedKind);
}
@@ -333,18 +335,20 @@
}
VariantMatcher create(const SourceRange &NameRange,
- ArrayRef<ParserValue> Args, Diagnostics *Error) const {
+ ArrayRef<ParserValue> Args,
+ Diagnostics *Error) const override {
return Func(MatcherName, NameRange, Args, Error);
}
- bool isVariadic() const { return true; }
- unsigned getNumArgs() const { return 0; }
+ bool isVariadic() const override { return true; }
+ unsigned getNumArgs() const override { return 0; }
void getArgKinds(ast_type_traits::ASTNodeKind ThisKind, unsigned ArgNo,
- std::vector<ArgKind> &Kinds) const {
+ std::vector<ArgKind> &Kinds) const override {
Kinds.push_back(ArgsKind);
}
- bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind, unsigned *Specificity,
- ast_type_traits::ASTNodeKind *LeastDerivedKind) const {
+ bool isConvertibleTo(
+ ast_type_traits::ASTNodeKind Kind, unsigned *Specificity,
+ ast_type_traits::ASTNodeKind *LeastDerivedKind) const override {
return isRetKindConvertibleTo(RetKinds, Kind, Specificity,
LeastDerivedKind);
}
@@ -487,11 +491,11 @@
OverloadedMatcherDescriptor(ArrayRef<MatcherDescriptor *> Callbacks)
: Overloads(Callbacks.begin(), Callbacks.end()) {}
- virtual ~OverloadedMatcherDescriptor() {}
+ ~OverloadedMatcherDescriptor() override {}
- virtual VariantMatcher create(const SourceRange &NameRange,
- ArrayRef<ParserValue> Args,
- Diagnostics *Error) const {
+ VariantMatcher create(const SourceRange &NameRange,
+ ArrayRef<ParserValue> Args,
+ Diagnostics *Error) const override {
std::vector<VariantMatcher> Constructed;
Diagnostics::OverloadContext Ctx(Error);
for (const auto &O : Overloads) {
@@ -512,7 +516,7 @@
return Constructed[0];
}
- bool isVariadic() const {
+ bool isVariadic() const override {
bool Overload0Variadic = Overloads[0]->isVariadic();
#ifndef NDEBUG
for (const auto &O : Overloads) {
@@ -522,7 +526,7 @@
return Overload0Variadic;
}
- unsigned getNumArgs() const {
+ unsigned getNumArgs() const override {
unsigned Overload0NumArgs = Overloads[0]->getNumArgs();
#ifndef NDEBUG
for (const auto &O : Overloads) {
@@ -533,15 +537,16 @@
}
void getArgKinds(ast_type_traits::ASTNodeKind ThisKind, unsigned ArgNo,
- std::vector<ArgKind> &Kinds) const {
+ std::vector<ArgKind> &Kinds) const override {
for (const auto &O : Overloads) {
if (O->isConvertibleTo(ThisKind))
O->getArgKinds(ThisKind, ArgNo, Kinds);
}
}
- bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind, unsigned *Specificity,
- ast_type_traits::ASTNodeKind *LeastDerivedKind) const {
+ bool isConvertibleTo(
+ ast_type_traits::ASTNodeKind Kind, unsigned *Specificity,
+ ast_type_traits::ASTNodeKind *LeastDerivedKind) const override {
for (const auto &O : Overloads) {
if (O->isConvertibleTo(Kind, Specificity, LeastDerivedKind))
return true;
@@ -562,9 +567,9 @@
: MinCount(MinCount), MaxCount(MaxCount), Op(Op),
MatcherName(MatcherName) {}
- virtual VariantMatcher create(const SourceRange &NameRange,
- ArrayRef<ParserValue> Args,
- Diagnostics *Error) const override {
+ VariantMatcher create(const SourceRange &NameRange,
+ ArrayRef<ParserValue> Args,
+ Diagnostics *Error) const override {
if (Args.size() < MinCount || MaxCount < Args.size()) {
const std::string MaxStr =
(MaxCount == UINT_MAX ? "" : Twine(MaxCount)).str();
diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp
index 169f1df..94fa1d9 100644
--- a/lib/Analysis/CFG.cpp
+++ b/lib/Analysis/CFG.cpp
@@ -3950,9 +3950,8 @@
}
}
}
-
- virtual ~StmtPrinterHelper() {}
+ ~StmtPrinterHelper() override {}
const LangOptions &getLangOpts() const { return LangOpts; }
void setBlockID(signed i) { currentBlock = i; }
diff --git a/lib/Analysis/Consumed.cpp b/lib/Analysis/Consumed.cpp
index 967f3e1..fa985ee 100644
--- a/lib/Analysis/Consumed.cpp
+++ b/lib/Analysis/Consumed.cpp
@@ -1442,7 +1442,7 @@
CurrStates,
WarningsHandler);
- if (BlockInfo.allBackEdgesVisited(*SI, CurrBlock))
+ if (BlockInfo.allBackEdgesVisited(CurrBlock, *SI))
BlockInfo.discardInfo(*SI);
} else {
BlockInfo.addInfo(*SI, CurrStates, OwnershipTaken);
diff --git a/lib/Analysis/UninitializedValues.cpp b/lib/Analysis/UninitializedValues.cpp
index 8a6870f..3c7bc4e 100644
--- a/lib/Analysis/UninitializedValues.cpp
+++ b/lib/Analysis/UninitializedValues.cpp
@@ -837,7 +837,7 @@
: hadUse(numBlocks, false), hadAnyUse(false),
currentBlock(0) {}
- virtual ~PruneBlocksHandler() {}
+ ~PruneBlocksHandler() override {}
/// Records if a CFGBlock had a potential use of an uninitialized variable.
llvm::BitVector hadUse;
diff --git a/lib/Basic/OpenMPKinds.cpp b/lib/Basic/OpenMPKinds.cpp
index 6e98d48..b83a069 100644
--- a/lib/Basic/OpenMPKinds.cpp
+++ b/lib/Basic/OpenMPKinds.cpp
@@ -374,7 +374,6 @@
}
bool clang::isOpenMPThreadPrivate(OpenMPClauseKind Kind) {
- return Kind == OMPC_threadprivate ||
- Kind == OMPC_copyin; // TODO add next clauses like 'copyprivate'.
+ return Kind == OMPC_threadprivate || Kind == OMPC_copyin;
}
diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp
index 118e3f3..c0b0453 100644
--- a/lib/Basic/SourceManager.cpp
+++ b/lib/Basic/SourceManager.cpp
@@ -110,8 +110,8 @@
// possible.
if (!BufferOrError) {
StringRef FillStr("<<<MISSING SOURCE FILE>>>\n");
- Buffer.setPointer(MemoryBuffer::getNewMemBuffer(ContentsEntry->getSize(),
- "<invalid>").release());
+ Buffer.setPointer(MemoryBuffer::getNewUninitMemBuffer(
+ ContentsEntry->getSize(), "<invalid>").release());
char *Ptr = const_cast<char*>(Buffer.getPointer()->getBufferStart());
for (unsigned i = 0, e = ContentsEntry->getSize(); i != e; ++i)
Ptr[i] = FillStr[i % FillStr.size()];
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index fb73231..fd8215b 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -445,6 +445,7 @@
public:
NetBSDTargetInfo(const llvm::Triple &Triple) : OSTargetInfo<Target>(Triple) {
this->UserLabelPrefix = "";
+ this->MCountName = "_mcount";
}
};
@@ -713,8 +714,7 @@
// RegParmMax is inherited from the underlying architecture
this->LongDoubleFormat = &llvm::APFloat::IEEEdouble;
if (Triple.getArch() == llvm::Triple::arm) {
- this->DescriptionString =
- "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S128";
+ // Handled in ARM's setABI().
} else if (Triple.getArch() == llvm::Triple::x86) {
this->DescriptionString = "e-m:e-p:32:32-i64:64-n8:16:32-S128";
} else if (Triple.getArch() == llvm::Triple::x86_64) {
@@ -743,8 +743,11 @@
bool HasVSX;
bool HasP8Vector;
bool HasP8Crypto;
+ bool HasDirectMove;
bool HasQPX;
bool HasHTM;
+ bool HasBPERMD;
+ bool HasExtDiv;
protected:
std::string ABI;
@@ -752,7 +755,8 @@
public:
PPCTargetInfo(const llvm::Triple &Triple)
: TargetInfo(Triple), HasVSX(false), HasP8Vector(false),
- HasP8Crypto(false), HasQPX(false), HasHTM(false) {
+ HasP8Crypto(false), HasDirectMove(false), HasQPX(false), HasHTM(false),
+ HasBPERMD(false), HasExtDiv(false) {
BigEndian = (Triple.getArch() != llvm::Triple::ppc64le);
LongDoubleWidth = LongDoubleAlign = 128;
LongDoubleFormat = &llvm::APFloat::PPCDoubleDouble;
@@ -1012,6 +1016,16 @@
continue;
}
+ if (Feature == "bpermd") {
+ HasBPERMD = true;
+ continue;
+ }
+
+ if (Feature == "extdiv") {
+ HasExtDiv = true;
+ continue;
+ }
+
if (Feature == "power8-vector") {
HasP8Vector = true;
continue;
@@ -1022,6 +1036,11 @@
continue;
}
+ if (Feature == "direct-move") {
+ HasDirectMove = true;
+ continue;
+ }
+
if (Feature == "qpx") {
HasQPX = true;
continue;
@@ -1234,6 +1253,20 @@
.Case("ppc64le", true)
.Case("pwr8", true)
.Default(false);
+ Features["bpermd"] = llvm::StringSwitch<bool>(CPU)
+ .Case("ppc64le", true)
+ .Case("pwr8", true)
+ .Case("pwr7", true)
+ .Default(false);
+ Features["extdiv"] = llvm::StringSwitch<bool>(CPU)
+ .Case("ppc64le", true)
+ .Case("pwr8", true)
+ .Case("pwr7", true)
+ .Default(false);
+ Features["direct-move"] = llvm::StringSwitch<bool>(CPU)
+ .Case("ppc64le", true)
+ .Case("pwr8", true)
+ .Default(false);
}
bool PPCTargetInfo::hasFeature(StringRef Feature) const {
@@ -1242,8 +1275,11 @@
.Case("vsx", HasVSX)
.Case("power8-vector", HasP8Vector)
.Case("crypto", HasP8Crypto)
+ .Case("direct-move", HasDirectMove)
.Case("qpx", HasQPX)
.Case("htm", HasHTM)
+ .Case("bpermd", HasBPERMD)
+ .Case("extdiv", HasExtDiv)
.Default(false);
}
@@ -1477,6 +1513,7 @@
GK_SM21,
GK_SM30,
GK_SM35,
+ GK_SM37,
} GPU;
public:
@@ -1512,6 +1549,9 @@
case GK_SM35:
CUDAArchCode = "350";
break;
+ case GK_SM37:
+ CUDAArchCode = "370";
+ break;
default:
llvm_unreachable("Unhandled target CPU");
}
@@ -1564,6 +1604,7 @@
.Case("sm_21", GK_SM21)
.Case("sm_30", GK_SM30)
.Case("sm_35", GK_SM35)
+ .Case("sm_37", GK_SM37)
.Default(GK_NONE);
return GPU != GK_NONE;
@@ -1591,20 +1632,22 @@
public:
NVPTX32TargetInfo(const llvm::Triple &Triple) : NVPTXTargetInfo(Triple) {
PointerWidth = PointerAlign = 32;
- SizeType = PtrDiffType = TargetInfo::UnsignedInt;
+ SizeType = TargetInfo::UnsignedInt;
+ PtrDiffType = TargetInfo::SignedInt;
IntPtrType = TargetInfo::SignedInt;
DescriptionString = "e-p:32:32-i64:64-v16:16-v32:32-n16:32:64";
- }
+ }
};
class NVPTX64TargetInfo : public NVPTXTargetInfo {
public:
NVPTX64TargetInfo(const llvm::Triple &Triple) : NVPTXTargetInfo(Triple) {
PointerWidth = PointerAlign = 64;
- SizeType = PtrDiffType = TargetInfo::UnsignedLongLong;
- IntPtrType = TargetInfo::SignedLongLong;
+ SizeType = TargetInfo::UnsignedLong;
+ PtrDiffType = TargetInfo::SignedLong;
+ IntPtrType = TargetInfo::SignedLong;
DescriptionString = "e-i64:64-v16:16-v32:32-n16:32:64";
- }
+ }
};
static const unsigned R600AddrSpaceMap[] = {
@@ -1635,6 +1678,7 @@
class R600TargetInfo : public TargetInfo {
static const Builtin::Info BuiltinInfo[];
+ static const char * const GCCRegNames[];
/// \brief The GPU profiles supported by the R600 target.
enum GPUKind {
@@ -1685,10 +1729,7 @@
}
void getGCCRegNames(const char * const *&Names,
- unsigned &numNames) const override {
- Names = nullptr;
- numNames = 0;
- }
+ unsigned &NumNames) const override;
void getGCCRegAliases(const GCCRegAlias *&Aliases,
unsigned &NumAliases) const override {
@@ -1791,6 +1832,64 @@
{ #ID, TYPE, ATTRS, 0, ALL_LANGUAGES },
#include "clang/Basic/BuiltinsR600.def"
};
+const char * const R600TargetInfo::GCCRegNames[] = {
+ "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7",
+ "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15",
+ "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23",
+ "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31",
+ "v32", "v33", "v34", "v35", "v36", "v37", "v38", "v39",
+ "v40", "v41", "v42", "v43", "v44", "v45", "v46", "v47",
+ "v48", "v49", "v50", "v51", "v52", "v53", "v54", "v55",
+ "v56", "v57", "v58", "v59", "v60", "v61", "v62", "v63",
+ "v64", "v65", "v66", "v67", "v68", "v69", "v70", "v71",
+ "v72", "v73", "v74", "v75", "v76", "v77", "v78", "v79",
+ "v80", "v81", "v82", "v83", "v84", "v85", "v86", "v87",
+ "v88", "v89", "v90", "v91", "v92", "v93", "v94", "v95",
+ "v96", "v97", "v98", "v99", "v100", "v101", "v102", "v103",
+ "v104", "v105", "v106", "v107", "v108", "v109", "v110", "v111",
+ "v112", "v113", "v114", "v115", "v116", "v117", "v118", "v119",
+ "v120", "v121", "v122", "v123", "v124", "v125", "v126", "v127",
+ "v128", "v129", "v130", "v131", "v132", "v133", "v134", "v135",
+ "v136", "v137", "v138", "v139", "v140", "v141", "v142", "v143",
+ "v144", "v145", "v146", "v147", "v148", "v149", "v150", "v151",
+ "v152", "v153", "v154", "v155", "v156", "v157", "v158", "v159",
+ "v160", "v161", "v162", "v163", "v164", "v165", "v166", "v167",
+ "v168", "v169", "v170", "v171", "v172", "v173", "v174", "v175",
+ "v176", "v177", "v178", "v179", "v180", "v181", "v182", "v183",
+ "v184", "v185", "v186", "v187", "v188", "v189", "v190", "v191",
+ "v192", "v193", "v194", "v195", "v196", "v197", "v198", "v199",
+ "v200", "v201", "v202", "v203", "v204", "v205", "v206", "v207",
+ "v208", "v209", "v210", "v211", "v212", "v213", "v214", "v215",
+ "v216", "v217", "v218", "v219", "v220", "v221", "v222", "v223",
+ "v224", "v225", "v226", "v227", "v228", "v229", "v230", "v231",
+ "v232", "v233", "v234", "v235", "v236", "v237", "v238", "v239",
+ "v240", "v241", "v242", "v243", "v244", "v245", "v246", "v247",
+ "v248", "v249", "v250", "v251", "v252", "v253", "v254", "v255",
+ "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
+ "s8", "s9", "s10", "s11", "s12", "s13", "s14", "s15",
+ "s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23",
+ "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31",
+ "s32", "s33", "s34", "s35", "s36", "s37", "s38", "s39",
+ "s40", "s41", "s42", "s43", "s44", "s45", "s46", "s47",
+ "s48", "s49", "s50", "s51", "s52", "s53", "s54", "s55",
+ "s56", "s57", "s58", "s59", "s60", "s61", "s62", "s63",
+ "s64", "s65", "s66", "s67", "s68", "s69", "s70", "s71",
+ "s72", "s73", "s74", "s75", "s76", "s77", "s78", "s79",
+ "s80", "s81", "s82", "s83", "s84", "s85", "s86", "s87",
+ "s88", "s89", "s90", "s91", "s92", "s93", "s94", "s95",
+ "s96", "s97", "s98", "s99", "s100", "s101", "s102", "s103",
+ "s104", "s105", "s106", "s107", "s108", "s109", "s110", "s111",
+ "s112", "s113", "s114", "s115", "s116", "s117", "s118", "s119",
+ "s120", "s121", "s122", "s123", "s124", "s125", "s126", "s127"
+ "exec", "vcc", "scc", "m0", "flat_scr", "exec_lo", "exec_hi",
+ "vcc_lo", "vcc_hi", "flat_scr_lo", "flat_scr_hi"
+};
+
+void R600TargetInfo::getGCCRegNames(const char * const *&Names,
+ unsigned &NumNames) const {
+ Names = GCCRegNames;
+ NumNames = llvm::array_lengthof(GCCRegNames);
+}
// Namespace for x86 abstract base class
const Builtin::Info BuiltinInfo[] = {
@@ -3430,7 +3529,10 @@
: WindowsTargetInfo<X86_32TargetInfo>(Triple) {
WCharType = UnsignedShort;
DoubleAlign = LongLongAlign = 64;
- DescriptionString = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-S32";
+ bool IsWinCOFF =
+ getTriple().isOSWindows() && getTriple().isOSBinFormatCOFF();
+ DescriptionString = IsWinCOFF ? "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-S32"
+ : "e-m:e-p:32:32-i64:64-f80:32-n8:16:32-S32";
}
void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const override {
@@ -3897,6 +3999,9 @@
"-a:0:32"
"-n32"
"-S64";
+ } else if (T.isOSNaCl()) {
+ assert(!BigEndian && "NaCl on ARM does not support big endian");
+ DescriptionString = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S128";
} else {
DescriptionString =
BigEndian ? "E-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"
@@ -4080,7 +4185,7 @@
Features["hwdiv"] = true;
Features["hwdiv-arm"] = true;
} else if (CPU == "cortex-m3" || CPU == "cortex-m4" || CPU == "cortex-m7" ||
- CPU == "sc300") {
+ CPU == "sc300" || CPU == "cortex-r4" || CPU == "cortex-r4f") {
Features["hwdiv"] = true;
}
}
@@ -4181,7 +4286,7 @@
.Cases("cortex-a5", "cortex-a7", "cortex-a8", "7A")
.Cases("cortex-a9", "cortex-a12", "cortex-a15", "cortex-a17", "krait",
"7A")
- .Cases("cortex-r4", "cortex-r5", "cortex-r7", "7R")
+ .Cases("cortex-r4", "cortex-r4f", "cortex-r5", "cortex-r7", "7R")
.Case("swift", "7S")
.Case("cyclone", "8A")
.Cases("sc300", "cortex-m3", "7M")
@@ -4198,7 +4303,7 @@
.Cases("cortex-a53", "cortex-a57", "cortex-a72", "A")
.Cases("cortex-m3", "cortex-m4", "cortex-m0", "cortex-m0plus", "M")
.Cases("cortex-m1", "cortex-m7", "sc000", "sc300", "M")
- .Cases("cortex-r4", "cortex-r5", "cortex-r7", "R")
+ .Cases("cortex-r4", "cortex-r4f", "cortex-r5", "cortex-r7", "R")
.Default("");
}
bool setCPU(const std::string &Name) override {
@@ -4560,8 +4665,8 @@
public:
ARMleTargetInfo(const llvm::Triple &Triple)
: ARMTargetInfo(Triple, false) { }
- virtual void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const {
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override {
Builder.defineMacro("__ARMEL__");
ARMTargetInfo::getTargetDefines(Opts, Builder);
}
@@ -4571,8 +4676,8 @@
public:
ARMbeTargetInfo(const llvm::Triple &Triple)
: ARMTargetInfo(Triple, true) { }
- virtual void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const {
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override {
Builder.defineMacro("__ARMEB__");
Builder.defineMacro("__ARM_BIG_ENDIAN");
ARMTargetInfo::getTargetDefines(Opts, Builder);
@@ -4744,8 +4849,8 @@
return CPUKnown;
}
- virtual void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const override {
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override {
// Target identification.
Builder.defineMacro("__aarch64__");
@@ -4804,8 +4909,8 @@
Builder.defineMacro("__ARM_FEATURE_CRYPTO");
}
- virtual void getTargetBuiltins(const Builtin::Info *&Records,
- unsigned &NumRecords) const override {
+ void getTargetBuiltins(const Builtin::Info *&Records,
+ unsigned &NumRecords) const override {
Records = BuiltinInfo;
NumRecords = clang::AArch64::LastTSBuiltin - Builtin::FirstTSBuiltin;
}
@@ -4841,14 +4946,13 @@
return TargetInfo::AArch64ABIBuiltinVaList;
}
- virtual void getGCCRegNames(const char *const *&Names,
- unsigned &NumNames) const override;
- virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
- unsigned &NumAliases) const override;
+ void getGCCRegNames(const char *const *&Names,
+ unsigned &NumNames) const override;
+ void getGCCRegAliases(const GCCRegAlias *&Aliases,
+ unsigned &NumAliases) const override;
- virtual bool
- validateAsmConstraint(const char *&Name,
- TargetInfo::ConstraintInfo &Info) const override {
+ bool validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &Info) const override {
switch (*Name) {
default:
return false;
@@ -5402,10 +5506,16 @@
};
class SystemZTargetInfo : public TargetInfo {
+ static const Builtin::Info BuiltinInfo[];
static const char *const GCCRegNames[];
+ std::string CPU;
+ bool HasTransactionalExecution;
public:
- SystemZTargetInfo(const llvm::Triple &Triple) : TargetInfo(Triple) {
+ SystemZTargetInfo(const llvm::Triple &Triple)
+ : TargetInfo(Triple), CPU("z10"), HasTransactionalExecution(false) {
+ IntMaxType = SignedLong;
+ Int64Type = SignedLong;
TLSSupported = true;
IntWidth = IntAlign = 32;
LongWidth = LongLongWidth = LongAlign = LongLongAlign = 64;
@@ -5423,12 +5533,13 @@
Builder.defineMacro("__s390x__");
Builder.defineMacro("__zarch__");
Builder.defineMacro("__LONG_DOUBLE_128__");
+ if (HasTransactionalExecution)
+ Builder.defineMacro("__HTM__");
}
void getTargetBuiltins(const Builtin::Info *&Records,
unsigned &NumRecords) const override {
- // FIXME: Implement.
- Records = nullptr;
- NumRecords = 0;
+ Records = BuiltinInfo;
+ NumRecords = clang::SystemZ::LastTSBuiltin-Builtin::FirstTSBuiltin;
}
void getGCCRegNames(const char *const *&Names,
@@ -5449,16 +5560,42 @@
return TargetInfo::SystemZBuiltinVaList;
}
bool setCPU(const std::string &Name) override {
+ CPU = Name;
bool CPUKnown = llvm::StringSwitch<bool>(Name)
.Case("z10", true)
.Case("z196", true)
.Case("zEC12", true)
.Default(false);
- // No need to store the CPU yet. There aren't any CPU-specific
- // macros to define.
return CPUKnown;
}
+ void getDefaultFeatures(llvm::StringMap<bool> &Features) const override {
+ if (CPU == "zEC12")
+ Features["transactional-execution"] = true;
+ }
+
+ bool handleTargetFeatures(std::vector<std::string> &Features,
+ DiagnosticsEngine &Diags) override {
+ HasTransactionalExecution = false;
+ for (unsigned i = 0, e = Features.size(); i != e; ++i) {
+ if (Features[i] == "+transactional-execution")
+ HasTransactionalExecution = true;
+ }
+ return true;
+ }
+
+ bool hasFeature(StringRef Feature) const override {
+ return llvm::StringSwitch<bool>(Feature)
+ .Case("systemz", true)
+ .Case("htm", HasTransactionalExecution)
+ .Default(false);
+ }
+};
+
+const Builtin::Info SystemZTargetInfo::BuiltinInfo[] = {
+#define BUILTIN(ID, TYPE, ATTRS) \
+ { #ID, TYPE, ATTRS, 0, ALL_LANGUAGES },
+#include "clang/Basic/BuiltinsSystemZ.def"
};
const char *const SystemZTargetInfo::GCCRegNames[] = {
@@ -5859,9 +5996,30 @@
case 'R': // An address that can be used in a non-macro load or store
Info.setAllowsMemory();
return true;
+ case 'Z':
+ if (Name[1] == 'C') { // An address usable by ll, and sc.
+ Info.setAllowsMemory();
+ Name++; // Skip over 'Z'.
+ return true;
+ }
+ return false;
}
}
+ std::string convertConstraint(const char *&Constraint) const override {
+ std::string R;
+ switch (*Constraint) {
+ case 'Z': // Two-character constraint; add "^" hint for later parsing.
+ if (Constraint[1] == 'C') {
+ R = std::string("^") + std::string(Constraint, 2);
+ Constraint++;
+ return R;
+ }
+ break;
+ }
+ return TargetInfo::convertConstraint(Constraint);
+ }
+
const char *getClobbers() const override {
// In GCC, $1 is not widely used in generated code (it's used only in a few
// specific situations), so there is no real need for users to add it to
@@ -6752,6 +6910,8 @@
switch (os) {
case llvm::Triple::Linux:
return new LinuxTargetInfo<PPC64TargetInfo>(Triple);
+ case llvm::Triple::NetBSD:
+ return new NetBSDTargetInfo<PPC64TargetInfo>(Triple);
default:
return new PPC64TargetInfo(Triple);
}
diff --git a/lib/Basic/VirtualFileSystem.cpp b/lib/Basic/VirtualFileSystem.cpp
index 5164bcf..8a882e1 100644
--- a/lib/Basic/VirtualFileSystem.cpp
+++ b/lib/Basic/VirtualFileSystem.cpp
@@ -92,7 +92,7 @@
}
public:
- ~RealFile();
+ ~RealFile() override;
ErrorOr<Status> status() override;
ErrorOr<std::unique_ptr<MemoryBuffer>>
getBuffer(const Twine &Name, int64_t FileSize = -1,
@@ -362,7 +362,7 @@
Status S;
public:
- virtual ~DirectoryEntry();
+ ~DirectoryEntry() override;
DirectoryEntry(StringRef Name, std::vector<Entry *> Contents, Status S)
: Entry(EK_Directory, Name), Contents(std::move(Contents)),
S(std::move(S)) {}
@@ -498,7 +498,7 @@
ErrorOr<Status> status(const Twine &Path, Entry *E);
public:
- ~VFSFromYAML();
+ ~VFSFromYAML() override;
/// \brief Parses \p Buffer, which is expected to be in YAML format and
/// returns a virtual file system representing its contents.
diff --git a/lib/CodeGen/BackendUtil.cpp b/lib/CodeGen/BackendUtil.cpp
index bdab637..7bc351a 100644
--- a/lib/CodeGen/BackendUtil.cpp
+++ b/lib/CodeGen/BackendUtil.cpp
@@ -27,7 +27,6 @@
#include "llvm/IR/Verifier.h"
#include "llvm/MC/SubtargetFeature.h"
#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/Timer.h"
@@ -97,7 +96,7 @@
void CreatePasses();
- /// CreateTargetMachine - Generates the TargetMachine.
+ /// Generates the TargetMachine.
/// Returns Null if it is unable to create the target machine.
/// Some of our clang tests specify triples which are not built
/// into clang. This is okay because these tests check the generated
@@ -107,10 +106,10 @@
/// the requested target.
TargetMachine *CreateTargetMachine(bool MustCreateTM);
- /// AddEmitPasses - Add passes necessary to emit assembly or LLVM IR.
+ /// Add passes necessary to emit assembly or LLVM IR.
///
/// \return True on success.
- bool AddEmitPasses(BackendAction Action, formatted_raw_ostream &OS);
+ bool AddEmitPasses(BackendAction Action, raw_pwrite_stream &OS);
public:
EmitAssemblyHelper(DiagnosticsEngine &_Diags,
@@ -133,7 +132,7 @@
std::unique_ptr<TargetMachine> TM;
- void EmitAssembly(BackendAction Action, raw_ostream *OS);
+ void EmitAssembly(BackendAction Action, raw_pwrite_stream *OS);
};
// We need this wrapper to access LangOpts and CGOpts from extension functions
@@ -437,8 +436,6 @@
BackendArgs.push_back("-time-passes");
for (unsigned i = 0, e = CodeGenOpts.BackendOptions.size(); i != e; ++i)
BackendArgs.push_back(CodeGenOpts.BackendOptions[i].c_str());
- if (CodeGenOpts.NoGlobalMerge)
- BackendArgs.push_back("-enable-global-merge=false");
BackendArgs.push_back(nullptr);
llvm::cl::ParseCommandLineOptions(BackendArgs.size() - 1,
BackendArgs.data());
@@ -549,7 +546,7 @@
}
bool EmitAssemblyHelper::AddEmitPasses(BackendAction Action,
- formatted_raw_ostream &OS) {
+ raw_pwrite_stream &OS) {
// Create the code generator passes.
legacy::PassManager *PM = getCodeGenPasses();
@@ -586,9 +583,9 @@
return true;
}
-void EmitAssemblyHelper::EmitAssembly(BackendAction Action, raw_ostream *OS) {
+void EmitAssemblyHelper::EmitAssembly(BackendAction Action,
+ raw_pwrite_stream *OS) {
TimeRegion Region(llvm::TimePassesIsEnabled ? &CodeGenerationTime : nullptr);
- llvm::formatted_raw_ostream FormattedOS;
bool UsesCodeGen = (Action != Backend_EmitNothing &&
Action != Backend_EmitBC &&
@@ -604,17 +601,17 @@
break;
case Backend_EmitBC:
- getPerModulePasses()->add(createBitcodeWriterPass(*OS));
+ getPerModulePasses()->add(
+ createBitcodeWriterPass(*OS, CodeGenOpts.EmitLLVMUseLists));
break;
case Backend_EmitLL:
- FormattedOS.setStream(*OS, formatted_raw_ostream::PRESERVE_STREAM);
- getPerModulePasses()->add(createPrintModulePass(FormattedOS));
+ getPerModulePasses()->add(
+ createPrintModulePass(*OS, "", CodeGenOpts.EmitLLVMUseLists));
break;
default:
- FormattedOS.setStream(*OS, formatted_raw_ostream::PRESERVE_STREAM);
- if (!AddEmitPasses(Action, FormattedOS))
+ if (!AddEmitPasses(Action, *OS))
return;
}
@@ -651,7 +648,7 @@
const clang::TargetOptions &TOpts,
const LangOptions &LOpts, StringRef TDesc,
Module *M, BackendAction Action,
- raw_ostream *OS) {
+ raw_pwrite_stream *OS) {
EmitAssemblyHelper AsmHelper(Diags, CGOpts, TOpts, LOpts, M);
AsmHelper.EmitAssembly(Action, OS);
diff --git a/lib/CodeGen/CGAtomic.cpp b/lib/CodeGen/CGAtomic.cpp
index b7222fc..2de9cb2 100644
--- a/lib/CodeGen/CGAtomic.cpp
+++ b/lib/CodeGen/CGAtomic.cpp
@@ -189,7 +189,7 @@
assert(LVal.isSimple());
llvm::Value *addr = getAtomicAddress();
if (hasPadding())
- addr = CGF.Builder.CreateStructGEP(addr, 0);
+ addr = CGF.Builder.CreateStructGEP(nullptr, addr, 0);
return LValue::MakeAddr(addr, getValueType(), LVal.getAlignment(),
CGF.getContext(), LVal.getTBAAInfo());
@@ -209,7 +209,7 @@
/// \param IsWeak true if atomic operation is weak, false otherwise.
/// \returns Pair of values: previous value from storage (value type) and
/// boolean flag (i1 type) with true if success and false otherwise.
- std::pair<llvm::Value *, llvm::Value *> EmitAtomicCompareExchange(
+ std::pair<RValue, llvm::Value *> EmitAtomicCompareExchange(
RValue Expected, RValue Desired,
llvm::AtomicOrdering Success = llvm::SequentiallyConsistent,
llvm::AtomicOrdering Failure = llvm::SequentiallyConsistent,
@@ -235,13 +235,13 @@
/// \brief Emits atomic load as LLVM instruction.
llvm::Value *EmitAtomicLoadOp(llvm::AtomicOrdering AO, bool IsVolatile);
/// \brief Emits atomic compare-and-exchange op as a libcall.
- std::pair<llvm::Value *, llvm::Value *> EmitAtomicCompareExchangeLibcall(
- llvm::Value *ExpectedAddr, llvm::Value *DesiredAddr,
+ std::pair<RValue, llvm::Value *> EmitAtomicCompareExchangeLibcall(
+ RValue Expected, RValue DesiredAddr,
llvm::AtomicOrdering Success = llvm::SequentiallyConsistent,
llvm::AtomicOrdering Failure = llvm::SequentiallyConsistent);
/// \brief Emits atomic compare-and-exchange op as LLVM instruction.
- std::pair<llvm::Value *, llvm::Value *> EmitAtomicCompareExchangeOp(
- llvm::Value *Expected, llvm::Value *Desired,
+ std::pair<RValue, llvm::Value *> EmitAtomicCompareExchangeOp(
+ RValue Expected, RValue Desired,
llvm::AtomicOrdering Success = llvm::SequentiallyConsistent,
llvm::AtomicOrdering Failure = llvm::SequentiallyConsistent,
bool IsWeak = false);
@@ -1060,19 +1060,20 @@
// Drill into the padding structure if we have one.
if (hasPadding())
- addr = CGF.Builder.CreateStructGEP(addr, 0);
+ addr = CGF.Builder.CreateStructGEP(nullptr, addr, 0);
// Otherwise, just convert the temporary to an r-value using the
// normal conversion routine.
return CGF.convertTempToRValue(addr, getValueType(), loc);
- } else if (!AsValue)
+ }
+ if (!AsValue)
// Get RValue from temp memory as atomic for non-simple lvalues
return RValue::get(
CGF.Builder.CreateAlignedLoad(addr, AtomicAlign.getQuantity()));
- else if (LVal.isBitField())
+ if (LVal.isBitField())
return CGF.EmitLoadOfBitfieldLValue(LValue::MakeBitfield(
addr, LVal.getBitFieldInfo(), LVal.getType(), LVal.getAlignment()));
- else if (LVal.isVectorElt())
+ if (LVal.isVectorElt())
return CGF.EmitLoadOfLValue(LValue::MakeVectorElt(addr, LVal.getVectorIdx(),
LVal.getType(),
LVal.getAlignment()),
@@ -1291,7 +1292,7 @@
if (RVal.isScalar() && (!hasPadding() || !LVal.isSimple())) {
llvm::Value *Value = RVal.getScalarVal();
if (isa<llvm::IntegerType>(Value->getType()))
- return Value;
+ return CGF.EmitToMemory(Value, ValueTy);
else {
llvm::IntegerType *InputIntTy = llvm::IntegerType::get(
CGF.getLLVMContext(),
@@ -1312,13 +1313,15 @@
getAtomicAlignment().getQuantity());
}
-std::pair<llvm::Value *, llvm::Value *> AtomicInfo::EmitAtomicCompareExchangeOp(
- llvm::Value *Expected, llvm::Value *Desired, llvm::AtomicOrdering Success,
+std::pair<RValue, llvm::Value *> AtomicInfo::EmitAtomicCompareExchangeOp(
+ RValue Expected, RValue Desired, llvm::AtomicOrdering Success,
llvm::AtomicOrdering Failure, bool IsWeak) {
// Do the atomic store.
+ auto *ExpectedVal = convertRValueToInt(Expected);
+ auto *DesiredVal = convertRValueToInt(Desired);
auto *Addr = emitCastToAtomicIntPointer(getAtomicAddress());
- auto *Inst = CGF.Builder.CreateAtomicCmpXchg(Addr, Expected, Desired, Success,
- Failure);
+ auto *Inst = CGF.Builder.CreateAtomicCmpXchg(Addr, ExpectedVal, DesiredVal,
+ Success, Failure);
// Other decoration.
Inst->setVolatile(LVal.isVolatileQualified());
Inst->setWeak(IsWeak);
@@ -1326,16 +1329,20 @@
// Okay, turn that back into the original value type.
auto *PreviousVal = CGF.Builder.CreateExtractValue(Inst, /*Idxs=*/0);
auto *SuccessFailureVal = CGF.Builder.CreateExtractValue(Inst, /*Idxs=*/1);
- return std::make_pair(PreviousVal, SuccessFailureVal);
+ return std::make_pair(
+ ConvertIntToValueOrAtomic(PreviousVal, AggValueSlot::ignored(),
+ SourceLocation(), /*AsValue=*/false),
+ SuccessFailureVal);
}
-std::pair<llvm::Value *, llvm::Value *>
-AtomicInfo::EmitAtomicCompareExchangeLibcall(llvm::Value *ExpectedAddr,
- llvm::Value *DesiredAddr,
+std::pair<RValue, llvm::Value *>
+AtomicInfo::EmitAtomicCompareExchangeLibcall(RValue Expected, RValue Desired,
llvm::AtomicOrdering Success,
llvm::AtomicOrdering Failure) {
// bool __atomic_compare_exchange(size_t size, void *obj, void *expected,
// void *desired, int success, int failure);
+ auto *ExpectedAddr = materializeRValue(Expected);
+ auto *DesiredAddr = materializeRValue(Desired);
CallArgList Args;
Args.add(RValue::get(getAtomicSizeValue()), CGF.getContext().getSizeType());
Args.add(RValue::get(CGF.EmitCastToVoidPtr(getAtomicAddress())),
@@ -1352,12 +1359,14 @@
CGF.getContext().IntTy);
auto SuccessFailureRVal = emitAtomicLibcall(CGF, "__atomic_compare_exchange",
CGF.getContext().BoolTy, Args);
- auto *PreviousVal = CGF.Builder.CreateAlignedLoad(
- ExpectedAddr, getValueAlignment().getQuantity());
- return std::make_pair(PreviousVal, SuccessFailureRVal.getScalarVal());
+
+ return std::make_pair(
+ convertTempToRValue(ExpectedAddr, AggValueSlot::ignored(),
+ SourceLocation(), /*AsValue=*/false),
+ SuccessFailureRVal.getScalarVal());
}
-std::pair<llvm::Value *, llvm::Value *> AtomicInfo::EmitAtomicCompareExchange(
+std::pair<RValue, llvm::Value *> AtomicInfo::EmitAtomicCompareExchange(
RValue Expected, RValue Desired, llvm::AtomicOrdering Success,
llvm::AtomicOrdering Failure, bool IsWeak) {
if (Failure >= Success)
@@ -1366,20 +1375,15 @@
// Check whether we should use a library call.
if (shouldUseLibcall()) {
- auto *ExpectedAddr = materializeRValue(Expected);
// Produce a source address.
- auto *DesiredAddr = materializeRValue(Desired);
- return EmitAtomicCompareExchangeLibcall(ExpectedAddr, DesiredAddr, Success,
+ return EmitAtomicCompareExchangeLibcall(Expected, Desired, Success,
Failure);
}
// If we've got a scalar value of the right size, try to avoid going
// through memory.
- auto *ExpectedIntVal = convertRValueToInt(Expected);
- auto *DesiredIntVal = convertRValueToInt(Desired);
-
- return EmitAtomicCompareExchangeOp(ExpectedIntVal, DesiredIntVal, Success,
- Failure, IsWeak);
+ return EmitAtomicCompareExchangeOp(Expected, Desired, Success, Failure,
+ IsWeak);
}
void CodeGenFunction::EmitAtomicStore(RValue rvalue, LValue lvalue,
@@ -1498,20 +1502,14 @@
atomics.getAtomicType(), SourceLocation()));
// Try to write new value using cmpxchg operation
auto Pair = atomics.EmitAtomicCompareExchange(OriginalRValue, NewRValue, AO);
- llvm::Value *OldValue = Pair.first;
- if (!atomics.shouldUseLibcall())
- // Convert integer value to original atomic type
- OldValue = atomics.ConvertIntToValueOrAtomic(
- OldValue, AggValueSlot::ignored(), SourceLocation(),
- /*AsValue=*/false).getScalarVal();
- PHI->addIncoming(OldValue, ContBB);
+ PHI->addIncoming(Pair.first.getScalarVal(), ContBB);
Builder.CreateCondBr(Pair.second, ExitBB, ContBB);
EmitBlock(ExitBB, /*IsFinished=*/true);
}
/// Emit a compare-and-exchange op for atomic type.
///
-std::pair<RValue, RValue> CodeGenFunction::EmitAtomicCompareExchange(
+std::pair<RValue, llvm::Value *> CodeGenFunction::EmitAtomicCompareExchange(
LValue Obj, RValue Expected, RValue Desired, SourceLocation Loc,
llvm::AtomicOrdering Success, llvm::AtomicOrdering Failure, bool IsWeak,
AggValueSlot Slot) {
@@ -1525,13 +1523,78 @@
Obj.getAddress()->getType()->getPointerElementType());
AtomicInfo Atomics(*this, Obj);
- auto Pair = Atomics.EmitAtomicCompareExchange(Expected, Desired, Success,
- Failure, IsWeak);
- return std::make_pair(Atomics.shouldUseLibcall()
- ? RValue::get(Pair.first)
- : Atomics.ConvertIntToValueOrAtomic(
- Pair.first, Slot, Loc, /*AsValue=*/true),
- RValue::get(Pair.second));
+ return Atomics.EmitAtomicCompareExchange(Expected, Desired, Success, Failure,
+ IsWeak);
+}
+
+void CodeGenFunction::EmitAtomicUpdate(
+ LValue LVal, llvm::AtomicOrdering AO,
+ const std::function<RValue(RValue)> &UpdateOp, bool IsVolatile) {
+ AtomicInfo Atomics(*this, LVal);
+ LValue AtomicLVal = Atomics.getAtomicLValue();
+
+ // Atomic load of prev value.
+ RValue OldRVal =
+ Atomics.EmitAtomicLoad(AggValueSlot::ignored(), SourceLocation(),
+ /*AsValue=*/false, AO, IsVolatile);
+ bool IsScalar = OldRVal.isScalar();
+ auto *OldVal =
+ IsScalar ? OldRVal.getScalarVal() : Atomics.convertRValueToInt(OldRVal);
+ // For non-simple lvalues perform compare-and-swap procedure.
+ auto *ContBB = createBasicBlock("atomic_cont");
+ auto *ExitBB = createBasicBlock("atomic_exit");
+ auto *CurBB = Builder.GetInsertBlock();
+ EmitBlock(ContBB);
+ llvm::PHINode *PHI = Builder.CreatePHI(OldVal->getType(),
+ /*NumReservedValues=*/2);
+ PHI->addIncoming(OldVal, CurBB);
+ RValue OriginalRValue =
+ IsScalar ? RValue::get(PHI) : Atomics.ConvertIntToValueOrAtomic(
+ PHI, AggValueSlot::ignored(),
+ SourceLocation(), /*AsValue=*/false);
+ // Build new lvalue for temp address
+ LValue UpdateLVal;
+ llvm::Value *Ptr = nullptr;
+ RValue UpRVal;
+ if (AtomicLVal.isSimple()) {
+ UpRVal = OriginalRValue;
+ } else {
+ // Build new lvalue for temp address
+ Ptr = Atomics.materializeRValue(OriginalRValue);
+ if (AtomicLVal.isBitField())
+ UpdateLVal =
+ LValue::MakeBitfield(Ptr, AtomicLVal.getBitFieldInfo(),
+ AtomicLVal.getType(), AtomicLVal.getAlignment());
+ else if (AtomicLVal.isVectorElt())
+ UpdateLVal = LValue::MakeVectorElt(Ptr, AtomicLVal.getVectorIdx(),
+ AtomicLVal.getType(),
+ AtomicLVal.getAlignment());
+ else {
+ assert(AtomicLVal.isExtVectorElt());
+ UpdateLVal = LValue::MakeExtVectorElt(Ptr, AtomicLVal.getExtVectorElts(),
+ AtomicLVal.getType(),
+ AtomicLVal.getAlignment());
+ }
+ UpdateLVal.setTBAAInfo(LVal.getTBAAInfo());
+ UpRVal = EmitLoadOfLValue(UpdateLVal, SourceLocation());
+ }
+ // Store new value in the corresponding memory area
+ RValue NewRVal = UpdateOp(UpRVal);
+ if (!AtomicLVal.isSimple()) {
+ EmitStoreThroughLValue(NewRVal, UpdateLVal);
+ // Load new value
+ NewRVal = RValue::get(
+ EmitLoadOfScalar(Ptr, AtomicLVal.isVolatile(),
+ Atomics.getAtomicAlignment().getQuantity(),
+ Atomics.getAtomicType(), SourceLocation()));
+ }
+ // Try to write new value using cmpxchg operation
+ auto Pair = Atomics.EmitAtomicCompareExchange(OriginalRValue, NewRVal, AO);
+ OldVal = IsScalar ? Pair.first.getScalarVal()
+ : Atomics.convertRValueToInt(Pair.first);
+ PHI->addIncoming(OldVal, ContBB);
+ Builder.CreateCondBr(Pair.second, ExitBB, ContBB);
+ EmitBlock(ExitBB, /*IsFinished=*/true);
}
void CodeGenFunction::EmitAtomicInit(Expr *init, LValue dest) {
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
index 7b8e839..202996b 100644
--- a/lib/CodeGen/CGBlocks.cpp
+++ b/lib/CodeGen/CGBlocks.cpp
@@ -621,8 +621,8 @@
}
// GEP down to the address.
- llvm::Value *addr = CGF.Builder.CreateStructGEP(blockInfo.Address,
- capture.getIndex());
+ llvm::Value *addr = CGF.Builder.CreateStructGEP(
+ blockInfo.StructureType, blockInfo.Address, capture.getIndex());
// We can use that GEP as the dominating IP.
if (!blockInfo.DominatingIP)
@@ -721,6 +721,7 @@
// Build the block descriptor.
llvm::Constant *descriptor = buildBlockDescriptor(CGM, blockInfo);
+ llvm::Type *blockTy = blockInfo.StructureType;
llvm::AllocaInst *blockAddr = blockInfo.Address;
assert(blockAddr && "block has no address!");
@@ -732,14 +733,17 @@
if (blockInfo.UsesStret) flags |= BLOCK_USE_STRET;
// Initialize the block literal.
- Builder.CreateStore(isa, Builder.CreateStructGEP(blockAddr, 0, "block.isa"));
- Builder.CreateStore(llvm::ConstantInt::get(IntTy, flags.getBitMask()),
- Builder.CreateStructGEP(blockAddr, 1, "block.flags"));
- Builder.CreateStore(llvm::ConstantInt::get(IntTy, 0),
- Builder.CreateStructGEP(blockAddr, 2, "block.reserved"));
- Builder.CreateStore(blockFn, Builder.CreateStructGEP(blockAddr, 3,
- "block.invoke"));
- Builder.CreateStore(descriptor, Builder.CreateStructGEP(blockAddr, 4,
+ Builder.CreateStore(
+ isa, Builder.CreateStructGEP(blockTy, blockAddr, 0, "block.isa"));
+ Builder.CreateStore(
+ llvm::ConstantInt::get(IntTy, flags.getBitMask()),
+ Builder.CreateStructGEP(blockTy, blockAddr, 1, "block.flags"));
+ Builder.CreateStore(
+ llvm::ConstantInt::get(IntTy, 0),
+ Builder.CreateStructGEP(blockTy, blockAddr, 2, "block.reserved"));
+ Builder.CreateStore(
+ blockFn, Builder.CreateStructGEP(blockTy, blockAddr, 3, "block.invoke"));
+ Builder.CreateStore(descriptor, Builder.CreateStructGEP(blockTy, blockAddr, 4,
"block.descriptor"));
// Finally, capture all the values into the block.
@@ -747,9 +751,8 @@
// First, 'this'.
if (blockDecl->capturesCXXThis()) {
- llvm::Value *addr = Builder.CreateStructGEP(blockAddr,
- blockInfo.CXXThisIndex,
- "block.captured-this.addr");
+ llvm::Value *addr = Builder.CreateStructGEP(
+ blockTy, blockAddr, blockInfo.CXXThisIndex, "block.captured-this.addr");
Builder.CreateStore(LoadCXXThis(), addr);
}
@@ -766,9 +769,8 @@
// This will be a [[type]]*, except that a byref entry will just be
// an i8**.
- llvm::Value *blockField =
- Builder.CreateStructGEP(blockAddr, capture.getIndex(),
- "block.captured");
+ llvm::Value *blockField = Builder.CreateStructGEP(
+ blockTy, blockAddr, capture.getIndex(), "block.captured");
// Compute the address of the thing we're going to move into the
// block literal.
@@ -779,7 +781,7 @@
BlockInfo->getCapture(variable);
// This is a [[type]]*, except that a byref entry wil just be an i8**.
- src = Builder.CreateStructGEP(LoadBlockStruct(),
+ src = Builder.CreateStructGEP(BlockInfo->StructureType, LoadBlockStruct(),
enclosingCapture.getIndex(),
"block.capture.addr");
} else if (blockDecl->isConversionFromLambda()) {
@@ -964,7 +966,8 @@
Builder.CreateBitCast(Callee, BlockLiteralTy, "block.literal");
// Get the function pointer from the literal.
- llvm::Value *FuncPtr = Builder.CreateStructGEP(BlockLiteral, 3);
+ llvm::Value *FuncPtr = Builder.CreateStructGEP(
+ CGM.getGenericBlockLiteralType(), BlockLiteral, 3);
BlockLiteral = Builder.CreateBitCast(BlockLiteral, VoidPtrTy);
@@ -1004,26 +1007,27 @@
if (capture.isConstant()) return LocalDeclMap[variable];
llvm::Value *addr =
- Builder.CreateStructGEP(LoadBlockStruct(), capture.getIndex(),
- "block.capture.addr");
+ Builder.CreateStructGEP(BlockInfo->StructureType, LoadBlockStruct(),
+ capture.getIndex(), "block.capture.addr");
if (isByRef) {
// addr should be a void** right now. Load, then cast the result
// to byref*.
addr = Builder.CreateLoad(addr);
- llvm::PointerType *byrefPointerType
- = llvm::PointerType::get(BuildByRefType(variable), 0);
+ auto *byrefType = BuildByRefType(variable);
+ llvm::PointerType *byrefPointerType = llvm::PointerType::get(byrefType, 0);
addr = Builder.CreateBitCast(addr, byrefPointerType,
"byref.addr");
// Follow the forwarding pointer.
- addr = Builder.CreateStructGEP(addr, 1, "byref.forwarding");
+ addr = Builder.CreateStructGEP(byrefType, addr, 1, "byref.forwarding");
addr = Builder.CreateLoad(addr, "byref.addr.forwarded");
// Cast back to byref* and GEP over to the actual object.
addr = Builder.CreateBitCast(addr, byrefPointerType);
- addr = Builder.CreateStructGEP(addr, getByRefValueLLVMField(variable),
+ addr = Builder.CreateStructGEP(byrefType, addr,
+ getByRefValueLLVMField(variable).second,
variable->getNameAsString());
}
@@ -1185,9 +1189,9 @@
// If we have a C++ 'this' reference, go ahead and force it into
// existence now.
if (blockDecl->capturesCXXThis()) {
- llvm::Value *addr = Builder.CreateStructGEP(BlockPointer,
- blockInfo.CXXThisIndex,
- "block.captured-this");
+ llvm::Value *addr =
+ Builder.CreateStructGEP(blockInfo.StructureType, BlockPointer,
+ blockInfo.CXXThisIndex, "block.captured-this");
CXXThisValue = Builder.CreateLoad(addr, "this");
}
@@ -1402,8 +1406,10 @@
}
unsigned index = capture.getIndex();
- llvm::Value *srcField = Builder.CreateStructGEP(src, index);
- llvm::Value *dstField = Builder.CreateStructGEP(dst, index);
+ llvm::Value *srcField =
+ Builder.CreateStructGEP(blockInfo.StructureType, src, index);
+ llvm::Value *dstField =
+ Builder.CreateStructGEP(blockInfo.StructureType, dst, index);
// If there's an explicit copy expression, we do that.
if (copyExpr) {
@@ -1560,7 +1566,8 @@
}
unsigned index = capture.getIndex();
- llvm::Value *srcField = Builder.CreateStructGEP(src, index);
+ llvm::Value *srcField =
+ Builder.CreateStructGEP(blockInfo.StructureType, src, index);
// If there's an explicit copy expression, we do that.
if (dtor) {
@@ -1799,13 +1806,15 @@
llvm::Value *destField = CGF.GetAddrOfLocalVar(&dst);
destField = CGF.Builder.CreateLoad(destField);
destField = CGF.Builder.CreateBitCast(destField, byrefPtrType);
- destField = CGF.Builder.CreateStructGEP(destField, valueFieldIndex, "x");
+ destField = CGF.Builder.CreateStructGEP(&byrefType, destField,
+ valueFieldIndex, "x");
// src->x
llvm::Value *srcField = CGF.GetAddrOfLocalVar(&src);
srcField = CGF.Builder.CreateLoad(srcField);
srcField = CGF.Builder.CreateBitCast(srcField, byrefPtrType);
- srcField = CGF.Builder.CreateStructGEP(srcField, valueFieldIndex, "x");
+ srcField =
+ CGF.Builder.CreateStructGEP(&byrefType, srcField, valueFieldIndex, "x");
byrefInfo.emitCopy(CGF, destField, srcField);
}
@@ -1866,7 +1875,7 @@
llvm::Value *V = CGF.GetAddrOfLocalVar(&src);
V = CGF.Builder.CreateLoad(V);
V = CGF.Builder.CreateBitCast(V, byrefType.getPointerTo(0));
- V = CGF.Builder.CreateStructGEP(V, byrefValueIndex, "x");
+ V = CGF.Builder.CreateStructGEP(&byrefType, V, byrefValueIndex, "x");
byrefInfo.emitDispose(CGF, V);
}
@@ -1923,7 +1932,7 @@
const VarDecl &var = *emission.Variable;
QualType type = var.getType();
- unsigned byrefValueIndex = getByRefValueLLVMField(&var);
+ unsigned byrefValueIndex = getByRefValueLLVMField(&var).second;
if (const CXXRecordDecl *record = type->getAsCXXRecordDecl()) {
const Expr *copyExpr = CGM.getContext().getBlockVarCopyInits(&var);
@@ -1993,18 +2002,20 @@
return ::buildByrefHelpers(CGM, byrefType, byrefValueIndex, byrefInfo);
}
-unsigned CodeGenFunction::getByRefValueLLVMField(const ValueDecl *VD) const {
+std::pair<llvm::Type *, unsigned>
+CodeGenFunction::getByRefValueLLVMField(const ValueDecl *VD) const {
assert(ByRefValueInfo.count(VD) && "Did not find value!");
-
- return ByRefValueInfo.find(VD)->second.second;
+
+ return ByRefValueInfo.find(VD)->second;
}
llvm::Value *CodeGenFunction::BuildBlockByrefAddress(llvm::Value *BaseAddr,
const VarDecl *V) {
- llvm::Value *Loc = Builder.CreateStructGEP(BaseAddr, 1, "forwarding");
+ auto P = getByRefValueLLVMField(V);
+ llvm::Value *Loc =
+ Builder.CreateStructGEP(P.first, BaseAddr, 1, "forwarding");
Loc = Builder.CreateLoad(Loc);
- Loc = Builder.CreateStructGEP(Loc, getByRefValueLLVMField(V),
- V->getNameAsString());
+ Loc = Builder.CreateStructGEP(P.first, Loc, P.second, V->getNameAsString());
return Loc;
}
@@ -2141,11 +2152,12 @@
if (type.isObjCGCWeak())
isa = 1;
V = Builder.CreateIntToPtr(Builder.getInt32(isa), Int8PtrTy, "isa");
- Builder.CreateStore(V, Builder.CreateStructGEP(addr, 0, "byref.isa"));
+ Builder.CreateStore(V,
+ Builder.CreateStructGEP(nullptr, addr, 0, "byref.isa"));
// Store the address of the variable into its own forwarding pointer.
- Builder.CreateStore(addr,
- Builder.CreateStructGEP(addr, 1, "byref.forwarding"));
+ Builder.CreateStore(
+ addr, Builder.CreateStructGEP(nullptr, addr, 1, "byref.forwarding"));
// Blocks ABI:
// c) the flags field is set to either 0 if no helper functions are
@@ -2191,25 +2203,26 @@
printf("\n");
}
}
-
+
Builder.CreateStore(llvm::ConstantInt::get(IntTy, flags.getBitMask()),
- Builder.CreateStructGEP(addr, 2, "byref.flags"));
+ Builder.CreateStructGEP(nullptr, addr, 2, "byref.flags"));
CharUnits byrefSize = CGM.GetTargetTypeStoreSize(byrefType);
V = llvm::ConstantInt::get(IntTy, byrefSize.getQuantity());
- Builder.CreateStore(V, Builder.CreateStructGEP(addr, 3, "byref.size"));
+ Builder.CreateStore(V,
+ Builder.CreateStructGEP(nullptr, addr, 3, "byref.size"));
if (helpers) {
- llvm::Value *copy_helper = Builder.CreateStructGEP(addr, 4);
+ llvm::Value *copy_helper = Builder.CreateStructGEP(nullptr, addr, 4);
Builder.CreateStore(helpers->CopyHelper, copy_helper);
- llvm::Value *destroy_helper = Builder.CreateStructGEP(addr, 5);
+ llvm::Value *destroy_helper = Builder.CreateStructGEP(nullptr, addr, 5);
Builder.CreateStore(helpers->DisposeHelper, destroy_helper);
}
if (ByRefHasLifetime && HasByrefExtendedLayout) {
llvm::Constant* ByrefLayoutInfo = CGM.getObjCRuntime().BuildByrefLayout(CGM, type);
- llvm::Value *ByrefInfoAddr = Builder.CreateStructGEP(addr, helpers ? 6 : 4,
- "byref.layout");
+ llvm::Value *ByrefInfoAddr =
+ Builder.CreateStructGEP(nullptr, addr, helpers ? 6 : 4, "byref.layout");
// cast destination to pointer to source type.
llvm::Type *DesTy = ByrefLayoutInfo->getType();
DesTy = DesTy->getPointerTo();
diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp
index 35597fe..2653d7c 100644
--- a/lib/CodeGen/CGBuiltin.cpp
+++ b/lib/CodeGen/CGBuiltin.cpp
@@ -1865,6 +1865,8 @@
case llvm::Triple::r600:
case llvm::Triple::amdgcn:
return EmitR600BuiltinExpr(BuiltinID, E);
+ case llvm::Triple::systemz:
+ return EmitSystemZBuiltinExpr(BuiltinID, E);
default:
return nullptr;
}
@@ -3105,7 +3107,7 @@
Indices.push_back(Builder.getInt32(i+vi));
Indices.push_back(Builder.getInt32(i+e+vi));
}
- Value *Addr = Builder.CreateConstInBoundsGEP1_32(Ops[0], vi);
+ Value *Addr = Builder.CreateConstInBoundsGEP1_32(Ty, Ops[0], vi);
SV = llvm::ConstantVector::get(Indices);
SV = Builder.CreateShuffleVector(Ops[1], Ops[2], SV, "vtrn");
SV = Builder.CreateStore(SV, Addr);
@@ -3133,7 +3135,7 @@
for (unsigned i = 0, e = VTy->getNumElements(); i != e; ++i)
Indices.push_back(ConstantInt::get(Int32Ty, 2*i+vi));
- Value *Addr = Builder.CreateConstInBoundsGEP1_32(Ops[0], vi);
+ Value *Addr = Builder.CreateConstInBoundsGEP1_32(Ty, Ops[0], vi);
SV = llvm::ConstantVector::get(Indices);
SV = Builder.CreateShuffleVector(Ops[1], Ops[2], SV, "vuzp");
SV = Builder.CreateStore(SV, Addr);
@@ -3153,7 +3155,7 @@
Indices.push_back(ConstantInt::get(Int32Ty, (i + vi*e) >> 1));
Indices.push_back(ConstantInt::get(Int32Ty, ((i + vi*e) >> 1)+e));
}
- Value *Addr = Builder.CreateConstInBoundsGEP1_32(Ops[0], vi);
+ Value *Addr = Builder.CreateConstInBoundsGEP1_32(Ty, Ops[0], vi);
SV = llvm::ConstantVector::get(Indices);
SV = Builder.CreateShuffleVector(Ops[1], Ops[2], SV, "vzip");
SV = Builder.CreateStore(SV, Addr);
@@ -5768,7 +5770,7 @@
Indices.push_back(ConstantInt::get(Int32Ty, i+vi));
Indices.push_back(ConstantInt::get(Int32Ty, i+e+vi));
}
- Value *Addr = Builder.CreateConstInBoundsGEP1_32(Ops[0], vi);
+ Value *Addr = Builder.CreateConstInBoundsGEP1_32(Ty, Ops[0], vi);
SV = llvm::ConstantVector::get(Indices);
SV = Builder.CreateShuffleVector(Ops[1], Ops[2], SV, "vtrn");
SV = Builder.CreateStore(SV, Addr);
@@ -5787,7 +5789,7 @@
for (unsigned i = 0, e = VTy->getNumElements(); i != e; ++i)
Indices.push_back(ConstantInt::get(Int32Ty, 2*i+vi));
- Value *Addr = Builder.CreateConstInBoundsGEP1_32(Ops[0], vi);
+ Value *Addr = Builder.CreateConstInBoundsGEP1_32(Ty, Ops[0], vi);
SV = llvm::ConstantVector::get(Indices);
SV = Builder.CreateShuffleVector(Ops[1], Ops[2], SV, "vuzp");
SV = Builder.CreateStore(SV, Addr);
@@ -5807,7 +5809,7 @@
Indices.push_back(ConstantInt::get(Int32Ty, (i + vi*e) >> 1));
Indices.push_back(ConstantInt::get(Int32Ty, ((i + vi*e) >> 1)+e));
}
- Value *Addr = Builder.CreateConstInBoundsGEP1_32(Ops[0], vi);
+ Value *Addr = Builder.CreateConstInBoundsGEP1_32(Ty, Ops[0], vi);
SV = llvm::ConstantVector::get(Indices);
SV = Builder.CreateShuffleVector(Ops[1], Ops[2], SV, "vzip");
SV = Builder.CreateStore(SV, Addr);
@@ -6371,119 +6373,6 @@
llvm::Function *F = CGM.getIntrinsic(ID);
return Builder.CreateCall(F, Ops, "");
}
-
- // P8 Crypto builtins
- case PPC::BI__builtin_altivec_crypto_vshasigmaw:
- case PPC::BI__builtin_altivec_crypto_vshasigmad:
- {
- ConstantInt *CI1 = dyn_cast<ConstantInt>(Ops[1]);
- ConstantInt *CI2 = dyn_cast<ConstantInt>(Ops[2]);
- assert(CI1 && CI2);
- if (CI1->getZExtValue() > 1) {
- CGM.Error(E->getArg(1)->getExprLoc(),
- "argument out of range (should be 0-1).");
- return llvm::UndefValue::get(Ops[0]->getType());
- }
- if (CI2->getZExtValue() > 15) {
- CGM.Error(E->getArg(2)->getExprLoc(),
- "argument out of range (should be 0-15).");
- return llvm::UndefValue::get(Ops[0]->getType());
- }
- switch (BuiltinID) {
- default: llvm_unreachable("Unsupported sigma intrinsic!");
- case PPC::BI__builtin_altivec_crypto_vshasigmaw:
- ID = Intrinsic::ppc_altivec_crypto_vshasigmaw;
- break;
- case PPC::BI__builtin_altivec_crypto_vshasigmad:
- ID = Intrinsic::ppc_altivec_crypto_vshasigmad;
- break;
- }
- llvm::Function *F = CGM.getIntrinsic(ID);
- return Builder.CreateCall(F, Ops, "");
- }
-
- // HTM builtins
- case PPC::BI__builtin_tbegin:
- case PPC::BI__builtin_tend:
- case PPC::BI__builtin_tsr: {
- unsigned int MaxValue;
- // The HTM instructions only accept one argument and with limited range.
- ConstantInt *CI = dyn_cast<ConstantInt>(Ops[0]);
- assert(CI);
- switch (BuiltinID) {
- case PPC::BI__builtin_tbegin:
- ID = Intrinsic::ppc_tbegin;
- MaxValue = 1;
- break;
- case PPC::BI__builtin_tend:
- ID = Intrinsic::ppc_tend;
- MaxValue = 1;
- break;
- case PPC::BI__builtin_tsr:
- ID = Intrinsic::ppc_tsr;
- MaxValue = 7;
- break;
- }
- if (CI->getZExtValue() > MaxValue) {
- std::stringstream ss;
- ss << "argument out of range (should be 0 or " << MaxValue << ")";
- CGM.Error(E->getArg(0)->getExprLoc(), ss.str());
- return llvm::UndefValue::get(Ops[0]->getType());
- }
-
- llvm::Function *F = CGM.getIntrinsic(ID);
- return Builder.CreateCall(F, Ops, "");
- }
- case PPC::BI__builtin_tabortdc:
- case PPC::BI__builtin_tabortwc: {
- // For wd and dc variant of tabort first argument must be a 5-bit constant
- // integer
- ConstantInt *CI = dyn_cast<ConstantInt>(Ops[0]);
- assert(CI);
- if (CI->getZExtValue() > 31) {
- CGM.ErrorUnsupported(E->getArg(0), "argument out of range (should be 0-31)");
- return llvm::UndefValue::get(Ops[0]->getType());
- }
- switch (BuiltinID) {
- case PPC::BI__builtin_tabortdc:
- ID = Intrinsic::ppc_tabortdc;
- break;
- case PPC::BI__builtin_tabortwc:
- ID = Intrinsic::ppc_tabortwc;
- break;
- }
- llvm::Function *F = CGM.getIntrinsic(ID);
- return Builder.CreateCall(F, Ops, "");
- }
- case PPC::BI__builtin_tabortdci:
- case PPC::BI__builtin_tabortwci: {
- // For wd and dc variant of tabort first and third argument must be a
- // 5-bit constant integer
- ConstantInt *CI = dyn_cast<ConstantInt>(Ops[0]);
- assert(CI);
- if (CI->getZExtValue() > 31) {
- CGM.ErrorUnsupported(E->getArg(0), "argument out of range (should be 0-31)");
- return llvm::UndefValue::get(Ops[0]->getType());
- }
- CI = dyn_cast<ConstantInt>(Ops[2]);
- assert(CI);
- if (CI->getZExtValue() > 31) {
- CGM.ErrorUnsupported(E->getArg(2), "argument out of range (should be 0-31)");
- return llvm::UndefValue::get(Ops[2]->getType());
- }
- switch (BuiltinID) {
- default: llvm_unreachable("Unsupported htm intrinsic!");
- case PPC::BI__builtin_tabortdci:
- ID = Intrinsic::ppc_tabortdci;
- break;
- case PPC::BI__builtin_tabortwci:
- ID = Intrinsic::ppc_tabortwci;
- break;
- }
- llvm::Function *F = CGM.getIntrinsic(ID);
- return Builder.CreateCall(F, Ops, "");
- }
-
}
}
@@ -6588,3 +6477,41 @@
return nullptr;
}
}
+
+Value *CodeGenFunction::EmitSystemZBuiltinExpr(unsigned BuiltinID,
+ const CallExpr *E) {
+ switch (BuiltinID) {
+ case SystemZ::BI__builtin_tbegin: {
+ Value *TDB = EmitScalarExpr(E->getArg(0));
+ Value *Control = llvm::ConstantInt::get(Int32Ty, 0xff0c);
+ Value *F = CGM.getIntrinsic(Intrinsic::s390_tbegin);
+ return Builder.CreateCall2(F, TDB, Control);
+ }
+ case SystemZ::BI__builtin_tbegin_nofloat: {
+ Value *TDB = EmitScalarExpr(E->getArg(0));
+ Value *Control = llvm::ConstantInt::get(Int32Ty, 0xff0c);
+ Value *F = CGM.getIntrinsic(Intrinsic::s390_tbegin_nofloat);
+ return Builder.CreateCall2(F, TDB, Control);
+ }
+ case SystemZ::BI__builtin_tbeginc: {
+ Value *TDB = llvm::ConstantPointerNull::get(Int8PtrTy);
+ Value *Control = llvm::ConstantInt::get(Int32Ty, 0xff08);
+ Value *F = CGM.getIntrinsic(Intrinsic::s390_tbeginc);
+ return Builder.CreateCall2(F, TDB, Control);
+ }
+ case SystemZ::BI__builtin_tabort: {
+ Value *Data = EmitScalarExpr(E->getArg(0));
+ Value *F = CGM.getIntrinsic(Intrinsic::s390_tabort);
+ return Builder.CreateCall(F, Builder.CreateSExt(Data, Int64Ty, "tabort"));
+ }
+ case SystemZ::BI__builtin_non_tx_store: {
+ Value *Address = EmitScalarExpr(E->getArg(0));
+ Value *Data = EmitScalarExpr(E->getArg(1));
+ Value *F = CGM.getIntrinsic(Intrinsic::s390_ntstg);
+ return Builder.CreateCall2(F, Data, Address);
+ }
+
+ default:
+ return nullptr;
+ }
+}
diff --git a/lib/CodeGen/CGCXXABI.h b/lib/CodeGen/CGCXXABI.h
index b6a94f9..2c73921 100644
--- a/lib/CodeGen/CGCXXABI.h
+++ b/lib/CodeGen/CGCXXABI.h
@@ -226,7 +226,7 @@
virtual llvm::Constant *getAddrOfRTTIDescriptor(QualType Ty) = 0;
virtual llvm::Constant *
- getAddrOfCXXHandlerMapEntry(QualType Ty, QualType CatchHandlerType) = 0;
+ getAddrOfCXXCatchHandlerType(QualType Ty, QualType CatchHandlerType) = 0;
virtual bool shouldTypeidBeNullChecked(bool IsDeref,
QualType SrcRecordTy) = 0;
diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp
index d397761..c031bd7 100644
--- a/lib/CodeGen/CGCall.cpp
+++ b/lib/CodeGen/CGCall.cpp
@@ -734,7 +734,8 @@
auto Exp = getTypeExpansion(Ty, getContext());
if (auto CAExp = dyn_cast<ConstantArrayExpansion>(Exp.get())) {
for (int i = 0, n = CAExp->NumElts; i < n; i++) {
- llvm::Value *EltAddr = Builder.CreateConstGEP2_32(LV.getAddress(), 0, i);
+ llvm::Value *EltAddr =
+ Builder.CreateConstGEP2_32(nullptr, LV.getAddress(), 0, i);
LValue LV = MakeAddrLValue(EltAddr, CAExp->EltTy);
ExpandTypeFromArgs(CAExp->EltTy, LV, AI);
}
@@ -756,10 +757,12 @@
ExpandTypeFromArgs(FD->getType(), SubLV, AI);
}
} else if (auto CExp = dyn_cast<ComplexExpansion>(Exp.get())) {
- llvm::Value *RealAddr = Builder.CreateStructGEP(LV.getAddress(), 0, "real");
+ llvm::Value *RealAddr =
+ Builder.CreateStructGEP(nullptr, LV.getAddress(), 0, "real");
EmitStoreThroughLValue(RValue::get(*AI++),
MakeAddrLValue(RealAddr, CExp->EltTy));
- llvm::Value *ImagAddr = Builder.CreateStructGEP(LV.getAddress(), 1, "imag");
+ llvm::Value *ImagAddr =
+ Builder.CreateStructGEP(nullptr, LV.getAddress(), 1, "imag");
EmitStoreThroughLValue(RValue::get(*AI++),
MakeAddrLValue(ImagAddr, CExp->EltTy));
} else {
@@ -775,7 +778,7 @@
if (auto CAExp = dyn_cast<ConstantArrayExpansion>(Exp.get())) {
llvm::Value *Addr = RV.getAggregateAddr();
for (int i = 0, n = CAExp->NumElts; i < n; i++) {
- llvm::Value *EltAddr = Builder.CreateConstGEP2_32(Addr, 0, i);
+ llvm::Value *EltAddr = Builder.CreateConstGEP2_32(nullptr, Addr, 0, i);
RValue EltRV =
convertTempToRValue(EltAddr, CAExp->EltTy, SourceLocation());
ExpandTypeToArgs(CAExp->EltTy, EltRV, IRFuncTy, IRCallArgs, IRCallArgPos);
@@ -843,7 +846,7 @@
return SrcPtr;
// GEP into the first element.
- SrcPtr = CGF.Builder.CreateConstGEP2_32(SrcPtr, 0, 0, "coerce.dive");
+ SrcPtr = CGF.Builder.CreateConstGEP2_32(SrcSTy, SrcPtr, 0, 0, "coerce.dive");
// If the first element is a struct, recurse.
llvm::Type *SrcTy =
@@ -981,7 +984,7 @@
if (llvm::StructType *STy =
dyn_cast<llvm::StructType>(Val->getType())) {
for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) {
- llvm::Value *EltPtr = CGF.Builder.CreateConstGEP2_32(DestPtr, 0, 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);
@@ -1772,8 +1775,9 @@
switch (ArgI.getKind()) {
case ABIArgInfo::InAlloca: {
assert(NumIRArgs == 0);
- llvm::Value *V = Builder.CreateStructGEP(
- ArgStruct, ArgI.getInAllocaFieldIndex(), Arg->getName());
+ llvm::Value *V =
+ Builder.CreateStructGEP(FI.getArgStruct(), ArgStruct,
+ ArgI.getInAllocaFieldIndex(), Arg->getName());
ArgVals.push_back(ValueAndIsPtr(V, HavePointer));
break;
}
@@ -1939,7 +1943,7 @@
// If the value is offset in memory, apply the offset now.
if (unsigned Offs = ArgI.getDirectOffset()) {
Ptr = Builder.CreateBitCast(Ptr, Builder.getInt8PtrTy());
- Ptr = Builder.CreateConstGEP1_32(Ptr, Offs);
+ Ptr = Builder.CreateConstGEP1_32(Builder.getInt8Ty(), Ptr, Offs);
Ptr = Builder.CreateBitCast(Ptr,
llvm::PointerType::getUnqual(ArgI.getCoerceToType()));
}
@@ -1961,7 +1965,7 @@
for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) {
auto AI = FnArgs[FirstIRArg + i];
AI->setName(Arg->getName() + ".coerce" + Twine(i));
- llvm::Value *EltPtr = Builder.CreateConstGEP2_32(Ptr, 0, i);
+ llvm::Value *EltPtr = Builder.CreateConstGEP2_32(STy, Ptr, 0, i);
Builder.CreateStore(AI, EltPtr);
}
} else {
@@ -1974,7 +1978,8 @@
for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) {
auto AI = FnArgs[FirstIRArg + i];
AI->setName(Arg->getName() + ".coerce" + Twine(i));
- llvm::Value *EltPtr = Builder.CreateConstGEP2_32(TempV, 0, i);
+ llvm::Value *EltPtr =
+ Builder.CreateConstGEP2_32(ArgI.getCoerceToType(), TempV, 0, i);
Builder.CreateStore(AI, EltPtr);
}
@@ -2269,8 +2274,8 @@
llvm::Function::arg_iterator EI = CurFn->arg_end();
--EI;
llvm::Value *ArgStruct = EI;
- llvm::Value *SRet =
- Builder.CreateStructGEP(ArgStruct, RetAI.getInAllocaFieldIndex());
+ llvm::Value *SRet = Builder.CreateStructGEP(
+ nullptr, ArgStruct, RetAI.getInAllocaFieldIndex());
RV = Builder.CreateLoad(SRet, "sret");
}
break;
@@ -2334,7 +2339,7 @@
// 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(V, Offs);
+ V = Builder.CreateConstGEP1_32(Builder.getInt8Ty(), V, Offs);
V = Builder.CreateBitCast(V,
llvm::PointerType::getUnqual(RetAI.getCoerceToType()));
}
@@ -2380,7 +2385,7 @@
Ret = Builder.CreateRetVoid();
}
- if (!RetDbgLoc.isUnknown())
+ if (RetDbgLoc)
Ret->setDebugLoc(std::move(RetDbgLoc));
}
@@ -2992,7 +2997,7 @@
if (CGM.getLangOpts().ObjCAutoRefCount)
AddObjCARCExceptionMetadata(Inst);
- return Inst;
+ return llvm::CallSite(Inst);
}
/// \brief Store a non-aggregate value to an address to initialize it. For
@@ -3029,7 +3034,7 @@
// If we're using inalloca, insert the allocation after the stack save.
// FIXME: Do this earlier rather than hacking it in here!
- llvm::Value *ArgMemory = nullptr;
+ llvm::AllocaInst *ArgMemory = nullptr;
if (llvm::StructType *ArgStruct = CallInfo.getArgStruct()) {
llvm::Instruction *IP = CallArgs.getStackBase();
llvm::AllocaInst *AI;
@@ -3058,7 +3063,8 @@
IRCallArgs[IRFunctionArgs.getSRetArgNo()] = SRetPtr;
} else {
llvm::Value *Addr =
- Builder.CreateStructGEP(ArgMemory, RetAI.getInAllocaFieldIndex());
+ Builder.CreateStructGEP(ArgMemory->getAllocatedType(), ArgMemory,
+ RetAI.getInAllocaFieldIndex());
Builder.CreateStore(SRetPtr, Addr);
}
}
@@ -3092,14 +3098,16 @@
cast<llvm::Instruction>(RV.getAggregateAddr());
CGBuilderTy::InsertPoint IP = Builder.saveIP();
Builder.SetInsertPoint(Placeholder);
- llvm::Value *Addr = Builder.CreateStructGEP(
- ArgMemory, ArgInfo.getInAllocaFieldIndex());
+ llvm::Value *Addr =
+ Builder.CreateStructGEP(ArgMemory->getAllocatedType(), ArgMemory,
+ ArgInfo.getInAllocaFieldIndex());
Builder.restoreIP(IP);
deferPlaceholderReplacement(Placeholder, Addr);
} else {
// Store the RValue into the argument struct.
llvm::Value *Addr =
- Builder.CreateStructGEP(ArgMemory, ArgInfo.getInAllocaFieldIndex());
+ Builder.CreateStructGEP(ArgMemory->getAllocatedType(), ArgMemory,
+ ArgInfo.getInAllocaFieldIndex());
unsigned AS = Addr->getType()->getPointerAddressSpace();
llvm::Type *MemType = ConvertTypeForMem(I->Ty)->getPointerTo(AS);
// There are some cases where a trivial bitcast is not avoidable. The
@@ -3201,7 +3209,7 @@
// If the value is offset in memory, apply the offset now.
if (unsigned Offs = ArgInfo.getDirectOffset()) {
SrcPtr = Builder.CreateBitCast(SrcPtr, Builder.getInt8PtrTy());
- SrcPtr = Builder.CreateConstGEP1_32(SrcPtr, Offs);
+ SrcPtr = Builder.CreateConstGEP1_32(Builder.getInt8Ty(), SrcPtr, Offs);
SrcPtr = Builder.CreateBitCast(SrcPtr,
llvm::PointerType::getUnqual(ArgInfo.getCoerceToType()));
@@ -3233,7 +3241,7 @@
assert(NumIRArgs == STy->getNumElements());
for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) {
- llvm::Value *EltPtr = Builder.CreateConstGEP2_32(SrcPtr, 0, i);
+ llvm::Value *EltPtr = Builder.CreateConstGEP2_32(STy, SrcPtr, 0, i);
llvm::LoadInst *LI = Builder.CreateLoad(EltPtr);
// We don't know what we're loading from.
LI->setAlignment(1);
@@ -3463,7 +3471,8 @@
llvm::Value *StorePtr = DestPtr;
if (unsigned Offs = RetAI.getDirectOffset()) {
StorePtr = Builder.CreateBitCast(StorePtr, Builder.getInt8PtrTy());
- StorePtr = Builder.CreateConstGEP1_32(StorePtr, Offs);
+ StorePtr =
+ Builder.CreateConstGEP1_32(Builder.getInt8Ty(), StorePtr, Offs);
StorePtr = Builder.CreateBitCast(StorePtr,
llvm::PointerType::getUnqual(RetAI.getCoerceToType()));
}
diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp
index 84d6437..bd15c12 100644
--- a/lib/CodeGen/CGClass.cpp
+++ b/lib/CodeGen/CGClass.cpp
@@ -2088,14 +2088,6 @@
return VTable;
}
-void CodeGenFunction::EmitVTablePtrCheckForCall(const CXXMethodDecl *MD,
- llvm::Value *VTable) {
- if (!SanOpts.has(SanitizerKind::CFIVptr))
- return;
-
- EmitVTablePtrCheck(MD->getParent(), VTable);
-}
-
// If a class has a single non-virtual base and does not introduce or override
// virtual member functions or fields, it will have the same layout as its base.
// This function returns the least derived such class.
@@ -2131,6 +2123,15 @@
RD->bases_begin()->getType()->getAsCXXRecordDecl());
}
+void CodeGenFunction::EmitVTablePtrCheckForCall(const CXXMethodDecl *MD,
+ llvm::Value *VTable) {
+ const CXXRecordDecl *ClassDecl = MD->getParent();
+ if (!SanOpts.has(SanitizerKind::CFICastStrict))
+ ClassDecl = LeastDerivedClassWithSameLayout(ClassDecl);
+
+ EmitVTablePtrCheck(ClassDecl, VTable);
+}
+
void CodeGenFunction::EmitVTablePtrCheckForCast(QualType T,
llvm::Value *Derived,
bool MayBeNull) {
diff --git a/lib/CodeGen/CGCleanup.cpp b/lib/CodeGen/CGCleanup.cpp
index 566befc..299969a 100644
--- a/lib/CodeGen/CGCleanup.cpp
+++ b/lib/CodeGen/CGCleanup.cpp
@@ -52,8 +52,10 @@
llvm::StructType::get(V.first->getType(), V.second->getType(),
(void*) nullptr);
llvm::Value *addr = CGF.CreateTempAlloca(ComplexTy, "saved-complex");
- CGF.Builder.CreateStore(V.first, CGF.Builder.CreateStructGEP(addr, 0));
- CGF.Builder.CreateStore(V.second, CGF.Builder.CreateStructGEP(addr, 1));
+ CGF.Builder.CreateStore(V.first,
+ CGF.Builder.CreateStructGEP(ComplexTy, addr, 0));
+ CGF.Builder.CreateStore(V.second,
+ CGF.Builder.CreateStructGEP(ComplexTy, addr, 1));
return saved_type(addr, ComplexAddress);
}
@@ -82,9 +84,9 @@
return RValue::getAggregate(CGF.Builder.CreateLoad(Value));
case ComplexAddress: {
llvm::Value *real =
- CGF.Builder.CreateLoad(CGF.Builder.CreateStructGEP(Value, 0));
+ CGF.Builder.CreateLoad(CGF.Builder.CreateStructGEP(nullptr, Value, 0));
llvm::Value *imag =
- CGF.Builder.CreateLoad(CGF.Builder.CreateStructGEP(Value, 1));
+ CGF.Builder.CreateLoad(CGF.Builder.CreateStructGEP(nullptr, Value, 1));
return RValue::getComplex(real, imag);
}
}
@@ -469,8 +471,14 @@
EHScopeStack::Cleanup *Fn,
EHScopeStack::Cleanup::Flags flags,
llvm::Value *ActiveFlag) {
- // EH cleanups always occur within a terminate scope.
- if (flags.isForEHCleanup()) CGF.EHStack.pushTerminate();
+ // Itanium EH cleanups occur within a terminate scope. Microsoft SEH doesn't
+ // have this behavior, and the Microsoft C++ runtime will call terminate for
+ // us if the cleanup throws.
+ bool PushedTerminate = false;
+ if (flags.isForEHCleanup() && !CGF.getTarget().getCXXABI().isMicrosoft()) {
+ CGF.EHStack.pushTerminate();
+ PushedTerminate = true;
+ }
// If there's an active flag, load it and skip the cleanup if it's
// false.
@@ -493,7 +501,8 @@
CGF.EmitBlock(ContBB);
// Leave the terminate scope.
- if (flags.isForEHCleanup()) CGF.EHStack.popTerminate();
+ if (PushedTerminate)
+ CGF.EHStack.popTerminate();
}
static void ForwardPrebranchedFallthrough(llvm::BasicBlock *Exit,
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index 186c522..4af49c2 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -92,7 +92,7 @@
: CGF(CGF) {
if (CGF.getDebugInfo()) {
OriginalLocation = CGF.Builder.getCurrentDebugLocation();
- if (!Loc.isUnknown())
+ if (Loc)
CGF.Builder.SetCurrentDebugLocation(std::move(Loc));
}
}
@@ -120,20 +120,20 @@
return;
SourceManager &SM = CGM.getContext().getSourceManager();
- llvm::DIScope Scope(LexicalBlockStack.back());
+ auto *Scope = cast<llvm::MDScope>(LexicalBlockStack.back());
PresumedLoc PCLoc = SM.getPresumedLoc(CurLoc);
- if (PCLoc.isInvalid() || Scope.getFilename() == PCLoc.getFilename())
+ if (PCLoc.isInvalid() || Scope->getFilename() == PCLoc.getFilename())
return;
- if (Scope.isLexicalBlockFile()) {
- llvm::DILexicalBlockFile LBF = llvm::DILexicalBlockFile(Scope);
+ if (auto *LBF = dyn_cast<llvm::MDLexicalBlockFile>(Scope)) {
llvm::DIDescriptor D = DBuilder.createLexicalBlockFile(
- LBF.getScope(), getOrCreateFile(CurLoc));
+ LBF->getScope(), getOrCreateFile(CurLoc));
llvm::MDNode *N = D;
LexicalBlockStack.pop_back();
LexicalBlockStack.emplace_back(N);
- } else if (Scope.isLexicalBlock() || Scope.isSubprogram()) {
+ } else if (isa<llvm::MDLexicalBlock>(Scope) ||
+ isa<llvm::MDSubprogram>(Scope)) {
llvm::DIDescriptor D =
DBuilder.createLexicalBlockFile(Scope, getOrCreateFile(CurLoc));
llvm::MDNode *N = D;
@@ -150,7 +150,7 @@
auto I = RegionMap.find(Context);
if (I != RegionMap.end()) {
llvm::Metadata *V = I->second;
- return llvm::DIScope(dyn_cast_or_null<llvm::MDNode>(V));
+ return dyn_cast_or_null<llvm::MDScope>(V);
}
// Check namespace.
@@ -250,14 +250,14 @@
llvm::DIFile CGDebugInfo::getOrCreateFile(SourceLocation Loc) {
if (!Loc.isValid())
// If Location is not valid then use main input file.
- return DBuilder.createFile(TheCU.getFilename(), TheCU.getDirectory());
+ return DBuilder.createFile(TheCU->getFilename(), TheCU->getDirectory());
SourceManager &SM = CGM.getContext().getSourceManager();
PresumedLoc PLoc = SM.getPresumedLoc(Loc);
if (PLoc.isInvalid() || StringRef(PLoc.getFilename()).empty())
// If the location is not valid then use main input file.
- return DBuilder.createFile(TheCU.getFilename(), TheCU.getDirectory());
+ return DBuilder.createFile(TheCU->getFilename(), TheCU->getDirectory());
// Cache the results.
const char *fname = PLoc.getFilename();
@@ -266,7 +266,7 @@
if (it != DIFileCache.end()) {
// Verify that the information still exists.
if (llvm::Metadata *V = it->second)
- return llvm::DIFile(cast<llvm::MDNode>(V));
+ return cast<llvm::MDFile>(V);
}
llvm::DIFile F = DBuilder.createFile(PLoc.getFilename(), getCurrentDirname());
@@ -277,7 +277,7 @@
/// getOrCreateMainFile - Get the file info for main compile unit.
llvm::DIFile CGDebugInfo::getOrCreateMainFile() {
- return DBuilder.createFile(TheCU.getFilename(), TheCU.getDirectory());
+ return DBuilder.createFile(TheCU->getFilename(), TheCU->getDirectory());
}
/// getLineNumber - Get line number for the location. If location is invalid
@@ -606,7 +606,7 @@
// FIXME: ODR should apply to ObjC++ exactly the same wasy it does to C++.
// For now, only apply ODR with C++.
const TagDecl *TD = Ty->getDecl();
- if (TheCU.getLanguage() != llvm::dwarf::DW_LANG_C_plus_plus ||
+ if (TheCU->getSourceLanguage() != llvm::dwarf::DW_LANG_C_plus_plus ||
!TD->isExternallyVisible())
return FullName;
// Microsoft Mangler does not have support for mangleCXXRTTIName yet.
@@ -637,12 +637,12 @@
}
// Creates a forward declaration for a RecordDecl in the given context.
-llvm::DICompositeType
+llvm::MDCompositeType *
CGDebugInfo::getOrCreateRecordFwdDecl(const RecordType *Ty,
- llvm::DIDescriptor Ctx) {
+ llvm::MDScope *Ctx) {
const RecordDecl *RD = Ty->getDecl();
- if (llvm::DIType T = getTypeOrNull(CGM.getContext().getRecordType(RD)))
- return llvm::DICompositeType(T);
+ if (llvm::MDType *T = getTypeOrNull(CGM.getContext().getRecordType(RD)))
+ return cast<llvm::MDCompositeType>(T);
llvm::DIFile DefUnit = getOrCreateFile(RD->getLocation());
unsigned Line = getLineNumber(RD->getLocation());
StringRef RDName = getClassName(RD);
@@ -658,9 +658,9 @@
// Create the type.
SmallString<256> FullName = getUniqueTagTypeName(Ty, CGM, TheCU);
- llvm::DICompositeType RetTy = DBuilder.createReplaceableCompositeType(
+ llvm::MDCompositeType *RetTy = DBuilder.createReplaceableCompositeType(
getTagForRecord(RD), RDName, Ctx, DefUnit, Line, 0, Size, Align,
- llvm::DIDescriptor::FlagFwdDecl, FullName);
+ llvm::DebugNode::FlagFwdDecl, FullName);
ReplaceMap.emplace_back(
std::piecewise_construct, std::make_tuple(Ty),
std::make_tuple(static_cast<llvm::Metadata *>(RetTy)));
@@ -718,7 +718,7 @@
Elements = DBuilder.getOrCreateArray(EltTys);
EltTys.clear();
- unsigned Flags = llvm::DIDescriptor::FlagAppleBlock;
+ unsigned Flags = llvm::DebugNode::FlagAppleBlock;
unsigned LineNo = getLineNumber(CurLoc);
EltTy = DBuilder.createStructType(Unit, "__block_descriptor", Unit, LineNo,
@@ -777,31 +777,21 @@
Ty->getTemplateName().getAsTemplateDecl())->getTemplatedDecl();
SourceLocation Loc = AliasDecl->getLocation();
- llvm::DIFile File = getOrCreateFile(Loc);
- unsigned Line = getLineNumber(Loc);
-
- llvm::DIDescriptor Ctxt =
- getContextDescriptor(cast<Decl>(AliasDecl->getDeclContext()));
-
- return DBuilder.createTypedef(Src, internString(OS.str()), File, Line, Ctxt);
+ return DBuilder.createTypedef(
+ Src, internString(OS.str()), getOrCreateFile(Loc), getLineNumber(Loc),
+ getContextDescriptor(cast<Decl>(AliasDecl->getDeclContext())));
}
llvm::DIType CGDebugInfo::CreateType(const TypedefType *Ty, llvm::DIFile Unit) {
- // Typedefs are derived from some other type. If we have a typedef of a
- // typedef, make sure to emit the whole chain.
- llvm::DIType Src = getOrCreateType(Ty->getDecl()->getUnderlyingType(), Unit);
// We don't set size information, but do specify where the typedef was
// declared.
SourceLocation Loc = Ty->getDecl()->getLocation();
- llvm::DIFile File = getOrCreateFile(Loc);
- unsigned Line = getLineNumber(Loc);
- const TypedefNameDecl *TyDecl = Ty->getDecl();
- llvm::DIDescriptor TypedefContext =
- getContextDescriptor(cast<Decl>(Ty->getDecl()->getDeclContext()));
-
- return DBuilder.createTypedef(Src, TyDecl->getName(), File, Line,
- TypedefContext);
+ // Typedefs are derived from some other type.
+ return DBuilder.createTypedef(
+ getOrCreateType(Ty->getDecl()->getUnderlyingType(), Unit),
+ Ty->getDecl()->getName(), getOrCreateFile(Loc), getLineNumber(Loc),
+ getContextDescriptor(cast<Decl>(Ty->getDecl()->getDeclContext())));
}
llvm::DIType CGDebugInfo::CreateType(const FunctionType *Ty,
@@ -841,11 +831,11 @@
switch (Access) {
case clang::AS_private:
- return llvm::DIDescriptor::FlagPrivate;
+ return llvm::DebugNode::FlagPrivate;
case clang::AS_protected:
- return llvm::DIDescriptor::FlagProtected;
+ return llvm::DebugNode::FlagProtected;
case clang::AS_public:
- return llvm::DIDescriptor::FlagPublic;
+ return llvm::DebugNode::FlagPublic;
case clang::AS_none:
return 0;
}
@@ -1003,8 +993,7 @@
if (MI != StaticDataMemberCache.end()) {
assert(MI->second &&
"Static data member declaration should still exist");
- elements.push_back(
- llvm::DIDerivedType(cast<llvm::MDNode>(MI->second)));
+ elements.push_back(cast<llvm::MDDerivedTypeBase>(MI->second));
} else {
auto Field = CreateRecordStaticField(V, RecordTy, record);
elements.push_back(Field);
@@ -1022,27 +1011,29 @@
/// 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::DICompositeType
+llvm::MDSubroutineType *
CGDebugInfo::getOrCreateMethodType(const CXXMethodDecl *Method,
llvm::DIFile Unit) {
const FunctionProtoType *Func = Method->getType()->getAs<FunctionProtoType>();
if (Method->isStatic())
- return llvm::DICompositeType(getOrCreateType(QualType(Func, 0), Unit));
+ return cast_or_null<llvm::MDSubroutineType>(
+ getOrCreateType(QualType(Func, 0), Unit));
return getOrCreateInstanceMethodType(Method->getThisType(CGM.getContext()),
Func, Unit);
}
-llvm::DICompositeType CGDebugInfo::getOrCreateInstanceMethodType(
+llvm::MDSubroutineType *CGDebugInfo::getOrCreateInstanceMethodType(
QualType ThisPtr, const FunctionProtoType *Func, llvm::DIFile Unit) {
// Add "this" pointer.
- llvm::DITypeArray Args = llvm::DISubroutineType(
- getOrCreateType(QualType(Func, 0), Unit)).getTypeArray();
- assert(Args.getNumElements() && "Invalid number of arguments!");
+ llvm::DITypeArray Args(
+ cast<llvm::MDSubroutineType>(getOrCreateType(QualType(Func, 0), Unit))
+ ->getTypeArray());
+ assert(Args.size() && "Invalid number of arguments!");
SmallVector<llvm::Metadata *, 16> Elts;
// First element is always return type. For 'void' functions it is NULL.
- Elts.push_back(Args.getElement(0));
+ Elts.push_back(Args[0]);
// "this" pointer is always first argument.
const CXXRecordDecl *RD = ThisPtr->getPointeeCXXRecordDecl();
@@ -1070,16 +1061,16 @@
}
// Copy rest of the arguments.
- for (unsigned i = 1, e = Args.getNumElements(); i != e; ++i)
- Elts.push_back(Args.getElement(i));
+ for (unsigned i = 1, e = Args.size(); i != e; ++i)
+ Elts.push_back(Args[i]);
llvm::DITypeArray EltTypeArray = DBuilder.getOrCreateTypeArray(Elts);
unsigned Flags = 0;
if (Func->getExtProtoInfo().RefQualifier == RQ_LValue)
- Flags |= llvm::DIDescriptor::FlagLValueReference;
+ Flags |= llvm::DebugNode::FlagLValueReference;
if (Func->getExtProtoInfo().RefQualifier == RQ_RValue)
- Flags |= llvm::DIDescriptor::FlagRValueReference;
+ Flags |= llvm::DebugNode::FlagRValueReference;
return DBuilder.createSubroutineType(Unit, EltTypeArray, Flags);
}
@@ -1103,7 +1094,7 @@
isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(Method);
StringRef MethodName = getFunctionName(Method);
- llvm::DICompositeType MethodTy = getOrCreateMethodType(Method, Unit);
+ llvm::MDSubroutineType *MethodTy = getOrCreateMethodType(Method, Unit);
// Since a single ctor/dtor corresponds to multiple functions, it doesn't
// make sense to give a single ctor/dtor a linkage name.
@@ -1143,29 +1134,29 @@
unsigned Flags = 0;
if (Method->isImplicit())
- Flags |= llvm::DIDescriptor::FlagArtificial;
+ Flags |= llvm::DebugNode::FlagArtificial;
Flags |= getAccessFlag(Method->getAccess(), Method->getParent());
if (const CXXConstructorDecl *CXXC = dyn_cast<CXXConstructorDecl>(Method)) {
if (CXXC->isExplicit())
- Flags |= llvm::DIDescriptor::FlagExplicit;
+ Flags |= llvm::DebugNode::FlagExplicit;
} else if (const CXXConversionDecl *CXXC =
dyn_cast<CXXConversionDecl>(Method)) {
if (CXXC->isExplicit())
- Flags |= llvm::DIDescriptor::FlagExplicit;
+ Flags |= llvm::DebugNode::FlagExplicit;
}
if (Method->hasPrototype())
- Flags |= llvm::DIDescriptor::FlagPrototyped;
+ Flags |= llvm::DebugNode::FlagPrototyped;
if (Method->getRefQualifier() == RQ_LValue)
- Flags |= llvm::DIDescriptor::FlagLValueReference;
+ Flags |= llvm::DebugNode::FlagLValueReference;
if (Method->getRefQualifier() == RQ_RValue)
- Flags |= llvm::DIDescriptor::FlagRValueReference;
+ Flags |= llvm::DebugNode::FlagRValueReference;
llvm::DIArray TParamsArray = CollectFunctionTemplateParams(Method, Unit);
llvm::DISubprogram SP = DBuilder.createMethod(
RecordTy, MethodName, MethodLinkageName, MethodDefUnit, MethodLine,
MethodTy, /*isLocalToUnit=*/false,
/* isDefinition=*/false, Virtuality, VIndex, ContainingType, Flags,
- CGM.getLangOpts().Optimize, nullptr, TParamsArray);
+ CGM.getLangOpts().Optimize, nullptr, TParamsArray.get());
SPCache[Method->getCanonicalDecl()].reset(SP);
@@ -1240,7 +1231,7 @@
BaseOffset =
4 * CGM.getMicrosoftVTableContext().getVBTableIndex(RD, Base);
}
- BFlags = llvm::DIDescriptor::FlagVirtual;
+ BFlags = llvm::DebugNode::FlagVirtual;
} else
BaseOffset = CGM.getContext().toBits(RL.getBaseClassOffset(Base));
// FIXME: Inconsistent units for BaseOffset. It is in bytes when
@@ -1399,7 +1390,7 @@
/// getOrCreateVTablePtrType - Return debug info descriptor for vtable.
llvm::DIType CGDebugInfo::getOrCreateVTablePtrType(llvm::DIFile Unit) {
- if (VTablePtrType.isValid())
+ if (VTablePtrType)
return VTablePtrType;
ASTContext &Context = CGM.getContext();
@@ -1438,7 +1429,7 @@
unsigned Size = CGM.getContext().getTypeSize(CGM.getContext().VoidPtrTy);
llvm::DIType VPTR = DBuilder.createMemberType(
Unit, getVTableName(RD), Unit, 0, Size, 0, 0,
- llvm::DIDescriptor::FlagArtificial, getOrCreateVTablePtrType(Unit));
+ llvm::DebugNode::FlagArtificial, getOrCreateVTablePtrType(Unit));
EltTys.push_back(VPTR);
}
@@ -1466,11 +1457,10 @@
QualType Ty = CGM.getContext().getEnumType(ED);
void *TyPtr = Ty.getAsOpaquePtr();
auto I = TypeCache.find(TyPtr);
- if (I == TypeCache.end() ||
- !llvm::DIType(cast<llvm::MDNode>(I->second)).isForwardDecl())
+ if (I == TypeCache.end() || !cast<llvm::MDType>(I->second)->isForwardDecl())
return;
llvm::DIType Res = CreateTypeDefinition(Ty->castAs<EnumType>());
- assert(!Res.isForwardDecl());
+ assert(!Res->isForwardDecl());
TypeCache[TyPtr].reset(Res);
}
@@ -1490,7 +1480,7 @@
QualType Ty = CGM.getContext().getRecordType(RD);
llvm::DIType T = getTypeOrNull(Ty);
- if (T && T.isForwardDecl())
+ if (T && T->isForwardDecl())
completeClassData(RD);
}
@@ -1500,11 +1490,10 @@
QualType Ty = CGM.getContext().getRecordType(RD);
void *TyPtr = Ty.getAsOpaquePtr();
auto I = TypeCache.find(TyPtr);
- if (I != TypeCache.end() &&
- !llvm::DIType(cast<llvm::MDNode>(I->second)).isForwardDecl())
+ if (I != TypeCache.end() && !cast<llvm::MDType>(I->second)->isForwardDecl())
return;
llvm::DIType Res = CreateTypeDefinition(Ty->castAs<RecordType>());
- assert(!Res.isForwardDecl());
+ assert(!Res->isForwardDecl());
TypeCache[TyPtr].reset(Res);
}
@@ -1554,7 +1543,7 @@
/// CreateType - get structure or union type.
llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty) {
RecordDecl *RD = Ty->getDecl();
- llvm::DICompositeType T(getTypeOrNull(QualType(Ty, 0)));
+ llvm::DIType T = cast_or_null<llvm::MDType>(getTypeOrNull(QualType(Ty, 0)));
if (T || shouldOmitDefinition(DebugKind, RD, CGM.getLangOpts())) {
if (!T)
T = getOrCreateRecordFwdDecl(
@@ -1578,9 +1567,8 @@
// may refer to the forward decl if the struct is recursive) and replace all
// uses of the forward declaration with the final definition.
- llvm::DICompositeType FwdDecl(getOrCreateLimitedType(Ty, DefUnit));
- assert(FwdDecl.isCompositeType() &&
- "The debug type of a RecordType should be a llvm::DICompositeType");
+ auto *FwdDecl =
+ cast<llvm::MDCompositeType>(getOrCreateLimitedType(Ty, DefUnit));
const RecordDecl *D = RD->getDefinition();
if (!D || !D->isCompleteDefinition())
@@ -1619,8 +1607,8 @@
DBuilder.replaceArrays(FwdDecl, Elements);
if (FwdDecl->isTemporary())
- FwdDecl = llvm::DICompositeType(llvm::MDNode::replaceWithPermanent(
- llvm::TempMDNode(FwdDecl.get())));
+ FwdDecl =
+ llvm::MDNode::replaceWithPermanent(llvm::TempMDCompositeType(FwdDecl));
RegionMap[Ty->getDecl()].reset(FwdDecl);
return FwdDecl;
@@ -1667,7 +1655,8 @@
// Get overall information about the record type for the debug info.
llvm::DIFile DefUnit = getOrCreateFile(ID->getLocation());
unsigned Line = getLineNumber(ID->getLocation());
- llvm::dwarf::SourceLanguage RuntimeLang = TheCU.getLanguage();
+ auto RuntimeLang =
+ static_cast<llvm::dwarf::SourceLanguage>(TheCU->getSourceLanguage());
// If this is just a forward declaration return a special forward-declaration
// debug type since we won't be able to lay out the entire type.
@@ -1688,7 +1677,7 @@
ObjCInterfaceDecl *ID = Ty->getDecl();
llvm::DIFile DefUnit = getOrCreateFile(ID->getLocation());
unsigned Line = getLineNumber(ID->getLocation());
- unsigned RuntimeLang = TheCU.getLanguage();
+ unsigned RuntimeLang = TheCU->getSourceLanguage();
// Bit size, align and offset of the type.
uint64_t Size = CGM.getContext().getTypeSize(Ty);
@@ -1696,9 +1685,9 @@
unsigned Flags = 0;
if (ID->getImplementation())
- Flags |= llvm::DIDescriptor::FlagObjcClassComplete;
+ Flags |= llvm::DebugNode::FlagObjcClassComplete;
- llvm::DICompositeType RealDecl = DBuilder.createStructType(
+ llvm::MDCompositeType *RealDecl = DBuilder.createStructType(
Unit, ID->getName(), DefUnit, Line, Size, Align, Flags, llvm::DIType(),
llvm::DIArray(), RuntimeLang);
@@ -1706,7 +1695,7 @@
TypeCache[QTy.getAsOpaquePtr()].reset(RealDecl);
// Push the struct on region stack.
- LexicalBlockStack.emplace_back(static_cast<llvm::MDNode *>(RealDecl));
+ LexicalBlockStack.emplace_back(RealDecl);
RegionMap[Ty->getDecl()].reset(RealDecl);
// Convert all the elements.
@@ -1716,7 +1705,7 @@
if (SClass) {
llvm::DIType SClassTy =
getOrCreateType(CGM.getContext().getObjCInterfaceType(SClass), Unit);
- if (!SClassTy.isValid())
+ if (!SClassTy)
return llvm::DIType();
llvm::DIType InhTag = DBuilder.createInheritance(RealDecl, SClassTy, 0, 0);
@@ -1745,7 +1734,7 @@
for (ObjCIvarDecl *Field = ID->all_declared_ivar_begin(); Field;
Field = Field->getNextIvar(), ++FieldNo) {
llvm::DIType FieldTy = getOrCreateType(Field->getType(), Unit);
- if (!FieldTy.isValid())
+ if (!FieldTy)
return llvm::DIType();
StringRef FieldName = Field->getName();
@@ -1788,11 +1777,11 @@
unsigned Flags = 0;
if (Field->getAccessControl() == ObjCIvarDecl::Protected)
- Flags = llvm::DIDescriptor::FlagProtected;
+ Flags = llvm::DebugNode::FlagProtected;
else if (Field->getAccessControl() == ObjCIvarDecl::Private)
- Flags = llvm::DIDescriptor::FlagPrivate;
+ Flags = llvm::DebugNode::FlagPrivate;
else if (Field->getAccessControl() == ObjCIvarDecl::Public)
- Flags = llvm::DIDescriptor::FlagPublic;
+ Flags = llvm::DebugNode::FlagPublic;
llvm::MDNode *PropertyNode = nullptr;
if (ObjCImplementationDecl *ImpD = ID->getImplementation()) {
@@ -1948,14 +1937,14 @@
// If this is just a forward declaration, construct an appropriately
// marked node and just return it.
if (!ED->getDefinition()) {
- llvm::DIDescriptor EDContext;
- EDContext = getContextDescriptor(cast<Decl>(ED->getDeclContext()));
+ llvm::MDScope *EDContext =
+ getContextDescriptor(cast<Decl>(ED->getDeclContext()));
llvm::DIFile DefUnit = getOrCreateFile(ED->getLocation());
unsigned Line = getLineNumber(ED->getLocation());
StringRef EDName = ED->getName();
llvm::DIType RetTy = DBuilder.createReplaceableCompositeType(
llvm::dwarf::DW_TAG_enumeration_type, EDName, EDContext, DefUnit, Line,
- 0, Size, Align, llvm::DIDescriptor::FlagFwdDecl, FullName);
+ 0, Size, Align, llvm::DebugNode::FlagFwdDecl, FullName);
ReplaceMap.emplace_back(
std::piecewise_construct, std::make_tuple(Ty),
std::make_tuple(static_cast<llvm::Metadata *>(RetTy)));
@@ -1989,7 +1978,7 @@
llvm::DIFile DefUnit = getOrCreateFile(ED->getLocation());
unsigned Line = getLineNumber(ED->getLocation());
- llvm::DIDescriptor EnumContext =
+ llvm::MDScope *EnumContext =
getContextDescriptor(cast<Decl>(ED->getDeclContext()));
llvm::DIType ClassTy = ED->isFixed()
? getOrCreateType(ED->getIntegerType(), DefUnit)
@@ -2066,10 +2055,10 @@
if (it != TypeCache.end()) {
// Verify that the debug info still exists.
if (llvm::Metadata *V = it->second)
- return llvm::DIType(cast<llvm::MDNode>(V));
+ return cast<llvm::MDType>(V);
}
- return llvm::DIType();
+ return nullptr;
}
void CGDebugInfo::completeTemplateDefinition(
@@ -2218,21 +2207,21 @@
llvm::DIFile Unit) {
QualType QTy(Ty, 0);
- llvm::DICompositeType T(getTypeOrNull(QTy));
+ auto *T = cast_or_null<llvm::MDCompositeTypeBase>(getTypeOrNull(QTy));
// We may have cached a forward decl when we could have created
// a non-forward decl. Go ahead and create a non-forward decl
// now.
- if (T && !T.isForwardDecl())
+ if (T && !T->isForwardDecl())
return T;
// Otherwise create the type.
- llvm::DICompositeType Res = CreateLimitedType(Ty);
+ llvm::MDCompositeType *Res = CreateLimitedType(Ty);
// Propagate members from the declaration to the definition
// CreateType(const RecordType*) will overwrite this with the members in the
// correct order if the full type is needed.
- DBuilder.replaceArrays(Res, T ? T.getElements() : llvm::DIArray());
+ DBuilder.replaceArrays(Res, T ? T->getElements() : llvm::DIArray());
// And update the type cache.
TypeCache[QTy.getAsOpaquePtr()].reset(Res);
@@ -2240,7 +2229,7 @@
}
// TODO: Currently used for context chains when limiting debug info.
-llvm::DICompositeType CGDebugInfo::CreateLimitedType(const RecordType *Ty) {
+llvm::MDCompositeType *CGDebugInfo::CreateLimitedType(const RecordType *Ty) {
RecordDecl *RD = Ty->getDecl();
// Get overall information about the record type for the debug info.
@@ -2248,13 +2237,14 @@
unsigned Line = getLineNumber(RD->getLocation());
StringRef RDName = getClassName(RD);
- llvm::DIDescriptor RDContext =
+ llvm::MDScope *RDContext =
getContextDescriptor(cast<Decl>(RD->getDeclContext()));
// If we ended up creating the type during the context chain construction,
// just return that.
- llvm::DICompositeType T(getTypeOrNull(CGM.getContext().getRecordType(RD)));
- if (T && (!T.isForwardDecl() || !RD->getDefinition()))
+ auto *T = cast_or_null<llvm::MDCompositeType>(
+ getTypeOrNull(CGM.getContext().getRecordType(RD)));
+ if (T && (!T->isForwardDecl() || !RD->getDefinition()))
return T;
// If this is just a forward or incomplete declaration, construct an
@@ -2265,12 +2255,12 @@
uint64_t Size = CGM.getContext().getTypeSize(Ty);
uint64_t Align = CGM.getContext().getTypeAlign(Ty);
- llvm::DICompositeType RealDecl;
SmallString<256> FullName = getUniqueTagTypeName(Ty, CGM, TheCU);
- RealDecl = DBuilder.createReplaceableCompositeType(getTagForRecord(RD),
- RDName, RDContext, DefUnit, Line, 0, Size, Align, 0, FullName);
+ llvm::MDCompositeType *RealDecl = DBuilder.createReplaceableCompositeType(
+ getTagForRecord(RD), RDName, RDContext, DefUnit, Line, 0, Size, Align, 0,
+ FullName);
RegionMap[Ty->getDecl()].reset(RealDecl);
TypeCache[QualType(Ty, 0).getAsOpaquePtr()].reset(RealDecl);
@@ -2283,9 +2273,9 @@
}
void CGDebugInfo::CollectContainingType(const CXXRecordDecl *RD,
- llvm::DICompositeType RealDecl) {
+ llvm::MDCompositeType *RealDecl) {
// A class's primary base or the class itself contains the vtable.
- llvm::DICompositeType ContainingType;
+ llvm::MDCompositeType *ContainingType = nullptr;
const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD);
if (const CXXRecordDecl *PBase = RL.getPrimaryBase()) {
// Seek non-virtual primary base root.
@@ -2297,7 +2287,7 @@
else
break;
}
- ContainingType = llvm::DICompositeType(
+ ContainingType = cast<llvm::MDCompositeType>(
getOrCreateType(QualType(PBase->getTypeForDecl(), 0),
getOrCreateFile(RD->getLocation())));
} else if (RD->isDynamicClass())
@@ -2318,18 +2308,15 @@
return Ty;
}
-void CGDebugInfo::collectFunctionDeclProps(GlobalDecl GD,
- llvm::DIFile Unit,
- StringRef &Name, StringRef &LinkageName,
- llvm::DIDescriptor &FDContext,
- llvm::DIArray &TParamsArray,
- unsigned &Flags) {
+void CGDebugInfo::collectFunctionDeclProps(
+ GlobalDecl GD, llvm::DIFile Unit, StringRef &Name, StringRef &LinkageName,
+ llvm::MDScope *&FDContext, llvm::DIArray &TParamsArray, unsigned &Flags) {
const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl());
Name = getFunctionName(FD);
// Use mangled name as linkage name for C/C++ functions.
if (FD->hasPrototype()) {
LinkageName = CGM.getMangledName(GD);
- Flags |= llvm::DIDescriptor::FlagPrototyped;
+ Flags |= llvm::DebugNode::FlagPrototyped;
}
// No need to replicate the linkage name if it isn't different from the
// subprogram name, no need to have it at all unless coverage is enabled or
@@ -2355,7 +2342,7 @@
void CGDebugInfo::collectVarDeclProps(const VarDecl *VD, llvm::DIFile &Unit,
unsigned &LineNo, QualType &T,
StringRef &Name, StringRef &LinkageName,
- llvm::DIDescriptor &VDContext) {
+ llvm::MDScope *&VDContext) {
Unit = getOrCreateFile(VD->getLocation());
LineNo = getLineNumber(VD->getLocation());
@@ -2404,7 +2391,7 @@
unsigned Flags = 0;
SourceLocation Loc = FD->getLocation();
llvm::DIFile Unit = getOrCreateFile(Loc);
- llvm::DIDescriptor DContext(Unit);
+ llvm::MDScope *DContext = Unit;
unsigned Line = getLineNumber(Loc);
collectFunctionDeclProps(FD, Unit, Name, LinkageName, DContext,
@@ -2416,17 +2403,15 @@
QualType FnType =
CGM.getContext().getFunctionType(FD->getReturnType(), ArgTypes,
FunctionProtoType::ExtProtoInfo());
- llvm::DISubprogram SP =
- DBuilder.createTempFunctionFwdDecl(DContext, Name, LinkageName, Unit, Line,
- getOrCreateFunctionType(FD, FnType, Unit),
- !FD->isExternallyVisible(),
- false /*declaration*/, 0, Flags,
- CGM.getLangOpts().Optimize, nullptr,
- TParamsArray, getFunctionDeclaration(FD));
+ llvm::MDSubprogram *SP = DBuilder.createTempFunctionFwdDecl(
+ DContext, Name, LinkageName, Unit, Line,
+ getOrCreateFunctionType(FD, FnType, Unit), !FD->isExternallyVisible(),
+ false /*declaration*/, 0, Flags, CGM.getLangOpts().Optimize, nullptr,
+ TParamsArray.get(), getFunctionDeclaration(FD));
const FunctionDecl *CanonDecl = cast<FunctionDecl>(FD->getCanonicalDecl());
- FwdDeclReplaceMap.emplace_back(
- std::piecewise_construct, std::make_tuple(CanonDecl),
- std::make_tuple(static_cast<llvm::Metadata *>(SP)));
+ FwdDeclReplaceMap.emplace_back(std::piecewise_construct,
+ std::make_tuple(CanonDecl),
+ std::make_tuple(SP));
return SP;
}
@@ -2436,7 +2421,7 @@
StringRef Name, LinkageName;
SourceLocation Loc = VD->getLocation();
llvm::DIFile Unit = getOrCreateFile(Loc);
- llvm::DIDescriptor DContext(Unit);
+ llvm::MDScope *DContext = Unit;
unsigned Line = getLineNumber(Loc);
collectVarDeclProps(VD, Unit, Line, T, Name, LinkageName, DContext);
@@ -2452,7 +2437,7 @@
return GV;
}
-llvm::DIDescriptor CGDebugInfo::getDeclarationOrDefinition(const Decl *D) {
+llvm::DebugNode *CGDebugInfo::getDeclarationOrDefinition(const Decl *D) {
// We only need a declaration (not a definition) of the type - so use whatever
// we would otherwise do to get a type for a pointee. (forward declarations in
// limited debug info, full definitions (if the type definition is available)
@@ -2463,7 +2448,7 @@
auto I = DeclCache.find(D->getCanonicalDecl());
if (I != DeclCache.end())
- return llvm::DIDescriptor(dyn_cast_or_null<llvm::MDNode>(I->second));
+ return dyn_cast_or_null<llvm::DebugNode>(I->second);
// No definition for now. Emit a forward definition that might be
// merged with a potential upcoming definition.
@@ -2472,7 +2457,7 @@
else if (const auto *VD = dyn_cast<VarDecl>(D))
return getGlobalVariableForwardDeclaration(VD);
- return llvm::DIDescriptor();
+ return nullptr;
}
/// getFunctionDeclaration - Return debug info descriptor to describe method
@@ -2492,23 +2477,23 @@
if (MI == SPCache.end()) {
if (const CXXMethodDecl *MD =
dyn_cast<CXXMethodDecl>(FD->getCanonicalDecl())) {
- llvm::DICompositeType T(S);
+ llvm::DICompositeType T = cast<llvm::MDCompositeType>(S);
llvm::DISubprogram SP =
CreateCXXMemberFunction(MD, getOrCreateFile(MD->getLocation()), T);
return SP;
}
}
if (MI != SPCache.end()) {
- llvm::DISubprogram SP(dyn_cast_or_null<llvm::MDNode>(MI->second));
- if (SP.isSubprogram() && !SP.isDefinition())
+ auto *SP = dyn_cast_or_null<llvm::MDSubprogram>(MI->second);
+ if (SP && !SP->isDefinition())
return SP;
}
for (auto NextFD : FD->redecls()) {
auto MI = SPCache.find(NextFD->getCanonicalDecl());
if (MI != SPCache.end()) {
- llvm::DISubprogram SP(dyn_cast_or_null<llvm::MDNode>(MI->second));
- if (SP.isSubprogram() && !SP.isDefinition())
+ auto *SP = dyn_cast_or_null<llvm::MDSubprogram>(MI->second);
+ if (SP && !SP->isDefinition())
return SP;
}
}
@@ -2517,9 +2502,9 @@
// getOrCreateFunctionType - Construct DIType. If it is a c++ method, include
// implicit parameter "this".
-llvm::DICompositeType CGDebugInfo::getOrCreateFunctionType(const Decl *D,
- QualType FnType,
- llvm::DIFile F) {
+llvm::MDSubroutineType *CGDebugInfo::getOrCreateFunctionType(const Decl *D,
+ QualType FnType,
+ llvm::DIFile F) {
if (!D || DebugKind <= CodeGenOptions::DebugLineTablesOnly)
// Create fake but valid subroutine type. Otherwise
// llvm::DISubprogram::Verify() would return false, and
@@ -2575,7 +2560,7 @@
return DBuilder.createSubroutineType(F, EltTypeArray);
}
- return llvm::DICompositeType(getOrCreateType(FnType, F));
+ return cast<llvm::MDSubroutineType>(getOrCreateType(FnType, F));
}
/// EmitFunctionStart - Constructs the debug code for entering a function.
@@ -2593,7 +2578,7 @@
unsigned Flags = 0;
llvm::DIFile Unit = getOrCreateFile(Loc);
- llvm::DIDescriptor FDContext(Unit);
+ llvm::MDScope *FDContext = Unit;
llvm::DIArray TParamsArray;
if (!HasDecl) {
// Use llvm function name.
@@ -2602,8 +2587,8 @@
// If there is a DISubprogram for this function available then use it.
auto FI = SPCache.find(FD->getCanonicalDecl());
if (FI != SPCache.end()) {
- llvm::DIDescriptor SP(dyn_cast_or_null<llvm::MDNode>(FI->second));
- if (SP.isSubprogram() && llvm::DISubprogram(SP).isDefinition()) {
+ auto *SP = dyn_cast_or_null<llvm::MDSubprogram>(FI->second);
+ if (SP && SP->isDefinition()) {
llvm::MDNode *SPN = SP;
LexicalBlockStack.emplace_back(SPN);
RegionMap[D].reset(SP);
@@ -2614,17 +2599,17 @@
TParamsArray, Flags);
} else if (const ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(D)) {
Name = getObjCMethodName(OMD);
- Flags |= llvm::DIDescriptor::FlagPrototyped;
+ Flags |= llvm::DebugNode::FlagPrototyped;
} else {
// Use llvm function name.
Name = Fn->getName();
- Flags |= llvm::DIDescriptor::FlagPrototyped;
+ Flags |= llvm::DebugNode::FlagPrototyped;
}
if (!Name.empty() && Name[0] == '\01')
Name = Name.substr(1);
if (!HasDecl || D->isImplicit()) {
- Flags |= llvm::DIDescriptor::FlagArtificial;
+ Flags |= llvm::DebugNode::FlagArtificial;
// Artificial functions without a location should not silently reuse CurLoc.
if (Loc.isInvalid())
CurLoc = SourceLocation();
@@ -2641,7 +2626,7 @@
FDContext, Name, LinkageName, Unit, LineNo,
getOrCreateFunctionType(D, FnType, Unit), Fn->hasInternalLinkage(),
true /*definition*/, ScopeLine, Flags, CGM.getLangOpts().Optimize, Fn,
- TParamsArray, getFunctionDeclaration(D));
+ TParamsArray.get(), getFunctionDeclaration(D));
// We might get here with a VarDecl in the case we're generating
// code for the initialization of globals. Do not record these decls
// as they will overwrite the actual VarDecl Decl in the cache.
@@ -2678,7 +2663,7 @@
if (!LexicalBlockStack.empty())
Back = LexicalBlockStack.back().get();
llvm::DIDescriptor D = DBuilder.createLexicalBlock(
- llvm::DIDescriptor(Back), getOrCreateFile(CurLoc), getLineNumber(CurLoc),
+ cast<llvm::MDScope>(Back), getOrCreateFile(CurLoc), getLineNumber(CurLoc),
getColumnNumber(CurLoc));
llvm::MDNode *DN = D;
LexicalBlockStack.emplace_back(DN);
@@ -2801,7 +2786,7 @@
llvm::DIArray Elements = DBuilder.getOrCreateArray(EltTys);
- unsigned Flags = llvm::DIDescriptor::FlagBlockByrefStruct;
+ unsigned Flags = llvm::DebugNode::FlagBlockByrefStruct;
return DBuilder.createStructType(Unit, "", Unit, 0, FieldOffset, 0, Flags,
llvm::DIType(), Elements);
@@ -2842,20 +2827,20 @@
SmallVector<int64_t, 9> Expr;
unsigned Flags = 0;
if (VD->isImplicit())
- Flags |= llvm::DIDescriptor::FlagArtificial;
+ Flags |= llvm::DebugNode::FlagArtificial;
// If this is the first argument and it is implicit then
// give it an object pointer flag.
// FIXME: There has to be a better way to do this, but for static
// functions there won't be an implicit param at arg1 and
// otherwise it is 'self' or 'this'.
if (isa<ImplicitParamDecl>(VD) && ArgNo == 1)
- Flags |= llvm::DIDescriptor::FlagObjectPointer;
+ Flags |= llvm::DebugNode::FlagObjectPointer;
if (llvm::Argument *Arg = dyn_cast<llvm::Argument>(Storage))
if (Arg->getType()->isPointerTy() && !Arg->hasByValAttr() &&
!VD->getType()->isPointerType())
Expr.push_back(llvm::dwarf::DW_OP_deref);
- llvm::MDNode *Scope = LexicalBlockStack.back();
+ auto *Scope = cast<llvm::MDScope>(LexicalBlockStack.back());
StringRef Name = VD->getName();
if (!Name.empty()) {
@@ -2874,13 +2859,12 @@
// Create the descriptor for the variable.
llvm::DIVariable D = DBuilder.createLocalVariable(
- Tag, llvm::DIDescriptor(Scope), VD->getName(), Unit, Line, Ty, ArgNo);
+ Tag, Scope, VD->getName(), Unit, Line, Ty, ArgNo);
// Insert an llvm.dbg.declare into the current block.
- llvm::Instruction *Call =
- DBuilder.insertDeclare(Storage, D, DBuilder.createExpression(Expr),
- Builder.GetInsertBlock());
- Call->setDebugLoc(llvm::DebugLoc::get(Line, Column, Scope));
+ DBuilder.insertDeclare(Storage, D, DBuilder.createExpression(Expr),
+ llvm::DebugLoc::get(Line, Column, Scope),
+ Builder.GetInsertBlock());
return;
} else if (isa<VariableArrayType>(VD->getType()))
Expr.push_back(llvm::dwarf::DW_OP_deref);
@@ -2899,28 +2883,27 @@
// Use VarDecl's Tag, Scope and Line number.
llvm::DIVariable D = DBuilder.createLocalVariable(
- Tag, llvm::DIDescriptor(Scope), FieldName, Unit, Line, FieldTy,
+ Tag, Scope, FieldName, Unit, Line, FieldTy,
CGM.getLangOpts().Optimize, Flags, ArgNo);
// Insert an llvm.dbg.declare into the current block.
- llvm::Instruction *Call = DBuilder.insertDeclare(
- Storage, D, DBuilder.createExpression(Expr),
- Builder.GetInsertBlock());
- Call->setDebugLoc(llvm::DebugLoc::get(Line, Column, Scope));
+ DBuilder.insertDeclare(Storage, D, DBuilder.createExpression(Expr),
+ llvm::DebugLoc::get(Line, Column, Scope),
+ Builder.GetInsertBlock());
}
return;
}
}
// Create the descriptor for the variable.
- llvm::DIVariable D = DBuilder.createLocalVariable(
- Tag, llvm::DIDescriptor(Scope), Name, Unit, Line, Ty,
- CGM.getLangOpts().Optimize, Flags, ArgNo);
+ llvm::DIVariable D =
+ DBuilder.createLocalVariable(Tag, Scope, Name, Unit, Line, Ty,
+ CGM.getLangOpts().Optimize, Flags, ArgNo);
// Insert an llvm.dbg.declare into the current block.
- llvm::Instruction *Call = DBuilder.insertDeclare(
- Storage, D, DBuilder.createExpression(Expr), Builder.GetInsertBlock());
- Call->setDebugLoc(llvm::DebugLoc::get(Line, Column, Scope));
+ DBuilder.insertDeclare(Storage, D, DBuilder.createExpression(Expr),
+ llvm::DebugLoc::get(Line, Column, Scope),
+ Builder.GetInsertBlock());
}
void CGDebugInfo::EmitDeclareOfAutoVariable(const VarDecl *VD,
@@ -2998,19 +2981,19 @@
}
// Create the descriptor for the variable.
- llvm::DIVariable D =
- DBuilder.createLocalVariable(llvm::dwarf::DW_TAG_auto_variable,
- llvm::DIDescriptor(LexicalBlockStack.back()),
- VD->getName(), Unit, Line, Ty);
+ llvm::DIVariable D = DBuilder.createLocalVariable(
+ llvm::dwarf::DW_TAG_auto_variable,
+ cast<llvm::MDLocalScope>(LexicalBlockStack.back()), VD->getName(), Unit,
+ Line, Ty);
// Insert an llvm.dbg.declare into the current block.
- llvm::Instruction *Call = InsertPoint ?
- DBuilder.insertDeclare(Storage, D, DBuilder.createExpression(addr),
- InsertPoint)
- : DBuilder.insertDeclare(Storage, D, DBuilder.createExpression(addr),
- Builder.GetInsertBlock());
- Call->setDebugLoc(
- llvm::DebugLoc::get(Line, Column, LexicalBlockStack.back()));
+ auto DL = llvm::DebugLoc::get(Line, Column, LexicalBlockStack.back());
+ if (InsertPoint)
+ DBuilder.insertDeclare(Storage, D, DBuilder.createExpression(addr), DL,
+ InsertPoint);
+ else
+ DBuilder.insertDeclare(Storage, D, DBuilder.createExpression(addr), DL,
+ Builder.GetInsertBlock());
}
/// EmitDeclareOfArgVariable - Emit call to llvm.dbg.declare for an argument
@@ -3158,27 +3141,25 @@
type = DBuilder.createPointerType(type, CGM.PointerWidthInBits);
// Get overall information about the block.
- unsigned flags = llvm::DIDescriptor::FlagArtificial;
- llvm::MDNode *scope = LexicalBlockStack.back();
+ unsigned flags = llvm::DebugNode::FlagArtificial;
+ auto *scope = cast<llvm::MDLocalScope>(LexicalBlockStack.back());
// Create the descriptor for the parameter.
llvm::DIVariable debugVar = DBuilder.createLocalVariable(
- llvm::dwarf::DW_TAG_arg_variable, llvm::DIDescriptor(scope),
- Arg->getName(), tunit, line, type, CGM.getLangOpts().Optimize, flags,
- ArgNo);
+ llvm::dwarf::DW_TAG_arg_variable, scope, Arg->getName(), tunit, line,
+ type, CGM.getLangOpts().Optimize, flags, ArgNo);
if (LocalAddr) {
// Insert an llvm.dbg.value into the current block.
- llvm::Instruction *DbgVal = DBuilder.insertDbgValueIntrinsic(
+ DBuilder.insertDbgValueIntrinsic(
LocalAddr, 0, debugVar, DBuilder.createExpression(),
- Builder.GetInsertBlock());
- DbgVal->setDebugLoc(llvm::DebugLoc::get(line, column, scope));
+ llvm::DebugLoc::get(line, column, scope), Builder.GetInsertBlock());
}
// Insert an llvm.dbg.declare into the current block.
- llvm::Instruction *DbgDecl = DBuilder.insertDeclare(
- Arg, debugVar, DBuilder.createExpression(), Builder.GetInsertBlock());
- DbgDecl->setDebugLoc(llvm::DebugLoc::get(line, column, scope));
+ DBuilder.insertDeclare(Arg, debugVar, DBuilder.createExpression(),
+ llvm::DebugLoc::get(line, column, scope),
+ Builder.GetInsertBlock());
}
/// If D is an out-of-class definition of a static data member of a class, find
@@ -3191,24 +3172,23 @@
auto MI = StaticDataMemberCache.find(D->getCanonicalDecl());
if (MI != StaticDataMemberCache.end()) {
assert(MI->second && "Static data member declaration should still exist");
- return llvm::DIDerivedType(cast<llvm::MDNode>(MI->second));
+ return cast<llvm::MDDerivedTypeBase>(MI->second);
}
// If the member wasn't found in the cache, lazily construct and add it to the
// type (used when a limited form of the type is emitted).
auto DC = D->getDeclContext();
- llvm::DICompositeType Ctxt(getContextDescriptor(cast<Decl>(DC)));
+ llvm::DICompositeType Ctxt =
+ cast<llvm::MDCompositeType>(getContextDescriptor(cast<Decl>(DC)));
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::DIDescriptor DContext) {
+llvm::DIGlobalVariable CGDebugInfo::CollectAnonRecordDecls(
+ const RecordDecl *RD, llvm::DIFile Unit, unsigned LineNo,
+ StringRef LinkageName, llvm::GlobalVariable *Var, llvm::MDScope *DContext) {
llvm::DIGlobalVariable GV;
for (const auto *Field : RD->fields()) {
@@ -3237,7 +3217,7 @@
assert(DebugKind >= CodeGenOptions::LimitedDebugInfo);
// Create global variable debug descriptor.
llvm::DIFile Unit;
- llvm::DIDescriptor DContext;
+ llvm::MDScope *DContext = nullptr;
unsigned LineNo;
StringRef DeclName, LinkageName;
QualType T;
@@ -3278,7 +3258,7 @@
Ty = getOrCreateType(QualType(ED->getTypeForDecl(), 0), Unit);
}
// Do not use DIGlobalVariable for enums.
- if (Ty.getTag() == llvm::dwarf::DW_TAG_enumeration_type)
+ if (Ty->getTag() == llvm::dwarf::DW_TAG_enumeration_type)
return;
// Do not emit separate definitions for function local const/statics.
if (isa<FunctionDecl>(VD->getDeclContext()))
@@ -3294,7 +3274,7 @@
return;
}
- llvm::DIDescriptor DContext =
+ llvm::MDScope *DContext =
getContextDescriptor(dyn_cast<Decl>(VD->getDeclContext()));
auto &GV = DeclCache[VD];
@@ -3307,7 +3287,7 @@
llvm::DIScope CGDebugInfo::getCurrentContextDescriptor(const Decl *D) {
if (!LexicalBlockStack.empty())
- return llvm::DIScope(LexicalBlockStack.back());
+ return cast<llvm::MDScope>(LexicalBlockStack.back());
return getContextDescriptor(D);
}
@@ -3328,7 +3308,7 @@
// Emitting one decl is sufficient - debuggers can detect that this is an
// overloaded name & provide lookup for all the overloads.
const UsingShadowDecl &USD = **UD.shadow_begin();
- if (llvm::DIDescriptor Target =
+ if (llvm::DebugNode *Target =
getDeclarationOrDefinition(USD.getUnderlyingDecl()))
DBuilder.createImportedDeclaration(
getCurrentContextDescriptor(cast<Decl>(USD.getDeclContext())), Target,
@@ -3341,7 +3321,7 @@
return llvm::DIImportedEntity();
auto &VH = NamespaceAliasCache[&NA];
if (VH)
- return llvm::DIImportedEntity(cast<llvm::MDNode>(VH));
+ return cast<llvm::MDImportedEntity>(VH);
llvm::DIImportedEntity R;
if (const NamespaceAliasDecl *Underlying =
dyn_cast<NamespaceAliasDecl>(NA.getAliasedNamespace()))
@@ -3366,12 +3346,12 @@
NSDecl = NSDecl->getCanonicalDecl();
auto I = NameSpaceCache.find(NSDecl);
if (I != NameSpaceCache.end())
- return llvm::DINameSpace(cast<llvm::MDNode>(I->second));
+ return cast<llvm::MDNamespace>(I->second);
unsigned LineNo = getLineNumber(NSDecl->getLocation());
llvm::DIFile FileD = getOrCreateFile(NSDecl->getLocation());
- llvm::DIDescriptor Context =
- getContextDescriptor(dyn_cast<Decl>(NSDecl->getDeclContext()));
+ llvm::MDScope *Context =
+ getContextDescriptor(dyn_cast<Decl>(NSDecl->getDeclContext()));
llvm::DINameSpace NS =
DBuilder.createNameSpace(Context, NSDecl->getName(), FileD, LineNo);
NameSpaceCache[NSDecl].reset(NS);
@@ -3383,23 +3363,23 @@
// element and the size(), so don't cache/reference them.
for (size_t i = 0; i != ObjCInterfaceCache.size(); ++i) {
ObjCInterfaceCacheEntry E = ObjCInterfaceCache[i];
- E.Decl.replaceAllUsesWith(CGM.getLLVMContext(),
- E.Type->getDecl()->getDefinition()
- ? CreateTypeDefinition(E.Type, E.Unit)
- : E.Decl);
+ llvm::MDType *Ty = E.Type->getDecl()->getDefinition()
+ ? CreateTypeDefinition(E.Type, E.Unit)
+ : E.Decl;
+ DBuilder.replaceTemporary(llvm::TempMDType(E.Decl), Ty);
}
for (auto p : ReplaceMap) {
assert(p.second);
- llvm::DIType Ty(cast<llvm::MDNode>(p.second));
- assert(Ty.isForwardDecl());
+ auto *Ty = cast<llvm::MDType>(p.second);
+ assert(Ty->isForwardDecl());
auto it = TypeCache.find(p.first);
assert(it != TypeCache.end());
assert(it->second);
- llvm::DIType RepTy(cast<llvm::MDNode>(it->second));
- Ty.replaceAllUsesWith(CGM.getLLVMContext(), RepTy);
+ DBuilder.replaceTemporary(llvm::TempMDType(Ty),
+ cast<llvm::MDType>(it->second));
}
for (const auto &p : FwdDeclReplaceMap) {
@@ -3416,15 +3396,15 @@
else
Repl = it->second;
- FwdDecl.replaceAllUsesWith(CGM.getLLVMContext(),
- llvm::DIDescriptor(cast<llvm::MDNode>(Repl)));
+ DBuilder.replaceTemporary(llvm::TempMDNode(FwdDecl),
+ cast<llvm::MDNode>(Repl));
}
// We keep our own list of retained types, because we need to look
// up the final type in the type cache.
for (std::vector<void *>::const_iterator RI = RetainedTypes.begin(),
RE = RetainedTypes.end(); RI != RE; ++RI)
- DBuilder.retainType(llvm::DIType(cast<llvm::MDNode>(TypeCache[*RI])));
+ DBuilder.retainType(cast<llvm::MDType>(TypeCache[*RI]));
DBuilder.finalize();
}
@@ -3432,7 +3412,8 @@
void CGDebugInfo::EmitExplicitCastType(QualType Ty) {
if (CGM.getCodeGenOpts().getDebugInfo() < CodeGenOptions::LimitedDebugInfo)
return;
- llvm::DIType DieTy = getOrCreateType(Ty, getOrCreateMainFile());
- // Don't ignore in case of explicit cast where it is referenced indirectly.
- DBuilder.retainType(DieTy);
+
+ if (llvm::DIType DieTy = getOrCreateType(Ty, getOrCreateMainFile()))
+ // Don't ignore in case of explicit cast where it is referenced indirectly.
+ DBuilder.retainType(DieTy);
}
diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h
index 62ba801..6fcceed 100644
--- a/lib/CodeGen/CGDebugInfo.h
+++ b/lib/CodeGen/CGDebugInfo.h
@@ -56,7 +56,7 @@
SourceLocation CurLoc;
llvm::DIType VTablePtrType;
llvm::DIType ClassTy;
- llvm::DICompositeType ObjTy;
+ llvm::MDCompositeType *ObjTy = nullptr;
llvm::DIType SelTy;
llvm::DIType OCLImage1dDITy, OCLImage1dArrayDITy, OCLImage1dBufferDITy;
llvm::DIType OCLImage2dDITy, OCLImage2dArrayDITy;
@@ -129,8 +129,9 @@
llvm::DIType CreateType(const FunctionType *Ty, llvm::DIFile F);
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);
+ llvm::MDCompositeType *CreateLimitedType(const RecordType *Ty);
+ void CollectContainingType(const CXXRecordDecl *RD,
+ llvm::MDCompositeType *CT);
llvm::DIType CreateType(const ObjCInterfaceType *Ty, llvm::DIFile F);
llvm::DIType CreateTypeDefinition(const ObjCInterfaceType *Ty, llvm::DIFile F);
llvm::DIType CreateType(const ObjCObjectType *Ty, llvm::DIFile F);
@@ -144,12 +145,13 @@
llvm::DIType CreateTypeDefinition(const EnumType *Ty);
llvm::DIType CreateSelfType(const QualType &QualTy, llvm::DIType Ty);
llvm::DIType getTypeOrNull(const QualType);
- llvm::DICompositeType getOrCreateMethodType(const CXXMethodDecl *Method,
- llvm::DIFile F);
- llvm::DICompositeType getOrCreateInstanceMethodType(
- QualType ThisPtr, const FunctionProtoType *Func, llvm::DIFile Unit);
- llvm::DICompositeType getOrCreateFunctionType(const Decl *D, QualType FnType,
+ llvm::MDSubroutineType *getOrCreateMethodType(const CXXMethodDecl *Method,
llvm::DIFile F);
+ llvm::MDSubroutineType *
+ getOrCreateInstanceMethodType(QualType ThisPtr, const FunctionProtoType *Func,
+ llvm::DIFile Unit);
+ llvm::MDSubroutineType *
+ getOrCreateFunctionType(const Decl *D, QualType FnType, llvm::DIFile F);
llvm::DIType getOrCreateVTablePtrType(llvm::DIFile F);
llvm::DINameSpace getOrCreateNameSpace(const NamespaceDecl *N);
llvm::DIType getOrCreateTypeDeclaration(QualType PointeeTy, llvm::DIFile F);
@@ -323,8 +325,8 @@
llvm::DIScope getCurrentContextDescriptor(const Decl *Decl);
/// \brief Create a forward decl for a RecordType in a given context.
- llvm::DICompositeType getOrCreateRecordFwdDecl(const RecordType *,
- llvm::DIDescriptor);
+ llvm::MDCompositeType *getOrCreateRecordFwdDecl(const RecordType *,
+ llvm::MDScope *);
/// \brief Create a set of decls for the context chain.
llvm::DIDescriptor createContextChain(const Decl *Decl);
@@ -363,7 +365,7 @@
/// \brief Retrieve the DIDescriptor, if any, for the canonical form of this
/// declaration.
- llvm::DIDescriptor getDeclarationOrDefinition(const Decl *D);
+ llvm::DebugNode *getDeclarationOrDefinition(const Decl *D);
/// \brief Return debug info descriptor to describe method
/// declaration for the given method definition.
@@ -385,9 +387,9 @@
/// Return a global variable that represents one of the collection of
/// global variables created for an anonmyous union.
llvm::DIGlobalVariable
- CollectAnonRecordDecls(const RecordDecl *RD, llvm::DIFile Unit, unsigned LineNo,
- StringRef LinkageName, llvm::GlobalVariable *Var,
- llvm::DIDescriptor DContext);
+ CollectAnonRecordDecls(const RecordDecl *RD, llvm::DIFile Unit,
+ unsigned LineNo, StringRef LinkageName,
+ llvm::GlobalVariable *Var, llvm::MDScope *DContext);
/// \brief Get function name for the given FunctionDecl. If the
/// name is constructed on demand (e.g. C++ destructor) then the name
@@ -419,18 +421,15 @@
/// \brief Collect various properties of a FunctionDecl.
/// \param GD A GlobalDecl whose getDecl() must return a FunctionDecl.
- void collectFunctionDeclProps(GlobalDecl GD,
- llvm::DIFile Unit,
+ void collectFunctionDeclProps(GlobalDecl GD, llvm::DIFile Unit,
StringRef &Name, StringRef &LinkageName,
- llvm::DIDescriptor &FDContext,
- llvm::DIArray &TParamsArray,
- unsigned &Flags);
+ llvm::MDScope *&FDContext,
+ llvm::DIArray &TParamsArray, unsigned &Flags);
/// \brief Collect various properties of a VarDecl.
void collectVarDeclProps(const VarDecl *VD, llvm::DIFile &Unit,
- unsigned &LineNo, QualType &T,
- StringRef &Name, StringRef &LinkageName,
- llvm::DIDescriptor &VDContext);
+ unsigned &LineNo, QualType &T, StringRef &Name,
+ StringRef &LinkageName, llvm::MDScope *&VDContext);
/// \brief Allocate a copy of \p A using the DebugInfoNames allocator
/// and return a reference to it. If multiple arguments are given the strings
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index f79d137..f1ccb09 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -635,8 +635,9 @@
if (capturedByInit) {
// We can use a simple GEP for this because it can't have been
// moved yet.
- tempLV.setAddress(Builder.CreateStructGEP(tempLV.getAddress(),
- getByRefValueLLVMField(cast<VarDecl>(D))));
+ tempLV.setAddress(Builder.CreateStructGEP(
+ nullptr, tempLV.getAddress(),
+ getByRefValueLLVMField(cast<VarDecl>(D)).second));
}
llvm::PointerType *ty
@@ -797,8 +798,9 @@
// If necessary, get a pointer to the element and emit it.
if (!Elt->isNullValue() && !isa<llvm::UndefValue>(Elt))
- emitStoresForInitAfterMemset(Elt, Builder.CreateConstGEP2_32(Loc, 0, i),
- isVolatile, Builder);
+ emitStoresForInitAfterMemset(
+ Elt, Builder.CreateConstGEP2_32(Init->getType(), Loc, 0, i),
+ isVolatile, Builder);
}
return;
}
@@ -811,8 +813,9 @@
// If necessary, get a pointer to the element and emit it.
if (!Elt->isNullValue() && !isa<llvm::UndefValue>(Elt))
- emitStoresForInitAfterMemset(Elt, Builder.CreateConstGEP2_32(Loc, 0, i),
- isVolatile, Builder);
+ emitStoresForInitAfterMemset(
+ Elt, Builder.CreateConstGEP2_32(Init->getType(), Loc, 0, i),
+ isVolatile, Builder);
}
}
diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp
index 236337b..eb4ddc7 100644
--- a/lib/CodeGen/CGDeclCXX.cpp
+++ b/lib/CodeGen/CGDeclCXX.cpp
@@ -298,6 +298,11 @@
CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D,
llvm::GlobalVariable *Addr,
bool PerformInit) {
+ // Check if we've already initialized this decl.
+ auto I = DelayedCXXInitPosition.find(D);
+ if (I != DelayedCXXInitPosition.end() && I->second == ~0U)
+ return;
+
llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false);
SmallString<256> FnName;
{
@@ -327,11 +332,9 @@
CXXThreadLocalInitVars.push_back(Addr);
} else if (PerformInit && ISA) {
EmitPointerToInitFunc(D, Addr, Fn, ISA);
- DelayedCXXInitPosition.erase(D);
} else if (auto *IPA = D->getAttr<InitPriorityAttr>()) {
OrderGlobalInits Key(IPA->getPriority(), PrioritizedCXXGlobalInits.size());
PrioritizedCXXGlobalInits.push_back(std::make_pair(Key, Fn));
- DelayedCXXInitPosition.erase(D);
} else if (isTemplateInstantiation(D->getTemplateSpecializationKind())) {
// C++ [basic.start.init]p2:
// Definitions of explicitly specialized class template static data
@@ -346,24 +349,24 @@
// minor startup time optimization. In the MS C++ ABI, there are no guard
// variables, so this COMDAT key is required for correctness.
AddGlobalCtor(Fn, 65535, COMDATKey);
- DelayedCXXInitPosition.erase(D);
} else if (D->hasAttr<SelectAnyAttr>()) {
// SelectAny globals will be comdat-folded. Put the initializer into a
// COMDAT group associated with the global, so the initializers get folded
// too.
AddGlobalCtor(Fn, 65535, COMDATKey);
- DelayedCXXInitPosition.erase(D);
} else {
- llvm::DenseMap<const Decl *, unsigned>::iterator I =
- DelayedCXXInitPosition.find(D);
+ I = DelayedCXXInitPosition.find(D); // Re-do lookup in case of re-hash.
if (I == DelayedCXXInitPosition.end()) {
CXXGlobalInits.push_back(Fn);
- } else {
- assert(CXXGlobalInits[I->second] == nullptr);
+ } else if (I->second != ~0U) {
+ assert(I->second < CXXGlobalInits.size() &&
+ CXXGlobalInits[I->second] == nullptr);
CXXGlobalInits[I->second] = Fn;
- DelayedCXXInitPosition.erase(I);
}
}
+
+ // Remember that we already emitted the initializer for this global.
+ DelayedCXXInitPosition[D] = ~0U;
}
void CodeGenModule::EmitCXXThreadLocalInitFunc() {
diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp
index 223b8f7..ff12a9a 100644
--- a/lib/CodeGen/CGException.cpp
+++ b/lib/CodeGen/CGException.cpp
@@ -19,8 +19,11 @@
#include "clang/AST/Mangle.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtObjC.h"
+#include "clang/AST/StmtVisitor.h"
#include "llvm/IR/CallSite.h"
#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/IntrinsicInst.h"
+#include "llvm/Support/SaveAndRestore.h"
using namespace clang;
using namespace CodeGen;
@@ -406,13 +409,6 @@
return Builder.CreateLoad(getEHSelectorSlot(), "sel");
}
-llvm::Value *CodeGenFunction::getAbnormalTerminationSlot() {
- if (!AbnormalTerminationSlot)
- AbnormalTerminationSlot =
- CreateTempAlloca(Int8Ty, "abnormal.termination.slot");
- return AbnormalTerminationSlot;
-}
-
void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E,
bool KeepInsertionPoint) {
if (const Expr *SubExpr = E->getSubExpr()) {
@@ -458,6 +454,10 @@
EHStack.pushTerminate();
}
} else if (EST == EST_Dynamic || EST == EST_DynamicNone) {
+ // TODO: Revisit exception specifications for the MS ABI. There is a way to
+ // encode these in an object file but MSVC doesn't do anything with it.
+ if (getTarget().getCXXABI().isMicrosoft())
+ return;
unsigned NumExceptions = Proto->getNumExceptions();
EHFilterScope *Filter = EHStack.pushFilter(NumExceptions);
@@ -532,6 +532,10 @@
EHStack.popTerminate();
}
} else if (EST == EST_Dynamic || EST == EST_DynamicNone) {
+ // TODO: Revisit exception specifications for the MS ABI. There is a way to
+ // encode these in an object file but MSVC doesn't do anything with it.
+ if (getTarget().getCXXABI().isMicrosoft())
+ return;
EHFilterScope &filterScope = cast<EHFilterScope>(*EHStack.begin());
emitFilterDispatchBlock(*this, filterScope);
EHStack.popFilter();
@@ -568,7 +572,7 @@
TypeInfo = CGM.getObjCRuntime().GetEHType(CaughtType);
else
TypeInfo =
- CGM.getAddrOfCXXHandlerMapEntry(CaughtType, C->getCaughtType());
+ CGM.getAddrOfCXXCatchHandlerType(CaughtType, C->getCaughtType());
CatchScope->setHandler(I, TypeInfo, Handler);
} else {
// No exception decl indicates '...', a catch-all.
@@ -1277,8 +1281,7 @@
return;
}
- SEHFinallyInfo FI;
- EnterSEHTryStmt(S, FI);
+ EnterSEHTryStmt(S);
{
JumpDest TryExit = getJumpDestInCurrentScope("__try.__leave");
@@ -1291,109 +1294,224 @@
else
delete TryExit.getBlock();
}
- ExitSEHTryStmt(S, FI);
+ ExitSEHTryStmt(S);
}
namespace {
-struct PerformSEHFinally : EHScopeStack::Cleanup {
- CodeGenFunction::SEHFinallyInfo *FI;
- PerformSEHFinally(CodeGenFunction::SEHFinallyInfo *FI) : FI(FI) {}
+struct PerformSEHFinally : EHScopeStack::Cleanup {
+ llvm::Function *OutlinedFinally;
+ PerformSEHFinally(llvm::Function *OutlinedFinally)
+ : OutlinedFinally(OutlinedFinally) {}
void Emit(CodeGenFunction &CGF, Flags F) override {
- // Cleanups are emitted at most twice: once for normal control flow and once
- // for exception control flow. Branch into the finally block, and remember
- // the continuation block so we can branch out later.
- if (!FI->FinallyBB) {
- FI->FinallyBB = CGF.createBasicBlock("__finally");
- FI->FinallyBB->insertInto(CGF.CurFn);
- FI->FinallyBB->moveAfter(CGF.Builder.GetInsertBlock());
- }
+ ASTContext &Context = CGF.getContext();
+ QualType ArgTys[2] = {Context.BoolTy, Context.VoidPtrTy};
+ FunctionProtoType::ExtProtoInfo EPI;
+ const auto *FTP = cast<FunctionType>(
+ Context.getFunctionType(Context.VoidTy, ArgTys, EPI));
- // Set the termination status and branch in.
- CGF.Builder.CreateStore(
- llvm::ConstantInt::get(CGF.Int8Ty, F.isForEHCleanup()),
- CGF.getAbnormalTerminationSlot());
- CGF.Builder.CreateBr(FI->FinallyBB);
+ CallArgList Args;
+ llvm::Value *IsForEH =
+ llvm::ConstantInt::get(CGF.ConvertType(ArgTys[0]), F.isForEHCleanup());
+ Args.add(RValue::get(IsForEH), ArgTys[0]);
- // Create a continuation block for normal or exceptional control.
- if (F.isForEHCleanup()) {
- assert(!FI->ResumeBB && "double emission for EH");
- FI->ResumeBB = CGF.createBasicBlock("__finally.resume");
- CGF.EmitBlock(FI->ResumeBB);
- } else {
- assert(F.isForNormalCleanup() && !FI->ContBB && "double normal emission");
- FI->ContBB = CGF.createBasicBlock("__finally.cont");
- CGF.EmitBlock(FI->ContBB);
- // Try to keep source order.
- FI->ContBB->moveAfter(FI->FinallyBB);
- }
+ 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]);
+
+ const CGFunctionInfo &FnInfo =
+ CGM.getTypes().arrangeFreeFunctionCall(Args, FTP, /*chainCall=*/false);
+ CGF.EmitCall(FnInfo, OutlinedFinally, ReturnValueSlot(), Args);
}
};
}
+namespace {
+/// Find all local variable captures in the statement.
+struct CaptureFinder : ConstStmtVisitor<CaptureFinder> {
+ CodeGenFunction &ParentCGF;
+ const VarDecl *ParentThis;
+ SmallVector<const VarDecl *, 4> Captures;
+ CaptureFinder(CodeGenFunction &ParentCGF, const VarDecl *ParentThis)
+ : ParentCGF(ParentCGF), ParentThis(ParentThis) {}
+
+ void Visit(const Stmt *S) {
+ // See if this is a capture, then recurse.
+ ConstStmtVisitor<CaptureFinder>::Visit(S);
+ for (const Stmt *Child : S->children())
+ if (Child)
+ Visit(Child);
+ }
+
+ void VisitDeclRefExpr(const DeclRefExpr *E) {
+ // If this is already a capture, just make sure we capture 'this'.
+ if (E->refersToEnclosingVariableOrCapture()) {
+ Captures.push_back(ParentThis);
+ return;
+ }
+
+ const auto *D = dyn_cast<VarDecl>(E->getDecl());
+ if (D && D->isLocalVarDeclOrParm() && D->hasLocalStorage())
+ Captures.push_back(D);
+ }
+
+ void VisitCXXThisExpr(const CXXThisExpr *E) {
+ Captures.push_back(ParentThis);
+ }
+};
+}
+
+void CodeGenFunction::EmitCapturedLocals(CodeGenFunction &ParentCGF,
+ const Stmt *OutlinedStmt,
+ llvm::Value *ParentFP) {
+ // 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())
+ 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);
+
+ // Create llvm.framerecover calls for all captures.
+ for (const VarDecl *VD : Finder.Captures) {
+ if (isa<ImplicitParamDecl>(VD)) {
+ CGM.ErrorUnsupported(VD, "'this' captured by SEH");
+ CXXThisValue = llvm::UndefValue::get(ConvertTypeForMem(VD->getType()));
+ continue;
+ }
+ if (VD->getType()->isVariablyModifiedType()) {
+ CGM.ErrorUnsupported(VD, "VLA captured by SEH");
+ continue;
+ }
+ assert((isa<ImplicitParamDecl>(VD) || VD->isLocalVarDeclOrParm()) &&
+ "captured non-local variable");
+
+ // If this decl hasn't been declared yet, it will be declared in the
+ // OutlinedStmt.
+ auto I = ParentCGF.LocalDeclMap.find(VD);
+ if (I == ParentCGF.LocalDeclMap.end())
+ 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.CreateCall3(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;
+ }
+}
+
+/// 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,
+ const Stmt *OutlinedStmt) {
+ llvm::Function *ParentFn = ParentCGF.CurFn;
+ const CGFunctionInfo &FnInfo = CGM.getTypes().arrangeFreeFunctionDeclaration(
+ RetTy, Args, FunctionType::ExtInfo(), /*isVariadic=*/false);
+
+ llvm::FunctionType *FnTy = CGM.getTypes().GetFunctionType(FnInfo);
+ llvm::Function *Fn = llvm::Function::Create(
+ FnTy, llvm::GlobalValue::InternalLinkage, Name.str(), &CGM.getModule());
+ // The filter is either in the same comdat as the function, or it's internal.
+ if (llvm::Comdat *C = ParentFn->getComdat()) {
+ Fn->setComdat(C);
+ } else if (ParentFn->hasWeakLinkage() || ParentFn->hasLinkOnceLinkage()) {
+ llvm::Comdat *C = CGM.getModule().getOrInsertComdat(ParentFn->getName());
+ ParentFn->setComdat(C);
+ Fn->setComdat(C);
+ } else {
+ Fn->setLinkage(llvm::GlobalValue::InternalLinkage);
+ }
+
+ IsOutlinedSEHHelper = true;
+
+ StartFunction(GlobalDecl(), RetTy, Fn, FnInfo, Args,
+ OutlinedStmt->getLocStart(), OutlinedStmt->getLocStart());
+
+ CGM.SetLLVMFunctionAttributes(nullptr, FnInfo, CurFn);
+
+ auto AI = Fn->arg_begin();
+ ++AI;
+ EmitCapturedLocals(ParentCGF, OutlinedStmt, &*AI);
+}
+
/// Create a stub filter function that will ultimately hold the code of the
/// filter expression. The EH preparation passes in LLVM will outline the code
/// from the main function body into this stub.
llvm::Function *
CodeGenFunction::GenerateSEHFilterFunction(CodeGenFunction &ParentCGF,
const SEHExceptStmt &Except) {
- const Decl *ParentCodeDecl = ParentCGF.CurCodeDecl;
- llvm::Function *ParentFn = ParentCGF.CurFn;
+ const Expr *FilterExpr = Except.getFilterExpr();
+ SourceLocation StartLoc = FilterExpr->getLocStart();
- Expr *FilterExpr = Except.getFilterExpr();
+ 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);
}
- // Arrange a function with the declaration:
- // int filt(EXCEPTION_POINTERS *exception_pointers, void *frame_pointer)
- QualType RetTy = getContext().IntTy;
- FunctionArgList Args;
- SEHPointersDecl = ImplicitParamDecl::Create(
- getContext(), nullptr, FilterExpr->getLocStart(),
- &getContext().Idents.get("exception_pointers"), getContext().VoidPtrTy);
- Args.push_back(SEHPointersDecl);
- Args.push_back(ImplicitParamDecl::Create(
- getContext(), nullptr, FilterExpr->getLocStart(),
- &getContext().Idents.get("frame_pointer"), getContext().VoidPtrTy));
- const CGFunctionInfo &FnInfo = CGM.getTypes().arrangeFreeFunctionDeclaration(
- RetTy, Args, FunctionType::ExtInfo(), /*isVariadic=*/false);
- llvm::FunctionType *FnTy = CGM.getTypes().GetFunctionType(FnInfo);
- llvm::Function *Fn = llvm::Function::Create(FnTy, ParentFn->getLinkage(),
- Name.str(), &CGM.getModule());
- // The filter is either in the same comdat as the function, or it's internal.
- if (llvm::Comdat *C = ParentFn->getComdat()) {
- Fn->setComdat(C);
- } else if (ParentFn->hasWeakLinkage() || ParentFn->hasLinkOnceLinkage()) {
- // FIXME: Unreachable with Rafael's changes?
- llvm::Comdat *C = CGM.getModule().getOrInsertComdat(ParentFn->getName());
- ParentFn->setComdat(C);
- Fn->setComdat(C);
- } else {
- Fn->setLinkage(llvm::GlobalValue::InternalLinkage);
- }
+ startOutlinedSEHHelper(ParentCGF, Name, getContext().IntTy, Args, FilterExpr);
- StartFunction(GlobalDecl(), RetTy, Fn, FnInfo, Args,
- FilterExpr->getLocStart(), FilterExpr->getLocStart());
+ // 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();
- // Insert dummy allocas for every local variable in scope. We'll initialize
- // them and prune the unused ones after we find out which ones were
- // referenced.
- for (const auto &DeclPtrs : ParentCGF.LocalDeclMap) {
- const Decl *VD = DeclPtrs.first;
- llvm::Value *Ptr = DeclPtrs.second;
- auto *ValTy = cast<llvm::PointerType>(Ptr->getType())->getElementType();
- LocalDeclMap[VD] = CreateTempAlloca(ValTy, Ptr->getName() + ".filt");
- }
-
// Emit the original filter expression, convert to i32, and return.
llvm::Value *R = EmitScalarExpr(FilterExpr);
R = Builder.CreateIntCast(R, CGM.IntTy,
@@ -1402,18 +1520,42 @@
FinishFunction(FilterExpr->getLocEnd());
- for (const auto &DeclPtrs : ParentCGF.LocalDeclMap) {
- const Decl *VD = DeclPtrs.first;
- auto *Alloca = cast<llvm::AllocaInst>(LocalDeclMap[VD]);
- if (Alloca->hasNUses(0)) {
- Alloca->eraseFromParent();
- continue;
- }
- ErrorUnsupported(FilterExpr,
- "SEH filter expression local variable capture");
+ return CurFn;
+}
+
+llvm::Function *
+CodeGenFunction::GenerateSEHFinallyFunction(CodeGenFunction &ParentCGF,
+ const SEHFinallyStmt &Finally) {
+ const Stmt *FinallyBlock = Finally.getBlock();
+ SourceLocation StartLoc = FinallyBlock->getLocStart();
+
+ FunctionArgList Args;
+ Args.push_back(ImplicitParamDecl::Create(
+ getContext(), nullptr, StartLoc,
+ &getContext().Idents.get("abnormal_termination"), getContext().BoolTy));
+ 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);
}
- return Fn;
+ startOutlinedSEHHelper(ParentCGF, Name, getContext().VoidTy, Args,
+ FinallyBlock);
+
+ // Emit the original filter expression, convert to i32, and return.
+ EmitStmt(FinallyBlock);
+
+ FinishFunction(FinallyBlock->getLocEnd());
+
+ return CurFn;
}
void CodeGenFunction::EmitSEHExceptionCodeSave() {
@@ -1429,7 +1571,7 @@
llvm::Type *RecordTy = CGM.Int32Ty->getPointerTo();
llvm::Type *PtrsTy = llvm::StructType::get(RecordTy, CGM.VoidPtrTy, nullptr);
Ptrs = Builder.CreateBitCast(Ptrs, PtrsTy->getPointerTo());
- llvm::Value *Rec = Builder.CreateStructGEP(Ptrs, 0);
+ llvm::Value *Rec = Builder.CreateStructGEP(PtrsTy, Ptrs, 0);
Rec = Builder.CreateLoad(Rec);
llvm::Value *Code = Builder.CreateLoad(Rec);
Code = Builder.CreateZExt(Code, CGM.IntPtrTy);
@@ -1457,21 +1599,24 @@
}
llvm::Value *CodeGenFunction::EmitSEHAbnormalTermination() {
- // Load from the abnormal termination slot. It will be uninitialized outside
- // of __finally blocks, which we should warn or error on.
- llvm::Value *IsEH = Builder.CreateLoad(getAbnormalTerminationSlot());
- return Builder.CreateZExt(IsEH, Int32Ty);
+ // Abnormal termination is just the first parameter to the outlined finally
+ // helper.
+ auto AI = CurFn->arg_begin();
+ return Builder.CreateZExt(&*AI, Int32Ty);
}
-void CodeGenFunction::EnterSEHTryStmt(const SEHTryStmt &S, SEHFinallyInfo &FI) {
- if (S.getFinallyHandler()) {
+void CodeGenFunction::EnterSEHTryStmt(const SEHTryStmt &S) {
+ CodeGenFunction HelperCGF(CGM, /*suppressNewContext=*/true);
+ if (const SEHFinallyStmt *Finally = S.getFinallyHandler()) {
// Push a cleanup for __finally blocks.
- EHStack.pushCleanup<PerformSEHFinally>(NormalAndEHCleanup, &FI);
+ llvm::Function *FinallyFunc =
+ HelperCGF.GenerateSEHFinallyFunction(*this, *Finally);
+ EHStack.pushCleanup<PerformSEHFinally>(NormalAndEHCleanup, FinallyFunc);
return;
}
// Otherwise, we must have an __except block.
- SEHExceptStmt *Except = S.getExceptHandler();
+ const SEHExceptStmt *Except = S.getExceptHandler();
assert(Except);
EHCatchScope *CatchScope = EHStack.pushCatch(1);
@@ -1486,40 +1631,17 @@
// In general, we have to emit an outlined filter function. Use the function
// in place of the RTTI typeinfo global that C++ EH uses.
- CodeGenFunction FilterCGF(CGM, /*suppressNewContext=*/true);
llvm::Function *FilterFunc =
- FilterCGF.GenerateSEHFilterFunction(*this, *Except);
+ HelperCGF.GenerateSEHFilterFunction(*this, *Except);
llvm::Constant *OpaqueFunc =
llvm::ConstantExpr::getBitCast(FilterFunc, Int8PtrTy);
CatchScope->setHandler(0, OpaqueFunc, createBasicBlock("__except"));
}
-void CodeGenFunction::ExitSEHTryStmt(const SEHTryStmt &S, SEHFinallyInfo &FI) {
+void CodeGenFunction::ExitSEHTryStmt(const SEHTryStmt &S) {
// Just pop the cleanup if it's a __finally block.
- if (const SEHFinallyStmt *Finally = S.getFinallyHandler()) {
+ if (S.getFinallyHandler()) {
PopCleanupBlock();
- assert(FI.ContBB && "did not emit normal cleanup");
-
- // Emit the code into FinallyBB.
- CGBuilderTy::InsertPoint SavedIP = Builder.saveIP();
- Builder.SetInsertPoint(FI.FinallyBB);
- EmitStmt(Finally->getBlock());
-
- if (HaveInsertPoint()) {
- if (FI.ResumeBB) {
- llvm::Value *IsEH = Builder.CreateLoad(getAbnormalTerminationSlot(),
- "abnormal.termination");
- IsEH = Builder.CreateICmpEQ(IsEH, llvm::ConstantInt::get(Int8Ty, 0));
- Builder.CreateCondBr(IsEH, FI.ContBB, FI.ResumeBB);
- } else {
- // There was nothing exceptional in the try body, so we only have normal
- // control flow.
- Builder.CreateBr(FI.ContBB);
- }
- }
-
- Builder.restoreIP(SavedIP);
-
return;
}
@@ -1569,7 +1691,13 @@
if (HaveInsertPoint())
EmitStopPoint(&S);
- assert(!SEHTryEpilogueStack.empty() &&
- "sema should have rejected this __leave");
+ // This must be a __leave from a __finally block, which we warn on and is UB.
+ // Just emit unreachable.
+ if (!isSEHTryScope()) {
+ Builder.CreateUnreachable();
+ Builder.ClearInsertionPoint();
+ return;
+ }
+
EmitBranchThroughCleanup(*SEHTryEpilogueStack.back());
}
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index 5ba51cc..4147317 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -300,26 +300,26 @@
const MaterializeTemporaryExpr *M, const Expr *Inner) {
switch (M->getStorageDuration()) {
case SD_FullExpression:
- case SD_Automatic:
+ case SD_Automatic: {
// If we have a constant temporary array or record try to promote it into a
// constant global under the same rules a normal constant would've been
// promoted. This is easier on the optimizer and generally emits fewer
// instructions.
+ QualType Ty = Inner->getType();
if (CGF.CGM.getCodeGenOpts().MergeAllConstants &&
- (M->getType()->isArrayType() || M->getType()->isRecordType()) &&
- CGF.CGM.isTypeConstant(M->getType(), true))
- if (llvm::Constant *Init =
- CGF.CGM.EmitConstantExpr(Inner, M->getType(), &CGF)) {
+ (Ty->isArrayType() || Ty->isRecordType()) &&
+ CGF.CGM.isTypeConstant(Ty, true))
+ if (llvm::Constant *Init = CGF.CGM.EmitConstantExpr(Inner, Ty, &CGF)) {
auto *GV = new llvm::GlobalVariable(
CGF.CGM.getModule(), Init->getType(), /*isConstant=*/true,
llvm::GlobalValue::PrivateLinkage, Init, ".ref.tmp");
GV->setAlignment(
- CGF.getContext().getTypeAlignInChars(M->getType()).getQuantity());
+ CGF.getContext().getTypeAlignInChars(Ty).getQuantity());
// FIXME: Should we put the new global into a COMDAT?
return GV;
}
- return CGF.CreateMemTemp(Inner->getType(), "ref.tmp");
-
+ return CGF.CreateMemTemp(Ty, "ref.tmp");
+ }
case SD_Thread:
case SD_Static:
return CGF.CGM.GetAddrOfGlobalTemporary(M, Inner);
@@ -2077,9 +2077,8 @@
assert(E->getSubExpr()->getType()->isAnyComplexType());
unsigned Idx = E->getOpcode() == UO_Imag;
- return MakeAddrLValue(Builder.CreateStructGEP(LV.getAddress(),
- Idx, "idx"),
- ExprTy);
+ return MakeAddrLValue(
+ Builder.CreateStructGEP(nullptr, LV.getAddress(), Idx, "idx"), ExprTy);
}
case UO_PreInc:
case UO_PreDec: {
@@ -2675,7 +2674,7 @@
unsigned Idx = RL.getLLVMFieldNo(field);
if (Idx != 0)
// For structs, we GEP to the field that the record layout suggests.
- Addr = Builder.CreateStructGEP(Addr, Idx, field->getName());
+ Addr = Builder.CreateStructGEP(nullptr, Addr, Idx, field->getName());
// Get the access type.
llvm::Type *PtrTy = llvm::Type::getIntNPtrTy(
getLLVMContext(), Info.StorageSize,
@@ -2710,7 +2709,7 @@
} else {
// For structs, we GEP to the field that the record layout suggests.
unsigned idx = CGM.getTypes().getCGRecordLayout(rec).getLLVMFieldNo(field);
- addr = Builder.CreateStructGEP(addr, idx, field->getName());
+ addr = Builder.CreateStructGEP(nullptr, addr, idx, field->getName());
// If this is a reference field, load the reference right now.
if (const ReferenceType *refType = type->getAs<ReferenceType>()) {
@@ -2789,7 +2788,7 @@
const CGRecordLayout &RL =
CGM.getTypes().getCGRecordLayout(Field->getParent());
unsigned idx = RL.getLLVMFieldNo(Field);
- llvm::Value *V = Builder.CreateStructGEP(Base.getAddress(), idx);
+ llvm::Value *V = Builder.CreateStructGEP(nullptr, Base.getAddress(), idx);
assert(!FieldType.getObjCGCAttr() && "fields cannot have GC attrs");
// Make sure that the address is pointing to the right type. This is critical
@@ -3369,7 +3368,7 @@
llvm::Value *CalleePrefixStruct = Builder.CreateBitCast(
Callee, llvm::PointerType::getUnqual(PrefixStructTy));
llvm::Value *CalleeSigPtr =
- Builder.CreateConstGEP2_32(CalleePrefixStruct, 0, 0);
+ Builder.CreateConstGEP2_32(PrefixStructTy, CalleePrefixStruct, 0, 0);
llvm::Value *CalleeSig = Builder.CreateLoad(CalleeSigPtr);
llvm::Value *CalleeSigMatch = Builder.CreateICmpEQ(CalleeSig, PrefixSig);
@@ -3379,7 +3378,7 @@
EmitBlock(TypeCheck);
llvm::Value *CalleeRTTIPtr =
- Builder.CreateConstGEP2_32(CalleePrefixStruct, 0, 1);
+ Builder.CreateConstGEP2_32(PrefixStructTy, CalleePrefixStruct, 0, 1);
llvm::Value *CalleeRTTI = Builder.CreateLoad(CalleeRTTIPtr);
llvm::Value *CalleeRTTIMatch =
Builder.CreateICmpEQ(CalleeRTTI, FTRTTIConst);
diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp
index 5b0d9f0..6b4cf68 100644
--- a/lib/CodeGen/CGExprAgg.cpp
+++ b/lib/CodeGen/CGExprAgg.cpp
@@ -645,7 +645,7 @@
// Build a GEP to refer to the subobject.
llvm::Value *valueAddr =
- CGF.Builder.CreateStructGEP(valueDest.getAddr(), 0);
+ CGF.Builder.CreateStructGEP(nullptr, valueDest.getAddr(), 0);
valueDest = AggValueSlot::forAddr(valueAddr,
valueDest.getAlignment(),
valueDest.getQualifiers(),
@@ -666,7 +666,7 @@
CGF.EmitAggExpr(E->getSubExpr(), atomicSlot);
llvm::Value *valueAddr =
- Builder.CreateStructGEP(atomicSlot.getAddr(), 0);
+ Builder.CreateStructGEP(nullptr, atomicSlot.getAddr(), 0);
RValue rvalue = RValue::getAggregate(valueAddr, atomicSlot.isVolatile());
return EmitFinalDestCopy(valueType, rvalue);
}
diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp
index 6852d3a..4bffad3 100644
--- a/lib/CodeGen/CGExprCXX.cpp
+++ b/lib/CodeGen/CGExprCXX.cpp
@@ -256,6 +256,12 @@
} else if (UseVirtualCall) {
Callee = CGM.getCXXABI().getVirtualFunctionPointer(*this, MD, This, Ty);
} else {
+ if (SanOpts.has(SanitizerKind::CFINVCall) &&
+ MD->getParent()->isDynamicClass()) {
+ llvm::Value *VTable = GetVTablePtr(This, Int8PtrTy);
+ EmitVTablePtrCheckForCall(MD, VTable);
+ }
+
if (getLangOpts().AppleKext && MD->isVirtual() && HasQualifier)
Callee = BuildAppleKextVirtualCall(MD, Qualifier, Ty);
else if (!DevirtualizedMethod)
@@ -778,12 +784,10 @@
llvm_unreachable("bad evaluation kind");
}
-void
-CodeGenFunction::EmitNewArrayInitializer(const CXXNewExpr *E,
- QualType ElementType,
- llvm::Value *BeginPtr,
- llvm::Value *NumElements,
- llvm::Value *AllocSizeWithoutCookie) {
+void CodeGenFunction::EmitNewArrayInitializer(
+ const CXXNewExpr *E, QualType ElementType, llvm::Type *ElementTy,
+ llvm::Value *BeginPtr, llvm::Value *NumElements,
+ llvm::Value *AllocSizeWithoutCookie) {
// If we have a type with trivial initialization and no initializer,
// there's nothing to do.
if (!E->hasInitializer())
@@ -809,7 +813,8 @@
if (const ConstantArrayType *CAT = dyn_cast_or_null<ConstantArrayType>(
AllocType->getAsArrayTypeUnsafe())) {
unsigned AS = CurPtr->getType()->getPointerAddressSpace();
- llvm::Type *AllocPtrTy = ConvertTypeForMem(AllocType)->getPointerTo(AS);
+ ElementTy = ConvertTypeForMem(AllocType);
+ llvm::Type *AllocPtrTy = ElementTy->getPointerTo(AS);
CurPtr = Builder.CreateBitCast(CurPtr, AllocPtrTy);
InitListElements *= getContext().getConstantArrayElementCount(CAT);
}
@@ -839,7 +844,8 @@
// initialization loops.
StoreAnyExprIntoOneUnit(*this, ILE->getInit(i),
ILE->getInit(i)->getType(), CurPtr);
- CurPtr = Builder.CreateConstInBoundsGEP1_32(CurPtr, 1, "array.exp.next");
+ CurPtr = Builder.CreateConstInBoundsGEP1_32(ElementTy, CurPtr, 1,
+ "array.exp.next");
}
// The remaining elements are filled with the array filler expression.
@@ -1000,7 +1006,7 @@
// Advance to the next element by adjusting the pointer type as necessary.
llvm::Value *NextPtr =
- Builder.CreateConstInBoundsGEP1_32(CurPtr, 1, "array.next");
+ Builder.CreateConstInBoundsGEP1_32(ElementTy, CurPtr, 1, "array.next");
// Check whether we've gotten to the end of the array and, if so,
// exit the loop.
@@ -1012,13 +1018,12 @@
}
static void EmitNewInitializer(CodeGenFunction &CGF, const CXXNewExpr *E,
- QualType ElementType,
- llvm::Value *NewPtr,
- llvm::Value *NumElements,
+ QualType ElementType, llvm::Type *ElementTy,
+ llvm::Value *NewPtr, llvm::Value *NumElements,
llvm::Value *AllocSizeWithoutCookie) {
ApplyDebugLocation DL(CGF, E);
if (E->isArray())
- CGF.EmitNewArrayInitializer(E, ElementType, NewPtr, NumElements,
+ CGF.EmitNewArrayInitializer(E, ElementType, ElementTy, NewPtr, NumElements,
AllocSizeWithoutCookie);
else if (const Expr *Init = E->getInitializer())
StoreAnyExprIntoOneUnit(CGF, Init, E->getAllocatedType(), NewPtr);
@@ -1326,11 +1331,11 @@
E, allocType);
}
- llvm::Type *elementPtrTy
- = ConvertTypeForMem(allocType)->getPointerTo(AS);
+ llvm::Type *elementTy = ConvertTypeForMem(allocType);
+ llvm::Type *elementPtrTy = elementTy->getPointerTo(AS);
llvm::Value *result = Builder.CreateBitCast(allocation, elementPtrTy);
- EmitNewInitializer(*this, E, allocType, result, numElements,
+ EmitNewInitializer(*this, E, allocType, elementTy, result, numElements,
allocSizeWithoutCookie);
if (E->isArray()) {
// NewPtr is a pointer to the base element type. If we're
diff --git a/lib/CodeGen/CGExprComplex.cpp b/lib/CodeGen/CGExprComplex.cpp
index b2228f0..dead1b5 100644
--- a/lib/CodeGen/CGExprComplex.cpp
+++ b/lib/CodeGen/CGExprComplex.cpp
@@ -317,14 +317,14 @@
llvm::Value *Real=nullptr, *Imag=nullptr;
if (!IgnoreReal || isVolatile) {
- llvm::Value *RealP = Builder.CreateStructGEP(SrcPtr, 0,
+ llvm::Value *RealP = Builder.CreateStructGEP(nullptr, SrcPtr, 0,
SrcPtr->getName() + ".realp");
Real = Builder.CreateAlignedLoad(RealP, AlignR, isVolatile,
SrcPtr->getName() + ".real");
}
if (!IgnoreImag || isVolatile) {
- llvm::Value *ImagP = Builder.CreateStructGEP(SrcPtr, 1,
+ llvm::Value *ImagP = Builder.CreateStructGEP(nullptr, SrcPtr, 1,
SrcPtr->getName() + ".imagp");
Imag = Builder.CreateAlignedLoad(ImagP, AlignI, isVolatile,
SrcPtr->getName() + ".imag");
@@ -341,8 +341,8 @@
return CGF.EmitAtomicStore(RValue::getComplex(Val), lvalue, isInit);
llvm::Value *Ptr = lvalue.getAddress();
- llvm::Value *RealPtr = Builder.CreateStructGEP(Ptr, 0, "real");
- llvm::Value *ImagPtr = Builder.CreateStructGEP(Ptr, 1, "imag");
+ llvm::Value *RealPtr = Builder.CreateStructGEP(nullptr, Ptr, 0, "real");
+ llvm::Value *ImagPtr = Builder.CreateStructGEP(nullptr, Ptr, 1, "imag");
unsigned AlignR = lvalue.getAlignment().getQuantity();
ASTContext &C = CGF.getContext();
QualType ComplexTy = lvalue.getType();
diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp
index 7406354..b1cf99c 100644
--- a/lib/CodeGen/CGExprConstant.cpp
+++ b/lib/CodeGen/CGExprConstant.cpp
@@ -1115,7 +1115,7 @@
unsigned AS = C->getType()->getPointerAddressSpace();
llvm::Type *CharPtrTy = Int8Ty->getPointerTo(AS);
llvm::Constant *Casted = llvm::ConstantExpr::getBitCast(C, CharPtrTy);
- Casted = llvm::ConstantExpr::getGetElementPtr(Casted, Offset);
+ Casted = llvm::ConstantExpr::getGetElementPtr(Int8Ty, Casted, Offset);
C = llvm::ConstantExpr::getPointerCast(Casted, C->getType());
}
diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
index 16ce69d..658bd3e 100644
--- a/lib/CodeGen/CGExprScalar.cpp
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -1451,13 +1451,13 @@
// anything here.
if (!E->getType()->isVariableArrayType()) {
assert(isa<llvm::PointerType>(V->getType()) && "Expected pointer");
+ llvm::Type *NewTy = ConvertType(E->getType());
V = CGF.Builder.CreatePointerCast(
- V, ConvertType(E->getType())->getPointerTo(
- V->getType()->getPointerAddressSpace()));
+ V, NewTy->getPointerTo(V->getType()->getPointerAddressSpace()));
assert(isa<llvm::ArrayType>(V->getType()->getPointerElementType()) &&
"Expected pointer to array");
- V = Builder.CreateStructGEP(V, 0, "arraydecay");
+ V = Builder.CreateStructGEP(NewTy, V, 0, "arraydecay");
}
// Make sure the array decay ends up being the right type. This matters if
@@ -1845,10 +1845,9 @@
llvm::BasicBlock *opBB = Builder.GetInsertBlock();
llvm::BasicBlock *contBB = CGF.createBasicBlock("atomic_cont", CGF.CurFn);
auto Pair = CGF.EmitAtomicCompareExchange(
- LV, RValue::get(atomicPHI), RValue::get(CGF.EmitToMemory(value, type)),
- E->getExprLoc());
- llvm::Value *old = Pair.first.getScalarVal();
- llvm::Value *success = Pair.second.getScalarVal();
+ LV, RValue::get(atomicPHI), RValue::get(value), E->getExprLoc());
+ llvm::Value *old = CGF.EmitToMemory(Pair.first.getScalarVal(), type);
+ llvm::Value *success = Pair.second;
atomicPHI->addIncoming(old, opBB);
Builder.CreateCondBr(success, contBB, opBB);
Builder.SetInsertPoint(contBB);
@@ -2189,10 +2188,9 @@
llvm::BasicBlock *opBB = Builder.GetInsertBlock();
llvm::BasicBlock *contBB = CGF.createBasicBlock("atomic_cont", CGF.CurFn);
auto Pair = CGF.EmitAtomicCompareExchange(
- LHSLV, RValue::get(atomicPHI),
- RValue::get(CGF.EmitToMemory(Result, LHSTy)), E->getExprLoc());
- llvm::Value *old = Pair.first.getScalarVal();
- llvm::Value *success = Pair.second.getScalarVal();
+ LHSLV, RValue::get(atomicPHI), RValue::get(Result), E->getExprLoc());
+ llvm::Value *old = CGF.EmitToMemory(Pair.first.getScalarVal(), LHSTy);
+ llvm::Value *success = Pair.second;
atomicPHI->addIncoming(old, opBB);
Builder.CreateCondBr(success, contBB, opBB);
Builder.SetInsertPoint(contBB);
diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp
index 19f5ca2..dfad13a 100644
--- a/lib/CodeGen/CGObjC.cpp
+++ b/lib/CodeGen/CGObjC.cpp
@@ -102,8 +102,8 @@
ArrayType::Normal, /*IndexTypeQuals=*/0);
// Allocate the temporary array(s).
- llvm::Value *Objects = CreateMemTemp(ElementArrayType, "objects");
- llvm::Value *Keys = nullptr;
+ llvm::AllocaInst *Objects = CreateMemTemp(ElementArrayType, "objects");
+ llvm::AllocaInst *Keys = nullptr;
if (DLE)
Keys = CreateMemTemp(ElementArrayType, "keys");
@@ -119,10 +119,9 @@
if (ALE) {
// Emit the element and store it to the appropriate array slot.
const Expr *Rhs = ALE->getElement(i);
- LValue LV = LValue::MakeAddr(Builder.CreateStructGEP(Objects, i),
- ElementType,
- Context.getTypeAlignInChars(Rhs->getType()),
- Context);
+ LValue LV = LValue::MakeAddr(
+ Builder.CreateStructGEP(Objects->getAllocatedType(), Objects, i),
+ ElementType, Context.getTypeAlignInChars(Rhs->getType()), Context);
llvm::Value *value = EmitScalarExpr(Rhs);
EmitStoreThroughLValue(RValue::get(value), LV, true);
@@ -132,19 +131,17 @@
} else {
// Emit the key and store it to the appropriate array slot.
const Expr *Key = DLE->getKeyValueElement(i).Key;
- LValue KeyLV = LValue::MakeAddr(Builder.CreateStructGEP(Keys, i),
- ElementType,
- Context.getTypeAlignInChars(Key->getType()),
- Context);
+ LValue KeyLV = LValue::MakeAddr(
+ Builder.CreateStructGEP(Keys->getAllocatedType(), Keys, i),
+ ElementType, Context.getTypeAlignInChars(Key->getType()), Context);
llvm::Value *keyValue = EmitScalarExpr(Key);
EmitStoreThroughLValue(RValue::get(keyValue), KeyLV, /*isInit=*/true);
// Emit the value and store it to the appropriate array slot.
- const Expr *Value = DLE->getKeyValueElement(i).Value;
- LValue ValueLV = LValue::MakeAddr(Builder.CreateStructGEP(Objects, i),
- ElementType,
- Context.getTypeAlignInChars(Value->getType()),
- Context);
+ const Expr *Value = DLE->getKeyValueElement(i).Value;
+ LValue ValueLV = LValue::MakeAddr(
+ Builder.CreateStructGEP(Objects->getAllocatedType(), Objects, i),
+ ElementType, Context.getTypeAlignInChars(Value->getType()), Context);
llvm::Value *valueValue = EmitScalarExpr(Value);
EmitStoreThroughLValue(RValue::get(valueValue), ValueLV, /*isInit=*/true);
if (TrackNeededObjects) {
@@ -1434,7 +1431,7 @@
// Fast enumeration state.
QualType StateTy = CGM.getObjCFastEnumerationStateType();
- llvm::Value *StatePtr = CreateMemTemp(StateTy, "state.ptr");
+ llvm::AllocaInst *StatePtr = CreateMemTemp(StateTy, "state.ptr");
EmitNullInitialization(StatePtr, StateTy);
// Number of elements in the items array.
@@ -1518,8 +1515,8 @@
// Save the initial mutations value. This is the value at an
// address that was written into the state object by
// countByEnumeratingWithState:objects:count:.
- llvm::Value *StateMutationsPtrPtr =
- Builder.CreateStructGEP(StatePtr, 2, "mutationsptr.ptr");
+ llvm::Value *StateMutationsPtrPtr = Builder.CreateStructGEP(
+ StatePtr->getAllocatedType(), StatePtr, 2, "mutationsptr.ptr");
llvm::Value *StateMutationsPtr = Builder.CreateLoad(StateMutationsPtrPtr,
"mutationsptr");
@@ -1599,8 +1596,8 @@
// Fetch the buffer out of the enumeration state.
// TODO: this pointer should actually be invariant between
// refreshes, which would help us do certain loop optimizations.
- llvm::Value *StateItemsPtr =
- Builder.CreateStructGEP(StatePtr, 1, "stateitems.ptr");
+ llvm::Value *StateItemsPtr = Builder.CreateStructGEP(
+ StatePtr->getAllocatedType(), StatePtr, 1, "stateitems.ptr");
llvm::Value *EnumStateItems =
Builder.CreateLoad(StateItemsPtr, "stateitems");
diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp
index da95260..981fe90 100644
--- a/lib/CodeGen/CGObjCGNU.cpp
+++ b/lib/CodeGen/CGObjCGNU.cpp
@@ -171,8 +171,9 @@
/// where the C code specifies const char*.
llvm::Constant *MakeConstantString(const std::string &Str,
const std::string &Name="") {
- llvm::Constant *ConstStr = CGM.GetAddrOfConstantCString(Str, Name.c_str());
- return llvm::ConstantExpr::getGetElementPtr(ConstStr, Zeros);
+ auto *ConstStr = CGM.GetAddrOfConstantCString(Str, Name.c_str());
+ return llvm::ConstantExpr::getGetElementPtr(ConstStr->getValueType(),
+ ConstStr, Zeros);
}
/// Emits a linkonce_odr string, whose name is the prefix followed by the
/// string value. This allows the linker to combine the strings between
@@ -181,13 +182,14 @@
llvm::Constant *ExportUniqueString(const std::string &Str,
const std::string prefix) {
std::string name = prefix + Str;
- llvm::Constant *ConstStr = TheModule.getGlobalVariable(name);
+ auto *ConstStr = TheModule.getGlobalVariable(name);
if (!ConstStr) {
llvm::Constant *value = llvm::ConstantDataArray::getString(VMContext,Str);
ConstStr = new llvm::GlobalVariable(TheModule, value->getType(), true,
llvm::GlobalValue::LinkOnceODRLinkage, value, prefix + Str);
}
- return llvm::ConstantExpr::getGetElementPtr(ConstStr, Zeros);
+ return llvm::ConstantExpr::getGetElementPtr(ConstStr->getValueType(),
+ ConstStr, Zeros);
}
/// Generates a global structure, initialized by the elements in the vector.
/// The element types must match the types of the structure elements in the
@@ -237,8 +239,9 @@
NameAndAttributes += TypeStr;
NameAndAttributes += '\0';
NameAndAttributes += PD->getNameAsString();
- return llvm::ConstantExpr::getGetElementPtr(
- CGM.GetAddrOfConstantCString(NameAndAttributes), Zeros);
+ auto *ConstStr = CGM.GetAddrOfConstantCString(NameAndAttributes);
+ return llvm::ConstantExpr::getGetElementPtr(ConstStr->getValueType(),
+ ConstStr, Zeros);
}
return MakeConstantString(PD->getNameAsString());
}
@@ -672,8 +675,8 @@
slot->setMetadata(msgSendMDKind, node);
// Load the imp from the slot
- llvm::Value *imp =
- Builder.CreateLoad(Builder.CreateStructGEP(slot.getInstruction(), 4));
+ llvm::Value *imp = Builder.CreateLoad(
+ Builder.CreateStructGEP(nullptr, slot.getInstruction(), 4));
// The lookup function may have changed the receiver, so make sure we use
// the new one.
@@ -690,7 +693,7 @@
CGF.EmitNounwindRuntimeCall(SlotLookupSuperFn, lookupArgs);
slot->setOnlyReadsMemory();
- return Builder.CreateLoad(Builder.CreateStructGEP(slot, 4));
+ return Builder.CreateLoad(Builder.CreateStructGEP(nullptr, slot, 4));
}
public:
CGObjCGNUstep(CodeGenModule &Mod) : CGObjCGNU(Mod, 9, 3) {
@@ -1013,7 +1016,7 @@
llvm::Value *CGObjCGNU::GetClassNamed(CodeGenFunction &CGF,
const std::string &Name,
bool isWeak) {
- llvm::Value *ClassName = CGM.GetAddrOfConstantCString(Name);
+ llvm::GlobalVariable *ClassNameGV = CGM.GetAddrOfConstantCString(Name);
// With the incompatible ABI, this will need to be replaced with a direct
// reference to the class symbol. For the compatible nonfragile ABI we are
// still performing this lookup at run time but emitting the symbol for the
@@ -1023,7 +1026,8 @@
// with memoized versions or with static references if it's safe to do so.
if (!isWeak)
EmitClassRef(Name);
- ClassName = CGF.Builder.CreateStructGEP(ClassName, 0);
+ llvm::Value *ClassName =
+ CGF.Builder.CreateStructGEP(ClassNameGV->getValueType(), ClassNameGV, 0);
llvm::Constant *ClassLookupFn =
CGM.CreateRuntimeFunction(llvm::FunctionType::get(IdTy, PtrToInt8Ty, true),
@@ -1143,21 +1147,22 @@
// It's quite ugly hard-coding this. Ideally we'd generate it using the host
// platform's name mangling.
const char *vtableName = "_ZTVN7gnustep7libobjc22__objc_class_type_infoE";
- llvm::Constant *Vtable = TheModule.getGlobalVariable(vtableName);
+ auto *Vtable = TheModule.getGlobalVariable(vtableName);
if (!Vtable) {
Vtable = new llvm::GlobalVariable(TheModule, PtrToInt8Ty, true,
llvm::GlobalValue::ExternalLinkage,
nullptr, vtableName);
}
llvm::Constant *Two = llvm::ConstantInt::get(IntTy, 2);
- Vtable = llvm::ConstantExpr::getGetElementPtr(Vtable, Two);
- Vtable = llvm::ConstantExpr::getBitCast(Vtable, PtrToInt8Ty);
+ auto *BVtable = llvm::ConstantExpr::getBitCast(
+ llvm::ConstantExpr::getGetElementPtr(Vtable->getValueType(), Vtable, Two),
+ PtrToInt8Ty);
llvm::Constant *typeName =
ExportUniqueString(className, "__objc_eh_typename_");
std::vector<llvm::Constant*> fields;
- fields.push_back(Vtable);
+ fields.push_back(BVtable);
fields.push_back(typeName);
llvm::Constant *TI =
MakeGlobal(llvm::StructType::get(PtrToInt8Ty, PtrToInt8Ty,
@@ -1275,11 +1280,11 @@
}
}
// Cast the pointer to a simplified version of the class structure
+ llvm::Type *CastTy = llvm::StructType::get(IdTy, IdTy, nullptr);
ReceiverClass = Builder.CreateBitCast(ReceiverClass,
- llvm::PointerType::getUnqual(
- llvm::StructType::get(IdTy, IdTy, nullptr)));
+ llvm::PointerType::getUnqual(CastTy));
// Get the superclass pointer
- ReceiverClass = Builder.CreateStructGEP(ReceiverClass, 1);
+ ReceiverClass = Builder.CreateStructGEP(CastTy, ReceiverClass, 1);
// Load the superclass pointer
ReceiverClass = Builder.CreateLoad(ReceiverClass);
// Construct the structure used to look up the IMP
@@ -1287,8 +1292,10 @@
Receiver->getType(), IdTy, nullptr);
llvm::Value *ObjCSuper = Builder.CreateAlloca(ObjCSuperTy);
- Builder.CreateStore(Receiver, Builder.CreateStructGEP(ObjCSuper, 0));
- Builder.CreateStore(ReceiverClass, Builder.CreateStructGEP(ObjCSuper, 1));
+ Builder.CreateStore(Receiver,
+ Builder.CreateStructGEP(ObjCSuperTy, ObjCSuper, 0));
+ Builder.CreateStore(ReceiverClass,
+ Builder.CreateStructGEP(ObjCSuperTy, ObjCSuper, 1));
ObjCSuper = EnforceType(Builder, ObjCSuper, PtrToObjCSuperTy);
@@ -2294,7 +2301,8 @@
offsetPointerIndexes[2] = llvm::ConstantInt::get(IndexTy, ivarIndex);
// Get the correct ivar field
llvm::Constant *offsetValue = llvm::ConstantExpr::getGetElementPtr(
- IvarList, offsetPointerIndexes);
+ cast<llvm::GlobalVariable>(IvarList)->getValueType(), IvarList,
+ offsetPointerIndexes);
// Get the existing variable, if one exists.
llvm::GlobalVariable *offset = TheModule.getNamedGlobal(Name);
if (offset) {
@@ -2439,8 +2447,8 @@
// Number of static selectors
Elements.push_back(llvm::ConstantInt::get(LongTy, SelectorCount));
- llvm::Constant *SelectorList = MakeGlobalArray(SelStructTy, Selectors,
- ".objc_selector_list");
+ llvm::GlobalVariable *SelectorList =
+ MakeGlobalArray(SelStructTy, Selectors, ".objc_selector_list");
Elements.push_back(llvm::ConstantExpr::getBitCast(SelectorList,
SelStructPtrTy));
@@ -2450,8 +2458,8 @@
llvm::Constant *Idxs[] = {Zeros[0],
llvm::ConstantInt::get(Int32Ty, i), Zeros[0]};
// FIXME: We're generating redundant loads and stores here!
- llvm::Constant *SelPtr = llvm::ConstantExpr::getGetElementPtr(SelectorList,
- makeArrayRef(Idxs, 2));
+ llvm::Constant *SelPtr = llvm::ConstantExpr::getGetElementPtr(
+ SelectorList->getValueType(), SelectorList, makeArrayRef(Idxs, 2));
// If selectors are defined as an opaque type, cast the pointer to this
// type.
SelPtr = llvm::ConstantExpr::getBitCast(SelPtr, SelectorTy);
diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp
index b9fdf73..a45446a 100644
--- a/lib/CodeGen/CGObjCMac.cpp
+++ b/lib/CodeGen/CGObjCMac.cpp
@@ -486,7 +486,6 @@
}
ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm);
- ~ObjCCommonTypesHelper(){}
};
/// ObjCTypesHelper - Helper class that encapsulates lazy
@@ -595,7 +594,6 @@
public:
ObjCTypesHelper(CodeGen::CodeGenModule &cgm);
- ~ObjCTypesHelper() {}
};
/// ObjCNonFragileABITypesHelper - will have all types needed by objective-c's
@@ -733,7 +731,6 @@
llvm::Type *EHTypePtrTy;
ObjCNonFragileABITypesHelper(CodeGen::CodeGenModule &cgm);
- ~ObjCNonFragileABITypesHelper(){}
};
class CGObjCCommonMac : public CodeGen::CGObjCRuntime {
@@ -1678,14 +1675,13 @@
/// getConstantGEP() - Help routine to construct simple GEPs.
static llvm::Constant *getConstantGEP(llvm::LLVMContext &VMContext,
- llvm::Constant *C,
- unsigned idx0,
+ llvm::GlobalVariable *C, unsigned idx0,
unsigned idx1) {
llvm::Value *Idxs[] = {
llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), idx0),
llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), idx1)
};
- return llvm::ConstantExpr::getGetElementPtr(C, Idxs);
+ return llvm::ConstantExpr::getGetElementPtr(C->getValueType(), C, Idxs);
}
/// hasObjCExceptionAttribute - Return true if this class or any super
@@ -1791,8 +1787,9 @@
CGF.CreateTempAlloca(ObjCTypes.SuperTy, "objc_super");
llvm::Value *ReceiverAsObject =
CGF.Builder.CreateBitCast(Receiver, ObjCTypes.ObjectPtrTy);
- CGF.Builder.CreateStore(ReceiverAsObject,
- CGF.Builder.CreateStructGEP(ObjCSuper, 0));
+ CGF.Builder.CreateStore(
+ ReceiverAsObject,
+ CGF.Builder.CreateStructGEP(ObjCTypes.SuperTy, ObjCSuper, 0));
// If this is a class message the metaclass is passed as the target.
llvm::Value *Target;
@@ -1805,20 +1802,20 @@
// the class's "isa" pointer. The following assumes that
// isa" is the first ivar in a class (which it must be).
Target = EmitClassRef(CGF, Class->getSuperClass());
- Target = CGF.Builder.CreateStructGEP(Target, 0);
+ Target = CGF.Builder.CreateStructGEP(ObjCTypes.ClassTy, Target, 0);
Target = CGF.Builder.CreateLoad(Target);
} else {
- llvm::Value *MetaClassPtr = EmitMetaClassRef(Class);
- llvm::Value *SuperPtr = CGF.Builder.CreateStructGEP(MetaClassPtr, 1);
+ llvm::Constant *MetaClassPtr = EmitMetaClassRef(Class);
+ llvm::Value *SuperPtr =
+ CGF.Builder.CreateStructGEP(ObjCTypes.ClassTy, MetaClassPtr, 1);
llvm::Value *Super = CGF.Builder.CreateLoad(SuperPtr);
Target = Super;
}
- }
- else if (isCategoryImpl)
+ } else if (isCategoryImpl)
Target = EmitClassRef(CGF, Class->getSuperClass());
else {
llvm::Value *ClassPtr = EmitSuperClassRef(Class);
- ClassPtr = CGF.Builder.CreateStructGEP(ClassPtr, 1);
+ ClassPtr = CGF.Builder.CreateStructGEP(ObjCTypes.ClassTy, ClassPtr, 1);
Target = CGF.Builder.CreateLoad(ClassPtr);
}
// FIXME: We shouldn't need to do this cast, rectify the ASTContext and
@@ -1826,8 +1823,8 @@
llvm::Type *ClassTy =
CGM.getTypes().ConvertType(CGF.getContext().getObjCClassType());
Target = CGF.Builder.CreateBitCast(Target, ClassTy);
- CGF.Builder.CreateStore(Target,
- CGF.Builder.CreateStructGEP(ObjCSuper, 1));
+ CGF.Builder.CreateStore(
+ Target, CGF.Builder.CreateStructGEP(ObjCTypes.SuperTy, ObjCSuper, 1));
return EmitMessageSend(CGF, Return, ResultType,
EmitSelector(CGF, Sel),
ObjCSuper, ObjCTypes.SuperPtrCTy,
@@ -3816,8 +3813,8 @@
// - Call setjmp on the exception data buffer.
llvm::Constant *Zero = llvm::ConstantInt::get(CGF.Builder.getInt32Ty(), 0);
llvm::Value *GEPIndexes[] = { Zero, Zero, Zero };
- llvm::Value *SetJmpBuffer =
- CGF.Builder.CreateGEP(ExceptionData, GEPIndexes, "setjmp_buffer");
+ llvm::Value *SetJmpBuffer = CGF.Builder.CreateGEP(
+ ObjCTypes.ExceptionDataTy, ExceptionData, GEPIndexes, "setjmp_buffer");
llvm::CallInst *SetJmpResult = CGF.EmitNounwindRuntimeCall(
ObjCTypes.getSetJmpFn(), SetJmpBuffer, "setjmp_result");
SetJmpResult->setCanReturnTwice();
@@ -5264,6 +5261,7 @@
// const uint32_t size; // sizeof(struct _protocol_t)
// const uint32_t flags; // = 0
// const char ** extendedMethodTypes;
+ // const char *demangledName;
// }
// Holder for struct _protocol_list_t *
@@ -5276,6 +5274,7 @@
MethodListnfABIPtrTy, MethodListnfABIPtrTy,
MethodListnfABIPtrTy, MethodListnfABIPtrTy,
PropertyListPtrTy, IntTy, IntTy, Int8PtrPtrTy,
+ Int8PtrTy,
nullptr);
// struct _protocol_t*
@@ -6208,6 +6207,7 @@
/// const uint32_t size; // sizeof(struct _protocol_t)
/// const uint32_t flags; // = 0
/// const char ** extendedMethodTypes;
+/// const char *demangledName;
/// }
/// @endcode
///
@@ -6259,7 +6259,7 @@
MethodTypesExt.insert(MethodTypesExt.end(),
OptMethodTypesExt.begin(), OptMethodTypesExt.end());
- llvm::Constant *Values[11];
+ llvm::Constant *Values[12];
// isa is NULL
Values[0] = llvm::Constant::getNullValue(ObjCTypes.ObjectPtrTy);
Values[1] = GetClassName(PD->getObjCRuntimeNameAsString());
@@ -6292,6 +6292,9 @@
Values[10] = EmitProtocolMethodTypes("\01l_OBJC_$_PROTOCOL_METHOD_TYPES_"
+ PD->getObjCRuntimeNameAsString(),
MethodTypesExt, ObjCTypes);
+ // const char *demangledName;
+ Values[11] = llvm::Constant::getNullValue(ObjCTypes.Int8PtrTy);
+
llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ProtocolnfABITy,
Values);
@@ -6563,7 +6566,8 @@
args[1].RV = RValue::get(mref);
// Load the function to call from the message ref table.
- llvm::Value *callee = CGF.Builder.CreateStructGEP(mref, 0);
+ llvm::Value *callee =
+ CGF.Builder.CreateStructGEP(ObjCTypes.MessageRefTy, mref, 0);
callee = CGF.Builder.CreateLoad(callee, "msgSend_fn");
callee = CGF.Builder.CreateBitCast(callee, MSI.MessengerType);
@@ -6728,8 +6732,9 @@
llvm::Value *ReceiverAsObject =
CGF.Builder.CreateBitCast(Receiver, ObjCTypes.ObjectPtrTy);
- CGF.Builder.CreateStore(ReceiverAsObject,
- CGF.Builder.CreateStructGEP(ObjCSuper, 0));
+ CGF.Builder.CreateStore(
+ ReceiverAsObject,
+ CGF.Builder.CreateStructGEP(ObjCTypes.SuperTy, ObjCSuper, 0));
// If this is a class message the metaclass is passed as the target.
llvm::Value *Target;
@@ -6743,8 +6748,8 @@
llvm::Type *ClassTy =
CGM.getTypes().ConvertType(CGF.getContext().getObjCClassType());
Target = CGF.Builder.CreateBitCast(Target, ClassTy);
- CGF.Builder.CreateStore(Target,
- CGF.Builder.CreateStructGEP(ObjCSuper, 1));
+ CGF.Builder.CreateStore(
+ Target, CGF.Builder.CreateStructGEP(ObjCTypes.SuperTy, ObjCSuper, 1));
return (isVTableDispatchedSelector(Sel))
? EmitVTableMessageSend(CGF, Return, ResultType, Sel,
@@ -6993,10 +6998,10 @@
llvm::Value *VTableIdx = llvm::ConstantInt::get(CGM.Int32Ty, 2);
llvm::Constant *Values[] = {
- llvm::ConstantExpr::getGetElementPtr(VTableGV, VTableIdx),
- GetClassName(ID->getObjCRuntimeNameAsString()),
- GetClassGlobal(ClassName.str())
- };
+ llvm::ConstantExpr::getGetElementPtr(VTableGV->getValueType(), VTableGV,
+ VTableIdx),
+ GetClassName(ID->getObjCRuntimeNameAsString()),
+ GetClassGlobal(ClassName.str())};
llvm::Constant *Init =
llvm::ConstantStruct::get(ObjCTypes.EHTypeTy, Values);
diff --git a/lib/CodeGen/CGOpenMPRuntime.cpp b/lib/CodeGen/CGOpenMPRuntime.cpp
index ef2d214..5988c78 100644
--- a/lib/CodeGen/CGOpenMPRuntime.cpp
+++ b/lib/CodeGen/CGOpenMPRuntime.cpp
@@ -31,47 +31,73 @@
/// \brief Base class for handling code generation inside OpenMP regions.
class CGOpenMPRegionInfo : public CodeGenFunction::CGCapturedStmtInfo {
public:
- CGOpenMPRegionInfo(const OMPExecutableDirective &D, const CapturedStmt &CS)
- : CGCapturedStmtInfo(CS, CR_OpenMP), Directive(D) {}
+ /// \brief Kinds of OpenMP regions used in codegen.
+ enum CGOpenMPRegionKind {
+ /// \brief Region with outlined function for standalone 'parallel'
+ /// directive.
+ ParallelOutlinedRegion,
+ /// \brief Region with outlined function for standalone 'task' directive.
+ TaskOutlinedRegion,
+ /// \brief Region for constructs that do not require function outlining,
+ /// like 'for', 'sections', 'atomic' etc. directives.
+ InlinedRegion,
+ };
- CGOpenMPRegionInfo(const OMPExecutableDirective &D)
- : CGCapturedStmtInfo(CR_OpenMP), Directive(D) {}
+ CGOpenMPRegionInfo(const CapturedStmt &CS,
+ const CGOpenMPRegionKind RegionKind,
+ const RegionCodeGenTy &CodeGen)
+ : CGCapturedStmtInfo(CS, CR_OpenMP), RegionKind(RegionKind),
+ CodeGen(CodeGen) {}
+
+ CGOpenMPRegionInfo(const CGOpenMPRegionKind RegionKind,
+ const RegionCodeGenTy &CodeGen)
+ : CGCapturedStmtInfo(CR_OpenMP), RegionKind(RegionKind),
+ CodeGen(CodeGen) {}
/// \brief Get a variable or parameter for storing global thread id
/// inside OpenMP construct.
virtual const VarDecl *getThreadIDVariable() const = 0;
+ /// \brief Emit the captured statement body.
+ virtual void EmitBody(CodeGenFunction &CGF, const Stmt *S) override;
+
/// \brief Get an LValue for the current ThreadID variable.
/// \return LValue for thread id variable. This LValue always has type int32*.
virtual LValue getThreadIDVariableLValue(CodeGenFunction &CGF);
- /// \brief Emit the captured statement body.
- virtual void EmitBody(CodeGenFunction &CGF, const Stmt *S) override;
+ CGOpenMPRegionKind getRegionKind() const { return RegionKind; }
static bool classof(const CGCapturedStmtInfo *Info) {
return Info->getKind() == CR_OpenMP;
}
+
protected:
- /// \brief OpenMP executable directive associated with the region.
- const OMPExecutableDirective &Directive;
+ CGOpenMPRegionKind RegionKind;
+ const RegionCodeGenTy &CodeGen;
};
/// \brief API for captured statement code generation in OpenMP constructs.
class CGOpenMPOutlinedRegionInfo : public CGOpenMPRegionInfo {
public:
- CGOpenMPOutlinedRegionInfo(const OMPExecutableDirective &D,
- const CapturedStmt &CS, const VarDecl *ThreadIDVar)
- : CGOpenMPRegionInfo(D, CS), ThreadIDVar(ThreadIDVar) {
+ CGOpenMPOutlinedRegionInfo(const CapturedStmt &CS, const VarDecl *ThreadIDVar,
+ const RegionCodeGenTy &CodeGen)
+ : CGOpenMPRegionInfo(CS, ParallelOutlinedRegion, CodeGen),
+ ThreadIDVar(ThreadIDVar) {
assert(ThreadIDVar != nullptr && "No ThreadID in OpenMP region.");
}
/// \brief Get a variable or parameter for storing global thread id
/// inside OpenMP construct.
- virtual const VarDecl *getThreadIDVariable() const override {
- return ThreadIDVar;
- }
+ const VarDecl *getThreadIDVariable() const override { return ThreadIDVar; }
+
/// \brief Get the name of the capture helper.
StringRef getHelperName() const override { return ".omp_outlined."; }
+ static bool classof(const CGCapturedStmtInfo *Info) {
+ return CGOpenMPRegionInfo::classof(Info) &&
+ cast<CGOpenMPRegionInfo>(Info)->getRegionKind() ==
+ ParallelOutlinedRegion;
+ }
+
private:
/// \brief A variable or parameter storing global thread id for OpenMP
/// constructs.
@@ -81,84 +107,121 @@
/// \brief API for captured statement code generation in OpenMP constructs.
class CGOpenMPTaskOutlinedRegionInfo : public CGOpenMPRegionInfo {
public:
- CGOpenMPTaskOutlinedRegionInfo(const OMPExecutableDirective &D,
- const CapturedStmt &CS,
+ CGOpenMPTaskOutlinedRegionInfo(const CapturedStmt &CS,
const VarDecl *ThreadIDVar,
- const VarDecl *PartIDVar)
- : CGOpenMPRegionInfo(D, CS), ThreadIDVar(ThreadIDVar),
- PartIDVar(PartIDVar) {
+ const RegionCodeGenTy &CodeGen)
+ : CGOpenMPRegionInfo(CS, TaskOutlinedRegion, CodeGen),
+ ThreadIDVar(ThreadIDVar) {
assert(ThreadIDVar != nullptr && "No ThreadID in OpenMP region.");
}
/// \brief Get a variable or parameter for storing global thread id
/// inside OpenMP construct.
- virtual const VarDecl *getThreadIDVariable() const override {
- return ThreadIDVar;
- }
+ const VarDecl *getThreadIDVariable() const override { return ThreadIDVar; }
/// \brief Get an LValue for the current ThreadID variable.
- virtual LValue getThreadIDVariableLValue(CodeGenFunction &CGF) override;
-
- /// \brief Emit the captured statement body.
- virtual void EmitBody(CodeGenFunction &CGF, const Stmt *S) override;
+ LValue getThreadIDVariableLValue(CodeGenFunction &CGF) override;
/// \brief Get the name of the capture helper.
StringRef getHelperName() const override { return ".omp_outlined."; }
+ static bool classof(const CGCapturedStmtInfo *Info) {
+ return CGOpenMPRegionInfo::classof(Info) &&
+ cast<CGOpenMPRegionInfo>(Info)->getRegionKind() ==
+ TaskOutlinedRegion;
+ }
+
private:
/// \brief A variable or parameter storing global thread id for OpenMP
/// constructs.
const VarDecl *ThreadIDVar;
- /// \brief A variable or parameter storing part id for OpenMP tasking
- /// constructs.
- const VarDecl *PartIDVar;
};
/// \brief API for inlined captured statement code generation in OpenMP
/// constructs.
class CGOpenMPInlinedRegionInfo : public CGOpenMPRegionInfo {
public:
- CGOpenMPInlinedRegionInfo(const OMPExecutableDirective &D,
- CodeGenFunction::CGCapturedStmtInfo *OldCSI)
- : CGOpenMPRegionInfo(D), OldCSI(OldCSI),
+ CGOpenMPInlinedRegionInfo(CodeGenFunction::CGCapturedStmtInfo *OldCSI,
+ const RegionCodeGenTy &CodeGen)
+ : CGOpenMPRegionInfo(InlinedRegion, CodeGen), OldCSI(OldCSI),
OuterRegionInfo(dyn_cast_or_null<CGOpenMPRegionInfo>(OldCSI)) {}
// \brief Retrieve the value of the context parameter.
- virtual llvm::Value *getContextValue() const override {
+ llvm::Value *getContextValue() const override {
if (OuterRegionInfo)
return OuterRegionInfo->getContextValue();
llvm_unreachable("No context value for inlined OpenMP region");
}
+ virtual void setContextValue(llvm::Value *V) override {
+ if (OuterRegionInfo) {
+ OuterRegionInfo->setContextValue(V);
+ return;
+ }
+ llvm_unreachable("No context value for inlined OpenMP region");
+ }
/// \brief Lookup the captured field decl for a variable.
- virtual const FieldDecl *lookup(const VarDecl *VD) const override {
+ const FieldDecl *lookup(const VarDecl *VD) const override {
if (OuterRegionInfo)
return OuterRegionInfo->lookup(VD);
- llvm_unreachable("Trying to reference VarDecl that is neither local nor "
- "captured in outer OpenMP region");
+ // If there is no outer outlined region,no need to lookup in a list of
+ // captured variables, we can use the original one.
+ return nullptr;
}
- virtual FieldDecl *getThisFieldDecl() const override {
+ FieldDecl *getThisFieldDecl() const override {
if (OuterRegionInfo)
return OuterRegionInfo->getThisFieldDecl();
return nullptr;
}
/// \brief Get a variable or parameter for storing global thread id
/// inside OpenMP construct.
- virtual const VarDecl *getThreadIDVariable() const override {
+ const VarDecl *getThreadIDVariable() const override {
if (OuterRegionInfo)
return OuterRegionInfo->getThreadIDVariable();
return nullptr;
}
/// \brief Get the name of the capture helper.
- virtual StringRef getHelperName() const override {
+ StringRef getHelperName() const override {
+ if (auto *OuterRegionInfo = getOldCSI())
+ return OuterRegionInfo->getHelperName();
llvm_unreachable("No helper name for inlined OpenMP construct");
}
CodeGenFunction::CGCapturedStmtInfo *getOldCSI() const { return OldCSI; }
+ static bool classof(const CGCapturedStmtInfo *Info) {
+ return CGOpenMPRegionInfo::classof(Info) &&
+ cast<CGOpenMPRegionInfo>(Info)->getRegionKind() == InlinedRegion;
+ }
+
private:
/// \brief CodeGen info about outer OpenMP region.
CodeGenFunction::CGCapturedStmtInfo *OldCSI;
CGOpenMPRegionInfo *OuterRegionInfo;
};
+
+/// \brief RAII for emitting code of OpenMP constructs.
+class InlinedOpenMPRegionRAII {
+ CodeGenFunction &CGF;
+
+public:
+ /// \brief Constructs region for combined constructs.
+ /// \param CodeGen Code generation sequence for combined directives. Includes
+ /// a list of functions used for code generation of implicitly inlined
+ /// regions.
+ InlinedOpenMPRegionRAII(CodeGenFunction &CGF, const RegionCodeGenTy &CodeGen)
+ : CGF(CGF) {
+ // Start emission for the construct.
+ CGF.CapturedStmtInfo =
+ new CGOpenMPInlinedRegionInfo(CGF.CapturedStmtInfo, CodeGen);
+ }
+ ~InlinedOpenMPRegionRAII() {
+ // Restore original CapturedStmtInfo only if we're done with code emission.
+ auto *OldCSI =
+ cast<CGOpenMPInlinedRegionInfo>(CGF.CapturedStmtInfo)->getOldCSI();
+ delete CGF.CapturedStmtInfo;
+ CGF.CapturedStmtInfo = OldCSI;
+ }
+};
+
} // namespace
LValue CGOpenMPRegionInfo::getThreadIDVariableLValue(CodeGenFunction &CGF) {
@@ -172,15 +235,18 @@
->getPointeeType());
}
-void CGOpenMPRegionInfo::EmitBody(CodeGenFunction &CGF, const Stmt *S) {
- CodeGenFunction::OMPPrivateScope PrivateScope(CGF);
- CGF.EmitOMPPrivateClause(Directive, PrivateScope);
- CGF.EmitOMPFirstprivateClause(Directive, PrivateScope);
- if (PrivateScope.Privatize())
- // Emit implicit barrier to synchronize threads and avoid data races.
- CGF.CGM.getOpenMPRuntime().emitBarrierCall(CGF, Directive.getLocStart(),
- /*IsExplicit=*/false);
- CGCapturedStmtInfo::EmitBody(CGF, S);
+void CGOpenMPRegionInfo::EmitBody(CodeGenFunction &CGF, const Stmt * /*S*/) {
+ // 1.2.2 OpenMP Language Terminology
+ // Structured block - An executable statement with a single entry at the
+ // top and a single exit at the bottom.
+ // The point of exit cannot be a branch out of the structured block.
+ // longjmp() and throw() must not violate the entry/exit criteria.
+ CGF.EHStack.pushTerminate();
+ {
+ CodeGenFunction::RunCleanupsScope Scope(CGF);
+ CodeGen(CGF);
+ }
+ CGF.EHStack.popTerminate();
}
LValue CGOpenMPTaskOutlinedRegionInfo::getThreadIDVariableLValue(
@@ -190,14 +256,6 @@
getThreadIDVariable()->getType());
}
-void CGOpenMPTaskOutlinedRegionInfo::EmitBody(CodeGenFunction &CGF,
- const Stmt *S) {
- if (PartIDVar) {
- // TODO: emit code for untied tasks.
- }
- CGCapturedStmtInfo::EmitBody(CGF, S);
-}
-
CGOpenMPRuntime::CGOpenMPRuntime(CodeGenModule &CGM)
: CGM(CGM), DefaultOpenMPPSource(nullptr), KmpRoutineEntryPtrTy(nullptr) {
IdentTy = llvm::StructType::create(
@@ -216,13 +274,14 @@
}
llvm::Value *
-CGOpenMPRuntime::emitOutlinedFunction(const OMPExecutableDirective &D,
- const VarDecl *ThreadIDVar) {
+CGOpenMPRuntime::emitParallelOutlinedFunction(const OMPExecutableDirective &D,
+ const VarDecl *ThreadIDVar,
+ const RegionCodeGenTy &CodeGen) {
assert(ThreadIDVar->getType()->isPointerType() &&
"thread id variable must be of type kmp_int32 *");
const CapturedStmt *CS = cast<CapturedStmt>(D.getAssociatedStmt());
CodeGenFunction CGF(CGM, true);
- CGOpenMPOutlinedRegionInfo CGInfo(D, *CS, ThreadIDVar);
+ CGOpenMPOutlinedRegionInfo CGInfo(*CS, ThreadIDVar, CodeGen);
CGF.CapturedStmtInfo = &CGInfo;
return CGF.GenerateCapturedStmtFunction(*CS);
}
@@ -230,12 +289,12 @@
llvm::Value *
CGOpenMPRuntime::emitTaskOutlinedFunction(const OMPExecutableDirective &D,
const VarDecl *ThreadIDVar,
- const VarDecl *PartIDVar) {
+ const RegionCodeGenTy &CodeGen) {
assert(!ThreadIDVar->getType()->isPointerType() &&
"thread id variable must be of type kmp_int32 for tasks");
auto *CS = cast<CapturedStmt>(D.getAssociatedStmt());
CodeGenFunction CGF(CGM, true);
- CGOpenMPTaskOutlinedRegionInfo CGInfo(D, *CS, ThreadIDVar, PartIDVar);
+ CGOpenMPTaskOutlinedRegionInfo CGInfo(*CS, ThreadIDVar, CodeGen);
CGF.CapturedStmtInfo = &CGInfo;
return CGF.GenerateCapturedStmtFunction(*CS);
}
@@ -303,8 +362,8 @@
}
// char **psource = &.kmpc_loc_<flags>.addr.psource;
- auto *PSource =
- CGF.Builder.CreateConstInBoundsGEP2_32(LocValue, 0, IdentField_PSource);
+ auto *PSource = CGF.Builder.CreateConstInBoundsGEP2_32(IdentTy, LocValue, 0,
+ IdentField_PSource);
auto OMPDebugLoc = OpenMPDebugLocMap.lookup(Loc.getRawEncoding());
if (OMPDebugLoc == nullptr) {
@@ -595,6 +654,62 @@
RTLFn = CGM.CreateRuntimeFunction(FnTy, /*Name=*/"__kmpc_copyprivate");
break;
}
+ case OMPRTL__kmpc_reduce: {
+ // Build kmp_int32 __kmpc_reduce(ident_t *loc, kmp_int32 global_tid,
+ // kmp_int32 num_vars, size_t reduce_size, void *reduce_data, void
+ // (*reduce_func)(void *lhs_data, void *rhs_data), kmp_critical_name *lck);
+ llvm::Type *ReduceTypeParams[] = {CGM.VoidPtrTy, CGM.VoidPtrTy};
+ auto *ReduceFnTy = llvm::FunctionType::get(CGM.VoidTy, ReduceTypeParams,
+ /*isVarArg=*/false);
+ llvm::Type *TypeParams[] = {
+ getIdentTyPointerTy(), CGM.Int32Ty, CGM.Int32Ty, CGM.SizeTy,
+ CGM.VoidPtrTy, ReduceFnTy->getPointerTo(),
+ llvm::PointerType::getUnqual(KmpCriticalNameTy)};
+ llvm::FunctionType *FnTy =
+ llvm::FunctionType::get(CGM.Int32Ty, TypeParams, /*isVarArg=*/false);
+ RTLFn = CGM.CreateRuntimeFunction(FnTy, /*Name=*/"__kmpc_reduce");
+ break;
+ }
+ case OMPRTL__kmpc_reduce_nowait: {
+ // Build kmp_int32 __kmpc_reduce_nowait(ident_t *loc, kmp_int32
+ // global_tid, kmp_int32 num_vars, size_t reduce_size, void *reduce_data,
+ // void (*reduce_func)(void *lhs_data, void *rhs_data), kmp_critical_name
+ // *lck);
+ llvm::Type *ReduceTypeParams[] = {CGM.VoidPtrTy, CGM.VoidPtrTy};
+ auto *ReduceFnTy = llvm::FunctionType::get(CGM.VoidTy, ReduceTypeParams,
+ /*isVarArg=*/false);
+ llvm::Type *TypeParams[] = {
+ getIdentTyPointerTy(), CGM.Int32Ty, CGM.Int32Ty, CGM.SizeTy,
+ CGM.VoidPtrTy, ReduceFnTy->getPointerTo(),
+ llvm::PointerType::getUnqual(KmpCriticalNameTy)};
+ llvm::FunctionType *FnTy =
+ llvm::FunctionType::get(CGM.Int32Ty, TypeParams, /*isVarArg=*/false);
+ RTLFn = CGM.CreateRuntimeFunction(FnTy, /*Name=*/"__kmpc_reduce_nowait");
+ break;
+ }
+ case OMPRTL__kmpc_end_reduce: {
+ // Build void __kmpc_end_reduce(ident_t *loc, kmp_int32 global_tid,
+ // kmp_critical_name *lck);
+ llvm::Type *TypeParams[] = {
+ getIdentTyPointerTy(), CGM.Int32Ty,
+ llvm::PointerType::getUnqual(KmpCriticalNameTy)};
+ llvm::FunctionType *FnTy =
+ llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg=*/false);
+ RTLFn = CGM.CreateRuntimeFunction(FnTy, /*Name=*/"__kmpc_end_reduce");
+ break;
+ }
+ case OMPRTL__kmpc_end_reduce_nowait: {
+ // Build __kmpc_end_reduce_nowait(ident_t *loc, kmp_int32 global_tid,
+ // kmp_critical_name *lck);
+ llvm::Type *TypeParams[] = {
+ getIdentTyPointerTy(), CGM.Int32Ty,
+ llvm::PointerType::getUnqual(KmpCriticalNameTy)};
+ llvm::FunctionType *FnTy =
+ llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg=*/false);
+ RTLFn =
+ CGM.CreateRuntimeFunction(FnTy, /*Name=*/"__kmpc_end_reduce_nowait");
+ break;
+ }
}
return RTLFn;
}
@@ -906,24 +1021,46 @@
return getOrCreateInternalVariable(KmpCriticalNameTy, Name.concat(".var"));
}
-void CGOpenMPRuntime::emitCriticalRegion(
- CodeGenFunction &CGF, StringRef CriticalName,
- const std::function<void()> &CriticalOpGen, SourceLocation Loc) {
- auto RegionLock = getCriticalRegionLock(CriticalName);
+namespace {
+class CallEndCleanup : public EHScopeStack::Cleanup {
+public:
+ typedef ArrayRef<llvm::Value *> CleanupValuesTy;
+private:
+ llvm::Value *Callee;
+ llvm::SmallVector<llvm::Value *, 8> Args;
+
+public:
+ CallEndCleanup(llvm::Value *Callee, CleanupValuesTy Args)
+ : Callee(Callee), Args(Args.begin(), Args.end()) {}
+ void Emit(CodeGenFunction &CGF, Flags /*flags*/) override {
+ CGF.EmitRuntimeCall(Callee, Args);
+ }
+};
+} // namespace
+
+void CGOpenMPRuntime::emitCriticalRegion(CodeGenFunction &CGF,
+ StringRef CriticalName,
+ const RegionCodeGenTy &CriticalOpGen,
+ SourceLocation Loc) {
// __kmpc_critical(ident_t *, gtid, Lock);
// CriticalOpGen();
// __kmpc_end_critical(ident_t *, gtid, Lock);
// Prepare arguments and build a call to __kmpc_critical
- llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc),
- RegionLock};
- CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__kmpc_critical), Args);
- CriticalOpGen();
- // Build a call to __kmpc_end_critical
- CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__kmpc_end_critical), Args);
+ {
+ CodeGenFunction::RunCleanupsScope Scope(CGF);
+ llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc),
+ getCriticalRegionLock(CriticalName)};
+ CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__kmpc_critical), Args);
+ // Build a call to __kmpc_end_critical
+ CGF.EHStack.pushCleanup<CallEndCleanup>(
+ NormalAndEHCleanup, createRuntimeFunction(OMPRTL__kmpc_end_critical),
+ llvm::makeArrayRef(Args));
+ emitInlinedDirective(CGF, CriticalOpGen);
+ }
}
static void emitIfStmt(CodeGenFunction &CGF, llvm::Value *IfCond,
- const std::function<void()> &BodyOpGen) {
+ const RegionCodeGenTy &BodyOpGen) {
llvm::Value *CallBool = CGF.EmitScalarConversion(
IfCond,
CGF.getContext().getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/true),
@@ -934,14 +1071,14 @@
// Generate the branch (If-stmt)
CGF.Builder.CreateCondBr(CallBool, ThenBlock, ContBlock);
CGF.EmitBlock(ThenBlock);
- BodyOpGen();
+ CGF.CGM.getOpenMPRuntime().emitInlinedDirective(CGF, BodyOpGen);
// Emit the rest of bblocks/branches
CGF.EmitBranch(ContBlock);
CGF.EmitBlock(ContBlock, true);
}
void CGOpenMPRuntime::emitMasterRegion(CodeGenFunction &CGF,
- const std::function<void()> &MasterOpGen,
+ const RegionCodeGenTy &MasterOpGen,
SourceLocation Loc) {
// if(__kmpc_master(ident_t *, gtid)) {
// MasterOpGen();
@@ -951,23 +1088,12 @@
llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc)};
auto *IsMaster =
CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__kmpc_master), Args);
- emitIfStmt(CGF, IsMaster, [&]() -> void {
- MasterOpGen();
- // Build a call to __kmpc_end_master.
- // OpenMP [1.2.2 OpenMP Language Terminology]
- // For C/C++, an executable statement, possibly compound, with a single
- // entry at the top and a single exit at the bottom, or an OpenMP construct.
- // * Access to the structured block must not be the result of a branch.
- // * The point of exit cannot be a branch out of the structured block.
- // * The point of entry must not be a call to setjmp().
- // * longjmp() and throw() must not violate the entry/exit criteria.
- // * An expression statement, iteration statement, selection statement, or
- // try block is considered to be a structured block if the corresponding
- // compound statement obtained by enclosing it in { and } would be a
- // structured block.
- // It is analyzed in Sema, so we can just call __kmpc_end_master() on
- // fallthrough rather than pushing a normal cleanup for it.
- CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__kmpc_end_master), Args);
+ emitIfStmt(CGF, IsMaster, [&](CodeGenFunction &CGF) -> void {
+ CodeGenFunction::RunCleanupsScope Scope(CGF);
+ CGF.EHStack.pushCleanup<CallEndCleanup>(
+ NormalAndEHCleanup, createRuntimeFunction(OMPRTL__kmpc_end_master),
+ llvm::makeArrayRef(Args));
+ MasterOpGen(CGF);
});
}
@@ -981,8 +1107,9 @@
}
static llvm::Value *emitCopyprivateCopyFunction(
- CodeGenModule &CGM, llvm::Type *ArgsType, ArrayRef<const Expr *> SrcExprs,
- ArrayRef<const Expr *> DstExprs, ArrayRef<const Expr *> AssignmentOps) {
+ CodeGenModule &CGM, llvm::Type *ArgsType,
+ ArrayRef<const Expr *> CopyprivateVars, ArrayRef<const Expr *> DestExprs,
+ ArrayRef<const Expr *> SrcExprs, ArrayRef<const Expr *> AssignmentOps) {
auto &C = CGM.getContext();
// void copy_func(void *LHSArg, void *RHSArg);
FunctionArgList Args;
@@ -1001,7 +1128,7 @@
CGM.SetLLVMFunctionAttributes(/*D=*/nullptr, CGFI, Fn);
CodeGenFunction CGF(CGM);
CGF.StartFunction(GlobalDecl(), C.VoidTy, Fn, CGFI, Args);
- // Dst = (void*[n])(LHSArg);
+ // Dest = (void*[n])(LHSArg);
// Src = (void*[n])(RHSArg);
auto *LHS = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
CGF.Builder.CreateAlignedLoad(CGF.GetAddrOfLocalVar(&LHSArg),
@@ -1015,36 +1142,28 @@
// *(Type1*)Dst[1] = *(Type1*)Src[1];
// ...
// *(Typen*)Dst[n] = *(Typen*)Src[n];
- CodeGenFunction::OMPPrivateScope Scope(CGF);
for (unsigned I = 0, E = AssignmentOps.size(); I < E; ++I) {
- Scope.addPrivate(
- cast<VarDecl>(cast<DeclRefExpr>(SrcExprs[I])->getDecl()),
- [&]() -> llvm::Value *{
- return CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
- CGF.Builder.CreateAlignedLoad(CGF.Builder.CreateStructGEP(RHS, I),
- CGM.PointerAlignInBytes),
- CGF.ConvertTypeForMem(C.getPointerType(SrcExprs[I]->getType())));
- });
- Scope.addPrivate(
- cast<VarDecl>(cast<DeclRefExpr>(DstExprs[I])->getDecl()),
- [&]() -> llvm::Value *{
- return CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
- CGF.Builder.CreateAlignedLoad(CGF.Builder.CreateStructGEP(LHS, I),
- CGM.PointerAlignInBytes),
- CGF.ConvertTypeForMem(C.getPointerType(SrcExprs[I]->getType())));
- });
+ auto *DestAddr = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
+ CGF.Builder.CreateAlignedLoad(
+ CGF.Builder.CreateStructGEP(nullptr, LHS, I),
+ CGM.PointerAlignInBytes),
+ CGF.ConvertTypeForMem(C.getPointerType(SrcExprs[I]->getType())));
+ auto *SrcAddr = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
+ CGF.Builder.CreateAlignedLoad(
+ CGF.Builder.CreateStructGEP(nullptr, RHS, I),
+ CGM.PointerAlignInBytes),
+ CGF.ConvertTypeForMem(C.getPointerType(SrcExprs[I]->getType())));
+ CGF.EmitOMPCopy(CGF, CopyprivateVars[I]->getType(), DestAddr, SrcAddr,
+ cast<VarDecl>(cast<DeclRefExpr>(DestExprs[I])->getDecl()),
+ cast<VarDecl>(cast<DeclRefExpr>(SrcExprs[I])->getDecl()),
+ AssignmentOps[I]);
}
- Scope.Privatize();
- for (auto *E : AssignmentOps) {
- CGF.EmitIgnoredExpr(E);
- }
- Scope.ForceCleanup();
CGF.FinishFunction();
return Fn;
}
void CGOpenMPRuntime::emitSingleRegion(CodeGenFunction &CGF,
- const std::function<void()> &SingleOpGen,
+ const RegionCodeGenTy &SingleOpGen,
SourceLocation Loc,
ArrayRef<const Expr *> CopyprivateVars,
ArrayRef<const Expr *> SrcExprs,
@@ -1074,28 +1193,17 @@
llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc)};
auto *IsSingle =
CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__kmpc_single), Args);
- emitIfStmt(CGF, IsSingle, [&]() -> void {
- SingleOpGen();
+ emitIfStmt(CGF, IsSingle, [&](CodeGenFunction &CGF) -> void {
+ CodeGenFunction::RunCleanupsScope Scope(CGF);
+ CGF.EHStack.pushCleanup<CallEndCleanup>(
+ NormalAndEHCleanup, createRuntimeFunction(OMPRTL__kmpc_end_single),
+ llvm::makeArrayRef(Args));
+ SingleOpGen(CGF);
if (DidIt) {
// did_it = 1;
CGF.Builder.CreateAlignedStore(CGF.Builder.getInt32(1), DidIt,
DidIt->getAlignment());
}
- // Build a call to __kmpc_end_single.
- // OpenMP [1.2.2 OpenMP Language Terminology]
- // For C/C++, an executable statement, possibly compound, with a single
- // entry at the top and a single exit at the bottom, or an OpenMP construct.
- // * Access to the structured block must not be the result of a branch.
- // * The point of exit cannot be a branch out of the structured block.
- // * The point of entry must not be a call to setjmp().
- // * longjmp() and throw() must not violate the entry/exit criteria.
- // * An expression statement, iteration statement, selection statement, or
- // try block is considered to be a structured block if the corresponding
- // compound statement obtained by enclosing it in { and } would be a
- // structured block.
- // It is analyzed in Sema, so we can just call __kmpc_end_single() on
- // fallthrough rather than pushing a normal cleanup for it.
- CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__kmpc_end_single), Args);
});
// call __kmpc_copyprivate(ident_t *, gtid, <buf_size>, <copyprivate list>,
// <copy_func>, did_it);
@@ -1108,7 +1216,8 @@
auto *CopyprivateList =
CGF.CreateMemTemp(CopyprivateArrayTy, ".omp.copyprivate.cpr_list");
for (unsigned I = 0, E = CopyprivateVars.size(); I < E; ++I) {
- auto *Elem = CGF.Builder.CreateStructGEP(CopyprivateList, I);
+ auto *Elem = CGF.Builder.CreateStructGEP(
+ CopyprivateList->getAllocatedType(), CopyprivateList, I);
CGF.Builder.CreateAlignedStore(
CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
CGF.EmitLValue(CopyprivateVars[I]).getAddress(), CGF.VoidPtrTy),
@@ -1118,7 +1227,7 @@
// threads in the corresponding parallel region.
auto *CpyFn = emitCopyprivateCopyFunction(
CGM, CGF.ConvertTypeForMem(CopyprivateArrayTy)->getPointerTo(),
- SrcExprs, DstExprs, AssignmentOps);
+ CopyprivateVars, SrcExprs, DstExprs, AssignmentOps);
auto *BufSize = CGF.Builder.getInt32(
C.getTypeSizeInChars(CopyprivateArrayTy).getQuantity());
auto *CL = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(CopyprivateList,
@@ -1138,11 +1247,23 @@
}
void CGOpenMPRuntime::emitBarrierCall(CodeGenFunction &CGF, SourceLocation Loc,
- bool IsExplicit) {
+ OpenMPDirectiveKind Kind) {
// Build call __kmpc_cancel_barrier(loc, thread_id);
- auto Flags = static_cast<OpenMPLocationFlags>(
- OMP_IDENT_KMPC |
- (IsExplicit ? OMP_IDENT_BARRIER_EXPL : OMP_IDENT_BARRIER_IMPL));
+ OpenMPLocationFlags Flags = OMP_IDENT_KMPC;
+ if (Kind == OMPD_for) {
+ Flags =
+ static_cast<OpenMPLocationFlags>(Flags | OMP_IDENT_BARRIER_IMPL_FOR);
+ } else if (Kind == OMPD_sections) {
+ Flags = static_cast<OpenMPLocationFlags>(Flags |
+ OMP_IDENT_BARRIER_IMPL_SECTIONS);
+ } else if (Kind == OMPD_single) {
+ Flags =
+ static_cast<OpenMPLocationFlags>(Flags | OMP_IDENT_BARRIER_IMPL_SINGLE);
+ } else if (Kind == OMPD_barrier) {
+ Flags = static_cast<OpenMPLocationFlags>(Flags | OMP_IDENT_BARRIER_EXPL);
+ } else {
+ Flags = static_cast<OpenMPLocationFlags>(Flags | OMP_IDENT_BARRIER_IMPL);
+ }
// Build call __kmpc_cancel_barrier(loc, thread_id);
// Replace __kmpc_barrier() function by __kmpc_cancel_barrier() because this
// one provides the same functionality and adds initial support for
@@ -1262,6 +1383,7 @@
assert((ScheduleKind == OMPC_SCHEDULE_static ||
ScheduleKind == OMPC_SCHEDULE_unknown) &&
"Non-static schedule kinds are not yet implemented");
+ (void)ScheduleKind;
// Call __kmpc_for_static_fini(ident_t *loc, kmp_int32 tid);
llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc, OMP_IDENT_KMPC),
getThreadID(CGF, Loc)};
@@ -1379,7 +1501,8 @@
static llvm::Value *
emitProxyTaskFunction(CodeGenModule &CGM, SourceLocation Loc,
QualType KmpInt32Ty, QualType KmpTaskTPtrQTy,
- QualType SharedsPtrTy, llvm::Value *TaskFunction) {
+ QualType SharedsPtrTy, llvm::Value *TaskFunction,
+ llvm::Type *KmpTaskTTy) {
auto &C = CGM.getContext();
FunctionArgList Args;
ImplicitParamDecl GtidArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr, KmpInt32Ty);
@@ -1407,12 +1530,12 @@
auto TaskTypeArgAddr = CGF.EmitLoadOfScalar(
CGF.GetAddrOfLocalVar(&TaskTypeArg), /*Volatile=*/false,
CGM.PointerAlignInBytes, KmpTaskTPtrQTy, Loc);
- auto *PartidPtr = CGF.Builder.CreateStructGEP(TaskTypeArgAddr,
+ auto *PartidPtr = CGF.Builder.CreateStructGEP(KmpTaskTTy, TaskTypeArgAddr,
/*Idx=*/KmpTaskTPartId);
auto *PartidParam = CGF.EmitLoadOfScalar(
PartidPtr, /*Volatile=*/false,
C.getTypeAlignInChars(KmpInt32Ty).getQuantity(), KmpInt32Ty, Loc);
- auto *SharedsPtr = CGF.Builder.CreateStructGEP(TaskTypeArgAddr,
+ auto *SharedsPtr = CGF.Builder.CreateStructGEP(KmpTaskTTy, TaskTypeArgAddr,
/*Idx=*/KmpTaskTShareds);
auto *SharedsParam =
CGF.EmitLoadOfScalar(SharedsPtr, /*Volatile=*/false,
@@ -1441,14 +1564,16 @@
auto KmpTaskQTy =
createKmpTaskTRecordDecl(CGM, KmpInt32Ty, KmpRoutineEntryPtrQTy);
QualType KmpTaskTPtrQTy = C.getPointerType(KmpTaskQTy);
- auto KmpTaskTPtrTy = CGF.ConvertType(KmpTaskQTy)->getPointerTo();
+ auto *KmpTaskTTy = CGF.ConvertType(KmpTaskQTy);
+ auto *KmpTaskTPtrTy = KmpTaskTTy->getPointerTo();
auto KmpTaskTySize = CGM.getSize(C.getTypeSizeInChars(KmpTaskQTy));
QualType SharedsPtrTy = C.getPointerType(SharedsTy);
// Build a proxy function kmp_int32 .omp_task_entry.(kmp_int32 gtid,
// kmp_task_t *tt);
- auto *TaskEntry = emitProxyTaskFunction(CGM, Loc, KmpInt32Ty, KmpTaskTPtrQTy,
- SharedsPtrTy, TaskFunction);
+ auto *TaskEntry =
+ emitProxyTaskFunction(CGM, Loc, KmpInt32Ty, KmpTaskTPtrQTy, SharedsPtrTy,
+ TaskFunction, KmpTaskTTy);
// Build call kmp_task_t * __kmpc_omp_task_alloc(ident_t *, kmp_int32 gtid,
// kmp_int32 flags, size_t sizeof_kmp_task_t, size_t sizeof_shareds,
@@ -1481,7 +1606,7 @@
if (!SharedsTy->getAsStructureType()->getDecl()->field_empty())
CGF.EmitAggregateCopy(
CGF.EmitLoadOfScalar(
- CGF.Builder.CreateStructGEP(NewTaskNewTaskTTy,
+ CGF.Builder.CreateStructGEP(KmpTaskTTy, NewTaskNewTaskTTy,
/*Idx=*/KmpTaskTShareds),
/*Volatile=*/false, CGM.PointerAlignInBytes, SharedsPtrTy, Loc),
Shareds, SharedsTy);
@@ -1490,7 +1615,7 @@
CGF.Builder.CreateAlignedStore(
llvm::ConstantPointerNull::get(
cast<llvm::PointerType>(KmpRoutineEntryPtrTy)),
- CGF.Builder.CreateStructGEP(NewTaskNewTaskTTy,
+ CGF.Builder.CreateStructGEP(KmpTaskTTy, NewTaskNewTaskTTy,
/*Idx=*/KmpTaskTDestructors),
CGM.PointerAlignInBytes);
@@ -1504,23 +1629,268 @@
CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__kmpc_omp_task), TaskArgs);
}
-InlinedOpenMPRegionRAII::InlinedOpenMPRegionRAII(
- CodeGenFunction &CGF, const OMPExecutableDirective &D)
- : CGF(CGF) {
- CGF.CapturedStmtInfo = new CGOpenMPInlinedRegionInfo(D, CGF.CapturedStmtInfo);
- // 1.2.2 OpenMP Language Terminology
- // Structured block - An executable statement with a single entry at the
- // top and a single exit at the bottom.
- // The point of exit cannot be a branch out of the structured block.
- // longjmp() and throw() must not violate the entry/exit criteria.
- CGF.EHStack.pushTerminate();
+static llvm::Value *emitReductionFunction(CodeGenModule &CGM,
+ llvm::Type *ArgsType,
+ ArrayRef<const Expr *> LHSExprs,
+ ArrayRef<const Expr *> RHSExprs,
+ ArrayRef<const Expr *> ReductionOps) {
+ auto &C = CGM.getContext();
+
+ // void reduction_func(void *LHSArg, void *RHSArg);
+ FunctionArgList Args;
+ ImplicitParamDecl LHSArg(C, /*DC=*/nullptr, SourceLocation(), /*Id=*/nullptr,
+ C.VoidPtrTy);
+ ImplicitParamDecl RHSArg(C, /*DC=*/nullptr, SourceLocation(), /*Id=*/nullptr,
+ C.VoidPtrTy);
+ Args.push_back(&LHSArg);
+ Args.push_back(&RHSArg);
+ FunctionType::ExtInfo EI;
+ auto &CGFI = CGM.getTypes().arrangeFreeFunctionDeclaration(
+ C.VoidTy, Args, EI, /*isVariadic=*/false);
+ auto *Fn = llvm::Function::Create(
+ CGM.getTypes().GetFunctionType(CGFI), llvm::GlobalValue::InternalLinkage,
+ ".omp.reduction.reduction_func", &CGM.getModule());
+ CGM.SetLLVMFunctionAttributes(/*D=*/nullptr, CGFI, Fn);
+ CodeGenFunction CGF(CGM);
+ CGF.StartFunction(GlobalDecl(), C.VoidTy, Fn, CGFI, Args);
+
+ // Dst = (void*[n])(LHSArg);
+ // Src = (void*[n])(RHSArg);
+ auto *LHS = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
+ CGF.Builder.CreateAlignedLoad(CGF.GetAddrOfLocalVar(&LHSArg),
+ CGF.PointerAlignInBytes),
+ ArgsType);
+ auto *RHS = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
+ CGF.Builder.CreateAlignedLoad(CGF.GetAddrOfLocalVar(&RHSArg),
+ CGF.PointerAlignInBytes),
+ ArgsType);
+
+ // ...
+ // *(Type<i>*)lhs[i] = RedOp<i>(*(Type<i>*)lhs[i], *(Type<i>*)rhs[i]);
+ // ...
+ CodeGenFunction::OMPPrivateScope Scope(CGF);
+ for (unsigned I = 0, E = ReductionOps.size(); I < E; ++I) {
+ Scope.addPrivate(
+ cast<VarDecl>(cast<DeclRefExpr>(RHSExprs[I])->getDecl()),
+ [&]() -> llvm::Value *{
+ return CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
+ CGF.Builder.CreateAlignedLoad(
+ CGF.Builder.CreateStructGEP(/*Ty=*/nullptr, RHS, I),
+ CGM.PointerAlignInBytes),
+ CGF.ConvertTypeForMem(C.getPointerType(RHSExprs[I]->getType())));
+ });
+ Scope.addPrivate(
+ cast<VarDecl>(cast<DeclRefExpr>(LHSExprs[I])->getDecl()),
+ [&]() -> llvm::Value *{
+ return CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
+ CGF.Builder.CreateAlignedLoad(
+ CGF.Builder.CreateStructGEP(/*Ty=*/nullptr, LHS, I),
+ CGM.PointerAlignInBytes),
+ CGF.ConvertTypeForMem(C.getPointerType(LHSExprs[I]->getType())));
+ });
+ }
+ Scope.Privatize();
+ for (auto *E : ReductionOps) {
+ CGF.EmitIgnoredExpr(E);
+ }
+ Scope.ForceCleanup();
+ CGF.FinishFunction();
+ return Fn;
}
-InlinedOpenMPRegionRAII::~InlinedOpenMPRegionRAII() {
- CGF.EHStack.popTerminate();
- auto *OldCSI =
- cast<CGOpenMPInlinedRegionInfo>(CGF.CapturedStmtInfo)->getOldCSI();
- delete CGF.CapturedStmtInfo;
- CGF.CapturedStmtInfo = OldCSI;
+void CGOpenMPRuntime::emitReduction(CodeGenFunction &CGF, SourceLocation Loc,
+ ArrayRef<const Expr *> LHSExprs,
+ ArrayRef<const Expr *> RHSExprs,
+ ArrayRef<const Expr *> ReductionOps,
+ bool WithNowait) {
+ // Next code should be emitted for reduction:
+ //
+ // static kmp_critical_name lock = { 0 };
+ //
+ // void reduce_func(void *lhs[<n>], void *rhs[<n>]) {
+ // *(Type0*)lhs[0] = ReductionOperation0(*(Type0*)lhs[0], *(Type0*)rhs[0]);
+ // ...
+ // *(Type<n>-1*)lhs[<n>-1] = ReductionOperation<n>-1(*(Type<n>-1*)lhs[<n>-1],
+ // *(Type<n>-1*)rhs[<n>-1]);
+ // }
+ //
+ // ...
+ // void *RedList[<n>] = {&<RHSExprs>[0], ..., &<RHSExprs>[<n>-1]};
+ // switch (__kmpc_reduce{_nowait}(<loc>, <gtid>, <n>, sizeof(RedList),
+ // RedList, reduce_func, &<lock>)) {
+ // case 1:
+ // ...
+ // <LHSExprs>[i] = RedOp<i>(*<LHSExprs>[i], *<RHSExprs>[i]);
+ // ...
+ // __kmpc_end_reduce{_nowait}(<loc>, <gtid>, &<lock>);
+ // break;
+ // case 2:
+ // ...
+ // Atomic(<LHSExprs>[i] = RedOp<i>(*<LHSExprs>[i], *<RHSExprs>[i]));
+ // ...
+ // break;
+ // default:;
+ // }
+
+ auto &C = CGM.getContext();
+
+ // 1. Build a list of reduction variables.
+ // void *RedList[<n>] = {<ReductionVars>[0], ..., <ReductionVars>[<n>-1]};
+ llvm::APInt ArraySize(/*unsigned int numBits=*/32, RHSExprs.size());
+ QualType ReductionArrayTy =
+ C.getConstantArrayType(C.VoidPtrTy, ArraySize, ArrayType::Normal,
+ /*IndexTypeQuals=*/0);
+ auto *ReductionList =
+ CGF.CreateMemTemp(ReductionArrayTy, ".omp.reduction.red_list");
+ for (unsigned I = 0, E = RHSExprs.size(); I < E; ++I) {
+ auto *Elem = CGF.Builder.CreateStructGEP(/*Ty=*/nullptr, ReductionList, I);
+ CGF.Builder.CreateAlignedStore(
+ CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
+ CGF.EmitLValue(RHSExprs[I]).getAddress(), CGF.VoidPtrTy),
+ Elem, CGM.PointerAlignInBytes);
+ }
+
+ // 2. Emit reduce_func().
+ auto *ReductionFn = emitReductionFunction(
+ CGM, CGF.ConvertTypeForMem(ReductionArrayTy)->getPointerTo(), LHSExprs,
+ RHSExprs, ReductionOps);
+
+ // 3. Create static kmp_critical_name lock = { 0 };
+ auto *Lock = getCriticalRegionLock(".reduction");
+
+ // 4. Build res = __kmpc_reduce{_nowait}(<loc>, <gtid>, <n>, sizeof(RedList),
+ // RedList, reduce_func, &<lock>);
+ auto *IdentTLoc = emitUpdateLocation(
+ CGF, Loc,
+ static_cast<OpenMPLocationFlags>(OMP_IDENT_KMPC | OMP_ATOMIC_REDUCE));
+ auto *ThreadId = getThreadID(CGF, Loc);
+ auto *ReductionArrayTySize = llvm::ConstantInt::get(
+ CGM.SizeTy, C.getTypeSizeInChars(ReductionArrayTy).getQuantity());
+ auto *RL = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(ReductionList,
+ CGF.VoidPtrTy);
+ llvm::Value *Args[] = {
+ IdentTLoc, // ident_t *<loc>
+ ThreadId, // i32 <gtid>
+ CGF.Builder.getInt32(RHSExprs.size()), // i32 <n>
+ ReductionArrayTySize, // size_type sizeof(RedList)
+ RL, // void *RedList
+ ReductionFn, // void (*) (void *, void *) <reduce_func>
+ Lock // kmp_critical_name *&<lock>
+ };
+ auto Res = CGF.EmitRuntimeCall(
+ createRuntimeFunction(WithNowait ? OMPRTL__kmpc_reduce_nowait
+ : OMPRTL__kmpc_reduce),
+ Args);
+
+ // 5. Build switch(res)
+ auto *DefaultBB = CGF.createBasicBlock(".omp.reduction.default");
+ auto *SwInst = CGF.Builder.CreateSwitch(Res, DefaultBB, /*NumCases=*/2);
+
+ // 6. Build case 1:
+ // ...
+ // <LHSExprs>[i] = RedOp<i>(*<LHSExprs>[i], *<RHSExprs>[i]);
+ // ...
+ // __kmpc_end_reduce{_nowait}(<loc>, <gtid>, &<lock>);
+ // break;
+ auto *Case1BB = CGF.createBasicBlock(".omp.reduction.case1");
+ SwInst->addCase(CGF.Builder.getInt32(1), Case1BB);
+ CGF.EmitBlock(Case1BB);
+
+ {
+ CodeGenFunction::RunCleanupsScope Scope(CGF);
+ // Add emission of __kmpc_end_reduce{_nowait}(<loc>, <gtid>, &<lock>);
+ llvm::Value *EndArgs[] = {
+ IdentTLoc, // ident_t *<loc>
+ ThreadId, // i32 <gtid>
+ Lock // kmp_critical_name *&<lock>
+ };
+ CGF.EHStack.pushCleanup<CallEndCleanup>(
+ NormalAndEHCleanup,
+ createRuntimeFunction(WithNowait ? OMPRTL__kmpc_end_reduce_nowait
+ : OMPRTL__kmpc_end_reduce),
+ llvm::makeArrayRef(EndArgs));
+ for (auto *E : ReductionOps) {
+ CGF.EmitIgnoredExpr(E);
+ }
+ }
+
+ CGF.EmitBranch(DefaultBB);
+
+ // 7. Build case 2:
+ // ...
+ // Atomic(<LHSExprs>[i] = RedOp<i>(*<LHSExprs>[i], *<RHSExprs>[i]));
+ // ...
+ // break;
+ auto *Case2BB = CGF.createBasicBlock(".omp.reduction.case2");
+ SwInst->addCase(CGF.Builder.getInt32(2), Case2BB);
+ CGF.EmitBlock(Case2BB);
+
+ {
+ CodeGenFunction::RunCleanupsScope Scope(CGF);
+ auto I = LHSExprs.begin();
+ for (auto *E : ReductionOps) {
+ const Expr *XExpr = nullptr;
+ const Expr *EExpr = nullptr;
+ const Expr *UpExpr = nullptr;
+ BinaryOperatorKind BO = BO_Comma;
+ // Try to emit update expression as a simple atomic.
+ if (auto *ACO = dyn_cast<AbstractConditionalOperator>(E)) {
+ // If this is a conditional operator, analyze it's condition for
+ // min/max reduction operator.
+ E = ACO->getCond();
+ }
+ if (auto *BO = dyn_cast<BinaryOperator>(E)) {
+ if (BO->getOpcode() == BO_Assign) {
+ XExpr = BO->getLHS();
+ UpExpr = BO->getRHS();
+ }
+ }
+ // Analyze RHS part of the whole expression.
+ if (UpExpr) {
+ if (auto *BORHS =
+ dyn_cast<BinaryOperator>(UpExpr->IgnoreParenImpCasts())) {
+ EExpr = BORHS->getRHS();
+ BO = BORHS->getOpcode();
+ }
+ }
+ if (XExpr) {
+ auto *VD = cast<VarDecl>(cast<DeclRefExpr>(*I)->getDecl());
+ LValue X = CGF.EmitLValue(XExpr);
+ RValue E;
+ if (EExpr)
+ E = CGF.EmitAnyExpr(EExpr);
+ CGF.EmitOMPAtomicSimpleUpdateExpr(
+ X, E, BO, /*IsXLHSInRHSPart=*/true, llvm::Monotonic, Loc,
+ [&CGF, UpExpr, VD](RValue XRValue) {
+ CodeGenFunction::OMPPrivateScope PrivateScope(CGF);
+ PrivateScope.addPrivate(
+ VD, [&CGF, VD, XRValue]() -> llvm::Value *{
+ auto *LHSTemp = CGF.CreateMemTemp(VD->getType());
+ CGF.EmitStoreThroughLValue(
+ XRValue,
+ CGF.MakeNaturalAlignAddrLValue(LHSTemp, VD->getType()));
+ return LHSTemp;
+ });
+ (void)PrivateScope.Privatize();
+ return CGF.EmitAnyExpr(UpExpr);
+ });
+ } else {
+ // Emit as a critical region.
+ emitCriticalRegion(CGF, ".atomic_reduction", [E](CodeGenFunction &CGF) {
+ CGF.EmitIgnoredExpr(E);
+ }, Loc);
+ }
+ ++I;
+ }
+ }
+
+ CGF.EmitBranch(DefaultBB);
+ CGF.EmitBlock(DefaultBB, /*IsFinished=*/true);
+}
+
+void CGOpenMPRuntime::emitInlinedDirective(CodeGenFunction &CGF,
+ const RegionCodeGenTy &CodeGen) {
+ InlinedOpenMPRegionRAII Region(CGF, CodeGen);
+ CGF.CapturedStmtInfo->EmitBody(CGF, /*S=*/nullptr);
}
diff --git a/lib/CodeGen/CGOpenMPRuntime.h b/lib/CodeGen/CGOpenMPRuntime.h
index f8849e6..fa59930 100644
--- a/lib/CodeGen/CGOpenMPRuntime.h
+++ b/lib/CodeGen/CGOpenMPRuntime.h
@@ -43,7 +43,10 @@
class CodeGenFunction;
class CodeGenModule;
+typedef llvm::function_ref<void(CodeGenFunction &)> RegionCodeGenTy;
+
class CGOpenMPRuntime {
+private:
enum OpenMPRTLFunction {
/// \brief Call to void __kmpc_fork_call(ident_t *loc, kmp_int32 argc,
/// kmpc_micro microtask, ...);
@@ -100,6 +103,21 @@
// kmp_int32 cpy_size, void *cpy_data, void(*cpy_func)(void *, void *),
// kmp_int32 didit);
OMPRTL__kmpc_copyprivate,
+ // Call to kmp_int32 __kmpc_reduce(ident_t *loc, kmp_int32 global_tid,
+ // kmp_int32 num_vars, size_t reduce_size, void *reduce_data, void
+ // (*reduce_func)(void *lhs_data, void *rhs_data), kmp_critical_name *lck);
+ OMPRTL__kmpc_reduce,
+ // Call to kmp_int32 __kmpc_reduce_nowait(ident_t *loc, kmp_int32
+ // global_tid, kmp_int32 num_vars, size_t reduce_size, void *reduce_data,
+ // void (*reduce_func)(void *lhs_data, void *rhs_data), kmp_critical_name
+ // *lck);
+ OMPRTL__kmpc_reduce_nowait,
+ // Call to void __kmpc_end_reduce(ident_t *loc, kmp_int32 global_tid,
+ // kmp_critical_name *lck);
+ OMPRTL__kmpc_end_reduce,
+ // Call to void __kmpc_end_reduce_nowait(ident_t *loc, kmp_int32 global_tid,
+ // kmp_critical_name *lck);
+ OMPRTL__kmpc_end_reduce_nowait,
};
/// \brief Values for bit flags used in the ident_t to describe the fields.
@@ -284,25 +302,27 @@
virtual ~CGOpenMPRuntime() {}
virtual void clear();
- /// \brief Emits outlined function for the specified OpenMP directive \a D.
- /// This outlined function has type void(*)(kmp_int32 *ThreadID, kmp_int32
- /// BoundID, struct context_vars*).
+ /// \brief Emits outlined function for the specified OpenMP parallel directive
+ /// \a D. This outlined function has type void(*)(kmp_int32 *ThreadID,
+ /// kmp_int32 BoundID, struct context_vars*).
/// \param D OpenMP directive.
/// \param ThreadIDVar Variable for thread id in the current OpenMP region.
- ///
- virtual llvm::Value *emitOutlinedFunction(const OMPExecutableDirective &D,
- const VarDecl *ThreadIDVar);
+ /// \param CodeGen Code generation sequence for the \a D directive.
+ virtual llvm::Value *
+ emitParallelOutlinedFunction(const OMPExecutableDirective &D,
+ const VarDecl *ThreadIDVar,
+ const RegionCodeGenTy &CodeGen);
/// \brief Emits outlined function for the OpenMP task directive \a D. This
/// outlined function has type void(*)(kmp_int32 ThreadID, kmp_int32
/// PartID, struct context_vars*).
/// \param D OpenMP directive.
/// \param ThreadIDVar Variable for thread id in the current OpenMP region.
- /// \param PartIDVar If not nullptr - variable used for part id in tasks.
+ /// \param CodeGen Code generation sequence for the \a D directive.
///
virtual llvm::Value *emitTaskOutlinedFunction(const OMPExecutableDirective &D,
const VarDecl *ThreadIDVar,
- const VarDecl *PartIDVar);
+ const RegionCodeGenTy &CodeGen);
/// \brief Cleans up references to the objects in finished function.
///
@@ -334,14 +354,14 @@
/// \param CriticalOpGen Generator for the statement associated with the given
/// critical region.
virtual void emitCriticalRegion(CodeGenFunction &CGF, StringRef CriticalName,
- const std::function<void()> &CriticalOpGen,
+ const RegionCodeGenTy &CriticalOpGen,
SourceLocation Loc);
/// \brief Emits a master region.
/// \param MasterOpGen Generator for the statement associated with the given
/// master region.
virtual void emitMasterRegion(CodeGenFunction &CGF,
- const std::function<void()> &MasterOpGen,
+ const RegionCodeGenTy &MasterOpGen,
SourceLocation Loc);
/// \brief Emits code for a taskyield directive.
@@ -351,18 +371,19 @@
/// \param SingleOpGen Generator for the statement associated with the given
/// single region.
virtual void emitSingleRegion(CodeGenFunction &CGF,
- const std::function<void()> &SingleOpGen,
+ const RegionCodeGenTy &SingleOpGen,
SourceLocation Loc,
ArrayRef<const Expr *> CopyprivateVars,
+ ArrayRef<const Expr *> DestExprs,
ArrayRef<const Expr *> SrcExprs,
- ArrayRef<const Expr *> DstExprs,
ArrayRef<const Expr *> AssignmentOps);
- /// \brief Emits explicit barrier for OpenMP threads.
- /// \param IsExplicit true, if it is explicitly specified barrier.
+ /// \brief Emit an implicit/explicit barrier for OpenMP threads.
+ /// \param Kind Directive for which this implicit barrier call must be
+ /// generated. Must be OMPD_barrier for explicit barrier generation.
///
virtual void emitBarrierCall(CodeGenFunction &CGF, SourceLocation Loc,
- bool IsExplicit = true);
+ OpenMPDirectiveKind Kind);
/// \brief Check if the specified \a ScheduleKind is static non-chunked.
/// This kind of worksharing directive is emitted without outer loop.
@@ -505,17 +526,56 @@
llvm::PointerIntPair<llvm::Value *, 1, bool> Final,
llvm::Value *TaskFunction, QualType SharedsTy,
llvm::Value *Shareds);
+
+ /// \brief Emit code for the directive that does not require outlining.
+ ///
+ /// \param CodeGen Code generation sequence for the \a D directive.
+ virtual void emitInlinedDirective(CodeGenFunction &CGF,
+ const RegionCodeGenTy &CodeGen);
+ /// \brief Emit a code for reduction clause. Next code should be emitted for
+ /// reduction:
+ /// \code
+ ///
+ /// static kmp_critical_name lock = { 0 };
+ ///
+ /// void reduce_func(void *lhs[<n>], void *rhs[<n>]) {
+ /// ...
+ /// *(Type<i>*)lhs[i] = RedOp<i>(*(Type<i>*)lhs[i], *(Type<i>*)rhs[i]);
+ /// ...
+ /// }
+ ///
+ /// ...
+ /// void *RedList[<n>] = {&<RHSExprs>[0], ..., &<RHSExprs>[<n>-1]};
+ /// switch (__kmpc_reduce{_nowait}(<loc>, <gtid>, <n>, sizeof(RedList),
+ /// RedList, reduce_func, &<lock>)) {
+ /// case 1:
+ /// ...
+ /// <LHSExprs>[i] = RedOp<i>(*<LHSExprs>[i], *<RHSExprs>[i]);
+ /// ...
+ /// __kmpc_end_reduce{_nowait}(<loc>, <gtid>, &<lock>);
+ /// break;
+ /// case 2:
+ /// ...
+ /// Atomic(<LHSExprs>[i] = RedOp<i>(*<LHSExprs>[i], *<RHSExprs>[i]));
+ /// ...
+ /// break;
+ /// default:;
+ /// }
+ /// \endcode
+ ///
+ /// \param LHSExprs List of LHS in \a ReductionOps reduction operations.
+ /// \param RHSExprs List of RHS in \a ReductionOps reduction operations.
+ /// \param ReductionOps List of reduction operations in form 'LHS binop RHS'
+ /// or 'operator binop(LHS, RHS)'.
+ /// \param WithNowait true if parent directive has also nowait clause, false
+ /// otherwise.
+ virtual void emitReduction(CodeGenFunction &CGF, SourceLocation Loc,
+ ArrayRef<const Expr *> LHSExprs,
+ ArrayRef<const Expr *> RHSExprs,
+ ArrayRef<const Expr *> ReductionOps,
+ bool WithNowait);
};
-/// \brief RAII for emitting code of CapturedStmt without function outlining.
-class InlinedOpenMPRegionRAII {
- CodeGenFunction &CGF;
-
-public:
- InlinedOpenMPRegionRAII(CodeGenFunction &CGF,
- const OMPExecutableDirective &D);
- ~InlinedOpenMPRegionRAII();
-};
} // namespace CodeGen
} // namespace clang
diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp
index e433984..481fdbe 100644
--- a/lib/CodeGen/CGStmt.cpp
+++ b/lib/CodeGen/CGStmt.cpp
@@ -1021,6 +1021,12 @@
/// if the function returns void, or may be missing one if the function returns
/// non-void. Fun stuff :).
void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) {
+ // Returning from an outlined SEH helper is UB, and we already warn on it.
+ if (IsOutlinedSEHHelper) {
+ Builder.CreateUnreachable();
+ Builder.ClearInsertionPoint();
+ }
+
// Emit the result value, even if unused, to evalute the side effects.
const Expr *RV = S.getRetValue();
diff --git a/lib/CodeGen/CGStmtOpenMP.cpp b/lib/CodeGen/CGStmtOpenMP.cpp
index 9af7474..aa53756 100644
--- a/lib/CodeGen/CGStmtOpenMP.cpp
+++ b/lib/CodeGen/CGStmtOpenMP.cpp
@@ -23,21 +23,6 @@
//===----------------------------------------------------------------------===//
// OpenMP Directive Emission
//===----------------------------------------------------------------------===//
-namespace {
-/// \brief RAII for inlined OpenMP regions (like 'omp for', 'omp simd', 'omp
-/// critical' etc.). Helps to generate proper debug info and provides correct
-/// code generation for such constructs.
-class InlinedOpenMPRegionScopeRAII {
- InlinedOpenMPRegionRAII Region;
- CodeGenFunction::LexicalScope DirectiveScope;
-
-public:
- InlinedOpenMPRegionScopeRAII(CodeGenFunction &CGF,
- const OMPExecutableDirective &D)
- : Region(CGF, D), DirectiveScope(CGF, D.getSourceRange()) {}
-};
-} // namespace
-
/// \brief Emits code for OpenMP 'if' clause using specified \a CodeGen
/// function. Here is the logic:
/// if (Cond) {
@@ -84,117 +69,171 @@
CGF.EmitBlock(ContBlock, /*IsFinished*/ true);
}
-void CodeGenFunction::EmitOMPAggregateAssign(LValue OriginalAddr,
- llvm::Value *PrivateAddr,
- const Expr *AssignExpr,
- QualType OriginalType,
- const VarDecl *VDInit) {
- EmitBlock(createBasicBlock(".omp.assign.begin."));
- if (!isa<CXXConstructExpr>(AssignExpr) || isTrivialInitializer(AssignExpr)) {
- // Perform simple memcpy.
- EmitAggregateAssign(PrivateAddr, OriginalAddr.getAddress(),
- AssignExpr->getType());
- } else {
- // Perform element-by-element initialization.
- QualType ElementTy;
- auto SrcBegin = OriginalAddr.getAddress();
- auto DestBegin = PrivateAddr;
- auto ArrayTy = OriginalType->getAsArrayTypeUnsafe();
- auto SrcNumElements = emitArrayLength(ArrayTy, ElementTy, SrcBegin);
- auto DestNumElements = emitArrayLength(ArrayTy, ElementTy, DestBegin);
- auto SrcEnd = Builder.CreateGEP(SrcBegin, SrcNumElements);
- auto DestEnd = Builder.CreateGEP(DestBegin, DestNumElements);
- // The basic structure here is a do-while loop, because we don't
- // need to check for the zero-element case.
- auto BodyBB = createBasicBlock("omp.arraycpy.body");
- auto DoneBB = createBasicBlock("omp.arraycpy.done");
- auto IsEmpty =
- Builder.CreateICmpEQ(DestBegin, DestEnd, "omp.arraycpy.isempty");
- Builder.CreateCondBr(IsEmpty, DoneBB, BodyBB);
+void CodeGenFunction::EmitOMPAggregateAssign(
+ llvm::Value *DestAddr, llvm::Value *SrcAddr, QualType OriginalType,
+ const llvm::function_ref<void(llvm::Value *, llvm::Value *)> &CopyGen) {
+ // Perform element-by-element initialization.
+ QualType ElementTy;
+ auto SrcBegin = SrcAddr;
+ auto DestBegin = DestAddr;
+ auto ArrayTy = OriginalType->getAsArrayTypeUnsafe();
+ auto NumElements = emitArrayLength(ArrayTy, ElementTy, DestBegin);
+ // Cast from pointer to array type to pointer to single element.
+ SrcBegin = Builder.CreatePointerBitCastOrAddrSpaceCast(SrcBegin,
+ DestBegin->getType());
+ auto DestEnd = Builder.CreateGEP(DestBegin, NumElements);
+ // The basic structure here is a while-do loop.
+ auto BodyBB = createBasicBlock("omp.arraycpy.body");
+ auto DoneBB = createBasicBlock("omp.arraycpy.done");
+ auto IsEmpty =
+ Builder.CreateICmpEQ(DestBegin, DestEnd, "omp.arraycpy.isempty");
+ Builder.CreateCondBr(IsEmpty, DoneBB, BodyBB);
- // Enter the loop body, making that address the current address.
- auto EntryBB = Builder.GetInsertBlock();
- EmitBlock(BodyBB);
- auto SrcElementPast = Builder.CreatePHI(SrcBegin->getType(), 2,
- "omp.arraycpy.srcElementPast");
- SrcElementPast->addIncoming(SrcEnd, EntryBB);
- auto DestElementPast = Builder.CreatePHI(DestBegin->getType(), 2,
- "omp.arraycpy.destElementPast");
- DestElementPast->addIncoming(DestEnd, EntryBB);
+ // Enter the loop body, making that address the current address.
+ auto EntryBB = Builder.GetInsertBlock();
+ EmitBlock(BodyBB);
+ auto SrcElementCurrent =
+ Builder.CreatePHI(SrcBegin->getType(), 2, "omp.arraycpy.srcElementPast");
+ SrcElementCurrent->addIncoming(SrcBegin, EntryBB);
+ auto DestElementCurrent = Builder.CreatePHI(DestBegin->getType(), 2,
+ "omp.arraycpy.destElementPast");
+ DestElementCurrent->addIncoming(DestBegin, EntryBB);
- // Shift the address back by one element.
- auto NegativeOne = llvm::ConstantInt::get(SizeTy, -1, true);
- auto DestElement = Builder.CreateGEP(DestElementPast, NegativeOne,
- "omp.arraycpy.dest.element");
- auto SrcElement = Builder.CreateGEP(SrcElementPast, NegativeOne,
- "omp.arraycpy.src.element");
- {
- // Create RunCleanScope to cleanup possible temps.
- CodeGenFunction::RunCleanupsScope Init(*this);
- // Emit initialization for single element.
- LocalDeclMap[VDInit] = SrcElement;
- EmitAnyExprToMem(AssignExpr, DestElement,
- AssignExpr->getType().getQualifiers(),
- /*IsInitializer*/ false);
- LocalDeclMap.erase(VDInit);
- }
+ // Emit copy.
+ CopyGen(DestElementCurrent, SrcElementCurrent);
- // Check whether we've reached the end.
- auto Done =
- Builder.CreateICmpEQ(DestElement, DestBegin, "omp.arraycpy.done");
- Builder.CreateCondBr(Done, DoneBB, BodyBB);
- DestElementPast->addIncoming(DestElement, Builder.GetInsertBlock());
- SrcElementPast->addIncoming(SrcElement, Builder.GetInsertBlock());
+ // Shift the address forward by one element.
+ auto DestElementNext = Builder.CreateConstGEP1_32(
+ DestElementCurrent, /*Idx0=*/1, "omp.arraycpy.dest.element");
+ auto SrcElementNext = Builder.CreateConstGEP1_32(
+ SrcElementCurrent, /*Idx0=*/1, "omp.arraycpy.src.element");
+ // Check whether we've reached the end.
+ auto Done =
+ Builder.CreateICmpEQ(DestElementNext, DestEnd, "omp.arraycpy.done");
+ Builder.CreateCondBr(Done, DoneBB, BodyBB);
+ DestElementCurrent->addIncoming(DestElementNext, Builder.GetInsertBlock());
+ SrcElementCurrent->addIncoming(SrcElementNext, Builder.GetInsertBlock());
- // Done.
- EmitBlock(DoneBB, true);
- }
- EmitBlock(createBasicBlock(".omp.assign.end."));
+ // Done.
+ EmitBlock(DoneBB, /*IsFinished=*/true);
}
-void CodeGenFunction::EmitOMPFirstprivateClause(
- const OMPExecutableDirective &D,
- CodeGenFunction::OMPPrivateScope &PrivateScope) {
- auto PrivateFilter = [](const OMPClause *C) -> bool {
+void CodeGenFunction::EmitOMPCopy(CodeGenFunction &CGF,
+ QualType OriginalType, llvm::Value *DestAddr,
+ llvm::Value *SrcAddr, const VarDecl *DestVD,
+ const VarDecl *SrcVD, const Expr *Copy) {
+ if (OriginalType->isArrayType()) {
+ auto *BO = dyn_cast<BinaryOperator>(Copy);
+ if (BO && BO->getOpcode() == BO_Assign) {
+ // Perform simple memcpy for simple copying.
+ CGF.EmitAggregateAssign(DestAddr, SrcAddr, OriginalType);
+ } else {
+ // For arrays with complex element types perform element by element
+ // copying.
+ CGF.EmitOMPAggregateAssign(
+ DestAddr, SrcAddr, OriginalType,
+ [&CGF, Copy, SrcVD, DestVD](llvm::Value *DestElement,
+ llvm::Value *SrcElement) {
+ // Working with the single array element, so have to remap
+ // destination and source variables to corresponding array
+ // elements.
+ CodeGenFunction::OMPPrivateScope Remap(CGF);
+ Remap.addPrivate(DestVD, [DestElement]() -> llvm::Value *{
+ return DestElement;
+ });
+ Remap.addPrivate(
+ SrcVD, [SrcElement]() -> llvm::Value *{ return SrcElement; });
+ (void)Remap.Privatize();
+ CGF.EmitIgnoredExpr(Copy);
+ });
+ }
+ } else {
+ // Remap pseudo source variable to private copy.
+ CodeGenFunction::OMPPrivateScope Remap(CGF);
+ Remap.addPrivate(SrcVD, [SrcAddr]() -> llvm::Value *{ return SrcAddr; });
+ Remap.addPrivate(DestVD, [DestAddr]() -> llvm::Value *{ return DestAddr; });
+ (void)Remap.Privatize();
+ // Emit copying of the whole variable.
+ CGF.EmitIgnoredExpr(Copy);
+ }
+}
+
+bool CodeGenFunction::EmitOMPFirstprivateClause(const OMPExecutableDirective &D,
+ OMPPrivateScope &PrivateScope) {
+ auto FirstprivateFilter = [](const OMPClause *C) -> bool {
return C->getClauseKind() == OMPC_firstprivate;
};
- for (OMPExecutableDirective::filtered_clause_iterator<decltype(PrivateFilter)>
- I(D.clauses(), PrivateFilter); I; ++I) {
+ llvm::DenseSet<const VarDecl *> EmittedAsFirstprivate;
+ for (OMPExecutableDirective::filtered_clause_iterator<decltype(
+ FirstprivateFilter)> I(D.clauses(), FirstprivateFilter);
+ I; ++I) {
auto *C = cast<OMPFirstprivateClause>(*I);
auto IRef = C->varlist_begin();
auto InitsRef = C->inits().begin();
for (auto IInit : C->private_copies()) {
auto *OrigVD = cast<VarDecl>(cast<DeclRefExpr>(*IRef)->getDecl());
- auto *VD = cast<VarDecl>(cast<DeclRefExpr>(IInit)->getDecl());
- bool IsRegistered;
- if (*InitsRef != nullptr) {
- // Emit VarDecl with copy init for arrays.
- auto *FD = CapturedStmtInfo->lookup(OrigVD);
- LValue Base = MakeNaturalAlignAddrLValue(
- CapturedStmtInfo->getContextValue(),
- getContext().getTagDeclType(FD->getParent()));
- auto OriginalAddr = EmitLValueForField(Base, FD);
- auto VDInit = cast<VarDecl>(cast<DeclRefExpr>(*InitsRef)->getDecl());
- IsRegistered = PrivateScope.addPrivate(OrigVD, [&]() -> llvm::Value * {
- auto Emission = EmitAutoVarAlloca(*VD);
- // Emit initialization of aggregate firstprivate vars.
- EmitOMPAggregateAssign(OriginalAddr, Emission.getAllocatedAddress(),
- VD->getInit(), (*IRef)->getType(), VDInit);
- EmitAutoVarCleanups(Emission);
- return Emission.getAllocatedAddress();
- });
- } else
- IsRegistered = PrivateScope.addPrivate(OrigVD, [&]() -> llvm::Value * {
- // Emit private VarDecl with copy init.
- EmitDecl(*VD);
- return GetAddrOfLocalVar(VD);
- });
- assert(IsRegistered && "firstprivate var already registered as private");
- // Silence the warning about unused variable.
- (void)IsRegistered;
+ if (EmittedAsFirstprivate.count(OrigVD) == 0) {
+ EmittedAsFirstprivate.insert(OrigVD);
+ auto *VD = cast<VarDecl>(cast<DeclRefExpr>(IInit)->getDecl());
+ auto *VDInit = cast<VarDecl>(cast<DeclRefExpr>(*InitsRef)->getDecl());
+ bool IsRegistered;
+ DeclRefExpr DRE(
+ const_cast<VarDecl *>(OrigVD),
+ /*RefersToEnclosingVariableOrCapture=*/CapturedStmtInfo->lookup(
+ OrigVD) != nullptr,
+ (*IRef)->getType(), VK_LValue, (*IRef)->getExprLoc());
+ auto *OriginalAddr = EmitLValue(&DRE).getAddress();
+ if (OrigVD->getType()->isArrayType()) {
+ // Emit VarDecl with copy init for arrays.
+ // Get the address of the original variable captured in current
+ // captured region.
+ IsRegistered = PrivateScope.addPrivate(OrigVD, [&]() -> llvm::Value *{
+ auto Emission = EmitAutoVarAlloca(*VD);
+ auto *Init = VD->getInit();
+ if (!isa<CXXConstructExpr>(Init) || isTrivialInitializer(Init)) {
+ // Perform simple memcpy.
+ EmitAggregateAssign(Emission.getAllocatedAddress(), OriginalAddr,
+ (*IRef)->getType());
+ } else {
+ EmitOMPAggregateAssign(
+ Emission.getAllocatedAddress(), OriginalAddr,
+ (*IRef)->getType(),
+ [this, VDInit, Init](llvm::Value *DestElement,
+ llvm::Value *SrcElement) {
+ // Clean up any temporaries needed by the initialization.
+ RunCleanupsScope InitScope(*this);
+ // Emit initialization for single element.
+ LocalDeclMap[VDInit] = SrcElement;
+ EmitAnyExprToMem(Init, DestElement,
+ Init->getType().getQualifiers(),
+ /*IsInitializer*/ false);
+ LocalDeclMap.erase(VDInit);
+ });
+ }
+ EmitAutoVarCleanups(Emission);
+ return Emission.getAllocatedAddress();
+ });
+ } else {
+ IsRegistered = PrivateScope.addPrivate(OrigVD, [&]() -> llvm::Value *{
+ // Emit private VarDecl with copy init.
+ // Remap temp VDInit variable to the address of the original
+ // variable
+ // (for proper handling of captured global variables).
+ LocalDeclMap[VDInit] = OriginalAddr;
+ EmitDecl(*VD);
+ LocalDeclMap.erase(VDInit);
+ return GetAddrOfLocalVar(VD);
+ });
+ }
+ assert(IsRegistered &&
+ "firstprivate var already registered as private");
+ // Silence the warning about unused variable.
+ (void)IsRegistered;
+ }
++IRef, ++InitsRef;
}
}
+ return !EmittedAsFirstprivate.empty();
}
void CodeGenFunction::EmitOMPPrivateClause(
@@ -224,9 +263,225 @@
}
}
+bool CodeGenFunction::EmitOMPCopyinClause(const OMPExecutableDirective &D) {
+ // threadprivate_var1 = master_threadprivate_var1;
+ // operator=(threadprivate_var2, master_threadprivate_var2);
+ // ...
+ // __kmpc_barrier(&loc, global_tid);
+ auto CopyinFilter = [](const OMPClause *C) -> bool {
+ return C->getClauseKind() == OMPC_copyin;
+ };
+ llvm::DenseSet<const VarDecl *> CopiedVars;
+ llvm::BasicBlock *CopyBegin = nullptr, *CopyEnd = nullptr;
+ for (OMPExecutableDirective::filtered_clause_iterator<decltype(CopyinFilter)>
+ I(D.clauses(), CopyinFilter);
+ I; ++I) {
+ auto *C = cast<OMPCopyinClause>(*I);
+ auto IRef = C->varlist_begin();
+ auto ISrcRef = C->source_exprs().begin();
+ auto IDestRef = C->destination_exprs().begin();
+ for (auto *AssignOp : C->assignment_ops()) {
+ auto *VD = cast<VarDecl>(cast<DeclRefExpr>(*IRef)->getDecl());
+ if (CopiedVars.insert(VD->getCanonicalDecl()).second) {
+ // Get the address of the master variable.
+ auto *MasterAddr = VD->isStaticLocal()
+ ? CGM.getStaticLocalDeclAddress(VD)
+ : CGM.GetAddrOfGlobal(VD);
+ // Get the address of the threadprivate variable.
+ auto *PrivateAddr = EmitLValue(*IRef).getAddress();
+ if (CopiedVars.size() == 1) {
+ // At first check if current thread is a master thread. If it is, no
+ // need to copy data.
+ CopyBegin = createBasicBlock("copyin.not.master");
+ CopyEnd = createBasicBlock("copyin.not.master.end");
+ Builder.CreateCondBr(
+ Builder.CreateICmpNE(
+ Builder.CreatePtrToInt(MasterAddr, CGM.IntPtrTy),
+ Builder.CreatePtrToInt(PrivateAddr, CGM.IntPtrTy)),
+ CopyBegin, CopyEnd);
+ EmitBlock(CopyBegin);
+ }
+ auto *SrcVD = cast<VarDecl>(cast<DeclRefExpr>(*ISrcRef)->getDecl());
+ auto *DestVD = cast<VarDecl>(cast<DeclRefExpr>(*IDestRef)->getDecl());
+ EmitOMPCopy(*this, (*IRef)->getType(), PrivateAddr, MasterAddr, DestVD,
+ SrcVD, AssignOp);
+ }
+ ++IRef;
+ ++ISrcRef;
+ ++IDestRef;
+ }
+ }
+ if (CopyEnd) {
+ // Exit out of copying procedure for non-master thread.
+ EmitBlock(CopyEnd, /*IsFinished=*/true);
+ return true;
+ }
+ return false;
+}
+
+bool CodeGenFunction::EmitOMPLastprivateClauseInit(
+ const OMPExecutableDirective &D, OMPPrivateScope &PrivateScope) {
+ auto LastprivateFilter = [](const OMPClause *C) -> bool {
+ return C->getClauseKind() == OMPC_lastprivate;
+ };
+ bool HasAtLeastOneLastprivate = false;
+ llvm::DenseSet<const VarDecl *> AlreadyEmittedVars;
+ for (OMPExecutableDirective::filtered_clause_iterator<decltype(
+ LastprivateFilter)> I(D.clauses(), LastprivateFilter);
+ I; ++I) {
+ auto *C = cast<OMPLastprivateClause>(*I);
+ auto IRef = C->varlist_begin();
+ auto IDestRef = C->destination_exprs().begin();
+ for (auto *IInit : C->private_copies()) {
+ // Keep the address of the original variable for future update at the end
+ // of the loop.
+ auto *OrigVD = cast<VarDecl>(cast<DeclRefExpr>(*IRef)->getDecl());
+ if (AlreadyEmittedVars.insert(OrigVD->getCanonicalDecl()).second) {
+ auto *DestVD = cast<VarDecl>(cast<DeclRefExpr>(*IDestRef)->getDecl());
+ PrivateScope.addPrivate(DestVD, [this, OrigVD, IRef]() -> llvm::Value *{
+ DeclRefExpr DRE(
+ const_cast<VarDecl *>(OrigVD),
+ /*RefersToEnclosingVariableOrCapture=*/CapturedStmtInfo->lookup(
+ OrigVD) != nullptr,
+ (*IRef)->getType(), VK_LValue, (*IRef)->getExprLoc());
+ return EmitLValue(&DRE).getAddress();
+ });
+ // Check if the variable is also a firstprivate: in this case IInit is
+ // not generated. Initialization of this variable will happen in codegen
+ // for 'firstprivate' clause.
+ if (!IInit)
+ continue;
+ auto *VD = cast<VarDecl>(cast<DeclRefExpr>(IInit)->getDecl());
+ bool IsRegistered =
+ PrivateScope.addPrivate(OrigVD, [&]() -> llvm::Value *{
+ // Emit private VarDecl with copy init.
+ EmitDecl(*VD);
+ return GetAddrOfLocalVar(VD);
+ });
+ assert(IsRegistered && "lastprivate var already registered as private");
+ HasAtLeastOneLastprivate = HasAtLeastOneLastprivate || IsRegistered;
+ }
+ ++IRef, ++IDestRef;
+ }
+ }
+ return HasAtLeastOneLastprivate;
+}
+
+void CodeGenFunction::EmitOMPLastprivateClauseFinal(
+ const OMPExecutableDirective &D, llvm::Value *IsLastIterCond) {
+ // Emit following code:
+ // if (<IsLastIterCond>) {
+ // orig_var1 = private_orig_var1;
+ // ...
+ // orig_varn = private_orig_varn;
+ // }
+ auto *ThenBB = createBasicBlock(".omp.lastprivate.then");
+ auto *DoneBB = createBasicBlock(".omp.lastprivate.done");
+ Builder.CreateCondBr(IsLastIterCond, ThenBB, DoneBB);
+ EmitBlock(ThenBB);
+ {
+ auto LastprivateFilter = [](const OMPClause *C) -> bool {
+ return C->getClauseKind() == OMPC_lastprivate;
+ };
+ llvm::DenseSet<const VarDecl *> AlreadyEmittedVars;
+ for (OMPExecutableDirective::filtered_clause_iterator<decltype(
+ LastprivateFilter)> I(D.clauses(), LastprivateFilter);
+ I; ++I) {
+ auto *C = cast<OMPLastprivateClause>(*I);
+ auto IRef = C->varlist_begin();
+ auto ISrcRef = C->source_exprs().begin();
+ auto IDestRef = C->destination_exprs().begin();
+ for (auto *AssignOp : C->assignment_ops()) {
+ auto *PrivateVD = cast<VarDecl>(cast<DeclRefExpr>(*IRef)->getDecl());
+ if (AlreadyEmittedVars.insert(PrivateVD->getCanonicalDecl()).second) {
+ auto *SrcVD = cast<VarDecl>(cast<DeclRefExpr>(*ISrcRef)->getDecl());
+ auto *DestVD = cast<VarDecl>(cast<DeclRefExpr>(*IDestRef)->getDecl());
+ // Get the address of the original variable.
+ auto *OriginalAddr = GetAddrOfLocalVar(DestVD);
+ // Get the address of the private variable.
+ auto *PrivateAddr = GetAddrOfLocalVar(PrivateVD);
+ EmitOMPCopy(*this, (*IRef)->getType(), OriginalAddr, PrivateAddr,
+ DestVD, SrcVD, AssignOp);
+ }
+ ++IRef;
+ ++ISrcRef;
+ ++IDestRef;
+ }
+ }
+ }
+ EmitBlock(DoneBB, /*IsFinished=*/true);
+}
+
+void CodeGenFunction::EmitOMPReductionClauseInit(
+ const OMPExecutableDirective &D,
+ CodeGenFunction::OMPPrivateScope &PrivateScope) {
+ auto ReductionFilter = [](const OMPClause *C) -> bool {
+ return C->getClauseKind() == OMPC_reduction;
+ };
+ for (OMPExecutableDirective::filtered_clause_iterator<decltype(
+ ReductionFilter)> I(D.clauses(), ReductionFilter);
+ I; ++I) {
+ auto *C = cast<OMPReductionClause>(*I);
+ auto ILHS = C->lhs_exprs().begin();
+ auto IRHS = C->rhs_exprs().begin();
+ for (auto IRef : C->varlists()) {
+ auto *OrigVD = cast<VarDecl>(cast<DeclRefExpr>(IRef)->getDecl());
+ auto *LHSVD = cast<VarDecl>(cast<DeclRefExpr>(*ILHS)->getDecl());
+ auto *PrivateVD = cast<VarDecl>(cast<DeclRefExpr>(*IRHS)->getDecl());
+ // Store the address of the original variable associated with the LHS
+ // implicit variable.
+ PrivateScope.addPrivate(LHSVD, [this, OrigVD, IRef]() -> llvm::Value *{
+ DeclRefExpr DRE(const_cast<VarDecl *>(OrigVD),
+ CapturedStmtInfo->lookup(OrigVD) != nullptr,
+ IRef->getType(), VK_LValue, IRef->getExprLoc());
+ return EmitLValue(&DRE).getAddress();
+ });
+ // Emit reduction copy.
+ bool IsRegistered =
+ PrivateScope.addPrivate(OrigVD, [this, PrivateVD]() -> llvm::Value *{
+ // Emit private VarDecl with reduction init.
+ EmitDecl(*PrivateVD);
+ return GetAddrOfLocalVar(PrivateVD);
+ });
+ assert(IsRegistered && "private var already registered as private");
+ // Silence the warning about unused variable.
+ (void)IsRegistered;
+ ++ILHS, ++IRHS;
+ }
+ }
+}
+
+void CodeGenFunction::EmitOMPReductionClauseFinal(
+ const OMPExecutableDirective &D) {
+ llvm::SmallVector<const Expr *, 8> LHSExprs;
+ llvm::SmallVector<const Expr *, 8> RHSExprs;
+ llvm::SmallVector<const Expr *, 8> ReductionOps;
+ auto ReductionFilter = [](const OMPClause *C) -> bool {
+ return C->getClauseKind() == OMPC_reduction;
+ };
+ bool HasAtLeastOneReduction = false;
+ for (OMPExecutableDirective::filtered_clause_iterator<decltype(
+ ReductionFilter)> I(D.clauses(), ReductionFilter);
+ I; ++I) {
+ HasAtLeastOneReduction = true;
+ auto *C = cast<OMPReductionClause>(*I);
+ LHSExprs.append(C->lhs_exprs().begin(), C->lhs_exprs().end());
+ RHSExprs.append(C->rhs_exprs().begin(), C->rhs_exprs().end());
+ ReductionOps.append(C->reduction_ops().begin(), C->reduction_ops().end());
+ }
+ if (HasAtLeastOneReduction) {
+ // Emit nowait reduction if nowait clause is present or directive is a
+ // parallel directive (it always has implicit barrier).
+ CGM.getOpenMPRuntime().emitReduction(
+ *this, D.getLocEnd(), LHSExprs, RHSExprs, ReductionOps,
+ D.getSingleClause(OMPC_nowait) ||
+ isOpenMPParallelDirective(D.getDirectiveKind()));
+ }
+}
+
/// \brief Emits code for OpenMP parallel directive in the parallel region.
-static void EmitOMPParallelCall(CodeGenFunction &CGF,
- const OMPParallelDirective &S,
+static void emitOMPParallelCall(CodeGenFunction &CGF,
+ const OMPExecutableDirective &S,
llvm::Value *OutlinedFn,
llvm::Value *CapturedStruct) {
if (auto C = S.getSingleClause(/*K*/ OMPC_num_threads)) {
@@ -241,22 +496,51 @@
CapturedStruct);
}
-void CodeGenFunction::EmitOMPParallelDirective(const OMPParallelDirective &S) {
+static void emitCommonOMPParallelDirective(CodeGenFunction &CGF,
+ const OMPExecutableDirective &S,
+ const RegionCodeGenTy &CodeGen) {
auto CS = cast<CapturedStmt>(S.getAssociatedStmt());
- auto CapturedStruct = GenerateCapturedStmtArgument(*CS);
- auto OutlinedFn = CGM.getOpenMPRuntime().emitOutlinedFunction(
- S, *CS->getCapturedDecl()->param_begin());
+ auto CapturedStruct = CGF.GenerateCapturedStmtArgument(*CS);
+ auto OutlinedFn = CGF.CGM.getOpenMPRuntime().emitParallelOutlinedFunction(
+ S, *CS->getCapturedDecl()->param_begin(), CodeGen);
if (auto C = S.getSingleClause(/*K*/ OMPC_if)) {
auto Cond = cast<OMPIfClause>(C)->getCondition();
- EmitOMPIfClause(*this, Cond, [&](bool ThenBlock) {
+ EmitOMPIfClause(CGF, Cond, [&](bool ThenBlock) {
if (ThenBlock)
- EmitOMPParallelCall(*this, S, OutlinedFn, CapturedStruct);
+ emitOMPParallelCall(CGF, S, OutlinedFn, CapturedStruct);
else
- CGM.getOpenMPRuntime().emitSerialCall(*this, S.getLocStart(),
- OutlinedFn, CapturedStruct);
+ CGF.CGM.getOpenMPRuntime().emitSerialCall(CGF, S.getLocStart(),
+ OutlinedFn, CapturedStruct);
});
} else
- EmitOMPParallelCall(*this, S, OutlinedFn, CapturedStruct);
+ emitOMPParallelCall(CGF, S, OutlinedFn, CapturedStruct);
+}
+
+void CodeGenFunction::EmitOMPParallelDirective(const OMPParallelDirective &S) {
+ LexicalScope Scope(*this, S.getSourceRange());
+ // Emit parallel region as a standalone region.
+ auto &&CodeGen = [&S](CodeGenFunction &CGF) {
+ OMPPrivateScope PrivateScope(CGF);
+ bool Copyins = CGF.EmitOMPCopyinClause(S);
+ bool Firstprivates = CGF.EmitOMPFirstprivateClause(S, PrivateScope);
+ if (Copyins || Firstprivates) {
+ // Emit implicit barrier to synchronize threads and avoid data races on
+ // initialization of firstprivate variables or propagation master's thread
+ // values of threadprivate variables to local instances of that variables
+ // of all other implicit threads.
+ CGF.CGM.getOpenMPRuntime().emitBarrierCall(CGF, S.getLocStart(),
+ OMPD_unknown);
+ }
+ CGF.EmitOMPPrivateClause(S, PrivateScope);
+ CGF.EmitOMPReductionClauseInit(S, PrivateScope);
+ (void)PrivateScope.Privatize();
+ CGF.EmitStmt(cast<CapturedStmt>(S.getAssociatedStmt())->getCapturedStmt());
+ CGF.EmitOMPReductionClauseFinal(S);
+ // Emit implicit barrier at the end of the 'parallel' directive.
+ CGF.CGM.getOpenMPRuntime().emitBarrierCall(CGF, S.getLocStart(),
+ OMPD_unknown);
+ };
+ emitCommonOMPParallelDirective(*this, S, CodeGen);
}
void CodeGenFunction::EmitOMPLoopBody(const OMPLoopDirective &S,
@@ -289,10 +573,10 @@
}
}
-void CodeGenFunction::EmitOMPInnerLoop(const Stmt &S, bool RequiresCleanup,
- const Expr *LoopCond,
- const Expr *IncExpr,
- const std::function<void()> &BodyGen) {
+void CodeGenFunction::EmitOMPInnerLoop(
+ const Stmt &S, bool RequiresCleanup, const Expr *LoopCond,
+ const Expr *IncExpr,
+ const llvm::function_ref<void(CodeGenFunction &)> &BodyGen) {
auto LoopExit = getJumpDestInCurrentScope("omp.inner.for.end");
auto Cnt = getPGORegionCounter(&S);
@@ -323,7 +607,7 @@
auto Continue = getJumpDestInCurrentScope("omp.inner.for.inc");
BreakContinueStack.push_back(BreakContinue(LoopExit, Continue));
- BodyGen();
+ BodyGen(*this);
// Emit "IV = IV + 1" and a back-edge to the condition block.
EmitBlock(Continue.getBlock());
@@ -414,129 +698,132 @@
}
void CodeGenFunction::EmitOMPSimdDirective(const OMPSimdDirective &S) {
- // Pragma 'simd' code depends on presence of 'lastprivate'.
- // If present, we have to separate last iteration of the loop:
- //
- // if (LastIteration != 0) {
- // for (IV in 0..LastIteration-1) BODY;
- // BODY with updates of lastprivate vars;
- // <Final counter/linear vars updates>;
- // }
- //
- // otherwise (when there's no lastprivate):
- //
- // for (IV in 0..LastIteration) BODY;
- // <Final counter/linear vars updates>;
- //
+ auto &&CodeGen = [&S](CodeGenFunction &CGF) {
+ // Pragma 'simd' code depends on presence of 'lastprivate'.
+ // If present, we have to separate last iteration of the loop:
+ //
+ // if (LastIteration != 0) {
+ // for (IV in 0..LastIteration-1) BODY;
+ // BODY with updates of lastprivate vars;
+ // <Final counter/linear vars updates>;
+ // }
+ //
+ // otherwise (when there's no lastprivate):
+ //
+ // for (IV in 0..LastIteration) BODY;
+ // <Final counter/linear vars updates>;
+ //
- // Walk clauses and process safelen/lastprivate.
- bool SeparateIter = false;
- LoopStack.setParallel();
- LoopStack.setVectorizerEnable(true);
- for (auto C : S.clauses()) {
- switch (C->getClauseKind()) {
- case OMPC_safelen: {
- RValue Len = EmitAnyExpr(cast<OMPSafelenClause>(C)->getSafelen(),
- AggValueSlot::ignored(), true);
- llvm::ConstantInt *Val = cast<llvm::ConstantInt>(Len.getScalarVal());
- LoopStack.setVectorizerWidth(Val->getZExtValue());
- // In presence of finite 'safelen', it may be unsafe to mark all
- // the memory instructions parallel, because loop-carried
- // dependences of 'safelen' iterations are possible.
- LoopStack.setParallel(false);
- break;
- }
- case OMPC_aligned:
- EmitOMPAlignedClause(*this, CGM, cast<OMPAlignedClause>(*C));
- break;
- case OMPC_lastprivate:
- SeparateIter = true;
- break;
- default:
- // Not handled yet
- ;
- }
- }
-
- InlinedOpenMPRegionScopeRAII Region(*this, S);
-
- // Emit inits for the linear variables.
- for (auto C : OMPExecutableDirective::linear_filter(S.clauses())) {
- for (auto Init : C->inits()) {
- auto *D = cast<VarDecl>(cast<DeclRefExpr>(Init)->getDecl());
- EmitVarDecl(*D);
- }
- }
-
- // Emit the loop iteration variable.
- const Expr *IVExpr = S.getIterationVariable();
- const VarDecl *IVDecl = cast<VarDecl>(cast<DeclRefExpr>(IVExpr)->getDecl());
- EmitVarDecl(*IVDecl);
- EmitIgnoredExpr(S.getInit());
-
- // Emit the iterations count variable.
- // If it is not a variable, Sema decided to calculate iterations count on each
- // iteration (e.g., it is foldable into a constant).
- if (auto LIExpr = dyn_cast<DeclRefExpr>(S.getLastIteration())) {
- EmitVarDecl(*cast<VarDecl>(LIExpr->getDecl()));
- // Emit calculation of the iterations count.
- EmitIgnoredExpr(S.getCalcLastIteration());
- }
-
- // Emit the linear steps for the linear clauses.
- // If a step is not constant, it is pre-calculated before the loop.
- for (auto C : OMPExecutableDirective::linear_filter(S.clauses())) {
- if (auto CS = cast_or_null<BinaryOperator>(C->getCalcStep()))
- if (auto SaveRef = cast<DeclRefExpr>(CS->getLHS())) {
- EmitVarDecl(*cast<VarDecl>(SaveRef->getDecl()));
- // Emit calculation of the linear step.
- EmitIgnoredExpr(CS);
+ // Walk clauses and process safelen/lastprivate.
+ bool SeparateIter = false;
+ CGF.LoopStack.setParallel();
+ CGF.LoopStack.setVectorizerEnable(true);
+ for (auto C : S.clauses()) {
+ switch (C->getClauseKind()) {
+ case OMPC_safelen: {
+ RValue Len = CGF.EmitAnyExpr(cast<OMPSafelenClause>(C)->getSafelen(),
+ AggValueSlot::ignored(), true);
+ llvm::ConstantInt *Val = cast<llvm::ConstantInt>(Len.getScalarVal());
+ CGF.LoopStack.setVectorizerWidth(Val->getZExtValue());
+ // In presence of finite 'safelen', it may be unsafe to mark all
+ // the memory instructions parallel, because loop-carried
+ // dependences of 'safelen' iterations are possible.
+ CGF.LoopStack.setParallel(false);
+ break;
}
- }
+ case OMPC_aligned:
+ EmitOMPAlignedClause(CGF, CGF.CGM, cast<OMPAlignedClause>(*C));
+ break;
+ case OMPC_lastprivate:
+ SeparateIter = true;
+ break;
+ default:
+ // Not handled yet
+ ;
+ }
+ }
- if (SeparateIter) {
- // Emit: if (LastIteration > 0) - begin.
- RegionCounter Cnt = getPGORegionCounter(&S);
- auto ThenBlock = createBasicBlock("simd.if.then");
- auto ContBlock = createBasicBlock("simd.if.end");
- EmitBranchOnBoolExpr(S.getPreCond(), ThenBlock, ContBlock, Cnt.getCount());
- EmitBlock(ThenBlock);
- Cnt.beginRegion(Builder);
- // Emit 'then' code.
- {
- OMPPrivateScope LoopScope(*this);
- EmitPrivateLoopCounters(*this, LoopScope, S.counters());
- EmitPrivateLinearVars(*this, S, LoopScope);
- EmitOMPPrivateClause(S, LoopScope);
- (void)LoopScope.Privatize();
- EmitOMPInnerLoop(S, LoopScope.requiresCleanups(),
- S.getCond(/*SeparateIter=*/true), S.getInc(),
- [&S, this]() {
- EmitOMPLoopBody(S);
- EmitStopPoint(&S);
- });
- EmitOMPLoopBody(S, /* SeparateIter */ true);
+ // Emit inits for the linear variables.
+ for (auto C : OMPExecutableDirective::linear_filter(S.clauses())) {
+ for (auto Init : C->inits()) {
+ auto *D = cast<VarDecl>(cast<DeclRefExpr>(Init)->getDecl());
+ CGF.EmitVarDecl(*D);
+ }
}
- EmitOMPSimdFinal(S);
- // Emit: if (LastIteration != 0) - end.
- EmitBranch(ContBlock);
- EmitBlock(ContBlock, true);
- } else {
- {
- OMPPrivateScope LoopScope(*this);
- EmitPrivateLoopCounters(*this, LoopScope, S.counters());
- EmitPrivateLinearVars(*this, S, LoopScope);
- EmitOMPPrivateClause(S, LoopScope);
- (void)LoopScope.Privatize();
- EmitOMPInnerLoop(S, LoopScope.requiresCleanups(),
- S.getCond(/*SeparateIter=*/false), S.getInc(),
- [&S, this]() {
- EmitOMPLoopBody(S);
- EmitStopPoint(&S);
- });
+
+ // Emit the loop iteration variable.
+ const Expr *IVExpr = S.getIterationVariable();
+ const VarDecl *IVDecl = cast<VarDecl>(cast<DeclRefExpr>(IVExpr)->getDecl());
+ CGF.EmitVarDecl(*IVDecl);
+ CGF.EmitIgnoredExpr(S.getInit());
+
+ // Emit the iterations count variable.
+ // If it is not a variable, Sema decided to calculate iterations count on
+ // each
+ // iteration (e.g., it is foldable into a constant).
+ if (auto LIExpr = dyn_cast<DeclRefExpr>(S.getLastIteration())) {
+ CGF.EmitVarDecl(*cast<VarDecl>(LIExpr->getDecl()));
+ // Emit calculation of the iterations count.
+ CGF.EmitIgnoredExpr(S.getCalcLastIteration());
}
- EmitOMPSimdFinal(S);
- }
+
+ // Emit the linear steps for the linear clauses.
+ // If a step is not constant, it is pre-calculated before the loop.
+ for (auto C : OMPExecutableDirective::linear_filter(S.clauses())) {
+ if (auto CS = cast_or_null<BinaryOperator>(C->getCalcStep()))
+ if (auto SaveRef = cast<DeclRefExpr>(CS->getLHS())) {
+ CGF.EmitVarDecl(*cast<VarDecl>(SaveRef->getDecl()));
+ // Emit calculation of the linear step.
+ CGF.EmitIgnoredExpr(CS);
+ }
+ }
+
+ if (SeparateIter) {
+ // Emit: if (LastIteration > 0) - begin.
+ RegionCounter Cnt = CGF.getPGORegionCounter(&S);
+ auto ThenBlock = CGF.createBasicBlock("simd.if.then");
+ auto ContBlock = CGF.createBasicBlock("simd.if.end");
+ CGF.EmitBranchOnBoolExpr(S.getPreCond(), ThenBlock, ContBlock,
+ Cnt.getCount());
+ CGF.EmitBlock(ThenBlock);
+ Cnt.beginRegion(CGF.Builder);
+ // Emit 'then' code.
+ {
+ OMPPrivateScope LoopScope(CGF);
+ EmitPrivateLoopCounters(CGF, LoopScope, S.counters());
+ EmitPrivateLinearVars(CGF, S, LoopScope);
+ CGF.EmitOMPPrivateClause(S, LoopScope);
+ (void)LoopScope.Privatize();
+ CGF.EmitOMPInnerLoop(S, LoopScope.requiresCleanups(),
+ S.getCond(/*SeparateIter=*/true), S.getInc(),
+ [&S](CodeGenFunction &CGF) {
+ CGF.EmitOMPLoopBody(S);
+ CGF.EmitStopPoint(&S);
+ });
+ CGF.EmitOMPLoopBody(S, /* SeparateIter */ true);
+ }
+ CGF.EmitOMPSimdFinal(S);
+ // Emit: if (LastIteration != 0) - end.
+ CGF.EmitBranch(ContBlock);
+ CGF.EmitBlock(ContBlock, true);
+ } else {
+ {
+ OMPPrivateScope LoopScope(CGF);
+ EmitPrivateLoopCounters(CGF, LoopScope, S.counters());
+ EmitPrivateLinearVars(CGF, S, LoopScope);
+ CGF.EmitOMPPrivateClause(S, LoopScope);
+ (void)LoopScope.Privatize();
+ CGF.EmitOMPInnerLoop(S, LoopScope.requiresCleanups(),
+ S.getCond(/*SeparateIter=*/false), S.getInc(),
+ [&S](CodeGenFunction &CGF) {
+ CGF.EmitOMPLoopBody(S);
+ CGF.EmitStopPoint(&S);
+ });
+ }
+ CGF.EmitOMPSimdFinal(S);
+ }
+ };
+ CGM.getOpenMPRuntime().emitInlinedDirective(*this, CodeGen);
}
void CodeGenFunction::EmitOMPForOuterLoop(OpenMPScheduleClauseKind ScheduleKind,
@@ -654,9 +941,10 @@
BreakContinueStack.push_back(BreakContinue(LoopExit, Continue));
EmitOMPInnerLoop(S, LoopScope.requiresCleanups(),
- S.getCond(/*SeparateIter=*/false), S.getInc(), [&S, this]() {
- EmitOMPLoopBody(S);
- EmitStopPoint(&S);
+ S.getCond(/*SeparateIter=*/false), S.getInc(),
+ [&S](CodeGenFunction &CGF) {
+ CGF.EmitOMPLoopBody(S);
+ CGF.EmitStopPoint(&S);
});
EmitBlock(Continue.getBlock());
@@ -686,7 +974,7 @@
return CGF.EmitLValue(Helper);
}
-void CodeGenFunction::EmitOMPWorksharingLoop(const OMPLoopDirective &S) {
+bool CodeGenFunction::EmitOMPWorksharingLoop(const OMPLoopDirective &S) {
// Emit the loop iteration variable.
auto IVExpr = cast<DeclRefExpr>(S.getIterationVariable());
auto IVDecl = cast<VarDecl>(IVExpr->getDecl());
@@ -703,6 +991,7 @@
auto &RT = CGM.getOpenMPRuntime();
+ bool HasLastprivateClause;
// Check pre-condition.
{
// Skip the entire loop if we don't meet the precondition.
@@ -725,6 +1014,13 @@
EmitOMPHelperVar(*this, cast<DeclRefExpr>(S.getIsLastIterVariable()));
OMPPrivateScope LoopScope(*this);
+ if (EmitOMPFirstprivateClause(S, LoopScope)) {
+ // Emit implicit barrier to synchronize threads and avoid data races on
+ // initialization of firstprivate variables.
+ CGM.getOpenMPRuntime().emitBarrierCall(*this, S.getLocStart(),
+ OMPD_unknown);
+ }
+ HasLastprivateClause = EmitOMPLastprivateClauseInit(S, LoopScope);
EmitPrivateLoopCounters(*this, LoopScope, S.counters());
(void)LoopScope.Privatize();
@@ -759,9 +1055,9 @@
// while (idx <= UB) { BODY; ++idx; }
EmitOMPInnerLoop(S, LoopScope.requiresCleanups(),
S.getCond(/*SeparateIter=*/false), S.getInc(),
- [&S, this]() {
- EmitOMPLoopBody(S);
- EmitStopPoint(&S);
+ [&S](CodeGenFunction &CGF) {
+ CGF.EmitOMPLoopBody(S);
+ CGF.EmitStopPoint(&S);
});
// Tell the runtime we are done.
RT.emitForFinish(*this, S.getLocStart(), ScheduleKind);
@@ -772,21 +1068,30 @@
UB.getAddress(), ST.getAddress(), IL.getAddress(),
Chunk);
}
+ // Emit final copy of the lastprivate variables if IsLastIter != 0.
+ if (HasLastprivateClause)
+ EmitOMPLastprivateClauseFinal(
+ S, Builder.CreateIsNotNull(EmitLoadOfScalar(IL, S.getLocStart())));
}
// We're now done with the loop, so jump to the continuation block.
EmitBranch(ContBlock);
EmitBlock(ContBlock, true);
}
+ return HasLastprivateClause;
}
void CodeGenFunction::EmitOMPForDirective(const OMPForDirective &S) {
- InlinedOpenMPRegionScopeRAII Region(*this, S);
-
- EmitOMPWorksharingLoop(S);
+ LexicalScope Scope(*this, S.getSourceRange());
+ bool HasLastprivates = false;
+ auto &&CodeGen = [&S, &HasLastprivates](CodeGenFunction &CGF) {
+ HasLastprivates = CGF.EmitOMPWorksharingLoop(S);
+ };
+ CGM.getOpenMPRuntime().emitInlinedDirective(*this, CodeGen);
// Emit an implicit barrier at the end.
- CGM.getOpenMPRuntime().emitBarrierCall(*this, S.getLocStart(),
- /*IsExplicit*/ false);
+ if (!S.getSingleClause(OMPC_nowait) || HasLastprivates) {
+ CGM.getOpenMPRuntime().emitBarrierCall(*this, S.getLocStart(), OMPD_for);
+ }
}
void CodeGenFunction::EmitOMPForSimdDirective(const OMPForSimdDirective &) {
@@ -802,107 +1107,122 @@
return LVal;
}
-void CodeGenFunction::EmitOMPSectionsDirective(const OMPSectionsDirective &S) {
- InlinedOpenMPRegionScopeRAII Region(*this, S);
-
+static OpenMPDirectiveKind emitSections(CodeGenFunction &CGF,
+ const OMPExecutableDirective &S) {
auto *Stmt = cast<CapturedStmt>(S.getAssociatedStmt())->getCapturedStmt();
auto *CS = dyn_cast<CompoundStmt>(Stmt);
if (CS && CS->size() > 1) {
- auto &C = CGM.getContext();
- auto KmpInt32Ty = C.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/1);
- // Emit helper vars inits.
- LValue LB = createSectionLVal(*this, KmpInt32Ty, ".omp.sections.lb.",
- Builder.getInt32(0));
- auto *GlobalUBVal = Builder.getInt32(CS->size() - 1);
- LValue UB =
- createSectionLVal(*this, KmpInt32Ty, ".omp.sections.ub.", GlobalUBVal);
- LValue ST = createSectionLVal(*this, KmpInt32Ty, ".omp.sections.st.",
- Builder.getInt32(1));
- LValue IL = createSectionLVal(*this, KmpInt32Ty, ".omp.sections.il.",
- Builder.getInt32(0));
- // Loop counter.
- LValue IV = createSectionLVal(*this, KmpInt32Ty, ".omp.sections.iv.");
- OpaqueValueExpr IVRefExpr(S.getLocStart(), KmpInt32Ty, VK_LValue);
- OpaqueValueMapping OpaqueIV(*this, &IVRefExpr, IV);
- OpaqueValueExpr UBRefExpr(S.getLocStart(), KmpInt32Ty, VK_LValue);
- OpaqueValueMapping OpaqueUB(*this, &UBRefExpr, UB);
- // Generate condition for loop.
- BinaryOperator Cond(&IVRefExpr, &UBRefExpr, BO_LE, C.BoolTy, VK_RValue,
- OK_Ordinary, S.getLocStart(), /*fpContractable=*/false);
- // Increment for loop counter.
- UnaryOperator Inc(&IVRefExpr, UO_PreInc, KmpInt32Ty, VK_RValue, OK_Ordinary,
- S.getLocStart());
- auto BodyGen = [this, CS, &S, &IV]() {
- // Iterate through all sections and emit a switch construct:
- // switch (IV) {
- // case 0:
- // <SectionStmt[0]>;
- // break;
- // ...
- // case <NumSection> - 1:
- // <SectionStmt[<NumSection> - 1]>;
- // break;
- // }
- // .omp.sections.exit:
- auto *ExitBB = createBasicBlock(".omp.sections.exit");
- auto *SwitchStmt = Builder.CreateSwitch(
- EmitLoadOfLValue(IV, S.getLocStart()).getScalarVal(), ExitBB,
- CS->size());
- unsigned CaseNumber = 0;
- for (auto C = CS->children(); C; ++C, ++CaseNumber) {
- auto CaseBB = createBasicBlock(".omp.sections.case");
- EmitBlock(CaseBB);
- SwitchStmt->addCase(Builder.getInt32(CaseNumber), CaseBB);
- EmitStmt(*C);
- EmitBranch(ExitBB);
- }
- EmitBlock(ExitBB, /*IsFinished=*/true);
+ auto &&CodeGen = [&S, CS](CodeGenFunction &CGF) {
+ auto &C = CGF.CGM.getContext();
+ auto KmpInt32Ty = C.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/1);
+ // Emit helper vars inits.
+ LValue LB = createSectionLVal(CGF, KmpInt32Ty, ".omp.sections.lb.",
+ CGF.Builder.getInt32(0));
+ auto *GlobalUBVal = CGF.Builder.getInt32(CS->size() - 1);
+ LValue UB =
+ createSectionLVal(CGF, KmpInt32Ty, ".omp.sections.ub.", GlobalUBVal);
+ LValue ST = createSectionLVal(CGF, KmpInt32Ty, ".omp.sections.st.",
+ CGF.Builder.getInt32(1));
+ LValue IL = createSectionLVal(CGF, KmpInt32Ty, ".omp.sections.il.",
+ CGF.Builder.getInt32(0));
+ // Loop counter.
+ LValue IV = createSectionLVal(CGF, KmpInt32Ty, ".omp.sections.iv.");
+ OpaqueValueExpr IVRefExpr(S.getLocStart(), KmpInt32Ty, VK_LValue);
+ CodeGenFunction::OpaqueValueMapping OpaqueIV(CGF, &IVRefExpr, IV);
+ OpaqueValueExpr UBRefExpr(S.getLocStart(), KmpInt32Ty, VK_LValue);
+ CodeGenFunction::OpaqueValueMapping OpaqueUB(CGF, &UBRefExpr, UB);
+ // Generate condition for loop.
+ BinaryOperator Cond(&IVRefExpr, &UBRefExpr, BO_LE, C.BoolTy, VK_RValue,
+ OK_Ordinary, S.getLocStart(),
+ /*fpContractable=*/false);
+ // Increment for loop counter.
+ UnaryOperator Inc(&IVRefExpr, UO_PreInc, KmpInt32Ty, VK_RValue,
+ OK_Ordinary, S.getLocStart());
+ auto BodyGen = [CS, &S, &IV](CodeGenFunction &CGF) {
+ // Iterate through all sections and emit a switch construct:
+ // switch (IV) {
+ // case 0:
+ // <SectionStmt[0]>;
+ // break;
+ // ...
+ // case <NumSection> - 1:
+ // <SectionStmt[<NumSection> - 1]>;
+ // break;
+ // }
+ // .omp.sections.exit:
+ auto *ExitBB = CGF.createBasicBlock(".omp.sections.exit");
+ auto *SwitchStmt = CGF.Builder.CreateSwitch(
+ CGF.EmitLoadOfLValue(IV, S.getLocStart()).getScalarVal(), ExitBB,
+ CS->size());
+ unsigned CaseNumber = 0;
+ for (auto C = CS->children(); C; ++C, ++CaseNumber) {
+ auto CaseBB = CGF.createBasicBlock(".omp.sections.case");
+ CGF.EmitBlock(CaseBB);
+ SwitchStmt->addCase(CGF.Builder.getInt32(CaseNumber), CaseBB);
+ CGF.EmitStmt(*C);
+ CGF.EmitBranch(ExitBB);
+ }
+ CGF.EmitBlock(ExitBB, /*IsFinished=*/true);
+ };
+ // Emit static non-chunked loop.
+ CGF.CGM.getOpenMPRuntime().emitForInit(
+ CGF, S.getLocStart(), OMPC_SCHEDULE_static, /*IVSize=*/32,
+ /*IVSigned=*/true, IL.getAddress(), LB.getAddress(), UB.getAddress(),
+ ST.getAddress());
+ // UB = min(UB, GlobalUB);
+ auto *UBVal = CGF.EmitLoadOfScalar(UB, S.getLocStart());
+ auto *MinUBGlobalUB = CGF.Builder.CreateSelect(
+ CGF.Builder.CreateICmpSLT(UBVal, GlobalUBVal), UBVal, GlobalUBVal);
+ CGF.EmitStoreOfScalar(MinUBGlobalUB, UB);
+ // IV = LB;
+ CGF.EmitStoreOfScalar(CGF.EmitLoadOfScalar(LB, S.getLocStart()), IV);
+ // while (idx <= UB) { BODY; ++idx; }
+ CGF.EmitOMPInnerLoop(S, /*RequiresCleanup=*/false, &Cond, &Inc, BodyGen);
+ // Tell the runtime we are done.
+ CGF.CGM.getOpenMPRuntime().emitForFinish(CGF, S.getLocStart(),
+ OMPC_SCHEDULE_static);
};
- // Emit static non-chunked loop.
- CGM.getOpenMPRuntime().emitForInit(
- *this, S.getLocStart(), OMPC_SCHEDULE_static, /*IVSize=*/32,
- /*IVSigned=*/true, IL.getAddress(), LB.getAddress(), UB.getAddress(),
- ST.getAddress());
- // UB = min(UB, GlobalUB);
- auto *UBVal = EmitLoadOfScalar(UB, S.getLocStart());
- auto *MinUBGlobalUB = Builder.CreateSelect(
- Builder.CreateICmpSLT(UBVal, GlobalUBVal), UBVal, GlobalUBVal);
- EmitStoreOfScalar(MinUBGlobalUB, UB);
- // IV = LB;
- EmitStoreOfScalar(EmitLoadOfScalar(LB, S.getLocStart()), IV);
- // while (idx <= UB) { BODY; ++idx; }
- EmitOMPInnerLoop(S, /*RequiresCleanup=*/false, &Cond, &Inc, BodyGen);
- // Tell the runtime we are done.
- CGM.getOpenMPRuntime().emitForFinish(*this, S.getLocStart(),
- OMPC_SCHEDULE_static);
- } else {
- // If only one section is found - no need to generate loop, emit as a single
- // region.
- CGM.getOpenMPRuntime().emitSingleRegion(*this, [&]() -> void {
- InlinedOpenMPRegionScopeRAII Region(*this, S);
- EmitStmt(Stmt);
- EnsureInsertPoint();
- }, S.getLocStart(), llvm::None, llvm::None, llvm::None, llvm::None);
- }
+ CGF.CGM.getOpenMPRuntime().emitInlinedDirective(CGF, CodeGen);
+ return OMPD_sections;
+ }
+ // If only one section is found - no need to generate loop, emit as a single
+ // region.
+ auto &&CodeGen = [Stmt](CodeGenFunction &CGF) {
+ CGF.EmitStmt(Stmt);
+ CGF.EnsureInsertPoint();
+ };
+ CGF.CGM.getOpenMPRuntime().emitSingleRegion(CGF, CodeGen, S.getLocStart(),
+ llvm::None, llvm::None,
+ llvm::None, llvm::None);
+ return OMPD_single;
+}
+
+void CodeGenFunction::EmitOMPSectionsDirective(const OMPSectionsDirective &S) {
+ LexicalScope Scope(*this, S.getSourceRange());
+ OpenMPDirectiveKind EmittedAs = emitSections(*this, S);
// Emit an implicit barrier at the end.
- if (!S.getSingleClause(OMPC_nowait))
- CGM.getOpenMPRuntime().emitBarrierCall(*this, S.getLocStart(),
- /*IsExplicit=*/false);
+ if (!S.getSingleClause(OMPC_nowait)) {
+ CGM.getOpenMPRuntime().emitBarrierCall(*this, S.getLocStart(), EmittedAs);
+ }
}
void CodeGenFunction::EmitOMPSectionDirective(const OMPSectionDirective &S) {
- InlinedOpenMPRegionScopeRAII Region(*this, S);
- EmitStmt(cast<CapturedStmt>(S.getAssociatedStmt())->getCapturedStmt());
- EnsureInsertPoint();
+ LexicalScope Scope(*this, S.getSourceRange());
+ auto &&CodeGen = [&S](CodeGenFunction &CGF) {
+ CGF.EmitStmt(cast<CapturedStmt>(S.getAssociatedStmt())->getCapturedStmt());
+ CGF.EnsureInsertPoint();
+ };
+ CGM.getOpenMPRuntime().emitInlinedDirective(*this, CodeGen);
}
void CodeGenFunction::EmitOMPSingleDirective(const OMPSingleDirective &S) {
llvm::SmallVector<const Expr *, 8> CopyprivateVars;
+ llvm::SmallVector<const Expr *, 8> DestExprs;
llvm::SmallVector<const Expr *, 8> SrcExprs;
- llvm::SmallVector<const Expr *, 8> DstExprs;
llvm::SmallVector<const Expr *, 8> AssignmentOps;
- // Check if there are any 'copyprivate' clauses associated with this 'single'
+ // Check if there are any 'copyprivate' clauses associated with this
+ // 'single'
// construct.
auto CopyprivateFilter = [](const OMPClause *C) -> bool {
return C->getClauseKind() == OMPC_copyprivate;
@@ -914,44 +1234,60 @@
for (CopyprivateIter I(S.clauses(), CopyprivateFilter); I; ++I) {
auto *C = cast<OMPCopyprivateClause>(*I);
CopyprivateVars.append(C->varlists().begin(), C->varlists().end());
+ DestExprs.append(C->destination_exprs().begin(),
+ C->destination_exprs().end());
SrcExprs.append(C->source_exprs().begin(), C->source_exprs().end());
- DstExprs.append(C->destination_exprs().begin(),
- C->destination_exprs().end());
AssignmentOps.append(C->assignment_ops().begin(),
C->assignment_ops().end());
}
+ LexicalScope Scope(*this, S.getSourceRange());
// Emit code for 'single' region along with 'copyprivate' clauses
- CGM.getOpenMPRuntime().emitSingleRegion(*this, [&]() -> void {
- InlinedOpenMPRegionScopeRAII Region(*this, S);
- EmitStmt(cast<CapturedStmt>(S.getAssociatedStmt())->getCapturedStmt());
- EnsureInsertPoint();
- }, S.getLocStart(), CopyprivateVars, SrcExprs, DstExprs, AssignmentOps);
+ auto &&CodeGen = [&S](CodeGenFunction &CGF) {
+ CGF.EmitStmt(cast<CapturedStmt>(S.getAssociatedStmt())->getCapturedStmt());
+ CGF.EnsureInsertPoint();
+ };
+ CGM.getOpenMPRuntime().emitSingleRegion(*this, CodeGen, S.getLocStart(),
+ CopyprivateVars, DestExprs, SrcExprs,
+ AssignmentOps);
// Emit an implicit barrier at the end.
- if (!S.getSingleClause(OMPC_nowait))
- CGM.getOpenMPRuntime().emitBarrierCall(*this, S.getLocStart(),
- /*IsExplicit=*/false);
+ if (!S.getSingleClause(OMPC_nowait)) {
+ CGM.getOpenMPRuntime().emitBarrierCall(*this, S.getLocStart(), OMPD_single);
+ }
}
void CodeGenFunction::EmitOMPMasterDirective(const OMPMasterDirective &S) {
- CGM.getOpenMPRuntime().emitMasterRegion(*this, [&]() -> void {
- InlinedOpenMPRegionScopeRAII Region(*this, S);
- EmitStmt(cast<CapturedStmt>(S.getAssociatedStmt())->getCapturedStmt());
- EnsureInsertPoint();
- }, S.getLocStart());
+ LexicalScope Scope(*this, S.getSourceRange());
+ auto &&CodeGen = [&S](CodeGenFunction &CGF) {
+ CGF.EmitStmt(cast<CapturedStmt>(S.getAssociatedStmt())->getCapturedStmt());
+ CGF.EnsureInsertPoint();
+ };
+ CGM.getOpenMPRuntime().emitMasterRegion(*this, CodeGen, S.getLocStart());
}
void CodeGenFunction::EmitOMPCriticalDirective(const OMPCriticalDirective &S) {
+ LexicalScope Scope(*this, S.getSourceRange());
+ auto &&CodeGen = [&S](CodeGenFunction &CGF) {
+ CGF.EmitStmt(cast<CapturedStmt>(S.getAssociatedStmt())->getCapturedStmt());
+ CGF.EnsureInsertPoint();
+ };
CGM.getOpenMPRuntime().emitCriticalRegion(
- *this, S.getDirectiveName().getAsString(), [&]() -> void {
- InlinedOpenMPRegionScopeRAII Region(*this, S);
- EmitStmt(cast<CapturedStmt>(S.getAssociatedStmt())->getCapturedStmt());
- EnsureInsertPoint();
- }, S.getLocStart());
+ *this, S.getDirectiveName().getAsString(), CodeGen, S.getLocStart());
}
-void
-CodeGenFunction::EmitOMPParallelForDirective(const OMPParallelForDirective &) {
- llvm_unreachable("CodeGen for 'omp parallel for' is not supported yet.");
+void CodeGenFunction::EmitOMPParallelForDirective(
+ const OMPParallelForDirective &S) {
+ // Emit directive as a combined directive that consists of two implicit
+ // directives: 'parallel' with 'for' directive.
+ LexicalScope Scope(*this, S.getSourceRange());
+ auto &&CodeGen = [&S](CodeGenFunction &CGF) {
+ CGF.EmitOMPWorksharingLoop(S);
+ // Emit implicit barrier at the end of parallel region, but this barrier
+ // is at the end of 'for' directive, so emit it as the implicit barrier for
+ // this 'for' directive.
+ CGF.CGM.getOpenMPRuntime().emitBarrierCall(CGF, S.getLocStart(),
+ OMPD_parallel);
+ };
+ emitCommonOMPParallelDirective(*this, S, CodeGen);
}
void CodeGenFunction::EmitOMPParallelForSimdDirective(
@@ -960,19 +1296,36 @@
}
void CodeGenFunction::EmitOMPParallelSectionsDirective(
- const OMPParallelSectionsDirective &) {
- llvm_unreachable("CodeGen for 'omp parallel sections' is not supported yet.");
+ const OMPParallelSectionsDirective &S) {
+ // Emit directive as a combined directive that consists of two implicit
+ // directives: 'parallel' with 'sections' directive.
+ LexicalScope Scope(*this, S.getSourceRange());
+ auto &&CodeGen = [&S](CodeGenFunction &CGF) {
+ (void)emitSections(CGF, S);
+ // Emit implicit barrier at the end of parallel region.
+ CGF.CGM.getOpenMPRuntime().emitBarrierCall(CGF, S.getLocStart(),
+ OMPD_parallel);
+ };
+ emitCommonOMPParallelDirective(*this, S, CodeGen);
}
void CodeGenFunction::EmitOMPTaskDirective(const OMPTaskDirective &S) {
// Emit outlined function for task construct.
+ LexicalScope Scope(*this, S.getSourceRange());
auto CS = cast<CapturedStmt>(S.getAssociatedStmt());
auto CapturedStruct = GenerateCapturedStmtArgument(*CS);
auto *I = CS->getCapturedDecl()->param_begin();
+ auto *PartId = std::next(I);
// The first function argument for tasks is a thread id, the second one is a
// part id (0 for tied tasks, >=0 for untied task).
+ auto &&CodeGen = [PartId, &S](CodeGenFunction &CGF) {
+ if (*PartId) {
+ // TODO: emit code for untied tasks.
+ }
+ CGF.EmitStmt(cast<CapturedStmt>(S.getAssociatedStmt())->getCapturedStmt());
+ };
auto OutlinedFn =
- CGM.getOpenMPRuntime().emitTaskOutlinedFunction(S, *I, *std::next(I));
+ CGM.getOpenMPRuntime().emitTaskOutlinedFunction(S, *I, CodeGen);
// Check if we should emit tied or untied task.
bool Tied = !S.getSingleClause(OMPC_untied);
// Check if the task is final
@@ -1001,7 +1354,7 @@
}
void CodeGenFunction::EmitOMPBarrierDirective(const OMPBarrierDirective &S) {
- CGM.getOpenMPRuntime().emitBarrierCall(*this, S.getLocStart());
+ CGM.getOpenMPRuntime().emitBarrierCall(*this, S.getLocStart(), OMPD_barrier);
}
void CodeGenFunction::EmitOMPTaskwaitDirective(const OMPTaskwaitDirective &) {
@@ -1116,9 +1469,156 @@
CGF.CGM.getOpenMPRuntime().emitFlush(CGF, llvm::None, Loc);
}
+bool emitOMPAtomicRMW(CodeGenFunction &CGF, LValue X, RValue Update,
+ BinaryOperatorKind BO, llvm::AtomicOrdering AO,
+ bool IsXLHSInRHSPart) {
+ auto &Context = CGF.CGM.getContext();
+ // Allow atomicrmw only if 'x' and 'update' are integer values, lvalue for 'x'
+ // expression is simple and atomic is allowed for the given type for the
+ // target platform.
+ if (BO == BO_Comma || !Update.isScalar() ||
+ !Update.getScalarVal()->getType()->isIntegerTy() || !X.isSimple() ||
+ (!isa<llvm::ConstantInt>(Update.getScalarVal()) &&
+ (Update.getScalarVal()->getType() !=
+ X.getAddress()->getType()->getPointerElementType())) ||
+ !Context.getTargetInfo().hasBuiltinAtomic(
+ Context.getTypeSize(X.getType()), Context.toBits(X.getAlignment())))
+ return false;
+
+ llvm::AtomicRMWInst::BinOp RMWOp;
+ switch (BO) {
+ case BO_Add:
+ RMWOp = llvm::AtomicRMWInst::Add;
+ break;
+ case BO_Sub:
+ if (!IsXLHSInRHSPart)
+ return false;
+ RMWOp = llvm::AtomicRMWInst::Sub;
+ break;
+ case BO_And:
+ RMWOp = llvm::AtomicRMWInst::And;
+ break;
+ case BO_Or:
+ RMWOp = llvm::AtomicRMWInst::Or;
+ break;
+ case BO_Xor:
+ RMWOp = llvm::AtomicRMWInst::Xor;
+ break;
+ case BO_LT:
+ RMWOp = X.getType()->hasSignedIntegerRepresentation()
+ ? (IsXLHSInRHSPart ? llvm::AtomicRMWInst::Min
+ : llvm::AtomicRMWInst::Max)
+ : (IsXLHSInRHSPart ? llvm::AtomicRMWInst::UMin
+ : llvm::AtomicRMWInst::UMax);
+ break;
+ case BO_GT:
+ RMWOp = X.getType()->hasSignedIntegerRepresentation()
+ ? (IsXLHSInRHSPart ? llvm::AtomicRMWInst::Max
+ : llvm::AtomicRMWInst::Min)
+ : (IsXLHSInRHSPart ? llvm::AtomicRMWInst::UMax
+ : llvm::AtomicRMWInst::UMin);
+ break;
+ case BO_Mul:
+ case BO_Div:
+ case BO_Rem:
+ case BO_Shl:
+ case BO_Shr:
+ case BO_LAnd:
+ case BO_LOr:
+ return false;
+ case BO_PtrMemD:
+ case BO_PtrMemI:
+ case BO_LE:
+ case BO_GE:
+ case BO_EQ:
+ case BO_NE:
+ case BO_Assign:
+ case BO_AddAssign:
+ case BO_SubAssign:
+ case BO_AndAssign:
+ case BO_OrAssign:
+ case BO_XorAssign:
+ case BO_MulAssign:
+ case BO_DivAssign:
+ case BO_RemAssign:
+ case BO_ShlAssign:
+ case BO_ShrAssign:
+ case BO_Comma:
+ llvm_unreachable("Unsupported atomic update operation");
+ }
+ auto *UpdateVal = Update.getScalarVal();
+ if (auto *IC = dyn_cast<llvm::ConstantInt>(UpdateVal)) {
+ UpdateVal = CGF.Builder.CreateIntCast(
+ IC, X.getAddress()->getType()->getPointerElementType(),
+ X.getType()->hasSignedIntegerRepresentation());
+ }
+ CGF.Builder.CreateAtomicRMW(RMWOp, X.getAddress(), UpdateVal, AO);
+ return true;
+}
+
+void CodeGenFunction::EmitOMPAtomicSimpleUpdateExpr(
+ LValue X, RValue E, BinaryOperatorKind BO, bool IsXLHSInRHSPart,
+ llvm::AtomicOrdering AO, SourceLocation Loc,
+ const llvm::function_ref<RValue(RValue)> &CommonGen) {
+ // Update expressions are allowed to have the following forms:
+ // x binop= expr; -> xrval + expr;
+ // x++, ++x -> xrval + 1;
+ // x--, --x -> xrval - 1;
+ // x = x binop expr; -> xrval binop expr
+ // x = expr Op x; - > expr binop xrval;
+ if (!emitOMPAtomicRMW(*this, X, E, BO, AO, IsXLHSInRHSPart)) {
+ if (X.isGlobalReg()) {
+ // Emit an update expression: 'xrval' binop 'expr' or 'expr' binop
+ // 'xrval'.
+ EmitStoreThroughLValue(CommonGen(EmitLoadOfLValue(X, Loc)), X);
+ } else {
+ // Perform compare-and-swap procedure.
+ EmitAtomicUpdate(X, AO, CommonGen, X.getType().isVolatileQualified());
+ }
+ }
+}
+
+static void EmitOMPAtomicUpdateExpr(CodeGenFunction &CGF, bool IsSeqCst,
+ const Expr *X, const Expr *E,
+ const Expr *UE, bool IsXLHSInRHSPart,
+ SourceLocation Loc) {
+ assert(isa<BinaryOperator>(UE->IgnoreImpCasts()) &&
+ "Update expr in 'atomic update' must be a binary operator.");
+ auto *BOUE = cast<BinaryOperator>(UE->IgnoreImpCasts());
+ // Update expressions are allowed to have the following forms:
+ // x binop= expr; -> xrval + expr;
+ // x++, ++x -> xrval + 1;
+ // x--, --x -> xrval - 1;
+ // x = x binop expr; -> xrval binop expr
+ // x = expr Op x; - > expr binop xrval;
+ assert(X->isLValue() && "X of 'omp atomic update' is not lvalue");
+ LValue XLValue = CGF.EmitLValue(X);
+ RValue ExprRValue = CGF.EmitAnyExpr(E);
+ auto AO = IsSeqCst ? llvm::SequentiallyConsistent : llvm::Monotonic;
+ auto *LHS = cast<OpaqueValueExpr>(BOUE->getLHS()->IgnoreImpCasts());
+ auto *RHS = cast<OpaqueValueExpr>(BOUE->getRHS()->IgnoreImpCasts());
+ auto *XRValExpr = IsXLHSInRHSPart ? LHS : RHS;
+ auto *ERValExpr = IsXLHSInRHSPart ? RHS : LHS;
+ auto Gen =
+ [&CGF, UE, ExprRValue, XRValExpr, ERValExpr](RValue XRValue) -> RValue {
+ CodeGenFunction::OpaqueValueMapping MapExpr(CGF, ERValExpr, ExprRValue);
+ CodeGenFunction::OpaqueValueMapping MapX(CGF, XRValExpr, XRValue);
+ return CGF.EmitAnyExpr(UE);
+ };
+ CGF.EmitOMPAtomicSimpleUpdateExpr(XLValue, ExprRValue, BOUE->getOpcode(),
+ IsXLHSInRHSPart, AO, Loc, Gen);
+ // OpenMP, 2.12.6, atomic Construct
+ // Any atomic construct with a seq_cst clause forces the atomically
+ // performed operation to include an implicit flush operation without a
+ // list.
+ if (IsSeqCst)
+ CGF.CGM.getOpenMPRuntime().emitFlush(CGF, llvm::None, Loc);
+}
+
static void EmitOMPAtomicExpr(CodeGenFunction &CGF, OpenMPClauseKind Kind,
bool IsSeqCst, const Expr *X, const Expr *V,
- const Expr *E, SourceLocation Loc) {
+ const Expr *E, const Expr *UE,
+ bool IsXLHSInRHSPart, SourceLocation Loc) {
switch (Kind) {
case OMPC_read:
EmitOMPAtomicReadExpr(CGF, IsSeqCst, X, V, Loc);
@@ -1126,7 +1626,10 @@
case OMPC_write:
EmitOMPAtomicWriteExpr(CGF, IsSeqCst, X, E, Loc);
break;
+ case OMPC_unknown:
case OMPC_update:
+ EmitOMPAtomicUpdateExpr(CGF, IsSeqCst, X, E, UE, IsXLHSInRHSPart, Loc);
+ break;
case OMPC_capture:
llvm_unreachable("CodeGen for 'omp atomic clause' is not supported yet.");
case OMPC_if:
@@ -1153,7 +1656,6 @@
case OMPC_untied:
case OMPC_threadprivate:
case OMPC_mergeable:
- case OMPC_unknown:
llvm_unreachable("Clause is not allowed in 'omp atomic'.");
}
}
@@ -1173,10 +1675,13 @@
S.getAssociatedStmt()->IgnoreContainers(/*IgnoreCaptured=*/true);
if (const auto *EWC = dyn_cast<ExprWithCleanups>(CS))
enterFullExpression(EWC);
- InlinedOpenMPRegionScopeRAII Region(*this, S);
- EmitOMPAtomicExpr(*this, Kind, IsSeqCst, S.getX(), S.getV(), S.getExpr(),
- S.getLocStart());
+ LexicalScope Scope(*this, S.getSourceRange());
+ auto &&CodeGen = [&S, Kind, IsSeqCst](CodeGenFunction &CGF) {
+ EmitOMPAtomicExpr(CGF, Kind, IsSeqCst, S.getX(), S.getV(), S.getExpr(),
+ S.getUpdateExpr(), S.isXLHSInRHSPart(), S.getLocStart());
+ };
+ CGM.getOpenMPRuntime().emitInlinedDirective(*this, CodeGen);
}
void CodeGenFunction::EmitOMPTargetDirective(const OMPTargetDirective &) {
diff --git a/lib/CodeGen/CGVTT.cpp b/lib/CodeGen/CGVTT.cpp
index 81bd651..895afd7 100644
--- a/lib/CodeGen/CGVTT.cpp
+++ b/lib/CodeGen/CGVTT.cpp
@@ -18,7 +18,7 @@
using namespace clang;
using namespace CodeGen;
-static llvm::Constant *
+static llvm::GlobalVariable *
GetAddrOfVTTVTable(CodeGenVTables &CGVT, CodeGenModule &CGM,
const CXXRecordDecl *MostDerivedClass,
const VTTVTable &VTable,
@@ -47,8 +47,8 @@
llvm::Type *Int8PtrTy = CGM.Int8PtrTy, *Int64Ty = CGM.Int64Ty;
llvm::ArrayType *ArrayType =
llvm::ArrayType::get(Int8PtrTy, Builder.getVTTComponents().size());
-
- SmallVector<llvm::Constant *, 8> VTables;
+
+ SmallVector<llvm::GlobalVariable *, 8> VTables;
SmallVector<VTableAddressPointsMapTy, 8> VTableAddressPoints;
for (const VTTVTable *i = Builder.getVTTVTables().begin(),
*e = Builder.getVTTVTables().end(); i != e; ++i) {
@@ -61,7 +61,7 @@
for (const VTTComponent *i = Builder.getVTTComponents().begin(),
*e = Builder.getVTTComponents().end(); i != e; ++i) {
const VTTVTable &VTTVT = Builder.getVTTVTables()[i->VTableIndex];
- llvm::Constant *VTable = VTables[i->VTableIndex];
+ llvm::GlobalVariable *VTable = VTables[i->VTableIndex];
uint64_t AddressPoint;
if (VTTVT.getBase() == RD) {
// Just get the address point for the regular vtable.
@@ -79,8 +79,8 @@
llvm::ConstantInt::get(Int64Ty, AddressPoint)
};
- llvm::Constant *Init =
- llvm::ConstantExpr::getInBoundsGetElementPtr(VTable, Idxs);
+ llvm::Constant *Init = llvm::ConstantExpr::getInBoundsGetElementPtr(
+ VTable->getValueType(), VTable, Idxs);
Init = llvm::ConstantExpr::getBitCast(Init, Int8PtrTy);
diff --git a/lib/CodeGen/CGVTables.cpp b/lib/CodeGen/CGVTables.cpp
index 372db7a..57370a6 100644
--- a/lib/CodeGen/CGVTables.cpp
+++ b/lib/CodeGen/CGVTables.cpp
@@ -842,7 +842,10 @@
void CodeGenModule::EmitVTableBitSetEntries(llvm::GlobalVariable *VTable,
const VTableLayout &VTLayout) {
- if (!LangOpts.Sanitize.has(SanitizerKind::CFIVptr))
+ if (!LangOpts.Sanitize.has(SanitizerKind::CFIVCall) &&
+ !LangOpts.Sanitize.has(SanitizerKind::CFINVCall) &&
+ !LangOpts.Sanitize.has(SanitizerKind::CFIDerivedCast) &&
+ !LangOpts.Sanitize.has(SanitizerKind::CFIUnrelatedCast))
return;
llvm::Metadata *VTableMD = llvm::ConstantAsMetadata::get(VTable);
diff --git a/lib/CodeGen/CGValue.h b/lib/CodeGen/CGValue.h
index 82cd949..9205591 100644
--- a/lib/CodeGen/CGValue.h
+++ b/lib/CodeGen/CGValue.h
@@ -19,6 +19,7 @@
#include "clang/AST/CharUnits.h"
#include "clang/AST/Type.h"
#include "llvm/IR/Value.h"
+#include "llvm/IR/Type.h"
namespace llvm {
class Constant;
@@ -299,6 +300,7 @@
LValue R;
R.LVType = Simple;
+ assert(address->getType()->isPointerTy());
R.V = address;
R.Initialize(type, qs, alignment, TBAAInfo);
return R;
diff --git a/lib/CodeGen/CodeGenAction.cpp b/lib/CodeGen/CodeGenAction.cpp
index b5ed12a..60aac07 100644
--- a/lib/CodeGen/CodeGenAction.cpp
+++ b/lib/CodeGen/CodeGenAction.cpp
@@ -46,7 +46,7 @@
const CodeGenOptions &CodeGenOpts;
const TargetOptions &TargetOpts;
const LangOptions &LangOpts;
- raw_ostream *AsmOutStream;
+ raw_pwrite_stream *AsmOutStream;
ASTContext *Context;
Timer LLVMIRGeneration;
@@ -61,7 +61,7 @@
const TargetOptions &targetopts,
const LangOptions &langopts, bool TimePasses,
const std::string &infile, llvm::Module *LinkModule,
- raw_ostream *OS, LLVMContext &C,
+ raw_pwrite_stream *OS, LLVMContext &C,
CoverageSourceInfo *CoverageInfo = nullptr)
: Diags(_Diags), Action(action), CodeGenOpts(compopts),
TargetOpts(targetopts), LangOpts(langopts), AsmOutStream(OS),
@@ -601,9 +601,8 @@
return VMContext;
}
-static raw_ostream *GetOutputStream(CompilerInstance &CI,
- StringRef InFile,
- BackendAction Action) {
+static raw_pwrite_stream *
+GetOutputStream(CompilerInstance &CI, StringRef InFile, BackendAction Action) {
switch (Action) {
case Backend_EmitAssembly:
return CI.createDefaultOutputFile(false, InFile, "s");
@@ -625,7 +624,7 @@
std::unique_ptr<ASTConsumer>
CodeGenAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
BackendAction BA = static_cast<BackendAction>(Act);
- std::unique_ptr<raw_ostream> OS(GetOutputStream(CI, InFile, BA));
+ std::unique_ptr<raw_pwrite_stream> OS(GetOutputStream(CI, InFile, BA));
if (BA != Backend_EmitNothing && !OS)
return nullptr;
@@ -678,7 +677,7 @@
if (getCurrentFileKind() == IK_LLVM_IR) {
BackendAction BA = static_cast<BackendAction>(Act);
CompilerInstance &CI = getCompilerInstance();
- raw_ostream *OS = GetOutputStream(CI, getCurrentFile(), BA);
+ raw_pwrite_stream *OS = GetOutputStream(CI, getCurrentFile(), BA);
if (BA != Backend_EmitNothing && !OS)
return;
diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
index 9e80f0a..42c3a42 100644
--- a/lib/CodeGen/CodeGenFunction.cpp
+++ b/lib/CodeGen/CodeGenFunction.cpp
@@ -40,7 +40,7 @@
CurFn(nullptr), CapturedStmtInfo(nullptr),
SanOpts(CGM.getLangOpts().Sanitize), IsSanitizerScope(false),
CurFuncIsThunk(false), AutoreleaseResult(false), SawAsmBlock(false),
- BlockInfo(nullptr), BlockPointer(nullptr),
+ IsOutlinedSEHHelper(false), BlockInfo(nullptr), BlockPointer(nullptr),
LambdaThisCaptureField(nullptr), NormalCleanupDest(nullptr),
NextCleanupDestIndex(1), FirstBlockInfo(nullptr), EHResumeBlock(nullptr),
ExceptionSlot(nullptr), EHSelectorSlot(nullptr),
@@ -70,6 +70,9 @@
if (CGM.getCodeGenOpts().NoSignedZeros) {
FMF.setNoSignedZeros();
}
+ if (CGM.getCodeGenOpts().ReciprocalMath) {
+ FMF.setAllowReciprocal();
+ }
Builder.SetFastMathFlags(FMF);
}
@@ -279,6 +282,20 @@
Builder.ClearInsertionPoint();
}
+ // If some of our locals escaped, insert a call to llvm.frameescape in the
+ // entry block.
+ if (!EscapedLocals.empty()) {
+ // Invert the map from local to index into a simple vector. There should be
+ // no holes.
+ SmallVector<llvm::Value *, 4> EscapeArgs;
+ EscapeArgs.resize(EscapedLocals.size());
+ for (auto &Pair : EscapedLocals)
+ EscapeArgs[Pair.second] = Pair.first;
+ llvm::Function *FrameEscapeFn = llvm::Intrinsic::getDeclaration(
+ &CGM.getModule(), llvm::Intrinsic::frameescape);
+ CGBuilderTy(AllocaInsertPt).CreateCall(FrameEscapeFn, EscapeArgs);
+ }
+
// Remove the AllocaInsertPt instruction, which is just a convenience for us.
llvm::Instruction *Ptr = AllocaInsertPt;
AllocaInsertPt = nullptr;
@@ -680,7 +697,7 @@
unsigned Idx = CurFnInfo->getReturnInfo().getInAllocaFieldIndex();
llvm::Function::arg_iterator EI = CurFn->arg_end();
--EI;
- llvm::Value *Addr = Builder.CreateStructGEP(EI, Idx);
+ llvm::Value *Addr = Builder.CreateStructGEP(nullptr, EI, Idx);
ReturnValue = Builder.CreateLoad(Addr, "agg.result");
} else {
ReturnValue = CreateIRTemp(RetTy, "retval");
@@ -1229,7 +1246,8 @@
/*volatile*/ false);
// Go to the next element.
- llvm::Value *next = Builder.CreateConstInBoundsGEP1_32(cur, 1, "vla.next");
+ llvm::Value *next = Builder.CreateConstInBoundsGEP1_32(Builder.getInt8Ty(),
+ cur, 1, "vla.next");
// Leave if that's the end of the VLA.
llvm::Value *done = Builder.CreateICmpEQ(next, end, "vla-init.isdone");
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index 151eb7e..4e7a7e2 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -192,7 +192,7 @@
CapturedRegionKind getKind() const { return Kind; }
- void setContextValue(llvm::Value *V) { ThisValue = V; }
+ virtual void setContextValue(llvm::Value *V) { ThisValue = V; }
// \brief Retrieve the value of the context parameter.
virtual llvm::Value *getContextValue() const { return ThisValue; }
@@ -263,6 +263,10 @@
/// potentially set the return value.
bool SawAsmBlock;
+ /// True if the current function is an outlined SEH helper. This can be a
+ /// finally block or filter expression.
+ bool IsOutlinedSEHHelper;
+
const CodeGen::CGBlockInfo *BlockInfo;
llvm::Value *BlockPointer;
@@ -351,17 +355,6 @@
void exit(CodeGenFunction &CGF);
};
- /// Cleanups can be emitted for two reasons: normal control leaving a region
- /// exceptional control flow leaving a region.
- struct SEHFinallyInfo {
- SEHFinallyInfo()
- : FinallyBB(nullptr), ContBB(nullptr), ResumeBB(nullptr) {}
-
- llvm::BasicBlock *FinallyBB;
- llvm::BasicBlock *ContBB;
- llvm::BasicBlock *ResumeBB;
- };
-
/// Returns true inside SEH __try blocks.
bool isSEHTryScope() const { return !SEHTryEpilogueStack.empty(); }
@@ -851,7 +844,8 @@
/// getByrefValueFieldNumber - Given a declaration, returns the LLVM field
/// number that holds the value.
- unsigned getByRefValueLLVMField(const ValueDecl *VD) const;
+ std::pair<llvm::Type *, unsigned>
+ getByRefValueLLVMField(const ValueDecl *VD) const;
/// BuildBlockByrefAddress - Computes address location of the
/// variable which is declared as __block.
@@ -876,6 +870,10 @@
typedef llvm::DenseMap<const Decl*, llvm::Value*> DeclMapTy;
DeclMapTy LocalDeclMap;
+ /// Track escaped local variables with auto storage. Used during SEH
+ /// outlining to produce a call to llvm.frameescape.
+ llvm::DenseMap<llvm::AllocaInst *, int> EscapedLocals;
+
/// LabelMap - This keeps track of the LLVM basic block for each C label.
llvm::DenseMap<const LabelDecl*, JumpDest> LabelMap;
@@ -1047,10 +1045,6 @@
llvm::Value *getExceptionSlot();
llvm::Value *getEHSelectorSlot();
- /// Stack slot that contains whether a __finally block is being executed as an
- /// EH cleanup or as a normal cleanup.
- llvm::Value *getAbnormalTerminationSlot();
-
/// Returns the contents of the function's exception object and selector
/// slots.
llvm::Value *getExceptionFromSlot();
@@ -1729,7 +1723,8 @@
llvm::Value *This);
void EmitNewArrayInitializer(const CXXNewExpr *E, QualType elementType,
- llvm::Value *NewPtr, llvm::Value *NumElements,
+ llvm::Type *ElementTy, llvm::Value *NewPtr,
+ llvm::Value *NumElements,
llvm::Value *AllocSizeWithoutCookie);
void EmitCXXTemporary(const CXXTemporary *Temporary, QualType TempType,
@@ -1895,8 +1890,8 @@
llvm::Value *getObjectAddress(CodeGenFunction &CGF) const {
if (!IsByRef) return Address;
- return CGF.Builder.CreateStructGEP(Address,
- CGF.getByRefValueLLVMField(Variable),
+ auto F = CGF.getByRefValueLLVMField(Variable);
+ return CGF.Builder.CreateStructGEP(F.first, Address, F.second,
Variable->getNameAsString());
}
};
@@ -1994,17 +1989,30 @@
void EmitCXXTryStmt(const CXXTryStmt &S);
void EmitSEHTryStmt(const SEHTryStmt &S);
void EmitSEHLeaveStmt(const SEHLeaveStmt &S);
- void EnterSEHTryStmt(const SEHTryStmt &S, SEHFinallyInfo &FI);
- void ExitSEHTryStmt(const SEHTryStmt &S, SEHFinallyInfo &FI);
+ void EnterSEHTryStmt(const SEHTryStmt &S);
+ void ExitSEHTryStmt(const SEHTryStmt &S);
+
+ void startOutlinedSEHHelper(CodeGenFunction &ParentCGF, StringRef Name,
+ QualType RetTy, FunctionArgList &Args,
+ const Stmt *OutlinedStmt);
llvm::Function *GenerateSEHFilterFunction(CodeGenFunction &ParentCGF,
const SEHExceptStmt &Except);
+ llvm::Function *GenerateSEHFinallyFunction(CodeGenFunction &ParentCGF,
+ const SEHFinallyStmt &Finally);
+
void EmitSEHExceptionCodeSave();
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.
+ void EmitCapturedLocals(CodeGenFunction &ParentCGF, const Stmt *OutlinedStmt,
+ llvm::Value *ParentFP);
+
void EmitCXXForRangeStmt(const CXXForRangeStmt &S,
ArrayRef<const Attr *> Attrs = None);
@@ -2014,13 +2022,100 @@
llvm::Function *GenerateCapturedStmtFunctionEpilog(const CapturedStmt &S);
llvm::Function *GenerateCapturedStmtFunction(const CapturedStmt &S);
llvm::Value *GenerateCapturedStmtArgument(const CapturedStmt &S);
- void EmitOMPAggregateAssign(LValue OriginalAddr, llvm::Value *PrivateAddr,
- const Expr *AssignExpr, QualType Type,
- const VarDecl *VDInit);
- void EmitOMPFirstprivateClause(const OMPExecutableDirective &D,
+ /// \brief Perform element by element copying of arrays with type \a
+ /// OriginalType from \a SrcAddr to \a DestAddr using copying procedure
+ /// generated by \a CopyGen.
+ ///
+ /// \param DestAddr Address of the destination array.
+ /// \param SrcAddr Address of the source array.
+ /// \param OriginalType Type of destination and source arrays.
+ /// \param CopyGen Copying procedure that copies value of single array element
+ /// to another single array element.
+ void EmitOMPAggregateAssign(
+ llvm::Value *DestAddr, llvm::Value *SrcAddr, QualType OriginalType,
+ const llvm::function_ref<void(llvm::Value *, llvm::Value *)> &CopyGen);
+ /// \brief Emit proper copying of data from one variable to another.
+ ///
+ /// \param OriginalType Original type of the copied variables.
+ /// \param DestAddr Destination address.
+ /// \param SrcAddr Source address.
+ /// \param DestVD Destination variable used in \a CopyExpr (for arrays, has
+ /// type of the base array element).
+ /// \param SrcVD Source variable used in \a CopyExpr (for arrays, has type of
+ /// the base array element).
+ /// \param Copy Actual copygin expression for copying data from \a SrcVD to \a
+ /// DestVD.
+ void EmitOMPCopy(CodeGenFunction &CGF, QualType OriginalType,
+ llvm::Value *DestAddr, llvm::Value *SrcAddr,
+ const VarDecl *DestVD, const VarDecl *SrcVD,
+ const Expr *Copy);
+ /// \brief Emit atomic update code for constructs: \a X = \a X \a BO \a E or
+ /// \a X = \a E \a BO \a E.
+ ///
+ /// \param X Value to be updated.
+ /// \param E Update value.
+ /// \param BO Binary operation for update operation.
+ /// \param IsXLHSInRHSPart true if \a X is LHS in RHS part of the update
+ /// expression, false otherwise.
+ /// \param AO Atomic ordering of the generated atomic instructions.
+ /// \param CommonGen Code generator for complex expressions that cannot be
+ /// expressed through atomicrmw instruction.
+ void EmitOMPAtomicSimpleUpdateExpr(
+ LValue X, RValue E, BinaryOperatorKind BO, bool IsXLHSInRHSPart,
+ llvm::AtomicOrdering AO, SourceLocation Loc,
+ const llvm::function_ref<RValue(RValue)> &CommonGen);
+ bool EmitOMPFirstprivateClause(const OMPExecutableDirective &D,
OMPPrivateScope &PrivateScope);
void EmitOMPPrivateClause(const OMPExecutableDirective &D,
OMPPrivateScope &PrivateScope);
+ /// \brief Emit code for copyin clause in \a D directive. The next code is
+ /// generated at the start of outlined functions for directives:
+ /// \code
+ /// threadprivate_var1 = master_threadprivate_var1;
+ /// operator=(threadprivate_var2, master_threadprivate_var2);
+ /// ...
+ /// __kmpc_barrier(&loc, global_tid);
+ /// \endcode
+ ///
+ /// \param D OpenMP directive possibly with 'copyin' clause(s).
+ /// \returns true if at least one copyin variable is found, false otherwise.
+ bool EmitOMPCopyinClause(const OMPExecutableDirective &D);
+ /// \brief Emit initial code for lastprivate variables. If some variable is
+ /// not also firstprivate, then the default initialization is used. Otherwise
+ /// initialization of this variable is performed by EmitOMPFirstprivateClause
+ /// method.
+ ///
+ /// \param D Directive that may have 'lastprivate' directives.
+ /// \param PrivateScope Private scope for capturing lastprivate variables for
+ /// proper codegen in internal captured statement.
+ ///
+ /// \returns true if there is at least one lastprivate variable, false
+ /// otherwise.
+ bool EmitOMPLastprivateClauseInit(const OMPExecutableDirective &D,
+ OMPPrivateScope &PrivateScope);
+ /// \brief Emit final copying of lastprivate values to original variables at
+ /// the end of the worksharing or simd directive.
+ ///
+ /// \param D Directive that has at least one 'lastprivate' directives.
+ /// \param IsLastIterCond Boolean condition that must be set to 'i1 true' if
+ /// it is the last iteration of the loop code in associated directive, or to
+ /// 'i1 false' otherwise.
+ void EmitOMPLastprivateClauseFinal(const OMPExecutableDirective &D,
+ llvm::Value *IsLastIterCond);
+ /// \brief Emit initial code for reduction variables. Creates reduction copies
+ /// and initializes them with the values according to OpenMP standard.
+ ///
+ /// \param D Directive (possibly) with the 'reduction' clause.
+ /// \param PrivateScope Private scope for capturing reduction variables for
+ /// proper codegen in internal captured statement.
+ ///
+ void EmitOMPReductionClauseInit(const OMPExecutableDirective &D,
+ OMPPrivateScope &PrivateScope);
+ /// \brief Emit final update of reduction values to original variables at
+ /// the end of the directive.
+ ///
+ /// \param D Directive that has at least one 'reduction' directives.
+ void EmitOMPReductionClauseFinal(const OMPExecutableDirective &D);
void EmitOMPParallelDirective(const OMPParallelDirective &S);
void EmitOMPSimdDirective(const OMPSimdDirective &S);
@@ -2044,16 +2139,21 @@
void EmitOMPTargetDirective(const OMPTargetDirective &S);
void EmitOMPTeamsDirective(const OMPTeamsDirective &S);
+ void
+ EmitOMPInnerLoop(const Stmt &S, bool RequiresCleanup, const Expr *LoopCond,
+ const Expr *IncExpr,
+ const llvm::function_ref<void(CodeGenFunction &)> &BodyGen);
+
private:
/// Helpers for the OpenMP loop directives.
void EmitOMPLoopBody(const OMPLoopDirective &Directive,
bool SeparateIter = false);
- void EmitOMPInnerLoop(const Stmt &S, bool RequiresCleanup,
- const Expr *LoopCond, const Expr *IncExpr,
- const std::function<void()> &BodyGen);
void EmitOMPSimdFinal(const OMPLoopDirective &S);
- void EmitOMPWorksharingLoop(const OMPLoopDirective &S);
+ /// \brief Emit code for the worksharing loop-based directive.
+ /// \return true, if this construct has any lastprivate clause, false -
+ /// otherwise.
+ bool EmitOMPWorksharingLoop(const OMPLoopDirective &S);
void EmitOMPForOuterLoop(OpenMPScheduleClauseKind ScheduleKind,
const OMPLoopDirective &S,
OMPPrivateScope &LoopScope, llvm::Value *LB,
@@ -2123,12 +2223,16 @@
void EmitAtomicStore(RValue rvalue, LValue lvalue, llvm::AtomicOrdering AO,
bool IsVolatile, bool isInit);
- std::pair<RValue, RValue> EmitAtomicCompareExchange(
+ std::pair<RValue, llvm::Value *> EmitAtomicCompareExchange(
LValue Obj, RValue Expected, RValue Desired, SourceLocation Loc,
llvm::AtomicOrdering Success = llvm::SequentiallyConsistent,
llvm::AtomicOrdering Failure = llvm::SequentiallyConsistent,
bool IsWeak = false, AggValueSlot Slot = AggValueSlot::ignored());
+ void EmitAtomicUpdate(LValue LVal, llvm::AtomicOrdering AO,
+ const std::function<RValue(RValue)> &UpdateOp,
+ bool IsVolatile);
+
/// EmitToMemory - Change a scalar value from its value
/// representation to its in-memory representation.
llvm::Value *EmitToMemory(llvm::Value *Value, QualType Ty);
@@ -2430,6 +2534,7 @@
llvm::Value *EmitX86BuiltinExpr(unsigned BuiltinID, const CallExpr *E);
llvm::Value *EmitPPCBuiltinExpr(unsigned BuiltinID, const CallExpr *E);
llvm::Value *EmitR600BuiltinExpr(unsigned BuiltinID, const CallExpr *E);
+ llvm::Value *EmitSystemZBuiltinExpr(unsigned BuiltinID, const CallExpr *E);
llvm::Value *EmitObjCProtocolExpr(const ObjCProtocolExpr *E);
llvm::Value *EmitObjCStringLiteral(const ObjCStringLiteral *E);
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index f4ae684..17b7ddc 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -147,8 +147,8 @@
unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
"Could not read profile: %0");
getDiags().Report(DiagID) << EC.message();
- }
- PGOReader = std::move(ReaderOrErr.get());
+ } else
+ PGOReader = std::move(ReaderOrErr.get());
}
// If coverage mapping generation is enabled, create the
@@ -2134,7 +2134,8 @@
}
static bool isVarDeclStrongDefinition(const ASTContext &Context,
- const VarDecl *D, bool NoCommon) {
+ CodeGenModule &CGM, const VarDecl *D,
+ bool NoCommon) {
// Don't give variables common linkage if -fno-common was specified unless it
// was overridden by a NoCommon attribute.
if ((NoCommon || D->hasAttr<NoCommonAttr>()) && !D->hasAttr<CommonAttr>())
@@ -2159,6 +2160,10 @@
if (D->hasAttr<WeakImportAttr>())
return true;
+ // A variable cannot be both common and exist in a comdat.
+ if (shouldBeInCOMDAT(CGM, *D))
+ return true;
+
// Declarations with a required alignment do not have common linakge in MSVC
// mode.
if (Context.getLangOpts().MSVCCompat) {
@@ -2227,7 +2232,7 @@
// C++ doesn't have tentative definitions and thus cannot have common
// linkage.
if (!getLangOpts().CPlusPlus && isa<VarDecl>(D) &&
- !isVarDeclStrongDefinition(Context, cast<VarDecl>(D),
+ !isVarDeclStrongDefinition(Context, *this, cast<VarDecl>(D),
CodeGenOpts.NoCommon))
return llvm::GlobalVariable::CommonLinkage;
@@ -2350,7 +2355,7 @@
callSite->replaceAllUsesWith(newCall.getInstruction());
// Copy debug location attached to CI.
- if (!callSite->getDebugLoc().isUnknown())
+ if (callSite->getDebugLoc())
newCall->setDebugLoc(callSite->getDebugLoc());
callSite->eraseFromParent();
}
@@ -2564,12 +2569,10 @@
Tys);
}
-static llvm::StringMapEntry<llvm::Constant*> &
-GetConstantCFStringEntry(llvm::StringMap<llvm::Constant*> &Map,
- const StringLiteral *Literal,
- bool TargetIsLSB,
- bool &IsUTF16,
- unsigned &StringLength) {
+static llvm::StringMapEntry<llvm::GlobalVariable *> &
+GetConstantCFStringEntry(llvm::StringMap<llvm::GlobalVariable *> &Map,
+ const StringLiteral *Literal, bool TargetIsLSB,
+ bool &IsUTF16, unsigned &StringLength) {
StringRef String = Literal->getString();
unsigned NumBytes = String.size();
@@ -2601,10 +2604,9 @@
nullptr)).first;
}
-static llvm::StringMapEntry<llvm::Constant*> &
-GetConstantStringEntry(llvm::StringMap<llvm::Constant*> &Map,
- const StringLiteral *Literal,
- unsigned &StringLength) {
+static llvm::StringMapEntry<llvm::GlobalVariable *> &
+GetConstantStringEntry(llvm::StringMap<llvm::GlobalVariable *> &Map,
+ const StringLiteral *Literal, unsigned &StringLength) {
StringRef String = Literal->getString();
StringLength = String.size();
return *Map.insert(std::make_pair(String, nullptr)).first;
@@ -2614,10 +2616,10 @@
CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) {
unsigned StringLength = 0;
bool isUTF16 = false;
- llvm::StringMapEntry<llvm::Constant*> &Entry =
- GetConstantCFStringEntry(CFConstantStringMap, Literal,
- getDataLayout().isLittleEndian(),
- isUTF16, StringLength);
+ llvm::StringMapEntry<llvm::GlobalVariable *> &Entry =
+ GetConstantCFStringEntry(CFConstantStringMap, Literal,
+ getDataLayout().isLittleEndian(), isUTF16,
+ StringLength);
if (auto *C = Entry.second)
return C;
@@ -2633,7 +2635,7 @@
llvm::Constant *GV = CreateRuntimeVariable(Ty,
"__CFConstantStringClassReference");
// Decay array -> ptr
- V = llvm::ConstantExpr::getGetElementPtr(GV, Zeros);
+ V = llvm::ConstantExpr::getGetElementPtr(Ty, GV, Zeros);
CFConstantStringClassRef = V;
}
else
@@ -2686,7 +2688,7 @@
}
// String.
- Fields[2] = llvm::ConstantExpr::getGetElementPtr(GV, Zeros);
+ Fields[2] = llvm::ConstantExpr::getGetElementPtr(GV->getType(), GV, Zeros);
if (isUTF16)
// Cast the UTF16 string to the correct type.
@@ -2707,11 +2709,11 @@
return GV;
}
-llvm::Constant *
+llvm::GlobalVariable *
CodeGenModule::GetAddrOfConstantString(const StringLiteral *Literal) {
unsigned StringLength = 0;
- llvm::StringMapEntry<llvm::Constant*> &Entry =
- GetConstantStringEntry(CFConstantStringMap, Literal, StringLength);
+ llvm::StringMapEntry<llvm::GlobalVariable *> &Entry =
+ GetConstantStringEntry(CFConstantStringMap, Literal, StringLength);
if (auto *C = Entry.second)
return C;
@@ -2740,11 +2742,10 @@
llvm::Type *PTy = llvm::ArrayType::get(Ty, 0);
GV = CreateRuntimeVariable(PTy, str);
// Decay array -> ptr
- V = llvm::ConstantExpr::getGetElementPtr(GV, Zeros);
+ V = llvm::ConstantExpr::getGetElementPtr(PTy, GV, Zeros);
ConstantStringClassRef = V;
}
- }
- else
+ } else
V = ConstantStringClassRef;
if (!NSConstantStringType) {
@@ -2800,8 +2801,9 @@
// of the string is via this class initializer.
CharUnits Align = getContext().getTypeAlignInChars(getContext().CharTy);
GV->setAlignment(Align.getQuantity());
- Fields[1] = llvm::ConstantExpr::getGetElementPtr(GV, Zeros);
-
+ Fields[1] =
+ llvm::ConstantExpr::getGetElementPtr(GV->getValueType(), GV, Zeros);
+
// String length.
llvm::Type *Ty = getTypes().ConvertType(getContext().UnsignedIntTy);
Fields[2] = llvm::ConstantInt::get(Ty, StringLength);
@@ -3433,7 +3435,7 @@
void CodeGenModule::EmitDeferredUnusedCoverageMappings() {
std::vector<const Decl *> DeferredDecls;
- for (const auto I : DeferredEmptyCoverageMappingDecls) {
+ for (const auto &I : DeferredEmptyCoverageMappingDecls) {
if (!I.second)
continue;
DeferredDecls.push_back(I.first);
@@ -3638,9 +3640,9 @@
}
llvm::Constant *
-CodeGenModule::getAddrOfCXXHandlerMapEntry(QualType Ty,
- QualType CatchHandlerType) {
- return getCXXABI().getAddrOfCXXHandlerMapEntry(Ty, CatchHandlerType);
+CodeGenModule::getAddrOfCXXCatchHandlerType(QualType Ty,
+ QualType CatchHandlerType) {
+ return getCXXABI().getAddrOfCXXCatchHandlerType(Ty, CatchHandlerType);
}
llvm::Constant *CodeGenModule::GetAddrOfRTTIDescriptor(QualType Ty,
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
index ce540e9..feef6c2 100644
--- a/lib/CodeGen/CodeGenModule.h
+++ b/lib/CodeGen/CodeGenModule.h
@@ -366,7 +366,7 @@
/// Map used to get unique annotation strings.
llvm::StringMap<llvm::Constant*> AnnotationStrings;
- llvm::StringMap<llvm::Constant*> CFConstantStringMap;
+ llvm::StringMap<llvm::GlobalVariable *> CFConstantStringMap;
llvm::DenseMap<llvm::Constant *, llvm::GlobalVariable *> ConstantStringMap;
llvm::DenseMap<const Decl*, llvm::Constant *> StaticLocalDeclMap;
@@ -400,7 +400,8 @@
/// When a C++ decl with an initializer is deferred, null is
/// appended to CXXGlobalInits, and the index of that null is placed
/// here so that the initializer will be performed in the correct
- /// order.
+ /// order. Once the decl is emitted, the index is replaced with ~0U to ensure
+ /// that we don't re-emit the initializer.
llvm::DenseMap<const Decl*, unsigned> DelayedCXXInitPosition;
typedef std::pair<OrderGlobalInits, llvm::Function*> GlobalInitData;
@@ -719,8 +720,8 @@
/// Get the address of the RTTI descriptor for the given type.
llvm::Constant *GetAddrOfRTTIDescriptor(QualType Ty, bool ForEH = false);
- llvm::Constant *getAddrOfCXXHandlerMapEntry(QualType Ty,
- QualType CatchHandlerType);
+ llvm::Constant *getAddrOfCXXCatchHandlerType(QualType Ty,
+ QualType CatchHandlerType);
/// Get the address of a uuid descriptor .
llvm::Constant *GetAddrOfUuidDescriptor(const CXXUuidofExpr* E);
@@ -786,7 +787,7 @@
/// Return a pointer to a constant NSString object for the given string. Or a
/// user defined String object as defined via
/// -fconstant-string-class=class_name option.
- llvm::Constant *GetAddrOfConstantString(const StringLiteral *Literal);
+ llvm::GlobalVariable *GetAddrOfConstantString(const StringLiteral *Literal);
/// Return a constant array for the given string.
llvm::Constant *GetConstantArrayFromStringLiteral(const StringLiteral *E);
diff --git a/lib/CodeGen/CodeGenPGO.cpp b/lib/CodeGen/CodeGenPGO.cpp
index 557828d..cc6ac20 100644
--- a/lib/CodeGen/CodeGenPGO.cpp
+++ b/lib/CodeGen/CodeGenPGO.cpp
@@ -880,12 +880,10 @@
if (!haveRegionCounts())
return nullptr;
uint64_t LoopCount = Cnt.getCount();
- uint64_t CondCount = 0;
- bool Found = getStmtCount(Cond, CondCount);
- assert(Found && "missing expected loop condition count");
- (void)Found;
- if (CondCount == 0)
+ Optional<uint64_t> CondCount = getStmtCount(Cond);
+ assert(CondCount.hasValue() && "missing expected loop condition count");
+ if (*CondCount == 0)
return nullptr;
return createBranchWeights(LoopCount,
- std::max(CondCount, LoopCount) - LoopCount);
+ std::max(*CondCount, LoopCount) - LoopCount);
}
diff --git a/lib/CodeGen/CodeGenPGO.h b/lib/CodeGen/CodeGenPGO.h
index 431c850..c92a057 100644
--- a/lib/CodeGen/CodeGenPGO.h
+++ b/lib/CodeGen/CodeGenPGO.h
@@ -69,23 +69,20 @@
/// Check if an execution count is known for a given statement. If so, return
/// true and put the value in Count; else return false.
- bool getStmtCount(const Stmt *S, uint64_t &Count) {
+ Optional<uint64_t> getStmtCount(const Stmt *S) {
if (!StmtCountMap)
- return false;
- llvm::DenseMap<const Stmt*, uint64_t>::const_iterator
- I = StmtCountMap->find(S);
+ return None;
+ auto I = StmtCountMap->find(S);
if (I == StmtCountMap->end())
- return false;
- Count = I->second;
- return true;
+ return None;
+ return I->second;
}
/// If the execution count for the current statement is known, record that
/// as the current count.
void setCurrentStmt(const Stmt *S) {
- uint64_t Count;
- if (getStmtCount(S, Count))
- setCurrentRegionCount(Count);
+ if (auto Count = getStmtCount(S))
+ setCurrentRegionCount(*Count);
}
/// Calculate branch weights appropriate for PGO data
diff --git a/lib/CodeGen/CoverageMappingGen.cpp b/lib/CodeGen/CoverageMappingGen.cpp
index 07db6c7..d26eced 100644
--- a/lib/CodeGen/CoverageMappingGen.cpp
+++ b/lib/CodeGen/CoverageMappingGen.cpp
@@ -748,7 +748,7 @@
size_t Index =
pushRegion(Counter::getZero(), getStart(CS->body_front()),
getEnd(CS->body_back()));
- for (const auto &Child : CS->children())
+ for (const auto *Child : CS->children())
Visit(Child);
popRegions(Index);
}
diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp
index f23cd9f..eb7ab1d 100644
--- a/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/lib/CodeGen/ItaniumCXXABI.cpp
@@ -127,7 +127,8 @@
void EmitFundamentalRTTIDescriptors();
llvm::Constant *getAddrOfRTTIDescriptor(QualType Ty) override;
llvm::Constant *
- getAddrOfCXXHandlerMapEntry(QualType Ty, QualType CatchHandlerType) override {
+ getAddrOfCXXCatchHandlerType(QualType Ty,
+ QualType CatchHandlerType) override {
return getAddrOfRTTIDescriptor(Ty);
}
@@ -1387,7 +1388,7 @@
llvm::Constant *ItaniumCXXABI::getVTableAddressPointForConstExpr(
BaseSubobject Base, const CXXRecordDecl *VTableClass) {
- llvm::Constant *VTable = getAddrOfVTable(VTableClass, CharUnits());
+ auto *VTable = getAddrOfVTable(VTableClass, CharUnits());
// Find the appropriate vtable within the vtable group.
uint64_t AddressPoint = CGM.getItaniumVTableContext()
@@ -1398,7 +1399,8 @@
llvm::ConstantInt::get(CGM.Int64Ty, AddressPoint)
};
- return llvm::ConstantExpr::getInBoundsGetElementPtr(VTable, Indices);
+ return llvm::ConstantExpr::getInBoundsGetElementPtr(VTable->getValueType(),
+ VTable, Indices);
}
llvm::GlobalVariable *ItaniumCXXABI::getAddrOfVTable(const CXXRecordDecl *RD,
@@ -1442,7 +1444,8 @@
Ty = Ty->getPointerTo()->getPointerTo();
llvm::Value *VTable = CGF.GetVTablePtr(This, Ty);
- CGF.EmitVTablePtrCheckForCall(cast<CXXMethodDecl>(GD.getDecl()), VTable);
+ if (CGF.SanOpts.has(SanitizerKind::CFIVCall))
+ CGF.EmitVTablePtrCheckForCall(cast<CXXMethodDecl>(GD.getDecl()), VTable);
uint64_t VTableIndex = CGM.getItaniumVTableContext().getMethodVTableIndex(GD);
llvm::Value *VFuncPtr =
@@ -1666,7 +1669,7 @@
CGF.Builder.CreateStore(elementSize, cookie);
// The second element is the element count.
- cookie = CGF.Builder.CreateConstInBoundsGEP1_32(cookie, 1);
+ cookie = CGF.Builder.CreateConstInBoundsGEP1_32(CGF.SizeTy, cookie, 1);
CGF.Builder.CreateStore(numElements, cookie);
// Finally, compute a pointer to the actual data buffer by skipping
@@ -2604,7 +2607,8 @@
// The vtable address point is 2.
llvm::Constant *Two = llvm::ConstantInt::get(PtrDiffTy, 2);
- VTable = llvm::ConstantExpr::getInBoundsGetElementPtr(VTable, Two);
+ VTable =
+ llvm::ConstantExpr::getInBoundsGetElementPtr(CGM.Int8PtrTy, VTable, Two);
VTable = llvm::ConstantExpr::getBitCast(VTable, CGM.Int8PtrTy);
Fields.push_back(VTable);
diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp b/lib/CodeGen/MicrosoftCXXABI.cpp
index f8f7845..f00cd9c 100644
--- a/lib/CodeGen/MicrosoftCXXABI.cpp
+++ b/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -45,7 +45,7 @@
: CGCXXABI(CGM), BaseClassDescriptorType(nullptr),
ClassHierarchyDescriptorType(nullptr),
CompleteObjectLocatorType(nullptr), CatchableTypeType(nullptr),
- ThrowInfoType(nullptr), HandlerMapEntryType(nullptr) {}
+ ThrowInfoType(nullptr), CatchHandlerTypeType(nullptr) {}
bool HasThisReturn(GlobalDecl GD) const override;
bool hasMostDerivedReturn(GlobalDecl GD) const override;
@@ -85,7 +85,7 @@
llvm::Constant *getAddrOfRTTIDescriptor(QualType Ty) override;
llvm::Constant *
- getAddrOfCXXHandlerMapEntry(QualType Ty, QualType CatchHandlerType) override;
+ getAddrOfCXXCatchHandlerType(QualType Ty, QualType CatchHandlerType) override;
bool shouldTypeidBeNullChecked(bool IsDeref, QualType SrcRecordTy) override;
void EmitBadTypeidCall(CodeGenFunction &CGF) override;
@@ -573,16 +573,16 @@
void emitCXXStructor(const CXXMethodDecl *MD, StructorType Type) override;
- llvm::StructType *getHandlerMapEntryType() {
- if (!HandlerMapEntryType) {
+ llvm::StructType *getCatchHandlerTypeType() {
+ if (!CatchHandlerTypeType) {
llvm::Type *FieldTypes[] = {
- CGM.IntTy, // Flags
- getImageRelativeType(CGM.Int8PtrTy), // TypeDescriptor
+ CGM.IntTy, // Flags
+ CGM.Int8PtrTy, // TypeDescriptor
};
- HandlerMapEntryType = llvm::StructType::create(
- CGM.getLLVMContext(), FieldTypes, "eh.HandlerMapEntry");
+ CatchHandlerTypeType = llvm::StructType::create(
+ CGM.getLLVMContext(), FieldTypes, "eh.CatchHandlerType");
}
- return HandlerMapEntryType;
+ return CatchHandlerTypeType;
}
llvm::StructType *getCatchableTypeType() {
@@ -698,7 +698,7 @@
llvm::StructType *CatchableTypeType;
llvm::DenseMap<uint32_t, llvm::StructType *> CatchableTypeArrayTypeMap;
llvm::StructType *ThrowInfoType;
- llvm::StructType *HandlerMapEntryType;
+ llvm::StructType *CatchHandlerTypeType;
};
}
@@ -809,7 +809,9 @@
llvm::Function *BeginCatch =
CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_begincatch);
- if (!CatchParam) {
+ // If this is a catch-all or the catch parameter is unnamed, we don't need to
+ // emit an alloca to the object.
+ if (!CatchParam || !CatchParam->getDeclName()) {
llvm::Value *Args[2] = {Exn, llvm::Constant::getNullValue(CGF.Int8PtrTy)};
CGF.EmitNounwindRuntimeCall(BeginCatch, Args);
CGF.EHStack.pushCleanup<CallEndCatchMSVC>(NormalAndEHCleanup);
@@ -1121,7 +1123,8 @@
Offs += Layout.getVBaseClassOffset(VBT->getVBaseWithVPtr());
llvm::Value *VBPtr =
CGF.Builder.CreateConstInBoundsGEP1_64(ThisInt8Ptr, Offs.getQuantity());
- llvm::Value *GVPtr = CGF.Builder.CreateConstInBoundsGEP2_32(GV, 0, 0);
+ llvm::Value *GVPtr =
+ CGF.Builder.CreateConstInBoundsGEP2_32(GV->getValueType(), GV, 0, 0);
VBPtr = CGF.Builder.CreateBitCast(VBPtr, GVPtr->getType()->getPointerTo(0),
"vbptr." + VBT->ReusingBase->getName());
CGF.Builder.CreateStore(GVPtr, VBPtr);
@@ -1255,7 +1258,7 @@
// FIXME: Update the code that emits this adjustment in thunks prologues.
This = CGF.Builder.CreateConstGEP1_32(This, StaticOffset.getQuantity());
} else {
- This = CGF.Builder.CreateConstInBoundsGEP1_32(This,
+ This = CGF.Builder.CreateConstInBoundsGEP1_32(CGF.Int8Ty, This,
StaticOffset.getQuantity());
}
}
@@ -1310,8 +1313,8 @@
This = CGF.Builder.CreateBitCast(This, charPtrTy);
assert(Adjustment.isPositive());
- This =
- CGF.Builder.CreateConstInBoundsGEP1_32(This, -Adjustment.getQuantity());
+ This = CGF.Builder.CreateConstInBoundsGEP1_32(CGF.Int8Ty, This,
+ -Adjustment.getQuantity());
return CGF.Builder.CreateBitCast(This, thisTy);
}
@@ -1550,8 +1553,8 @@
llvm::ConstantInt::get(CGM.IntTy, 1)};
// Create a GEP which points just after the first entry in the VFTable,
// this should be the location of the first virtual method.
- llvm::Constant *VTableGEP =
- llvm::ConstantExpr::getInBoundsGetElementPtr(VTable, GEPIndices);
+ llvm::Constant *VTableGEP = llvm::ConstantExpr::getInBoundsGetElementPtr(
+ VTable->getValueType(), VTable, GEPIndices);
if (llvm::GlobalValue::isWeakForLinker(VFTableLinkage)) {
VFTableLinkage = llvm::GlobalValue::ExternalLinkage;
if (C)
@@ -1871,7 +1874,7 @@
}
if (RA.NonVirtual)
- V = CGF.Builder.CreateConstInBoundsGEP1_32(V, RA.NonVirtual);
+ V = CGF.Builder.CreateConstInBoundsGEP1_32(CGF.Int8Ty, V, RA.NonVirtual);
// Cast back to the original type.
return CGF.Builder.CreateBitCast(V, Ret->getType());
@@ -3020,13 +3023,15 @@
if (CHD->isWeakForLinker())
CHD->setComdat(CGM.getModule().getOrInsertComdat(CHD->getName()));
+ auto *Bases = getBaseClassArray(Classes);
+
// Initialize the base class ClassHierarchyDescriptor.
llvm::Constant *Fields[] = {
llvm::ConstantInt::get(CGM.IntTy, 0), // Unknown
llvm::ConstantInt::get(CGM.IntTy, Flags),
llvm::ConstantInt::get(CGM.IntTy, Classes.size()),
ABI.getImageRelativeConstant(llvm::ConstantExpr::getInBoundsGetElementPtr(
- getBaseClassArray(Classes),
+ Bases->getValueType(), Bases,
llvm::ArrayRef<llvm::Value *>(GEPIndices))),
};
CHD->setInitializer(llvm::ConstantStruct::get(Type, Fields));
@@ -3193,8 +3198,8 @@
}
llvm::Constant *
-MicrosoftCXXABI::getAddrOfCXXHandlerMapEntry(QualType Type,
- QualType CatchHandlerType) {
+MicrosoftCXXABI::getAddrOfCXXCatchHandlerType(QualType Type,
+ QualType CatchHandlerType) {
// TypeDescriptors for exceptions never have qualified pointer types,
// qualifiers are stored seperately in order to support qualification
// conversions.
@@ -3203,16 +3208,6 @@
bool IsReference = CatchHandlerType->isReferenceType();
- SmallString<256> MangledName;
- {
- llvm::raw_svector_ostream Out(MangledName);
- getMangleContext().mangleCXXHandlerMapEntry(Type, IsConst, IsVolatile,
- IsReference, Out);
- }
-
- if (llvm::GlobalVariable *GV = CGM.getModule().getNamedGlobal(MangledName))
- return llvm::ConstantExpr::getBitCast(GV, CGM.Int8PtrTy);
-
uint32_t Flags = 0;
if (IsConst)
Flags |= 1;
@@ -3221,15 +3216,24 @@
if (IsReference)
Flags |= 8;
+ SmallString<256> MangledName;
+ {
+ llvm::raw_svector_ostream Out(MangledName);
+ getMangleContext().mangleCXXCatchHandlerType(Type, Flags, Out);
+ }
+
+ if (llvm::GlobalVariable *GV = CGM.getModule().getNamedGlobal(MangledName))
+ return llvm::ConstantExpr::getBitCast(GV, CGM.Int8PtrTy);
+
llvm::Constant *Fields[] = {
- llvm::ConstantInt::get(CGM.IntTy, Flags), // Flags
- getImageRelativeConstant(getAddrOfRTTIDescriptor(Type)), // TypeDescriptor
+ llvm::ConstantInt::get(CGM.IntTy, Flags), // Flags
+ getAddrOfRTTIDescriptor(Type), // TypeDescriptor
};
- llvm::StructType *HandlerMapEntryType = getHandlerMapEntryType();
+ llvm::StructType *CatchHandlerTypeType = getCatchHandlerTypeType();
auto *Var = new llvm::GlobalVariable(
- CGM.getModule(), HandlerMapEntryType, /*Constant=*/true,
+ CGM.getModule(), CatchHandlerTypeType, /*Constant=*/true,
llvm::GlobalValue::PrivateLinkage,
- llvm::ConstantStruct::get(HandlerMapEntryType, Fields),
+ llvm::ConstantStruct::get(CatchHandlerTypeType, Fields),
StringRef(MangledName));
Var->setUnnamedAddr(true);
Var->setSection("llvm.metadata");
@@ -3596,9 +3600,10 @@
// - a standard pointer conversion (4.10) not involving conversions to
// pointers to private or protected or ambiguous classes
//
- // All pointers are convertible to pointer-to-void so ensure that it is in the
- // CatchableTypeArray.
- if (IsPointer)
+ // C++14 [conv.ptr]p2:
+ // A prvalue of type "pointer to cv T," where T is an object type, can be
+ // converted to a prvalue of type "pointer to cv void".
+ if (IsPointer && T->getPointeeType()->isObjectType())
CatchableTypes.insert(getCatchableType(getContext().VoidPtrTy));
// C++14 [except.handle]p3:
diff --git a/lib/CodeGen/ModuleBuilder.cpp b/lib/CodeGen/ModuleBuilder.cpp
index 03771e1..25e5740 100644
--- a/lib/CodeGen/ModuleBuilder.cpp
+++ b/lib/CodeGen/ModuleBuilder.cpp
@@ -63,7 +63,7 @@
CoverageInfo(CoverageInfo),
M(new llvm::Module(ModuleName, C)) {}
- virtual ~CodeGeneratorImpl() {
+ ~CodeGeneratorImpl() override {
// There should normally not be any leftover inline method definitions.
assert(DeferredInlineMethodDefinitions.empty() ||
Diags.hasErrorOccurred());
diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp
index 43cf791..48c85e6 100644
--- a/lib/CodeGen/TargetInfo.cpp
+++ b/lib/CodeGen/TargetInfo.cpp
@@ -37,7 +37,8 @@
unsigned LastIndex) {
// Alternatively, we could emit this as a loop in the source.
for (unsigned I = FirstIndex; I <= LastIndex; ++I) {
- llvm::Value *Cell = Builder.CreateConstInBoundsGEP1_32(Array, I);
+ llvm::Value *Cell =
+ Builder.CreateConstInBoundsGEP1_32(Builder.getInt8Ty(), Array, I);
Builder.CreateStore(Value, Cell);
}
}
@@ -339,9 +340,15 @@
//
// FIXME: This needs to be generalized to handle classes as well.
const RecordDecl *RD = RT->getDecl();
- if (!RD->isStruct() || isa<CXXRecordDecl>(RD))
+ if (!RD->isStruct())
return false;
+ // We try to expand CLike CXXRecordDecl.
+ if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
+ if (!CXXRD->isCLike())
+ return false;
+ }
+
uint64_t Size = 0;
for (const auto *FD : RD->fields()) {
@@ -1352,7 +1359,8 @@
} else {
// 9 is %eflags, which doesn't get a size on Darwin for some
// reason.
- Builder.CreateStore(Four8, Builder.CreateConstInBoundsGEP1_32(Address, 9));
+ Builder.CreateStore(
+ Four8, Builder.CreateConstInBoundsGEP1_32(CGF.Int8Ty, Address, 9));
// 11-16 are st(0..5). Not sure why we stop at 5.
// These have size 12, which is sizeof(long double) on
@@ -1617,7 +1625,7 @@
: X86_64TargetCodeGenInfo(CGT, HasAVX) {}
void getDependentLibraryOption(llvm::StringRef Lib,
- llvm::SmallString<24> &Opt) const {
+ llvm::SmallString<24> &Opt) const override {
Opt = "\01";
Opt += Lib;
}
@@ -2766,8 +2774,8 @@
static llvm::Value *EmitVAArgFromMemory(llvm::Value *VAListAddr,
QualType Ty,
CodeGenFunction &CGF) {
- llvm::Value *overflow_arg_area_p =
- CGF.Builder.CreateStructGEP(VAListAddr, 2, "overflow_arg_area_p");
+ llvm::Value *overflow_arg_area_p = CGF.Builder.CreateStructGEP(
+ nullptr, VAListAddr, 2, "overflow_arg_area_p");
llvm::Value *overflow_arg_area =
CGF.Builder.CreateLoad(overflow_arg_area_p, "overflow_arg_area");
@@ -2847,14 +2855,16 @@
llvm::Value *gp_offset_p = nullptr, *gp_offset = nullptr;
llvm::Value *fp_offset_p = nullptr, *fp_offset = nullptr;
if (neededInt) {
- gp_offset_p = CGF.Builder.CreateStructGEP(VAListAddr, 0, "gp_offset_p");
+ gp_offset_p =
+ CGF.Builder.CreateStructGEP(nullptr, VAListAddr, 0, "gp_offset_p");
gp_offset = CGF.Builder.CreateLoad(gp_offset_p, "gp_offset");
InRegs = llvm::ConstantInt::get(CGF.Int32Ty, 48 - neededInt * 8);
InRegs = CGF.Builder.CreateICmpULE(gp_offset, InRegs, "fits_in_gp");
}
if (neededSSE) {
- fp_offset_p = CGF.Builder.CreateStructGEP(VAListAddr, 1, "fp_offset_p");
+ fp_offset_p =
+ CGF.Builder.CreateStructGEP(nullptr, VAListAddr, 1, "fp_offset_p");
fp_offset = CGF.Builder.CreateLoad(fp_offset_p, "fp_offset");
llvm::Value *FitsInFP =
llvm::ConstantInt::get(CGF.Int32Ty, 176 - neededSSE * 16);
@@ -2882,9 +2892,8 @@
// simple assembling of a structure from scattered addresses has many more
// loads than necessary. Can we clean this up?
llvm::Type *LTy = CGF.ConvertTypeForMem(Ty);
- llvm::Value *RegAddr =
- CGF.Builder.CreateLoad(CGF.Builder.CreateStructGEP(VAListAddr, 3),
- "reg_save_area");
+ llvm::Value *RegAddr = CGF.Builder.CreateLoad(
+ CGF.Builder.CreateStructGEP(nullptr, VAListAddr, 3), "reg_save_area");
if (neededInt && neededSSE) {
// FIXME: Cleanup.
assert(AI.isDirect() && "Unexpected ABI info for mixed regs");
@@ -2904,9 +2913,9 @@
llvm::Value *RegHiAddr = TyLo->isFPOrFPVectorTy() ? GPAddr : FPAddr;
llvm::Value *V =
CGF.Builder.CreateLoad(CGF.Builder.CreateBitCast(RegLoAddr, PTyLo));
- CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(Tmp, 0));
+ CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(ST, Tmp, 0));
V = CGF.Builder.CreateLoad(CGF.Builder.CreateBitCast(RegHiAddr, PTyHi));
- CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(Tmp, 1));
+ CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(ST, Tmp, 1));
RegAddr = CGF.Builder.CreateBitCast(Tmp,
llvm::PointerType::getUnqual(LTy));
@@ -2943,10 +2952,10 @@
Tmp = CGF.Builder.CreateBitCast(Tmp, ST->getPointerTo());
V = CGF.Builder.CreateLoad(CGF.Builder.CreateBitCast(RegAddrLo,
DblPtrTy));
- CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(Tmp, 0));
+ CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(ST, Tmp, 0));
V = CGF.Builder.CreateLoad(CGF.Builder.CreateBitCast(RegAddrHi,
DblPtrTy));
- CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(Tmp, 1));
+ CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(ST, Tmp, 1));
RegAddr = CGF.Builder.CreateBitCast(Tmp,
llvm::PointerType::getUnqual(LTy));
}
@@ -3781,10 +3790,12 @@
ImagAddr = Builder.CreateIntToPtr(ImagAddr, PBaseTy);
llvm::Value *Real = Builder.CreateLoad(RealAddr, false, ".vareal");
llvm::Value *Imag = Builder.CreateLoad(ImagAddr, false, ".vaimag");
- llvm::Value *Ptr = CGF.CreateTempAlloca(CGT.ConvertTypeForMem(Ty),
- "vacplx");
- llvm::Value *RealPtr = Builder.CreateStructGEP(Ptr, 0, ".real");
- llvm::Value *ImagPtr = Builder.CreateStructGEP(Ptr, 1, ".imag");
+ llvm::AllocaInst *Ptr =
+ CGF.CreateTempAlloca(CGT.ConvertTypeForMem(Ty), "vacplx");
+ llvm::Value *RealPtr =
+ Builder.CreateStructGEP(Ptr->getAllocatedType(), Ptr, 0, ".real");
+ llvm::Value *ImagPtr =
+ Builder.CreateStructGEP(Ptr->getAllocatedType(), Ptr, 1, ".imag");
Builder.CreateStore(Real, RealPtr, false);
Builder.CreateStore(Imag, ImagPtr, false);
return Ptr;
@@ -3904,8 +3915,8 @@
llvm::Value *EmitAAPCSVAArg(llvm::Value *VAListAddr, QualType Ty,
CodeGenFunction &CGF) const;
- virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
- CodeGenFunction &CGF) const override {
+ llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const override {
return isDarwinPCS() ? EmitDarwinVAArg(VAListAddr, Ty, CGF)
: EmitAAPCSVAArg(VAListAddr, Ty, CGF);
}
@@ -3916,13 +3927,15 @@
AArch64TargetCodeGenInfo(CodeGenTypes &CGT, AArch64ABIInfo::ABIKind Kind)
: TargetCodeGenInfo(new AArch64ABIInfo(CGT, Kind)) {}
- StringRef getARCRetainAutoreleasedReturnValueMarker() const {
+ StringRef getARCRetainAutoreleasedReturnValueMarker() const override {
return "mov\tfp, fp\t\t; marker for objc_retainAutoreleaseReturnValue";
}
- int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const { return 31; }
+ int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const override {
+ return 31;
+ }
- virtual bool doesReturnSlotInterfereWithArgs() const { return false; }
+ bool doesReturnSlotInterfereWithArgs() const override { return false; }
};
}
@@ -4119,13 +4132,15 @@
int RegSize = IsIndirect ? 8 : getContext().getTypeSize(Ty) / 8;
if (!IsFPR) {
// 3 is the field number of __gr_offs
- reg_offs_p = CGF.Builder.CreateStructGEP(VAListAddr, 3, "gr_offs_p");
+ reg_offs_p =
+ CGF.Builder.CreateStructGEP(nullptr, VAListAddr, 3, "gr_offs_p");
reg_offs = CGF.Builder.CreateLoad(reg_offs_p, "gr_offs");
reg_top_index = 1; // field number for __gr_top
RegSize = llvm::RoundUpToAlignment(RegSize, 8);
} else {
// 4 is the field number of __vr_offs.
- reg_offs_p = CGF.Builder.CreateStructGEP(VAListAddr, 4, "vr_offs_p");
+ reg_offs_p =
+ CGF.Builder.CreateStructGEP(nullptr, VAListAddr, 4, "vr_offs_p");
reg_offs = CGF.Builder.CreateLoad(reg_offs_p, "vr_offs");
reg_top_index = 2; // field number for __vr_top
RegSize = 16 * NumRegs;
@@ -4186,8 +4201,8 @@
CGF.EmitBlock(InRegBlock);
llvm::Value *reg_top_p = nullptr, *reg_top = nullptr;
- reg_top_p =
- CGF.Builder.CreateStructGEP(VAListAddr, reg_top_index, "reg_top_p");
+ reg_top_p = CGF.Builder.CreateStructGEP(nullptr, VAListAddr, reg_top_index,
+ "reg_top_p");
reg_top = CGF.Builder.CreateLoad(reg_top_p, "reg_top");
llvm::Value *BaseAddr = CGF.Builder.CreateGEP(reg_top, reg_offs);
llvm::Value *RegAddr = nullptr;
@@ -4210,7 +4225,7 @@
assert(!IsIndirect && "Homogeneous aggregates should be passed directly");
llvm::Type *BaseTy = CGF.ConvertType(QualType(Base, 0));
llvm::Type *HFATy = llvm::ArrayType::get(BaseTy, NumMembers);
- llvm::Value *Tmp = CGF.CreateTempAlloca(HFATy);
+ llvm::AllocaInst *Tmp = CGF.CreateTempAlloca(HFATy);
int Offset = 0;
if (CGF.CGM.getDataLayout().isBigEndian() && Ctx.getTypeSize(Base) < 128)
@@ -4221,7 +4236,8 @@
llvm::Value *LoadAddr = CGF.Builder.CreateGEP(BaseAddr, BaseOffset);
LoadAddr = CGF.Builder.CreateBitCast(
LoadAddr, llvm::PointerType::getUnqual(BaseTy));
- llvm::Value *StoreAddr = CGF.Builder.CreateStructGEP(Tmp, i);
+ llvm::Value *StoreAddr =
+ CGF.Builder.CreateStructGEP(Tmp->getAllocatedType(), Tmp, i);
llvm::Value *Elem = CGF.Builder.CreateLoad(LoadAddr);
CGF.Builder.CreateStore(Elem, StoreAddr);
@@ -4254,7 +4270,7 @@
CGF.EmitBlock(OnStackBlock);
llvm::Value *stack_p = nullptr, *OnStackAddr = nullptr;
- stack_p = CGF.Builder.CreateStructGEP(VAListAddr, 0, "stack_p");
+ stack_p = CGF.Builder.CreateStructGEP(nullptr, VAListAddr, 0, "stack_p");
OnStackAddr = CGF.Builder.CreateLoad(stack_p, "stack");
// Again, stack arguments may need realigmnent. In this case both integer and
@@ -5171,7 +5187,9 @@
}
bool SystemZABIInfo::isCompoundType(QualType Ty) const {
- return Ty->isAnyComplexType() || isAggregateTypeForABI(Ty);
+ return (Ty->isAnyComplexType() ||
+ Ty->isVectorType() ||
+ isAggregateTypeForABI(Ty));
}
bool SystemZABIInfo::isFPArgumentType(QualType Ty) const {
@@ -5206,11 +5224,12 @@
// Check the fields.
for (const auto *FD : RD->fields()) {
- // Empty bitfields don't affect things either way.
+ // For compatibility with GCC, ignore empty bitfields in C++ mode.
// Unlike isSingleElementStruct(), empty structure and array fields
// do count. So do anonymous bitfields that aren't zero-sized.
- if (FD->isBitField() && FD->getBitWidthValue(getContext()) == 0)
- return true;
+ if (getContext().getLangOpts().CPlusPlus &&
+ FD->isBitField() && FD->getBitWidthValue(getContext()) == 0)
+ continue;
// Unlike isSingleElementStruct(), arrays do not count.
// Nested isFPArgumentType structures still do though.
@@ -5242,17 +5261,21 @@
// Every argument occupies 8 bytes and is passed by preference in either
// GPRs or FPRs.
Ty = CGF.getContext().getCanonicalType(Ty);
+ llvm::Type *ArgTy = CGF.ConvertTypeForMem(Ty);
+ llvm::Type *APTy = llvm::PointerType::getUnqual(ArgTy);
ABIArgInfo AI = classifyArgumentType(Ty);
- bool InFPRs = isFPArgumentType(Ty);
-
- llvm::Type *APTy = llvm::PointerType::getUnqual(CGF.ConvertTypeForMem(Ty));
bool IsIndirect = AI.isIndirect();
+ bool InFPRs = false;
unsigned UnpaddedBitSize;
if (IsIndirect) {
APTy = llvm::PointerType::getUnqual(APTy);
UnpaddedBitSize = 64;
- } else
+ } else {
+ if (AI.getCoerceToType())
+ ArgTy = AI.getCoerceToType();
+ InFPRs = ArgTy->isFloatTy() || ArgTy->isDoubleTy();
UnpaddedBitSize = getContext().getTypeSize(Ty);
+ }
unsigned PaddedBitSize = 64;
assert((UnpaddedBitSize <= PaddedBitSize) && "Invalid argument size.");
@@ -5272,8 +5295,8 @@
RegPadding = Padding; // values are passed in the low bits of a GPR
}
- llvm::Value *RegCountPtr =
- CGF.Builder.CreateStructGEP(VAListAddr, RegCountField, "reg_count_ptr");
+ llvm::Value *RegCountPtr = CGF.Builder.CreateStructGEP(
+ nullptr, VAListAddr, RegCountField, "reg_count_ptr");
llvm::Value *RegCount = CGF.Builder.CreateLoad(RegCountPtr, "reg_count");
llvm::Type *IndexTy = RegCount->getType();
llvm::Value *MaxRegsV = llvm::ConstantInt::get(IndexTy, MaxRegs);
@@ -5297,7 +5320,7 @@
llvm::Value *RegOffset =
CGF.Builder.CreateAdd(ScaledRegCount, RegBase, "reg_offset");
llvm::Value *RegSaveAreaPtr =
- CGF.Builder.CreateStructGEP(VAListAddr, 3, "reg_save_area_ptr");
+ CGF.Builder.CreateStructGEP(nullptr, VAListAddr, 3, "reg_save_area_ptr");
llvm::Value *RegSaveArea =
CGF.Builder.CreateLoad(RegSaveAreaPtr, "reg_save_area");
llvm::Value *RawRegAddr =
@@ -5316,8 +5339,8 @@
CGF.EmitBlock(InMemBlock);
// Work out the address of a stack argument.
- llvm::Value *OverflowArgAreaPtr =
- CGF.Builder.CreateStructGEP(VAListAddr, 2, "overflow_arg_area_ptr");
+ llvm::Value *OverflowArgAreaPtr = CGF.Builder.CreateStructGEP(
+ nullptr, VAListAddr, 2, "overflow_arg_area_ptr");
llvm::Value *OverflowArgArea =
CGF.Builder.CreateLoad(OverflowArgAreaPtr, "overflow_arg_area");
llvm::Value *PaddingV = llvm::ConstantInt::get(IndexTy, Padding);
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index 0e99c58..07a5e42 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -2062,6 +2062,9 @@
else
TC = new toolchains::Linux(*this, Target, Args);
break;
+ case llvm::Triple::NaCl:
+ TC = new toolchains::NaCl_TC(*this, Target, Args);
+ break;
case llvm::Triple::Solaris:
TC = new toolchains::Solaris(*this, Target, Args);
break;
@@ -2149,7 +2152,7 @@
Major = Minor = Micro = 0;
if (*Str == '\0')
- return true;
+ return false;
char *End;
Major = (unsigned) strtol(Str, &End, 10);
diff --git a/lib/Driver/SanitizerArgs.cpp b/lib/Driver/SanitizerArgs.cpp
index fb907a7..cd3785c 100644
--- a/lib/Driver/SanitizerArgs.cpp
+++ b/lib/Driver/SanitizerArgs.cpp
@@ -48,7 +48,7 @@
RecoverableByDefault = Undefined | Integer,
Unrecoverable = Address | Unreachable | Return,
LegacyFsanitizeRecoverMask = Undefined | Integer,
- NeedsLTO = CFIDerivedCast | CFIUnrelatedCast | CFIVptr,
+ NeedsLTO = CFI,
};
}
@@ -159,7 +159,8 @@
}
bool SanitizerArgs::needsUbsanRt() const {
- return !UbsanTrapOnError && hasOneOf(Sanitizers, NeedsUbsanRt);
+ return !UbsanTrapOnError && hasOneOf(Sanitizers, NeedsUbsanRt) &&
+ !Sanitizers.has(SanitizerKind::Address);
}
bool SanitizerArgs::requiresPIE() const {
diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp
index 9606df6..434dc4d 100644
--- a/lib/Driver/ToolChains.cpp
+++ b/lib/Driver/ToolChains.cpp
@@ -135,7 +135,7 @@
.Cases("sc000", "cortex-m0", "cortex-m0plus", "cortex-m1", "armv6m")
.Cases("cortex-a5", "cortex-a7", "cortex-a8", "armv7")
.Cases("cortex-a9", "cortex-a12", "cortex-a15", "cortex-a17", "krait", "armv7")
- .Cases("cortex-r4", "cortex-r5", "cortex-r7", "armv7r")
+ .Cases("cortex-r4", "cortex-r4f", "cortex-r5", "cortex-r7", "armv7r")
.Cases("sc300", "cortex-m3", "armv7m")
.Cases("cortex-m4", "cortex-m7", "armv7em")
.Case("swift", "armv7s")
@@ -338,6 +338,12 @@
OS + "_dynamic.dylib").str(),
/*AlwaysLink*/ true, /*IsEmbedded*/ false,
/*AddRPath*/ true);
+
+ if (GetCXXStdlibType(Args) == ToolChain::CST_Libcxx) {
+ // Add explicit dependcy on -lc++abi, as -lc++ doesn't re-export
+ // all RTTI-related symbols that UBSan uses.
+ CmdArgs.push_back("-lc++abi");
+ }
}
void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
@@ -401,9 +407,6 @@
<< "-fsanitize=undefined";
} else {
AddLinkSanitizerLibArgs(Args, CmdArgs, "ubsan");
- // Add explicit dependcy on -lc++abi, as -lc++ doesn't re-export
- // all RTTI-related symbols that UBSan uses.
- CmdArgs.push_back("-lc++abi");
}
}
@@ -2084,7 +2087,8 @@
getTriple().getArch() == llvm::Triple::aarch64_be ||
(getTriple().getOS() == llvm::Triple::Linux &&
(!V.isOlderThan(4, 7, 0) ||
- getTriple().getEnvironment() == llvm::Triple::Android));
+ getTriple().getEnvironment() == llvm::Triple::Android)) ||
+ getTriple().getOS() == llvm::Triple::NaCl;
if (DriverArgs.hasFlag(options::OPT_fuse_init_array,
options::OPT_fno_use_init_array,
@@ -2307,6 +2311,159 @@
}
// End Hexagon
+/// NaCl Toolchain
+NaCl_TC::NaCl_TC(const Driver &D, const llvm::Triple &Triple,
+ const ArgList &Args)
+ : Generic_ELF(D, Triple, Args) {
+
+ // Remove paths added by Generic_GCC. NaCl Toolchain cannot use the
+ // default paths, and must instead only use the paths provided
+ // with this toolchain based on architecture.
+ path_list& file_paths = getFilePaths();
+ path_list& prog_paths = getProgramPaths();
+
+ file_paths.clear();
+ prog_paths.clear();
+
+ // Path for library files (libc.a, ...)
+ std::string FilePath(getDriver().Dir + "/../");
+
+ // Path for tools (clang, ld, etc..)
+ std::string ProgPath(getDriver().Dir + "/../");
+
+ // Path for toolchain libraries (libgcc.a, ...)
+ std::string ToolPath(getDriver().ResourceDir + "/lib/");
+
+ switch(Triple.getArch()) {
+ case llvm::Triple::x86: {
+ file_paths.push_back(FilePath + "x86_64-nacl/lib32");
+ file_paths.push_back(FilePath + "x86_64-nacl/usr/lib32");
+ prog_paths.push_back(ProgPath + "x86_64-nacl/bin");
+ file_paths.push_back(ToolPath + "i686-nacl");
+ break;
+ }
+ case llvm::Triple::x86_64: {
+ file_paths.push_back(FilePath + "x86_64-nacl/lib");
+ file_paths.push_back(FilePath + "x86_64-nacl/usr/lib");
+ prog_paths.push_back(ProgPath + "x86_64-nacl/bin");
+ file_paths.push_back(ToolPath + "x86_64-nacl");
+ break;
+ }
+ case llvm::Triple::arm: {
+ file_paths.push_back(FilePath + "arm-nacl/lib");
+ file_paths.push_back(FilePath + "arm-nacl/usr/lib");
+ prog_paths.push_back(ProgPath + "arm-nacl/bin");
+ file_paths.push_back(ToolPath + "arm-nacl");
+ break;
+ }
+ default:
+ break;
+ }
+
+ // Use provided linker, not system linker
+ Linker = GetProgramPath("ld");
+ NaClArmMacrosPath = GetFilePath("nacl-arm-macros.s");
+}
+
+void NaCl_TC::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {
+ const Driver &D = getDriver();
+ if (DriverArgs.hasArg(options::OPT_nostdinc))
+ return;
+
+ if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
+ SmallString<128> P(D.ResourceDir);
+ llvm::sys::path::append(P, "include");
+ addSystemInclude(DriverArgs, CC1Args, P.str());
+ }
+
+ if (DriverArgs.hasArg(options::OPT_nostdlibinc))
+ return;
+
+ SmallString<128> P(D.Dir + "/../");
+ if (getTriple().getArch() == llvm::Triple::arm) {
+ llvm::sys::path::append(P, "arm-nacl/usr/include");
+ } else if (getTriple().getArch() == llvm::Triple::x86) {
+ llvm::sys::path::append(P, "x86_64-nacl/usr/include");
+ } else if (getTriple().getArch() == llvm::Triple::x86_64) {
+ llvm::sys::path::append(P, "x86_64-nacl/usr/include");
+ } else {
+ return;
+ }
+
+ addSystemInclude(DriverArgs, CC1Args, P.str());
+ llvm::sys::path::remove_filename(P);
+ llvm::sys::path::remove_filename(P);
+ llvm::sys::path::append(P, "include");
+ addSystemInclude(DriverArgs, CC1Args, P.str());
+}
+
+void NaCl_TC::AddCXXStdlibLibArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ // Check for -stdlib= flags. We only support libc++ but this consumes the arg
+ // if the value is libc++, and emits an error for other values.
+ GetCXXStdlibType(Args);
+ CmdArgs.push_back("-lc++");
+}
+
+void NaCl_TC::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {
+ const Driver &D = getDriver();
+ if (DriverArgs.hasArg(options::OPT_nostdlibinc) ||
+ DriverArgs.hasArg(options::OPT_nostdincxx))
+ return;
+
+ // Check for -stdlib= flags. We only support libc++ but this consumes the arg
+ // if the value is libc++, and emits an error for other values.
+ GetCXXStdlibType(DriverArgs);
+
+ if (getTriple().getArch() == llvm::Triple::arm) {
+ SmallString<128> P(D.Dir + "/../");
+ llvm::sys::path::append(P, "arm-nacl/include/c++/v1");
+ addSystemInclude(DriverArgs, CC1Args, P.str());
+ } else if (getTriple().getArch() == llvm::Triple::x86) {
+ SmallString<128> P(D.Dir + "/../");
+ llvm::sys::path::append(P, "x86_64-nacl/include/c++/v1");
+ addSystemInclude(DriverArgs, CC1Args, P.str());
+ } else if (getTriple().getArch() == llvm::Triple::x86_64) {
+ SmallString<128> P(D.Dir + "/../");
+ llvm::sys::path::append(P, "x86_64-nacl/include/c++/v1");
+ addSystemInclude(DriverArgs, CC1Args, P.str());
+ }
+}
+
+ToolChain::CXXStdlibType NaCl_TC::GetCXXStdlibType(const ArgList &Args) const {
+ if (Arg *A = Args.getLastArg(options::OPT_stdlib_EQ)) {
+ StringRef Value = A->getValue();
+ if (Value == "libc++")
+ return ToolChain::CST_Libcxx;
+ getDriver().Diag(diag::err_drv_invalid_stdlib_name)
+ << A->getAsString(Args);
+ }
+
+ return ToolChain::CST_Libcxx;
+}
+
+std::string NaCl_TC::ComputeEffectiveClangTriple(
+ const ArgList &Args, types::ID InputType) const {
+ llvm::Triple TheTriple(ComputeLLVMTriple(Args, InputType));
+ if (TheTriple.getArch() == llvm::Triple::arm &&
+ TheTriple.getEnvironment() == llvm::Triple::UnknownEnvironment)
+ TheTriple.setEnvironment(llvm::Triple::GNUEABIHF);
+ return TheTriple.getTriple();
+}
+
+Tool *NaCl_TC::buildLinker() const {
+ return new tools::nacltools::Link(*this);
+}
+
+Tool *NaCl_TC::buildAssembler() const {
+ if (getTriple().getArch() == llvm::Triple::arm)
+ return new tools::nacltools::AssembleARM(*this);
+ return new tools::gnutools::Assemble(*this);
+}
+// End NaCl
+
/// TCEToolChain - A tool chain using the llvm bitcode tools to perform
/// all subcommands. See http://tce.cs.tut.fi for our peculiar target.
/// Currently does not support anything else but compilation.
@@ -2706,10 +2863,12 @@
DebianSqueeze,
DebianWheezy,
DebianJessie,
+ DebianStretch,
Exherbo,
RHEL4,
RHEL5,
RHEL6,
+ RHEL7,
Fedora,
OpenSUSE,
UbuntuHardy,
@@ -2725,11 +2884,13 @@
UbuntuRaring,
UbuntuSaucy,
UbuntuTrusty,
+ UbuntuUtopic,
+ UbuntuVivid,
UnknownDistro
};
static bool IsRedhat(enum Distro Distro) {
- return Distro == Fedora || (Distro >= RHEL4 && Distro <= RHEL6);
+ return Distro == Fedora || (Distro >= RHEL4 && Distro <= RHEL7);
}
static bool IsOpenSUSE(enum Distro Distro) {
@@ -2737,11 +2898,11 @@
}
static bool IsDebian(enum Distro Distro) {
- return Distro >= DebianLenny && Distro <= DebianJessie;
+ return Distro >= DebianLenny && Distro <= DebianStretch;
}
static bool IsUbuntu(enum Distro Distro) {
- return Distro >= UbuntuHardy && Distro <= UbuntuTrusty;
+ return Distro >= UbuntuHardy && Distro <= UbuntuVivid;
}
static Distro DetectDistro(llvm::Triple::ArchType Arch) {
@@ -2768,6 +2929,8 @@
.Case("raring", UbuntuRaring)
.Case("saucy", UbuntuSaucy)
.Case("trusty", UbuntuTrusty)
+ .Case("utopic", UbuntuUtopic)
+ .Case("vivid", UbuntuVivid)
.Default(UnknownDistro);
return Version;
}
@@ -2779,7 +2942,9 @@
return Fedora;
if (Data.startswith("Red Hat Enterprise Linux") ||
Data.startswith("CentOS")) {
- if (Data.find("release 6") != StringRef::npos)
+ if (Data.find("release 7") != StringRef::npos)
+ return RHEL7;
+ else if (Data.find("release 6") != StringRef::npos)
return RHEL6;
else if (Data.find("release 5") != StringRef::npos)
return RHEL5;
@@ -2800,6 +2965,8 @@
return DebianWheezy;
else if (Data.startswith("jessie/sid") || Data[0] == '8')
return DebianJessie;
+ else if (Data.startswith("stretch/sid") || Data[0] == '9')
+ return DebianStretch;
return UnknownDistro;
}
@@ -2996,8 +3163,7 @@
if (IsRedhat(Distro))
ExtraOpts.push_back("--no-add-needed");
- if (Distro == DebianSqueeze || Distro == DebianWheezy ||
- Distro == DebianJessie || IsOpenSUSE(Distro) ||
+ if ((IsDebian(Distro) && Distro >= DebianSqueeze) || IsOpenSUSE(Distro) ||
(IsRedhat(Distro) && Distro != RHEL4 && Distro != RHEL5) ||
(IsUbuntu(Distro) && Distro >= UbuntuKarmic))
ExtraOpts.push_back("--build-id");
diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h
index ebd23d1..456bf77 100644
--- a/lib/Driver/ToolChains.h
+++ b/lib/Driver/ToolChains.h
@@ -152,7 +152,7 @@
public:
Generic_GCC(const Driver &D, const llvm::Triple &Triple,
const llvm::opt::ArgList &Args);
- ~Generic_GCC();
+ ~Generic_GCC() override;
void printVerboseInfo(raw_ostream &OS) const override;
@@ -196,7 +196,7 @@
public:
MachO(const Driver &D, const llvm::Triple &Triple,
const llvm::opt::ArgList &Args);
- ~MachO();
+ ~MachO() override;
/// @name MachO specific toolchain API
/// {
@@ -345,7 +345,7 @@
public:
Darwin(const Driver &D, const llvm::Triple &Triple,
const llvm::opt::ArgList &Args);
- ~Darwin();
+ ~Darwin() override;
std::string ComputeEffectiveClangTriple(const llvm::opt::ArgList &Args,
types::ID InputType) const override;
@@ -487,8 +487,7 @@
AddCCKextLibArgs(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) const override;
- virtual void addClangWarningOptions(llvm::opt::ArgStringList &CC1Args)
- const override;
+ void addClangWarningOptions(llvm::opt::ArgStringList &CC1Args) const override;
void
AddLinkARCArgs(const llvm::opt::ArgList &Args,
@@ -699,7 +698,7 @@
public:
Hexagon_TC(const Driver &D, const llvm::Triple &Triple,
const llvm::opt::ArgList &Args);
- ~Hexagon_TC();
+ ~Hexagon_TC() override;
void
AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
@@ -717,13 +716,52 @@
static StringRef GetTargetCPU(const llvm::opt::ArgList &Args);
};
+class LLVM_LIBRARY_VISIBILITY NaCl_TC : public Generic_ELF {
+public:
+ NaCl_TC(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
+
+ void
+ AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+ void
+ AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+
+ CXXStdlibType
+ GetCXXStdlibType(const llvm::opt::ArgList &Args) const override;
+
+ void
+ AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const override;
+
+ bool
+ IsIntegratedAssemblerDefault() const override { return false; }
+
+ // Get the path to the file containing NaCl's ARM macros. It lives in NaCl_TC
+ // because the AssembleARM tool needs a const char * that it can pass around
+ // and the toolchain outlives all the jobs.
+ const char *GetNaClArmMacrosPath() const { return NaClArmMacrosPath.c_str(); }
+
+ std::string ComputeEffectiveClangTriple(const llvm::opt::ArgList &Args,
+ types::ID InputType) const override;
+ std::string Linker;
+
+protected:
+ Tool *buildLinker() const override;
+ Tool *buildAssembler() const override;
+
+private:
+ std::string NaClArmMacrosPath;
+};
+
/// TCEToolChain - A tool chain using the llvm bitcode tools to perform
/// all subcommands. See http://tce.cs.tut.fi for our peculiar target.
class LLVM_LIBRARY_VISIBILITY TCEToolChain : public ToolChain {
public:
TCEToolChain(const Driver &D, const llvm::Triple &Triple,
const llvm::opt::ArgList &Args);
- ~TCEToolChain();
+ ~TCEToolChain() override;
bool IsMathErrnoDefault() const override;
bool isPICDefault() const override;
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index ed1bd3e..3053d9b 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -750,9 +750,8 @@
Features.push_back("-crypto");
}
- // En/disable crc
- if (Arg *A = Args.getLastArg(options::OPT_mcrc,
- options::OPT_mnocrc)) {
+ // En/disable crc code generation.
+ if (Arg *A = Args.getLastArg(options::OPT_mcrc, options::OPT_mnocrc)) {
if (A->getOption().matches(options::OPT_mcrc))
Features.push_back("+crc");
else
@@ -862,12 +861,14 @@
}
}
- // Setting -mno-global-merge disables the codegen global merge pass. Setting
- // -mglobal-merge has no effect as the pass is enabled by default.
+ // Forward the -mglobal-merge option for explicit control over the pass.
if (Arg *A = Args.getLastArg(options::OPT_mglobal_merge,
options::OPT_mno_global_merge)) {
+ CmdArgs.push_back("-backend-option");
if (A->getOption().matches(options::OPT_mno_global_merge))
- CmdArgs.push_back("-mno-global-merge");
+ CmdArgs.push_back("-arm-global-merge=false");
+ else
+ CmdArgs.push_back("-arm-global-merge=true");
}
if (!Args.hasFlag(options::OPT_mimplicit_float,
@@ -958,12 +959,14 @@
CmdArgs.push_back("-aarch64-fix-cortex-a53-835769=1");
}
- // Setting -mno-global-merge disables the codegen global merge pass. Setting
- // -mglobal-merge has no effect as the pass is enabled by default.
+ // Forward the -mglobal-merge option for explicit control over the pass.
if (Arg *A = Args.getLastArg(options::OPT_mglobal_merge,
options::OPT_mno_global_merge)) {
+ CmdArgs.push_back("-backend-option");
if (A->getOption().matches(options::OPT_mno_global_merge))
- CmdArgs.push_back("-mno-global-merge");
+ CmdArgs.push_back("-aarch64-global-merge=false");
+ else
+ CmdArgs.push_back("-aarch64-global-merge=true");
}
if (Args.hasArg(options::OPT_ffixed_x18)) {
@@ -1115,11 +1118,21 @@
if (Arg *A = Args.getLastArg(options::OPT_mnan_EQ)) {
StringRef Val = StringRef(A->getValue());
- if (Val == "2008")
- Features.push_back("+nan2008");
- else if (Val == "legacy")
- Features.push_back("-nan2008");
- else
+ if (Val == "2008") {
+ if (mips::getSupportedNanEncoding(CPUName) & mips::Nan2008)
+ Features.push_back("+nan2008");
+ else {
+ Features.push_back("-nan2008");
+ D.Diag(diag::warn_target_unsupported_nan2008) << CPUName;
+ }
+ } else if (Val == "legacy") {
+ if (mips::getSupportedNanEncoding(CPUName) & mips::NanLegacy)
+ Features.push_back("-nan2008");
+ else {
+ Features.push_back("+nan2008");
+ D.Diag(diag::warn_target_unsupported_nanlegacy) << CPUName;
+ }
+ } else
D.Diag(diag::err_drv_unsupported_option_argument)
<< A->getOption().getName() << Val;
}
@@ -1418,6 +1431,18 @@
return "z10";
}
+static void getSystemZTargetFeatures(const ArgList &Args,
+ std::vector<const char *> &Features) {
+ // -m(no-)htm overrides use of the transactional-execution facility.
+ if (Arg *A = Args.getLastArg(options::OPT_mhtm,
+ options::OPT_mno_htm)) {
+ if (A->getOption().matches(options::OPT_mhtm))
+ Features.push_back("+transactional-execution");
+ else
+ Features.push_back("-transactional-execution");
+ }
+}
+
static const char *getX86TargetCPU(const ArgList &Args,
const llvm::Triple &Triple) {
if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
@@ -1566,6 +1591,17 @@
static void getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple,
const ArgList &Args,
std::vector<const char *> &Features) {
+ // If -march=native, autodetect the feature list.
+ if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
+ if (StringRef(A->getValue()) == "native") {
+ llvm::StringMap<bool> HostFeatures;
+ if (llvm::sys::getHostCPUFeatures(HostFeatures))
+ for (auto &F : HostFeatures)
+ Features.push_back(Args.MakeArgString((F.second ? "+" : "-") +
+ F.first()));
+ }
+ }
+
if (Triple.getArchName() == "x86_64h") {
// x86_64h implies quite a few of the more modern subtarget features
// for Haswell class CPUs, but not all of them. Opt-out of a few.
@@ -1766,8 +1802,17 @@
const ArgList &Args,
std::vector<const char *> &Features) {
std::pair<StringRef, StringRef> Split = March.split("+");
- if (Split.first != "armv8-a")
+
+ if (Split.first == "armv8-a" ||
+ Split.first == "armv8a") {
+ // ok, no additional features.
+ } else if (
+ Split.first == "armv8.1-a" ||
+ Split.first == "armv8.1a" ) {
+ Features.push_back("+v8.1a");
+ } else {
return false;
+ }
if (Split.second.size() && !DecodeAArch64Features(D, Split.second, Features))
return false;
@@ -1885,6 +1930,9 @@
case llvm::Triple::sparcv9:
getSparcTargetFeatures(Args, Features);
break;
+ case llvm::Triple::systemz:
+ getSystemZTargetFeatures(Args, Features);
+ break;
case llvm::Triple::aarch64:
case llvm::Triple::aarch64_be:
getAArch64TargetFeatures(D, Args, Features);
@@ -2281,18 +2329,10 @@
StaticRuntimes.push_back("msan");
if (SanArgs.needsTsanRt())
StaticRuntimes.push_back("tsan");
- // WARNING: UBSan should always go last.
if (SanArgs.needsUbsanRt()) {
- // Check if UBSan is combined with another sanitizers.
- if (StaticRuntimes.empty()) {
- StaticRuntimes.push_back("ubsan_standalone");
- if (SanArgs.linkCXXRuntimes())
- StaticRuntimes.push_back("ubsan_standalone_cxx");
- } else {
- StaticRuntimes.push_back("ubsan");
- if (SanArgs.linkCXXRuntimes())
- StaticRuntimes.push_back("ubsan_cxx");
- }
+ StaticRuntimes.push_back("ubsan_standalone");
+ if (SanArgs.linkCXXRuntimes())
+ StaticRuntimes.push_back("ubsan_standalone_cxx");
}
}
@@ -2647,6 +2687,13 @@
assert(JA.getType() == types::TY_PP_Asm &&
"Unexpected output type!");
}
+
+ // Preserve use-list order by default when emitting bitcode, so that
+ // loading the bitcode up in 'opt' or 'llc' and running passes gives the
+ // same result as running passes here. For LTO, we don't need to preserve
+ // the use-list order, since serialization to bitcode is part of the flow.
+ if (JA.getType() == types::TY_LLVM_BC)
+ CmdArgs.push_back("-emit-llvm-uselists");
}
// We normally speed up the clang process a bit by skipping destructors at
@@ -3045,6 +3092,9 @@
if (!SignedZeros)
CmdArgs.push_back("-fno-signed-zeros");
+ if (ReciprocalMath)
+ CmdArgs.push_back("-freciprocal-math");
+
// Validate and pass through -fp-contract option.
if (Arg *A = Args.getLastArg(options::OPT_ffast_math, FastMathAliasOption,
options::OPT_fno_fast_math,
@@ -3087,8 +3137,10 @@
Args.hasArg(options::OPT_dA))
CmdArgs.push_back("-masm-verbose");
- if (!Args.hasFlag(options::OPT_fintegrated_as, options::OPT_fno_integrated_as,
- IsIntegratedAssemblerDefault))
+ bool UsingIntegratedAssembler =
+ Args.hasFlag(options::OPT_fintegrated_as, options::OPT_fno_integrated_as,
+ IsIntegratedAssemblerDefault);
+ if (!UsingIntegratedAssembler)
CmdArgs.push_back("-no-integrated-as");
if (Args.hasArg(options::OPT_fdebug_pass_structure)) {
@@ -3332,7 +3384,8 @@
}
if (!Args.hasFlag(options::OPT_funique_section_names,
- options::OPT_fno_unique_section_names, true))
+ options::OPT_fno_unique_section_names,
+ !UsingIntegratedAssembler))
CmdArgs.push_back("-fno-unique-section-names");
Args.AddAllArgs(CmdArgs, options::OPT_finstrument_functions);
@@ -5586,7 +5639,7 @@
.Cases("arm1156t2-s", "arm1156t2f-s", "v6t2")
.Cases("cortex-a5", "cortex-a7", "cortex-a8", "v7")
.Cases("cortex-a9", "cortex-a12", "cortex-a15", "cortex-a17", "krait", "v7")
- .Cases("cortex-r4", "cortex-r5", "cortex-r7", "v7r")
+ .Cases("cortex-r4", "cortex-r4f", "cortex-r5", "cortex-r7", "v7r")
.Cases("sc000", "cortex-m0", "cortex-m0plus", "cortex-m1", "v6m")
.Cases("sc300", "cortex-m3", "v7m")
.Cases("cortex-m4", "cortex-m7", "v7em")
@@ -5610,6 +5663,26 @@
CmdArgs.push_back(LinkFlag);
}
+mips::NanEncoding mips::getSupportedNanEncoding(StringRef &CPU) {
+ return (NanEncoding)llvm::StringSwitch<int>(CPU)
+ .Case("mips1", NanLegacy)
+ .Case("mips2", NanLegacy)
+ .Case("mips3", NanLegacy)
+ .Case("mips4", NanLegacy)
+ .Case("mips5", NanLegacy)
+ .Case("mips32", NanLegacy)
+ .Case("mips32r2", NanLegacy)
+ .Case("mips32r3", NanLegacy | Nan2008)
+ .Case("mips32r5", NanLegacy | Nan2008)
+ .Case("mips32r6", Nan2008)
+ .Case("mips64", NanLegacy)
+ .Case("mips64r2", NanLegacy)
+ .Case("mips64r3", NanLegacy | Nan2008)
+ .Case("mips64r5", NanLegacy | Nan2008)
+ .Case("mips64r6", Nan2008)
+ .Default(NanLegacy);
+}
+
bool mips::hasMipsAbiArg(const ArgList &Args, const char *Value) {
Arg *A = Args.getLastArg(options::OPT_mabi_EQ);
return A && (A->getValue() == StringRef(Value));
@@ -7391,7 +7464,8 @@
}
StringRef ARMFloatABI = tools::arm::getARMFloatABI(
- getToolChain().getDriver(), Args, Triple);
+ getToolChain().getDriver(), Args,
+ llvm::Triple(getToolChain().ComputeEffectiveClangTriple(Args)));
CmdArgs.push_back(Args.MakeArgString("-mfloat-abi=" + ARMFloatABI));
Args.AddLastArg(CmdArgs, options::OPT_march_EQ);
@@ -7911,6 +7985,172 @@
llvm::make_unique<Command>(JA, *this, ToolChain.Linker.c_str(), CmdArgs));
}
+
+// NaCl ARM assembly (inline or standalone) can be written with a set of macros
+// for the various SFI requirements like register masking. The assembly tool
+// inserts the file containing the macros as an input into all the assembly
+// jobs.
+void nacltools::AssembleARM::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ const toolchains::NaCl_TC& ToolChain =
+ static_cast<const toolchains::NaCl_TC&>(getToolChain());
+ InputInfo NaClMacros(ToolChain.GetNaClArmMacrosPath(), types::TY_PP_Asm,
+ "nacl-arm-macros.s");
+ InputInfoList NewInputs;
+ NewInputs.push_back(NaClMacros);
+ NewInputs.append(Inputs.begin(), Inputs.end());
+ gnutools::Assemble::ConstructJob(C, JA, Output, NewInputs, Args,
+ LinkingOutput);
+}
+
+
+// This is quite similar to gnutools::link::ConstructJob with changes that
+// we use static by default, do not yet support sanitizers or LTO, and a few
+// others. Eventually we can support more of that and hopefully migrate back
+// to gnutools::link.
+void nacltools::Link::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+
+ const toolchains::NaCl_TC& ToolChain =
+ static_cast<const toolchains::NaCl_TC&>(getToolChain());
+ const Driver &D = ToolChain.getDriver();
+ const bool IsStatic =
+ !Args.hasArg(options::OPT_dynamic) &&
+ !Args.hasArg(options::OPT_shared);
+
+ ArgStringList CmdArgs;
+
+ // Silence warning for "clang -g foo.o -o foo"
+ Args.ClaimAllArgs(options::OPT_g_Group);
+ // and "clang -emit-llvm foo.o -o foo"
+ Args.ClaimAllArgs(options::OPT_emit_llvm);
+ // and for "clang -w foo.o -o foo". Other warning options are already
+ // handled somewhere else.
+ Args.ClaimAllArgs(options::OPT_w);
+
+ if (!D.SysRoot.empty())
+ CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
+
+ if (Args.hasArg(options::OPT_rdynamic))
+ CmdArgs.push_back("-export-dynamic");
+
+ if (Args.hasArg(options::OPT_s))
+ CmdArgs.push_back("-s");
+
+ // NaCl_TC doesn't have ExtraOpts like Linux; the only relevant flag from
+ // there is --build-id, which we do want.
+ CmdArgs.push_back("--build-id");
+
+ if (!IsStatic)
+ CmdArgs.push_back("--eh-frame-hdr");
+
+ CmdArgs.push_back("-m");
+ if (ToolChain.getArch() == llvm::Triple::x86)
+ CmdArgs.push_back("elf_i386_nacl");
+ else if (ToolChain.getArch() == llvm::Triple::arm)
+ CmdArgs.push_back("armelf_nacl");
+ else if (ToolChain.getArch() == llvm::Triple::x86_64)
+ CmdArgs.push_back("elf_x86_64_nacl");
+ else
+ D.Diag(diag::err_target_unsupported_arch) << ToolChain.getArchName() <<
+ "Native Client";
+
+
+ if (IsStatic)
+ CmdArgs.push_back("-static");
+ else if (Args.hasArg(options::OPT_shared))
+ CmdArgs.push_back("-shared");
+
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+ if (!Args.hasArg(options::OPT_nostdlib) &&
+ !Args.hasArg(options::OPT_nostartfiles)) {
+ if (!Args.hasArg(options::OPT_shared))
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt1.o")));
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o")));
+
+ const char *crtbegin;
+ if (IsStatic)
+ crtbegin = "crtbeginT.o";
+ else if (Args.hasArg(options::OPT_shared))
+ crtbegin = "crtbeginS.o";
+ else
+ crtbegin = "crtbegin.o";
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin)));
+ }
+
+ Args.AddAllArgs(CmdArgs, options::OPT_L);
+ Args.AddAllArgs(CmdArgs, options::OPT_u);
+
+ const ToolChain::path_list &Paths = ToolChain.getFilePaths();
+
+ for (const auto &Path : Paths)
+ CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + Path));
+
+ if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle))
+ CmdArgs.push_back("--no-demangle");
+
+ AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs);
+
+ if (D.CCCIsCXX() &&
+ !Args.hasArg(options::OPT_nostdlib) &&
+ !Args.hasArg(options::OPT_nodefaultlibs)) {
+ bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) &&
+ !IsStatic;
+ if (OnlyLibstdcxxStatic)
+ CmdArgs.push_back("-Bstatic");
+ ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
+ if (OnlyLibstdcxxStatic)
+ CmdArgs.push_back("-Bdynamic");
+ CmdArgs.push_back("-lm");
+ }
+
+ if (!Args.hasArg(options::OPT_nostdlib)) {
+ if (!Args.hasArg(options::OPT_nodefaultlibs)) {
+ // Always use groups, since it has no effect on dynamic libraries.
+ CmdArgs.push_back("--start-group");
+ CmdArgs.push_back("-lc");
+ // NaCl's libc++ currently requires libpthread, so just always include it
+ // in the group for C++.
+ if (Args.hasArg(options::OPT_pthread) ||
+ Args.hasArg(options::OPT_pthreads) ||
+ D.CCCIsCXX()) {
+ CmdArgs.push_back("-lpthread");
+ }
+
+ CmdArgs.push_back("-lgcc");
+ CmdArgs.push_back("--as-needed");
+ if (IsStatic)
+ CmdArgs.push_back("-lgcc_eh");
+ else
+ CmdArgs.push_back("-lgcc_s");
+ CmdArgs.push_back("--no-as-needed");
+ CmdArgs.push_back("--end-group");
+ }
+
+ if (!Args.hasArg(options::OPT_nostartfiles)) {
+ const char *crtend;
+ if (Args.hasArg(options::OPT_shared))
+ crtend = "crtendS.o";
+ else
+ crtend = "crtend.o";
+
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtend)));
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o")));
+ }
+ }
+
+ C.addCommand(llvm::make_unique<Command>(JA, *this,
+ ToolChain.Linker.c_str(), CmdArgs));
+}
+
+
void minix::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
diff --git a/lib/Driver/Tools.h b/lib/Driver/Tools.h
index 5161557..33fadd1 100644
--- a/lib/Driver/Tools.h
+++ b/lib/Driver/Tools.h
@@ -234,6 +234,11 @@
}
namespace mips {
+ typedef enum {
+ NanLegacy = 1,
+ Nan2008 = 2
+ } NanEncoding;
+ NanEncoding getSupportedNanEncoding(StringRef &CPU);
void getMipsCPUAndABI(const llvm::opt::ArgList &Args,
const llvm::Triple &Triple, StringRef &CPUName,
StringRef &ABIName);
@@ -507,6 +512,33 @@
const char *LinkingOutput) const override;
};
}
+
+namespace nacltools {
+ class LLVM_LIBRARY_VISIBILITY AssembleARM : public gnutools::Assemble {
+ public:
+ AssembleARM(const ToolChain &TC) : gnutools::Assemble(TC) {}
+
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+ };
+ class LLVM_LIBRARY_VISIBILITY Link : public Tool {
+ public:
+ Link(const ToolChain &TC) : Tool("NaCl::Link", "linker", TC) {}
+
+ bool hasIntegratedCPP() const override { return false; }
+ bool isLinkJob() const override { return true; }
+
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+ };
+}
+
/// minix -- Directly call GNU Binutils assembler and linker
namespace minix {
class LLVM_LIBRARY_VISIBILITY Assemble : public GnuTool {
diff --git a/lib/Edit/EditedSource.cpp b/lib/Edit/EditedSource.cpp
index a5b5875..e557de9 100644
--- a/lib/Edit/EditedSource.cpp
+++ b/lib/Edit/EditedSource.cpp
@@ -295,9 +295,11 @@
}
if (buffer[end] == ' ') {
+ assert((end + 1 != buffer.size() || buffer.data()[end + 1] == 0) &&
+ "buffer not zero-terminated!");
if (canRemoveWhitespace(/*left=*/buffer[begin-1],
/*beforeWSpace=*/buffer[end-1],
- /*right=*/buffer[end+1],
+ /*right=*/buffer.data()[end + 1], // zero-terminated
LangOpts))
++len;
return;
diff --git a/lib/Format/ContinuationIndenter.cpp b/lib/Format/ContinuationIndenter.cpp
index 83fd6ee..a2a68bd 100644
--- a/lib/Format/ContinuationIndenter.cpp
+++ b/lib/Format/ContinuationIndenter.cpp
@@ -634,7 +634,7 @@
std::min(State.LowestLevelOnLine, Current.NestingLevel);
if (Current.isMemberAccess())
State.Stack.back().StartOfFunctionCall =
- Current.LastOperator ? 0 : State.Column + Current.ColumnWidth;
+ Current.LastOperator ? 0 : State.Column;
if (Current.is(TT_SelectorName))
State.Stack.back().ObjCSelectorNameFound = true;
if (Current.is(TT_CtorInitializerColon)) {
@@ -849,7 +849,8 @@
bool NoLineBreak = State.Stack.back().NoLineBreak ||
(Current.is(TT_TemplateOpener) &&
State.Stack.back().ContainsUnwrappedBuilder);
- unsigned NestedBlockIndent = State.Stack.back().NestedBlockIndent;
+ unsigned NestedBlockIndent = std::max(State.Stack.back().StartOfFunctionCall,
+ State.Stack.back().NestedBlockIndent);
State.Stack.push_back(ParenState(NewIndent, NewIndentLevel,
State.Stack.back().LastSpace,
AvoidBinPacking, NoLineBreak));
diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp
index b44ea5d..ad9398c 100644
--- a/lib/Format/Format.cpp
+++ b/lib/Format/Format.cpp
@@ -780,7 +780,15 @@
return false;
FormatToken *EndBacktick = Tokens.back();
- if (!(EndBacktick->is(tok::unknown) && EndBacktick->TokenText == "`"))
+ // Backticks get lexed as tok:unknown tokens. If a template string contains
+ // a comment start, it gets lexed as a tok::comment, or tok::unknown if
+ // unterminated.
+ if (!EndBacktick->isOneOf(tok::comment, tok::unknown))
+ return false;
+ size_t CommentBacktickPos = EndBacktick->TokenText.find('`');
+ // Unknown token that's not actually a backtick, or a comment that doesn't
+ // contain a backtick.
+ if (CommentBacktickPos == StringRef::npos)
return false;
unsigned TokenCount = 0;
@@ -812,7 +820,14 @@
Tokens.resize(Tokens.size() - TokenCount);
Tokens.back()->Type = TT_TemplateString;
- const char *EndOffset = EndBacktick->TokenText.data() + 1;
+ const char *EndOffset =
+ EndBacktick->TokenText.data() + 1 + CommentBacktickPos;
+ if (CommentBacktickPos != 0) {
+ // If the backtick was not the first character (e.g. in a comment),
+ // re-lex after the backtick position.
+ SourceLocation Loc = EndBacktick->Tok.getLocation();
+ resetLexer(SourceMgr.getFileOffset(Loc) + CommentBacktickPos + 1);
+ }
Tokens.back()->TokenText =
StringRef(Tokens.back()->TokenText.data(),
EndOffset - Tokens.back()->TokenText.data());
@@ -1506,8 +1521,7 @@
LangOpts.CPlusPlus11 = Style.Standard == FormatStyle::LS_Cpp03 ? 0 : 1;
LangOpts.CPlusPlus14 = Style.Standard == FormatStyle::LS_Cpp03 ? 0 : 1;
LangOpts.LineComment = 1;
- bool AlternativeOperators = Style.Language != FormatStyle::LK_JavaScript &&
- Style.Language != FormatStyle::LK_Java;
+ bool AlternativeOperators = Style.Language == FormatStyle::LK_Cpp;
LangOpts.CXXOperatorNames = AlternativeOperators ? 1 : 0;
LangOpts.Bool = 1;
LangOpts.ObjC1 = 1;
diff --git a/lib/Format/FormatToken.h b/lib/Format/FormatToken.h
index cef7a63..bc14d4c 100644
--- a/lib/Format/FormatToken.h
+++ b/lib/Format/FormatToken.h
@@ -49,6 +49,7 @@
TT_InlineASMColon,
TT_JavaAnnotation,
TT_JsTypeColon,
+ TT_JsTypeOptionalQuestion,
TT_LambdaArrow,
TT_LambdaLSquare,
TT_LeadingJavaAnnotation,
@@ -549,6 +550,10 @@
kw_repeated = &IdentTable.get("repeated");
kw_required = &IdentTable.get("required");
kw_returns = &IdentTable.get("returns");
+
+ kw_signals = &IdentTable.get("signals");
+ kw_slots = &IdentTable.get("slots");
+ kw_qslots = &IdentTable.get("Q_SLOTS");
}
// Context sensitive keywords.
@@ -583,6 +588,11 @@
IdentifierInfo *kw_repeated;
IdentifierInfo *kw_required;
IdentifierInfo *kw_returns;
+
+ // QT keywords.
+ IdentifierInfo *kw_signals;
+ IdentifierInfo *kw_slots;
+ IdentifierInfo *kw_qslots;
};
} // namespace format
diff --git a/lib/Format/TokenAnnotator.cpp b/lib/Format/TokenAnnotator.cpp
index e0da80c..5b148ea 100644
--- a/lib/Format/TokenAnnotator.cpp
+++ b/lib/Format/TokenAnnotator.cpp
@@ -149,6 +149,8 @@
bool MightBeFunctionType = CurrentToken->is(tok::star);
bool HasMultipleLines = false;
bool HasMultipleParametersOnALine = false;
+ bool MightBeObjCForRangeLoop =
+ Left->Previous && Left->Previous->is(tok::kw_for);
while (CurrentToken) {
// LookForDecls is set when "if (" has been seen. Check for
// 'identifier' '*' 'identifier' followed by not '=' -- this
@@ -210,7 +212,8 @@
}
if (CurrentToken->isOneOf(tok::r_square, tok::r_brace))
return false;
- else if (CurrentToken->is(tok::l_brace))
+
+ if (CurrentToken->is(tok::l_brace))
Left->Type = TT_Unknown; // Not TT_ObjCBlockLParen
if (CurrentToken->is(tok::comma) && CurrentToken->Next &&
!CurrentToken->Next->HasUnescapedNewline &&
@@ -219,6 +222,11 @@
if (CurrentToken->isOneOf(tok::kw_const, tok::kw_auto) ||
CurrentToken->isSimpleTypeSpecifier())
Contexts.back().IsExpression = false;
+ if (CurrentToken->isOneOf(tok::semi, tok::colon))
+ MightBeObjCForRangeLoop = false;
+ if (MightBeObjCForRangeLoop && CurrentToken->is(Keywords.kw_in))
+ CurrentToken->Type = TT_ObjCForIn;
+
FormatToken *Tok = CurrentToken;
if (!consumeToken())
return false;
@@ -342,7 +350,8 @@
Style.Language == FormatStyle::LK_Proto) &&
Previous->is(tok::identifier))
Previous->Type = TT_SelectorName;
- if (CurrentToken->is(tok::colon))
+ if (CurrentToken->is(tok::colon) ||
+ Style.Language == FormatStyle::LK_JavaScript)
Left->Type = TT_DictLiteral;
}
if (!consumeToken())
@@ -408,6 +417,16 @@
if (!Tok->Previous)
return false;
// Colons from ?: are handled in parseConditional().
+ if (Style.Language == FormatStyle::LK_JavaScript) {
+ if (Contexts.back().ColonIsForRangeExpr ||
+ (Contexts.size() == 1 &&
+ !Line.First->isOneOf(tok::kw_enum, tok::kw_case)) ||
+ Contexts.back().ContextKind == tok::l_paren ||
+ Contexts.back().ContextKind == tok::l_square) {
+ Tok->Type = TT_JsTypeColon;
+ break;
+ }
+ }
if (Contexts.back().ColonIsDictLiteral) {
Tok->Type = TT_DictLiteral;
} else if (Contexts.back().ColonIsObjCMethodExpr ||
@@ -421,16 +440,12 @@
if (!Contexts.back().FirstObjCSelectorName)
Contexts.back().FirstObjCSelectorName = Tok->Previous;
} else if (Contexts.back().ColonIsForRangeExpr) {
- Tok->Type = Style.Language == FormatStyle::LK_JavaScript
- ? TT_JsTypeColon
- : TT_RangeBasedForLoopColon;
+ Tok->Type = TT_RangeBasedForLoopColon;
} else if (CurrentToken && CurrentToken->is(tok::numeric_constant)) {
Tok->Type = TT_BitFieldColon;
} else if (Contexts.size() == 1 &&
!Line.First->isOneOf(tok::kw_enum, tok::kw_case)) {
- if (Style.Language == FormatStyle::LK_JavaScript)
- Tok->Type = TT_JsTypeColon;
- else if (Tok->Previous->is(tok::r_paren))
+ if (Tok->Previous->is(tok::r_paren))
Tok->Type = TT_CtorInitializerColon;
else
Tok->Type = TT_InheritanceColon;
@@ -440,9 +455,7 @@
// the colon are passed as macro arguments.
Tok->Type = TT_ObjCMethodExpr;
} else if (Contexts.back().ContextKind == tok::l_paren) {
- Tok->Type = Style.Language == FormatStyle::LK_JavaScript
- ? TT_JsTypeColon
- : TT_InlineASMColon;
+ Tok->Type = TT_InlineASMColon;
}
break;
case tok::kw_if:
@@ -515,16 +528,20 @@
}
break;
case tok::question:
+ if (Style.Language == FormatStyle::LK_JavaScript && Tok->Next &&
+ Tok->Next->isOneOf(tok::colon, tok::semi, tok::r_paren,
+ tok::r_brace)) {
+ // Question marks before semicolons, colons, commas, etc. indicate
+ // optional types (fields, parameters), e.g.
+ // `function(x?: string, y?) {...}` or `class X {y?;}`
+ Tok->Type = TT_JsTypeOptionalQuestion;
+ break;
+ }
parseConditional();
break;
case tok::kw_template:
parseTemplateDeclaration();
break;
- case tok::identifier:
- if (Line.First->is(tok::kw_for) && Tok->is(Keywords.kw_in) &&
- Tok->Previous->isNot(tok::colon))
- Tok->Type = TT_ObjCForIn;
- break;
case tok::comma:
if (Contexts.back().FirstStartOfName && Contexts.size() == 1) {
Contexts.back().FirstStartOfName->PartOfMultiVariableDeclStmt = true;
@@ -714,27 +731,22 @@
Context(tok::TokenKind ContextKind, unsigned BindingStrength,
bool IsExpression)
: ContextKind(ContextKind), BindingStrength(BindingStrength),
- LongestObjCSelectorName(0), ColonIsForRangeExpr(false),
- ColonIsDictLiteral(false), ColonIsObjCMethodExpr(false),
- FirstObjCSelectorName(nullptr), FirstStartOfName(nullptr),
- IsExpression(IsExpression), CanBeExpression(true),
- InTemplateArgument(false), InCtorInitializer(false),
- CaretFound(false), IsForEachMacro(false) {}
+ IsExpression(IsExpression) {}
tok::TokenKind ContextKind;
unsigned BindingStrength;
- unsigned LongestObjCSelectorName;
- bool ColonIsForRangeExpr;
- bool ColonIsDictLiteral;
- bool ColonIsObjCMethodExpr;
- FormatToken *FirstObjCSelectorName;
- FormatToken *FirstStartOfName;
bool IsExpression;
- bool CanBeExpression;
- bool InTemplateArgument;
- bool InCtorInitializer;
- bool CaretFound;
- bool IsForEachMacro;
+ unsigned LongestObjCSelectorName = 0;
+ bool ColonIsForRangeExpr = false;
+ bool ColonIsDictLiteral = false;
+ bool ColonIsObjCMethodExpr = false;
+ FormatToken *FirstObjCSelectorName = nullptr;
+ FormatToken *FirstStartOfName = nullptr;
+ bool CanBeExpression = true;
+ bool InTemplateArgument = false;
+ bool InCtorInitializer = false;
+ bool CaretFound = false;
+ bool IsForEachMacro = false;
};
/// \brief Puts a new \c Context onto the stack \c Contexts for the lifetime
@@ -1652,7 +1664,7 @@
if (Right.isOneOf(tok::semi, tok::comma))
return false;
if (Right.is(tok::less) &&
- (Left.isOneOf(tok::kw_template, tok::r_paren) ||
+ (Left.is(tok::kw_template) ||
(Line.Type == LT_ObjCDecl && Style.ObjCSpaceBeforeProtocolList)))
return true;
if (Left.isOneOf(tok::exclaim, tok::tilde))
@@ -1773,7 +1785,7 @@
} else if (Style.Language == FormatStyle::LK_JavaScript) {
if (Left.is(Keywords.kw_var))
return true;
- if (Right.is(TT_JsTypeColon))
+ if (Right.isOneOf(TT_JsTypeColon, TT_JsTypeOptionalQuestion))
return false;
if ((Left.is(tok::l_brace) || Right.is(tok::r_brace)) &&
Line.First->isOneOf(Keywords.kw_import, tok::kw_export))
diff --git a/lib/Format/UnwrappedLineFormatter.h b/lib/Format/UnwrappedLineFormatter.h
index 9b83b27..7d5b011 100644
--- a/lib/Format/UnwrappedLineFormatter.h
+++ b/lib/Format/UnwrappedLineFormatter.h
@@ -80,7 +80,8 @@
if (Style.Language == FormatStyle::LK_Java ||
Style.Language == FormatStyle::LK_JavaScript)
return 0;
- if (RootToken.isAccessSpecifier(false) || RootToken.isObjCAccessSpecifier())
+ if (RootToken.isAccessSpecifier(false) ||
+ RootToken.isObjCAccessSpecifier() || RootToken.is(Keywords.kw_signals))
return Style.AccessModifierOffset;
return 0;
}
diff --git a/lib/Format/UnwrappedLineParser.cpp b/lib/Format/UnwrappedLineParser.cpp
index 10ce0e9..905f9c1 100644
--- a/lib/Format/UnwrappedLineParser.cpp
+++ b/lib/Format/UnwrappedLineParser.cpp
@@ -68,7 +68,7 @@
Line.InPPDirective = true;
}
- ~ScopedMacroState() {
+ ~ScopedMacroState() override {
TokenSource = PreviousTokenSource;
ResetToken = Token;
Line.InPPDirective = false;
@@ -420,7 +420,7 @@
Line->Level = InitialLevel;
}
-static bool IsGoogScope(const UnwrappedLine &Line) {
+static bool isGoogScope(const UnwrappedLine &Line) {
// FIXME: Closure-library specific stuff should not be hard-coded but be
// configurable.
if (Line.Tokens.size() < 4)
@@ -456,12 +456,13 @@
nextToken();
{
bool GoogScope =
- Style.Language == FormatStyle::LK_JavaScript && IsGoogScope(*Line);
+ Style.Language == FormatStyle::LK_JavaScript && isGoogScope(*Line);
ScopedLineState LineState(*this);
ScopedDeclarationState DeclarationState(*Line, DeclarationScopeStack,
/*MustBeDeclaration=*/false);
Line->Level += GoogScope ? 0 : 1;
parseLevel(/*HasOpeningBrace=*/true);
+ flushComments(isOnNewLine(*FormatTok));
Line->Level -= GoogScope ? 0 : 1;
}
nextToken();
@@ -752,6 +753,10 @@
parseJavaScriptEs6ImportExport();
return;
}
+ if (FormatTok->is(Keywords.kw_signals)) {
+ parseAccessSpecifier();
+ return;
+ }
// In all other cases, parse the declaration.
break;
default:
@@ -840,9 +845,8 @@
if (Line->Tokens.size() == 1 &&
// JS doesn't have macros, and within classes colons indicate fields,
// not labels.
- (Style.Language != FormatStyle::LK_JavaScript ||
- !Line->MustBeDeclaration)) {
- if (FormatTok->Tok.is(tok::colon)) {
+ Style.Language != FormatStyle::LK_JavaScript) {
+ if (FormatTok->Tok.is(tok::colon) && !Line->MustBeDeclaration) {
parseLabel();
return;
}
@@ -1035,6 +1039,17 @@
FormatTok->BlockKind = BK_BracedInit;
parseBracedList();
break;
+ case tok::r_paren:
+ // JavaScript can just have free standing methods and getters/setters in
+ // object literals. Detect them by a "{" following ")".
+ if (Style.Language == FormatStyle::LK_JavaScript) {
+ nextToken();
+ if (FormatTok->is(tok::l_brace))
+ parseChildBlock();
+ break;
+ }
+ nextToken();
+ break;
case tok::r_brace:
nextToken();
return !HasError;
@@ -1399,8 +1414,7 @@
void UnwrappedLineParser::parseAccessSpecifier() {
nextToken();
// Understand Qt's slots.
- if (FormatTok->is(tok::identifier) &&
- (FormatTok->TokenText == "slots" || FormatTok->TokenText == "Q_SLOTS"))
+ if (FormatTok->isOneOf(Keywords.kw_slots, Keywords.kw_qslots))
nextToken();
// Otherwise, we don't know what it is, and we'd better keep the next token.
if (FormatTok->Tok.is(tok::colon))
@@ -1527,7 +1541,8 @@
// it is often token-pasted.
while (FormatTok->is(tok::identifier) || FormatTok->is(tok::coloncolon) ||
FormatTok->is(tok::hashhash) ||
- (Style.Language == FormatStyle::LK_Java &&
+ ((Style.Language == FormatStyle::LK_Java ||
+ Style.Language == FormatStyle::LK_JavaScript) &&
FormatTok->isOneOf(tok::period, tok::comma)))
nextToken();
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index 692edc4..7226344 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -966,9 +966,9 @@
StringRef InFile) {
std::string Sysroot;
std::string OutputFile;
- raw_ostream *OS = nullptr;
- if (GeneratePCHAction::ComputeASTConsumerArguments(CI, InFile, Sysroot,
- OutputFile, OS))
+ raw_ostream *OS = GeneratePCHAction::ComputeASTConsumerArguments(
+ CI, InFile, Sysroot, OutputFile);
+ if (!OS)
return nullptr;
if (!CI.getFrontendOpts().RelocatablePCH)
diff --git a/lib/Frontend/CacheTokens.cpp b/lib/Frontend/CacheTokens.cpp
index d909d52..7d2a09c 100644
--- a/lib/Frontend/CacheTokens.cpp
+++ b/lib/Frontend/CacheTokens.cpp
@@ -183,7 +183,7 @@
typedef llvm::StringMap<OffsetOpt, llvm::BumpPtrAllocator> CachedStrsTy;
IDMap IM;
- llvm::raw_fd_ostream& Out;
+ raw_pwrite_stream &Out;
Preprocessor& PP;
uint32_t idcount;
PTHMap PM;
@@ -236,8 +236,8 @@
Offset EmitCachedSpellings();
public:
- PTHWriter(llvm::raw_fd_ostream& out, Preprocessor& pp)
- : Out(out), PP(pp), idcount(0), CurStrOffset(0) {}
+ PTHWriter(raw_pwrite_stream &out, Preprocessor &pp)
+ : Out(out), PP(pp), idcount(0), CurStrOffset(0) {}
PTHMap &getPM() { return PM; }
void GeneratePTH(const std::string &MainFile);
@@ -468,6 +468,16 @@
return SpellingsOff;
}
+static uint32_t swap32le(uint32_t X) {
+ return llvm::support::endian::byte_swap<uint32_t, llvm::support::little>(X);
+}
+
+static void pwrite32le(raw_pwrite_stream &OS, uint32_t Val, uint64_t &Off) {
+ uint32_t LEVal = swap32le(Val);
+ OS.pwrite(reinterpret_cast<const char *>(&LEVal), 4, Off);
+ Off += 4;
+}
+
void PTHWriter::GeneratePTH(const std::string &MainFile) {
// Generate the prologue.
Out << "cfe-pth" << '\0';
@@ -520,11 +530,11 @@
Offset FileTableOff = EmitFileTable();
// Finally, write the prologue.
- Out.seek(PrologueOffset);
- Emit32(IdTableOff.first);
- Emit32(IdTableOff.second);
- Emit32(FileTableOff);
- Emit32(SpellingOff);
+ uint64_t Off = PrologueOffset;
+ pwrite32le(Out, IdTableOff.first, Off);
+ pwrite32le(Out, IdTableOff.second, Off);
+ pwrite32le(Out, FileTableOff, Off);
+ pwrite32le(Out, SpellingOff, Off);
}
namespace {
@@ -537,7 +547,7 @@
PTHMap &PM;
public:
StatListener(PTHMap &pm) : PM(pm) {}
- ~StatListener() {}
+ ~StatListener() override {}
LookupResult getStat(const char *Path, FileData &Data, bool isFile,
std::unique_ptr<vfs::File> *F,
@@ -559,8 +569,7 @@
};
} // end anonymous namespace
-
-void clang::CacheTokens(Preprocessor &PP, llvm::raw_fd_ostream* OS) {
+void clang::CacheTokens(Preprocessor &PP, raw_pwrite_stream *OS) {
// Get the name of the main file.
const SourceManager &SrcMgr = PP.getSourceManager();
const FileEntry *MainFile = SrcMgr.getFileEntryForID(SrcMgr.getMainFileID());
diff --git a/lib/Frontend/ChainedIncludesSource.cpp b/lib/Frontend/ChainedIncludesSource.cpp
index be99b78..f3677f8 100644
--- a/lib/Frontend/ChainedIncludesSource.cpp
+++ b/lib/Frontend/ChainedIncludesSource.cpp
@@ -27,7 +27,7 @@
namespace {
class ChainedIncludesSource : public ExternalSemaSource {
public:
- virtual ~ChainedIncludesSource();
+ ~ChainedIncludesSource() override;
ExternalSemaSource &getFinalReader() const { return *FinalReader; }
diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp
index 1c5b322..fdaf7e2 100644
--- a/lib/Frontend/CompilerInstance.cpp
+++ b/lib/Frontend/CompilerInstance.cpp
@@ -329,7 +329,8 @@
PP->setPreprocessedOutput(getPreprocessorOutputOpts().ShowCPP);
- PP->getHeaderSearchInfo().setModuleCachePath(getSpecificModuleCachePath());
+ if (PP->getLangOpts().Modules)
+ PP->getHeaderSearchInfo().setModuleCachePath(getSpecificModuleCachePath());
// Handle generating dependencies, if requested.
const DependencyOutputOptions &DepOpts = getDependencyOutputOpts();
@@ -517,42 +518,43 @@
// Output Files
-void CompilerInstance::addOutputFile(const OutputFile &OutFile) {
+void CompilerInstance::addOutputFile(OutputFile &&OutFile) {
assert(OutFile.OS && "Attempt to add empty stream to output list!");
- OutputFiles.push_back(OutFile);
+ OutputFiles.push_back(std::move(OutFile));
}
void CompilerInstance::clearOutputFiles(bool EraseFiles) {
- for (std::list<OutputFile>::iterator
- it = OutputFiles.begin(), ie = OutputFiles.end(); it != ie; ++it) {
- delete it->OS;
- if (!it->TempFilename.empty()) {
+ for (OutputFile &OF : OutputFiles) {
+ // Manually close the stream before we rename it.
+ OF.OS.reset();
+
+ if (!OF.TempFilename.empty()) {
if (EraseFiles) {
- llvm::sys::fs::remove(it->TempFilename);
+ llvm::sys::fs::remove(OF.TempFilename);
} else {
- SmallString<128> NewOutFile(it->Filename);
+ SmallString<128> NewOutFile(OF.Filename);
// If '-working-directory' was passed, the output filename should be
// relative to that.
FileMgr->FixupRelativePath(NewOutFile);
if (std::error_code ec =
- llvm::sys::fs::rename(it->TempFilename, NewOutFile)) {
+ llvm::sys::fs::rename(OF.TempFilename, NewOutFile)) {
getDiagnostics().Report(diag::err_unable_to_rename_temp)
- << it->TempFilename << it->Filename << ec.message();
+ << OF.TempFilename << OF.Filename << ec.message();
- llvm::sys::fs::remove(it->TempFilename);
+ llvm::sys::fs::remove(OF.TempFilename);
}
}
- } else if (!it->Filename.empty() && EraseFiles)
- llvm::sys::fs::remove(it->Filename);
+ } else if (!OF.Filename.empty() && EraseFiles)
+ llvm::sys::fs::remove(OF.Filename);
}
OutputFiles.clear();
+ NonSeekStream.reset();
}
-llvm::raw_fd_ostream *
-CompilerInstance::createDefaultOutputFile(bool Binary,
- StringRef InFile,
+raw_pwrite_stream *
+CompilerInstance::createDefaultOutputFile(bool Binary, StringRef InFile,
StringRef Extension) {
return createOutputFile(getFrontendOpts().OutputFile, Binary,
/*RemoveFileOnSignal=*/true, InFile, Extension,
@@ -560,21 +562,20 @@
}
llvm::raw_null_ostream *CompilerInstance::createNullOutputFile() {
- llvm::raw_null_ostream *OS = new llvm::raw_null_ostream();
- addOutputFile(OutputFile("", "", OS));
- return OS;
+ auto OS = llvm::make_unique<llvm::raw_null_ostream>();
+ llvm::raw_null_ostream *Ret = OS.get();
+ addOutputFile(OutputFile("", "", std::move(OS)));
+ return Ret;
}
-llvm::raw_fd_ostream *
-CompilerInstance::createOutputFile(StringRef OutputPath,
- bool Binary, bool RemoveFileOnSignal,
- StringRef InFile,
- StringRef Extension,
- bool UseTemporary,
+raw_pwrite_stream *
+CompilerInstance::createOutputFile(StringRef OutputPath, bool Binary,
+ bool RemoveFileOnSignal, StringRef InFile,
+ StringRef Extension, bool UseTemporary,
bool CreateMissingDirectories) {
std::string OutputPathName, TempPathName;
std::error_code EC;
- llvm::raw_fd_ostream *OS = createOutputFile(
+ std::unique_ptr<raw_pwrite_stream> OS = createOutputFile(
OutputPath, EC, Binary, RemoveFileOnSignal, InFile, Extension,
UseTemporary, CreateMissingDirectories, &OutputPathName, &TempPathName);
if (!OS) {
@@ -583,15 +584,16 @@
return nullptr;
}
+ raw_pwrite_stream *Ret = OS.get();
// Add the output file -- but don't try to remove "-", since this means we are
// using stdin.
addOutputFile(OutputFile((OutputPathName != "-") ? OutputPathName : "",
- TempPathName, OS));
+ TempPathName, std::move(OS)));
- return OS;
+ return Ret;
}
-llvm::raw_fd_ostream *CompilerInstance::createOutputFile(
+std::unique_ptr<llvm::raw_pwrite_stream> CompilerInstance::createOutputFile(
StringRef OutputPath, std::error_code &Error, bool Binary,
bool RemoveFileOnSignal, StringRef InFile, StringRef Extension,
bool UseTemporary, bool CreateMissingDirectories,
@@ -679,7 +681,13 @@
if (TempPathName)
*TempPathName = TempFile;
- return OS.release();
+ if (!Binary || OS->supportsSeeking())
+ return std::move(OS);
+
+ auto B = llvm::make_unique<llvm::buffer_ostream>(*OS);
+ assert(!NonSeekStream);
+ NonSeekStream = std::move(OS);
+ return std::move(B);
}
// Initialization Utilities
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 5d2cdae..da1a088 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -405,6 +405,10 @@
// Default Dwarf version is 4 if we are generating debug information.
Opts.DwarfVersion = 4;
+ if (const Arg *A =
+ Args.getLastArg(OPT_emit_llvm_uselists, OPT_no_emit_llvm_uselists))
+ Opts.EmitLLVMUseLists = A->getOption().getID() == OPT_emit_llvm_uselists;
+
Opts.DisableLLVMOpts = Args.hasArg(OPT_disable_llvm_optzns);
Opts.DisableRedZone = Args.hasArg(OPT_disable_red_zone);
Opts.ForbidGuardVariables = Args.hasArg(OPT_fforbid_guard_variables);
@@ -451,10 +455,10 @@
Args.hasArg(OPT_cl_finite_math_only) ||
Args.hasArg(OPT_cl_fast_relaxed_math));
Opts.NoSignedZeros = Args.hasArg(OPT_fno_signed_zeros);
+ Opts.ReciprocalMath = Args.hasArg(OPT_freciprocal_math);
Opts.NoZeroInitializedInBSS = Args.hasArg(OPT_mno_zero_initialized_in_bss);
Opts.BackendOptions = Args.getAllArgValues(OPT_backend_option);
Opts.NumRegisterParameters = getLastArgIntValue(Args, OPT_mregparm, 0, Diags);
- Opts.NoGlobalMerge = Args.hasArg(OPT_mno_global_merge);
Opts.NoExecStack = Args.hasArg(OPT_mno_exec_stack);
Opts.FatalWarnings = Args.hasArg(OPT_massembler_fatal_warnings);
Opts.EnableSegmentedStacks = Args.hasArg(OPT_split_stacks);
@@ -1371,6 +1375,9 @@
if (Args.hasArg(OPT_fcuda_allow_host_calls_from_host_device))
Opts.CUDAAllowHostCallsFromHostDevice = 1;
+ if (Args.hasArg(OPT_fcuda_disable_target_call_checks))
+ Opts.CUDADisableTargetCallChecks = 1;
+
if (Opts.ObjC1) {
if (Arg *arg = Args.getLastArg(OPT_fobjc_runtime_EQ)) {
StringRef value = arg->getValue();
diff --git a/lib/Frontend/FrontendAction.cpp b/lib/Frontend/FrontendAction.cpp
index fd251ac..8390624 100644
--- a/lib/Frontend/FrontendAction.cpp
+++ b/lib/Frontend/FrontendAction.cpp
@@ -44,7 +44,7 @@
explicit DelegatingDeserializationListener(
ASTDeserializationListener *Previous, bool DeletePrevious)
: Previous(Previous), DeletePrevious(DeletePrevious) {}
- virtual ~DelegatingDeserializationListener() {
+ ~DelegatingDeserializationListener() override {
if (DeletePrevious)
delete Previous;
}
diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp
index bc11929..0defe5c 100644
--- a/lib/Frontend/FrontendActions.cpp
+++ b/lib/Frontend/FrontendActions.cpp
@@ -79,8 +79,9 @@
GeneratePCHAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
std::string Sysroot;
std::string OutputFile;
- raw_ostream *OS = nullptr;
- if (ComputeASTConsumerArguments(CI, InFile, Sysroot, OutputFile, OS))
+ raw_ostream *OS =
+ ComputeASTConsumerArguments(CI, InFile, Sysroot, OutputFile);
+ if (!OS)
return nullptr;
if (!CI.getFrontendOpts().RelocatablePCH)
@@ -89,28 +90,27 @@
nullptr, Sysroot, OS);
}
-bool GeneratePCHAction::ComputeASTConsumerArguments(CompilerInstance &CI,
- StringRef InFile,
- std::string &Sysroot,
- std::string &OutputFile,
- raw_ostream *&OS) {
+raw_ostream *GeneratePCHAction::ComputeASTConsumerArguments(
+ CompilerInstance &CI, StringRef InFile, std::string &Sysroot,
+ std::string &OutputFile) {
Sysroot = CI.getHeaderSearchOpts().Sysroot;
if (CI.getFrontendOpts().RelocatablePCH && Sysroot.empty()) {
CI.getDiagnostics().Report(diag::err_relocatable_without_isysroot);
- return true;
+ return nullptr;
}
// We use createOutputFile here because this is exposed via libclang, and we
// must disable the RemoveFileOnSignal behavior.
// We use a temporary to avoid race conditions.
- OS = CI.createOutputFile(CI.getFrontendOpts().OutputFile, /*Binary=*/true,
- /*RemoveFileOnSignal=*/false, InFile,
- /*Extension=*/"", /*useTemporary=*/true);
+ raw_ostream *OS =
+ CI.createOutputFile(CI.getFrontendOpts().OutputFile, /*Binary=*/true,
+ /*RemoveFileOnSignal=*/false, InFile,
+ /*Extension=*/"", /*useTemporary=*/true);
if (!OS)
- return true;
+ return nullptr;
OutputFile = CI.getFrontendOpts().OutputFile;
- return false;
+ return OS;
}
std::unique_ptr<ASTConsumer>
@@ -118,8 +118,9 @@
StringRef InFile) {
std::string Sysroot;
std::string OutputFile;
- raw_ostream *OS = nullptr;
- if (ComputeASTConsumerArguments(CI, InFile, Sysroot, OutputFile, OS))
+ raw_ostream *OS =
+ ComputeASTConsumerArguments(CI, InFile, Sysroot, OutputFile);
+ if (!OS)
return nullptr;
return llvm::make_unique<PCHGenerator>(CI.getPreprocessor(), OutputFile,
@@ -355,11 +356,9 @@
return true;
}
-bool GenerateModuleAction::ComputeASTConsumerArguments(CompilerInstance &CI,
- StringRef InFile,
- std::string &Sysroot,
- std::string &OutputFile,
- raw_ostream *&OS) {
+raw_ostream *GenerateModuleAction::ComputeASTConsumerArguments(
+ CompilerInstance &CI, StringRef InFile, std::string &Sysroot,
+ std::string &OutputFile) {
// If no output file was provided, figure out where this module would go
// in the module cache.
if (CI.getFrontendOpts().OutputFile.empty()) {
@@ -368,19 +367,20 @@
HS.getModuleFileName(CI.getLangOpts().CurrentModule,
ModuleMapForUniquing->getName());
}
-
+
// We use createOutputFile here because this is exposed via libclang, and we
// must disable the RemoveFileOnSignal behavior.
// We use a temporary to avoid race conditions.
- OS = CI.createOutputFile(CI.getFrontendOpts().OutputFile, /*Binary=*/true,
- /*RemoveFileOnSignal=*/false, InFile,
- /*Extension=*/"", /*useTemporary=*/true,
- /*CreateMissingDirectories=*/true);
+ raw_ostream *OS =
+ CI.createOutputFile(CI.getFrontendOpts().OutputFile, /*Binary=*/true,
+ /*RemoveFileOnSignal=*/false, InFile,
+ /*Extension=*/"", /*useTemporary=*/true,
+ /*CreateMissingDirectories=*/true);
if (!OS)
- return true;
-
+ return nullptr;
+
OutputFile = CI.getFrontendOpts().OutputFile;
- return false;
+ return OS;
}
std::unique_ptr<ASTConsumer>
@@ -480,9 +480,8 @@
return false;
}
- virtual bool
- ReadDiagnosticOptions(IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts,
- bool Complain) override {
+ bool ReadDiagnosticOptions(IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts,
+ bool Complain) override {
Out.indent(2) << "Diagnostic options:\n";
#define DIAGOPT(Name, Bits, Default) DUMP_BOOLEAN(DiagOpts->Name, #Name);
#define ENUM_DIAGOPT(Name, Type, Bits, Default) \
@@ -600,15 +599,9 @@
void GeneratePTHAction::ExecuteAction() {
CompilerInstance &CI = getCompilerInstance();
- if (CI.getFrontendOpts().OutputFile.empty() ||
- CI.getFrontendOpts().OutputFile == "-") {
- // FIXME: Don't fail this way.
- // FIXME: Verify that we can actually seek in the given file.
- llvm::report_fatal_error("PTH requires a seekable file for output!");
- }
- llvm::raw_fd_ostream *OS =
- CI.createDefaultOutputFile(true, getCurrentFile());
- if (!OS) return;
+ raw_pwrite_stream *OS = CI.createDefaultOutputFile(true, getCurrentFile());
+ if (!OS)
+ return;
CacheTokens(CI.getPreprocessor(), OS);
}
diff --git a/lib/Frontend/HeaderIncludeGen.cpp b/lib/Frontend/HeaderIncludeGen.cpp
index 2701194..5732e5b 100644
--- a/lib/Frontend/HeaderIncludeGen.cpp
+++ b/lib/Frontend/HeaderIncludeGen.cpp
@@ -35,7 +35,7 @@
OwnsOutputFile(OwnsOutputFile_), ShowAllHeaders(ShowAllHeaders_),
ShowDepth(ShowDepth_), MSStyle(MSStyle_) {}
- ~HeaderIncludesCallback() {
+ ~HeaderIncludesCallback() override {
if (OwnsOutputFile)
delete OutputFile;
}
diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp
index 9b4f7e5..2bd999e 100644
--- a/lib/Frontend/InitHeaderSearch.cpp
+++ b/lib/Frontend/InitHeaderSearch.cpp
@@ -232,6 +232,7 @@
case llvm::Triple::NetBSD:
case llvm::Triple::OpenBSD:
case llvm::Triple::Bitrig:
+ case llvm::Triple::NaCl:
break;
default:
// FIXME: temporary hack: hard-coded paths.
@@ -352,6 +353,7 @@
switch (os) {
case llvm::Triple::CloudABI:
case llvm::Triple::RTEMS:
+ case llvm::Triple::NaCl:
break;
default:
AddPath("/usr/include", ExternCSystem, false);
diff --git a/lib/Frontend/Rewrite/RewriteModernObjC.cpp b/lib/Frontend/Rewrite/RewriteModernObjC.cpp
index 12c57cd..e13cdb3 100644
--- a/lib/Frontend/Rewrite/RewriteModernObjC.cpp
+++ b/lib/Frontend/Rewrite/RewriteModernObjC.cpp
@@ -243,8 +243,8 @@
RewriteModernObjC(std::string inFile, raw_ostream *OS,
DiagnosticsEngine &D, const LangOptions &LOpts,
bool silenceMacroWarn, bool LineInfo);
-
- ~RewriteModernObjC() {}
+
+ ~RewriteModernObjC() override {}
void HandleTranslationUnit(ASTContext &C) override;
@@ -886,15 +886,15 @@
FieldDecl *FD = FieldDecl::Create(*Context, nullptr, SourceLocation(),
SourceLocation(),
&Context->Idents.get(D->getNameAsString()),
- IvarT, nullptr,
- /*BitWidth=*/nullptr, /*Mutable=*/true,
- ICIS_NoInit);
- MemberExpr *ME = new (Context)
- MemberExpr(PE, true, SourceLocation(), FD, SourceLocation(),
- FD->getType(), VK_LValue, OK_Ordinary);
- IvarT = Context->getDecltypeType(ME, ME->getType());
- }
- }
+ IvarT, nullptr,
+ /*BitWidth=*/nullptr, /*Mutable=*/true,
+ ICIS_NoInit);
+ MemberExpr *ME = new (Context)
+ MemberExpr(PE, true, SourceLocation(), FD, SourceLocation(),
+ FD->getType(), VK_LValue, OK_Ordinary);
+ IvarT = Context->getDecltypeType(ME, ME->getType());
+ }
+ }
convertObjCTypeToCStyleType(IvarT);
QualType castT = Context->getPointerType(IvarT);
std::string TypeString(castT.getAsString(Context->getPrintingPolicy()));
@@ -2689,7 +2689,7 @@
MsgExprs.push_back(subExpr);
SmallVector<QualType, 4> ArgTypes;
- ArgTypes.push_back(Context->getObjCIdType());
+ ArgTypes.push_back(Context->getObjCClassType());
ArgTypes.push_back(Context->getObjCSelType());
for (const auto PI : BoxingMethod->parameters())
ArgTypes.push_back(PI->getType());
@@ -2764,15 +2764,15 @@
FieldDecl *ARRFD = FieldDecl::Create(*Context, nullptr, SourceLocation(),
SourceLocation(),
&Context->Idents.get("arr"),
- Context->getPointerType(Context->VoidPtrTy),
- nullptr, /*BitWidth=*/nullptr,
- /*Mutable=*/true, ICIS_NoInit);
- MemberExpr *ArrayLiteralME = new (Context)
- MemberExpr(NSArrayCallExpr, false, SourceLocation(), ARRFD,
- SourceLocation(), ARRFD->getType(), VK_LValue, OK_Ordinary);
- QualType ConstIdT = Context->getObjCIdType().withConst();
- CStyleCastExpr * ArrayLiteralObjects =
- NoTypeInfoCStyleCastExpr(Context,
+ Context->getPointerType(Context->VoidPtrTy),
+ nullptr, /*BitWidth=*/nullptr,
+ /*Mutable=*/true, ICIS_NoInit);
+ MemberExpr *ArrayLiteralME = new (Context)
+ MemberExpr(NSArrayCallExpr, false, SourceLocation(), ARRFD,
+ SourceLocation(), ARRFD->getType(), VK_LValue, OK_Ordinary);
+ QualType ConstIdT = Context->getObjCIdType().withConst();
+ CStyleCastExpr * ArrayLiteralObjects =
+ NoTypeInfoCStyleCastExpr(Context,
Context->getPointerType(ConstIdT),
CK_BitCast,
ArrayLiteralME);
@@ -2816,7 +2816,7 @@
SmallVector<QualType, 4> ArgTypes;
- ArgTypes.push_back(Context->getObjCIdType());
+ ArgTypes.push_back(Context->getObjCClassType());
ArgTypes.push_back(Context->getObjCSelType());
for (const auto *PI : ArrayMethod->params())
ArgTypes.push_back(PI->getType());
@@ -2899,30 +2899,30 @@
FieldDecl *ARRFD = FieldDecl::Create(*Context, nullptr, SourceLocation(),
SourceLocation(),
&Context->Idents.get("arr"),
- Context->getPointerType(Context->VoidPtrTy),
- nullptr, /*BitWidth=*/nullptr,
- /*Mutable=*/true, ICIS_NoInit);
- MemberExpr *DictLiteralValueME = new (Context)
- MemberExpr(NSValueCallExpr, false, SourceLocation(), ARRFD,
- SourceLocation(), ARRFD->getType(), VK_LValue, OK_Ordinary);
- QualType ConstIdT = Context->getObjCIdType().withConst();
- CStyleCastExpr * DictValueObjects =
- NoTypeInfoCStyleCastExpr(Context,
+ Context->getPointerType(Context->VoidPtrTy),
+ nullptr, /*BitWidth=*/nullptr,
+ /*Mutable=*/true, ICIS_NoInit);
+ MemberExpr *DictLiteralValueME = new (Context)
+ MemberExpr(NSValueCallExpr, false, SourceLocation(), ARRFD,
+ SourceLocation(), ARRFD->getType(), VK_LValue, OK_Ordinary);
+ QualType ConstIdT = Context->getObjCIdType().withConst();
+ CStyleCastExpr * DictValueObjects =
+ NoTypeInfoCStyleCastExpr(Context,
Context->getPointerType(ConstIdT),
CK_BitCast,
DictLiteralValueME);
// (const id <NSCopying> [])keys
- Expr *NSKeyCallExpr =
- new (Context) CallExpr(*Context, NSDictDRE, KeyExprs,
- NSDictFType, VK_LValue, SourceLocation());
-
- MemberExpr *DictLiteralKeyME = new (Context)
- MemberExpr(NSKeyCallExpr, false, SourceLocation(), ARRFD,
- SourceLocation(), ARRFD->getType(), VK_LValue, OK_Ordinary);
-
- CStyleCastExpr * DictKeyObjects =
- NoTypeInfoCStyleCastExpr(Context,
- Context->getPointerType(ConstIdT),
+ Expr *NSKeyCallExpr =
+ new (Context) CallExpr(*Context, NSDictDRE, KeyExprs,
+ NSDictFType, VK_LValue, SourceLocation());
+
+ MemberExpr *DictLiteralKeyME = new (Context)
+ MemberExpr(NSKeyCallExpr, false, SourceLocation(), ARRFD,
+ SourceLocation(), ARRFD->getType(), VK_LValue, OK_Ordinary);
+
+ CStyleCastExpr * DictKeyObjects =
+ NoTypeInfoCStyleCastExpr(Context,
+ Context->getPointerType(ConstIdT),
CK_BitCast,
DictLiteralKeyME);
@@ -2969,7 +2969,7 @@
SmallVector<QualType, 8> ArgTypes;
- ArgTypes.push_back(Context->getObjCIdType());
+ ArgTypes.push_back(Context->getObjCClassType());
ArgTypes.push_back(Context->getObjCSelType());
for (const auto *PI : DictMethod->params()) {
QualType T = PI->getType();
@@ -3225,15 +3225,15 @@
FieldDecl *FieldD = FieldDecl::Create(*Context, nullptr, SourceLocation(),
SourceLocation(),
&Context->Idents.get("s"),
- returnType, nullptr,
- /*BitWidth=*/nullptr,
- /*Mutable=*/true, ICIS_NoInit);
- MemberExpr *ME = new (Context)
- MemberExpr(STCE, false, SourceLocation(), FieldD, SourceLocation(),
- FieldD->getType(), VK_LValue, OK_Ordinary);
-
- return ME;
-}
+ returnType, nullptr,
+ /*BitWidth=*/nullptr,
+ /*Mutable=*/true, ICIS_NoInit);
+ MemberExpr *ME = new (Context)
+ MemberExpr(STCE, false, SourceLocation(), FieldD, SourceLocation(),
+ FieldD->getType(), VK_LValue, OK_Ordinary);
+
+ return ME;
+}
Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
SourceLocation StartLoc,
@@ -4723,16 +4723,16 @@
FieldDecl *FD = FieldDecl::Create(*Context, nullptr, SourceLocation(),
SourceLocation(),
&Context->Idents.get("FuncPtr"),
- Context->VoidPtrTy, nullptr,
- /*BitWidth=*/nullptr, /*Mutable=*/true,
- ICIS_NoInit);
- MemberExpr *ME =
- new (Context) MemberExpr(PE, true, SourceLocation(), FD, SourceLocation(),
- FD->getType(), VK_LValue, OK_Ordinary);
-
- CastExpr *FunkCast = NoTypeInfoCStyleCastExpr(Context, PtrToFuncCastType,
- CK_BitCast, ME);
- PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), FunkCast);
+ Context->VoidPtrTy, nullptr,
+ /*BitWidth=*/nullptr, /*Mutable=*/true,
+ ICIS_NoInit);
+ MemberExpr *ME =
+ new (Context) MemberExpr(PE, true, SourceLocation(), FD, SourceLocation(),
+ FD->getType(), VK_LValue, OK_Ordinary);
+
+ CastExpr *FunkCast = NoTypeInfoCStyleCastExpr(Context, PtrToFuncCastType,
+ CK_BitCast, ME);
+ PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), FunkCast);
SmallVector<Expr*, 8> BlkExprs;
// Add the implicit argument.
@@ -4771,26 +4771,26 @@
FieldDecl *FD = FieldDecl::Create(*Context, nullptr, SourceLocation(),
SourceLocation(),
&Context->Idents.get("__forwarding"),
- Context->VoidPtrTy, nullptr,
- /*BitWidth=*/nullptr, /*Mutable=*/true,
- ICIS_NoInit);
- MemberExpr *ME = new (Context)
- MemberExpr(DeclRefExp, isArrow, SourceLocation(), FD, SourceLocation(),
- FD->getType(), VK_LValue, OK_Ordinary);
-
- StringRef Name = VD->getName();
- FD = FieldDecl::Create(*Context, nullptr, SourceLocation(), SourceLocation(),
+ Context->VoidPtrTy, nullptr,
+ /*BitWidth=*/nullptr, /*Mutable=*/true,
+ ICIS_NoInit);
+ MemberExpr *ME = new (Context)
+ MemberExpr(DeclRefExp, isArrow, SourceLocation(), FD, SourceLocation(),
+ FD->getType(), VK_LValue, OK_Ordinary);
+
+ StringRef Name = VD->getName();
+ FD = FieldDecl::Create(*Context, nullptr, SourceLocation(), SourceLocation(),
&Context->Idents.get(Name),
- Context->VoidPtrTy, nullptr,
- /*BitWidth=*/nullptr, /*Mutable=*/true,
- ICIS_NoInit);
- ME =
- new (Context) MemberExpr(ME, true, SourceLocation(), FD, SourceLocation(),
- DeclRefExp->getType(), VK_LValue, OK_Ordinary);
-
- // Need parens to enforce precedence.
- ParenExpr *PE = new (Context) ParenExpr(DeclRefExp->getExprLoc(),
- DeclRefExp->getExprLoc(),
+ Context->VoidPtrTy, nullptr,
+ /*BitWidth=*/nullptr, /*Mutable=*/true,
+ ICIS_NoInit);
+ ME =
+ new (Context) MemberExpr(ME, true, SourceLocation(), FD, SourceLocation(),
+ DeclRefExp->getType(), VK_LValue, OK_Ordinary);
+
+ // Need parens to enforce precedence.
+ ParenExpr *PE = new (Context) ParenExpr(DeclRefExp->getExprLoc(),
+ DeclRefExp->getExprLoc(),
ME);
ReplaceStmt(DeclRefExp, PE);
return PE;
@@ -7682,15 +7682,15 @@
FieldDecl *FD = FieldDecl::Create(*Context, nullptr, SourceLocation(),
SourceLocation(),
&Context->Idents.get(D->getNameAsString()),
- IvarT, nullptr,
- /*BitWidth=*/nullptr,
- /*Mutable=*/true, ICIS_NoInit);
- MemberExpr *ME = new (Context)
- MemberExpr(PE, true, SourceLocation(), FD, SourceLocation(),
- FD->getType(), VK_LValue, OK_Ordinary);
- IvarT = Context->getDecltypeType(ME, ME->getType());
- }
- }
+ IvarT, nullptr,
+ /*BitWidth=*/nullptr,
+ /*Mutable=*/true, ICIS_NoInit);
+ MemberExpr *ME = new (Context)
+ MemberExpr(PE, true, SourceLocation(), FD, SourceLocation(),
+ FD->getType(), VK_LValue, OK_Ordinary);
+ IvarT = Context->getDecltypeType(ME, ME->getType());
+ }
+ }
convertObjCTypeToCStyleType(IvarT);
QualType castT = Context->getPointerType(IvarT);
@@ -7711,15 +7711,15 @@
FieldDecl *FD = FieldDecl::Create(*Context, nullptr, SourceLocation(),
SourceLocation(),
&Context->Idents.get(D->getNameAsString()),
- D->getType(), nullptr,
- /*BitWidth=*/D->getBitWidth(),
- /*Mutable=*/true, ICIS_NoInit);
- MemberExpr *ME = new (Context)
- MemberExpr(PE, /*isArrow*/ false, SourceLocation(), FD,
- SourceLocation(), FD->getType(), VK_LValue, OK_Ordinary);
- Replacement = ME;
-
- }
+ D->getType(), nullptr,
+ /*BitWidth=*/D->getBitWidth(),
+ /*Mutable=*/true, ICIS_NoInit);
+ MemberExpr *ME = new (Context)
+ MemberExpr(PE, /*isArrow*/ false, SourceLocation(), FD,
+ SourceLocation(), FD->getType(), VK_LValue, OK_Ordinary);
+ Replacement = ME;
+
+ }
else
Replacement = PE;
}
diff --git a/lib/Frontend/Rewrite/RewriteObjC.cpp b/lib/Frontend/Rewrite/RewriteObjC.cpp
index 5802ba7..170c209 100644
--- a/lib/Frontend/Rewrite/RewriteObjC.cpp
+++ b/lib/Frontend/Rewrite/RewriteObjC.cpp
@@ -193,7 +193,7 @@
DiagnosticsEngine &D, const LangOptions &LOpts,
bool silenceMacroWarn);
- ~RewriteObjC() {}
+ ~RewriteObjC() override {}
void HandleTranslationUnit(ASTContext &C) override;
@@ -511,8 +511,8 @@
bool silenceMacroWarn) : RewriteObjC(inFile, OS,
D, LOpts,
silenceMacroWarn) {}
-
- ~RewriteObjCFragileABI() {}
+
+ ~RewriteObjCFragileABI() override {}
void Initialize(ASTContext &context) override;
// Rewriting metadata
diff --git a/lib/Frontend/SerializedDiagnosticPrinter.cpp b/lib/Frontend/SerializedDiagnosticPrinter.cpp
index 5dcacfa..d31b12e 100644
--- a/lib/Frontend/SerializedDiagnosticPrinter.cpp
+++ b/lib/Frontend/SerializedDiagnosticPrinter.cpp
@@ -61,8 +61,8 @@
DiagnosticOptions *DiagOpts)
: DiagnosticNoteRenderer(LangOpts, DiagOpts), Writer(Writer) {}
- virtual ~SDiagsRenderer() {}
-
+ ~SDiagsRenderer() override {}
+
protected:
void emitDiagnosticMessage(SourceLocation Loc,
PresumedLoc PLoc,
@@ -158,7 +158,7 @@
EmitPreamble();
}
- ~SDiagsWriter() {}
+ ~SDiagsWriter() override {}
void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
const Diagnostic &Info) override;
diff --git a/lib/Frontend/VerifyDiagnosticConsumer.cpp b/lib/Frontend/VerifyDiagnosticConsumer.cpp
index 3ff6b18..910e394 100644
--- a/lib/Frontend/VerifyDiagnosticConsumer.cpp
+++ b/lib/Frontend/VerifyDiagnosticConsumer.cpp
@@ -58,9 +58,9 @@
/// \brief Hook into the preprocessor and update the list of parsed
/// files when the preprocessor indicates a new file is entered.
- virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
- SrcMgr::CharacteristicKind FileType,
- FileID PrevFID) {
+ void FileChanged(SourceLocation Loc, FileChangeReason Reason,
+ SrcMgr::CharacteristicKind FileType,
+ FileID PrevFID) override {
Verify.UpdateParsedFileStatus(SM, SM.getFileID(Loc),
VerifyDiagnosticConsumer::IsParsed);
}
diff --git a/lib/Headers/CMakeLists.txt b/lib/Headers/CMakeLists.txt
index 080550f..5429092 100644
--- a/lib/Headers/CMakeLists.txt
+++ b/lib/Headers/CMakeLists.txt
@@ -18,6 +18,8 @@
float.h
fma4intrin.h
fmaintrin.h
+ htmintrin.h
+ htmxlintrin.h
ia32intrin.h
immintrin.h
Intrin.h
@@ -34,6 +36,7 @@
prfchwintrin.h
rdseedintrin.h
rtmintrin.h
+ s390intrin.h
shaintrin.h
smmintrin.h
stdalign.h
diff --git a/lib/Headers/avx2intrin.h b/lib/Headers/avx2intrin.h
index 7485bdd..949195b 100644
--- a/lib/Headers/avx2intrin.h
+++ b/lib/Headers/avx2intrin.h
@@ -160,7 +160,7 @@
#define _mm256_blend_epi16(V1, V2, M) __extension__ ({ \
__m256i __V1 = (V1); \
__m256i __V2 = (V2); \
- (__m256d)__builtin_shufflevector((__v16hi)__V1, (__v16hi)__V2, \
+ (__m256i)__builtin_shufflevector((__v16hi)__V1, (__v16hi)__V2, \
(((M) & 0x01) ? 16 : 0), \
(((M) & 0x02) ? 17 : 1), \
(((M) & 0x04) ? 18 : 2), \
diff --git a/lib/Headers/avx512fintrin.h b/lib/Headers/avx512fintrin.h
index c6d46cb..72af281 100644
--- a/lib/Headers/avx512fintrin.h
+++ b/lib/Headers/avx512fintrin.h
@@ -162,6 +162,168 @@
return __builtin_shufflevector(__a, __a, 0, 1, 2, 3);
}
+/* Bitwise operators */
+static __inline__ __m512i __attribute__((__always_inline__, __nodebug__))
+_mm512_and_epi32(__m512i __a, __m512i __b)
+{
+ return __a & __b;
+}
+
+static __inline__ __m512i __attribute__((__always_inline__, __nodebug__))
+_mm512_mask_and_epi32(__m512i __src, __mmask16 __k, __m512i __a, __m512i __b)
+{
+ return (__m512i) __builtin_ia32_pandd512_mask((__v16si) __a,
+ (__v16si) __b,
+ (__v16si) __src,
+ (__mmask16) __k);
+}
+static __inline__ __m512i __attribute__((__always_inline__, __nodebug__))
+_mm512_maskz_and_epi32(__mmask16 __k, __m512i __a, __m512i __b)
+{
+ return (__m512i) __builtin_ia32_pandd512_mask((__v16si) __a,
+ (__v16si) __b,
+ (__v16si)
+ _mm512_setzero_si512 (),
+ (__mmask16) __k);
+}
+
+static __inline__ __m512i __attribute__((__always_inline__, __nodebug__))
+_mm512_and_epi64(__m512i __a, __m512i __b)
+{
+ return __a & __b;
+}
+
+static __inline__ __m512i __attribute__((__always_inline__, __nodebug__))
+_mm512_mask_and_epi64(__m512i __src, __mmask8 __k, __m512i __a, __m512i __b)
+{
+ return (__m512i) __builtin_ia32_pandq512_mask ((__v8di) __a,
+ (__v8di) __b,
+ (__v8di) __src,
+ (__mmask8) __k);
+}
+static __inline__ __m512i __attribute__((__always_inline__, __nodebug__))
+_mm512_maskz_and_epi64(__mmask8 __k, __m512i __a, __m512i __b)
+{
+ return (__m512i) __builtin_ia32_pandq512_mask ((__v8di) __a,
+ (__v8di) __b,
+ (__v8di)
+ _mm512_setzero_si512 (),
+ (__mmask8) __k);
+}
+
+static __inline__ __m512i __attribute__((__always_inline__, __nodebug__))
+_mm512_or_epi32(__m512i __a, __m512i __b)
+{
+ return __a | __b;
+}
+
+static __inline__ __m512i __attribute__((__always_inline__, __nodebug__))
+_mm512_mask_or_epi32(__m512i __src, __mmask16 __k, __m512i __a, __m512i __b)
+{
+ return (__m512i) __builtin_ia32_pord512_mask((__v16si) __a,
+ (__v16si) __b,
+ (__v16si) __src,
+ (__mmask16) __k);
+}
+static __inline__ __m512i __attribute__((__always_inline__, __nodebug__))
+_mm512_maskz_or_epi32(__mmask16 __k, __m512i __a, __m512i __b)
+{
+ return (__m512i) __builtin_ia32_pord512_mask((__v16si) __a,
+ (__v16si) __b,
+ (__v16si)
+ _mm512_setzero_si512 (),
+ (__mmask16) __k);
+}
+
+static __inline__ __m512i __attribute__((__always_inline__, __nodebug__))
+_mm512_or_epi64(__m512i __a, __m512i __b)
+{
+ return __a | __b;
+}
+
+static __inline__ __m512i __attribute__((__always_inline__, __nodebug__))
+_mm512_mask_or_epi64(__m512i __src, __mmask8 __k, __m512i __a, __m512i __b)
+{
+ return (__m512i) __builtin_ia32_porq512_mask ((__v8di) __a,
+ (__v8di) __b,
+ (__v8di) __src,
+ (__mmask8) __k);
+}
+static __inline__ __m512i __attribute__((__always_inline__, __nodebug__))
+_mm512_maskz_or_epi64(__mmask8 __k, __m512i __a, __m512i __b)
+{
+ return (__m512i) __builtin_ia32_porq512_mask ((__v8di) __a,
+ (__v8di) __b,
+ (__v8di)
+ _mm512_setzero_si512 (),
+ (__mmask8) __k);
+}
+
+static __inline__ __m512i __attribute__((__always_inline__, __nodebug__))
+_mm512_xor_epi32(__m512i __a, __m512i __b)
+{
+ return __a ^ __b;
+}
+
+static __inline__ __m512i __attribute__((__always_inline__, __nodebug__))
+_mm512_mask_xor_epi32(__m512i __src, __mmask16 __k, __m512i __a, __m512i __b)
+{
+ return (__m512i) __builtin_ia32_pxord512_mask((__v16si) __a,
+ (__v16si) __b,
+ (__v16si) __src,
+ (__mmask16) __k);
+}
+static __inline__ __m512i __attribute__((__always_inline__, __nodebug__))
+_mm512_maskz_xor_epi32(__mmask16 __k, __m512i __a, __m512i __b)
+{
+ return (__m512i) __builtin_ia32_pxord512_mask((__v16si) __a,
+ (__v16si) __b,
+ (__v16si)
+ _mm512_setzero_si512 (),
+ (__mmask16) __k);
+}
+
+static __inline__ __m512i __attribute__((__always_inline__, __nodebug__))
+_mm512_xor_epi64(__m512i __a, __m512i __b)
+{
+ return __a ^ __b;
+}
+
+static __inline__ __m512i __attribute__((__always_inline__, __nodebug__))
+_mm512_mask_xor_epi64(__m512i __src, __mmask8 __k, __m512i __a, __m512i __b)
+{
+ return (__m512i) __builtin_ia32_pxorq512_mask ((__v8di) __a,
+ (__v8di) __b,
+ (__v8di) __src,
+ (__mmask8) __k);
+}
+static __inline__ __m512i __attribute__((__always_inline__, __nodebug__))
+_mm512_maskz_xor_epi64(__mmask8 __k, __m512i __a, __m512i __b)
+{
+ return (__m512i) __builtin_ia32_pxorq512_mask ((__v8di) __a,
+ (__v8di) __b,
+ (__v8di)
+ _mm512_setzero_si512 (),
+ (__mmask8) __k);
+}
+
+static __inline__ __m512i __attribute__((__always_inline__, __nodebug__))
+_mm512_and_si512(__m512i __a, __m512i __b)
+{
+ return __a & __b;
+}
+
+static __inline__ __m512i __attribute__((__always_inline__, __nodebug__))
+_mm512_or_si512(__m512i __a, __m512i __b)
+{
+ return __a | __b;
+}
+
+static __inline__ __m512i __attribute__((__always_inline__, __nodebug__))
+_mm512_xor_si512(__m512i __a, __m512i __b)
+{
+ return __a ^ __b;
+}
/* Arithmetic */
static __inline __m512d __attribute__((__always_inline__, __nodebug__))
diff --git a/lib/Headers/htmintrin.h b/lib/Headers/htmintrin.h
index 4598ee0..0088c7c 100644
--- a/lib/Headers/htmintrin.h
+++ b/lib/Headers/htmintrin.h
@@ -128,4 +128,99 @@
#endif /* __powerpc */
+#ifdef __s390__
+
+/* Condition codes generated by tbegin */
+#define _HTM_TBEGIN_STARTED 0
+#define _HTM_TBEGIN_INDETERMINATE 1
+#define _HTM_TBEGIN_TRANSIENT 2
+#define _HTM_TBEGIN_PERSISTENT 3
+
+/* The abort codes below this threshold are reserved for machine use. */
+#define _HTM_FIRST_USER_ABORT_CODE 256
+
+/* The transaction diagnostic block is it is defined in the Principles
+ of Operation chapter 5-91. */
+
+struct __htm_tdb {
+ unsigned char format; /* 0 */
+ unsigned char flags;
+ unsigned char reserved1[4];
+ unsigned short nesting_depth;
+ unsigned long long abort_code; /* 8 */
+ unsigned long long conflict_token; /* 16 */
+ unsigned long long atia; /* 24 */
+ unsigned char eaid; /* 32 */
+ unsigned char dxc;
+ unsigned char reserved2[2];
+ unsigned int program_int_id;
+ unsigned long long exception_id; /* 40 */
+ unsigned long long bea; /* 48 */
+ unsigned char reserved3[72]; /* 56 */
+ unsigned long long gprs[16]; /* 128 */
+} __attribute__((__packed__, __aligned__ (8)));
+
+
+/* Helper intrinsics to retry tbegin in case of transient failure. */
+
+static __inline int __attribute__((__always_inline__, __nodebug__))
+__builtin_tbegin_retry_null (int retry)
+{
+ int cc, i = 0;
+
+ while ((cc = __builtin_tbegin(0)) == _HTM_TBEGIN_TRANSIENT
+ && i++ < retry)
+ __builtin_tx_assist(i);
+
+ return cc;
+}
+
+static __inline int __attribute__((__always_inline__, __nodebug__))
+__builtin_tbegin_retry_tdb (void *tdb, int retry)
+{
+ int cc, i = 0;
+
+ while ((cc = __builtin_tbegin(tdb)) == _HTM_TBEGIN_TRANSIENT
+ && i++ < retry)
+ __builtin_tx_assist(i);
+
+ return cc;
+}
+
+#define __builtin_tbegin_retry(tdb, retry) \
+ (__builtin_constant_p(tdb == 0) && tdb == 0 ? \
+ __builtin_tbegin_retry_null(retry) : \
+ __builtin_tbegin_retry_tdb(tdb, retry))
+
+static __inline int __attribute__((__always_inline__, __nodebug__))
+__builtin_tbegin_retry_nofloat_null (int retry)
+{
+ int cc, i = 0;
+
+ while ((cc = __builtin_tbegin_nofloat(0)) == _HTM_TBEGIN_TRANSIENT
+ && i++ < retry)
+ __builtin_tx_assist(i);
+
+ return cc;
+}
+
+static __inline int __attribute__((__always_inline__, __nodebug__))
+__builtin_tbegin_retry_nofloat_tdb (void *tdb, int retry)
+{
+ int cc, i = 0;
+
+ while ((cc = __builtin_tbegin_nofloat(tdb)) == _HTM_TBEGIN_TRANSIENT
+ && i++ < retry)
+ __builtin_tx_assist(i);
+
+ return cc;
+}
+
+#define __builtin_tbegin_retry_nofloat(tdb, retry) \
+ (__builtin_constant_p(tdb == 0) && tdb == 0 ? \
+ __builtin_tbegin_retry_nofloat_null(retry) : \
+ __builtin_tbegin_retry_nofloat_tdb(tdb, retry))
+
+#endif /* __s390__ */
+
#endif /* __HTMINTRIN_H */
diff --git a/lib/Headers/htmxlintrin.h b/lib/Headers/htmxlintrin.h
index 8791afe..30f524d 100644
--- a/lib/Headers/htmxlintrin.h
+++ b/lib/Headers/htmxlintrin.h
@@ -212,4 +212,152 @@
#endif /* __powerpc__ */
+#ifdef __s390__
+
+#include <stdint.h>
+
+/* These intrinsics are being made available for compatibility with
+ the IBM XL compiler. For documentation please see the "z/OS XL
+ C/C++ Programming Guide" publically available on the web. */
+
+static __inline long __attribute__((__always_inline__, __nodebug__))
+__TM_simple_begin ()
+{
+ return __builtin_tbegin_nofloat (0);
+}
+
+static __inline long __attribute__((__always_inline__, __nodebug__))
+__TM_begin (void* const tdb)
+{
+ return __builtin_tbegin_nofloat (tdb);
+}
+
+static __inline long __attribute__((__always_inline__, __nodebug__))
+__TM_end ()
+{
+ return __builtin_tend ();
+}
+
+static __inline void __attribute__((__always_inline__))
+__TM_abort ()
+{
+ return __builtin_tabort (_HTM_FIRST_USER_ABORT_CODE);
+}
+
+static __inline void __attribute__((__always_inline__, __nodebug__))
+__TM_named_abort (unsigned char const code)
+{
+ return __builtin_tabort ((int)_HTM_FIRST_USER_ABORT_CODE + code);
+}
+
+static __inline void __attribute__((__always_inline__, __nodebug__))
+__TM_non_transactional_store (void* const addr, long long const value)
+{
+ __builtin_non_tx_store ((uint64_t*)addr, (uint64_t)value);
+}
+
+static __inline long __attribute__((__always_inline__, __nodebug__))
+__TM_nesting_depth (void* const tdb_ptr)
+{
+ int depth = __builtin_tx_nesting_depth ();
+ struct __htm_tdb *tdb = (struct __htm_tdb*)tdb_ptr;
+
+ if (depth != 0)
+ return depth;
+
+ if (tdb->format != 1)
+ return 0;
+ return tdb->nesting_depth;
+}
+
+/* Transaction failure diagnostics */
+
+static __inline long __attribute__((__always_inline__, __nodebug__))
+__TM_is_user_abort (void* const tdb_ptr)
+{
+ struct __htm_tdb *tdb = (struct __htm_tdb*)tdb_ptr;
+
+ if (tdb->format != 1)
+ return 0;
+
+ return !!(tdb->abort_code >= _HTM_FIRST_USER_ABORT_CODE);
+}
+
+static __inline long __attribute__((__always_inline__, __nodebug__))
+__TM_is_named_user_abort (void* const tdb_ptr, unsigned char* code)
+{
+ struct __htm_tdb *tdb = (struct __htm_tdb*)tdb_ptr;
+
+ if (tdb->format != 1)
+ return 0;
+
+ if (tdb->abort_code >= _HTM_FIRST_USER_ABORT_CODE)
+ {
+ *code = tdb->abort_code - _HTM_FIRST_USER_ABORT_CODE;
+ return 1;
+ }
+ return 0;
+}
+
+static __inline long __attribute__((__always_inline__, __nodebug__))
+__TM_is_illegal (void* const tdb_ptr)
+{
+ struct __htm_tdb *tdb = (struct __htm_tdb*)tdb_ptr;
+
+ return (tdb->format == 1
+ && (tdb->abort_code == 4 /* unfiltered program interruption */
+ || tdb->abort_code == 11 /* restricted instruction */));
+}
+
+static __inline long __attribute__((__always_inline__, __nodebug__))
+__TM_is_footprint_exceeded (void* const tdb_ptr)
+{
+ struct __htm_tdb *tdb = (struct __htm_tdb*)tdb_ptr;
+
+ return (tdb->format == 1
+ && (tdb->abort_code == 7 /* fetch overflow */
+ || tdb->abort_code == 8 /* store overflow */));
+}
+
+static __inline long __attribute__((__always_inline__, __nodebug__))
+__TM_is_nested_too_deep (void* const tdb_ptr)
+{
+ struct __htm_tdb *tdb = (struct __htm_tdb*)tdb_ptr;
+
+ return tdb->format == 1 && tdb->abort_code == 13; /* depth exceeded */
+}
+
+static __inline long __attribute__((__always_inline__, __nodebug__))
+__TM_is_conflict (void* const tdb_ptr)
+{
+ struct __htm_tdb *tdb = (struct __htm_tdb*)tdb_ptr;
+
+ return (tdb->format == 1
+ && (tdb->abort_code == 9 /* fetch conflict */
+ || tdb->abort_code == 10 /* store conflict */));
+}
+
+static __inline long __attribute__((__always_inline__, __nodebug__))
+__TM_is_failure_persistent (long const result)
+{
+ return result == _HTM_TBEGIN_PERSISTENT;
+}
+
+static __inline long __attribute__((__always_inline__, __nodebug__))
+__TM_failure_address (void* const tdb_ptr)
+{
+ struct __htm_tdb *tdb = (struct __htm_tdb*)tdb_ptr;
+ return tdb->atia;
+}
+
+static __inline long __attribute__((__always_inline__, __nodebug__))
+__TM_failure_code (void* const tdb_ptr)
+{
+ struct __htm_tdb *tdb = (struct __htm_tdb*)tdb_ptr;
+
+ return tdb->abort_code;
+}
+
+#endif /* __s390__ */
+
#endif /* __HTMXLINTRIN_H */
diff --git a/lib/Headers/module.modulemap b/lib/Headers/module.modulemap
index 062464e..bb2ca95 100644
--- a/lib/Headers/module.modulemap
+++ b/lib/Headers/module.modulemap
@@ -169,6 +169,19 @@
header "__wmmintrin_pclmul.h"
}
}
+
+ explicit module systemz {
+ requires systemz
+ export *
+
+ header "s390intrin.h"
+
+ explicit module htm {
+ requires htm
+ header "htmintrin.h"
+ header "htmxlintrin.h"
+ }
+ }
}
module _Builtin_stddef_max_align_t [system] [extern_c] {
diff --git a/lib/Headers/s390intrin.h b/lib/Headers/s390intrin.h
new file mode 100644
index 0000000..b209895
--- /dev/null
+++ b/lib/Headers/s390intrin.h
@@ -0,0 +1,35 @@
+/*===---- s390intrin.h - SystemZ intrinsics --------------------------------===
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ *===-----------------------------------------------------------------------===
+ */
+
+#ifndef __S390INTRIN_H
+#define __S390INTRIN_H
+
+#ifndef __s390__
+#error "<s390intrin.h> is for s390 only"
+#endif
+
+#ifdef __HTM__
+#include <htmintrin.h>
+#endif
+
+#endif /* __S390INTRIN_H*/
diff --git a/lib/Index/SimpleFormatContext.h b/lib/Index/SimpleFormatContext.h
index 080a4ad..b884214 100644
--- a/lib/Index/SimpleFormatContext.h
+++ b/lib/Index/SimpleFormatContext.h
@@ -44,8 +44,6 @@
Diagnostics->setClient(new IgnoringDiagConsumer, true);
}
- ~SimpleFormatContext() { }
-
FileID createInMemoryFile(StringRef Name, StringRef Content) {
std::unique_ptr<llvm::MemoryBuffer> Source =
llvm::MemoryBuffer::getMemBuffer(Content);
diff --git a/lib/Lex/LiteralSupport.cpp b/lib/Lex/LiteralSupport.cpp
index af3e27f..aed9164 100644
--- a/lib/Lex/LiteralSupport.cpp
+++ b/lib/Lex/LiteralSupport.cpp
@@ -597,7 +597,8 @@
if (isFloat) break; // LF invalid.
// Check for long long. The L's need to be adjacent and the same case.
- if (s+1 != ThisTokEnd && s[1] == s[0]) {
+ if (s[1] == s[0]) {
+ assert(s + 1 < ThisTokEnd && "didn't maximally munch?");
if (isFPConstant) break; // long long invalid for floats.
isLongLong = true;
++s; // Eat both of them.
@@ -611,54 +612,45 @@
if (isLong || isLongLong || MicrosoftInteger)
break;
- // Allow i8, i16, i32, i64, and i128.
- if (s + 1 != ThisTokEnd) {
+ if (!isFPConstant) {
+ // Allow i8, i16, i32, i64, and i128.
switch (s[1]) {
- case '8':
- if (isFPConstant) break;
- s += 2; // i8 suffix
- MicrosoftInteger = 8;
- break;
- case '1':
- if (isFPConstant) break;
- if (s + 2 == ThisTokEnd) break;
- if (s[2] == '6') {
- s += 3; // i16 suffix
- MicrosoftInteger = 16;
- }
- else if (s[2] == '2') {
- if (s + 3 == ThisTokEnd) break;
- if (s[3] == '8') {
- s += 4; // i128 suffix
- MicrosoftInteger = 128;
- }
- }
- break;
- case '3':
- if (isFPConstant) break;
- if (s + 2 == ThisTokEnd) break;
- if (s[2] == '2') {
- s += 3; // i32 suffix
- MicrosoftInteger = 32;
- }
- break;
- case '6':
- if (isFPConstant) break;
- if (s + 2 == ThisTokEnd) break;
- if (s[2] == '4') {
- s += 3; // i64 suffix
- MicrosoftInteger = 64;
- }
- break;
- default:
- break;
- }
- if (MicrosoftInteger)
+ case '8':
+ s += 2; // i8 suffix
+ MicrosoftInteger = 8;
break;
+ case '1':
+ if (s[2] == '6') {
+ s += 3; // i16 suffix
+ MicrosoftInteger = 16;
+ } else if (s[2] == '2' && s[3] == '8') {
+ s += 4; // i128 suffix
+ MicrosoftInteger = 128;
+ }
+ break;
+ case '3':
+ if (s[2] == '2') {
+ s += 3; // i32 suffix
+ MicrosoftInteger = 32;
+ }
+ break;
+ case '6':
+ if (s[2] == '4') {
+ s += 3; // i64 suffix
+ MicrosoftInteger = 64;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ if (MicrosoftInteger) {
+ assert(s <= ThisTokEnd && "didn't maximally munch?");
+ break;
}
}
// "i", "if", and "il" are user-defined suffixes in C++1y.
- if (PP.getLangOpts().CPlusPlus14 && *s == 'i')
+ if (*s == 'i' && PP.getLangOpts().CPlusPlus14)
break;
// fall through.
case 'j':
@@ -756,11 +748,11 @@
s++;
int c1 = s[0];
- int c2 = s[1];
// Handle a hex number like 0x1234.
- if ((c1 == 'x' || c1 == 'X') && (isHexDigit(c2) || c2 == '.')) {
+ if ((c1 == 'x' || c1 == 'X') && (isHexDigit(s[1]) || s[1] == '.')) {
s++;
+ assert(s < ThisTokEnd && "didn't maximally munch?");
radix = 16;
DigitsBegin = s;
s = SkipHexDigits(s);
@@ -812,7 +804,7 @@
}
// Handle simple binary numbers 0b01010
- if ((c1 == 'b' || c1 == 'B') && (c2 == '0' || c2 == '1')) {
+ if ((c1 == 'b' || c1 == 'B') && (s[1] == '0' || s[1] == '1')) {
// 0b101010 is a C++1y / GCC extension.
PP.Diag(TokLoc,
PP.getLangOpts().CPlusPlus14
@@ -821,6 +813,7 @@
? diag::ext_binary_literal_cxx14
: diag::ext_binary_literal);
++s;
+ assert(s < ThisTokEnd && "didn't maximally munch?");
radix = 2;
DigitsBegin = s;
s = SkipBinaryDigits(s);
diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp
index 7763181..3ceba05 100644
--- a/lib/Lex/PPMacroExpansion.cpp
+++ b/lib/Lex/PPMacroExpansion.cpp
@@ -1073,6 +1073,9 @@
// These expressions are only allowed within a preprocessor directive.
if (!PP.isParsingIfOrElifDirective()) {
PP.Diag(LParenLoc, diag::err_pp_directive_required) << II->getName();
+ // Return a valid identifier token.
+ assert(Tok.is(tok::identifier));
+ Tok.setIdentifierInfo(II);
return false;
}
@@ -1461,9 +1464,11 @@
Value = EvaluateHasInclude(Tok, II, *this);
else
Value = EvaluateHasIncludeNext(Tok, II, *this);
+
+ if (Tok.isNot(tok::r_paren))
+ return;
OS << (int)Value;
- if (Tok.is(tok::r_paren))
- Tok.setKind(tok::numeric_constant);
+ Tok.setKind(tok::numeric_constant);
} else if (II == Ident__has_warning) {
// The argument should be a parenthesized string literal.
// The argument to these builtins should be a parenthesized identifier.
diff --git a/lib/Lex/ScratchBuffer.cpp b/lib/Lex/ScratchBuffer.cpp
index 3bac889..cd8a27e 100644
--- a/lib/Lex/ScratchBuffer.cpp
+++ b/lib/Lex/ScratchBuffer.cpp
@@ -64,12 +64,13 @@
if (RequestLen < ScratchBufSize)
RequestLen = ScratchBufSize;
+ // Get scratch buffer. Zero-initialize it so it can be dumped into a PCH file
+ // deterministically.
std::unique_ptr<llvm::MemoryBuffer> OwnBuf =
llvm::MemoryBuffer::getNewMemBuffer(RequestLen, "<scratch space>");
llvm::MemoryBuffer &Buf = *OwnBuf;
FileID FID = SourceMgr.createFileID(std::move(OwnBuf));
BufferStartLoc = SourceMgr.getLocForStartOfFile(FID);
CurBuffer = const_cast<char*>(Buf.getBufferStart());
- BytesUsed = 1;
- CurBuffer[0] = '0'; // Start out with a \0 for cleanliness.
+ BytesUsed = 0;
}
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 5726fb6..8f4afdf 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -4782,7 +4782,8 @@
D.AddTypeInfo(DeclaratorChunk::getPointer(DS.getTypeQualifiers(), Loc,
DS.getConstSpecLoc(),
DS.getVolatileSpecLoc(),
- DS.getRestrictSpecLoc()),
+ DS.getRestrictSpecLoc(),
+ DS.getAtomicSpecLoc()),
DS.getAttributes(),
SourceLocation());
else
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index ec19f35..c74b028 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -799,7 +799,10 @@
// The operand of the decltype specifier is an unevaluated operand.
EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated,
nullptr,/*IsDecltype=*/true);
- Result = Actions.CorrectDelayedTyposInExpr(ParseExpression());
+ Result =
+ Actions.CorrectDelayedTyposInExpr(ParseExpression(), [](Expr *E) {
+ return E->hasPlaceholderType() ? ExprError() : E;
+ });
if (Result.isInvalid()) {
DS.SetTypeSpecError();
if (SkipUntil(tok::r_paren, StopAtSemi | StopBeforeMatch)) {
@@ -3527,7 +3530,9 @@
// Alternative tokens do not have identifier info, but their spelling
// starts with an alphabetical character.
SmallString<8> SpellingBuf;
- StringRef Spelling = PP.getSpelling(Tok.getLocation(), SpellingBuf);
+ SourceLocation SpellingLoc =
+ PP.getSourceManager().getSpellingLoc(Tok.getLocation());
+ StringRef Spelling = PP.getSpelling(SpellingLoc, SpellingBuf);
if (isLetter(Spelling[0])) {
Loc = ConsumeToken();
return &PP.getIdentifierTable().get(Spelling);
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index 72af14d..315c957 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -928,7 +928,8 @@
Res = Actions.ActOnIdExpression(
getCurScope(), ScopeSpec, TemplateKWLoc, Name, Tok.is(tok::l_paren),
isAddressOfOperand, std::move(Validator),
- /*IsInlineAsmIdentifier=*/false, &Replacement);
+ /*IsInlineAsmIdentifier=*/false,
+ Tok.is(tok::r_paren) ? nullptr : &Replacement);
if (!Res.isInvalid() && !Res.get()) {
UnconsumeToken(Replacement);
return ParseCastExpression(isUnaryExpression, isAddressOfOperand,
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index 1030072..08606d0 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -2535,7 +2535,7 @@
if (SS.isNotEmpty())
ObjectType = ParsedType();
if (Tok.isNot(tok::identifier) || NextToken().is(tok::coloncolon) ||
- SS.isInvalid()) {
+ !SS.isSet()) {
Diag(TildeLoc, diag::err_destructor_tilde_scope);
return true;
}
diff --git a/lib/Parse/ParseOpenMP.cpp b/lib/Parse/ParseOpenMP.cpp
index 764619a..143ef70 100644
--- a/lib/Parse/ParseOpenMP.cpp
+++ b/lib/Parse/ParseOpenMP.cpp
@@ -257,13 +257,8 @@
// Parse statement
AssociatedStmt = ParseStatement();
Actions.ActOnFinishOfCompoundStmt();
- if (!AssociatedStmt.isUsable()) {
- Actions.ActOnCapturedRegionError();
- CreateDirective = false;
- } else {
- AssociatedStmt = Actions.ActOnCapturedRegionEnd(AssociatedStmt.get());
- CreateDirective = AssociatedStmt.isUsable();
- }
+ AssociatedStmt = Actions.ActOnOpenMPRegionEnd(AssociatedStmt, Clauses);
+ CreateDirective = AssociatedStmt.isUsable();
}
if (CreateDirective)
Directive = Actions.ActOnOpenMPExecutableDirective(
diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp
index d15f2af..c31216d 100644
--- a/lib/Parse/ParseStmt.cpp
+++ b/lib/Parse/ParseStmt.cpp
@@ -476,7 +476,7 @@
{
ParseScopeFlags FilterScope(this, getCurScope()->getFlags() |
Scope::SEHFilterScope);
- FilterExpr = ParseExpression();
+ FilterExpr = Actions.CorrectDelayedTyposInExpr(ParseExpression());
}
if (getLangOpts().Borland) {
diff --git a/lib/Parse/ParseStmtAsm.cpp b/lib/Parse/ParseStmtAsm.cpp
index 9523ec3..85eff17 100644
--- a/lib/Parse/ParseStmtAsm.cpp
+++ b/lib/Parse/ParseStmtAsm.cpp
@@ -530,7 +530,7 @@
TheTarget->createMCAsmParser(*STI, *Parser, *MII, MCOptions));
std::unique_ptr<llvm::MCInstPrinter> IP(
- TheTarget->createMCInstPrinter(1, *MAI, *MII, *MRI, *STI));
+ TheTarget->createMCInstPrinter(llvm::Triple(TT), 1, *MAI, *MII, *MRI));
// Change to the Intel dialect.
Parser->setAssemblerDialect(1);
diff --git a/lib/Rewrite/RewriteRope.cpp b/lib/Rewrite/RewriteRope.cpp
index 1c82ee4..451ad07 100644
--- a/lib/Rewrite/RewriteRope.cpp
+++ b/lib/Rewrite/RewriteRope.cpp
@@ -89,9 +89,9 @@
bool IsLeaf;
RopePieceBTreeNode(bool isLeaf) : Size(0), IsLeaf(isLeaf) {}
- ~RopePieceBTreeNode() {}
- public:
+ ~RopePieceBTreeNode() = default;
+ public:
bool isLeaf() const { return IsLeaf; }
unsigned size() const { return Size; }
diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp
index 8ee2410..d697ecb 100644
--- a/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/lib/Sema/AnalysisBasedWarnings.cpp
@@ -139,7 +139,7 @@
return false;
}
- void compareAlwaysTrue(const BinaryOperator *B, bool isAlwaysTrue) {
+ void compareAlwaysTrue(const BinaryOperator *B, bool isAlwaysTrue) override {
if (HasMacroID(B))
return;
@@ -148,7 +148,8 @@
<< DiagRange << isAlwaysTrue;
}
- void compareBitwiseEquality(const BinaryOperator *B, bool isAlwaysTrue) {
+ void compareBitwiseEquality(const BinaryOperator *B,
+ bool isAlwaysTrue) override {
if (HasMacroID(B))
return;
@@ -1333,9 +1334,7 @@
public:
UninitValsDiagReporter(Sema &S) : S(S), uses(nullptr) {}
- ~UninitValsDiagReporter() {
- flushDiagnostics();
- }
+ ~UninitValsDiagReporter() override { flushDiagnostics(); }
MappedType &getUses(const VarDecl *vd) {
if (!uses)
@@ -1663,9 +1662,8 @@
}
}
-
- virtual void handleNegativeNotHeld(StringRef Kind, Name LockName, Name Neg,
- SourceLocation Loc) override {
+ void handleNegativeNotHeld(StringRef Kind, Name LockName, Name Neg,
+ SourceLocation Loc) override {
PartialDiagnosticAt Warning(Loc,
S.PDiag(diag::warn_acquire_requires_negative_cap)
<< Kind << LockName << Neg);
@@ -1680,17 +1678,14 @@
Warnings.push_back(DelayedDiag(Warning, getNotes()));
}
-
- virtual void handleLockAcquiredBefore(StringRef Kind, Name L1Name,
- Name L2Name, SourceLocation Loc)
- override {
+ void handleLockAcquiredBefore(StringRef Kind, Name L1Name, Name L2Name,
+ SourceLocation Loc) override {
PartialDiagnosticAt Warning(Loc,
S.PDiag(diag::warn_acquired_before) << Kind << L1Name << L2Name);
Warnings.push_back(DelayedDiag(Warning, getNotes()));
}
- virtual void handleBeforeAfterCycle(Name L1Name, SourceLocation Loc)
- override {
+ void handleBeforeAfterCycle(Name L1Name, SourceLocation Loc) override {
PartialDiagnosticAt Warning(Loc,
S.PDiag(diag::warn_acquired_before_after_cycle) << L1Name);
Warnings.push_back(DelayedDiag(Warning, getNotes()));
diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp
index f6689a9..1e7fc75 100644
--- a/lib/Sema/DeclSpec.cpp
+++ b/lib/Sema/DeclSpec.cpp
@@ -345,8 +345,9 @@
bool Declarator::isStaticMember() {
assert(getContext() == MemberContext);
return getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static ||
- CXXMethodDecl::isStaticOverloadedOperator(
- getName().OperatorFunctionId.Operator);
+ (getName().Kind == UnqualifiedId::IK_OperatorFunctionId &&
+ CXXMethodDecl::isStaticOverloadedOperator(
+ getName().OperatorFunctionId.Operator));
}
bool DeclSpec::hasTagDefinition() const {
diff --git a/lib/Sema/SemaCUDA.cpp b/lib/Sema/SemaCUDA.cpp
index 6033821..5973500 100644
--- a/lib/Sema/SemaCUDA.cpp
+++ b/lib/Sema/SemaCUDA.cpp
@@ -62,6 +62,11 @@
bool Sema::CheckCUDATarget(const FunctionDecl *Caller,
const FunctionDecl *Callee) {
+ // The CUDADisableTargetCallChecks short-circuits this check: we assume all
+ // cross-target calls are valid.
+ if (getLangOpts().CUDADisableTargetCallChecks)
+ return false;
+
CUDAFunctionTarget CallerTarget = IdentifyCUDATarget(Caller),
CalleeTarget = IdentifyCUDATarget(Callee);
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index abcccba..05eaaec 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -546,11 +546,21 @@
if (CheckMipsBuiltinFunctionCall(BuiltinID, TheCall))
return ExprError();
break;
+ case llvm::Triple::systemz:
+ if (CheckSystemZBuiltinFunctionCall(BuiltinID, TheCall))
+ return ExprError();
+ break;
case llvm::Triple::x86:
case llvm::Triple::x86_64:
if (CheckX86BuiltinFunctionCall(BuiltinID, TheCall))
return ExprError();
break;
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ case llvm::Triple::ppc64le:
+ if (CheckPPCBuiltinFunctionCall(BuiltinID, TheCall))
+ return ExprError();
+ break;
default:
break;
}
@@ -895,6 +905,63 @@
return SemaBuiltinConstantArgRange(TheCall, i, l, u);
}
+bool Sema::CheckPPCBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
+ unsigned i = 0, l = 0, u = 0;
+ bool Is64BitBltin = BuiltinID == PPC::BI__builtin_divde ||
+ BuiltinID == PPC::BI__builtin_divdeu ||
+ BuiltinID == PPC::BI__builtin_bpermd;
+ bool IsTarget64Bit = Context.getTargetInfo()
+ .getTypeWidth(Context
+ .getTargetInfo()
+ .getIntPtrType()) == 64;
+ bool IsBltinExtDiv = BuiltinID == PPC::BI__builtin_divwe ||
+ BuiltinID == PPC::BI__builtin_divweu ||
+ BuiltinID == PPC::BI__builtin_divde ||
+ BuiltinID == PPC::BI__builtin_divdeu;
+
+ if (Is64BitBltin && !IsTarget64Bit)
+ return Diag(TheCall->getLocStart(), diag::err_64_bit_builtin_32_bit_tgt)
+ << TheCall->getSourceRange();
+
+ if ((IsBltinExtDiv && !Context.getTargetInfo().hasFeature("extdiv")) ||
+ (BuiltinID == PPC::BI__builtin_bpermd &&
+ !Context.getTargetInfo().hasFeature("bpermd")))
+ return Diag(TheCall->getLocStart(), diag::err_ppc_builtin_only_on_pwr7)
+ << TheCall->getSourceRange();
+
+ switch (BuiltinID) {
+ default: return false;
+ case PPC::BI__builtin_altivec_crypto_vshasigmaw:
+ case PPC::BI__builtin_altivec_crypto_vshasigmad:
+ return SemaBuiltinConstantArgRange(TheCall, 1, 0, 1) ||
+ SemaBuiltinConstantArgRange(TheCall, 2, 0, 15);
+ case PPC::BI__builtin_tbegin:
+ case PPC::BI__builtin_tend: i = 0; l = 0; u = 1; break;
+ case PPC::BI__builtin_tsr: i = 0; l = 0; u = 7; break;
+ case PPC::BI__builtin_tabortwc:
+ case PPC::BI__builtin_tabortdc: i = 0; l = 0; u = 31; break;
+ case PPC::BI__builtin_tabortwci:
+ case PPC::BI__builtin_tabortdci:
+ return SemaBuiltinConstantArgRange(TheCall, 0, 0, 31) ||
+ SemaBuiltinConstantArgRange(TheCall, 2, 0, 31);
+ }
+ return SemaBuiltinConstantArgRange(TheCall, i, l, u);
+}
+
+bool Sema::CheckSystemZBuiltinFunctionCall(unsigned BuiltinID,
+ CallExpr *TheCall) {
+ if (BuiltinID == SystemZ::BI__builtin_tabort) {
+ Expr *Arg = TheCall->getArg(0);
+ llvm::APSInt AbortCode(32);
+ if (Arg->isIntegerConstantExpr(AbortCode, Context) &&
+ AbortCode.getSExtValue() >= 0 && AbortCode.getSExtValue() < 256)
+ return Diag(Arg->getLocStart(), diag::err_systemz_invalid_tabort_code)
+ << Arg->getSourceRange();
+ }
+
+ return false;
+}
+
bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
unsigned i = 0, l = 0, u = 0;
switch (BuiltinID) {
@@ -7660,6 +7727,35 @@
(void) AnalyzeBitFieldAssignment(*this, BitField, Init, InitLoc);
}
+static void diagnoseArrayStarInParamType(Sema &S, QualType PType,
+ SourceLocation Loc) {
+ if (!PType->isVariablyModifiedType())
+ return;
+ if (const auto *PointerTy = dyn_cast<PointerType>(PType)) {
+ diagnoseArrayStarInParamType(S, PointerTy->getPointeeType(), Loc);
+ return;
+ }
+ if (const auto *ReferenceTy = dyn_cast<ReferenceType>(PType)) {
+ diagnoseArrayStarInParamType(S, ReferenceTy->getPointeeType(), Loc);
+ return;
+ }
+ if (const auto *ParenTy = dyn_cast<ParenType>(PType)) {
+ diagnoseArrayStarInParamType(S, ParenTy->getInnerType(), Loc);
+ return;
+ }
+
+ const ArrayType *AT = S.Context.getAsArrayType(PType);
+ if (!AT)
+ return;
+
+ if (AT->getSizeModifier() != ArrayType::Star) {
+ diagnoseArrayStarInParamType(S, AT->getElementType(), Loc);
+ return;
+ }
+
+ S.Diag(Loc, diag::err_array_star_in_function_definition);
+}
+
/// CheckParmsForFunctionDef - Check that the parameters of the given
/// function are appropriate for the definition of a function. This
/// takes care of any checks that cannot be performed on the
@@ -7698,15 +7794,9 @@
// notation in their sequences of declarator specifiers to specify
// variable length array types.
QualType PType = Param->getOriginalType();
- while (const ArrayType *AT = Context.getAsArrayType(PType)) {
- if (AT->getSizeModifier() == ArrayType::Star) {
- // FIXME: This diagnostic should point the '[*]' if source-location
- // information is added for it.
- Diag(Param->getLocation(), diag::err_array_star_in_function_definition);
- break;
- }
- PType= AT->getElementType();
- }
+ // FIXME: This diagnostic should point the '[*]' if source-location
+ // information is added for it.
+ diagnoseArrayStarInParamType(*this, PType, Param->getLocation());
// MSVC destroys objects passed by value in the callee. Therefore a
// function definition which takes such a parameter must be able to call the
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 9bbfeaf..1bad38f 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -7489,23 +7489,10 @@
// Handle attributes.
ProcessDeclAttributes(S, NewFD, D);
- QualType RetType = NewFD->getReturnType();
- const CXXRecordDecl *Ret = RetType->isRecordType() ?
- RetType->getAsCXXRecordDecl() : RetType->getPointeeCXXRecordDecl();
- if (!NewFD->isInvalidDecl() && !NewFD->hasAttr<WarnUnusedResultAttr>() &&
- Ret && Ret->hasAttr<WarnUnusedResultAttr>()) {
- const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(NewFD);
- // Attach WarnUnusedResult to functions returning types with that attribute.
- // Don't apply the attribute to that type's own non-static member functions
- // (to avoid warning on things like assignment operators)
- if (!MD || MD->getParent() != Ret)
- NewFD->addAttr(WarnUnusedResultAttr::CreateImplicit(Context));
- }
-
if (getLangOpts().OpenCL) {
// OpenCL v1.1 s6.5: Using an address space qualifier in a function return
// type declaration will generate a compilation error.
- unsigned AddressSpace = RetType.getAddressSpace();
+ unsigned AddressSpace = NewFD->getReturnType().getAddressSpace();
if (AddressSpace == LangAS::opencl_local ||
AddressSpace == LangAS::opencl_global ||
AddressSpace == LangAS::opencl_constant) {
@@ -10282,6 +10269,18 @@
if (canRedefineFunction(Definition, getLangOpts()))
return;
+ // If we don't have a visible definition of the function, and it's inline or
+ // a template, it's OK to form another definition of it.
+ //
+ // FIXME: Should we skip the body of the function and use the old definition
+ // in this case? That may be necessary for functions that return local types
+ // through a deduced return type, or instantiate templates with local types.
+ if (!hasVisibleDefinition(Definition) &&
+ (Definition->isInlineSpecified() ||
+ Definition->getDescribedFunctionTemplate() ||
+ Definition->getNumTemplateParameterLists()))
+ return;
+
if (getLangOpts().GNUMode && Definition->isInlineSpecified() &&
Definition->getStorageClass() == SC_Extern)
Diag(FD->getLocation(), diag::err_redefinition_extern_inline)
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 1c50d77..4f3fed5 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -51,6 +51,11 @@
static bool isFunctionOrMethod(const Decl *D) {
return (D->getFunctionType() != nullptr) || isa<ObjCMethodDecl>(D);
}
+/// \brief Return true if the given decl has function type (function or
+/// function-typed variable) or an Objective-C method or a block.
+static bool isFunctionOrMethodOrBlock(const Decl *D) {
+ return isFunctionOrMethod(D) || isa<BlockDecl>(D);
+}
/// Return true if the given decl has a declarator that should have
/// been processed by Sema::GetTypeForDeclarator.
@@ -257,7 +262,7 @@
unsigned AttrArgNum,
const Expr *IdxExpr,
uint64_t &Idx) {
- assert(isFunctionOrMethod(D));
+ assert(isFunctionOrMethodOrBlock(D));
// In C++ the implicit 'this' function parameter also counts.
// Parameters are counted from one.
@@ -1611,7 +1616,7 @@
// The checking path for 'noreturn' and 'analyzer_noreturn' are different
// because 'analyzer_noreturn' does not impact the type.
- if (!isFunctionOrMethod(D) && !isa<BlockDecl>(D)) {
+ if (!isFunctionOrMethodOrBlock(D)) {
ValueDecl *VD = dyn_cast<ValueDecl>(D);
if (!VD || (!VD->getType()->isBlockPointerType() &&
!VD->getType()->isFunctionPointerType())) {
@@ -2127,6 +2132,22 @@
Attr.getAttributeSpellingListIndex()));
}
+static void handleObjCIndependentClass(Sema &S, Decl *D, const AttributeList &Attr) {
+ if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) {
+ QualType T = TD->getUnderlyingType();
+ if (!T->isObjCObjectPointerType()) {
+ S.Diag(TD->getLocation(), diag::warn_ptr_independentclass_attribute);
+ return;
+ }
+ } else {
+ S.Diag(D->getLocation(), diag::warn_independentclass_attribute);
+ return;
+ }
+ D->addAttr(::new (S.Context)
+ ObjCIndependentClassAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
+}
+
static void handleBlocksAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (!Attr.isArgIdent(0)) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type)
@@ -2873,6 +2894,16 @@
if (!Attr.isPackExpansion() && S.DiagnoseUnexpandedParameterPack(E))
return;
+ if (E->isValueDependent()) {
+ if (const auto *TND = dyn_cast<TypedefNameDecl>(D)) {
+ if (!TND->getUnderlyingType()->isDependentType()) {
+ S.Diag(Attr.getLoc(), diag::err_alignment_dependent_typedef_name)
+ << E->getSourceRange();
+ return;
+ }
+ }
+ }
+
S.AddAlignedAttr(Attr.getRange(), D, E, Attr.getAttributeSpellingListIndex(),
Attr.isPackExpansion());
}
@@ -4676,6 +4707,9 @@
case AttributeList::AT_ObjCNSObject:
handleObjCNSObject(S, D, Attr);
break;
+ case AttributeList::AT_ObjCIndependentClass:
+ handleObjCIndependentClass(S, D, Attr);
+ break;
case AttributeList::AT_Blocks:
handleBlocksAttr(S, D, Attr);
break;
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index f7183bc..b0e6aca 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -316,8 +316,17 @@
if (DiagnoseUnexpandedParameterPack(DefaultArg, UPPC_DefaultArgument)) {
Param->setInvalidDecl();
return;
- }
-
+ }
+
+ // C++11 [dcl.fct.default]p3
+ // A default argument expression [...] shall not be specified for a
+ // parameter pack.
+ if (Param->isParameterPack()) {
+ Diag(EqualLoc, diag::err_param_default_argument_on_parameter_pack)
+ << DefaultArg->getSourceRange();
+ return;
+ }
+
// Check that the default argument is well-formed
CheckDefaultArgumentVisitor DefaultArgChecker(DefaultArg, this);
if (DefaultArgChecker.Visit(DefaultArg)) {
@@ -606,7 +615,8 @@
<< New << New->isConstexpr();
Diag(Old->getLocation(), diag::note_previous_declaration);
Invalid = true;
- } else if (!Old->isInlined() && New->isInlined() && Old->isDefined(Def)) {
+ } else if (!Old->getMostRecentDecl()->isInlined() && New->isInlined() &&
+ Old->isDefined(Def)) {
// C++11 [dcl.fcn.spec]p4:
// If the definition of a function appears in a translation unit before its
// first declaration as inline, the program is ill-formed.
@@ -688,16 +698,16 @@
break;
}
- // C++ [dcl.fct.default]p4:
- // In a given function declaration, all parameters
- // subsequent to a parameter with a default argument shall
- // have default arguments supplied in this or previous
- // declarations. A default argument shall not be redefined
- // by a later declaration (not even to the same value).
+ // C++11 [dcl.fct.default]p4:
+ // In a given function declaration, each parameter subsequent to a parameter
+ // with a default argument shall have a default argument supplied in this or
+ // a previous declaration or shall be a function parameter pack. A default
+ // argument shall not be redefined by a later declaration (not even to the
+ // same value).
unsigned LastMissingDefaultArg = 0;
for (; p < NumParams; ++p) {
ParmVarDecl *Param = FD->getParamDecl(p);
- if (!Param->hasDefaultArg()) {
+ if (!Param->hasDefaultArg() && !Param->isParameterPack()) {
if (Param->isInvalidDecl())
/* We already complained about this parameter. */;
else if (Param->getIdentifier())
@@ -8082,15 +8092,7 @@
if (RequireCompleteDeclContext(SS, LookupContext))
return BuildInvalid();
- // The normal rules do not apply to inheriting constructor declarations.
- if (NameInfo.getName().getNameKind() == DeclarationName::CXXConstructorName) {
- UsingDecl *UD = BuildValid();
- CheckInheritingConstructorUsingDecl(UD);
- return UD;
- }
-
- // Otherwise, look up the target name.
-
+ // Look up the target name.
LookupResult R(*this, NameInfo, LookupOrdinaryName);
// Unlike most lookups, we don't always want to hide tag
@@ -8109,8 +8111,12 @@
LookupQualifiedName(R, LookupContext);
- // Try to correct typos if possible.
- if (R.empty()) {
+ // Try to correct typos if possible. If constructor name lookup finds no
+ // results, that means the named class has no explicit constructors, and we
+ // suppressed declaring implicit ones (probably because it's dependent or
+ // invalid).
+ if (R.empty() &&
+ NameInfo.getName().getNameKind() != DeclarationName::CXXConstructorName) {
if (TypoCorrection Corrected = CorrectTypo(
R.getLookupNameInfo(), R.getLookupKind(), S, &SS,
llvm::make_unique<UsingValidatorCCC>(
@@ -8140,16 +8146,12 @@
NameInfo.setName(Context.DeclarationNames.getCXXConstructorName(
Context.getCanonicalType(Context.getRecordType(RD))));
NameInfo.setNamedTypeInfo(nullptr);
-
- // Build it and process it as an inheriting constructor.
- UsingDecl *UD = BuildValid();
- CheckInheritingConstructorUsingDecl(UD);
- return UD;
+ for (auto *Ctor : LookupConstructors(RD))
+ R.addDecl(Ctor);
+ } else {
+ // FIXME: Pick up all the declarations if we found an overloaded function.
+ R.addDecl(ND);
}
-
- // FIXME: Pick up all the declarations if we found an overloaded function.
- R.setLookupName(Corrected.getCorrection());
- R.addDecl(ND);
} else {
Diag(IdentLoc, diag::err_no_member)
<< NameInfo.getName() << LookupContext << SS.getRange();
@@ -8189,6 +8191,18 @@
}
UsingDecl *UD = BuildValid();
+
+ // The normal rules do not apply to inheriting constructor declarations.
+ if (NameInfo.getName().getNameKind() == DeclarationName::CXXConstructorName) {
+ // Suppress access diagnostics; the access check is instead performed at the
+ // point of use for an inheriting constructor.
+ R.suppressDiagnostics();
+ CheckInheritingConstructorUsingDecl(UD);
+ return UD;
+ }
+
+ // Otherwise, look up the target name.
+
for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
UsingShadowDecl *PrevDecl = nullptr;
if (!CheckUsingShadowDecl(UD, *I, Previous, PrevDecl))
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index 4865b08..dc47ce9 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -2240,8 +2240,14 @@
if (getLangOpts().Modules && !getLangOpts().CurrentModule.empty())
continue;
- if (!MatchTwoMethodDeclarations(Method, List->getMethod()))
+ if (!MatchTwoMethodDeclarations(Method, List->getMethod())) {
+ // Even if two method types do not match, we would like to say
+ // there is more than one declaration so unavailability/deprecated
+ // warning is not too noisy.
+ if (!Method->isDefined())
+ List->setHasMoreThanOneDecl(true);
continue;
+ }
ObjCMethodDecl *PrevObjCMethod = List->getMethod();
@@ -2340,19 +2346,33 @@
return Methods.size() > 1;
}
-bool Sema::AreMultipleMethodsInGlobalPool(Selector Sel, bool instance) {
+bool Sema::AreMultipleMethodsInGlobalPool(Selector Sel, ObjCMethodDecl *BestMethod,
+ SourceRange R,
+ bool receiverIdOrClass) {
GlobalMethodPool::iterator Pos = MethodPool.find(Sel);
// Test for no method in the pool which should not trigger any warning by
// caller.
if (Pos == MethodPool.end())
return true;
- ObjCMethodList &MethList = instance ? Pos->second.first : Pos->second.second;
+ ObjCMethodList &MethList =
+ BestMethod->isInstanceMethod() ? Pos->second.first : Pos->second.second;
+
+ // Diagnose finding more than one method in global pool
+ SmallVector<ObjCMethodDecl *, 4> Methods;
+ Methods.push_back(BestMethod);
+ for (ObjCMethodList *M = &MethList; M; M = M->getNext())
+ if (M->getMethod() && !M->getMethod()->isHidden() &&
+ M->getMethod() != BestMethod)
+ Methods.push_back(M->getMethod());
+ if (Methods.size() > 1)
+ DiagnoseMultipleMethodInGlobalPool(Methods, Sel, R, receiverIdOrClass);
+
return MethList.hasMoreThanOneDecl();
}
ObjCMethodDecl *Sema::LookupMethodInGlobalPool(Selector Sel, SourceRange R,
bool receiverIdOrClass,
- bool warn, bool instance) {
+ bool instance) {
if (ExternalSource)
ReadMethodPool(Sel);
@@ -2364,31 +2384,23 @@
ObjCMethodList &MethList = instance ? Pos->second.first : Pos->second.second;
SmallVector<ObjCMethodDecl *, 4> Methods;
for (ObjCMethodList *M = &MethList; M; M = M->getNext()) {
- if (M->getMethod() && !M->getMethod()->isHidden()) {
- // If we're not supposed to warn about mismatches, we're done.
- if (!warn)
- return M->getMethod();
-
- Methods.push_back(M->getMethod());
- }
+ if (M->getMethod() && !M->getMethod()->isHidden())
+ return M->getMethod();
}
+ return nullptr;
+}
- // If there aren't any visible methods, we're done.
- // FIXME: Recover if there are any known-but-hidden methods?
- if (Methods.empty())
- return nullptr;
-
- if (Methods.size() == 1)
- return Methods[0];
-
+void Sema::DiagnoseMultipleMethodInGlobalPool(SmallVectorImpl<ObjCMethodDecl*> &Methods,
+ Selector Sel, SourceRange R,
+ bool receiverIdOrClass) {
// We found multiple methods, so we may have to complain.
bool issueDiagnostic = false, issueError = false;
-
+
// We support a warning which complains about *any* difference in
// method signature.
bool strictSelectorMatch =
- receiverIdOrClass && warn &&
- !Diags.isIgnored(diag::warn_strict_multiple_method_decl, R.getBegin());
+ receiverIdOrClass &&
+ !Diags.isIgnored(diag::warn_strict_multiple_method_decl, R.getBegin());
if (strictSelectorMatch) {
for (unsigned I = 1, N = Methods.size(); I != N; ++I) {
if (!MatchTwoMethodDeclarations(Methods[0], Methods[I], MMS_strict)) {
@@ -2397,7 +2409,7 @@
}
}
}
-
+
// If we didn't see any strict differences, we won't see any loose
// differences. In ARC, however, we also need to check for loose
// mismatches, because most of them are errors.
@@ -2413,7 +2425,7 @@
break;
}
}
-
+
if (issueDiagnostic) {
if (issueError)
Diag(R.getBegin(), diag::err_arc_multiple_method_decl) << Sel << R;
@@ -2421,16 +2433,15 @@
Diag(R.getBegin(), diag::warn_strict_multiple_method_decl) << Sel << R;
else
Diag(R.getBegin(), diag::warn_multiple_method_decl) << Sel << R;
-
+
Diag(Methods[0]->getLocStart(),
issueError ? diag::note_possibility : diag::note_using)
- << Methods[0]->getSourceRange();
+ << Methods[0]->getSourceRange();
for (unsigned I = 1, N = Methods.size(); I != N; ++I) {
Diag(Methods[I]->getLocStart(), diag::note_also_found)
- << Methods[I]->getSourceRange();
+ << Methods[I]->getSourceRange();
+ }
}
- }
- return Methods[0];
}
ObjCMethodDecl *Sema::LookupImplementedMethodInGlobalPool(Selector Sel) {
@@ -2574,10 +2585,9 @@
case Decl::ObjCProtocol:
return Sema::OCK_Protocol;
case Decl::ObjCCategory:
- if (dyn_cast<ObjCCategoryDecl>(CurContext)->IsClassExtension())
+ if (cast<ObjCCategoryDecl>(CurContext)->IsClassExtension())
return Sema::OCK_ClassExtension;
- else
- return Sema::OCK_Category;
+ return Sema::OCK_Category;
case Decl::ObjCImplementation:
return Sema::OCK_Implementation;
case Decl::ObjCCategoryImpl:
@@ -3289,7 +3299,7 @@
case OMF_alloc:
case OMF_new:
- InferRelatedResultType = ObjCMethod->isClassMethod();
+ InferRelatedResultType = ObjCMethod->isClassMethod();
break;
case OMF_init:
@@ -3300,7 +3310,8 @@
break;
}
- if (InferRelatedResultType)
+ if (InferRelatedResultType &&
+ !ObjCMethod->getReturnType()->isObjCIndependentClassType())
ObjCMethod->SetRelatedResultType();
}
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 6eac5b6..d18aeab 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -4608,6 +4608,83 @@
return hasInvalid;
}
+/// If a builtin function has a pointer argument with no explicit address
+/// space, than it should be able to accept a pointer to any address
+/// space as input. In order to do this, we need to replace the
+/// standard builtin declaration with one that uses the same address space
+/// as the call.
+///
+/// \returns nullptr If this builtin is not a candidate for a rewrite i.e.
+/// it does not contain any pointer arguments without
+/// an address space qualifer. Otherwise the rewritten
+/// FunctionDecl is returned.
+/// TODO: Handle pointer return types.
+static FunctionDecl *rewriteBuiltinFunctionDecl(Sema *Sema, ASTContext &Context,
+ const FunctionDecl *FDecl,
+ MultiExprArg ArgExprs) {
+
+ QualType DeclType = FDecl->getType();
+ const FunctionProtoType *FT = dyn_cast<FunctionProtoType>(DeclType);
+
+ if (!Context.BuiltinInfo.hasPtrArgsOrResult(FDecl->getBuiltinID()) ||
+ !FT || FT->isVariadic() || ArgExprs.size() != FT->getNumParams())
+ return nullptr;
+
+ bool NeedsNewDecl = false;
+ unsigned i = 0;
+ SmallVector<QualType, 8> OverloadParams;
+
+ for (QualType ParamType : FT->param_types()) {
+
+ // Convert array arguments to pointer to simplify type lookup.
+ Expr *Arg = Sema->DefaultFunctionArrayLvalueConversion(ArgExprs[i++]).get();
+ QualType ArgType = Arg->getType();
+ if (!ParamType->isPointerType() ||
+ ParamType.getQualifiers().hasAddressSpace() ||
+ !ArgType->isPointerType() ||
+ !ArgType->getPointeeType().getQualifiers().hasAddressSpace()) {
+ OverloadParams.push_back(ParamType);
+ continue;
+ }
+
+ NeedsNewDecl = true;
+ unsigned AS = ArgType->getPointeeType().getQualifiers().getAddressSpace();
+
+ QualType PointeeType = ParamType->getPointeeType();
+ PointeeType = Context.getAddrSpaceQualType(PointeeType, AS);
+ OverloadParams.push_back(Context.getPointerType(PointeeType));
+ }
+
+ if (!NeedsNewDecl)
+ return nullptr;
+
+ FunctionProtoType::ExtProtoInfo EPI;
+ QualType OverloadTy = Context.getFunctionType(FT->getReturnType(),
+ OverloadParams, EPI);
+ DeclContext *Parent = Context.getTranslationUnitDecl();
+ FunctionDecl *OverloadDecl = FunctionDecl::Create(Context, Parent,
+ FDecl->getLocation(),
+ FDecl->getLocation(),
+ FDecl->getIdentifier(),
+ OverloadTy,
+ /*TInfo=*/nullptr,
+ SC_Extern, false,
+ /*hasPrototype=*/true);
+ SmallVector<ParmVarDecl*, 16> Params;
+ FT = cast<FunctionProtoType>(OverloadTy);
+ for (unsigned i = 0, e = FT->getNumParams(); i != e; ++i) {
+ QualType ParamType = FT->getParamType(i);
+ ParmVarDecl *Parm =
+ ParmVarDecl::Create(Context, OverloadDecl, SourceLocation(),
+ SourceLocation(), nullptr, ParamType,
+ /*TInfo=*/nullptr, SC_None, nullptr);
+ Parm->setScopeInfo(0, i);
+ Params.push_back(Parm);
+ }
+ OverloadDecl->setParams(Params);
+ return OverloadDecl;
+}
+
/// ActOnCallExpr - Handle a call to Fn with the specified array of arguments.
/// This provides the location of the left/right parens and a list of comma
/// locations.
@@ -4711,10 +4788,24 @@
if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(NakedFn))
if (UnOp->getOpcode() == UO_AddrOf)
NakedFn = UnOp->getSubExpr()->IgnoreParens();
-
- if (isa<DeclRefExpr>(NakedFn))
+
+ if (isa<DeclRefExpr>(NakedFn)) {
NDecl = cast<DeclRefExpr>(NakedFn)->getDecl();
- else if (isa<MemberExpr>(NakedFn))
+
+ FunctionDecl *FDecl = dyn_cast<FunctionDecl>(NDecl);
+ if (FDecl && FDecl->getBuiltinID()) {
+ // Rewrite the function decl for this builtin by replacing paramaters
+ // with no explicit address space with the address space of the arguments
+ // in ArgExprs.
+ if ((FDecl = rewriteBuiltinFunctionDecl(this, Context, FDecl, ArgExprs))) {
+ NDecl = FDecl;
+ Fn = DeclRefExpr::Create(Context, FDecl->getQualifierLoc(),
+ SourceLocation(), FDecl, false,
+ SourceLocation(), FDecl->getType(),
+ Fn->getValueKind(), FDecl);
+ }
+ }
+ } else if (isa<MemberExpr>(NakedFn))
NDecl = cast<MemberExpr>(NakedFn)->getMemberDecl();
if (FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(NDecl)) {
@@ -8084,8 +8175,7 @@
if (Type->isObjCIdType()) {
// For 'id', just check the global pool.
Method = S.LookupInstanceMethodInGlobalPool(IsEqualSel, SourceRange(),
- /*receiverId=*/true,
- /*warn=*/false);
+ /*receiverId=*/true);
} else {
// Check protocols.
Method = S.LookupMethodInQualifiedType(IsEqualSel, Type,
@@ -8891,6 +8981,139 @@
return (isa<BlockDecl>(DC) ? NCCK_Block : NCCK_Lambda);
}
+static bool IsTypeModifiable(QualType Ty, bool IsDereference) {
+ Ty = Ty.getNonReferenceType();
+ if (IsDereference && Ty->isPointerType())
+ Ty = Ty->getPointeeType();
+ return !Ty.isConstQualified();
+}
+
+/// Emit the "read-only variable not assignable" error and print notes to give
+/// more information about why the variable is not assignable, such as pointing
+/// to the declaration of a const variable, showing that a method is const, or
+/// that the function is returning a const reference.
+static void DiagnoseConstAssignment(Sema &S, const Expr *E,
+ SourceLocation Loc) {
+ // Update err_typecheck_assign_const and note_typecheck_assign_const
+ // when this enum is changed.
+ enum {
+ ConstFunction,
+ ConstVariable,
+ ConstMember,
+ ConstMethod,
+ ConstUnknown, // Keep as last element
+ };
+
+ SourceRange ExprRange = E->getSourceRange();
+
+ // Only emit one error on the first const found. All other consts will emit
+ // a note to the error.
+ bool DiagnosticEmitted = false;
+
+ // Track if the current expression is the result of a derefence, and if the
+ // next checked expression is the result of a derefence.
+ bool IsDereference = false;
+ bool NextIsDereference = false;
+
+ // Loop to process MemberExpr chains.
+ while (true) {
+ IsDereference = NextIsDereference;
+ NextIsDereference = false;
+
+ E = E->IgnoreParenImpCasts();
+ if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
+ NextIsDereference = ME->isArrow();
+ const ValueDecl *VD = ME->getMemberDecl();
+ if (const FieldDecl *Field = dyn_cast<FieldDecl>(VD)) {
+ // Mutable fields can be modified even if the class is const.
+ if (Field->isMutable()) {
+ assert(DiagnosticEmitted && "Expected diagnostic not emitted.");
+ break;
+ }
+
+ if (!IsTypeModifiable(Field->getType(), IsDereference)) {
+ if (!DiagnosticEmitted) {
+ S.Diag(Loc, diag::err_typecheck_assign_const)
+ << ExprRange << ConstMember << false /*static*/ << Field
+ << Field->getType();
+ DiagnosticEmitted = true;
+ }
+ S.Diag(VD->getLocation(), diag::note_typecheck_assign_const)
+ << ConstMember << false /*static*/ << Field << Field->getType()
+ << Field->getSourceRange();
+ }
+ E = ME->getBase();
+ continue;
+ } else if (const VarDecl *VDecl = dyn_cast<VarDecl>(VD)) {
+ if (VDecl->getType().isConstQualified()) {
+ if (!DiagnosticEmitted) {
+ S.Diag(Loc, diag::err_typecheck_assign_const)
+ << ExprRange << ConstMember << true /*static*/ << VDecl
+ << VDecl->getType();
+ DiagnosticEmitted = true;
+ }
+ S.Diag(VD->getLocation(), diag::note_typecheck_assign_const)
+ << ConstMember << true /*static*/ << VDecl << VDecl->getType()
+ << VDecl->getSourceRange();
+ }
+ // Static fields do not inherit constness from parents.
+ break;
+ }
+ break;
+ } // End MemberExpr
+ break;
+ }
+
+ if (const CallExpr *CE = dyn_cast<CallExpr>(E)) {
+ // Function calls
+ const FunctionDecl *FD = CE->getDirectCallee();
+ if (!IsTypeModifiable(FD->getReturnType(), IsDereference)) {
+ if (!DiagnosticEmitted) {
+ S.Diag(Loc, diag::err_typecheck_assign_const) << ExprRange
+ << ConstFunction << FD;
+ DiagnosticEmitted = true;
+ }
+ S.Diag(FD->getReturnTypeSourceRange().getBegin(),
+ diag::note_typecheck_assign_const)
+ << ConstFunction << FD << FD->getReturnType()
+ << FD->getReturnTypeSourceRange();
+ }
+ } else if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
+ // Point to variable declaration.
+ if (const ValueDecl *VD = DRE->getDecl()) {
+ if (!IsTypeModifiable(VD->getType(), IsDereference)) {
+ if (!DiagnosticEmitted) {
+ S.Diag(Loc, diag::err_typecheck_assign_const)
+ << ExprRange << ConstVariable << VD << VD->getType();
+ DiagnosticEmitted = true;
+ }
+ S.Diag(VD->getLocation(), diag::note_typecheck_assign_const)
+ << ConstVariable << VD << VD->getType() << VD->getSourceRange();
+ }
+ }
+ } else if (isa<CXXThisExpr>(E)) {
+ if (const DeclContext *DC = S.getFunctionLevelDeclContext()) {
+ if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC)) {
+ if (MD->isConst()) {
+ if (!DiagnosticEmitted) {
+ S.Diag(Loc, diag::err_typecheck_assign_const) << ExprRange
+ << ConstMethod << MD;
+ DiagnosticEmitted = true;
+ }
+ S.Diag(MD->getLocation(), diag::note_typecheck_assign_const)
+ << ConstMethod << MD << MD->getSourceRange();
+ }
+ }
+ }
+ }
+
+ if (DiagnosticEmitted)
+ return;
+
+ // Can't determine a more specific message, so display the generic error.
+ S.Diag(Loc, diag::err_typecheck_assign_const) << ExprRange << ConstUnknown;
+}
+
/// CheckForModifiableLvalue - Verify that E is a modifiable lvalue. If not,
/// emit an error and return true. If so, return false.
static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
@@ -8907,8 +9130,6 @@
bool NeedType = false;
switch (IsLV) { // C99 6.5.16p2
case Expr::MLV_ConstQualified:
- DiagID = diag::err_typecheck_assign_const;
-
// Use a specialized diagnostic when we're assigning to an object
// from an enclosing function or block.
if (NonConstCaptureKind NCCK = isReferenceToNonConstCapture(S, E)) {
@@ -8947,13 +9168,20 @@
if (Loc != OrigLoc)
Assign = SourceRange(OrigLoc, OrigLoc);
S.Diag(Loc, DiagID) << E->getSourceRange() << Assign;
- // We need to preserve the AST regardless, so migration tool
+ // We need to preserve the AST regardless, so migration tool
// can do its job.
return false;
}
}
}
+ // If none of the special cases above are triggered, then this is a
+ // simple const assignment.
+ if (DiagID == 0) {
+ DiagnoseConstAssignment(S, E, Loc);
+ return true;
+ }
+
break;
case Expr::MLV_ArrayType:
case Expr::MLV_ArrayTemporary:
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 5c43e0c..b050c93 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -1418,8 +1418,9 @@
<< ConvTy->isEnumeralType() << ConvTy;
}
- virtual SemaDiagnosticBuilder diagnoseConversion(
- Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) override {
+ SemaDiagnosticBuilder diagnoseConversion(Sema &S, SourceLocation Loc,
+ QualType T,
+ QualType ConvTy) override {
return S.Diag(Loc,
S.getLangOpts().CPlusPlus11
? diag::warn_cxx98_compat_array_size_conversion
diff --git a/lib/Sema/SemaExprMember.cpp b/lib/Sema/SemaExprMember.cpp
index fab2fe1..2da4488 100644
--- a/lib/Sema/SemaExprMember.cpp
+++ b/lib/Sema/SemaExprMember.cpp
@@ -109,9 +109,8 @@
NamedDecl *D = *I;
if (D->isCXXInstanceMember()) {
- if (dyn_cast<FieldDecl>(D) || dyn_cast<MSPropertyDecl>(D)
- || dyn_cast<IndirectFieldDecl>(D))
- isField = true;
+ isField |= isa<FieldDecl>(D) || isa<MSPropertyDecl>(D) ||
+ isa<IndirectFieldDecl>(D);
CXXRecordDecl *R = cast<CXXRecordDecl>(D->getDeclContext());
Classes.insert(R->getCanonicalDecl());
@@ -1536,7 +1535,15 @@
if (BaseType->isExtVectorType()) {
// FIXME: this expr should store IsArrow.
IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
- ExprValueKind VK = (IsArrow ? VK_LValue : BaseExpr.get()->getValueKind());
+ ExprValueKind VK;
+ if (IsArrow)
+ VK = VK_LValue;
+ else {
+ if (PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(BaseExpr.get()))
+ VK = POE->getSyntacticForm()->getValueKind();
+ else
+ VK = BaseExpr.get()->getValueKind();
+ }
QualType ret = CheckExtVectorComponent(S, BaseType, VK, OpLoc,
Member, MemberLoc);
if (ret.isNull())
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index 52a384f..63b7485 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -1043,7 +1043,7 @@
SourceLocation RParenLoc,
bool WarnMultipleSelectors) {
ObjCMethodDecl *Method = LookupInstanceMethodInGlobalPool(Sel,
- SourceRange(LParenLoc, RParenLoc), false, false);
+ SourceRange(LParenLoc, RParenLoc));
if (!Method)
Method = LookupFactoryMethodInGlobalPool(Sel,
SourceRange(LParenLoc, RParenLoc));
@@ -2393,8 +2393,11 @@
if (ObjCMethodDecl *BestMethod =
SelectBestMethod(Sel, ArgsIn, Method->isInstanceMethod()))
Method = BestMethod;
- if (!AreMultipleMethodsInGlobalPool(Sel, Method->isInstanceMethod()))
+ if (!AreMultipleMethodsInGlobalPool(Sel, Method,
+ SourceRange(LBracLoc, RBracLoc),
+ receiverIsId)) {
DiagnoseUseOfDecl(Method, SelLoc);
+ }
}
} else if (ReceiverType->isObjCClassType() ||
ReceiverType->isObjCQualifiedClassType()) {
@@ -2432,14 +2435,12 @@
// If not messaging 'self', look for any factory method named 'Sel'.
if (!Receiver || !isSelfExpr(Receiver)) {
Method = LookupFactoryMethodInGlobalPool(Sel,
- SourceRange(LBracLoc, RBracLoc),
- true);
+ SourceRange(LBracLoc, RBracLoc));
if (!Method) {
// If no class (factory) method was found, check if an _instance_
// method of the same name exists in the root class only.
Method = LookupInstanceMethodInGlobalPool(Sel,
- SourceRange(LBracLoc, RBracLoc),
- true);
+ SourceRange(LBracLoc, RBracLoc));
if (Method)
if (const ObjCInterfaceDecl *ID =
dyn_cast<ObjCInterfaceDecl>(Method->getDeclContext())) {
@@ -2516,6 +2517,14 @@
if (OCIType->qual_empty()) {
Method = LookupInstanceMethodInGlobalPool(Sel,
SourceRange(LBracLoc, RBracLoc));
+ if (Method) {
+ if (auto BestMethod =
+ SelectBestMethod(Sel, ArgsIn, Method->isInstanceMethod()))
+ Method = BestMethod;
+ AreMultipleMethodsInGlobalPool(Sel, Method,
+ SourceRange(LBracLoc, RBracLoc),
+ true);
+ }
if (Method && !forwardClass)
Diag(SelLoc, diag::warn_maynot_respond)
<< OCIType->getInterfaceDecl()->getIdentifier()
@@ -3357,7 +3366,7 @@
ObjCInterfaceDecl *CastClass
= InterfacePointerType->getObjectType()->getInterface();
if ((CastClass == ExprClass) ||
- (CastClass && ExprClass->isSuperClassOf(CastClass)))
+ (CastClass && CastClass->isSuperClassOf(ExprClass)))
return true;
if (warn)
S.Diag(castExpr->getLocStart(), diag::warn_objc_invalid_bridge)
@@ -3380,12 +3389,13 @@
return false;
}
}
+ } else if (!castType->isObjCIdType()) {
+ S.Diag(castExpr->getLocStart(), diag::err_objc_cf_bridged_not_interface)
+ << castExpr->getType() << Parm;
+ S.Diag(TDNDecl->getLocStart(), diag::note_declared_at);
+ if (Target)
+ S.Diag(Target->getLocStart(), diag::note_declared_at);
}
- S.Diag(castExpr->getLocStart(), diag::err_objc_cf_bridged_not_interface)
- << castExpr->getType() << Parm;
- S.Diag(TDNDecl->getLocStart(), diag::note_declared_at);
- if (Target)
- S.Diag(Target->getLocStart(), diag::note_declared_at);
return true;
}
return false;
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index 4a6531e..75ccc4e 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -6753,9 +6753,9 @@
case FK_TooManyInitsForScalar: {
SourceRange R;
- if (InitListExpr *InitList = dyn_cast<InitListExpr>(Args[0]))
- R = SourceRange(InitList->getInit(0)->getLocEnd(),
- InitList->getLocEnd());
+ auto *InitList = dyn_cast<InitListExpr>(Args[0]);
+ if (InitList && InitList->getNumInits() == 1)
+ R = SourceRange(InitList->getInit(0)->getLocEnd(), InitList->getLocEnd());
else
R = SourceRange(Args.front()->getLocEnd(), Args.back()->getLocEnd());
@@ -7356,7 +7356,6 @@
EqualLoc,
AllowExplicit);
InitializationSequence Seq(*this, Entity, Kind, InitE, TopLevelOfInitList);
- Init.get();
ExprResult Result = Seq.Perform(*this, Entity, Kind, InitE);
diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp
index 90a81f4..147dd7e 100644
--- a/lib/Sema/SemaLambda.cpp
+++ b/lib/Sema/SemaLambda.cpp
@@ -1340,22 +1340,27 @@
SourceRange IntroducerRange,
CXXRecordDecl *Class,
CXXMethodDecl *CallOperator) {
- const FunctionProtoType *Proto
- = CallOperator->getType()->getAs<FunctionProtoType>();
- QualType BlockPtrTy;
- {
- FunctionProtoType::ExtProtoInfo ExtInfo = Proto->getExtProtoInfo();
- ExtInfo.TypeQuals = 0;
- QualType FunctionTy = S.Context.getFunctionType(
- Proto->getReturnType(), Proto->getParamTypes(), ExtInfo);
- BlockPtrTy = S.Context.getBlockPointerType(FunctionTy);
- }
+ const FunctionProtoType *Proto =
+ CallOperator->getType()->getAs<FunctionProtoType>();
- FunctionProtoType::ExtProtoInfo ExtInfo(S.Context.getDefaultCallingConvention(
- /*IsVariadic=*/false, /*IsCXXMethod=*/true));
- ExtInfo.TypeQuals = Qualifiers::Const;
- QualType ConvTy = S.Context.getFunctionType(BlockPtrTy, None, ExtInfo);
-
+ // The function type inside the block pointer type is the same as the call
+ // operator with some tweaks. The calling convention is the default free
+ // function convention, and the type qualifications are lost.
+ FunctionProtoType::ExtProtoInfo BlockEPI = Proto->getExtProtoInfo();
+ BlockEPI.ExtInfo =
+ BlockEPI.ExtInfo.withCallingConv(S.Context.getDefaultCallingConvention(
+ Proto->isVariadic(), /*IsCXXMethod=*/false));
+ BlockEPI.TypeQuals = 0;
+ QualType FunctionTy = S.Context.getFunctionType(
+ Proto->getReturnType(), Proto->getParamTypes(), BlockEPI);
+ QualType BlockPtrTy = S.Context.getBlockPointerType(FunctionTy);
+
+ FunctionProtoType::ExtProtoInfo ConversionEPI(
+ S.Context.getDefaultCallingConvention(
+ /*IsVariadic=*/false, /*IsCXXMethod=*/true));
+ ConversionEPI.TypeQuals = Qualifiers::Const;
+ QualType ConvTy = S.Context.getFunctionType(BlockPtrTy, None, ConversionEPI);
+
SourceLocation Loc = IntroducerRange.getBegin();
DeclarationName Name
= S.Context.DeclarationNames.getCXXConversionFunctionName(
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index ac7376e..09424a4 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -1226,8 +1226,7 @@
DeclContext *DC = D->getLexicalDeclContext();
if (!D->isModulePrivate() &&
DC && !DC->isFileContext() && !isa<LinkageSpecDecl>(DC)) {
- NamedDecl *Hidden;
- if (SemaRef.hasVisibleDefinition(cast<NamedDecl>(DC), &Hidden)) {
+ if (SemaRef.hasVisibleDefinition(cast<NamedDecl>(DC))) {
if (SemaRef.ActiveTemplateInstantiations.empty()) {
// Cache the fact that this declaration is implicitly visible because
// its parent has a visible definition.
@@ -3071,7 +3070,7 @@
Result.getSema().ForceDeclarationOfImplicitMembers(Class);
// Enumerate all of the results in this context.
- for (const auto &R : Ctx->lookups()) {
+ for (DeclContextLookupResult R : Ctx->lookups()) {
for (auto *D : R) {
if (auto *ND = Result.getAcceptableDecl(D)) {
Consumer.FoundDecl(ND, Visited.checkHidden(ND), Ctx, InBaseClass);
diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp
index f4f4336..5e7b4b8 100644
--- a/lib/Sema/SemaObjCProperty.cpp
+++ b/lib/Sema/SemaObjCProperty.cpp
@@ -407,9 +407,11 @@
// this conversion is safe only because the wider type is for a 'readonly'
// property in primary class and 'narrowed' type for a 'readwrite' property
// in continuation class.
- if (!isa<ObjCObjectPointerType>(PIDecl->getType()) ||
- !isa<ObjCObjectPointerType>(PDecl->getType()) ||
- (!isObjCPointerConversion(PDecl->getType(), PIDecl->getType(),
+ QualType PrimaryClassPropertyT = Context.getCanonicalType(PIDecl->getType());
+ QualType ClassExtPropertyT = Context.getCanonicalType(PDecl->getType());
+ if (!isa<ObjCObjectPointerType>(PrimaryClassPropertyT) ||
+ !isa<ObjCObjectPointerType>(ClassExtPropertyT) ||
+ (!isObjCPointerConversion(ClassExtPropertyT, PrimaryClassPropertyT,
ConvertedType, IncompatibleObjC))
|| IncompatibleObjC) {
Diag(AtLoc,
diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp
index e027e55..fed0ac7 100644
--- a/lib/Sema/SemaOpenMP.cpp
+++ b/lib/Sema/SemaOpenMP.cpp
@@ -238,6 +238,7 @@
DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator Iter,
VarDecl *D) {
+ D = D->getCanonicalDecl();
DSAVarData DVar;
if (Iter == std::prev(Stack.rend())) {
// OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
@@ -342,6 +343,7 @@
DeclRefExpr *DSAStackTy::addUniqueAligned(VarDecl *D, DeclRefExpr *NewDE) {
assert(Stack.size() > 1 && "Data sharing attributes stack is empty");
+ D = D->getCanonicalDecl();
auto It = Stack.back().AlignedMap.find(D);
if (It == Stack.back().AlignedMap.end()) {
assert(NewDE && "Unexpected nullptr expr to be added into aligned map");
@@ -355,6 +357,7 @@
}
void DSAStackTy::addDSA(VarDecl *D, DeclRefExpr *E, OpenMPClauseKind A) {
+ D = D->getCanonicalDecl();
if (A == OMPC_threadprivate) {
Stack[0].SharingMap[D].Attributes = A;
Stack[0].SharingMap[D].RefExpr = E;
@@ -366,6 +369,7 @@
}
bool DSAStackTy::isOpenMPLocal(VarDecl *D, StackTy::reverse_iterator Iter) {
+ D = D->getCanonicalDecl();
if (Stack.size() > 2) {
reverse_iterator I = Iter, E = std::prev(Stack.rend());
Scope *TopScope = nullptr;
@@ -385,6 +389,7 @@
}
DSAStackTy::DSAVarData DSAStackTy::getTopDSA(VarDecl *D, bool FromParent) {
+ D = D->getCanonicalDecl();
DSAVarData DVar;
// OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
@@ -477,6 +482,7 @@
}
DSAStackTy::DSAVarData DSAStackTy::getImplicitDSA(VarDecl *D, bool FromParent) {
+ D = D->getCanonicalDecl();
auto StartI = Stack.rbegin();
auto EndI = std::prev(Stack.rend());
if (FromParent && StartI != EndI) {
@@ -489,6 +495,7 @@
DSAStackTy::DSAVarData DSAStackTy::hasDSA(VarDecl *D, ClausesPredicate CPred,
DirectivesPredicate DPred,
bool FromParent) {
+ D = D->getCanonicalDecl();
auto StartI = std::next(Stack.rbegin());
auto EndI = std::prev(Stack.rend());
if (FromParent && StartI != EndI) {
@@ -508,6 +515,7 @@
DSAStackTy::DSAVarData
DSAStackTy::hasInnermostDSA(VarDecl *D, ClausesPredicate CPred,
DirectivesPredicate DPred, bool FromParent) {
+ D = D->getCanonicalDecl();
auto StartI = std::next(Stack.rbegin());
auto EndI = std::prev(Stack.rend());
if (FromParent && StartI != EndI) {
@@ -546,6 +554,7 @@
bool Sema::IsOpenMPCapturedVar(VarDecl *VD) {
assert(LangOpts.OpenMP && "OpenMP is not allowed");
+ VD = VD->getCanonicalDecl();
if (DSAStack->getCurrentDirective() != OMPD_unknown) {
auto DVarPrivate = DSAStack->getTopDSA(VD, /*FromParent=*/false);
if (DVarPrivate.CKind != OMPC_unknown && isOpenMPPrivate(DVarPrivate.CKind))
@@ -573,46 +582,44 @@
// class type, unless the list item is also specified in a firstprivate
// clause.
if (auto D = dyn_cast_or_null<OMPExecutableDirective>(CurDirective)) {
- for (auto C : D->clauses()) {
- if (auto Clause = dyn_cast<OMPLastprivateClause>(C)) {
- for (auto VarRef : Clause->varlists()) {
- if (VarRef->isValueDependent() || VarRef->isTypeDependent())
+ for (auto *C : D->clauses()) {
+ if (auto *Clause = dyn_cast<OMPLastprivateClause>(C)) {
+ SmallVector<Expr *, 8> PrivateCopies;
+ for (auto *DE : Clause->varlists()) {
+ if (DE->isValueDependent() || DE->isTypeDependent()) {
+ PrivateCopies.push_back(nullptr);
continue;
- auto VD = cast<VarDecl>(cast<DeclRefExpr>(VarRef)->getDecl());
+ }
+ auto *VD = cast<VarDecl>(cast<DeclRefExpr>(DE)->getDecl());
auto DVar = DSAStack->getTopDSA(VD, false);
if (DVar.CKind == OMPC_lastprivate) {
- SourceLocation ELoc = VarRef->getExprLoc();
- auto Type = VarRef->getType();
- if (Type->isArrayType())
- Type = QualType(Type->getArrayElementTypeNoTypeQual(), 0);
- CXXRecordDecl *RD =
- getLangOpts().CPlusPlus ? Type->getAsCXXRecordDecl() : nullptr;
- // FIXME This code must be replaced by actual constructing of the
- // lastprivate variable.
- if (RD) {
- CXXConstructorDecl *CD = LookupDefaultConstructor(RD);
- PartialDiagnostic PD =
- PartialDiagnostic(PartialDiagnostic::NullDiagnostic());
- if (!CD ||
- CheckConstructorAccess(
- ELoc, CD, InitializedEntity::InitializeTemporary(Type),
- CD->getAccess(), PD) == AR_inaccessible ||
- CD->isDeleted()) {
- Diag(ELoc, diag::err_omp_required_method)
- << getOpenMPClauseName(OMPC_lastprivate) << 0;
- bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
- VarDecl::DeclarationOnly;
- Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl
- : diag::note_defined_here)
- << VD;
- Diag(RD->getLocation(), diag::note_previous_decl) << RD;
- continue;
- }
- MarkFunctionReferenced(ELoc, CD);
- DiagnoseUseOfDecl(CD, ELoc);
- }
+ // Generate helper private variable and initialize it with the
+ // default value. The address of the original variable is replaced
+ // by the address of the new private variable in CodeGen. This new
+ // variable is not added to IdResolver, so the code in the OpenMP
+ // region uses original variable for proper diagnostics.
+ auto *VDPrivate = VarDecl::Create(
+ Context, CurContext, DE->getLocStart(), DE->getExprLoc(),
+ VD->getIdentifier(), VD->getType(), VD->getTypeSourceInfo(),
+ SC_Auto);
+ ActOnUninitializedDecl(VDPrivate, /*TypeMayContainAuto=*/false);
+ if (VDPrivate->isInvalidDecl())
+ continue;
+ CurContext->addDecl(VDPrivate);
+ PrivateCopies.push_back(DeclRefExpr::Create(
+ Context, NestedNameSpecifierLoc(), SourceLocation(), VDPrivate,
+ /*RefersToEnclosingVariableOrCapture=*/false, SourceLocation(),
+ DE->getType(), VK_LValue));
+ } else {
+ // The variable is also a firstprivate, so initialization sequence
+ // for private copy is generated already.
+ PrivateCopies.push_back(nullptr);
}
}
+ // Set initializers to private copies if no errors were found.
+ if (PrivateCopies.size() == Clause->varlist_size()) {
+ Clause->setPrivateCopies(PrivateCopies);
+ }
}
}
}
@@ -759,7 +766,7 @@
// OpenMP [2.9.2, Restrictions, C/C++, p.2-6]
// A threadprivate directive must lexically precede all references to any
// of the variables in its list.
- if (VD->isUsed()) {
+ if (VD->isUsed() && !DSAStack->isThreadPrivate(VD)) {
Diag(Id.getLoc(), diag::err_omp_var_used)
<< getOpenMPDirectiveName(OMPD_threadprivate) << VD;
return ExprError();
@@ -817,6 +824,13 @@
VarDecl *VD = cast<VarDecl>(DE->getDecl());
SourceLocation ILoc = DE->getExprLoc();
+ QualType QType = VD->getType();
+ if (QType->isDependentType() || QType->isInstantiationDependentType()) {
+ // It will be analyzed later.
+ Vars.push_back(DE);
+ continue;
+ }
+
// OpenMP [2.9.2, Restrictions, C/C++, p.10]
// A threadprivate variable must not have an incomplete type.
if (RequireCompleteType(ILoc, VD->getType(),
@@ -1117,7 +1131,11 @@
break;
}
case OMPD_parallel_sections: {
+ QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1);
+ QualType KmpInt32PtrTy = Context.getPointerType(KmpInt32Ty);
Sema::CapturedParamNameType Params[] = {
+ std::make_pair(".global_tid.", KmpInt32PtrTy),
+ std::make_pair(".bound_tid.", KmpInt32PtrTy),
std::make_pair(StringRef(), QualType()) // __context with shared vars
};
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
@@ -1187,6 +1205,26 @@
}
}
+StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S,
+ ArrayRef<OMPClause *> Clauses) {
+ if (!S.isUsable()) {
+ ActOnCapturedRegionError();
+ return StmtError();
+ }
+ // Mark all variables in private list clauses as used in inner region. This is
+ // required for proper codegen.
+ for (auto *Clause : Clauses) {
+ if (isOpenMPPrivate(Clause->getClauseKind())) {
+ for (auto *VarRef : Clause->children()) {
+ if (auto *E = cast_or_null<Expr>(VarRef)) {
+ MarkDeclarationsReferencedInExpr(E);
+ }
+ }
+ }
+ }
+ return ActOnCapturedRegionEnd(S.get());
+}
+
static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack,
OpenMPDirectiveKind CurrentRegion,
const DeclarationNameInfo &CurrentName,
@@ -3282,40 +3320,54 @@
Sema &SemaRef;
/// \brief A location for note diagnostics (when error is found).
SourceLocation NoteLoc;
- /// \brief Atomic operation supposed to be performed on source expression.
- BinaryOperatorKind OpKind;
/// \brief 'x' lvalue part of the source atomic expression.
Expr *X;
- /// \brief 'x' rvalue part of the source atomic expression, used in the right
- /// hand side of the expression. We need this to properly generate RHS part of
- /// the source expression (x = x'rval' binop expr or x = expr binop x'rval').
- Expr *XRVal;
/// \brief 'expr' rvalue part of the source atomic expression.
Expr *E;
+ /// \brief Helper expression of the form
+ /// 'OpaqueValueExpr(x) binop OpaqueValueExpr(expr)' or
+ /// 'OpaqueValueExpr(expr) binop OpaqueValueExpr(x)'.
+ Expr *UpdateExpr;
+ /// \brief Is 'x' a LHS in a RHS part of full update expression. It is
+ /// important for non-associative operations.
+ bool IsXLHSInRHSPart;
+ BinaryOperatorKind Op;
+ SourceLocation OpLoc;
+ /// \brief true if the source expression is a postfix unary operation, false
+ /// if it is a prefix unary operation.
+ bool IsPostfixUpdate;
public:
OpenMPAtomicUpdateChecker(Sema &SemaRef)
- : SemaRef(SemaRef), OpKind(BO_PtrMemD), X(nullptr), XRVal(nullptr),
- E(nullptr) {}
+ : SemaRef(SemaRef), X(nullptr), E(nullptr), UpdateExpr(nullptr),
+ IsXLHSInRHSPart(false), Op(BO_PtrMemD), IsPostfixUpdate(false) {}
/// \brief Check specified statement that it is suitable for 'atomic update'
/// constructs and extract 'x', 'expr' and Operation from the original
- /// expression.
+ /// expression. If DiagId and NoteId == 0, then only check is performed
+ /// without error notification.
/// \param DiagId Diagnostic which should be emitted if error is found.
/// \param NoteId Diagnostic note for the main error message.
/// \return true if statement is not an update expression, false otherwise.
- bool checkStatement(Stmt *S, unsigned DiagId, unsigned NoteId);
+ bool checkStatement(Stmt *S, unsigned DiagId = 0, unsigned NoteId = 0);
/// \brief Return the 'x' lvalue part of the source atomic expression.
Expr *getX() const { return X; }
- /// \brief Return the 'x' rvalue part of the source atomic expression, used in
- /// the RHS part of the source expression.
- Expr *getXRVal() const { return XRVal; }
/// \brief Return the 'expr' rvalue part of the source atomic expression.
Expr *getExpr() const { return E; }
- /// \brief Return required atomic operation.
- BinaryOperatorKind getOpKind() const {return OpKind;}
+ /// \brief Return the update expression used in calculation of the updated
+ /// value. Always has form 'OpaqueValueExpr(x) binop OpaqueValueExpr(expr)' or
+ /// 'OpaqueValueExpr(expr) binop OpaqueValueExpr(x)'.
+ Expr *getUpdateExpr() const { return UpdateExpr; }
+ /// \brief Return true if 'x' is LHS in RHS part of full update expression,
+ /// false otherwise.
+ bool isXLHSInRHSPart() const { return IsXLHSInRHSPart; }
+
+ /// \brief true if the source expression is a postfix unary operation, false
+ /// if it is a prefix unary operation.
+ bool isPostfixUpdate() const { return IsPostfixUpdate; }
+
private:
- bool checkBinaryOperation(BinaryOperator *AtomicBinOp, unsigned DiagId,
- unsigned NoteId);
+ bool checkBinaryOperation(BinaryOperator *AtomicBinOp, unsigned DiagId = 0,
+ unsigned NoteId = 0);
};
} // namespace
@@ -3334,7 +3386,8 @@
if (AtomicInnerBinOp->isMultiplicativeOp() ||
AtomicInnerBinOp->isAdditiveOp() || AtomicInnerBinOp->isShiftOp() ||
AtomicInnerBinOp->isBitwiseOp()) {
- OpKind = AtomicInnerBinOp->getOpcode();
+ Op = AtomicInnerBinOp->getOpcode();
+ OpLoc = AtomicInnerBinOp->getOperatorLoc();
auto *LHS = AtomicInnerBinOp->getLHS();
auto *RHS = AtomicInnerBinOp->getRHS();
llvm::FoldingSetNodeID XId, LHSId, RHSId;
@@ -3346,10 +3399,10 @@
/*Canonical=*/true);
if (XId == LHSId) {
E = RHS;
- XRVal = LHS;
+ IsXLHSInRHSPart = true;
} else if (XId == RHSId) {
E = LHS;
- XRVal = RHS;
+ IsXLHSInRHSPart = false;
} else {
ErrorLoc = AtomicInnerBinOp->getExprLoc();
ErrorRange = AtomicInnerBinOp->getSourceRange();
@@ -3376,12 +3429,12 @@
NoteRange = SourceRange(NoteLoc, NoteLoc);
ErrorFound = NotAnAssignmentOp;
}
- if (ErrorFound != NoError) {
+ if (ErrorFound != NoError && DiagId != 0 && NoteId != 0) {
SemaRef.Diag(ErrorLoc, DiagId) << ErrorRange;
SemaRef.Diag(NoteLoc, NoteId) << ErrorFound << NoteRange;
return true;
} else if (SemaRef.CurContext->isDependentContext())
- E = X = XRVal = nullptr;
+ E = X = UpdateExpr = nullptr;
return false;
}
@@ -3405,26 +3458,27 @@
if (auto *AtomicCompAssignOp = dyn_cast<CompoundAssignOperator>(
AtomicBody->IgnoreParenImpCasts())) {
// Check for Compound Assignment Operation
- OpKind = BinaryOperator::getOpForCompoundAssignment(
+ Op = BinaryOperator::getOpForCompoundAssignment(
AtomicCompAssignOp->getOpcode());
- X = AtomicCompAssignOp->getLHS();
- XRVal = SemaRef.PerformImplicitConversion(
- X, AtomicCompAssignOp->getComputationLHSType(),
- Sema::AA_Casting, /*AllowExplicit=*/true).get();
+ OpLoc = AtomicCompAssignOp->getOperatorLoc();
E = AtomicCompAssignOp->getRHS();
+ X = AtomicCompAssignOp->getLHS();
+ IsXLHSInRHSPart = true;
} else if (auto *AtomicBinOp = dyn_cast<BinaryOperator>(
AtomicBody->IgnoreParenImpCasts())) {
// Check for Binary Operation
- return checkBinaryOperation(AtomicBinOp, DiagId, NoteId);
+ if(checkBinaryOperation(AtomicBinOp, DiagId, NoteId))
+ return true;
} else if (auto *AtomicUnaryOp =
- // Check for Binary Operation
dyn_cast<UnaryOperator>(AtomicBody->IgnoreParenImpCasts())) {
// Check for Unary Operation
if (AtomicUnaryOp->isIncrementDecrementOp()) {
- OpKind = AtomicUnaryOp->isIncrementOp() ? BO_Add : BO_Sub;
- XRVal = X = AtomicUnaryOp->getSubExpr();
- E = SemaRef.ActOnIntegerConstant(AtomicUnaryOp->getOperatorLoc(), 1)
- .get();
+ IsPostfixUpdate = AtomicUnaryOp->isPostfix();
+ Op = AtomicUnaryOp->isIncrementOp() ? BO_Add : BO_Sub;
+ OpLoc = AtomicUnaryOp->getOperatorLoc();
+ X = AtomicUnaryOp->getSubExpr();
+ E = SemaRef.ActOnIntegerConstant(OpLoc, /*uint64_t Val=*/1).get();
+ IsXLHSInRHSPart = true;
} else {
ErrorFound = NotAnUnaryIncDecExpression;
ErrorLoc = AtomicUnaryOp->getExprLoc();
@@ -3447,12 +3501,31 @@
NoteLoc = ErrorLoc = S->getLocStart();
NoteRange = ErrorRange = SourceRange(NoteLoc, NoteLoc);
}
- if (ErrorFound != NoError) {
+ if (ErrorFound != NoError && DiagId != 0 && NoteId != 0) {
SemaRef.Diag(ErrorLoc, DiagId) << ErrorRange;
SemaRef.Diag(NoteLoc, NoteId) << ErrorFound << NoteRange;
return true;
} else if (SemaRef.CurContext->isDependentContext())
- E = X = XRVal = nullptr;
+ E = X = UpdateExpr = nullptr;
+ if (E && X) {
+ // Build an update expression of form 'OpaqueValueExpr(x) binop
+ // OpaqueValueExpr(expr)' or 'OpaqueValueExpr(expr) binop
+ // OpaqueValueExpr(x)' and then cast it to the type of the 'x' expression.
+ auto *OVEX = new (SemaRef.getASTContext())
+ OpaqueValueExpr(X->getExprLoc(), X->getType(), VK_RValue);
+ auto *OVEExpr = new (SemaRef.getASTContext())
+ OpaqueValueExpr(E->getExprLoc(), E->getType(), VK_RValue);
+ auto Update =
+ SemaRef.CreateBuiltinBinOp(OpLoc, Op, IsXLHSInRHSPart ? OVEX : OVEExpr,
+ IsXLHSInRHSPart ? OVEExpr : OVEX);
+ if (Update.isInvalid())
+ return true;
+ Update = SemaRef.PerformImplicitConversion(Update.get(), X->getType(),
+ Sema::AA_Casting);
+ if (Update.isInvalid())
+ return true;
+ UpdateExpr = Update.get();
+ }
return false;
}
@@ -3467,7 +3540,6 @@
// top and a single exit at the bottom.
// The point of exit cannot be a branch out of the structured block.
// longjmp() and throw() must not violate the entry/exit criteria.
- // TODO further analysis of associated statements and clauses.
OpenMPClauseKind AtomicKind = OMPC_unknown;
SourceLocation AtomicKindLoc;
for (auto *C : Clauses) {
@@ -3490,11 +3562,12 @@
if (auto *EWC = dyn_cast<ExprWithCleanups>(Body))
Body = EWC->getSubExpr();
- BinaryOperatorKind OpKind = BO_PtrMemD;
Expr *X = nullptr;
- Expr *XRVal = nullptr;
Expr *V = nullptr;
Expr *E = nullptr;
+ Expr *UE = nullptr;
+ bool IsXLHSInRHSPart = false;
+ bool IsPostfixUpdate = false;
// OpenMP [2.12.6, atomic Construct]
// In the next expressions:
// * x and v (as applicable) are both l-value expressions with scalar type.
@@ -3517,14 +3590,14 @@
// expr or subexpressions of expr.
// * For forms that allow multiple occurrences of x, the number of times
// that x is evaluated is unspecified.
- enum {
- NotAnExpression,
- NotAnAssignmentOp,
- NotAScalarType,
- NotAnLValue,
- NoError
- } ErrorFound = NoError;
if (AtomicKind == OMPC_read) {
+ enum {
+ NotAnExpression,
+ NotAnAssignmentOp,
+ NotAScalarType,
+ NotAnLValue,
+ NoError
+ } ErrorFound = NoError;
SourceLocation ErrorLoc, NoteLoc;
SourceRange ErrorRange, NoteRange;
// If clause is read:
@@ -3580,6 +3653,13 @@
} else if (CurContext->isDependentContext())
V = X = nullptr;
} else if (AtomicKind == OMPC_write) {
+ enum {
+ NotAnExpression,
+ NotAnAssignmentOp,
+ NotAScalarType,
+ NotAnLValue,
+ NoError
+ } ErrorFound = NoError;
SourceLocation ErrorLoc, NoteLoc;
SourceRange ErrorRange, NoteRange;
// If clause is write:
@@ -3652,25 +3732,222 @@
if (!CurContext->isDependentContext()) {
E = Checker.getExpr();
X = Checker.getX();
- XRVal = Checker.getXRVal();
- OpKind = Checker.getOpKind();
+ UE = Checker.getUpdateExpr();
+ IsXLHSInRHSPart = Checker.isXLHSInRHSPart();
}
} else if (AtomicKind == OMPC_capture) {
- if (isa<Expr>(Body) && !isa<BinaryOperator>(Body)) {
- Diag(Body->getLocStart(),
- diag::err_omp_atomic_capture_not_expression_statement);
- return StmtError();
- } else if (!isa<Expr>(Body) && !isa<CompoundStmt>(Body)) {
- Diag(Body->getLocStart(),
- diag::err_omp_atomic_capture_not_compound_statement);
- return StmtError();
+ enum {
+ NotAnAssignmentOp,
+ NotACompoundStatement,
+ NotTwoSubstatements,
+ NotASpecificExpression,
+ NoError
+ } ErrorFound = NoError;
+ SourceLocation ErrorLoc, NoteLoc;
+ SourceRange ErrorRange, NoteRange;
+ if (auto *AtomicBody = dyn_cast<Expr>(Body)) {
+ // If clause is a capture:
+ // v = x++;
+ // v = x--;
+ // v = ++x;
+ // v = --x;
+ // v = x binop= expr;
+ // v = x = x binop expr;
+ // v = x = expr binop x;
+ auto *AtomicBinOp =
+ dyn_cast<BinaryOperator>(AtomicBody->IgnoreParenImpCasts());
+ if (AtomicBinOp && AtomicBinOp->getOpcode() == BO_Assign) {
+ V = AtomicBinOp->getLHS();
+ Body = AtomicBinOp->getRHS()->IgnoreParenImpCasts();
+ OpenMPAtomicUpdateChecker Checker(*this);
+ if (Checker.checkStatement(
+ Body, diag::err_omp_atomic_capture_not_expression_statement,
+ diag::note_omp_atomic_update))
+ return StmtError();
+ E = Checker.getExpr();
+ X = Checker.getX();
+ UE = Checker.getUpdateExpr();
+ IsXLHSInRHSPart = Checker.isXLHSInRHSPart();
+ IsPostfixUpdate = Checker.isPostfixUpdate();
+ } else {
+ ErrorLoc = AtomicBody->getExprLoc();
+ ErrorRange = AtomicBody->getSourceRange();
+ NoteLoc = AtomicBinOp ? AtomicBinOp->getOperatorLoc()
+ : AtomicBody->getExprLoc();
+ NoteRange = AtomicBinOp ? AtomicBinOp->getSourceRange()
+ : AtomicBody->getSourceRange();
+ ErrorFound = NotAnAssignmentOp;
+ }
+ if (ErrorFound != NoError) {
+ Diag(ErrorLoc, diag::err_omp_atomic_capture_not_expression_statement)
+ << ErrorRange;
+ Diag(NoteLoc, diag::note_omp_atomic_capture) << ErrorFound << NoteRange;
+ return StmtError();
+ } else if (CurContext->isDependentContext()) {
+ UE = V = E = X = nullptr;
+ }
+ } else {
+ // If clause is a capture:
+ // { v = x; x = expr; }
+ // { v = x; x++; }
+ // { v = x; x--; }
+ // { v = x; ++x; }
+ // { v = x; --x; }
+ // { v = x; x binop= expr; }
+ // { v = x; x = x binop expr; }
+ // { v = x; x = expr binop x; }
+ // { x++; v = x; }
+ // { x--; v = x; }
+ // { ++x; v = x; }
+ // { --x; v = x; }
+ // { x binop= expr; v = x; }
+ // { x = x binop expr; v = x; }
+ // { x = expr binop x; v = x; }
+ if (auto *CS = dyn_cast<CompoundStmt>(Body)) {
+ // Check that this is { expr1; expr2; }
+ if (CS->size() == 2) {
+ auto *First = CS->body_front();
+ auto *Second = CS->body_back();
+ if (auto *EWC = dyn_cast<ExprWithCleanups>(First))
+ First = EWC->getSubExpr()->IgnoreParenImpCasts();
+ if (auto *EWC = dyn_cast<ExprWithCleanups>(Second))
+ Second = EWC->getSubExpr()->IgnoreParenImpCasts();
+ // Need to find what subexpression is 'v' and what is 'x'.
+ OpenMPAtomicUpdateChecker Checker(*this);
+ bool IsUpdateExprFound = !Checker.checkStatement(Second);
+ BinaryOperator *BinOp = nullptr;
+ if (IsUpdateExprFound) {
+ BinOp = dyn_cast<BinaryOperator>(First);
+ IsUpdateExprFound = BinOp && BinOp->getOpcode() == BO_Assign;
+ }
+ if (IsUpdateExprFound && !CurContext->isDependentContext()) {
+ // { v = x; x++; }
+ // { v = x; x--; }
+ // { v = x; ++x; }
+ // { v = x; --x; }
+ // { v = x; x binop= expr; }
+ // { v = x; x = x binop expr; }
+ // { v = x; x = expr binop x; }
+ // Check that the first expression has form v = x.
+ auto *PossibleX = BinOp->getRHS()->IgnoreParenImpCasts();
+ llvm::FoldingSetNodeID XId, PossibleXId;
+ Checker.getX()->Profile(XId, Context, /*Canonical=*/true);
+ PossibleX->Profile(PossibleXId, Context, /*Canonical=*/true);
+ IsUpdateExprFound = XId == PossibleXId;
+ if (IsUpdateExprFound) {
+ V = BinOp->getLHS();
+ X = Checker.getX();
+ E = Checker.getExpr();
+ UE = Checker.getUpdateExpr();
+ IsXLHSInRHSPart = Checker.isXLHSInRHSPart();
+ IsPostfixUpdate = Checker.isPostfixUpdate();
+ }
+ }
+ if (!IsUpdateExprFound) {
+ IsUpdateExprFound = !Checker.checkStatement(First);
+ BinOp = nullptr;
+ if (IsUpdateExprFound) {
+ BinOp = dyn_cast<BinaryOperator>(Second);
+ IsUpdateExprFound = BinOp && BinOp->getOpcode() == BO_Assign;
+ }
+ if (IsUpdateExprFound && !CurContext->isDependentContext()) {
+ // { x++; v = x; }
+ // { x--; v = x; }
+ // { ++x; v = x; }
+ // { --x; v = x; }
+ // { x binop= expr; v = x; }
+ // { x = x binop expr; v = x; }
+ // { x = expr binop x; v = x; }
+ // Check that the second expression has form v = x.
+ auto *PossibleX = BinOp->getRHS()->IgnoreParenImpCasts();
+ llvm::FoldingSetNodeID XId, PossibleXId;
+ Checker.getX()->Profile(XId, Context, /*Canonical=*/true);
+ PossibleX->Profile(PossibleXId, Context, /*Canonical=*/true);
+ IsUpdateExprFound = XId == PossibleXId;
+ if (IsUpdateExprFound) {
+ V = BinOp->getLHS();
+ X = Checker.getX();
+ E = Checker.getExpr();
+ UE = Checker.getUpdateExpr();
+ IsXLHSInRHSPart = Checker.isXLHSInRHSPart();
+ IsPostfixUpdate = Checker.isPostfixUpdate();
+ }
+ }
+ }
+ if (!IsUpdateExprFound) {
+ // { v = x; x = expr; }
+ auto *FirstBinOp = dyn_cast<BinaryOperator>(First);
+ if (!FirstBinOp || FirstBinOp->getOpcode() != BO_Assign) {
+ ErrorFound = NotAnAssignmentOp;
+ NoteLoc = ErrorLoc = FirstBinOp ? FirstBinOp->getOperatorLoc()
+ : First->getLocStart();
+ NoteRange = ErrorRange = FirstBinOp
+ ? FirstBinOp->getSourceRange()
+ : SourceRange(ErrorLoc, ErrorLoc);
+ } else {
+ auto *SecondBinOp = dyn_cast<BinaryOperator>(Second);
+ if (!SecondBinOp || SecondBinOp->getOpcode() != BO_Assign) {
+ ErrorFound = NotAnAssignmentOp;
+ NoteLoc = ErrorLoc = SecondBinOp ? SecondBinOp->getOperatorLoc()
+ : Second->getLocStart();
+ NoteRange = ErrorRange = SecondBinOp
+ ? SecondBinOp->getSourceRange()
+ : SourceRange(ErrorLoc, ErrorLoc);
+ } else {
+ auto *PossibleXRHSInFirst =
+ FirstBinOp->getRHS()->IgnoreParenImpCasts();
+ auto *PossibleXLHSInSecond =
+ SecondBinOp->getLHS()->IgnoreParenImpCasts();
+ llvm::FoldingSetNodeID X1Id, X2Id;
+ PossibleXRHSInFirst->Profile(X1Id, Context, /*Canonical=*/true);
+ PossibleXLHSInSecond->Profile(X2Id, Context,
+ /*Canonical=*/true);
+ IsUpdateExprFound = X1Id == X2Id;
+ if (IsUpdateExprFound) {
+ V = FirstBinOp->getLHS();
+ X = SecondBinOp->getLHS();
+ E = SecondBinOp->getRHS();
+ UE = nullptr;
+ IsXLHSInRHSPart = false;
+ IsPostfixUpdate = true;
+ } else {
+ ErrorFound = NotASpecificExpression;
+ ErrorLoc = FirstBinOp->getExprLoc();
+ ErrorRange = FirstBinOp->getSourceRange();
+ NoteLoc = SecondBinOp->getLHS()->getExprLoc();
+ NoteRange = SecondBinOp->getRHS()->getSourceRange();
+ }
+ }
+ }
+ }
+ } else {
+ NoteLoc = ErrorLoc = Body->getLocStart();
+ NoteRange = ErrorRange =
+ SourceRange(Body->getLocStart(), Body->getLocStart());
+ ErrorFound = NotTwoSubstatements;
+ }
+ } else {
+ NoteLoc = ErrorLoc = Body->getLocStart();
+ NoteRange = ErrorRange =
+ SourceRange(Body->getLocStart(), Body->getLocStart());
+ ErrorFound = NotACompoundStatement;
+ }
+ if (ErrorFound != NoError) {
+ Diag(ErrorLoc, diag::err_omp_atomic_capture_not_compound_statement)
+ << ErrorRange;
+ Diag(NoteLoc, diag::note_omp_atomic_capture) << ErrorFound << NoteRange;
+ return StmtError();
+ } else if (CurContext->isDependentContext()) {
+ UE = V = E = X = nullptr;
+ }
}
}
getCurFunction()->setHasBranchProtectedScope();
return OMPAtomicDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt,
- OpKind, X, XRVal, V, E);
+ X, V, E, UE, IsXLHSInRHSPart,
+ IsPostfixUpdate);
}
StmtResult Sema::ActOnOpenMPTargetDirective(ArrayRef<OMPClause *> Clauses,
@@ -4542,7 +4819,7 @@
// A variable of class type (or array thereof) that appears in a private
// clause requires an accessible, unambiguous copy constructor for the
// class type.
- Type = Context.getBaseElementType(Type);
+ Type = Context.getBaseElementType(Type).getNonReferenceType();
// If an implicit firstprivate variable found it was checked already.
if (!IsImplicitClause) {
@@ -4632,10 +4909,10 @@
}
}
- Type = Type.getUnqualifiedType();
- auto VDPrivate = VarDecl::Create(Context, CurContext, DE->getLocStart(),
- ELoc, VD->getIdentifier(), VD->getType(),
- VD->getTypeSourceInfo(), /*S*/ SC_Auto);
+ auto VDPrivate =
+ VarDecl::Create(Context, CurContext, DE->getLocStart(), ELoc,
+ VD->getIdentifier(), VD->getType().getUnqualifiedType(),
+ VD->getTypeSourceInfo(), /*S*/ SC_Auto);
// Generate helper private variable and initialize it with the value of the
// original variable. The address of the original variable is replaced by
// the address of the new private variable in the CodeGen. This new variable
@@ -4654,9 +4931,12 @@
/*TemplateKWLoc*/ SourceLocation(), VDInit,
/*RefersToEnclosingVariableOrCapture*/ true, ELoc, Type,
/*VK*/ VK_LValue);
- VDInit->setIsUsed();
auto Init = DefaultLvalueConversion(VDInitRefExpr).get();
- InitializedEntity Entity = InitializedEntity::InitializeVariable(VDInit);
+ auto *VDInitTemp =
+ BuildVarDecl(*this, DE->getLocStart(), Type.getUnqualifiedType(),
+ ".firstprivate.temp");
+ InitializedEntity Entity =
+ InitializedEntity::InitializeVariable(VDInitTemp);
InitializationKind Kind = InitializationKind::CreateCopy(ELoc, ELoc);
InitializationSequence InitSeq(*this, Entity, Kind, Init);
@@ -4666,15 +4946,13 @@
else
VDPrivate->setInit(Result.getAs<Expr>());
} else {
- AddInitializerToDecl(
- VDPrivate,
- DefaultLvalueConversion(
- DeclRefExpr::Create(Context, NestedNameSpecifierLoc(),
- SourceLocation(), DE->getDecl(),
- /*RefersToEnclosingVariableOrCapture=*/true,
- DE->getExprLoc(), DE->getType(),
- /*VK=*/VK_LValue)).get(),
- /*DirectInit=*/false, /*TypeMayContainAuto=*/false);
+ auto *VDInit =
+ BuildVarDecl(*this, DE->getLocStart(), Type, ".firstprivate.temp");
+ VDInitRefExpr =
+ BuildDeclRefExpr(VDInit, Type, VK_LValue, DE->getExprLoc()).get();
+ AddInitializerToDecl(VDPrivate,
+ DefaultLvalueConversion(VDInitRefExpr).get(),
+ /*DirectInit=*/false, /*TypeMayContainAuto=*/false);
}
if (VDPrivate->isInvalidDecl()) {
if (IsImplicitClause) {
@@ -4684,12 +4962,11 @@
continue;
}
CurContext->addDecl(VDPrivate);
- auto VDPrivateRefExpr =
- DeclRefExpr::Create(Context, /*QualifierLoc*/ NestedNameSpecifierLoc(),
- /*TemplateKWLoc*/ SourceLocation(), VDPrivate,
- /*RefersToEnclosingVariableOrCapture*/ false,
- DE->getLocStart(), DE->getType(),
- /*VK*/ VK_LValue);
+ auto VDPrivateRefExpr = DeclRefExpr::Create(
+ Context, /*QualifierLoc*/ NestedNameSpecifierLoc(),
+ /*TemplateKWLoc*/ SourceLocation(), VDPrivate,
+ /*RefersToEnclosingVariableOrCapture*/ false, DE->getLocStart(),
+ DE->getType().getUnqualifiedType(), /*VK*/ VK_LValue);
DSAStack->addDSA(VD, DE, OMPC_firstprivate);
Vars.push_back(DE);
PrivateCopies.push_back(VDPrivateRefExpr);
@@ -4708,11 +4985,17 @@
SourceLocation LParenLoc,
SourceLocation EndLoc) {
SmallVector<Expr *, 8> Vars;
+ SmallVector<Expr *, 8> SrcExprs;
+ SmallVector<Expr *, 8> DstExprs;
+ SmallVector<Expr *, 8> AssignmentOps;
for (auto &RefExpr : VarList) {
assert(RefExpr && "NULL expr in OpenMP lastprivate clause.");
if (isa<DependentScopeDeclRefExpr>(RefExpr)) {
// It will be analyzed later.
Vars.push_back(RefExpr);
+ SrcExprs.push_back(nullptr);
+ DstExprs.push_back(nullptr);
+ AssignmentOps.push_back(nullptr);
continue;
}
@@ -4734,6 +5017,9 @@
if (Type->isDependentType() || Type->isInstantiationDependentType()) {
// It will be analyzed later.
Vars.push_back(DE);
+ SrcExprs.push_back(nullptr);
+ DstExprs.push_back(nullptr);
+ AssignmentOps.push_back(nullptr);
continue;
}
@@ -4797,65 +5083,39 @@
// A variable of class type (or array thereof) that appears in a
// lastprivate clause requires an accessible, unambiguous copy assignment
// operator for the class type.
- while (Type.getNonReferenceType()->isArrayType())
- Type = cast<ArrayType>(Type.getNonReferenceType().getTypePtr())
- ->getElementType();
- CXXRecordDecl *RD = getLangOpts().CPlusPlus
- ? Type.getNonReferenceType()->getAsCXXRecordDecl()
- : nullptr;
- // FIXME This code must be replaced by actual copying and destructing of the
- // lastprivate variable.
- if (RD) {
- CXXMethodDecl *MD = LookupCopyingAssignment(RD, 0, false, 0);
- DeclAccessPair FoundDecl = DeclAccessPair::make(MD, MD->getAccess());
- if (MD) {
- if (CheckMemberAccess(ELoc, RD, FoundDecl) == AR_inaccessible ||
- MD->isDeleted()) {
- Diag(ELoc, diag::err_omp_required_method)
- << getOpenMPClauseName(OMPC_lastprivate) << 2;
- bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
- VarDecl::DeclarationOnly;
- Diag(VD->getLocation(),
- IsDecl ? diag::note_previous_decl : diag::note_defined_here)
- << VD;
- Diag(RD->getLocation(), diag::note_previous_decl) << RD;
- continue;
- }
- MarkFunctionReferenced(ELoc, MD);
- DiagnoseUseOfDecl(MD, ELoc);
- }
-
- CXXDestructorDecl *DD = RD->getDestructor();
- if (DD) {
- PartialDiagnostic PD =
- PartialDiagnostic(PartialDiagnostic::NullDiagnostic());
- if (CheckDestructorAccess(ELoc, DD, PD) == AR_inaccessible ||
- DD->isDeleted()) {
- Diag(ELoc, diag::err_omp_required_method)
- << getOpenMPClauseName(OMPC_lastprivate) << 4;
- bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
- VarDecl::DeclarationOnly;
- Diag(VD->getLocation(),
- IsDecl ? diag::note_previous_decl : diag::note_defined_here)
- << VD;
- Diag(RD->getLocation(), diag::note_previous_decl) << RD;
- continue;
- }
- MarkFunctionReferenced(ELoc, DD);
- DiagnoseUseOfDecl(DD, ELoc);
- }
- }
+ Type = Context.getBaseElementType(Type).getNonReferenceType();
+ auto *SrcVD = BuildVarDecl(*this, DE->getLocStart(),
+ Type.getUnqualifiedType(), ".lastprivate.src");
+ auto *PseudoSrcExpr = BuildDeclRefExpr(SrcVD, Type.getUnqualifiedType(),
+ VK_LValue, DE->getExprLoc()).get();
+ auto *DstVD =
+ BuildVarDecl(*this, DE->getLocStart(), Type, ".lastprivate.dst");
+ auto *PseudoDstExpr =
+ BuildDeclRefExpr(DstVD, Type, VK_LValue, DE->getExprLoc()).get();
+ // For arrays generate assignment operation for single element and replace
+ // it by the original array element in CodeGen.
+ auto AssignmentOp = BuildBinOp(/*S=*/nullptr, DE->getExprLoc(), BO_Assign,
+ PseudoDstExpr, PseudoSrcExpr);
+ if (AssignmentOp.isInvalid())
+ continue;
+ AssignmentOp = ActOnFinishFullExpr(AssignmentOp.get(), DE->getExprLoc(),
+ /*DiscardedValue=*/true);
+ if (AssignmentOp.isInvalid())
+ continue;
if (DVar.CKind != OMPC_firstprivate)
DSAStack->addDSA(VD, DE, OMPC_lastprivate);
Vars.push_back(DE);
+ SrcExprs.push_back(PseudoSrcExpr);
+ DstExprs.push_back(PseudoDstExpr);
+ AssignmentOps.push_back(AssignmentOp.get());
}
if (Vars.empty())
return nullptr;
return OMPLastprivateClause::Create(Context, StartLoc, LParenLoc, EndLoc,
- Vars);
+ Vars, SrcExprs, DstExprs, AssignmentOps);
}
OMPClause *Sema::ActOnOpenMPSharedClause(ArrayRef<Expr *> VarList,
@@ -4975,19 +5235,19 @@
switch (OOK) {
case OO_Plus:
case OO_Minus:
- BOK = BO_AddAssign;
+ BOK = BO_Add;
break;
case OO_Star:
- BOK = BO_MulAssign;
+ BOK = BO_Mul;
break;
case OO_Amp:
- BOK = BO_AndAssign;
+ BOK = BO_And;
break;
case OO_Pipe:
- BOK = BO_OrAssign;
+ BOK = BO_Or;
break;
case OO_Caret:
- BOK = BO_XorAssign;
+ BOK = BO_Xor;
break;
case OO_AmpAmp:
BOK = BO_LAnd;
@@ -4995,7 +5255,44 @@
case OO_PipePipe:
BOK = BO_LOr;
break;
- default:
+ case OO_New:
+ case OO_Delete:
+ case OO_Array_New:
+ case OO_Array_Delete:
+ case OO_Slash:
+ case OO_Percent:
+ case OO_Tilde:
+ case OO_Exclaim:
+ case OO_Equal:
+ case OO_Less:
+ case OO_Greater:
+ case OO_LessEqual:
+ case OO_GreaterEqual:
+ case OO_PlusEqual:
+ case OO_MinusEqual:
+ case OO_StarEqual:
+ case OO_SlashEqual:
+ case OO_PercentEqual:
+ case OO_CaretEqual:
+ case OO_AmpEqual:
+ case OO_PipeEqual:
+ case OO_LessLess:
+ case OO_GreaterGreater:
+ case OO_LessLessEqual:
+ case OO_GreaterGreaterEqual:
+ case OO_EqualEqual:
+ case OO_ExclaimEqual:
+ case OO_PlusPlus:
+ case OO_MinusMinus:
+ case OO_Comma:
+ case OO_ArrowStar:
+ case OO_Arrow:
+ case OO_Call:
+ case OO_Subscript:
+ case OO_Conditional:
+ case NUM_OVERLOADED_OPERATORS:
+ llvm_unreachable("Unexpected reduction identifier");
+ case OO_None:
if (auto II = DN.getAsIdentifierInfo()) {
if (II->isStr("max"))
BOK = BO_GT;
@@ -5017,11 +5314,17 @@
}
SmallVector<Expr *, 8> Vars;
+ SmallVector<Expr *, 8> LHSs;
+ SmallVector<Expr *, 8> RHSs;
+ SmallVector<Expr *, 8> ReductionOps;
for (auto RefExpr : VarList) {
assert(RefExpr && "nullptr expr in OpenMP reduction clause.");
if (isa<DependentScopeDeclRefExpr>(RefExpr)) {
// It will be analyzed later.
Vars.push_back(RefExpr);
+ LHSs.push_back(nullptr);
+ RHSs.push_back(nullptr);
+ ReductionOps.push_back(nullptr);
continue;
}
@@ -5030,6 +5333,9 @@
RefExpr->containsUnexpandedParameterPack()) {
// It will be analyzed later.
Vars.push_back(RefExpr);
+ LHSs.push_back(nullptr);
+ RHSs.push_back(nullptr);
+ ReductionOps.push_back(nullptr);
continue;
}
@@ -5122,23 +5428,6 @@
<< VD;
continue;
}
- bool Suppress = getDiagnostics().getSuppressAllDiagnostics();
- getDiagnostics().setSuppressAllDiagnostics(true);
- ExprResult ReductionOp =
- BuildBinOp(DSAStack->getCurScope(), ReductionId.getLocStart(), BOK,
- RefExpr, RefExpr);
- getDiagnostics().setSuppressAllDiagnostics(Suppress);
- if (ReductionOp.isInvalid()) {
- Diag(ELoc, diag::err_omp_reduction_id_not_compatible) << Type
- << ReductionIdRange;
- bool IsDecl =
- VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
- Diag(VD->getLocation(),
- IsDecl ? diag::note_previous_decl : diag::note_defined_here)
- << VD;
- continue;
- }
-
// OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables Referenced
// in a Construct]
// Variables with the predetermined data-sharing attributes may not be
@@ -5181,55 +5470,160 @@
continue;
}
}
-
- CXXRecordDecl *RD = getLangOpts().CPlusPlus
- ? Type.getNonReferenceType()->getAsCXXRecordDecl()
- : nullptr;
- // FIXME This code must be replaced by actual constructing/destructing of
- // the reduction variable.
- if (RD) {
- CXXConstructorDecl *CD = LookupDefaultConstructor(RD);
- PartialDiagnostic PD =
- PartialDiagnostic(PartialDiagnostic::NullDiagnostic());
- if (!CD ||
- CheckConstructorAccess(ELoc, CD,
- InitializedEntity::InitializeTemporary(Type),
- CD->getAccess(), PD) == AR_inaccessible ||
- CD->isDeleted()) {
- Diag(ELoc, diag::err_omp_required_method)
- << getOpenMPClauseName(OMPC_reduction) << 0;
- bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
- VarDecl::DeclarationOnly;
- Diag(VD->getLocation(),
- IsDecl ? diag::note_previous_decl : diag::note_defined_here)
- << VD;
- Diag(RD->getLocation(), diag::note_previous_decl) << RD;
- continue;
+ Type = Type.getNonLValueExprType(Context).getUnqualifiedType();
+ auto *LHSVD = BuildVarDecl(*this, ELoc, Type, ".reduction.lhs");
+ auto *RHSVD = BuildVarDecl(*this, ELoc, Type, VD->getName());
+ // Add initializer for private variable.
+ Expr *Init = nullptr;
+ switch (BOK) {
+ case BO_Add:
+ case BO_Xor:
+ case BO_Or:
+ case BO_LOr:
+ // '+', '-', '^', '|', '||' reduction ops - initializer is '0'.
+ if (Type->isScalarType() || Type->isAnyComplexType()) {
+ Init = ActOnIntegerConstant(ELoc, /*Val=*/0).get();
}
- MarkFunctionReferenced(ELoc, CD);
- DiagnoseUseOfDecl(CD, ELoc);
-
- CXXDestructorDecl *DD = RD->getDestructor();
- if (DD) {
- if (CheckDestructorAccess(ELoc, DD, PD) == AR_inaccessible ||
- DD->isDeleted()) {
- Diag(ELoc, diag::err_omp_required_method)
- << getOpenMPClauseName(OMPC_reduction) << 4;
- bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
- VarDecl::DeclarationOnly;
- Diag(VD->getLocation(),
- IsDecl ? diag::note_previous_decl : diag::note_defined_here)
- << VD;
- Diag(RD->getLocation(), diag::note_previous_decl) << RD;
- continue;
+ break;
+ case BO_Mul:
+ case BO_LAnd:
+ if (Type->isScalarType() || Type->isAnyComplexType()) {
+ // '*' and '&&' reduction ops - initializer is '1'.
+ Init = ActOnIntegerConstant(ELoc, /*Val=*/1).get();
+ }
+ break;
+ case BO_And: {
+ // '&' reduction op - initializer is '~0'.
+ QualType OrigType = Type;
+ if (auto *ComplexTy = OrigType->getAs<ComplexType>()) {
+ Type = ComplexTy->getElementType();
+ }
+ if (Type->isRealFloatingType()) {
+ llvm::APFloat InitValue =
+ llvm::APFloat::getAllOnesValue(Context.getTypeSize(Type),
+ /*isIEEE=*/true);
+ Init = FloatingLiteral::Create(Context, InitValue, /*isexact=*/true,
+ Type, ELoc);
+ } else if (Type->isScalarType()) {
+ auto Size = Context.getTypeSize(Type);
+ QualType IntTy = Context.getIntTypeForBitwidth(Size, /*Signed=*/0);
+ llvm::APInt InitValue = llvm::APInt::getAllOnesValue(Size);
+ Init = IntegerLiteral::Create(Context, InitValue, IntTy, ELoc);
+ }
+ if (Init && OrigType->isAnyComplexType()) {
+ // Init = 0xFFFF + 0xFFFFi;
+ auto *Im = new (Context) ImaginaryLiteral(Init, OrigType);
+ Init = CreateBuiltinBinOp(ELoc, BO_Add, Init, Im).get();
+ }
+ Type = OrigType;
+ break;
+ }
+ case BO_LT:
+ case BO_GT: {
+ // 'min' reduction op - initializer is 'Largest representable number in
+ // the reduction list item type'.
+ // 'max' reduction op - initializer is 'Least representable number in
+ // the reduction list item type'.
+ if (Type->isIntegerType() || Type->isPointerType()) {
+ bool IsSigned = Type->hasSignedIntegerRepresentation();
+ auto Size = Context.getTypeSize(Type);
+ QualType IntTy =
+ Context.getIntTypeForBitwidth(Size, /*Signed=*/IsSigned);
+ llvm::APInt InitValue =
+ (BOK != BO_LT)
+ ? IsSigned ? llvm::APInt::getSignedMinValue(Size)
+ : llvm::APInt::getMinValue(Size)
+ : IsSigned ? llvm::APInt::getSignedMaxValue(Size)
+ : llvm::APInt::getMaxValue(Size);
+ Init = IntegerLiteral::Create(Context, InitValue, IntTy, ELoc);
+ if (Type->isPointerType()) {
+ // Cast to pointer type.
+ auto CastExpr = BuildCStyleCastExpr(
+ SourceLocation(), Context.getTrivialTypeSourceInfo(Type, ELoc),
+ SourceLocation(), Init);
+ if (CastExpr.isInvalid())
+ continue;
+ Init = CastExpr.get();
}
- MarkFunctionReferenced(ELoc, DD);
- DiagnoseUseOfDecl(DD, ELoc);
+ } else if (Type->isRealFloatingType()) {
+ llvm::APFloat InitValue = llvm::APFloat::getLargest(
+ Context.getFloatTypeSemantics(Type), BOK != BO_LT);
+ Init = FloatingLiteral::Create(Context, InitValue, /*isexact=*/true,
+ Type, ELoc);
+ }
+ break;
+ }
+ case BO_PtrMemD:
+ case BO_PtrMemI:
+ case BO_MulAssign:
+ case BO_Div:
+ case BO_Rem:
+ case BO_Sub:
+ case BO_Shl:
+ case BO_Shr:
+ case BO_LE:
+ case BO_GE:
+ case BO_EQ:
+ case BO_NE:
+ case BO_AndAssign:
+ case BO_XorAssign:
+ case BO_OrAssign:
+ case BO_Assign:
+ case BO_AddAssign:
+ case BO_SubAssign:
+ case BO_DivAssign:
+ case BO_RemAssign:
+ case BO_ShlAssign:
+ case BO_ShrAssign:
+ case BO_Comma:
+ llvm_unreachable("Unexpected reduction operation");
+ }
+ if (Init) {
+ AddInitializerToDecl(RHSVD, Init, /*DirectInit=*/false,
+ /*TypeMayContainAuto=*/false);
+ } else {
+ ActOnUninitializedDecl(RHSVD, /*TypeMayContainAuto=*/false);
+ }
+ if (!RHSVD->hasInit()) {
+ Diag(ELoc, diag::err_omp_reduction_id_not_compatible) << Type
+ << ReductionIdRange;
+ bool IsDecl =
+ VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
+ Diag(VD->getLocation(),
+ IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+ << VD;
+ continue;
+ }
+ auto *LHSDRE = BuildDeclRefExpr(LHSVD, Type, VK_LValue, ELoc).get();
+ auto *RHSDRE = BuildDeclRefExpr(RHSVD, Type, VK_LValue, ELoc).get();
+ ExprResult ReductionOp =
+ BuildBinOp(DSAStack->getCurScope(), ReductionId.getLocStart(), BOK,
+ LHSDRE, RHSDRE);
+ if (ReductionOp.isUsable()) {
+ if (BOK != BO_LOr && BOK != BO_LAnd) {
+ ReductionOp =
+ BuildBinOp(DSAStack->getCurScope(), ReductionId.getLocStart(),
+ BO_Assign, LHSDRE, ReductionOp.get());
+ } else {
+ auto *ConditionalOp = new (Context) ConditionalOperator(
+ ReductionOp.get(), SourceLocation(), LHSDRE, SourceLocation(),
+ RHSDRE, Type, VK_LValue, OK_Ordinary);
+ ReductionOp =
+ BuildBinOp(DSAStack->getCurScope(), ReductionId.getLocStart(),
+ BO_Assign, LHSDRE, ConditionalOp);
+ }
+ if (ReductionOp.isUsable()) {
+ ReductionOp = ActOnFinishFullExpr(ReductionOp.get());
}
}
+ if (ReductionOp.isInvalid())
+ continue;
DSAStack->addDSA(VD, DE, OMPC_reduction);
Vars.push_back(DE);
+ LHSs.push_back(LHSDRE);
+ RHSs.push_back(RHSDRE);
+ ReductionOps.push_back(ReductionOp.get());
}
if (Vars.empty())
@@ -5237,7 +5631,8 @@
return OMPReductionClause::Create(
Context, StartLoc, LParenLoc, ColonLoc, EndLoc, Vars,
- ReductionIdScopeSpec.getWithLocInContext(Context), ReductionId);
+ ReductionIdScopeSpec.getWithLocInContext(Context), ReductionId, LHSs,
+ RHSs, ReductionOps);
}
OMPClause *Sema::ActOnOpenMPLinearClause(ArrayRef<Expr *> VarList, Expr *Step,
@@ -5531,11 +5926,17 @@
SourceLocation LParenLoc,
SourceLocation EndLoc) {
SmallVector<Expr *, 8> Vars;
+ SmallVector<Expr *, 8> SrcExprs;
+ SmallVector<Expr *, 8> DstExprs;
+ SmallVector<Expr *, 8> AssignmentOps;
for (auto &RefExpr : VarList) {
assert(RefExpr && "NULL expr in OpenMP copyin clause.");
if (isa<DependentScopeDeclRefExpr>(RefExpr)) {
// It will be analyzed later.
Vars.push_back(RefExpr);
+ SrcExprs.push_back(nullptr);
+ DstExprs.push_back(nullptr);
+ AssignmentOps.push_back(nullptr);
continue;
}
@@ -5557,6 +5958,9 @@
if (Type->isDependentType() || Type->isInstantiationDependentType()) {
// It will be analyzed later.
Vars.push_back(DE);
+ SrcExprs.push_back(nullptr);
+ DstExprs.push_back(nullptr);
+ AssignmentOps.push_back(nullptr);
continue;
}
@@ -5573,40 +5977,38 @@
// A variable of class type (or array thereof) that appears in a
// copyin clause requires an accessible, unambiguous copy assignment
// operator for the class type.
- Type = Context.getBaseElementType(Type);
- CXXRecordDecl *RD =
- getLangOpts().CPlusPlus ? Type->getAsCXXRecordDecl() : nullptr;
- // FIXME This code must be replaced by actual assignment of the
- // threadprivate variable.
- if (RD) {
- CXXMethodDecl *MD = LookupCopyingAssignment(RD, 0, false, 0);
- DeclAccessPair FoundDecl = DeclAccessPair::make(MD, MD->getAccess());
- if (MD) {
- if (CheckMemberAccess(ELoc, RD, FoundDecl) == AR_inaccessible ||
- MD->isDeleted()) {
- Diag(ELoc, diag::err_omp_required_method)
- << getOpenMPClauseName(OMPC_copyin) << 2;
- bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
- VarDecl::DeclarationOnly;
- Diag(VD->getLocation(),
- IsDecl ? diag::note_previous_decl : diag::note_defined_here)
- << VD;
- Diag(RD->getLocation(), diag::note_previous_decl) << RD;
- continue;
- }
- MarkFunctionReferenced(ELoc, MD);
- DiagnoseUseOfDecl(MD, ELoc);
- }
- }
+ Type = Context.getBaseElementType(Type).getNonReferenceType();
+ auto *SrcVD = BuildVarDecl(*this, DE->getLocStart(),
+ Type.getUnqualifiedType(), ".copyin.src");
+ auto *PseudoSrcExpr = BuildDeclRefExpr(SrcVD, Type.getUnqualifiedType(),
+ VK_LValue, DE->getExprLoc())
+ .get();
+ auto *DstVD = BuildVarDecl(*this, DE->getLocStart(), Type, ".copyin.dst");
+ auto *PseudoDstExpr =
+ BuildDeclRefExpr(DstVD, Type, VK_LValue, DE->getExprLoc()).get();
+ // For arrays generate assignment operation for single element and replace
+ // it by the original array element in CodeGen.
+ auto AssignmentOp = BuildBinOp(/*S=*/nullptr, DE->getExprLoc(), BO_Assign,
+ PseudoDstExpr, PseudoSrcExpr);
+ if (AssignmentOp.isInvalid())
+ continue;
+ AssignmentOp = ActOnFinishFullExpr(AssignmentOp.get(), DE->getExprLoc(),
+ /*DiscardedValue=*/true);
+ if (AssignmentOp.isInvalid())
+ continue;
DSAStack->addDSA(VD, DE, OMPC_copyin);
Vars.push_back(DE);
+ SrcExprs.push_back(PseudoSrcExpr);
+ DstExprs.push_back(PseudoDstExpr);
+ AssignmentOps.push_back(AssignmentOp.get());
}
if (Vars.empty())
return nullptr;
- return OMPCopyinClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars);
+ return OMPCopyinClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars,
+ SrcExprs, DstExprs, AssignmentOps);
}
OMPClause *Sema::ActOnOpenMPCopyprivateClause(ArrayRef<Expr *> VarList,
@@ -5685,14 +6087,15 @@
// A variable of class type (or array thereof) that appears in a
// copyin clause requires an accessible, unambiguous copy assignment
// operator for the class type.
- auto *SrcVD = BuildVarDecl(*this, DE->getLocStart(), VD->getType(),
- ".copyprivate.src");
- auto *PseudoSrcExpr = BuildDeclRefExpr(SrcVD, DE->getType(), VK_LValue,
- DE->getExprLoc()).get();
- auto *DstVD = BuildVarDecl(*this, DE->getLocStart(), VD->getType(),
- ".copyprivate.dst");
- auto *PseudoDstExpr = BuildDeclRefExpr(DstVD, DE->getType(), VK_LValue,
- DE->getExprLoc()).get();
+ Type = Context.getBaseElementType(Type).getUnqualifiedType();
+ auto *SrcVD =
+ BuildVarDecl(*this, DE->getLocStart(), Type, ".copyprivate.src");
+ auto *PseudoSrcExpr =
+ BuildDeclRefExpr(SrcVD, Type, VK_LValue, DE->getExprLoc()).get();
+ auto *DstVD =
+ BuildVarDecl(*this, DE->getLocStart(), Type, ".copyprivate.dst");
+ auto *PseudoDstExpr =
+ BuildDeclRefExpr(DstVD, Type, VK_LValue, DE->getExprLoc()).get();
auto AssignmentOp = BuildBinOp(/*S=*/nullptr, DE->getExprLoc(), BO_Assign,
PseudoDstExpr, PseudoSrcExpr);
if (AssignmentOp.isInvalid())
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index fbf110b..8f9401b 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -1752,11 +1752,13 @@
return false;
// We can perform an integral promotion to the underlying type of the enum,
- // even if that's not the promoted type.
+ // even if that's not the promoted type. Note that the check for promoting
+ // the underlying type is based on the type alone, and does not consider
+ // the bitfield-ness of the actual source expression.
if (FromEnumType->getDecl()->isFixed()) {
QualType Underlying = FromEnumType->getDecl()->getIntegerType();
return Context.hasSameUnqualifiedType(Underlying, ToType) ||
- IsIntegralPromotion(From, Underlying, ToType);
+ IsIntegralPromotion(nullptr, Underlying, ToType);
}
// We have already pre-calculated the promotion type, so this is trivial.
@@ -2952,7 +2954,10 @@
bool HadMultipleCandidates = (CandidateSet.size() > 1);
OverloadCandidateSet::iterator Best;
- switch (CandidateSet.BestViableFunction(S, From->getLocStart(), Best, true)) {
+ switch (auto Result =
+ CandidateSet.BestViableFunction(S, From->getLocStart(),
+ Best, true)) {
+ case OR_Deleted:
case OR_Success: {
// Record the standard conversion we used and the conversion function.
CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(Best->Function);
@@ -2965,13 +2970,11 @@
User.After.setAsIdentityConversion();
User.After.setFromType(ThisType->getAs<PointerType>()->getPointeeType());
User.After.setAllToTypes(ToType);
- return OR_Success;
+ return Result;
}
case OR_No_Viable_Function:
return OR_No_Viable_Function;
- case OR_Deleted:
- return OR_Deleted;
case OR_Ambiguous:
return OR_Ambiguous;
}
diff --git a/lib/Sema/SemaPseudoObject.cpp b/lib/Sema/SemaPseudoObject.cpp
index 935128b..3e465af 100644
--- a/lib/Sema/SemaPseudoObject.cpp
+++ b/lib/Sema/SemaPseudoObject.cpp
@@ -1192,7 +1192,7 @@
AtIndexGetter =
S.LookupInstanceMethodInGlobalPool(AtIndexGetterSelector,
RefExpr->getSourceRange(),
- true, false);
+ true);
}
if (AtIndexGetter) {
@@ -1314,7 +1314,7 @@
AtIndexSetter =
S.LookupInstanceMethodInGlobalPool(AtIndexSetterSelector,
RefExpr->getSourceRange(),
- true, false);
+ true);
}
bool err = false;
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index f923f61..ed5da43 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -15,6 +15,7 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTDiagnostic.h"
#include "clang/AST/CharUnits.h"
+#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/EvaluatedExprVisitor.h"
#include "clang/AST/ExprCXX.h"
@@ -23,12 +24,14 @@
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtObjC.h"
#include "clang/AST/TypeLoc.h"
+#include "clang/AST/TypeOrdering.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallString.h"
@@ -236,7 +239,9 @@
// is written in a macro body, only warn if it has the warn_unused_result
// attribute.
if (const Decl *FD = CE->getCalleeDecl()) {
- if (FD->hasAttr<WarnUnusedResultAttr>()) {
+ const FunctionDecl *Func = dyn_cast<FunctionDecl>(FD);
+ if (Func ? Func->hasUnusedResultAttr()
+ : FD->hasAttr<WarnUnusedResultAttr>()) {
Diag(Loc, diag::warn_unused_result) << R1 << R2;
return;
}
@@ -1133,29 +1138,15 @@
Diag(TheDefaultStmt->getDefaultLoc(), diag::warn_unreachable_default);
// Produce a nice diagnostic if multiple values aren't handled.
- switch (UnhandledNames.size()) {
- case 0: break;
- case 1:
- Diag(CondExpr->getExprLoc(), TheDefaultStmt
- ? diag::warn_def_missing_case1 : diag::warn_missing_case1)
- << UnhandledNames[0];
- break;
- case 2:
- Diag(CondExpr->getExprLoc(), TheDefaultStmt
- ? diag::warn_def_missing_case2 : diag::warn_missing_case2)
- << UnhandledNames[0] << UnhandledNames[1];
- break;
- case 3:
- Diag(CondExpr->getExprLoc(), TheDefaultStmt
- ? diag::warn_def_missing_case3 : diag::warn_missing_case3)
- << UnhandledNames[0] << UnhandledNames[1] << UnhandledNames[2];
- break;
- default:
- Diag(CondExpr->getExprLoc(), TheDefaultStmt
- ? diag::warn_def_missing_cases : diag::warn_missing_cases)
- << (unsigned)UnhandledNames.size()
- << UnhandledNames[0] << UnhandledNames[1] << UnhandledNames[2];
- break;
+ if (!UnhandledNames.empty()) {
+ DiagnosticBuilder DB = Diag(CondExpr->getExprLoc(),
+ TheDefaultStmt ? diag::warn_def_missing_case
+ : diag::warn_missing_case)
+ << (int)UnhandledNames.size();
+
+ for (size_t I = 0, E = std::min(UnhandledNames.size(), (size_t)3);
+ I != E; ++I)
+ DB << UnhandledNames[I];
}
if (!hasCasesNotInSwitch)
@@ -2373,6 +2364,156 @@
return S;
}
+// Warn when the loop variable is a const reference that creates a copy.
+// Suggest using the non-reference type for copies. If a copy can be prevented
+// suggest the const reference type that would do so.
+// For instance, given "for (const &Foo : Range)", suggest
+// "for (const Foo : Range)" to denote a copy is made for the loop. If
+// possible, also suggest "for (const &Bar : Range)" if this type prevents
+// the copy altogether.
+static void DiagnoseForRangeReferenceVariableCopies(Sema &SemaRef,
+ const VarDecl *VD,
+ QualType RangeInitType) {
+ const Expr *InitExpr = VD->getInit();
+ if (!InitExpr)
+ return;
+
+ QualType VariableType = VD->getType();
+
+ const MaterializeTemporaryExpr *MTE =
+ dyn_cast<MaterializeTemporaryExpr>(InitExpr);
+
+ // No copy made.
+ if (!MTE)
+ return;
+
+ const Expr *E = MTE->GetTemporaryExpr()->IgnoreImpCasts();
+
+ // Searching for either UnaryOperator for dereference of a pointer or
+ // CXXOperatorCallExpr for handling iterators.
+ while (!isa<CXXOperatorCallExpr>(E) && !isa<UnaryOperator>(E)) {
+ if (const CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(E)) {
+ E = CCE->getArg(0);
+ } else if (const CXXMemberCallExpr *Call = dyn_cast<CXXMemberCallExpr>(E)) {
+ const MemberExpr *ME = cast<MemberExpr>(Call->getCallee());
+ E = ME->getBase();
+ } else {
+ const MaterializeTemporaryExpr *MTE = cast<MaterializeTemporaryExpr>(E);
+ E = MTE->GetTemporaryExpr();
+ }
+ E = E->IgnoreImpCasts();
+ }
+
+ bool ReturnsReference = false;
+ if (isa<UnaryOperator>(E)) {
+ ReturnsReference = true;
+ } else {
+ const CXXOperatorCallExpr *Call = cast<CXXOperatorCallExpr>(E);
+ const FunctionDecl *FD = Call->getDirectCallee();
+ QualType ReturnType = FD->getReturnType();
+ ReturnsReference = ReturnType->isReferenceType();
+ }
+
+ if (ReturnsReference) {
+ // Loop variable creates a temporary. Suggest either to go with
+ // non-reference loop variable to indiciate a copy is made, or
+ // the correct time to bind a const reference.
+ SemaRef.Diag(VD->getLocation(), diag::warn_for_range_const_reference_copy)
+ << VD << VariableType << E->getType();
+ QualType NonReferenceType = VariableType.getNonReferenceType();
+ NonReferenceType.removeLocalConst();
+ QualType NewReferenceType =
+ SemaRef.Context.getLValueReferenceType(E->getType().withConst());
+ SemaRef.Diag(VD->getLocStart(), diag::note_use_type_or_non_reference)
+ << NonReferenceType << NewReferenceType << VD->getSourceRange();
+ } else {
+ // The range always returns a copy, so a temporary is always created.
+ // Suggest removing the reference from the loop variable.
+ SemaRef.Diag(VD->getLocation(), diag::warn_for_range_variable_always_copy)
+ << VD << RangeInitType;
+ QualType NonReferenceType = VariableType.getNonReferenceType();
+ NonReferenceType.removeLocalConst();
+ SemaRef.Diag(VD->getLocStart(), diag::note_use_non_reference_type)
+ << NonReferenceType << VD->getSourceRange();
+ }
+}
+
+// Warns when the loop variable can be changed to a reference type to
+// prevent a copy. For instance, if given "for (const Foo x : Range)" suggest
+// "for (const Foo &x : Range)" if this form does not make a copy.
+static void DiagnoseForRangeConstVariableCopies(Sema &SemaRef,
+ const VarDecl *VD) {
+ const Expr *InitExpr = VD->getInit();
+ if (!InitExpr)
+ return;
+
+ QualType VariableType = VD->getType();
+
+ if (const CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(InitExpr)) {
+ if (!CE->getConstructor()->isCopyConstructor())
+ return;
+ } else if (const CastExpr *CE = dyn_cast<CastExpr>(InitExpr)) {
+ if (CE->getCastKind() != CK_LValueToRValue)
+ return;
+ } else {
+ return;
+ }
+
+ // TODO: Determine a maximum size that a POD type can be before a diagnostic
+ // should be emitted. Also, only ignore POD types with trivial copy
+ // constructors.
+ if (VariableType.isPODType(SemaRef.Context))
+ return;
+
+ // Suggest changing from a const variable to a const reference variable
+ // if doing so will prevent a copy.
+ SemaRef.Diag(VD->getLocation(), diag::warn_for_range_copy)
+ << VD << VariableType << InitExpr->getType();
+ SemaRef.Diag(VD->getLocStart(), diag::note_use_reference_type)
+ << SemaRef.Context.getLValueReferenceType(VariableType)
+ << VD->getSourceRange();
+}
+
+/// DiagnoseForRangeVariableCopies - Diagnose three cases and fixes for them.
+/// 1) for (const foo &x : foos) where foos only returns a copy. Suggest
+/// using "const foo x" to show that a copy is made
+/// 2) for (const bar &x : foos) where bar is a temporary intialized by bar.
+/// Suggest either "const bar x" to keep the copying or "const foo& x" to
+/// prevent the copy.
+/// 3) for (const foo x : foos) where x is constructed from a reference foo.
+/// Suggest "const foo &x" to prevent the copy.
+static void DiagnoseForRangeVariableCopies(Sema &SemaRef,
+ const CXXForRangeStmt *ForStmt) {
+ if (SemaRef.Diags.isIgnored(diag::warn_for_range_const_reference_copy,
+ ForStmt->getLocStart()) &&
+ SemaRef.Diags.isIgnored(diag::warn_for_range_variable_always_copy,
+ ForStmt->getLocStart()) &&
+ SemaRef.Diags.isIgnored(diag::warn_for_range_copy,
+ ForStmt->getLocStart())) {
+ return;
+ }
+
+ const VarDecl *VD = ForStmt->getLoopVariable();
+ if (!VD)
+ return;
+
+ QualType VariableType = VD->getType();
+
+ if (VariableType->isIncompleteType())
+ return;
+
+ const Expr *InitExpr = VD->getInit();
+ if (!InitExpr)
+ return;
+
+ if (VariableType->isReferenceType()) {
+ DiagnoseForRangeReferenceVariableCopies(SemaRef, VD,
+ ForStmt->getRangeInit()->getType());
+ } else if (VariableType.isConstQualified()) {
+ DiagnoseForRangeConstVariableCopies(SemaRef, VD);
+ }
+}
+
/// FinishCXXForRangeStmt - Attach the body to a C++0x for-range statement.
/// This is a separate step from ActOnCXXForRangeStmt because analysis of the
/// body cannot be performed until after the type of the range variable is
@@ -2390,6 +2531,8 @@
DiagnoseEmptyStmtBody(ForStmt->getRParenLoc(), B,
diag::warn_empty_range_based_for_body);
+ DiagnoseForRangeVariableCopies(*this, ForStmt);
+
return S;
}
@@ -3267,36 +3410,111 @@
return new (Context) ObjCAutoreleasePoolStmt(AtLoc, Body);
}
-namespace {
+class CatchHandlerType {
+ QualType QT;
+ unsigned IsPointer : 1;
-class TypeWithHandler {
- QualType t;
- CXXCatchStmt *stmt;
+ // This is a special constructor to be used only with DenseMapInfo's
+ // getEmptyKey() and getTombstoneKey() functions.
+ friend struct llvm::DenseMapInfo<CatchHandlerType>;
+ enum Unique { ForDenseMap };
+ CatchHandlerType(QualType QT, Unique) : QT(QT), IsPointer(false) {}
+
public:
- TypeWithHandler(const QualType &type, CXXCatchStmt *statement)
- : t(type), stmt(statement) {}
+ /// Used when creating a CatchHandlerType from a handler type; will determine
+ /// whether the type is a pointer or reference and will strip off the the top
+ /// level pointer and cv-qualifiers.
+ CatchHandlerType(QualType Q) : QT(Q), IsPointer(false) {
+ if (QT->isPointerType())
+ IsPointer = true;
- // An arbitrary order is fine as long as it places identical
- // types next to each other.
- bool operator<(const TypeWithHandler &y) const {
- if (t.getAsOpaquePtr() < y.t.getAsOpaquePtr())
- return true;
- if (t.getAsOpaquePtr() > y.t.getAsOpaquePtr())
+ if (IsPointer || QT->isReferenceType())
+ QT = QT->getPointeeType();
+ QT = QT.getUnqualifiedType();
+ }
+
+ /// Used when creating a CatchHandlerType from a base class type; pretends the
+ /// type passed in had the pointer qualifier, does not need to get an
+ /// unqualified type.
+ CatchHandlerType(QualType QT, bool IsPointer)
+ : QT(QT), IsPointer(IsPointer) {}
+
+ QualType underlying() const { return QT; }
+ bool isPointer() const { return IsPointer; }
+
+ friend bool operator==(const CatchHandlerType &LHS,
+ const CatchHandlerType &RHS) {
+ // If the pointer qualification does not match, we can return early.
+ if (LHS.IsPointer != RHS.IsPointer)
return false;
- else
- return getTypeSpecStartLoc() < y.getTypeSpecStartLoc();
- }
-
- bool operator==(const TypeWithHandler& other) const {
- return t == other.t;
- }
-
- CXXCatchStmt *getCatchStmt() const { return stmt; }
- SourceLocation getTypeSpecStartLoc() const {
- return stmt->getExceptionDecl()->getTypeSpecStartLoc();
+ // Otherwise, check the underlying type without cv-qualifiers.
+ return LHS.QT == RHS.QT;
}
};
+namespace llvm {
+template <> struct DenseMapInfo<CatchHandlerType> {
+ static CatchHandlerType getEmptyKey() {
+ return CatchHandlerType(DenseMapInfo<QualType>::getEmptyKey(),
+ CatchHandlerType::ForDenseMap);
+ }
+
+ static CatchHandlerType getTombstoneKey() {
+ return CatchHandlerType(DenseMapInfo<QualType>::getTombstoneKey(),
+ CatchHandlerType::ForDenseMap);
+ }
+
+ static unsigned getHashValue(const CatchHandlerType &Base) {
+ return DenseMapInfo<QualType>::getHashValue(Base.underlying());
+ }
+
+ static bool isEqual(const CatchHandlerType &LHS,
+ const CatchHandlerType &RHS) {
+ return LHS == RHS;
+ }
+};
+
+// It's OK to treat CatchHandlerType as a POD type.
+template <> struct isPodLike<CatchHandlerType> {
+ static const bool value = true;
+};
+}
+
+namespace {
+class CatchTypePublicBases {
+ ASTContext &Ctx;
+ const llvm::DenseMap<CatchHandlerType, CXXCatchStmt *> &TypesToCheck;
+ const bool CheckAgainstPointer;
+
+ CXXCatchStmt *FoundHandler;
+ CanQualType FoundHandlerType;
+
+public:
+ CatchTypePublicBases(
+ ASTContext &Ctx,
+ const llvm::DenseMap<CatchHandlerType, CXXCatchStmt *> &T, bool C)
+ : Ctx(Ctx), TypesToCheck(T), CheckAgainstPointer(C),
+ FoundHandler(nullptr) {}
+
+ CXXCatchStmt *getFoundHandler() const { return FoundHandler; }
+ CanQualType getFoundHandlerType() const { return FoundHandlerType; }
+
+ static bool FindPublicBasesOfType(const CXXBaseSpecifier *S, CXXBasePath &,
+ void *User) {
+ auto &PBOT = *reinterpret_cast<CatchTypePublicBases *>(User);
+ if (S->getAccessSpecifier() == AccessSpecifier::AS_public) {
+ CatchHandlerType Check(S->getType(), PBOT.CheckAgainstPointer);
+ auto M = PBOT.TypesToCheck;
+ auto I = M.find(Check);
+ if (I != M.end()) {
+ PBOT.FoundHandler = I->second;
+ PBOT.FoundHandlerType = PBOT.Ctx.getCanonicalType(S->getType());
+ return true;
+ }
+ }
+ return false;
+ }
+};
}
/// ActOnCXXTryBlock - Takes a try compound-statement and a number of
@@ -3306,7 +3524,7 @@
// Don't report an error if 'try' is used in system headers.
if (!getLangOpts().CXXExceptions &&
!getSourceManager().isInSystemHeader(TryLoc))
- Diag(TryLoc, diag::err_exceptions_disabled) << "try";
+ Diag(TryLoc, diag::err_exceptions_disabled) << "try";
if (getCurScope() && getCurScope()->isOpenMPSimdDirectiveScope())
Diag(TryLoc, diag::err_omp_simd_region_cannot_use_stmt) << "try";
@@ -3320,55 +3538,74 @@
}
const unsigned NumHandlers = Handlers.size();
- assert(NumHandlers > 0 &&
+ assert(!Handlers.empty() &&
"The parser shouldn't call this if there are no handlers.");
- SmallVector<TypeWithHandler, 8> TypesWithHandlers;
-
+ llvm::DenseMap<CatchHandlerType, CXXCatchStmt *> HandledTypes;
for (unsigned i = 0; i < NumHandlers; ++i) {
- CXXCatchStmt *Handler = cast<CXXCatchStmt>(Handlers[i]);
- if (!Handler->getExceptionDecl()) {
- if (i < NumHandlers - 1)
- return StmtError(Diag(Handler->getLocStart(),
- diag::err_early_catch_all));
+ CXXCatchStmt *H = cast<CXXCatchStmt>(Handlers[i]);
+ // Diagnose when the handler is a catch-all handler, but it isn't the last
+ // handler for the try block. [except.handle]p5. Also, skip exception
+ // declarations that are invalid, since we can't usefully report on them.
+ if (!H->getExceptionDecl()) {
+ if (i < NumHandlers - 1)
+ return StmtError(Diag(H->getLocStart(), diag::err_early_catch_all));
continue;
+ } else if (H->getExceptionDecl()->isInvalidDecl())
+ continue;
+
+ // Walk the type hierarchy to diagnose when this type has already been
+ // handled (duplication), or cannot be handled (derivation inversion). We
+ // ignore top-level cv-qualifiers, per [except.handle]p3
+ CatchHandlerType HandlerCHT =
+ (QualType)Context.getCanonicalType(H->getCaughtType());
+
+ // We can ignore whether the type is a reference or a pointer; we need the
+ // underlying declaration type in order to get at the underlying record
+ // decl, if there is one.
+ QualType Underlying = HandlerCHT.underlying();
+ if (auto *RD = Underlying->getAsCXXRecordDecl()) {
+ if (!RD->hasDefinition())
+ continue;
+ // Check that none of the public, unambiguous base classes are in the
+ // map ([except.handle]p1). Give the base classes the same pointer
+ // qualification as the original type we are basing off of. This allows
+ // comparison against the handler type using the same top-level pointer
+ // as the original type.
+ CXXBasePaths Paths;
+ Paths.setOrigin(RD);
+ CatchTypePublicBases CTPB(Context, HandledTypes, HandlerCHT.isPointer());
+ if (RD->lookupInBases(CatchTypePublicBases::FindPublicBasesOfType, &CTPB,
+ Paths)) {
+ const CXXCatchStmt *Problem = CTPB.getFoundHandler();
+ if (!Paths.isAmbiguous(CTPB.getFoundHandlerType())) {
+ Diag(H->getExceptionDecl()->getTypeSpecStartLoc(),
+ diag::warn_exception_caught_by_earlier_handler)
+ << H->getCaughtType();
+ Diag(Problem->getExceptionDecl()->getTypeSpecStartLoc(),
+ diag::note_previous_exception_handler)
+ << Problem->getCaughtType();
+ }
+ }
}
- const QualType CaughtType = Handler->getCaughtType();
- const QualType CanonicalCaughtType = Context.getCanonicalType(CaughtType);
- TypesWithHandlers.push_back(TypeWithHandler(CanonicalCaughtType, Handler));
- }
-
- // Detect handlers for the same type as an earlier one.
- if (NumHandlers > 1) {
- llvm::array_pod_sort(TypesWithHandlers.begin(), TypesWithHandlers.end());
-
- TypeWithHandler prev = TypesWithHandlers[0];
- for (unsigned i = 1; i < TypesWithHandlers.size(); ++i) {
- TypeWithHandler curr = TypesWithHandlers[i];
-
- if (curr == prev) {
- Diag(curr.getTypeSpecStartLoc(),
- diag::warn_exception_caught_by_earlier_handler)
- << curr.getCatchStmt()->getCaughtType().getAsString();
- Diag(prev.getTypeSpecStartLoc(),
- diag::note_previous_exception_handler)
- << prev.getCatchStmt()->getCaughtType().getAsString();
- }
-
- prev = curr;
+ // Add the type the list of ones we have handled; diagnose if we've already
+ // handled it.
+ auto R = HandledTypes.insert(std::make_pair(H->getCaughtType(), H));
+ if (!R.second) {
+ const CXXCatchStmt *Problem = R.first->second;
+ Diag(H->getExceptionDecl()->getTypeSpecStartLoc(),
+ diag::warn_exception_caught_by_earlier_handler)
+ << H->getCaughtType();
+ Diag(Problem->getExceptionDecl()->getTypeSpecStartLoc(),
+ diag::note_previous_exception_handler)
+ << Problem->getCaughtType();
}
}
FSI->setHasCXXTry(TryLoc);
- // FIXME: We should detect handlers that cannot catch anything because an
- // earlier handler catches a superclass. Need to find a method that is not
- // quadratic for this.
- // Neither of these are explicitly forbidden, but every compiler detects them
- // and warns.
-
return CXXTryStmt::Create(Context, TryLoc, TryBlock, Handlers);
}
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 8e4fe85..f93a848 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -1747,7 +1747,7 @@
const MultiLevelTemplateArgumentList &TemplateArgs) {
bool Invalid = false;
SmallVector<CXXBaseSpecifier*, 4> InstantiatedBases;
- for (const auto Base : Pattern->bases()) {
+ for (const auto &Base : Pattern->bases()) {
if (!Base.getType()->isDependentType()) {
if (const CXXRecordDecl *RD = Base.getType()->getAsCXXRecordDecl()) {
if (RD->isInvalidDecl())
diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp
index e4fab71..fd3ba35 100644
--- a/lib/Sema/SemaTemplateVariadic.cpp
+++ b/lib/Sema/SemaTemplateVariadic.cpp
@@ -251,15 +251,10 @@
Locations.push_back(Unexpanded[I].second);
}
- DiagnosticBuilder DB
- = Names.size() == 0? Diag(Loc, diag::err_unexpanded_parameter_pack_0)
- << (int)UPPC
- : Names.size() == 1? Diag(Loc, diag::err_unexpanded_parameter_pack_1)
- << (int)UPPC << Names[0]
- : Names.size() == 2? Diag(Loc, diag::err_unexpanded_parameter_pack_2)
- << (int)UPPC << Names[0] << Names[1]
- : Diag(Loc, diag::err_unexpanded_parameter_pack_3_or_more)
- << (int)UPPC << Names[0] << Names[1];
+ DiagnosticBuilder DB = Diag(Loc, diag::err_unexpanded_parameter_pack)
+ << (int)UPPC << (int)Names.size();
+ for (size_t I = 0, E = std::min(Names.size(), (size_t)2); I != E; ++I)
+ DB << Names[I];
for (unsigned I = 0, N = Locations.size(); I != N; ++I)
DB << SourceRange(Locations[I]);
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 485b70a..5a6cc2e 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -2483,6 +2483,10 @@
// in a member pointer.
IsCXXInstanceMethod =
D.getTypeObject(I).Kind == DeclaratorChunk::MemberPointer;
+ } else if (D.getContext() == Declarator::LambdaExprContext) {
+ // This can only be a call operator for a lambda, which is an instance
+ // method.
+ IsCXXInstanceMethod = true;
} else {
// We're the innermost decl chunk, so must be a function declarator.
assert(D.isFunctionDeclarator());
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 1b0080a..df0e4b3 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -2623,6 +2623,31 @@
RBracLoc, Args);
}
+ /// \brief Build a new Objective-C instance/class message to 'super'.
+ ExprResult RebuildObjCMessageExpr(SourceLocation SuperLoc,
+ Selector Sel,
+ ArrayRef<SourceLocation> SelectorLocs,
+ ObjCMethodDecl *Method,
+ SourceLocation LBracLoc,
+ MultiExprArg Args,
+ SourceLocation RBracLoc) {
+ ObjCInterfaceDecl *Class = Method->getClassInterface();
+ QualType ReceiverTy = SemaRef.Context.getObjCInterfaceType(Class);
+
+ return Method->isInstanceMethod() ? SemaRef.BuildInstanceMessage(nullptr,
+ ReceiverTy,
+ SuperLoc,
+ Sel, Method, LBracLoc, SelectorLocs,
+ RBracLoc, Args)
+ : SemaRef.BuildClassMessage(nullptr,
+ ReceiverTy,
+ SuperLoc,
+ Sel, Method, LBracLoc, SelectorLocs,
+ RBracLoc, Args);
+
+
+ }
+
/// \brief Build a new Objective-C ivar reference expression.
///
/// By default, performs semantic analysis to build the new expression.
@@ -6645,7 +6670,16 @@
if (!D->getAssociatedStmt()) {
return StmtError();
}
- AssociatedStmt = getDerived().TransformStmt(D->getAssociatedStmt());
+ getDerived().getSema().ActOnOpenMPRegionStart(D->getDirectiveKind(),
+ /*CurScope=*/nullptr);
+ StmtResult Body;
+ {
+ Sema::CompoundScopeRAII CompoundScope(getSema());
+ Body = getDerived().TransformStmt(
+ cast<CapturedStmt>(D->getAssociatedStmt())->getCapturedStmt());
+ }
+ AssociatedStmt =
+ getDerived().getSema().ActOnOpenMPRegionEnd(Body, TClauses);
if (AssociatedStmt.isInvalid()) {
return StmtError();
}
@@ -10047,6 +10081,19 @@
Args,
E->getRightLoc());
}
+ else if (E->getReceiverKind() == ObjCMessageExpr::SuperClass ||
+ E->getReceiverKind() == ObjCMessageExpr::SuperInstance) {
+ // Build a new class message send to 'super'.
+ SmallVector<SourceLocation, 16> SelLocs;
+ E->getSelectorLocs(SelLocs);
+ return getDerived().RebuildObjCMessageExpr(E->getSuperLoc(),
+ E->getSelector(),
+ SelLocs,
+ E->getMethodDecl(),
+ E->getLeftLoc(),
+ Args,
+ E->getRightLoc());
+ }
// Instance message: transform the receiver
assert(E->getReceiverKind() == ObjCMessageExpr::Instance &&
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index 4d5141b..d26ed222 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -3354,11 +3354,6 @@
break;
}
- case MACRO_TABLE: {
- // FIXME: Not used yet.
- break;
- }
-
case LATE_PARSED_TEMPLATE: {
LateParsedTemplates.append(Record.begin(), Record.end());
break;
@@ -6730,20 +6725,14 @@
// individually, because finding an entity in one of them doesn't imply that
// we can't find a different entity in another one.
if (isa<CXXRecordDecl>(DC)) {
- auto Kind = Name.getNameKind();
- if (Kind == DeclarationName::CXXConstructorName ||
- Kind == DeclarationName::CXXDestructorName ||
- (Kind == DeclarationName::CXXOperatorName &&
- Name.getCXXOverloadedOperator() == OO_Equal)) {
- auto Merged = MergedLookups.find(DC);
- if (Merged != MergedLookups.end()) {
- for (unsigned I = 0; I != Merged->second.size(); ++I) {
- const DeclContext *Context = Merged->second[I];
- LookUpInContexts(Context);
- // We might have just added some more merged lookups. If so, our
- // iterator is now invalid, so grab a fresh one before continuing.
- Merged = MergedLookups.find(DC);
- }
+ auto Merged = MergedLookups.find(DC);
+ if (Merged != MergedLookups.end()) {
+ for (unsigned I = 0; I != Merged->second.size(); ++I) {
+ const DeclContext *Context = Merged->second[I];
+ LookUpInContexts(Context);
+ // We might have just added some more merged lookups. If so, our
+ // iterator is now invalid, so grab a fresh one before continuing.
+ Merged = MergedLookups.find(DC);
}
}
}
@@ -8679,7 +8668,10 @@
if (It != PendingFakeLookupResults.end()) {
for (auto *ND : PendingFakeLookupResults[II])
SemaObj->IdResolver.RemoveDecl(ND);
- PendingFakeLookupResults.erase(It);
+ // FIXME: this works around module+PCH performance issue.
+ // Rather than erase the result from the map, which is O(n), just clear
+ // the vector of NamedDecls.
+ It->second.clear();
}
}
diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp
index de2c625..5e911b4 100644
--- a/lib/Serialization/ASTReaderDecl.cpp
+++ b/lib/Serialization/ASTReaderDecl.cpp
@@ -1385,6 +1385,29 @@
"merging class definition into non-definition");
auto &DD = *D->DefinitionData.getNotUpdated();
+ // If the new definition has new special members, let the name lookup
+ // code know that it needs to look in the new definition too.
+ //
+ // FIXME: We only need to do this if the merged definition declares members
+ // that this definition did not declare, or if it defines members that this
+ // definition did not define.
+ if (DD.Definition != MergeDD.Definition) {
+ Reader.MergedLookups[DD.Definition].push_back(MergeDD.Definition);
+ DD.Definition->setHasExternalVisibleStorage();
+
+ if (DD.Definition->isHidden()) {
+ // If MergeDD is visible or becomes visible, make the definition visible.
+ if (!MergeDD.Definition->isHidden())
+ DD.Definition->Hidden = false;
+ else {
+ auto SubmoduleID = MergeDD.Definition->getOwningModuleID();
+ assert(SubmoduleID && "hidden definition in no module");
+ Reader.HiddenNamesMap[Reader.getSubmodule(SubmoduleID)]
+ .HiddenDecls.push_back(DD.Definition);
+ }
+ }
+ }
+
auto PFDI = Reader.PendingFakeDefinitionData.find(&DD);
if (PFDI != Reader.PendingFakeDefinitionData.end() &&
PFDI->second == ASTReader::PendingFakeDefinitionKind::Fake) {
@@ -1401,17 +1424,6 @@
return;
}
- // If the new definition has new special members, let the name lookup
- // code know that it needs to look in the new definition too.
- //
- // FIXME: We only need to do this if the merged definition declares members
- // that this definition did not declare, or if it defines members that this
- // definition did not define.
- if (MergeDD.DeclaredSpecialMembers && DD.Definition != MergeDD.Definition) {
- Reader.MergedLookups[DD.Definition].push_back(MergeDD.Definition);
- DD.Definition->setHasExternalVisibleStorage();
- }
-
// FIXME: Move this out into a .def file?
bool DetectedOdrViolation = false;
#define OR_FIELD(Field) DD.Field |= MergeDD.Field;
diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp
index c7b49de..57728c1 100644
--- a/lib/Serialization/ASTReaderStmt.cpp
+++ b/lib/Serialization/ASTReaderStmt.cpp
@@ -1889,6 +1889,22 @@
for (unsigned i = 0; i != NumVars; ++i)
Vars.push_back(Reader->Reader.ReadSubExpr());
C->setVarRefs(Vars);
+ Vars.clear();
+ for (unsigned i = 0; i != NumVars; ++i)
+ Vars.push_back(Reader->Reader.ReadSubExpr());
+ C->setPrivateCopies(Vars);
+ Vars.clear();
+ for (unsigned i = 0; i != NumVars; ++i)
+ Vars.push_back(Reader->Reader.ReadSubExpr());
+ C->setSourceExprs(Vars);
+ Vars.clear();
+ for (unsigned i = 0; i != NumVars; ++i)
+ Vars.push_back(Reader->Reader.ReadSubExpr());
+ C->setDestinationExprs(Vars);
+ Vars.clear();
+ for (unsigned i = 0; i != NumVars; ++i)
+ Vars.push_back(Reader->Reader.ReadSubExpr());
+ C->setAssignmentOps(Vars);
}
void OMPClauseReader::VisitOMPSharedClause(OMPSharedClause *C) {
@@ -1917,6 +1933,18 @@
for (unsigned i = 0; i != NumVars; ++i)
Vars.push_back(Reader->Reader.ReadSubExpr());
C->setVarRefs(Vars);
+ Vars.clear();
+ for (unsigned i = 0; i != NumVars; ++i)
+ Vars.push_back(Reader->Reader.ReadSubExpr());
+ C->setLHSExprs(Vars);
+ Vars.clear();
+ for (unsigned i = 0; i != NumVars; ++i)
+ Vars.push_back(Reader->Reader.ReadSubExpr());
+ C->setRHSExprs(Vars);
+ Vars.clear();
+ for (unsigned i = 0; i != NumVars; ++i)
+ Vars.push_back(Reader->Reader.ReadSubExpr());
+ C->setReductionOps(Vars);
}
void OMPClauseReader::VisitOMPLinearClause(OMPLinearClause *C) {
@@ -1959,11 +1987,23 @@
void OMPClauseReader::VisitOMPCopyinClause(OMPCopyinClause *C) {
C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
unsigned NumVars = C->varlist_size();
- SmallVector<Expr *, 16> Vars;
- Vars.reserve(NumVars);
+ SmallVector<Expr *, 16> Exprs;
+ Exprs.reserve(NumVars);
for (unsigned i = 0; i != NumVars; ++i)
- Vars.push_back(Reader->Reader.ReadSubExpr());
- C->setVarRefs(Vars);
+ Exprs.push_back(Reader->Reader.ReadSubExpr());
+ C->setVarRefs(Exprs);
+ Exprs.clear();
+ for (unsigned i = 0; i != NumVars; ++i)
+ Exprs.push_back(Reader->Reader.ReadSubExpr());
+ C->setSourceExprs(Exprs);
+ Exprs.clear();
+ for (unsigned i = 0; i != NumVars; ++i)
+ Exprs.push_back(Reader->Reader.ReadSubExpr());
+ C->setDestinationExprs(Exprs);
+ Exprs.clear();
+ for (unsigned i = 0; i != NumVars; ++i)
+ Exprs.push_back(Reader->Reader.ReadSubExpr());
+ C->setAssignmentOps(Exprs);
}
void OMPClauseReader::VisitOMPCopyprivateClause(OMPCopyprivateClause *C) {
@@ -2157,11 +2197,12 @@
// The NumClauses field was read in ReadStmtFromStream.
++Idx;
VisitOMPExecutableDirective(D);
- D->setOpKind(static_cast<BinaryOperatorKind>(Record[Idx++]));
D->setX(Reader.ReadSubExpr());
- D->setXRVal(Reader.ReadSubExpr());
D->setV(Reader.ReadSubExpr());
D->setExpr(Reader.ReadSubExpr());
+ D->setUpdateExpr(Reader.ReadSubExpr());
+ D->IsXLHSInRHSPart = Record[Idx++] != 0;
+ D->IsPostfixUpdate = Record[Idx++] != 0;
}
void ASTStmtReader::VisitOMPTargetDirective(OMPTargetDirective *D) {
diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp
index eccff9d..df05f04 100644
--- a/lib/Serialization/ASTWriter.cpp
+++ b/lib/Serialization/ASTWriter.cpp
@@ -927,7 +927,6 @@
RECORD(LOCAL_REDECLARATIONS);
RECORD(OBJC_CATEGORIES);
RECORD(MACRO_OFFSET);
- RECORD(MACRO_TABLE);
RECORD(LATE_PARSED_TEMPLATE);
RECORD(OPTIMIZE_PRAGMA_OPTIONS);
@@ -2083,13 +2082,10 @@
llvm::array_pod_sort(MacroDirectives.begin(), MacroDirectives.end(),
&compareMacroDirectives);
- llvm::OnDiskChainedHashTableGenerator<ASTMacroTableTrait> Generator;
-
// Emit the macro directives as a list and associate the offset with the
// identifier they belong to.
for (unsigned I = 0, N = MacroDirectives.size(); I != N; ++I) {
const IdentifierInfo *Name = MacroDirectives[I].first;
- uint64_t MacroDirectiveOffset = Stream.GetCurrentBitNo();
MacroDirective *MD = MacroDirectives[I].second;
// If the macro or identifier need no updates, don't write the macro history
@@ -2127,15 +2123,9 @@
if (Record.empty())
continue;
+ IdentMacroDirectivesOffsetMap[Name] = Stream.GetCurrentBitNo();
Stream.EmitRecord(PP_MACRO_DIRECTIVE_HISTORY, Record);
Record.clear();
-
- IdentMacroDirectivesOffsetMap[Name] = MacroDirectiveOffset;
-
- IdentID NameID = getIdentifierRef(Name);
- ASTMacroTableTrait::Data data;
- data.MacroDirectivesOffset = MacroDirectiveOffset;
- Generator.insert(NameID, data);
}
/// \brief Offsets of each of the macros into the bitstream, indexed by
@@ -2211,33 +2201,9 @@
Stream.ExitBlock();
- // Create the on-disk hash table in a buffer.
- SmallString<4096> MacroTable;
- uint32_t BucketOffset;
- {
- using namespace llvm::support;
- llvm::raw_svector_ostream Out(MacroTable);
- // Make sure that no bucket is at offset 0
- endian::Writer<little>(Out).write<uint32_t>(0);
- BucketOffset = Generator.Emit(Out);
- }
-
- // Write the macro table
- using namespace llvm;
- BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
- Abbrev->Add(BitCodeAbbrevOp(MACRO_TABLE));
- Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
- Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
- unsigned MacroTableAbbrev = Stream.EmitAbbrev(Abbrev);
-
- Record.push_back(MACRO_TABLE);
- Record.push_back(BucketOffset);
- Stream.EmitRecordWithBlob(MacroTableAbbrev, Record, MacroTable);
- Record.clear();
-
// Write the offsets table for macro IDs.
using namespace llvm;
- Abbrev = new BitCodeAbbrev();
+ auto *Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(MACRO_OFFSET));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of macros
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // first ID
diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp
index 3632672..608aa59 100644
--- a/lib/Serialization/ASTWriterDecl.cpp
+++ b/lib/Serialization/ASTWriterDecl.cpp
@@ -994,13 +994,16 @@
std::sort(LookupResults.begin(), LookupResults.end(), llvm::less_first());
for (auto &NameAndResult : LookupResults) {
DeclarationName Name = NameAndResult.first;
- (void)Name;
- assert(Name.getNameKind() != DeclarationName::CXXConstructorName &&
- "Cannot have a constructor name in a namespace!");
- assert(Name.getNameKind() != DeclarationName::CXXConversionFunctionName &&
- "Cannot have a conversion function name in a namespace!");
-
DeclContext::lookup_result Result = NameAndResult.second;
+ if (Name.getNameKind() == DeclarationName::CXXConstructorName ||
+ Name.getNameKind() == DeclarationName::CXXConversionFunctionName) {
+ // We have to work around a name lookup bug here where negative lookup
+ // results for these names get cached in namespace lookup tables.
+ assert(Result.empty() && "Cannot have a constructor or conversion "
+ "function name in a namespace!");
+ continue;
+ }
+
for (NamedDecl *ND : Result)
Writer.GetDeclRef(ND);
}
diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp
index 6e647c3..f15f76c 100644
--- a/lib/Serialization/ASTWriterStmt.cpp
+++ b/lib/Serialization/ASTWriterStmt.cpp
@@ -1798,6 +1798,14 @@
Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
for (auto *VE : C->varlists())
Writer->Writer.AddStmt(VE);
+ for (auto *E : C->private_copies())
+ Writer->Writer.AddStmt(E);
+ for (auto *E : C->source_exprs())
+ Writer->Writer.AddStmt(E);
+ for (auto *E : C->destination_exprs())
+ Writer->Writer.AddStmt(E);
+ for (auto *E : C->assignment_ops())
+ Writer->Writer.AddStmt(E);
}
void OMPClauseWriter::VisitOMPSharedClause(OMPSharedClause *C) {
@@ -1815,6 +1823,12 @@
Writer->Writer.AddDeclarationNameInfo(C->getNameInfo(), Record);
for (auto *VE : C->varlists())
Writer->Writer.AddStmt(VE);
+ for (auto *E : C->lhs_exprs())
+ Writer->Writer.AddStmt(E);
+ for (auto *E : C->rhs_exprs())
+ Writer->Writer.AddStmt(E);
+ for (auto *E : C->reduction_ops())
+ Writer->Writer.AddStmt(E);
}
void OMPClauseWriter::VisitOMPLinearClause(OMPLinearClause *C) {
@@ -1851,6 +1865,12 @@
Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
for (auto *VE : C->varlists())
Writer->Writer.AddStmt(VE);
+ for (auto *E : C->source_exprs())
+ Writer->Writer.AddStmt(E);
+ for (auto *E : C->destination_exprs())
+ Writer->Writer.AddStmt(E);
+ for (auto *E : C->assignment_ops())
+ Writer->Writer.AddStmt(E);
}
void OMPClauseWriter::VisitOMPCopyprivateClause(OMPCopyprivateClause *C) {
@@ -2005,11 +2025,12 @@
VisitStmt(D);
Record.push_back(D->getNumClauses());
VisitOMPExecutableDirective(D);
- Record.push_back(D->getOpKind());
Writer.AddStmt(D->getX());
- Writer.AddStmt(D->getXRVal());
Writer.AddStmt(D->getV());
Writer.AddStmt(D->getExpr());
+ Writer.AddStmt(D->getUpdateExpr());
+ Record.push_back(D->isXLHSInRHSPart() ? 1 : 0);
+ Record.push_back(D->isPostfixUpdate() ? 1 : 0);
Code = serialization::STMT_OMP_ATOMIC_DIRECTIVE;
}
diff --git a/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp b/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
index c1ea767..f4be5b3 100644
--- a/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
@@ -142,7 +142,7 @@
: cfg(cfg), Ctx(ctx), BR(br), Checker(checker), AC(ac), Parents(parents),
Escaped(escaped), currentBlock(nullptr) {}
- virtual ~DeadStoreObs() {}
+ ~DeadStoreObs() override {}
bool isLive(const LiveVariables::LivenessValues &Live, const VarDecl *D) {
if (Live.isLive(D))
diff --git a/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp b/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
index 0d73160..52e2936 100644
--- a/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
@@ -137,7 +137,7 @@
public:
SecKeychainBugVisitor(SymbolRef S) : Sym(S) {}
- virtual ~SecKeychainBugVisitor() {}
+ ~SecKeychainBugVisitor() override {}
void Profile(llvm::FoldingSetNodeID &ID) const override {
static int X = 0;
diff --git a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index 4155998..0cf0094 100644
--- a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -50,6 +50,8 @@
class RefState {
enum Kind { // Reference to allocated memory.
Allocated,
+ // Reference to zero-allocated memory.
+ AllocatedOfSizeZero,
// Reference to released/freed memory.
Released,
// The responsibility for freeing resources has transferred from
@@ -62,8 +64,8 @@
};
const Stmt *S;
- unsigned K : 2; // Kind enum, but stored as a bitfield.
- unsigned Family : 30; // Rest of 32-bit word, currently just an allocation
+ unsigned K : 3; // Kind enum, but stored as a bitfield.
+ unsigned Family : 29; // Rest of 32-bit word, currently just an allocation
// family.
RefState(Kind k, const Stmt *s, unsigned family)
@@ -72,6 +74,7 @@
}
public:
bool isAllocated() const { return K == Allocated; }
+ bool isAllocatedOfSizeZero() const { return K == AllocatedOfSizeZero; }
bool isReleased() const { return K == Released; }
bool isRelinquished() const { return K == Relinquished; }
bool isEscaped() const { return K == Escaped; }
@@ -87,6 +90,10 @@
static RefState getAllocated(unsigned family, const Stmt *s) {
return RefState(Allocated, s, family);
}
+ static RefState getAllocatedOfSizeZero(const RefState *RS) {
+ return RefState(AllocatedOfSizeZero, RS->getStmt(),
+ RS->getAllocationFamily());
+ }
static RefState getReleased(unsigned family, const Stmt *s) {
return RefState(Released, s, family);
}
@@ -107,6 +114,7 @@
switch (static_cast<Kind>(K)) {
#define CASE(ID) case ID: OS << #ID; break;
CASE(Allocated)
+ CASE(AllocatedOfSizeZero)
CASE(Released)
CASE(Relinquished)
CASE(Escaped)
@@ -222,6 +230,7 @@
mutable std::unique_ptr<BugType> BT_FreeAlloca[CK_NumCheckKinds];
mutable std::unique_ptr<BugType> BT_MismatchedDealloc;
mutable std::unique_ptr<BugType> BT_OffsetFree[CK_NumCheckKinds];
+ mutable std::unique_ptr<BugType> BT_UseZerroAllocated[CK_NumCheckKinds];
mutable IdentifierInfo *II_alloca, *II_malloc, *II_free, *II_realloc,
*II_calloc, *II_valloc, *II_reallocf, *II_strndup,
*II_strdup, *II_kmalloc, *II_if_nameindex,
@@ -257,6 +266,12 @@
MemoryOperationKind MemKind) const;
bool isStandardNewDelete(const FunctionDecl *FD, ASTContext &C) const;
///@}
+
+ /// \brief Perform a zero-allocation check.
+ ProgramStateRef ProcessZeroAllocation(CheckerContext &C, const Expr *E,
+ const unsigned AllocationSizeArg,
+ ProgramStateRef State) const;
+
ProgramStateRef MallocMemReturnsAttr(CheckerContext &C,
const CallExpr *CE,
const OwnershipAttr* Att,
@@ -307,6 +322,9 @@
bool checkUseAfterFree(SymbolRef Sym, CheckerContext &C, const Stmt *S) const;
+ void checkUseZeroAllocated(SymbolRef Sym, CheckerContext &C,
+ const Stmt *S) const;
+
bool checkDoubleDelete(SymbolRef Sym, CheckerContext &C) const;
/// Check if the function is known free memory, or if it is
@@ -361,6 +379,9 @@
void ReportDoubleDelete(CheckerContext &C, SymbolRef Sym) const;
+ void ReportUseZeroAllocated(CheckerContext &C, SourceRange Range,
+ SymbolRef Sym) const;
+
/// Find the location of the allocation for Sym on the path leading to the
/// exploded node N.
LeakInfo getAllocationSite(const ExplodedNode *N, SymbolRef Sym,
@@ -393,7 +414,7 @@
MallocBugVisitor(SymbolRef S, bool isLeak = false)
: Sym(S), Mode(Normal), FailedReallocSymbol(nullptr), IsLeak(isLeak) {}
- virtual ~MallocBugVisitor() {}
+ ~MallocBugVisitor() override {}
void Profile(llvm::FoldingSetNodeID &ID) const override {
static int X = 0;
@@ -405,7 +426,9 @@
const Stmt *Stmt) {
// Did not track -> allocated. Other state (released) -> allocated.
return (Stmt && (isa<CallExpr>(Stmt) || isa<CXXNewExpr>(Stmt)) &&
- (S && S->isAllocated()) && (!SPrev || !SPrev->isAllocated()));
+ (S && (S->isAllocated() || S->isAllocatedOfSizeZero())) &&
+ (!SPrev || !(SPrev->isAllocated() ||
+ SPrev->isAllocatedOfSizeZero())));
}
inline bool isReleased(const RefState *S, const RefState *SPrev,
@@ -431,7 +454,9 @@
// check. If we have to handle more cases here, it might be cleaner just
// to track this extra bit in the state itself.
return ((!Stmt || !isa<CallExpr>(Stmt)) &&
- (S && S->isAllocated()) && (SPrev && !SPrev->isAllocated()));
+ (S && (S->isAllocated() || S->isAllocatedOfSizeZero())) &&
+ (SPrev && !(SPrev->isAllocated() ||
+ SPrev->isAllocatedOfSizeZero())));
}
PathDiagnosticPiece *VisitNode(const ExplodedNode *N,
@@ -730,6 +755,8 @@
return;
if (CE->getNumArgs() < 3) {
State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State);
+ if (CE->getNumArgs() == 1)
+ State = ProcessZeroAllocation(C, CE, 0, State);
} else if (CE->getNumArgs() == 3) {
llvm::Optional<ProgramStateRef> MaybeState =
performKernelMalloc(CE, C, State);
@@ -749,12 +776,17 @@
if (CE->getNumArgs() < 1)
return;
State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State);
+ State = ProcessZeroAllocation(C, CE, 0, State);
} else if (FunI == II_realloc) {
State = ReallocMem(C, CE, false, State);
+ State = ProcessZeroAllocation(C, CE, 1, State);
} else if (FunI == II_reallocf) {
State = ReallocMem(C, CE, true, State);
+ State = ProcessZeroAllocation(C, CE, 1, State);
} else if (FunI == II_calloc) {
State = CallocMem(C, CE, State);
+ State = ProcessZeroAllocation(C, CE, 0, State);
+ State = ProcessZeroAllocation(C, CE, 1, State);
} else if (FunI == II_free) {
State = FreeMemAux(C, CE, State, 0, false, ReleasedAllocatedMemory);
} else if (FunI == II_strdup) {
@@ -764,18 +796,23 @@
} else if (FunI == II_alloca) {
State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State,
AF_Alloca);
+ State = ProcessZeroAllocation(C, CE, 0, State);
} else if (isStandardNewDelete(FD, C.getASTContext())) {
// Process direct calls to operator new/new[]/delete/delete[] functions
// as distinct from new/new[]/delete/delete[] expressions that are
// processed by the checkPostStmt callbacks for CXXNewExpr and
// CXXDeleteExpr.
OverloadedOperatorKind K = FD->getOverloadedOperator();
- if (K == OO_New)
+ if (K == OO_New) {
State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State,
AF_CXXNew);
- else if (K == OO_Array_New)
+ State = ProcessZeroAllocation(C, CE, 0, State);
+ }
+ else if (K == OO_Array_New) {
State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State,
AF_CXXNewArray);
+ State = ProcessZeroAllocation(C, CE, 0, State);
+ }
else if (K == OO_Delete || K == OO_Array_Delete)
State = FreeMemAux(C, CE, State, 0, false, ReleasedAllocatedMemory);
else
@@ -809,6 +846,68 @@
C.addTransition(State);
}
+// Performs a 0-sized allocations check.
+ProgramStateRef MallocChecker::ProcessZeroAllocation(CheckerContext &C,
+ const Expr *E,
+ const unsigned AllocationSizeArg,
+ ProgramStateRef State) const {
+ if (!State)
+ return nullptr;
+
+ const Expr *Arg = nullptr;
+
+ if (const CallExpr *CE = dyn_cast<CallExpr>(E)) {
+ Arg = CE->getArg(AllocationSizeArg);
+ }
+ else if (const CXXNewExpr *NE = dyn_cast<CXXNewExpr>(E)) {
+ if (NE->isArray())
+ Arg = NE->getArraySize();
+ else
+ return State;
+ }
+ else
+ llvm_unreachable("not a CallExpr or CXXNewExpr");
+
+ assert(Arg);
+
+ Optional<DefinedSVal> DefArgVal =
+ State->getSVal(Arg, C.getLocationContext()).getAs<DefinedSVal>();
+
+ if (!DefArgVal)
+ return State;
+
+ // Check if the allocation size is 0.
+ ProgramStateRef TrueState, FalseState;
+ SValBuilder &SvalBuilder = C.getSValBuilder();
+ DefinedSVal Zero =
+ SvalBuilder.makeZeroVal(Arg->getType()).castAs<DefinedSVal>();
+
+ std::tie(TrueState, FalseState) =
+ State->assume(SvalBuilder.evalEQ(State, *DefArgVal, Zero));
+
+ if (TrueState && !FalseState) {
+ SVal retVal = State->getSVal(E, C.getLocationContext());
+ SymbolRef Sym = retVal.getAsLocSymbol();
+ if (!Sym)
+ return State;
+
+ const RefState *RS = State->get<RegionState>(Sym);
+ if (!RS)
+ return State; // TODO: change to assert(RS); after realloc() will
+ // guarantee have a RegionState attached.
+
+ if (!RS->isAllocated())
+ return State;
+
+ return TrueState->set<RegionState>(Sym,
+ RefState::getAllocatedOfSizeZero(RS));
+ }
+
+ // Assume the value is non-zero going forward.
+ assert(FalseState);
+ return FalseState;
+}
+
static QualType getDeepPointeeType(QualType T) {
QualType Result = T, PointeeType = T->getPointeeType();
while (!PointeeType.isNull()) {
@@ -868,6 +967,7 @@
// existing binding.
State = MallocUpdateRefState(C, NE, State, NE->isArray() ? AF_CXXNewArray
: AF_CXXNew);
+ State = ProcessZeroAllocation(C, NE, 0, State);
C.addTransition(State);
}
@@ -1291,7 +1391,8 @@
// If the pointer is allocated or escaped, but we are now trying to free it,
// check that the call to free is proper.
- } else if (RsBase->isAllocated() || RsBase->isEscaped()) {
+ } else if (RsBase->isAllocated() || RsBase->isAllocatedOfSizeZero() ||
+ RsBase->isEscaped()) {
// Check if an expected deallocation function matches the real one.
bool DeallocMatchesAlloc =
@@ -1316,7 +1417,8 @@
}
}
- ReleasedAllocated = (RsBase != nullptr) && RsBase->isAllocated();
+ ReleasedAllocated = (RsBase != nullptr) && (RsBase->isAllocated() ||
+ RsBase->isAllocatedOfSizeZero());
// Clean out the info on previous call to free return info.
State = State->remove<FreeReturnValue>(SymBase);
@@ -1741,6 +1843,36 @@
}
}
+void MallocChecker::ReportUseZeroAllocated(CheckerContext &C,
+ SourceRange Range,
+ SymbolRef Sym) const {
+
+ if (!ChecksEnabled[CK_MallocChecker] &&
+ !ChecksEnabled[CK_NewDeleteChecker])
+ return;
+
+ Optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(C, Sym);
+
+ if (!CheckKind.hasValue())
+ return;
+
+ if (ExplodedNode *N = C.generateSink()) {
+ if (!BT_UseZerroAllocated[*CheckKind])
+ BT_UseZerroAllocated[*CheckKind].reset(new BugType(
+ CheckNames[*CheckKind], "Use of zero allocated", "Memory Error"));
+
+ BugReport *R = new BugReport(*BT_UseZerroAllocated[*CheckKind],
+ "Use of zero-allocated memory", N);
+
+ R->addRange(Range);
+ if (Sym) {
+ R->markInteresting(Sym);
+ R->addVisitor(llvm::make_unique<MallocBugVisitor>(Sym));
+ }
+ C.emitReport(R);
+ }
+}
+
ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C,
const CallExpr *CE,
bool FreesOnFail,
@@ -1988,7 +2120,7 @@
SmallVector<SymbolRef, 2> Errors;
for (RegionStateTy::iterator I = RS.begin(), E = RS.end(); I != E; ++I) {
if (SymReaper.isDead(I->first)) {
- if (I->second.isAllocated())
+ if (I->second.isAllocated() || I->second.isAllocatedOfSizeZero())
Errors.push_back(I->first);
// Remove the dead symbol from the map.
RS = F.remove(RS, I->first);
@@ -2156,6 +2288,15 @@
return false;
}
+void MallocChecker::checkUseZeroAllocated(SymbolRef Sym, CheckerContext &C,
+ const Stmt *S) const {
+ assert(Sym);
+ const RefState *RS = C.getState()->get<RegionState>(Sym);
+
+ if (RS && RS->isAllocatedOfSizeZero())
+ ReportUseZeroAllocated(C, RS->getStmt()->getSourceRange(), Sym);
+}
+
bool MallocChecker::checkDoubleDelete(SymbolRef Sym, CheckerContext &C) const {
if (isReleased(Sym, C)) {
@@ -2169,8 +2310,10 @@
void MallocChecker::checkLocation(SVal l, bool isLoad, const Stmt *S,
CheckerContext &C) const {
SymbolRef Sym = l.getLocSymbolInBase();
- if (Sym)
+ if (Sym) {
checkUseAfterFree(Sym, C, S);
+ checkUseZeroAllocated(Sym, C, S);
+ }
}
// If a symbolic region is assumed to NULL (or another constant), stop tracking
@@ -2414,7 +2557,8 @@
continue;
if (const RefState *RS = State->get<RegionState>(sym)) {
- if (RS->isAllocated() && CheckRefState(RS)) {
+ if ((RS->isAllocated() || RS->isAllocatedOfSizeZero()) &&
+ CheckRefState(RS)) {
State = State->remove<RegionState>(sym);
State = State->set<RegionState>(sym, RefState::getEscaped(RS));
}
diff --git a/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp
index f38ce77..e913479 100644
--- a/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp
@@ -142,13 +142,13 @@
}
}
}
- else if (isa<MemberExpr>(E)) {
+ else if (const auto *ME = dyn_cast<MemberExpr>(E)) {
// No points-to analysis, just look at the member
- const Decl * EmeMD = dyn_cast<MemberExpr>(E)->getMemberDecl();
+ const Decl *EmeMD = ME->getMemberDecl();
while (i != e) {
--i;
- if (isa<MemberExpr>(i->variable)) {
- if (dyn_cast<MemberExpr>(i->variable)->getMemberDecl() == EmeMD)
+ if (const auto *ME_i = dyn_cast<MemberExpr>(i->variable)) {
+ if (ME_i->getMemberDecl() == EmeMD)
i = toScanFor.erase (i);
}
}
diff --git a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
index 6b8596e..58c27d4 100644
--- a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
@@ -2475,9 +2475,7 @@
: ShouldResetSummaryLog(false),
IncludeAllocationLine(shouldIncludeAllocationSiteInLeakDiagnostics(AO)) {}
- virtual ~RetainCountChecker() {
- DeleteContainerSeconds(DeadSymbolTags);
- }
+ ~RetainCountChecker() override { DeleteContainerSeconds(DeadSymbolTags); }
void checkEndAnalysis(ExplodedGraph &G, BugReporter &BR,
ExprEngine &Eng) const {
@@ -2821,63 +2819,6 @@
return false;
}
-/// Returns the property that claims this instance variable, if any.
-static const ObjCPropertyDecl *findPropForIvar(const ObjCIvarDecl *Ivar) {
- auto IsPropertyForIvar = [Ivar](const ObjCPropertyDecl *Prop) -> bool {
- return Prop->getPropertyIvarDecl() == Ivar;
- };
-
- const ObjCInterfaceDecl *Interface = Ivar->getContainingInterface();
- auto PropIter = std::find_if(Interface->prop_begin(), Interface->prop_end(),
- IsPropertyForIvar);
- if (PropIter != Interface->prop_end()) {
- return *PropIter;
- }
-
- for (auto Extension : Interface->visible_extensions()) {
- PropIter = std::find_if(Extension->prop_begin(), Extension->prop_end(),
- IsPropertyForIvar);
- if (PropIter != Extension->prop_end())
- return *PropIter;
- }
-
- return nullptr;
-}
-
-namespace {
- enum Retaining_t {
- NonRetaining,
- Retaining
- };
-}
-
-static Optional<Retaining_t> getRetainSemantics(const ObjCPropertyDecl *Prop) {
- assert(Prop->getPropertyIvarDecl() &&
- "should only be used for properties with synthesized implementations");
-
- if (!Prop->hasWrittenStorageAttribute()) {
- // Don't assume anything about the retain semantics of readonly properties.
- if (Prop->isReadOnly())
- return None;
-
- // Don't assume anything about readwrite properties with manually-supplied
- // setters.
- const ObjCMethodDecl *Setter = Prop->getSetterMethodDecl();
- bool HasManualSetter = std::any_of(Setter->redecls_begin(),
- Setter->redecls_end(),
- [](const Decl *SetterRedecl) -> bool {
- return cast<ObjCMethodDecl>(SetterRedecl)->hasBody();
- });
- if (HasManualSetter)
- return None;
-
- // If the setter /is/ synthesized, we're already relying on the retain
- // semantics of the property. Continue as normal.
- }
-
- return Prop->isRetaining() ? Retaining : NonRetaining;
-}
-
void RetainCountChecker::checkPostStmt(const ObjCIvarRefExpr *IRE,
CheckerContext &C) const {
Optional<Loc> IVarLoc = C.getSVal(IRE).getAs<Loc>();
@@ -2914,14 +2855,6 @@
return;
}
- // Also don't do anything if the ivar is unretained. If so, we know that
- // there's no outstanding retain count for the value.
- if (Kind == RetEffect::ObjC)
- if (const ObjCPropertyDecl *Prop = findPropForIvar(IRE->getDecl()))
- if (auto retainSemantics = getRetainSemantics(Prop))
- if (retainSemantics.getValue() == NonRetaining)
- return;
-
// Note that this value has been loaded from an ivar.
C.addTransition(setRefBinding(State, Sym, RV->withIvarAccess()));
return;
@@ -2935,23 +2868,7 @@
return;
}
- bool didUpdateState = false;
- if (Kind == RetEffect::ObjC) {
- // Check if the ivar is known to be unretained. If so, we know that
- // there's no outstanding retain count for the value.
- if (const ObjCPropertyDecl *Prop = findPropForIvar(IRE->getDecl())) {
- if (auto retainSemantics = getRetainSemantics(Prop)) {
- if (retainSemantics.getValue() == NonRetaining) {
- State = setRefBinding(State, Sym, PlusZero);
- didUpdateState = true;
- }
- }
- }
- }
-
- if (!didUpdateState)
- State = setRefBinding(State, Sym, PlusZero.withIvarAccess());
-
+ State = setRefBinding(State, Sym, PlusZero.withIvarAccess());
C.addTransition(State);
}
@@ -3318,6 +3235,16 @@
RefVal::Kind ErrorKind,
SymbolRef Sym,
CheckerContext &C) const {
+ // HACK: Ignore retain-count issues on values accessed through ivars,
+ // because of cases like this:
+ // [_contentView retain];
+ // [_contentView removeFromSuperview];
+ // [self addSubview:_contentView]; // invalidates 'self'
+ // [_contentView release];
+ if (const RefVal *RV = getRefBinding(St, Sym))
+ if (RV->getIvarAccessHistory() != RefVal::IvarAccessHistory::None)
+ return;
+
ExplodedNode *N = C.generateSink(St);
if (!N)
return;
@@ -3544,6 +3471,15 @@
RetEffect RE, RefVal X,
SymbolRef Sym,
ProgramStateRef state) const {
+ // HACK: Ignore retain-count issues on values accessed through ivars,
+ // because of cases like this:
+ // [_contentView retain];
+ // [_contentView removeFromSuperview];
+ // [self addSubview:_contentView]; // invalidates 'self'
+ // [_contentView release];
+ if (X.getIvarAccessHistory() != RefVal::IvarAccessHistory::None)
+ return;
+
// Any leaks or other errors?
if (X.isReturnedOwned() && X.getCount() == 0) {
if (RE.getKind() != RetEffect::NoRet) {
@@ -3781,6 +3717,15 @@
return setRefBinding(state, Sym, V);
}
+ // HACK: Ignore retain-count issues on values accessed through ivars,
+ // because of cases like this:
+ // [_contentView retain];
+ // [_contentView removeFromSuperview];
+ // [self addSubview:_contentView]; // invalidates 'self'
+ // [_contentView release];
+ if (V.getIvarAccessHistory() != RefVal::IvarAccessHistory::None)
+ return state;
+
// Woah! More autorelease counts then retain counts left.
// Emit hard error.
V = V ^ RefVal::ErrorOverAutorelease;
@@ -3814,11 +3759,22 @@
RetainCountChecker::handleSymbolDeath(ProgramStateRef state,
SymbolRef sid, RefVal V,
SmallVectorImpl<SymbolRef> &Leaked) const {
- bool hasLeak = false;
- if (V.isOwned())
+ bool hasLeak;
+
+ // HACK: Ignore retain-count issues on values accessed through ivars,
+ // because of cases like this:
+ // [_contentView retain];
+ // [_contentView removeFromSuperview];
+ // [self addSubview:_contentView]; // invalidates 'self'
+ // [_contentView release];
+ if (V.getIvarAccessHistory() != RefVal::IvarAccessHistory::None)
+ hasLeak = false;
+ else if (V.isOwned())
hasLeak = true;
else if (V.isNotOwned() || V.isReturnedOwned())
hasLeak = (V.getCount() > 0);
+ else
+ hasLeak = false;
if (!hasLeak)
return removeRefBinding(state, sid);
diff --git a/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp b/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
index 026cc02..3c1a3b4 100644
--- a/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
+++ b/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
@@ -45,7 +45,7 @@
public:
HTMLDiagnostics(AnalyzerOptions &AnalyzerOpts, const std::string& prefix, const Preprocessor &pp);
- virtual ~HTMLDiagnostics() { FlushDiagnostics(nullptr); }
+ ~HTMLDiagnostics() override { FlushDiagnostics(nullptr); }
void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
FilesMade *filesMade) override;
diff --git a/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp b/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
index 76026aa..e0aff58 100644
--- a/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
+++ b/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
@@ -37,7 +37,7 @@
const LangOptions &LangOpts,
bool supportsMultipleFiles);
- virtual ~PlistDiagnostics() {}
+ ~PlistDiagnostics() override {}
void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
FilesMade *filesMade) override;
diff --git a/lib/StaticAnalyzer/Core/SimpleConstraintManager.h b/lib/StaticAnalyzer/Core/SimpleConstraintManager.h
index a72d1d4..135cd4e 100644
--- a/lib/StaticAnalyzer/Core/SimpleConstraintManager.h
+++ b/lib/StaticAnalyzer/Core/SimpleConstraintManager.h
@@ -27,7 +27,7 @@
public:
SimpleConstraintManager(SubEngine *subengine, SValBuilder &SB)
: SU(subengine), SVB(SB) {}
- virtual ~SimpleConstraintManager();
+ ~SimpleConstraintManager() override;
//===------------------------------------------------------------------===//
// Common implementation for the interface provided by ConstraintManager.
diff --git a/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp b/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
index df9e4d6..b3cab87 100644
--- a/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
+++ b/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
@@ -29,7 +29,7 @@
SimpleSValBuilder(llvm::BumpPtrAllocator &alloc, ASTContext &context,
ProgramStateManager &stateMgr)
: SValBuilder(alloc, context, stateMgr) {}
- virtual ~SimpleSValBuilder() {}
+ ~SimpleSValBuilder() override {}
SVal evalMinus(NonLoc val) override;
SVal evalComplement(NonLoc val) override;
diff --git a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
index 621718e..fbeffb8 100644
--- a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
+++ b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
@@ -92,7 +92,7 @@
public:
ClangDiagPathDiagConsumer(DiagnosticsEngine &Diag)
: Diag(Diag), IncludePath(false) {}
- virtual ~ClangDiagPathDiagConsumer() {}
+ ~ClangDiagPathDiagConsumer() override {}
StringRef getName() const override { return "ClangDiags"; }
bool supportsLogicalOpControlFlow() const override { return true; }
@@ -199,7 +199,7 @@
}
}
- ~AnalysisConsumer() {
+ ~AnalysisConsumer() override {
if (Opts->PrintStats)
delete TUTotalTimer;
}
@@ -373,8 +373,7 @@
return true;
}
- virtual void
- AddDiagnosticConsumer(PathDiagnosticConsumer *Consumer) override {
+ void AddDiagnosticConsumer(PathDiagnosticConsumer *Consumer) override {
PathConsumers.push_back(Consumer);
}
@@ -724,7 +723,7 @@
public:
UbigraphViz(std::unique_ptr<raw_ostream> Out, StringRef Filename);
- ~UbigraphViz();
+ ~UbigraphViz() override;
void AddEdge(ExplodedNode *Src, ExplodedNode *Dst) override;
};
diff --git a/lib/StaticAnalyzer/Frontend/ModelInjector.h b/lib/StaticAnalyzer/Frontend/ModelInjector.h
index fd24e32..e23bf8a 100644
--- a/lib/StaticAnalyzer/Frontend/ModelInjector.h
+++ b/lib/StaticAnalyzer/Frontend/ModelInjector.h
@@ -43,8 +43,8 @@
class ModelInjector : public CodeInjector {
public:
ModelInjector(CompilerInstance &CI);
- Stmt *getBody(const FunctionDecl *D);
- Stmt *getBody(const ObjCMethodDecl *D);
+ Stmt *getBody(const FunctionDecl *D) override;
+ Stmt *getBody(const ObjCMethodDecl *D) override;
private:
/// \brief Synthesize a body for a declaration
diff --git a/lib/Tooling/CompilationDatabase.cpp b/lib/Tooling/CompilationDatabase.cpp
index 383fb1a..2514f02 100644
--- a/lib/Tooling/CompilationDatabase.cpp
+++ b/lib/Tooling/CompilationDatabase.cpp
@@ -156,8 +156,8 @@
// recording for our own purposes.
UnusedInputDiagConsumer(DiagnosticConsumer *Other) : Other(Other) {}
- virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
- const Diagnostic &Info) override {
+ void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
+ const Diagnostic &Info) override {
if (Info.getID() == clang::diag::warn_drv_input_file_unused) {
// Arg 1 for this diagnostic is the option that didn't get used.
UnusedInputs.push_back(Info.getArgStdStr(0));
@@ -283,11 +283,9 @@
return true;
}
-FixedCompilationDatabase *
-FixedCompilationDatabase::loadFromCommandLine(int &Argc,
- const char **Argv,
- Twine Directory) {
- const char **DoubleDash = std::find(Argv, Argv + Argc, StringRef("--"));
+FixedCompilationDatabase *FixedCompilationDatabase::loadFromCommandLine(
+ int &Argc, const char *const *Argv, Twine Directory) {
+ const char *const *DoubleDash = std::find(Argv, Argv + Argc, StringRef("--"));
if (DoubleDash == Argv + Argc)
return nullptr;
std::vector<const char *> CommandLine(DoubleDash + 1, Argv + Argc);
diff --git a/lib/Tooling/Tooling.cpp b/lib/Tooling/Tooling.cpp
index 60371fb..e100003 100644
--- a/lib/Tooling/Tooling.cpp
+++ b/lib/Tooling/Tooling.cpp
@@ -90,7 +90,7 @@
}
/// \brief Returns a clang build invocation initialized from the CC1 flags.
-static clang::CompilerInvocation *newInvocation(
+clang::CompilerInvocation *newInvocation(
clang::DiagnosticsEngine *Diagnostics,
const llvm::opt::ArgStringList &CC1Args) {
assert(!CC1Args.empty() && "Must at least contain the program name!");
diff --git a/test/ARCMT/objcmt-property.m b/test/ARCMT/objcmt-property.m
index 61739ef..1ea4109 100644
--- a/test/ARCMT/objcmt-property.m
+++ b/test/ARCMT/objcmt-property.m
@@ -238,3 +238,11 @@
@property (nonatomic, readonly) int Idelegate;
@property (nonatomic, readonly) BOOL Bdelegate;
@end
+
+// rdar://19372798
+@protocol NSObject @end
+@protocol MyProtocol <NSObject>
+- (id)readonlyProperty;
+- (id)readWriteProperty;
+- (void)setReadWriteProperty:(id)readWriteProperty;
+@end
diff --git a/test/ARCMT/objcmt-property.m.result b/test/ARCMT/objcmt-property.m.result
index ec4ac85..58f8ce2 100644
--- a/test/ARCMT/objcmt-property.m.result
+++ b/test/ARCMT/objcmt-property.m.result
@@ -211,3 +211,10 @@
@property (nonatomic, readonly) int Idelegate;
@property (nonatomic, readonly) BOOL Bdelegate;
@end
+
+// rdar://19372798
+@protocol NSObject @end
+@protocol MyProtocol <NSObject>
+@property (nonatomic, readonly, strong) id readonlyProperty;
+@property (nonatomic, strong) id readWriteProperty;
+@end
diff --git a/test/Analysis/Malloc+MismatchedDeallocator_intersections.cpp b/test/Analysis/Malloc+MismatchedDeallocator_intersections.cpp
index 639790d..bca223b 100644
--- a/test/Analysis/Malloc+MismatchedDeallocator_intersections.cpp
+++ b/test/Analysis/Malloc+MismatchedDeallocator_intersections.cpp
@@ -24,5 +24,16 @@
int *p4 = new int;
delete p4;
- int j = *p4; // no-warning
+ int j = *p4; // no-warning
+}
+
+void testUseZeroAllocNoWarn() {
+ int *p1 = (int *)operator new(0);
+ *p1 = 1; // no-warning
+
+ int *p2 = (int *)operator new[](0);
+ p2[0] = 1; // no-warning
+
+ int *p3 = new int[0];
+ p3[0] = 1; // no-warning
}
diff --git a/test/Analysis/NewDelete-checker-test.cpp b/test/Analysis/NewDelete-checker-test.cpp
index 3f28c2e..443cb2e 100644
--- a/test/Analysis/NewDelete-checker-test.cpp
+++ b/test/Analysis/NewDelete-checker-test.cpp
@@ -87,6 +87,30 @@
new (w) PtrWrapper(new int); // no warn
}
+//-----------------------------------------
+// check for usage of zero-allocated memory
+//-----------------------------------------
+
+void testUseZeroAlloc1() {
+ int *p = (int *)operator new(0);
+ *p = 1; // expected-warning {{Use of zero-allocated memory}}
+ delete p;
+}
+
+int testUseZeroAlloc2() {
+ int *p = (int *)operator new[](0);
+ return p[0]; // expected-warning {{Use of zero-allocated memory}}
+ delete[] p;
+}
+
+void f(int);
+
+void testUseZeroAlloc3() {
+ int *p = new int[0];
+ f(*p); // expected-warning {{Use of zero-allocated memory}}
+ delete[] p;
+}
+
//---------------
// other checks
//---------------
diff --git a/test/Analysis/NewDelete-intersections.mm b/test/Analysis/NewDelete-intersections.mm
index 7b3fb6e..cde8122 100644
--- a/test/Analysis/NewDelete-intersections.mm
+++ b/test/Analysis/NewDelete-intersections.mm
@@ -43,6 +43,11 @@
delete p2; // no warn
}
+void testUseZeroAllocatedMalloced() {
+ int *p1 = (int *)malloc(0);
+ *p1 = 1; // no warn
+}
+
//----- Test free standard new
void testFreeOpNew() {
void *p = operator new(0);
diff --git a/test/Analysis/malloc.c b/test/Analysis/malloc.c
index 5762061..662df4c 100644
--- a/test/Analysis/malloc.c
+++ b/test/Analysis/malloc.c
@@ -200,6 +200,112 @@
char *r = reallocf(0, 12);
} // expected-warning {{Potential leak of memory pointed to by}}
+//------------------- Check usage of zero-allocated memory ---------------------
+void CheckUseZeroAllocatedNoWarn1() {
+ int *p = malloc(0);
+ free(p); // no warning
+}
+
+void CheckUseZeroAllocatedNoWarn2() {
+ int *p = alloca(0); // no warning
+}
+
+void CheckUseZeroAllocatedNoWarn3() {
+ int *p = malloc(0);
+ int *q = realloc(p, 8); // no warning
+ free(q);
+}
+
+void CheckUseZeroAllocatedNoWarn4() {
+ int *p = realloc(0, 8);
+ *p = 1; // no warning
+ free(p);
+}
+
+void CheckUseZeroAllocated1() {
+ int *p = malloc(0);
+ *p = 1; // expected-warning {{Use of zero-allocated memory}}
+ free(p);
+}
+
+char CheckUseZeroAllocated2() {
+ char *p = alloca(0);
+ return *p; // expected-warning {{Use of zero-allocated memory}}
+}
+
+void UseZeroAllocated(int *p) {
+ if (p)
+ *p = 7; // expected-warning {{Use of zero-allocated memory}}
+}
+void CheckUseZeroAllocated3() {
+ int *p = malloc(0);
+ UseZeroAllocated(p);
+}
+
+void f(char);
+void CheckUseZeroAllocated4() {
+ char *p = valloc(0);
+ f(*p); // expected-warning {{Use of zero-allocated memory}}
+ free(p);
+}
+
+void CheckUseZeroAllocated5() {
+ int *p = calloc(0, 2);
+ *p = 1; // expected-warning {{Use of zero-allocated memory}}
+ free(p);
+}
+
+void CheckUseZeroAllocated6() {
+ int *p = calloc(2, 0);
+ *p = 1; // expected-warning {{Use of zero-allocated memory}}
+ free(p);
+}
+
+void CheckUseZeroAllocated7() {
+ int *p = realloc(0, 0);
+ *p = 1; //TODO: warn about use of zero-allocated memory
+ free(p);
+}
+
+void CheckUseZeroAllocated8() {
+ int *p = malloc(8);
+ int *q = realloc(p, 0);
+ *q = 1; //TODO: warn about use of zero-allocated memory
+ free(q);
+}
+
+void CheckUseZeroAllocated9() {
+ int *p = realloc(0, 0);
+ int *q = realloc(p, 0);
+ *q = 1; //TODO: warn about use of zero-allocated memory
+ free(q);
+}
+
+void CheckUseZeroAllocatedPathNoWarn(_Bool b) {
+ int s = 0;
+ if (b)
+ s= 10;
+
+ char *p = malloc(s);
+
+ if (b)
+ *p = 1; // no warning
+
+ free(p);
+}
+
+void CheckUseZeroAllocatedPathWarn(_Bool b) {
+ int s = 10;
+ if (b)
+ s= 0;
+
+ char *p = malloc(s);
+
+ if (b)
+ *p = 1; // expected-warning {{Use of zero-allocated memory}}
+
+ free(p);
+}
// This case tests that storing malloc'ed memory to a static variable which is
// then returned is not leaked. In the absence of known contracts for functions
diff --git a/test/Analysis/properties.m b/test/Analysis/properties.m
index ca6f253..bf9424c 100644
--- a/test/Analysis/properties.m
+++ b/test/Analysis/properties.m
@@ -376,61 +376,61 @@
[_ownedProp retain];
[_ownedProp release];
[_ownedProp release];
- [_ownedProp release]; // expected-warning{{used after it is released}}
+ [_ownedProp release]; // FIXME-warning{{used after it is released}}
}
- (void)testOverreleaseUnownedIvar {
[_unownedProp retain];
[_unownedProp release];
- [_unownedProp release]; // expected-warning{{not owned at this point by the caller}}
+ [_unownedProp release]; // FIXME-warning{{not owned at this point by the caller}}
}
- (void)testOverreleaseIvarOnly {
[_ivarOnly retain];
[_ivarOnly release];
[_ivarOnly release];
- [_ivarOnly release]; // expected-warning{{used after it is released}}
+ [_ivarOnly release]; // FIXME-warning{{used after it is released}}
}
- (void)testOverreleaseReadonlyIvar {
[_readonlyProp retain];
[_readonlyProp release];
[_readonlyProp release];
- [_readonlyProp release]; // expected-warning{{used after it is released}}
+ [_readonlyProp release]; // FIXME-warning{{used after it is released}}
}
- (void)testOverreleaseImplicitManualIvar {
[_implicitManualProp retain];
[_implicitManualProp release];
[_implicitManualProp release];
- [_implicitManualProp release]; // expected-warning{{used after it is released}}
+ [_implicitManualProp release]; // FIXME-warning{{used after it is released}}
}
- (void)testOverreleaseImplicitSynthIvar {
[_implicitSynthProp retain];
[_implicitSynthProp release];
- [_implicitSynthProp release]; // expected-warning{{not owned at this point by the caller}}
+ [_implicitSynthProp release]; // FIXME-warning{{not owned at this point by the caller}}
}
- (void)testOverreleaseCF {
CFRetain(_cfProp);
CFRelease(_cfProp);
CFRelease(_cfProp);
- CFRelease(_cfProp); // expected-warning{{used after it is released}}
+ CFRelease(_cfProp); // FIXME-warning{{used after it is released}}
}
- (void)testOverreleaseOwnedIvarUse {
[_ownedProp retain];
[_ownedProp release];
[_ownedProp release];
- [_ownedProp myMethod]; // expected-warning{{used after it is released}}
+ [_ownedProp myMethod]; // FIXME-warning{{used after it is released}}
}
- (void)testOverreleaseIvarOnlyUse {
[_ivarOnly retain];
[_ivarOnly release];
[_ivarOnly release];
- [_ivarOnly myMethod]; // expected-warning{{used after it is released}}
+ [_ivarOnly myMethod]; // FIXME-warning{{used after it is released}}
}
- (void)testOverreleaseCFUse {
@@ -439,7 +439,7 @@
CFRelease(_cfProp);
extern void CFUse(CFTypeRef);
- CFUse(_cfProp); // expected-warning{{used after it is released}}
+ CFUse(_cfProp); // FIXME-warning{{used after it is released}}
}
- (void)testOverreleaseOwnedIvarAutoreleaseOkay {
@@ -459,14 +459,14 @@
[_ownedProp release];
[_ownedProp autorelease];
[_ownedProp autorelease];
-} // expected-warning{{Object autoreleased too many times}}
+} // FIXME-warning{{Object autoreleased too many times}}
- (void)testOverreleaseIvarOnlyAutorelease {
[_ivarOnly retain];
[_ivarOnly release];
[_ivarOnly autorelease];
[_ivarOnly autorelease];
-} // expected-warning{{Object autoreleased too many times}}
+} // FIXME-warning{{Object autoreleased too many times}}
- (void)testPropertyAccessThenReleaseOwned {
id owned = [self.ownedProp retain];
@@ -486,7 +486,7 @@
- (void)testPropertyAccessThenReleaseUnowned {
id unowned = [self.unownedProp retain];
[unowned release];
- [_unownedProp release]; // expected-warning{{not owned}}
+ [_unownedProp release]; // FIXME-warning{{not owned}}
}
- (void)testPropertyAccessThenReleaseUnowned2 {
@@ -494,7 +494,7 @@
id unowned = [self.unownedProp retain];
[unowned release];
clang_analyzer_eval(unowned == fromIvar); // expected-warning{{TRUE}}
- [fromIvar release]; // expected-warning{{not owned}}
+ [fromIvar release]; // FIXME-warning{{not owned}}
}
- (void)testPropertyAccessThenReleaseManual {
@@ -557,7 +557,7 @@
- (void)testPropertyAccessThenReleaseImplicitSynth {
id prop = [self.implicitSynthProp retain];
[prop release];
- [_implicitSynthProp release]; // expected-warning{{not owned}}
+ [_implicitSynthProp release]; // FIXME-warning{{not owned}}
}
- (void)testPropertyAccessThenReleaseImplicitSynth2 {
@@ -565,7 +565,7 @@
id prop = [self.implicitSynthProp retain];
[prop release];
clang_analyzer_eval(prop == fromIvar); // expected-warning{{TRUE}}
- [fromIvar release]; // expected-warning{{not owned}}
+ [fromIvar release]; // FIXME-warning{{not owned}}
}
- (id)getUnownedFromProperty {
@@ -671,6 +671,14 @@
}
}
+// rdar://problem/20335433
+- (void)retainIvarAndInvalidateSelf {
+ extern void invalidate(id);
+ [_unownedProp retain];
+ invalidate(self);
+ [_unownedProp release]; // no-warning
+}
+
@end
#endif // non-ARC
diff --git a/test/Analysis/retain-release-path-notes.m b/test/Analysis/retain-release-path-notes.m
index 23935b9..6b51305 100644
--- a/test/Analysis/retain-release-path-notes.m
+++ b/test/Analysis/retain-release-path-notes.m
@@ -282,48 +282,48 @@
}
- (void)testOverreleaseUnownedIvar {
- [_unownedProp retain]; // expected-note {{Object loaded from instance variable}}
- // expected-note@-1 {{Reference count incremented. The object now has a +1 retain count}}
- [_unownedProp release]; // expected-note {{Reference count decremented}}
- [_unownedProp release]; // expected-note {{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
- // expected-warning@-1 {{not owned at this point by the caller}}
+ [_unownedProp retain]; // FIXME-note {{Object loaded from instance variable}}
+ // FIXME-note@-1 {{Reference count incremented. The object now has a +1 retain count}}
+ [_unownedProp release]; // FIXME-note {{Reference count decremented}}
+ [_unownedProp release]; // FIXME-note {{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
+ // FIXME-warning@-1 {{not owned at this point by the caller}}
}
- (void)testOverreleaseOwnedIvarUse {
- [_ownedProp retain]; // expected-note {{Object loaded from instance variable}}
- // expected-note@-1 {{Reference count incremented. The object now has a +1 retain count}}
- [_ownedProp release]; // expected-note {{Reference count decremented}}
- [_ownedProp release]; // expected-note {{Strong instance variable relinquished. Object released}}
- [_ownedProp myMethod]; // expected-note {{Reference-counted object is used after it is released}}
- // expected-warning@-1 {{used after it is released}}
+ [_ownedProp retain]; // FIXME-note {{Object loaded from instance variable}}
+ // FIXME-note@-1 {{Reference count incremented. The object now has a +1 retain count}}
+ [_ownedProp release]; // FIXME-note {{Reference count decremented}}
+ [_ownedProp release]; // FIXME-note {{Strong instance variable relinquished. Object released}}
+ [_ownedProp myMethod]; // FIXME-note {{Reference-counted object is used after it is released}}
+ // FIXME-warning@-1 {{used after it is released}}
}
- (void)testOverreleaseIvarOnlyUse {
- [_ivarOnly retain]; // expected-note {{Object loaded from instance variable}}
- // expected-note@-1 {{Reference count incremented. The object now has a +1 retain count}}
- [_ivarOnly release]; // expected-note {{Reference count decremented}}
- [_ivarOnly release]; // expected-note {{Strong instance variable relinquished. Object released}}
- [_ivarOnly myMethod]; // expected-note {{Reference-counted object is used after it is released}}
- // expected-warning@-1 {{used after it is released}}
+ [_ivarOnly retain]; // FIXME-note {{Object loaded from instance variable}}
+ // FIXME-note@-1 {{Reference count incremented. The object now has a +1 retain count}}
+ [_ivarOnly release]; // FIXME-note {{Reference count decremented}}
+ [_ivarOnly release]; // FIXME-note {{Strong instance variable relinquished. Object released}}
+ [_ivarOnly myMethod]; // FIXME-note {{Reference-counted object is used after it is released}}
+ // FIXME-warning@-1 {{used after it is released}}
}
- (void)testOverreleaseOwnedIvarAutorelease {
- [_ownedProp retain]; // expected-note {{Object loaded from instance variable}}
- // expected-note@-1 {{Reference count incremented. The object now has a +1 retain count}}
- [_ownedProp release]; // expected-note {{Reference count decremented}}
- [_ownedProp autorelease]; // expected-note {{Object autoreleased}}
- [_ownedProp autorelease]; // expected-note {{Object autoreleased}}
- // expected-note@+1 {{Object was autoreleased 2 times but the object has a +0 retain count}}
-} // expected-warning{{Object autoreleased too many times}}
+ [_ownedProp retain]; // FIXME-note {{Object loaded from instance variable}}
+ // FIXME-note@-1 {{Reference count incremented. The object now has a +1 retain count}}
+ [_ownedProp release]; // FIXME-note {{Reference count decremented}}
+ [_ownedProp autorelease]; // FIXME-note {{Object autoreleased}}
+ [_ownedProp autorelease]; // FIXME-note {{Object autoreleased}}
+ // FIXME-note@+1 {{Object was autoreleased 2 times but the object has a +0 retain count}}
+} // FIXME-warning{{Object autoreleased too many times}}
- (void)testOverreleaseIvarOnlyAutorelease {
- [_ivarOnly retain]; // expected-note {{Object loaded from instance variable}}
- // expected-note@-1 {{Reference count incremented. The object now has a +1 retain count}}
- [_ivarOnly release]; // expected-note {{Reference count decremented}}
- [_ivarOnly autorelease]; // expected-note {{Object autoreleased}}
- [_ivarOnly autorelease]; // expected-note {{Object autoreleased}}
- // expected-note@+1 {{Object was autoreleased 2 times but the object has a +0 retain count}}
-} // expected-warning{{Object autoreleased too many times}}
+ [_ivarOnly retain]; // FIXME-note {{Object loaded from instance variable}}
+ // FIXME-note@-1 {{Reference count incremented. The object now has a +1 retain count}}
+ [_ivarOnly release]; // FIXME-note {{Reference count decremented}}
+ [_ivarOnly autorelease]; // FIXME-note {{Object autoreleased}}
+ [_ivarOnly autorelease]; // FIXME-note {{Object autoreleased}}
+ // FIXME-note@+1 {{Object was autoreleased 2 times but the object has a +0 retain count}}
+} // FIXME-warning{{Object autoreleased too many times}}
@end
@@ -6260,1894 +6260,4 @@
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>path</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>285</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>285</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>285</integer>
-// CHECK-NEXT: <key>col</key><integer>4</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>285</integer>
-// CHECK-NEXT: <key>col</key><integer>15</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>285</integer>
-// CHECK-NEXT: <key>col</key><integer>4</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>285</integer>
-// CHECK-NEXT: <key>col</key><integer>4</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>285</integer>
-// CHECK-NEXT: <key>col</key><integer>15</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Object loaded from instance variable</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Object loaded from instance variable</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>285</integer>
-// CHECK-NEXT: <key>col</key><integer>4</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>285</integer>
-// CHECK-NEXT: <key>col</key><integer>15</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>285</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>285</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>285</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>285</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>285</integer>
-// CHECK-NEXT: <key>col</key><integer>23</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>285</integer>
-// CHECK-NEXT: <key>col</key><integer>4</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>285</integer>
-// CHECK-NEXT: <key>col</key><integer>15</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Reference count incremented. The object now has a +1 retain count</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Reference count incremented. The object now has a +1 retain count</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>285</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>285</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>287</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>287</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>287</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>287</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>287</integer>
-// CHECK-NEXT: <key>col</key><integer>24</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>287</integer>
-// CHECK-NEXT: <key>col</key><integer>4</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>287</integer>
-// CHECK-NEXT: <key>col</key><integer>15</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Reference count decremented</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Reference count decremented</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>287</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>287</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>288</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>288</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>288</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>288</integer>
-// CHECK-NEXT: <key>col</key><integer>4</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>288</integer>
-// CHECK-NEXT: <key>col</key><integer>15</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Incorrect decrement of the reference count of an object that is not owned at this point by the caller</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Incorrect decrement of the reference count of an object that is not owned at this point by the caller</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>description</key><string>Incorrect decrement of the reference count of an object that is not owned at this point by the caller</string>
-// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
-// CHECK-NEXT: <key>type</key><string>Bad release</string>
-// CHECK-NEXT: <key>check_name</key><string>osx.cocoa.RetainCount</string>
-// CHECK-NEXT: <key>issue_context_kind</key><string>Objective-C method</string>
-// CHECK-NEXT: <key>issue_context</key><string>testOverreleaseUnownedIvar</string>
-// CHECK-NEXT: <key>issue_hash</key><string>4</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>288</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>path</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>293</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>293</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>293</integer>
-// CHECK-NEXT: <key>col</key><integer>4</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>293</integer>
-// CHECK-NEXT: <key>col</key><integer>13</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>293</integer>
-// CHECK-NEXT: <key>col</key><integer>4</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>293</integer>
-// CHECK-NEXT: <key>col</key><integer>4</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>293</integer>
-// CHECK-NEXT: <key>col</key><integer>13</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Object loaded from instance variable</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Object loaded from instance variable</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>293</integer>
-// CHECK-NEXT: <key>col</key><integer>4</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>293</integer>
-// CHECK-NEXT: <key>col</key><integer>13</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>293</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>293</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>293</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>293</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>293</integer>
-// CHECK-NEXT: <key>col</key><integer>21</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>293</integer>
-// CHECK-NEXT: <key>col</key><integer>4</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>293</integer>
-// CHECK-NEXT: <key>col</key><integer>13</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Reference count incremented. The object now has a +1 retain count</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Reference count incremented. The object now has a +1 retain count</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>293</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>293</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>295</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>295</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>295</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>295</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>295</integer>
-// CHECK-NEXT: <key>col</key><integer>22</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>295</integer>
-// CHECK-NEXT: <key>col</key><integer>4</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>295</integer>
-// CHECK-NEXT: <key>col</key><integer>13</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Reference count decremented</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Reference count decremented</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>295</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>295</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>296</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>296</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>296</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>296</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>296</integer>
-// CHECK-NEXT: <key>col</key><integer>22</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>296</integer>
-// CHECK-NEXT: <key>col</key><integer>4</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>296</integer>
-// CHECK-NEXT: <key>col</key><integer>13</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Strong instance variable relinquished. Object released</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Strong instance variable relinquished. Object released</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>296</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>296</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>297</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>297</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>297</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>297</integer>
-// CHECK-NEXT: <key>col</key><integer>4</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>297</integer>
-// CHECK-NEXT: <key>col</key><integer>13</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Reference-counted object is used after it is released</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Reference-counted object is used after it is released</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>description</key><string>Reference-counted object is used after it is released</string>
-// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
-// CHECK-NEXT: <key>type</key><string>Use-after-release</string>
-// CHECK-NEXT: <key>check_name</key><string>osx.cocoa.RetainCount</string>
-// CHECK-NEXT: <key>issue_context_kind</key><string>Objective-C method</string>
-// CHECK-NEXT: <key>issue_context</key><string>testOverreleaseOwnedIvarUse</string>
-// CHECK-NEXT: <key>issue_hash</key><string>5</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>297</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>path</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>302</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>302</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>302</integer>
-// CHECK-NEXT: <key>col</key><integer>4</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>302</integer>
-// CHECK-NEXT: <key>col</key><integer>12</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>302</integer>
-// CHECK-NEXT: <key>col</key><integer>4</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>302</integer>
-// CHECK-NEXT: <key>col</key><integer>4</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>302</integer>
-// CHECK-NEXT: <key>col</key><integer>12</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Object loaded from instance variable</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Object loaded from instance variable</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>302</integer>
-// CHECK-NEXT: <key>col</key><integer>4</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>302</integer>
-// CHECK-NEXT: <key>col</key><integer>12</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>302</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>302</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>302</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>302</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>302</integer>
-// CHECK-NEXT: <key>col</key><integer>20</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>302</integer>
-// CHECK-NEXT: <key>col</key><integer>4</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>302</integer>
-// CHECK-NEXT: <key>col</key><integer>12</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Reference count incremented. The object now has a +1 retain count</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Reference count incremented. The object now has a +1 retain count</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>302</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>302</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>304</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>304</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>304</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>304</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>304</integer>
-// CHECK-NEXT: <key>col</key><integer>21</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>304</integer>
-// CHECK-NEXT: <key>col</key><integer>4</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>304</integer>
-// CHECK-NEXT: <key>col</key><integer>12</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Reference count decremented</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Reference count decremented</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>304</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>304</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>305</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>305</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>305</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>305</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>305</integer>
-// CHECK-NEXT: <key>col</key><integer>21</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>305</integer>
-// CHECK-NEXT: <key>col</key><integer>4</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>305</integer>
-// CHECK-NEXT: <key>col</key><integer>12</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Strong instance variable relinquished. Object released</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Strong instance variable relinquished. Object released</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>305</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>305</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>306</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>306</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>306</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>306</integer>
-// CHECK-NEXT: <key>col</key><integer>4</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>306</integer>
-// CHECK-NEXT: <key>col</key><integer>12</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Reference-counted object is used after it is released</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Reference-counted object is used after it is released</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>description</key><string>Reference-counted object is used after it is released</string>
-// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
-// CHECK-NEXT: <key>type</key><string>Use-after-release</string>
-// CHECK-NEXT: <key>check_name</key><string>osx.cocoa.RetainCount</string>
-// CHECK-NEXT: <key>issue_context_kind</key><string>Objective-C method</string>
-// CHECK-NEXT: <key>issue_context</key><string>testOverreleaseIvarOnlyUse</string>
-// CHECK-NEXT: <key>issue_hash</key><string>5</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>306</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>path</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>311</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>311</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>311</integer>
-// CHECK-NEXT: <key>col</key><integer>4</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>311</integer>
-// CHECK-NEXT: <key>col</key><integer>13</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>311</integer>
-// CHECK-NEXT: <key>col</key><integer>4</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>311</integer>
-// CHECK-NEXT: <key>col</key><integer>4</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>311</integer>
-// CHECK-NEXT: <key>col</key><integer>13</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Object loaded from instance variable</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Object loaded from instance variable</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>311</integer>
-// CHECK-NEXT: <key>col</key><integer>4</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>311</integer>
-// CHECK-NEXT: <key>col</key><integer>13</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>311</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>311</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>311</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>311</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>311</integer>
-// CHECK-NEXT: <key>col</key><integer>21</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>311</integer>
-// CHECK-NEXT: <key>col</key><integer>4</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>311</integer>
-// CHECK-NEXT: <key>col</key><integer>13</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Reference count incremented. The object now has a +1 retain count</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Reference count incremented. The object now has a +1 retain count</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>311</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>311</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>313</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>313</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>313</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>313</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>313</integer>
-// CHECK-NEXT: <key>col</key><integer>22</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>313</integer>
-// CHECK-NEXT: <key>col</key><integer>4</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>313</integer>
-// CHECK-NEXT: <key>col</key><integer>13</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Reference count decremented</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Reference count decremented</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>313</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>313</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>314</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>314</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>314</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>314</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>314</integer>
-// CHECK-NEXT: <key>col</key><integer>26</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>314</integer>
-// CHECK-NEXT: <key>col</key><integer>4</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>314</integer>
-// CHECK-NEXT: <key>col</key><integer>13</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Object autoreleased</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Object autoreleased</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>314</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>314</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>315</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>315</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>315</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>315</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>315</integer>
-// CHECK-NEXT: <key>col</key><integer>26</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>315</integer>
-// CHECK-NEXT: <key>col</key><integer>4</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>315</integer>
-// CHECK-NEXT: <key>col</key><integer>13</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Object autoreleased</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Object autoreleased</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>315</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>315</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>317</integer>
-// CHECK-NEXT: <key>col</key><integer>1</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>317</integer>
-// CHECK-NEXT: <key>col</key><integer>1</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>317</integer>
-// CHECK-NEXT: <key>col</key><integer>1</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Object was autoreleased 2 times but the object has a +0 retain count</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Object was autoreleased 2 times but the object has a +0 retain count</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>description</key><string>Object autoreleased too many times</string>
-// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
-// CHECK-NEXT: <key>type</key><string>Object autoreleased too many times</string>
-// CHECK-NEXT: <key>check_name</key><string>osx.cocoa.RetainCount</string>
-// CHECK-NEXT: <key>issue_context_kind</key><string>Objective-C method</string>
-// CHECK-NEXT: <key>issue_context</key><string>testOverreleaseOwnedIvarAutorelease</string>
-// CHECK-NEXT: <key>issue_hash</key><string>7</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>317</integer>
-// CHECK-NEXT: <key>col</key><integer>1</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>path</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>320</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>320</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>320</integer>
-// CHECK-NEXT: <key>col</key><integer>4</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>320</integer>
-// CHECK-NEXT: <key>col</key><integer>12</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>320</integer>
-// CHECK-NEXT: <key>col</key><integer>4</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>320</integer>
-// CHECK-NEXT: <key>col</key><integer>4</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>320</integer>
-// CHECK-NEXT: <key>col</key><integer>12</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Object loaded from instance variable</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Object loaded from instance variable</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>320</integer>
-// CHECK-NEXT: <key>col</key><integer>4</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>320</integer>
-// CHECK-NEXT: <key>col</key><integer>12</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>320</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>320</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>320</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>320</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>320</integer>
-// CHECK-NEXT: <key>col</key><integer>20</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>320</integer>
-// CHECK-NEXT: <key>col</key><integer>4</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>320</integer>
-// CHECK-NEXT: <key>col</key><integer>12</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Reference count incremented. The object now has a +1 retain count</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Reference count incremented. The object now has a +1 retain count</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>320</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>320</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>322</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>322</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>322</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>322</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>322</integer>
-// CHECK-NEXT: <key>col</key><integer>21</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>322</integer>
-// CHECK-NEXT: <key>col</key><integer>4</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>322</integer>
-// CHECK-NEXT: <key>col</key><integer>12</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Reference count decremented</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Reference count decremented</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>322</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>322</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>323</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>323</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>323</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>323</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>323</integer>
-// CHECK-NEXT: <key>col</key><integer>25</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>323</integer>
-// CHECK-NEXT: <key>col</key><integer>4</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>323</integer>
-// CHECK-NEXT: <key>col</key><integer>12</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Object autoreleased</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Object autoreleased</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>323</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>323</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>324</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>324</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>324</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>324</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>324</integer>
-// CHECK-NEXT: <key>col</key><integer>25</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>324</integer>
-// CHECK-NEXT: <key>col</key><integer>4</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>324</integer>
-// CHECK-NEXT: <key>col</key><integer>12</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Object autoreleased</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Object autoreleased</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>324</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>324</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>326</integer>
-// CHECK-NEXT: <key>col</key><integer>1</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>326</integer>
-// CHECK-NEXT: <key>col</key><integer>1</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>326</integer>
-// CHECK-NEXT: <key>col</key><integer>1</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Object was autoreleased 2 times but the object has a +0 retain count</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Object was autoreleased 2 times but the object has a +0 retain count</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>description</key><string>Object autoreleased too many times</string>
-// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
-// CHECK-NEXT: <key>type</key><string>Object autoreleased too many times</string>
-// CHECK-NEXT: <key>check_name</key><string>osx.cocoa.RetainCount</string>
-// CHECK-NEXT: <key>issue_context_kind</key><string>Objective-C method</string>
-// CHECK-NEXT: <key>issue_context</key><string>testOverreleaseIvarOnlyAutorelease</string>
-// CHECK-NEXT: <key>issue_hash</key><string>7</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>326</integer>
-// CHECK-NEXT: <key>col</key><integer>1</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p3.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p3.cpp
index e03c216..11c17f3 100644
--- a/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p3.cpp
+++ b/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p3.cpp
@@ -14,3 +14,6 @@
void mem8(int (*fp)(int) = (int (*)(int = 17))0); // expected-error{{default arguments can only be specified for parameters in a function declaration}}
};
+
+template <typename... Ts>
+void defaultpack(Ts... = 0) {} // expected-error{{parameter pack cannot have a default argument}}
diff --git a/test/CXX/drs/dr3xx.cpp b/test/CXX/drs/dr3xx.cpp
index cea4d64..5ac4f01 100644
--- a/test/CXX/drs/dr3xx.cpp
+++ b/test/CXX/drs/dr3xx.cpp
@@ -170,9 +170,9 @@
void f() {
try {
throw D();
- } catch (const A&) {
+ } catch (const A&) { // expected-note {{for type 'const dr308::A &'}}
// unreachable
- } catch (const B&) {
+ } catch (const B&) { // expected-warning {{exception of type 'const dr308::B &' will be caught by earlier handler}}
// get here instead
}
}
diff --git a/test/CXX/drs/dr7xx.cpp b/test/CXX/drs/dr7xx.cpp
new file mode 100644
index 0000000..fe4a2dc
--- /dev/null
+++ b/test/CXX/drs/dr7xx.cpp
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -std=c++98 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++11 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++14 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++1z %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+
+namespace dr777 { // dr777: 3.7
+#if __cplusplus >= 201103L
+template <typename... T>
+void f(int i = 0, T ...args) {}
+void ff() { f(); }
+
+template <typename... T>
+void g(int i = 0, T ...args, T ...args2) {}
+
+template <typename... T>
+void h(int i = 0, T ...args, int j = 1) {}
+#endif
+}
+
+// expected-no-diagnostics
diff --git a/test/CXX/special/class.dtor/p10-0x.cpp b/test/CXX/special/class.dtor/p10-0x.cpp
index 029cbd6..3b8a0ad 100644
--- a/test/CXX/special/class.dtor/p10-0x.cpp
+++ b/test/CXX/special/class.dtor/p10-0x.cpp
@@ -27,9 +27,9 @@
y->~decltype(A())(); // expected-error{{use of undeclared identifier 'y'}}
typedef int *intp;
- i->~decltype(int())(); // expected-error{{member reference type 'int' is not a pointer; maybe you meant to use '.'?}}
+ i->~decltype(int())(); // expected-error{{member reference type 'int' is not a pointer; did you mean to use '.'?}}
i.~decltype(int())();
- i->~decltype(intp())(); // expected-error{{member reference type 'int' is not a pointer; maybe you meant to use '.'?}} \
+ i->~decltype(intp())(); // expected-error{{member reference type 'int' is not a pointer; did you mean to use '.'?}} \
expected-error{{the type of object expression ('int') does not match the type being destroyed ('decltype(intp())' (aka 'int *')) in pseudo-destructor expression}}
i.~decltype(intp())(); // expected-error{{the type of object expression ('int') does not match the type being destroyed ('decltype(intp())' (aka 'int *')) in pseudo-destructor expression}}
pi->~decltype(int())();
diff --git a/test/CXX/temp/temp.decls/temp.mem/p5.cpp b/test/CXX/temp/temp.decls/temp.mem/p5.cpp
index 8bcd773..1e061fa 100644
--- a/test/CXX/temp/temp.decls/temp.mem/p5.cpp
+++ b/test/CXX/temp/temp.decls/temp.mem/p5.cpp
@@ -55,8 +55,8 @@
// Partial ordering with conversion function templates.
struct X0 {
template<typename T> operator T*() {
- T x = 1;
- x = 17; // expected-error{{read-only variable is not assignable}}
+ T x = 1; // expected-note{{variable 'x' declared const here}}
+ x = 17; // expected-error{{cannot assign to variable 'x' with const-qualified type 'const int'}}
}
template<typename T> operator T*() const; // expected-note{{explicit instantiation refers here}}
diff --git a/test/CodeGen/2007-02-25-C-DotDotDot.c b/test/CodeGen/2007-02-25-C-DotDotDot.c
index 1c3a3df..ade052e 100644
--- a/test/CodeGen/2007-02-25-C-DotDotDot.c
+++ b/test/CodeGen/2007-02-25-C-DotDotDot.c
@@ -3,7 +3,7 @@
// Make sure the call to foo is compiled as:
// call float @foo()
// not
-// call float (...)* bitcast (float ()* @foo to float (...)*)( )
+// call float (...) bitcast (float ()* @foo to float (...)*)( )
static float foo() { return 0.0; }
// CHECK: call float @foo
diff --git a/test/CodeGen/2008-07-29-override-alias-decl.c b/test/CodeGen/2008-07-29-override-alias-decl.c
index 0c2d0c6..84fac34 100644
--- a/test/CodeGen/2008-07-29-override-alias-decl.c
+++ b/test/CodeGen/2008-07-29-override-alias-decl.c
@@ -14,6 +14,6 @@
return f();
}
-// CHECK: [[call:%.*]] = call i32 (...)* @f()
+// CHECK: [[call:%.*]] = call i32 (...) @f()
// CHECK: ret i32 [[call]]
diff --git a/test/CodeGen/arm-abi-vector.c b/test/CodeGen/arm-abi-vector.c
index 468acdf..88bf593 100644
--- a/test/CodeGen/arm-abi-vector.c
+++ b/test/CodeGen/arm-abi-vector.c
@@ -37,9 +37,9 @@
double test_2i(__int2 *in) {
// CHECK: test_2i
-// CHECK: call arm_aapcscc double (i32, ...)* @varargs_vec_2i(i32 3, <2 x i32> {{%.*}})
+// CHECK: call arm_aapcscc double (i32, ...) @varargs_vec_2i(i32 3, <2 x i32> {{%.*}})
// APCS-GNU: test_2i
-// APCS-GNU: call double (i32, ...)* @varargs_vec_2i(i32 3, <2 x i32> {{%.*}})
+// APCS-GNU: call double (i32, ...) @varargs_vec_2i(i32 3, <2 x i32> {{%.*}})
return varargs_vec_2i(3, *in);
}
@@ -63,9 +63,9 @@
double test_3c(__char3 *in) {
// CHECK: test_3c
-// CHECK: call arm_aapcscc double (i32, ...)* @varargs_vec_3c(i32 3, i32 {{%.*}})
+// CHECK: call arm_aapcscc double (i32, ...) @varargs_vec_3c(i32 3, i32 {{%.*}})
// APCS-GNU: test_3c
-// APCS-GNU: call double (i32, ...)* @varargs_vec_3c(i32 3, i32 {{%.*}})
+// APCS-GNU: call double (i32, ...) @varargs_vec_3c(i32 3, i32 {{%.*}})
return varargs_vec_3c(3, *in);
}
@@ -94,9 +94,9 @@
double test_5c(__char5 *in) {
// CHECK: test_5c
-// CHECK: call arm_aapcscc double (i32, ...)* @varargs_vec_5c(i32 5, <2 x i32> {{%.*}})
+// CHECK: call arm_aapcscc double (i32, ...) @varargs_vec_5c(i32 5, <2 x i32> {{%.*}})
// APCS-GNU: test_5c
-// APCS-GNU: call double (i32, ...)* @varargs_vec_5c(i32 5, <2 x i32> {{%.*}})
+// APCS-GNU: call double (i32, ...) @varargs_vec_5c(i32 5, <2 x i32> {{%.*}})
return varargs_vec_5c(5, *in);
}
@@ -128,9 +128,9 @@
double test_9c(__char9 *in) {
// CHECK: test_9c
-// CHECK: call arm_aapcscc double (i32, ...)* @varargs_vec_9c(i32 9, <4 x i32> {{%.*}})
+// CHECK: call arm_aapcscc double (i32, ...) @varargs_vec_9c(i32 9, <4 x i32> {{%.*}})
// APCS-GNU: test_9c
-// APCS-GNU: call double (i32, ...)* @varargs_vec_9c(i32 9, <4 x i32> {{%.*}})
+// APCS-GNU: call double (i32, ...) @varargs_vec_9c(i32 9, <4 x i32> {{%.*}})
return varargs_vec_9c(9, *in);
}
@@ -156,9 +156,9 @@
double test_19c(__char19 *in) {
// CHECK: test_19c
-// CHECK: call arm_aapcscc double (i32, ...)* @varargs_vec_19c(i32 19, <19 x i8>* {{%.*}})
+// CHECK: call arm_aapcscc double (i32, ...) @varargs_vec_19c(i32 19, <19 x i8>* {{%.*}})
// APCS-GNU: test_19c
-// APCS-GNU: call double (i32, ...)* @varargs_vec_19c(i32 19, <19 x i8>* {{%.*}})
+// APCS-GNU: call double (i32, ...) @varargs_vec_19c(i32 19, <19 x i8>* {{%.*}})
return varargs_vec_19c(19, *in);
}
@@ -187,9 +187,9 @@
double test_3s(__short3 *in) {
// CHECK: test_3s
-// CHECK: call arm_aapcscc double (i32, ...)* @varargs_vec_3s(i32 3, <2 x i32> {{%.*}})
+// CHECK: call arm_aapcscc double (i32, ...) @varargs_vec_3s(i32 3, <2 x i32> {{%.*}})
// APCS-GNU: test_3s
-// APCS-GNU: call double (i32, ...)* @varargs_vec_3s(i32 3, <2 x i32> {{%.*}})
+// APCS-GNU: call double (i32, ...) @varargs_vec_3s(i32 3, <2 x i32> {{%.*}})
return varargs_vec_3s(3, *in);
}
@@ -221,9 +221,9 @@
double test_5s(__short5 *in) {
// CHECK: test_5s
-// CHECK: call arm_aapcscc double (i32, ...)* @varargs_vec_5s(i32 5, <4 x i32> {{%.*}})
+// CHECK: call arm_aapcscc double (i32, ...) @varargs_vec_5s(i32 5, <4 x i32> {{%.*}})
// APCS-GNU: test_5s
-// APCS-GNU: call double (i32, ...)* @varargs_vec_5s(i32 5, <4 x i32> {{%.*}})
+// APCS-GNU: call double (i32, ...) @varargs_vec_5s(i32 5, <4 x i32> {{%.*}})
return varargs_vec_5s(5, *in);
}
@@ -256,8 +256,8 @@
double test_struct(StructWithVec* d) {
// CHECK: test_struct
-// CHECK: call arm_aapcscc double (i32, ...)* @varargs_struct(i32 3, [2 x i64] {{%.*}})
+// CHECK: call arm_aapcscc double (i32, ...) @varargs_struct(i32 3, [2 x i64] {{%.*}})
// APCS-GNU: test_struct
-// APCS-GNU: call double (i32, ...)* @varargs_struct(i32 3, [2 x i64] {{%.*}})
+// APCS-GNU: call double (i32, ...) @varargs_struct(i32 3, [2 x i64] {{%.*}})
return varargs_struct(3, *d);
}
diff --git a/test/CodeGen/arm-homogenous.c b/test/CodeGen/arm-homogenous.c
index 3426d99..42a9bc1 100644
--- a/test/CodeGen/arm-homogenous.c
+++ b/test/CodeGen/arm-homogenous.c
@@ -184,7 +184,7 @@
void test_struct_of_four_doubles_variadic(void) {
// CHECK: test_struct_of_four_doubles_variadic
-// CHECK: call arm_aapcs_vfpcc void (double, [4 x i64], [4 x i64], double, ...)* @takes_struct_of_four_doubles_variadic(double {{.*}}, [4 x i64] {{.*}}, [4 x i64] {{.*}}, double {{.*}})
+// CHECK: call arm_aapcs_vfpcc void (double, [4 x i64], [4 x i64], double, ...) @takes_struct_of_four_doubles_variadic(double {{.*}}, [4 x i64] {{.*}}, [4 x i64] {{.*}}, double {{.*}})
takes_struct_of_four_doubles_variadic(3.0, g_s4d, g_s4d, 4.0);
}
diff --git a/test/CodeGen/arm64-abi-vector.c b/test/CodeGen/arm64-abi-vector.c
index f4895c1..4566c41 100644
--- a/test/CodeGen/arm64-abi-vector.c
+++ b/test/CodeGen/arm64-abi-vector.c
@@ -29,7 +29,7 @@
double test_3c(__char3 *in) {
// CHECK: test_3c
-// CHECK: call double (i32, ...)* @varargs_vec_3c(i32 3, i32 {{%.*}})
+// CHECK: call double (i32, ...) @varargs_vec_3c(i32 3, i32 {{%.*}})
return varargs_vec_3c(3, *in);
}
@@ -49,7 +49,7 @@
double test_4c(__char4 *in) {
// CHECK: test_4c
-// CHECK: call double (i32, ...)* @varargs_vec_4c(i32 4, i32 {{%.*}})
+// CHECK: call double (i32, ...) @varargs_vec_4c(i32 4, i32 {{%.*}})
return varargs_vec_4c(4, *in);
}
@@ -69,7 +69,7 @@
double test_5c(__char5 *in) {
// CHECK: test_5c
-// CHECK: call double (i32, ...)* @varargs_vec_5c(i32 5, <2 x i32> {{%.*}})
+// CHECK: call double (i32, ...) @varargs_vec_5c(i32 5, <2 x i32> {{%.*}})
return varargs_vec_5c(5, *in);
}
@@ -91,7 +91,7 @@
double test_9c(__char9 *in) {
// CHECK: test_9c
-// CHECK: call double (i32, ...)* @varargs_vec_9c(i32 9, <4 x i32> {{%.*}})
+// CHECK: call double (i32, ...) @varargs_vec_9c(i32 9, <4 x i32> {{%.*}})
return varargs_vec_9c(9, *in);
}
@@ -112,7 +112,7 @@
double test_19c(__char19 *in) {
// CHECK: test_19c
-// CHECK: call double (i32, ...)* @varargs_vec_19c(i32 19, <19 x i8>* {{%.*}})
+// CHECK: call double (i32, ...) @varargs_vec_19c(i32 19, <19 x i8>* {{%.*}})
return varargs_vec_19c(19, *in);
}
@@ -132,7 +132,7 @@
double test_3s(__short3 *in) {
// CHECK: test_3s
-// CHECK: call double (i32, ...)* @varargs_vec_3s(i32 3, <2 x i32> {{%.*}})
+// CHECK: call double (i32, ...) @varargs_vec_3s(i32 3, <2 x i32> {{%.*}})
return varargs_vec_3s(3, *in);
}
@@ -154,7 +154,7 @@
double test_5s(__short5 *in) {
// CHECK: test_5s
-// CHECK: call double (i32, ...)* @varargs_vec_5s(i32 5, <4 x i32> {{%.*}})
+// CHECK: call double (i32, ...) @varargs_vec_5s(i32 5, <4 x i32> {{%.*}})
return varargs_vec_5s(5, *in);
}
@@ -176,7 +176,7 @@
double test_3i(__int3 *in) {
// CHECK: test_3i
-// CHECK: call double (i32, ...)* @varargs_vec_3i(i32 3, <4 x i32> {{%.*}})
+// CHECK: call double (i32, ...) @varargs_vec_3i(i32 3, <4 x i32> {{%.*}})
return varargs_vec_3i(3, *in);
}
@@ -198,7 +198,7 @@
double test_5i(__int5 *in) {
// CHECK: test_5i
-// CHECK: call double (i32, ...)* @varargs_vec_5i(i32 5, <5 x i32>* {{%.*}})
+// CHECK: call double (i32, ...) @varargs_vec_5i(i32 5, <5 x i32>* {{%.*}})
return varargs_vec_5i(5, *in);
}
@@ -220,7 +220,7 @@
double test_3d(__double3 *in) {
// CHECK: test_3d
-// CHECK: call double (i32, ...)* @varargs_vec_3d(i32 3, <3 x double>* {{%.*}})
+// CHECK: call double (i32, ...) @varargs_vec_3d(i32 3, <3 x double>* {{%.*}})
return varargs_vec_3d(3, *in);
}
@@ -285,7 +285,7 @@
__short3 *s3, __short5 *s5, __int3 *i3, __int5 *i5,
__double3 *d3) {
double ret = varargs_vec(3, *c3, *c5, *c9, *c19, *s3, *s5, *i3, *i5, *d3);
-// CHECK: call double (i32, ...)* @varargs_vec(i32 3, i32 {{%.*}}, <2 x i32> {{%.*}}, <4 x i32> {{%.*}}, <19 x i8>* {{%.*}}, <2 x i32> {{%.*}}, <4 x i32> {{%.*}}, <4 x i32> {{%.*}}, <5 x i32>* {{%.*}}, <3 x double>* {{%.*}})
+// CHECK: call double (i32, ...) @varargs_vec(i32 3, i32 {{%.*}}, <2 x i32> {{%.*}}, <4 x i32> {{%.*}}, <19 x i8>* {{%.*}}, <2 x i32> {{%.*}}, <4 x i32> {{%.*}}, <4 x i32> {{%.*}}, <5 x i32>* {{%.*}}, <3 x double>* {{%.*}})
return ret;
}
diff --git a/test/CodeGen/arm64-arguments.c b/test/CodeGen/arm64-arguments.c
index 5c56fd4..c276350 100644
--- a/test/CodeGen/arm64-arguments.c
+++ b/test/CodeGen/arm64-arguments.c
@@ -641,7 +641,7 @@
float test_hfa_call(struct HFA *a) {
// CHECK-LABEL: define float @test_hfa_call(%struct.HFA* %a)
-// CHECK: call float (i32, ...)* @test_hfa(i32 1, [4 x float] {{.*}})
+// CHECK: call float (i32, ...) @test_hfa(i32 1, [4 x float] {{.*}})
test_hfa(1, *a);
}
diff --git a/test/CodeGen/avx512f-builtins.c b/test/CodeGen/avx512f-builtins.c
index 89f8a53..340beb8 100644
--- a/test/CodeGen/avx512f-builtins.c
+++ b/test/CodeGen/avx512f-builtins.c
@@ -633,3 +633,112 @@
// CHECK: @llvm.x86.avx512.mask.ucmp.q.512(<8 x i64> {{.*}}, <8 x i64> {{.*}}, i8 3, i8 {{.*}})
return (__mmask8)_mm512_mask_cmp_epu64_mask(__u, __a, __b, 3);
}
+
+__m512i test_mm512_mask_and_epi32(__m512i __src,__mmask16 __k, __m512i __a, __m512i __b) {
+ // CHECK-LABEL: @test_mm512_mask_and_epi32
+ // CHECK: @llvm.x86.avx512.mask.pand.d.512
+ return _mm512_mask_and_epi32(__src, __k,__a, __b);
+}
+
+__m512i test_mm512_maskz_and_epi32(__mmask16 __k, __m512i __a, __m512i __b) {
+ // CHECK-LABEL: @test_mm512_maskz_and_epi32
+ // CHECK: @llvm.x86.avx512.mask.pand.d.512
+ return _mm512_maskz_and_epi32(__k,__a, __b);
+}
+
+__m512i test_mm512_mask_and_epi64(__m512i __src,__mmask8 __k, __m512i __a, __m512i __b) {
+ // CHECK-LABEL: @test_mm512_mask_and_epi64
+ // CHECK: @llvm.x86.avx512.mask.pand.q.512
+ return _mm512_mask_and_epi64(__src, __k,__a, __b);
+}
+
+__m512i test_mm512_maskz_and_epi64(__mmask8 __k, __m512i __a, __m512i __b) {
+ // CHECK-LABEL: @test_mm512_maskz_and_epi64
+ // CHECK: @llvm.x86.avx512.mask.pand.q.512
+ return _mm512_maskz_and_epi64(__k,__a, __b);
+}
+
+__m512i test_mm512_mask_or_epi32(__m512i __src,__mmask16 __k, __m512i __a, __m512i __b) {
+ // CHECK-LABEL: @test_mm512_mask_or_epi32
+ // CHECK: @llvm.x86.avx512.mask.por.d.512
+ return _mm512_mask_or_epi32(__src, __k,__a, __b);
+}
+
+__m512i test_mm512_maskz_or_epi32(__mmask16 __k, __m512i __a, __m512i __b) {
+ // CHECK-LABEL: @test_mm512_maskz_or_epi32
+ // CHECK: @llvm.x86.avx512.mask.por.d.512
+ return _mm512_maskz_or_epi32(__k,__a, __b);
+}
+
+__m512i test_mm512_mask_or_epi64(__m512i __src,__mmask8 __k, __m512i __a, __m512i __b) {
+ // CHECK-LABEL: @test_mm512_mask_or_epi64
+ // CHECK: @llvm.x86.avx512.mask.por.q.512
+ return _mm512_mask_or_epi64(__src, __k,__a, __b);
+}
+
+__m512i test_mm512_maskz_or_epi64(__mmask8 __k, __m512i __a, __m512i __b) {
+ // CHECK-LABEL: @test_mm512_maskz_or_epi64
+ // CHECK: @llvm.x86.avx512.mask.por.q.512
+ return _mm512_maskz_or_epi64(__k,__a, __b);
+}
+
+__m512i test_mm512_mask_xor_epi32(__m512i __src,__mmask16 __k, __m512i __a, __m512i __b) {
+ // CHECK-LABEL: @test_mm512_mask_xor_epi32
+ // CHECK: @llvm.x86.avx512.mask.pxor.d.512
+ return _mm512_mask_xor_epi32(__src, __k,__a, __b);
+}
+
+__m512i test_mm512_maskz_xor_epi32(__mmask16 __k, __m512i __a, __m512i __b) {
+ // CHECK-LABEL: @test_mm512_maskz_xor_epi32
+ // CHECK: @llvm.x86.avx512.mask.pxor.d.512
+ return _mm512_maskz_xor_epi32(__k,__a, __b);
+}
+
+__m512i test_mm512_mask_xor_epi64(__m512i __src,__mmask8 __k, __m512i __a, __m512i __b) {
+ // CHECK-LABEL: @test_mm512_mask_xor_epi64
+ // CHECK: @llvm.x86.avx512.mask.pxor.q.512
+ return _mm512_mask_xor_epi64(__src, __k,__a, __b);
+}
+
+__m512i test_mm512_maskz_xor_epi64(__mmask8 __k, __m512i __a, __m512i __b) {
+ // CHECK-LABEL: @test_mm512_maskz_xor_epi64
+ // CHECK: @llvm.x86.avx512.mask.pxor.q.512
+ return _mm512_maskz_xor_epi64(__k,__a, __b);
+}
+
+__m512i test_mm512_and_epi32(__m512i __src,__mmask16 __k, __m512i __a, __m512i __b) {
+ // CHECK-LABEL: @test_mm512_and_epi32
+ // CHECK: and <8 x i64>
+ return _mm512_and_epi32(__a, __b);
+}
+
+__m512i test_mm512_and_epi64(__m512i __src,__mmask8 __k, __m512i __a, __m512i __b) {
+ // CHECK-LABEL: @test_mm512_and_epi64
+ // CHECK: and <8 x i64>
+ return _mm512_and_epi64(__a, __b);
+}
+
+__m512i test_mm512_or_epi32(__m512i __src,__mmask16 __k, __m512i __a, __m512i __b) {
+ // CHECK-LABEL: @test_mm512_or_epi32
+ // CHECK: or <8 x i64>
+ return _mm512_or_epi32(__a, __b);
+}
+
+__m512i test_mm512_or_epi64(__m512i __src,__mmask8 __k, __m512i __a, __m512i __b) {
+ // CHECK-LABEL: @test_mm512_or_epi64
+ // CHECK: or <8 x i64>
+ return _mm512_or_epi64(__a, __b);
+}
+
+__m512i test_mm512_xor_epi32(__m512i __src,__mmask16 __k, __m512i __a, __m512i __b) {
+ // CHECK-LABEL: @test_mm512_xor_epi32
+ // CHECK: xor <8 x i64>
+ return _mm512_xor_epi32(__a, __b);
+}
+
+__m512i test_mm512_xor_epi64(__m512i __src,__mmask8 __k, __m512i __a, __m512i __b) {
+ // CHECK-LABEL: @test_mm512_xor_epi64
+ // CHECK: xor <8 x i64>
+ return _mm512_xor_epi64(__a, __b);
+}
+
diff --git a/test/CodeGen/blocks-seq.c b/test/CodeGen/blocks-seq.c
index a7851d6..b3e6729 100644
--- a/test/CodeGen/blocks-seq.c
+++ b/test/CodeGen/blocks-seq.c
@@ -1,9 +1,9 @@
// RUN: %clang_cc1 -fblocks -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
// CHECK: [[Vi:%.+]] = alloca %struct.__block_byref_i, align 8
-// CHECK: call i32 (...)* @rhs()
+// CHECK: call i32 (...) @rhs()
// CHECK: [[V7:%.+]] = getelementptr inbounds %struct.__block_byref_i, %struct.__block_byref_i* [[Vi]], i32 0, i32 1
// CHECK: load %struct.__block_byref_i*, %struct.__block_byref_i** [[V7]]
-// CHECK: call i32 (...)* @rhs()
+// CHECK: call i32 (...) @rhs()
// CHECK: [[V11:%.+]] = getelementptr inbounds %struct.__block_byref_i, %struct.__block_byref_i* [[Vi]], i32 0, i32 1
// CHECK: load %struct.__block_byref_i*, %struct.__block_byref_i** [[V11]]
diff --git a/test/CodeGen/builtin-assume.c b/test/CodeGen/builtin-assume.c
index 8f83f17..19afec6 100644
--- a/test/CodeGen/builtin-assume.c
+++ b/test/CodeGen/builtin-assume.c
@@ -1,25 +1,44 @@
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck %s
// RUN: %clang_cc1 -triple i386-mingw32 -fms-extensions -emit-llvm -o - %s | FileCheck %s
+int nonconst(void);
+int isconst(void) __attribute__((const));
+int ispure(void) __attribute__((pure));
+
// CHECK-LABEL: @test1
int test1(int *a, int i) {
// CHECK: store i32* %a, i32** [[A_ADDR:%.+]], align
// CHECK: [[A:%.+]] = load i32*, i32** [[A_ADDR]]
// CHECK: [[CMP:%.+]] = icmp ne i32* [[A]], null
// CHECK: call void @llvm.assume(i1 [[CMP]])
+
+// CHECK: [[CALL:%.+]] = call i32 @isconst()
+// CHECK: [[BOOL:%.+]] = icmp ne i32 [[CALL]], 0
+// CHECK: call void @llvm.assume(i1 [[BOOL]])
+
+// CHECK: [[CALLPURE:%.+]] = call i32 @ispure()
+// CHECK: [[BOOLPURE:%.+]] = icmp ne i32 [[CALLPURE]], 0
+// CHECK: call void @llvm.assume(i1 [[BOOLPURE]])
#ifdef _MSC_VER
__assume(a != 0)
+ __assume(isconst());
+ __assume(ispure());
#else
__builtin_assume(a != 0);
+ __builtin_assume(isconst());
+ __builtin_assume(ispure());
#endif
// Nothing is generated for an assume with side effects...
// CHECK-NOT: load i32*, i32** %i.addr
// CHECK-NOT: call void @llvm.assume
+// CHECK-NOT: call i32 @nonconst()
#ifdef _MSC_VER
__assume(++i != 0)
+ __assume(nonconst());
#else
__builtin_assume(++i != 0);
+ __builtin_assume(nonconst());
#endif
return a[0];
diff --git a/test/CodeGen/builtin-expect.c b/test/CodeGen/builtin-expect.c
index 21c3ade..884110c 100644
--- a/test/CodeGen/builtin-expect.c
+++ b/test/CodeGen/builtin-expect.c
@@ -23,9 +23,9 @@
// CHECK-LABEL: define i32 @main()
// CHECK: call void @isigprocmask()
-// CHECK: [[C:%.*]] = call i64 (...)* @bar()
+// CHECK: [[C:%.*]] = call i64 (...) @bar()
// CHECK_O0: call void @isigprocmask()
-// CHECK_O0: [[C:%.*]] = call i64 (...)* @bar()
+// CHECK_O0: [[C:%.*]] = call i64 (...) @bar()
// CHECK_O0-NOT: call i64 @llvm.expect
diff --git a/test/CodeGen/builtins-ppc-crypto-diag.c b/test/CodeGen/builtins-ppc-crypto-diag.c
deleted file mode 100644
index 4408ab4..0000000
--- a/test/CodeGen/builtins-ppc-crypto-diag.c
+++ /dev/null
@@ -1,47 +0,0 @@
-// REQUIRES: powerpc-registered-target
-// RUN: not %clang_cc1 -faltivec -triple powerpc64le-unknown-unknown -D_T1LW -target-feature +crypto -emit-llvm %s -o - 2>&1 | FileCheck %s -check-prefix=CHECK-T1
-// RUN: not %clang_cc1 -faltivec -triple powerpc64le-unknown-unknown -D_T1MW -target-feature +crypto -emit-llvm %s -o - 2>&1 | FileCheck %s -check-prefix=CHECK-T1
-// RUN: not %clang_cc1 -faltivec -triple powerpc64le-unknown-unknown -D_T2LW -target-feature +crypto -emit-llvm %s -o - 2>&1 | FileCheck %s -check-prefix=CHECK-T2
-// RUN: not %clang_cc1 -faltivec -triple powerpc64le-unknown-unknown -D_T2MW -target-feature +crypto -emit-llvm %s -o - 2>&1 | FileCheck %s -check-prefix=CHECK-T2
-// RUN: not %clang_cc1 -faltivec -triple powerpc64le-unknown-unknown -D_T1LD -target-feature +crypto -emit-llvm %s -o - 2>&1 | FileCheck %s -check-prefix=CHECK-T1
-// RUN: not %clang_cc1 -faltivec -triple powerpc64le-unknown-unknown -D_T1MD -target-feature +crypto -emit-llvm %s -o - 2>&1 | FileCheck %s -check-prefix=CHECK-T1
-// RUN: not %clang_cc1 -faltivec -triple powerpc64le-unknown-unknown -D_T2LD -target-feature +crypto -emit-llvm %s -o - 2>&1 | FileCheck %s -check-prefix=CHECK-T2
-// RUN: not %clang_cc1 -faltivec -triple powerpc64le-unknown-unknown -D_T2MD -target-feature +crypto -emit-llvm %s -o - 2>&1 | FileCheck %s -check-prefix=CHECK-T2
-#include <altivec.h>
-
-#define W_INIT { 0x01020304, 0x05060708, \
- 0x090A0B0C, 0x0D0E0F10 };
-#define D_INIT { 0x0102030405060708, \
- 0x090A0B0C0D0E0F10 };
-vector unsigned int test_vshasigmaw_or(void)
-{
- vector unsigned int a = W_INIT
-#ifdef _T1LW // Arg1 too large
- vector unsigned int b = __builtin_crypto_vshasigmaw(a, 2, 15);
-#elif defined(_T1MW) // Arg1 negative
- vector unsigned int c = __builtin_crypto_vshasigmaw(a, -1, 15);
-#elif defined(_T2LW) // Arg2 too large
- vector unsigned int d = __builtin_crypto_vshasigmaw(a, 0, 85);
-#elif defined(_T2MW) // Arg1 negative
- vector unsigned int e = __builtin_crypto_vshasigmaw(a, 1, -15);
-#endif
- return __builtin_crypto_vshasigmaw(a, 1, 15);
-}
-
-vector unsigned long long test_vshasigmad_or(void)
-{
- vector unsigned long long a = D_INIT
-#ifdef _T1LD // Arg1 too large
- vector unsigned long long b = __builtin_crypto_vshasigmad(a, 2, 15);
-#elif defined(_T1MD) // Arg1 negative
- vector unsigned long long c = __builtin_crypto_vshasigmad(a, -1, 15);
-#elif defined(_T2LD) // Arg2 too large
- vector unsigned long long d = __builtin_crypto_vshasigmad(a, 0, 85);
-#elif defined(_T2MD) // Arg1 negative
- vector unsigned long long e = __builtin_crypto_vshasigmad(a, 1, -15);
-#endif
- return __builtin_crypto_vshasigmad(a, 0, 15);
-}
-
-// CHECK-T1: error: argument out of range (should be 0-1).
-// CHECK-T2: error: argument out of range (should be 0-15).
diff --git a/test/CodeGen/builtins-ppc-p7-disabled.c b/test/CodeGen/builtins-ppc-p7-disabled.c
new file mode 100644
index 0000000..9ccedd2
--- /dev/null
+++ b/test/CodeGen/builtins-ppc-p7-disabled.c
@@ -0,0 +1,33 @@
+// REQUIRES: powerpc-registered-target
+// RUN: not %clang_cc1 -triple powerpc64-unknown-unknown \
+// RUN: -target-cpu pwr6 -emit-llvm %s -o - 2>&1 \
+// RUN: | FileCheck %s
+
+// RUN: not %clang_cc1 -triple powerpc-unknown-unknown -emit-llvm %s -o - 2>&1 \
+// RUN: -target-cpu pwr7 | FileCheck %s -check-prefix=CHECK-32
+
+void call_p7_builtins(void)
+{
+ int a = __builtin_divwe(33, 11);
+ unsigned int b = __builtin_divweu(33U, 11U);
+ unsigned long long d = __builtin_divde(33ULL, 11ULL);
+ unsigned long long e = __builtin_divdeu(33ULL, 11ULL);
+ unsigned long long f = __builtin_bpermd(33ULL, 11ULL);
+}
+
+// CHECK: error: this builtin is only valid on POWER7 or later CPUs
+// CHECK: __builtin_divwe
+// CHECK: error: this builtin is only valid on POWER7 or later CPUs
+// CHECK: __builtin_divweu
+// CHECK: error: this builtin is only valid on POWER7 or later CPUs
+// CHECK: __builtin_divde
+// CHECK: error: this builtin is only valid on POWER7 or later CPUs
+// CHECK: __builtin_divdeu
+// CHECK: error: this builtin is only valid on POWER7 or later CPUs
+// CHECK: __builtin_bpermd
+// CHECK-32: error: this builtin is only available on 64-bit targets
+// CHECK-32: __builtin_divde
+// CHECK-32: error: this builtin is only available on 64-bit targets
+// CHECK-32: __builtin_divdeu
+// CHECK-32: error: this builtin is only available on 64-bit targets
+// CHECK-32: __builtin_bpermd
diff --git a/test/CodeGen/builtins-ppc-p7.c b/test/CodeGen/builtins-ppc-p7.c
new file mode 100644
index 0000000..f584410
--- /dev/null
+++ b/test/CodeGen/builtins-ppc-p7.c
@@ -0,0 +1,52 @@
+// REQUIRES: powerpc-registered-target
+// RUN: %clang_cc1 -triple powerpc64-unknown-unknown -target-cpu pwr7 \
+// RUN: -emit-llvm %s -o - | FileCheck %s
+
+// RUN: %clang_cc1 -triple powerpc64le-unknown-unknown -target-cpu pwr8 \
+// RUN: -emit-llvm %s -o - | FileCheck %s
+
+// CHECK-LABEL: define signext i32 @test_divwe
+int test_divwe(void)
+{
+ int a = 74;
+ int b = 32;
+ return __builtin_divwe(a, b);
+// CHECK @llvm.ppc.divwe
+}
+
+// CHECK-LABEL: define zeroext i32 @test_divweu
+unsigned int test_divweu(void)
+{
+ unsigned int a = 74;
+ unsigned int b = 32;
+ return __builtin_divweu(a, b);
+// CHECK @llvm.ppc.divweu
+}
+
+// CHECK-LABEL: define i64 @test_divde
+long long test_divde(void)
+{
+ long long a = 74LL;
+ long long b = 32LL;
+ return __builtin_divde(a, b);
+// CHECK @llvm.ppc.divde
+}
+
+// CHECK-LABEL: define i64 @test_divdeu
+unsigned long long test_divdeu(void)
+{
+ unsigned long long a = 74ULL;
+ unsigned long long b = 32ULL;
+ return __builtin_divdeu(a, b);
+// CHECK @llvm.ppc.divdeu
+}
+
+// CHECK-LABEL: define i64 @test_bpermd
+long long test_bpermd(void)
+{
+ long long a = 74LL;
+ long long b = 32LL;
+ return __builtin_bpermd(a, b);
+// CHECK @llvm.ppc.bpermd
+}
+
diff --git a/test/CodeGen/builtins-systemz-error.c b/test/CodeGen/builtins-systemz-error.c
new file mode 100644
index 0000000..73431b0
--- /dev/null
+++ b/test/CodeGen/builtins-systemz-error.c
@@ -0,0 +1,9 @@
+// REQUIRES: systemz-registered-target
+// RUN: %clang_cc1 -target-cpu zEC12 -triple s390x-unknown-unknown \
+// RUN: -Wall -Wno-unused -Werror -fsyntax-only -verify %s
+
+void test1(void) {
+ __builtin_tabort (0); // expected-error {{invalid transaction abort code}}
+ __builtin_tabort (255); // expected-error {{invalid transaction abort code}}
+}
+
diff --git a/test/CodeGen/builtins-systemz.c b/test/CodeGen/builtins-systemz.c
new file mode 100644
index 0000000..f5de700
--- /dev/null
+++ b/test/CodeGen/builtins-systemz.c
@@ -0,0 +1,144 @@
+// REQUIRES: systemz-registered-target
+// RUN: %clang_cc1 -target-cpu zEC12 -triple s390x-ibm-linux -Wall -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -target-cpu zEC12 -triple s390x-ibm-linux -Wall -Wno-unused -Werror -emit-llvm -x c++ %s -o - | FileCheck %s
+
+#include <stdint.h>
+#include <htmintrin.h>
+
+int global = 0;
+uint64_t g;
+struct __htm_tdb global_tdb;
+
+void test_htm1(struct __htm_tdb *tdb, int reg, int *mem, uint64_t *mem64) {
+// CHECK-LABEL: test_htm1
+
+ __builtin_tbegin ((void *)0);
+// CHECK: call i32 @llvm.s390.tbegin(i8* null, i32 65292)
+ __builtin_tbegin ((void *)0x12345678);
+// CHECK: call i32 @llvm.s390.tbegin(i8* inttoptr (i64 305419896 to i8*), i32 65292)
+ __builtin_tbegin (tdb);
+// CHECK: call i32 @llvm.s390.tbegin(i8* %{{.*}}, i32 65292)
+ __builtin_tbegin (&global_tdb);
+// CHECK: call i32 @llvm.s390.tbegin(i8* getelementptr inbounds (%struct.__htm_tdb, %struct.__htm_tdb* @global_tdb, i32 0, i32 0), i32 65292)
+
+ __builtin_tbegin_nofloat ((void *)0);
+// CHECK: call i32 @llvm.s390.tbegin.nofloat(i8* null, i32 65292)
+ __builtin_tbegin_nofloat ((void *)0x12345678);
+// CHECK: call i32 @llvm.s390.tbegin.nofloat(i8* inttoptr (i64 305419896 to i8*), i32 65292)
+ __builtin_tbegin_nofloat (tdb);
+// CHECK: call i32 @llvm.s390.tbegin.nofloat(i8* %{{.*}}, i32 65292)
+ __builtin_tbegin_nofloat (&global_tdb);
+// CHECK: call i32 @llvm.s390.tbegin.nofloat(i8* getelementptr inbounds (%struct.__htm_tdb, %struct.__htm_tdb* @global_tdb, i32 0, i32 0), i32 65292)
+
+ __builtin_tbegin_retry ((void *)0, 6);
+// CHECK: call i32 @llvm.s390.tbegin(i8* null, i32 65292)
+// CHECK: call void @llvm.s390.ppa.txassist(i32 %{{.*}})
+ __builtin_tbegin_retry ((void *)0x12345678, 6);
+// CHECK: call i32 @llvm.s390.tbegin(i8* %{{.*}}, i32 65292)
+// CHECK: call void @llvm.s390.ppa.txassist(i32 %{{.*}})
+ __builtin_tbegin_retry (tdb, 6);
+// CHECK: call i32 @llvm.s390.tbegin(i8* %{{.*}}, i32 65292)
+// CHECK: call void @llvm.s390.ppa.txassist(i32 %{{.*}})
+ __builtin_tbegin_retry (&global_tdb, 6);
+// CHECK: call i32 @llvm.s390.tbegin(i8* %{{.*}}, i32 65292)
+// CHECK: call void @llvm.s390.ppa.txassist(i32 %{{.*}})
+
+ __builtin_tbegin_retry_nofloat ((void *)0, 6);
+// CHECK: call i32 @llvm.s390.tbegin.nofloat(i8* null, i32 65292)
+// CHECK: call void @llvm.s390.ppa.txassist(i32 %{{.*}})
+ __builtin_tbegin_retry_nofloat ((void *)0x12345678, 6);
+// CHECK: call i32 @llvm.s390.tbegin.nofloat(i8* %{{.*}}, i32 65292)
+// CHECK: call void @llvm.s390.ppa.txassist(i32 %{{.*}})
+ __builtin_tbegin_retry_nofloat (tdb, 6);
+// CHECK: call i32 @llvm.s390.tbegin.nofloat(i8* %{{.*}}, i32 65292)
+// CHECK: call void @llvm.s390.ppa.txassist(i32 %{{.*}})
+ __builtin_tbegin_retry_nofloat (&global_tdb, 6);
+// CHECK: call i32 @llvm.s390.tbegin.nofloat(i8* %{{.*}}, i32 65292)
+// CHECK: call void @llvm.s390.ppa.txassist(i32 %{{.*}})
+
+ __builtin_tbeginc ();
+// CHECK: call void @llvm.s390.tbeginc(i8* null, i32 65288)
+
+ __builtin_tabort (256);
+// CHECK: call void @llvm.s390.tabort(i64 256)
+ __builtin_tabort (-1);
+// CHECK: call void @llvm.s390.tabort(i64 -1)
+ __builtin_tabort (reg);
+// CHECK: call void @llvm.s390.tabort(i64 %{{.*}})
+
+ __builtin_tend();
+// CHECK: call i32 @llvm.s390.tend()
+
+ int n = __builtin_tx_nesting_depth();
+// CHECK: call i32 @llvm.s390.etnd()
+
+ __builtin_non_tx_store (mem64, 0);
+// CHECK: call void @llvm.s390.ntstg(i64 0, i64* %{{.*}})
+ const uint64_t val_var = 0x1122334455667788;
+ __builtin_non_tx_store (mem64, val_var);
+// CHECK: call void @llvm.s390.ntstg(i64 1234605616436508552, i64* %{{.*}})
+ __builtin_non_tx_store (mem64, (uint64_t)reg);
+// CHECK: call void @llvm.s390.ntstg(i64 %{{.*}}, i64* %{{.*}})
+ __builtin_non_tx_store (mem64, g);
+// CHECK: call void @llvm.s390.ntstg(i64 %{{.*}}, i64* %{{.*}})
+ __builtin_non_tx_store ((uint64_t *)0, 0);
+// CHECK: call void @llvm.s390.ntstg(i64 0, i64* null)
+ __builtin_non_tx_store ((uint64_t *)0x12345678, 0);
+// CHECK: call void @llvm.s390.ntstg(i64 0, i64* inttoptr (i64 305419896 to i64*))
+ __builtin_non_tx_store (&g, 23);
+// CHECK: call void @llvm.s390.ntstg(i64 23, i64* @g)
+ __builtin_non_tx_store (&g, reg);
+// CHECK: call void @llvm.s390.ntstg(i64 %{{.*}}, i64* @g)
+ __builtin_non_tx_store (&g, *mem);
+// CHECK: call void @llvm.s390.ntstg(i64 %{{.*}}, i64* @g)
+ __builtin_non_tx_store (&g, global);
+// CHECK: call void @llvm.s390.ntstg(i64 %{{.*}}, i64* @g)
+
+ __builtin_tx_assist (0);
+// CHECK: call void @llvm.s390.ppa.txassist(i32 0)
+ __builtin_tx_assist (1);
+// CHECK: call void @llvm.s390.ppa.txassist(i32 1)
+ __builtin_tx_assist (reg);
+// CHECK: call void @llvm.s390.ppa.txassist(i32 %{{.*}})
+ __builtin_tx_assist (*mem);
+// CHECK: call void @llvm.s390.ppa.txassist(i32 %{{.*}})
+ __builtin_tx_assist (global);
+// CHECK: call void @llvm.s390.ppa.txassist(i32 %{{.*}})
+}
+
+#include <htmxlintrin.h>
+
+void test_htmxl1(void) {
+// CHECK-LABEL: test_htmxl1
+
+ struct __htm_tdb tdb_struct;
+ void * const tdb = &tdb_struct;
+ long result;
+ unsigned char code;
+
+ result = __TM_simple_begin ();
+// CHECK: call i32 @llvm.s390.tbegin.nofloat(i8* null, i32 65292)
+ result = __TM_begin (tdb);
+// CHECK: call i32 @llvm.s390.tbegin.nofloat(i8* %{{.*}}, i32 65292)
+ result = __TM_end ();
+// CHECK: call i32 @llvm.s390.tend()
+ __TM_abort ();
+// CHECK: call void @llvm.s390.tabort(i64 256)
+ __TM_named_abort (42);
+// CHECK: call void @llvm.s390.tabort(i64 %{{.*}})
+ __TM_non_transactional_store (&g, 42);
+// CHECK: call void @llvm.s390.ntstg(i64 %{{.*}}, i64* %{{.*}})
+ result = __TM_nesting_depth (tdb);
+// CHECK: call i32 @llvm.s390.etnd()
+
+ result = __TM_is_user_abort (tdb);
+ result = __TM_is_named_user_abort (tdb, &code);
+ result = __TM_is_illegal (tdb);
+ result = __TM_is_footprint_exceeded (tdb);
+ result = __TM_is_nested_too_deep (tdb);
+ result = __TM_is_conflict (tdb);
+ result = __TM_is_failure_persistent (result);
+ result = __TM_failure_address (tdb);
+ result = __TM_failure_code (tdb);
+}
+
diff --git a/test/CodeGen/call.c b/test/CodeGen/call.c
index ef32775..7239111 100644
--- a/test/CodeGen/call.c
+++ b/test/CodeGen/call.c
@@ -18,7 +18,7 @@
void Interpret() {
JS_ReportErrorNumber(js_GetErrorMessage, 0);
- // CHECK: call void ({{.*}}, ...)* @JS_ReportErrorNumber({{.*}}@js_GetErrorMessage
+ // CHECK: call void ({{.*}}, ...) @JS_ReportErrorNumber({{.*}}@js_GetErrorMessage
}
diff --git a/test/CodeGen/catch-undef-behavior.c b/test/CodeGen/catch-undef-behavior.c
index 1ed288b..a438658 100644
--- a/test/CodeGen/catch-undef-behavior.c
+++ b/test/CodeGen/catch-undef-behavior.c
@@ -380,7 +380,7 @@
// CHECK-UBSAN: call void @__ubsan_handle_nonnull_arg
// CHECK-UBSAN-NOT: __ubsan_handle_nonnull_arg
- // CHECK-COMMON: call void (i32, ...)* @nonnull_variadic
+ // CHECK-COMMON: call void (i32, ...) @nonnull_variadic
nonnull_variadic(a, b);
}
diff --git a/test/CodeGen/exceptions-seh-finally.c b/test/CodeGen/exceptions-seh-finally.c
index eeadf0d..a594aaa 100644
--- a/test/CodeGen/exceptions-seh-finally.c
+++ b/test/CodeGen/exceptions-seh-finally.c
@@ -17,30 +17,20 @@
// CHECK: to label %[[invoke_cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
//
// CHECK: [[invoke_cont]]
-// CHECK: store i8 0, i8* %[[abnormal:[^ ]*]]
-// CHECK: br label %[[finally:[^ ]*]]
-//
-// CHECK: [[finally]]
-// CHECK: call void @cleanup()
-// CHECK: load i8, i8* %[[abnormal]]
-// CHECK: icmp eq
-// CHECK: br i1 %{{.*}}, label %[[finallycont:[^ ]*]], label %[[resumecont:[^ ]*]]
-//
-// CHECK: [[finallycont]]
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: call void @"\01?fin$0@0@basic_finally@@"(i1 zeroext false, i8* %[[fp]])
// CHECK-NEXT: ret void
//
// CHECK: [[lpad]]
// CHECK-NEXT: landingpad
// CHECK-NEXT: cleanup
-// CHECK: store i8 1, i8* %[[abnormal]]
-// CHECK: br label %[[finally]]
-//
-// CHECK: [[resumecont]]
-// CHECK: br label %[[ehresume:[^ ]*]]
-//
-// CHECK: [[ehresume]]
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: call void @"\01?fin$0@0@basic_finally@@"(i1 zeroext true, i8* %[[fp]])
// CHECK: resume { i8*, i32 }
+// CHECK: define internal void @"\01?fin$0@0@basic_finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)
+// CHECK: call void @cleanup()
+
// Mostly check that we don't double emit 'r' which would crash.
void decl_in_finally(void) {
__try {
@@ -67,10 +57,11 @@
// CHECK: to label %[[invoke_cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
//
// CHECK: [[invoke_cont]]
-// CHECK: store i8 0, i8* %[[abnormal:[^ ]*]]
-// CHECK: br label %[[finally:[^ ]*]]
-//
-// CHECK: [[finally]]
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: call void @"\01?fin$0@0@label_in_finally@@"(i1 zeroext false, i8* %[[fp]])
+// CHECK: ret void
+
+// CHECK: define internal void @"\01?fin$0@0@label_in_finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)
// CHECK: br label %[[l:[^ ]*]]
//
// CHECK: [[l]]
@@ -93,32 +84,22 @@
// CHECK: to label %[[invoke_cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
//
// CHECK: [[invoke_cont]]
-// CHECK: store i8 0, i8* %[[abnormal:[^ ]*]]
-// CHECK: br label %[[finally:[^ ]*]]
-//
-// CHECK: [[finally]]
-// CHECK: load i8, i8* %[[abnormal]]
-// CHECK: zext i8 %{{.*}} to i32
-// CHECK: store i32 %{{.*}}, i32* @crashed
-// CHECK: load i8, i8* %[[abnormal]]
-// CHECK: icmp eq
-// CHECK: br i1 %{{.*}}, label %[[finallycont:[^ ]*]], label %[[resumecont:[^ ]*]]
-//
-// CHECK: [[finallycont]]
-// CHECK-NEXT: ret void
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: call void @"\01?fin$0@0@use_abnormal_termination@@"(i1 zeroext false, i8* %[[fp]])
+// CHECK: ret void
//
// CHECK: [[lpad]]
// CHECK-NEXT: landingpad
// CHECK-NEXT: cleanup
-// CHECK: store i8 1, i8* %[[abnormal]]
-// CHECK: br label %[[finally]]
-//
-// CHECK: [[resumecont]]
-// CHECK: br label %[[ehresume:[^ ]*]]
-//
-// CHECK: [[ehresume]]
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: call void @"\01?fin$0@0@use_abnormal_termination@@"(i1 zeroext true, i8* %[[fp]])
// CHECK: resume { i8*, i32 }
+// CHECK: define internal void @"\01?fin$0@0@use_abnormal_termination@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)
+// CHECK: %[[abnormal_zext:[^ ]*]] = zext i1 %abnormal_termination to i32
+// CHECK: store i32 %[[abnormal_zext]], i32* @crashed
+// CHECK-NEXT: ret void
+
void noreturn_noop_finally() {
__try {
__noop();
@@ -128,12 +109,13 @@
}
// CHECK-LABEL: define void @noreturn_noop_finally()
-// CHECK: store i8 0, i8* %
-// CHECK: br label %[[finally:[^ ]*]]
-// CHECK: [[finally]]
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: call void @"\01?fin$0@0@noreturn_noop_finally@@"(i1 zeroext false, i8* %[[fp]])
+// CHECK: ret void
+
+// CHECK: define internal void @"\01?fin$0@0@noreturn_noop_finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)
// CHECK: call void @abort()
-// CHECK-NEXT: unreachable
-// CHECK-NOT: load
+// CHECK: unreachable
void noreturn_finally() {
__try {
@@ -148,18 +130,20 @@
// CHECK: to label %[[cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
//
// CHECK: [[cont]]
-// CHECK: store i8 0, i8* %
-// CHECK: br label %[[finally:[^ ]*]]
-//
-// CHECK: [[finally]]
-// CHECK: call void @abort()
-// CHECK-NEXT: unreachable
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: call void @"\01?fin$0@0@noreturn_finally@@"(i1 zeroext false, i8* %[[fp]])
+// CHECK: ret void
//
// CHECK: [[lpad]]
// CHECK: landingpad
// CHECK-NEXT: cleanup
-// CHECK: store i8 1, i8* %
-// CHECK: br label %[[finally]]
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: call void @"\01?fin$0@0@noreturn_finally@@"(i1 zeroext true, i8* %[[fp]])
+// CHECK: resume { i8*, i32 }
+
+// CHECK: define internal void @"\01?fin$0@0@noreturn_finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)
+// CHECK: call void @abort()
+// CHECK: unreachable
int finally_with_return() {
__try {
@@ -168,15 +152,15 @@
}
}
// CHECK-LABEL: define i32 @finally_with_return()
-// CHECK: store i8 0, i8* %
-// CHECK-NEXT: br label %[[finally:[^ ]*]]
-//
-// CHECK: [[finally]]
-// CHECK-NEXT: br label %[[finallycont:[^ ]*]]
-//
-// CHECK: [[finallycont]]
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK-NEXT: call void @"\01?fin$0@0@finally_with_return@@"(i1 zeroext false, i8* %[[fp]])
// CHECK-NEXT: ret i32 42
+// CHECK: define internal void @"\01?fin$0@0@finally_with_return@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)
+// CHECK-NOT: br i1
+// CHECK-NOT: br label
+// CHECK: ret void
+
int nested___finally___finally() {
__try {
__try {
@@ -188,38 +172,28 @@
}
return 0;
}
+
// CHECK-LABEL: define i32 @nested___finally___finally
-// CHECK: store i8 0, i8* %
-// CHECK-NEXT: br label %[[finally:[^ ]*]]
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: invoke void @"\01?fin$1@0@nested___finally___finally@@"(i1 zeroext false, i8* %[[fp]])
+// CHECK: to label %[[outercont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
//
-// CHECK: [[finally]]
-// CHECK-NEXT: store i32 1, i32* %
-// CHECK-NEXT: store i32 1, i32* %
-// CHECK-NEXT: br label %[[cleanup:[^ ]*]]
+// CHECK: [[outercont]]
+// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK-NEXT: call void @"\01?fin$0@0@nested___finally___finally@@"(i1 zeroext false, i8* %[[fp]])
+// CHECK-NEXT: ret i32 0
//
-// The finally's unreachable continuation block:
-// CHECK: store i32 0, i32* %
-// CHECK-NEXT: br label %[[cleanup]]
-//
-// CHECK: [[cleanup]]
-// CHECK-NEXT: store i8 0, i8* %
-// CHECK-NEXT: br label %[[outerfinally:[^ ]*]]
-//
-// CHECK: [[outerfinally]]
-// CHECK-NEXT: br label %[[finallycont:[^ ]*]]
-//
-// CHECK: [[finallycont]]
-// CHECK-NEXT: %[[dest:[^ ]*]] = load i32, i32* %
-// CHECK-NEXT: switch i32 %[[dest]]
-// CHECK-NEXT: i32 0, label %[[cleanupcont:[^ ]*]]
-//
-// CHECK: [[cleanupcont]]
-// CHECK-NEXT: store i32 0, i32* %
-// CHECK-NEXT: br label %[[return:[^ ]*]]
-//
-// CHECK: [[return]]
-// CHECK-NEXT: %[[reg:[^ ]*]] = load i32, i32* %
-// CHECK-NEXT: ret i32 %[[reg]]
+// CHECK: [[lpad]]
+// CHECK-NEXT: landingpad
+// CHECK-NEXT: cleanup
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK-NEXT: call void @"\01?fin$0@0@nested___finally___finally@@"(i1 zeroext true, i8* %[[fp]])
+
+// CHECK-LABEL: define internal void @"\01?fin$0@0@nested___finally___finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)
+// CHECK: ret void
+
+// CHECK-LABEL: define internal void @"\01?fin$1@0@nested___finally___finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)
+// CHECK: unreachable
int nested___finally___finally_with_eh_edge() {
__try {
@@ -234,58 +208,35 @@
return 912;
}
// CHECK-LABEL: define i32 @nested___finally___finally_with_eh_edge
-// CHECK: invoke void @might_crash() #3
-// CHECK-NEXT: to label %[[invokecont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
+// CHECK: invoke void @might_crash()
+// CHECK-NEXT: to label %[[invokecont:[^ ]*]] unwind label %[[lpad1:[^ ]*]]
//
-// CHECK: [[invokecont]]
-// CHECK-NEXT: store i8 0, i8* %[[abnormal:[^ ]*]]
-// CHECK-NEXT: br label %[[finally:[^ ]*]]
-
-// CHECK: [[finally]]
-// CHECK-NEXT: store i32 899, i32* %
-// CHECK-NEXT: store i32 1, i32* %
-// CHECK-NEXT: br label %[[cleanup:[^ ]*]]
+// [[invokecont]]
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: invoke void @"\01?fin$1@0@nested___finally___finally_with_eh_edge@@"(i1 zeroext false, i8* %[[fp]])
+// CHECK: to label %[[outercont:[^ ]*]] unwind label %[[lpad2:[^ ]*]]
//
-// The inner finally's unreachable continuation block:
-// CHECK: store i32 0, i32* %
-// CHECK-NEXT: br label %[[cleanup]]
+// CHECK: [[outercont]]
+// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK-NEXT: call void @"\01?fin$0@0@nested___finally___finally_with_eh_edge@@"(i1 zeroext false, i8* %[[fp]])
+// CHECK-NEXT: ret i32 912
//
-// CHECK: [[cleanup]]
-// CHECK-NEXT: store i8 0, i8* %
-// CHECK-NEXT: br label %[[outerfinally:[^ ]*]]
-//
-// CHECK: [[outerfinally]]
-// CHECK-NEXT: %[[abnormallocal:[^ ]*]] = load i8, i8* %[[abnormal]]
-// CHECK-NEXT: %[[reg:[^ ]*]] = icmp eq i8 %[[abnormallocal]], 0
-// CHECK-NEXT: br i1 %[[reg]], label %[[finallycont:[^ ]*]], label %[[finallyresume:[^ ]*]]
-//
-// CHECK: [[finallycont]]
-// CHECK-NEXT: %[[dest:[^ ]*]] = load i32, i32* %
-// CHECK-NEXT: switch i32 %[[dest]]
-// CHECK-NEXT: i32 0, label %[[cleanupcont:[^ ]*]]
-//
-// CHECK: [[cleanupcont]]
-// CHECK-NEXT: store i32 912, i32* %
-// CHECK-NEXT: br label %[[return:[^ ]*]]
-//
-//
-// CHECK: [[lpad]]
+// CHECK: [[lpad1]]
// CHECK-NEXT: landingpad
// CHECK-NEXT: cleanup
-// CHECK: store i8 1, i8* %[[abnormal]]
-// CHECK: br label %[[finally]]
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: invoke void @"\01?fin$1@0@nested___finally___finally_with_eh_edge@@"(i1 zeroext true, i8* %[[fp]])
+// CHECK: to label %[[outercont:[^ ]*]] unwind label %[[lpad2]]
//
-// The inner finally's unreachable resume block:
-// CHECK: store i8 1, i8* %[[abnormal]]
-// CHECK-NEXT: br label %[[outerfinally]]
-//
-// CHECK: [[finallyresume]]
-// CHECK-NEXT: br label %[[ehresume:[^ ]*]]
-//
-// CHECK: [[return]]
-// CHECK-NEXT: %[[reg:[^ ]*]] = load i32, i32* %
-// CHECK-NEXT: ret i32 %[[reg]]
-//
-// The ehresume block, not reachable either.
-// CHECK: [[ehresume]]
+// CHECK: [[lpad2]]
+// CHECK-NEXT: landingpad
+// CHECK-NEXT: cleanup
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: call void @"\01?fin$0@0@nested___finally___finally_with_eh_edge@@"(i1 zeroext true, i8* %[[fp]])
// CHECK: resume
+
+// CHECK-LABEL: define internal void @"\01?fin$0@0@nested___finally___finally_with_eh_edge@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)
+// CHECK: ret void
+
+// CHECK-LABEL: define internal void @"\01?fin$1@0@nested___finally___finally_with_eh_edge@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)
+// CHECK: unreachable
diff --git a/test/CodeGen/exceptions-seh-leave.c b/test/CodeGen/exceptions-seh-leave.c
index 0d38439..793501a 100644
--- a/test/CodeGen/exceptions-seh-leave.c
+++ b/test/CodeGen/exceptions-seh-leave.c
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 %s -triple x86_64-pc-win32 -fms-extensions -emit-llvm -o - | FileCheck %s
-void g();
+void g(void);
//////////////////////////////////////////////////////////////////////////////
// __leave with __except
@@ -38,7 +38,7 @@
return 1;
}
// CHECK-LABEL: define i32 @__leave_with___except()
-// CHECK: invoke void bitcast (void (...)* @g to void ()*)()
+// CHECK: invoke void @g()
// CHECK-NEXT: to label %[[cont:.*]] unwind label %{{.*}}
// For __excepts, instead of an explicit __try.__leave label, we could use
// use invoke.cont as __leave jump target instead. However, not doing this
@@ -74,8 +74,8 @@
// CHECK-NEXT: br label %[[tryleave:[^ ]*]]
// CHECK-NOT: store i32 23
// CHECK: [[tryleave]]
-// CHECK-NEXT: store i8 0, i8* %
-// CHECK-NEXT: br label %
+// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK-NEXT: call void @"\01?fin$0@0@__leave_with___finally_simple@@"(i1 zeroext false, i8* %[[fp]])
// __finally block doesn't return, __finally.cont doesn't exist.
int __leave_with___finally_noreturn() {
@@ -94,8 +94,8 @@
// CHECK-NEXT: br label %[[tryleave:[^ ]*]]
// CHECK-NOT: store i32 23
// CHECK: [[tryleave]]
-// CHECK-NEXT: store i8 0, i8* %
-// CHECK-NEXT: br label %
+// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK-NEXT: call void @"\01?fin$0@0@__leave_with___finally_noreturn@@"(i1 zeroext false, i8* %[[fp]])
// The "normal" case.
int __leave_with___finally() {
@@ -110,7 +110,7 @@
return 1;
}
// CHECK-LABEL: define i32 @__leave_with___finally()
-// CHECK: invoke void bitcast (void (...)* @g to void ()*)()
+// CHECK: invoke void @g()
// CHECK-NEXT: to label %[[cont:.*]] unwind label %{{.*}}
// For __finally, there needs to be an explicit __try.__leave, because
// abnormal.termination.slot needs to be set there.
@@ -118,8 +118,8 @@
// CHECK-NEXT: br label %[[tryleave:[^ ]*]]
// CHECK-NOT: store i32 23
// CHECK: [[tryleave]]
-// CHECK-NEXT: store i8 0, i8* %
-// CHECK-NEXT: br label %
+// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK-NEXT: call void @"\01?fin$0@0@__leave_with___finally@@"(i1 zeroext false, i8* %[[fp]])
//////////////////////////////////////////////////////////////////////////////
@@ -142,45 +142,37 @@
}
return 1;
}
-// The order of basic blocks in the below doesn't matter.
// CHECK-LABEL: define i32 @nested___except___finally()
-// CHECK-LABEL: invoke void bitcast (void (...)* @g to void ()*)()
-// CHECK-NEXT: to label %[[g1_cont:.*]] unwind label %[[g1_lpad:.*]]
+// CHECK-LABEL: invoke void @g()
+// CHECK-NEXT: to label %[[g1_cont1:.*]] unwind label %[[g1_lpad:.*]]
-// CHECK: [[g1_cont]]
-// CHECK-NEXT: store i8 0, i8* %[[abnormal:[^ ]*]]
-// CHECK-NEXT: br label %[[finally:[^ ]*]]
+// CHECK: [[g1_cont1]]
+// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK-NEXT: invoke void @"\01?fin$0@0@nested___except___finally@@"(i1 zeroext false, i8* %[[fp]])
+// CHECK-NEXT: to label %[[fin_cont:.*]] unwind label %[[g2_lpad:.*]]
-// CHECK: [[finally]]
-// CHECK-NEXT: invoke void bitcast (void (...)* @g to void ()*)()
-// CHECK-NEXT: to label %[[g2_cont:.*]] unwind label %[[g2_lpad:.*]]
-
-// CHECK: [[g2_cont]]
-// CHECK-NEXT: br label %[[tryleave:[^ ]*]]
-// CHECK-NOT: store i32 23
-
-// Unused __finally continuation block
+// CHECK: [[fin_cont]]
// CHECK: store i32 51, i32* %
-// CHECK-NEXT: br label %[[tryleave]]
-
-// CHECK: [[tryleave]]
// CHECK-NEXT: br label %[[trycont:[^ ]*]]
// CHECK: [[g1_lpad]]
-// CHECK: store i8 1, i8* %
-// CHECK-NEXT: br label %[[finally]]
+// CHECK-NEXT: landingpad
+// CHECK-NEXT: catch i8* null
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK-NEXT: invoke void @"\01?fin$0@0@nested___except___finally@@"(i1 zeroext true, i8* %[[fp]])
+// CHECK-NEXT: to label %[[g1_resume:.*]] unwind label %[[g2_lpad]]
// CHECK: [[g2_lpad]]
-// CHECK-NOT: %[[abnormal]]
-// CHECK: br label %[[except:[^ ]*]]
-
-// CHECK: [[except]]
-// CHECK-NEXT: br label %[[trycont]]
+// CHECK: br label %[[trycont]]
// CHECK: [[trycont]]
// CHECK-NEXT: ret i32 1
+// CHECK-LABEL: define internal void @"\01?fin$0@0@nested___except___finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)
+// CHECK: call void @g()
+// CHECK: unreachable
+
int nested___except___except() {
int myres = 0;
__try {
@@ -202,7 +194,7 @@
// The order of basic blocks in the below doesn't matter.
// CHECK-LABEL: define i32 @nested___except___except()
-// CHECK-LABEL: invoke void bitcast (void (...)* @g to void ()*)()
+// CHECK-LABEL: invoke void @g()
// CHECK-NEXT: to label %[[g1_cont:.*]] unwind label %[[g1_lpad:.*]]
// CHECK: [[g1_cont]]
@@ -213,7 +205,7 @@
// CHECK: br label %[[except:[^ ]*]]
// CHECK: [[except]]
-// CHECK-NEXT: invoke void bitcast (void (...)* @g to void ()*)() #3
+// CHECK-NEXT: invoke void @g()
// CHECK-NEXT: to label %[[g2_cont:.*]] unwind label %[[g2_lpad:.*]]
// CHECK: [[g2_cont]]
@@ -256,7 +248,7 @@
// The order of basic blocks in the below doesn't matter.
// CHECK-LABEL: define i32 @nested___finally___except()
-// CHECK-LABEL: invoke void bitcast (void (...)* @g to void ()*)()
+// CHECK-LABEL: invoke void @g()
// CHECK-NEXT: to label %[[g1_cont:.*]] unwind label %[[g1_lpad:.*]]
// CHECK: [[g1_cont]]
@@ -266,7 +258,7 @@
// CHECK: br label %[[except:[^ ]*]]
// CHECK: [[except]]
-// CHECK-NEXT: invoke void bitcast (void (...)* @g to void ()*)()
+// CHECK-NEXT: invoke void @g()
// CHECK-NEXT: to label %[[g2_cont:.*]] unwind label %[[g2_lpad:.*]]
// CHECK: [[g2_cont]]
@@ -274,31 +266,25 @@
// CHECK-NOT: 23
// CHECK: [[g2_lpad]]
-// CHECK: store i8 1, i8* %[[abnormal:[^ ]*]]
-// CHECK-NEXT: br label %[[finally:[^ ]*]]
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK-NEXT: call void @"\01?fin$0@0@nested___finally___except@@"(i1 zeroext true, i8* %[[fp]])
+// CHECK-NEXT: br label %[[ehresume:[^ ]*]]
// CHECK: [[trycont]]
// CHECK: store i32 51, i32* %
// CHECK-NEXT: br label %[[tryleave]]
// CHECK: [[tryleave]]
-// CHECK-NEXT: store i8 0, i8* %[[abnormal]]
-// CHECK-NEXT: br label %[[finally:[^ ]*]]
-
-// CHECK: [[finally]]
-// CHECK-NEXT: %[[abnormallocal:[^ ]*]] = load i8, i8* %[[abnormal]]
-// CHECK-NEXT: %[[reg:[^ ]*]] = icmp eq i8 %[[abnormallocal]], 0
-// CHECK-NEXT: br i1 %[[reg]], label %[[finallycont:[^ ]*]], label %[[finallyresume:[^ ]*]]
-
-// CHECK: [[finallycont]]
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK-NEXT: call void @"\01?fin$0@0@nested___finally___except@@"(i1 zeroext false, i8* %[[fp]])
// CHECK-NEXT: ret i32 1
-// CHECK: [[finallyresume]]
-// CHECK-NEXT: br label %[[ehresume:[^ ]*]]
-
// CHECK: [[ehresume]]
// CHECK: resume
+// CHECK-LABEL: define internal void @"\01?fin$0@0@nested___finally___except@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)
+// CHECK: ret void
+
int nested___finally___finally() {
int myres = 0;
__try {
@@ -320,51 +306,44 @@
// The order of basic blocks in the below doesn't matter.
// CHECK-LABEL: define i32 @nested___finally___finally()
-// CHECK-LABEL: invoke void bitcast (void (...)* @g to void ()*)()
+// CHECK-LABEL: invoke void @g()
// CHECK-NEXT: to label %[[g1_cont:.*]] unwind label %[[g1_lpad:.*]]
// CHECK: [[g1_cont]]
// CHECK: store i32 16, i32* %[[myres:[^ ]*]],
-// CHECK: store i8 0, i8* %[[abnormal:[^ ]*]]
-// CHECK-NEXT: br label %[[finally:[^ ]*]]
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK-NEXT: invoke void @"\01?fin$1@0@nested___finally___finally@@"(i1 zeroext false, i8* %[[fp]])
+// CHECK-NEXT: to label %[[finally_cont:.*]] unwind label %[[g2_lpad:.*]]
-// CHECK: [[finally]]
-// CHECK-NEXT: invoke void bitcast (void (...)* @g to void ()*)() #3
-// CHECK-NEXT: to label %[[g2_cont:.*]] unwind label %[[g2_lpad:.*]]
-
-// CHECK: [[g2_cont]]
-// CHECK-NEXT: br label %[[tryleave:[^ ]*]]
-// CHECK-NOT: store i32 23
-
-// There's an unreachable block for the skipped `myres = 51`.
+// CHECK: [[finally_cont]]
// CHECK: store i32 51, i32* %[[myres]]
-// CHECK-NEXT: br label %[[tryleave]]
-
-// CHECK: [[tryleave]]
-// CHECK-NEXT: store i8 0, i8* %[[abnormal]]
-// CHECK-NEXT: br label %[[outerfinally:[^ ]*]]
-
-// CHECK: [[outerfinally]]
-// CHECK-NEXT: %[[abnormallocal:[^ ]*]] = load i8, i8* %[[abnormal]]
-// CHECK-NEXT: %[[reg:[^ ]*]] = icmp eq i8 %[[abnormallocal]], 0
-// CHECK-NEXT: br i1 %[[reg]], label %[[finallycont:[^ ]*]], label %[[finallyresume:[^ ]*]]
-
-// CHECK: [[finallycont]]
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK-NEXT: call void @"\01?fin$0@0@nested___finally___finally@@"(i1 zeroext false, i8* %[[fp]])
// CHECK-NEXT: ret i32 1
// CHECK: [[g1_lpad]]
-// CHECK: store i8 1, i8* %[[abnormal]]
-// CHECK-NEXT: br label %[[finally:[^ ]*]]
+// CHECK-NEXT: landingpad
+// CHECK-NEXT: cleanup
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK-NEXT: invoke void @"\01?fin$1@0@nested___finally___finally@@"(i1 zeroext true, i8* %[[fp]])
+// CHECK-NEXT: to label %[[finally_cont2:.*]] unwind label %[[g2_lpad]]
// CHECK: [[g2_lpad]]
-// CHECK: br label %[[ehcleanup:[^ ]*]]
+// CHECK-NEXT: landingpad
+// CHECK-NEXT: cleanup
+// CHECK: br label %[[ehcleanup:.*]]
+
+// CHECK: [[finally_cont2]]
+// CHECK: br label %[[ehcleanup]]
// CHECK: [[ehcleanup]]
-// CHECK-NEXT: store i8 1, i8* %[[abnormal]]
-// CHECK-NEXT: br label %[[outerfinally]]
-
-// CHECK: [[finallyresume]]
-// CHECK-NEXT: br label %[[ehresume:[^ ]*]]
-
-// CHECK: [[ehresume]]
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK-NEXT: call void @"\01?fin$0@0@nested___finally___finally@@"(i1 zeroext true, i8* %[[fp]])
// CHECK: resume
+
+// CHECK-LABEL: define internal void @"\01?fin$0@0@nested___finally___finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)
+// CHECK: ret void
+
+// CHECK-LABEL: define internal void @"\01?fin$1@0@nested___finally___finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)
+// CHECK: call void @g()
+// CHECK: unreachable
diff --git a/test/CodeGen/exceptions-seh.c b/test/CodeGen/exceptions-seh.c
index 2d9d4b1..9a273ce 100644
--- a/test/CodeGen/exceptions-seh.c
+++ b/test/CodeGen/exceptions-seh.c
@@ -118,8 +118,6 @@
// CHECK: [[inner_try_cont]]
// CHECK: br label %[[outer_try_cont]]
-// FIXME: This lowering of __finally can't actually work, it will have to
-// change.
static unsigned g = 0;
void basic_finally(void) {
++g;
@@ -138,24 +136,23 @@
// CHECK: to label %[[cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
//
// CHECK: [[cont]]
-// CHECK: br label %[[finally:[^ ]*]]
-//
-// CHECK: [[finally]]
-// CHECK: load i32, i32* @g
-// CHECK: add i32 %{{.*}}, -1
-// CHECK: store i32 %{{.*}}, i32* @g
-// CHECK: icmp eq
-// CHECK: br i1 %{{.*}}, label
-//
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: call void @"\01?fin$0@0@basic_finally@@"(i1 zeroext false, i8* %[[fp]])
// CHECK: ret void
//
// CHECK: [[lpad]]
// CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*)
// CHECK-NEXT: cleanup
-// CHECK: br label %[[finally]]
-//
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: call void @"\01?fin$0@0@basic_finally@@"(i1 zeroext true, i8* %[[fp]])
// CHECK: resume
+// CHECK: define internal void @"\01?fin$0@0@basic_finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)
+// CHECK: load i32, i32* @g, align 4
+// CHECK: add i32 %{{.*}}, -1
+// CHECK: store i32 %{{.*}}, i32* @g, align 4
+// CHECK: ret void
+
int returns_int(void);
int except_return(void) {
__try {
diff --git a/test/CodeGen/finite-math.c b/test/CodeGen/finite-math.c
index fd8fcf6..8365b56 100644
--- a/test/CodeGen/finite-math.c
+++ b/test/CodeGen/finite-math.c
@@ -1,5 +1,6 @@
// RUN: %clang_cc1 -ffinite-math-only -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=FINITE
// RUN: %clang_cc1 -fno-signed-zeros -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=NSZ
+// RUN: %clang_cc1 -freciprocal-math -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=RECIP
float f0, f1, f2;
@@ -8,6 +9,7 @@
// FINITE: fadd nnan ninf
// NSZ: fadd nsz
+ // RECIP: fadd arcp
f0 = f1 + f2;
// CHECK: ret
diff --git a/test/CodeGen/mangle-windows.c b/test/CodeGen/mangle-windows.c
index 4a10875..db39425 100644
--- a/test/CodeGen/mangle-windows.c
+++ b/test/CodeGen/mangle-windows.c
@@ -1,15 +1,26 @@
// RUN: %clang_cc1 -emit-llvm %s -o - -triple=i386-pc-win32 | FileCheck %s
// RUN: %clang_cc1 -emit-llvm %s -o - -triple=i386-mingw32 | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm %s -o - -triple=i386-pc-windows-msvc-elf | FileCheck %s --check-prefix=ELF32
// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-pc-win32 | FileCheck %s --check-prefix=X64
// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-mingw32 | FileCheck %s --check-prefix=X64
+// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-pc-windows-msvc-elf | FileCheck %s --check-prefix=ELF64
+
+// CHECK: target datalayout = "e-m:x-{{.*}}"
+// X64: target datalayout = "e-m:w-{{.*}}"
+// ELF32: target datalayout = "e-m:e-{{.*}}"
+// ELF64: target datalayout = "e-m:e-{{.*}}"
void __stdcall f1(void) {}
// CHECK: define x86_stdcallcc void @"\01_f1@0"
// X64: define void @f1(
+// ELF32: define x86_stdcallcc void @"\01_f1@0"
+// ELF64: define void @f1(
void __fastcall f2(void) {}
// CHECK: define x86_fastcallcc void @"\01@f2@0"
// X64: define void @f2(
+// ELF32: define x86_fastcallcc void @"\01@f2@0"
+// ELF64: define void @f2(
void __stdcall f3() {}
// CHECK: define x86_stdcallcc void @"\01_f3@0"
@@ -46,10 +57,14 @@
void __vectorcall v1(void) {}
// CHECK: define x86_vectorcallcc void @"\01v1@@0"(
// X64: define x86_vectorcallcc void @"\01v1@@0"(
+// ELF32: define x86_vectorcallcc void @"\01v1@@0"(
+// ELF64: define x86_vectorcallcc void @"\01v1@@0"(
void __vectorcall v2(char a) {}
// CHECK: define x86_vectorcallcc void @"\01v2@@4"(
// X64: define x86_vectorcallcc void @"\01v2@@8"(
+// ELF32: define x86_vectorcallcc void @"\01v2@@4"(
+// ELF64: define x86_vectorcallcc void @"\01v2@@8"(
void __vectorcall v3(short a) {}
// CHECK: define x86_vectorcallcc void @"\01v3@@4"(
diff --git a/test/CodeGen/mcount.c b/test/CodeGen/mcount.c
index 5c608bc..99dc907 100644
--- a/test/CodeGen/mcount.c
+++ b/test/CodeGen/mcount.c
@@ -1,8 +1,18 @@
// RUN: %clang_cc1 -pg -triple i386-unknown-unknown -emit-llvm -o - %s | FileCheck %s
-// RUN: %clang_cc1 -pg -triple powerpc-unknown-gnu-linux -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-PPC %s
-// RUN: %clang_cc1 -pg -triple powerpc64-unknown-gnu-linux -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-PPC %s
-// RUN: %clang_cc1 -pg -triple powerpc64le-unknown-gnu-linux -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-PPC %s
+// RUN: %clang_cc1 -pg -triple powerpc-unknown-gnu-linux -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-PREFIXED %s
+// RUN: %clang_cc1 -pg -triple powerpc64-unknown-gnu-linux -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-PREFIXED %s
+// RUN: %clang_cc1 -pg -triple powerpc64le-unknown-gnu-linux -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-PREFIXED %s
+// RUN: %clang_cc1 -pg -triple i386-netbsd -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-PREFIXED %s
+// RUN: %clang_cc1 -pg -triple x86_64-netbsd -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-PREFIXED %s
+// RUN: %clang_cc1 -pg -triple arm-netbsd-eabi -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-PREFIXED %s
+// RUN: %clang_cc1 -pg -triple aarch64-netbsd -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-PREFIXED %s
+// RUN: %clang_cc1 -pg -triple mips-netbsd -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-PREFIXED %s
+// RUN: %clang_cc1 -pg -triple powerpc-netbsd -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-PREFIXED %s
+// RUN: %clang_cc1 -pg -triple powerpc64-netbsd -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-PREFIXED %s
+// RUN: %clang_cc1 -pg -triple powerpc64le-netbsd -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-PREFIXED %s
+// RUN: %clang_cc1 -pg -triple sparc-netbsd -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-PREFIXED %s
+// RUN: %clang_cc1 -pg -triple sparc64-netbsd -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-PREFIXED %s
void foo(void) {
// CHECK: call void @mcount()
-// CHECK-PPC: call void @_mcount()
+// CHECK-PREFIXED: call void @_mcount()
}
diff --git a/test/CodeGen/mips-inline-asm.c b/test/CodeGen/mips-inline-asm.c
new file mode 100644
index 0000000..2cfa41c
--- /dev/null
+++ b/test/CodeGen/mips-inline-asm.c
@@ -0,0 +1,19 @@
+// REQUIRES: mips-registered-target
+// RUN: %clang_cc1 -triple mips-linux-gnu -emit-llvm -o - %s | FileCheck %s
+
+int data;
+
+void m () {
+ asm("lw $1, %0" :: "m"(data));
+ // CHECK: call void asm sideeffect "lw $$1, $0", "*m,~{$1}"(i32* @data)
+}
+
+void ZC () {
+ asm("ll $1, %0" :: "ZC"(data));
+ // CHECK: call void asm sideeffect "ll $$1, $0", "*^ZC,~{$1}"(i32* @data)
+}
+
+void R () {
+ asm("lw $1, %0" :: "R"(data));
+ // CHECK: call void asm sideeffect "lw $$1, $0", "*R,~{$1}"(i32* @data)
+}
diff --git a/test/CodeGen/mips-unsupported-nan.c b/test/CodeGen/mips-unsupported-nan.c
new file mode 100644
index 0000000..14a36fc
--- /dev/null
+++ b/test/CodeGen/mips-unsupported-nan.c
@@ -0,0 +1,25 @@
+// RUN: %clang -target mipsel-unknown-linux -mnan=2008 -march=mips2 -emit-llvm -S %s -o - 2>&1 | FileCheck -check-prefix=CHECK-MIPS2 -check-prefix=CHECK-NANLEGACY %s
+// RUN: %clang -target mips64el-unknown-linux -mnan=2008 -march=mips3 -emit-llvm -S %s -o - 2>&1 | FileCheck -check-prefix=CHECK-MIPS3 -check-prefix=CHECK-NANLEGACY %s
+// RUN: %clang -target mips64el-unknown-linux -mnan=2008 -march=mips4 -emit-llvm -S %s -o - 2>&1 | FileCheck -check-prefix=CHECK-MIPS4 -check-prefix=CHECK-NANLEGACY %s
+// RUN: %clang -target mipsel-unknown-linux -mnan=2008 -march=mips32 -emit-llvm -S %s -o - 2>&1 | FileCheck -check-prefix=CHECK-MIPS32 -check-prefix=CHECK-NANLEGACY %s
+// RUN: %clang -target mipsel-unknown-linux -mnan=2008 -march=mips32r2 -emit-llvm -S %s -o - 2>&1 | FileCheck -check-prefix=CHECK-MIPS32R2 -check-prefix=CHECK-NANLEGACY %s
+// RUN: %clang -target mipsel-unknown-linux -mnan=2008 -march=mips32r3 -emit-llvm -S %s -o - 2>&1 | FileCheck -check-prefix=CHECK-NOT-MIPS32R3 -check-prefix=CHECK-NAN2008 %s
+// RUN: %clang -target mipsel-unknown-linux -mnan=legacy -march=mips32r6 -emit-llvm -S %s -o - 2>&1 | FileCheck -check-prefix=CHECK-MIPS32R6 -check-prefix=CHECK-NAN2008 %s
+// RUN: %clang -target mips64el-unknown-linux -mnan=2008 -march=mips64 -emit-llvm -S %s -o - 2>&1 | FileCheck -check-prefix=CHECK-MIPS64 -check-prefix=CHECK-NANLEGACY %s
+// RUN: %clang -target mips64el-unknown-linux -mnan=2008 -march=mips64r2 -emit-llvm -S %s -o - 2>&1 | FileCheck -check-prefix=CHECK-MIPS64R2 -check-prefix=CHECK-NANLEGACY %s
+// RUN: %clang -target mips64el-unknown-linux -mnan=legacy -march=mips64r6 -emit-llvm -S %s -o - 2>&1 | FileCheck -check-prefix=CHECK-MIPS64R6 -check-prefix=CHECK-NAN2008 %s
+
+// CHECK-MIPS2: warning: ignoring '-mnan=2008' option because the 'mips2' architecture does not support it
+// CHECK-MIPS3: warning: ignoring '-mnan=2008' option because the 'mips3' architecture does not support it
+// CHECK-MIPS4: warning: ignoring '-mnan=2008' option because the 'mips4' architecture does not support it
+// CHECK-MIPS32: warning: ignoring '-mnan=2008' option because the 'mips32' architecture does not support it
+// CHECK-MIPS32R2: warning: ignoring '-mnan=2008' option because the 'mips32r2' architecture does not support it
+// CHECK-MIPS32R3: warning: ignoring '-mnan=2008' option because the 'mips32r3' architecture does not support it
+// CHECK-MIPS32R6: warning: ignoring '-mnan=legacy' option because the 'mips32r6' architecture does not support it
+// CHECK-MIPS64: warning: ignoring '-mnan=2008' option because the 'mips64' architecture does not support it
+// CHECK-MIPS64R2: warning: ignoring '-mnan=2008' option because the 'mips64r2' architecture does not support it
+// CHECK-MIPS64R6: warning: ignoring '-mnan=legacy' option because the 'mips64r6' architecture does not support it
+// CHECK-NANLEGACY: float 0x7FF4000000000000
+// CHECK-NAN2008: float 0x7FF8000000000000
+
+float f = __builtin_nan("");
diff --git a/test/CodeGen/mrtd.c b/test/CodeGen/mrtd.c
index f929d4c..8d2aeee 100644
--- a/test/CodeGen/mrtd.c
+++ b/test/CodeGen/mrtd.c
@@ -23,6 +23,6 @@
qux(a1, a2, a3);
}
// CHECK-LABEL: define x86_stdcallcc void @quux
-// CHECK: call void (i32, ...)* @qux
+// CHECK: call void (i32, ...) @qux
// CHECK: attributes [[NUW]] = { nounwind{{.*}} }
diff --git a/test/CodeGen/ms-declspecs.c b/test/CodeGen/ms-declspecs.c
index 328fc83..c32733e 100644
--- a/test/CodeGen/ms-declspecs.c
+++ b/test/CodeGen/ms-declspecs.c
@@ -5,6 +5,12 @@
// CHECK: @x1 = weak_odr global i32 1, comdat, align 4
// CHECK: @x2 = weak_odr constant i32 2, comdat, align 4
+// selectany turns extern variable declarations into definitions.
+__declspec(selectany) int x3;
+extern __declspec(selectany) int x4;
+// CHECK: @x3 = weak_odr global i32 0, comdat, align 4
+// CHECK: @x4 = weak_odr global i32 0, comdat, align 4
+
struct __declspec(align(16)) S {
char x;
};
diff --git a/test/CodeGen/ms-declspecs.cpp b/test/CodeGen/ms-declspecs.cpp
new file mode 100644
index 0000000..decf5d6
--- /dev/null
+++ b/test/CodeGen/ms-declspecs.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -triple i386-pc-win32 %s -emit-llvm -fms-compatibility -o - | FileCheck %s
+
+// selectany turns extern "C" variable declarations into definitions.
+extern __declspec(selectany) int x1;
+extern "C" __declspec(selectany) int x2;
+extern "C++" __declspec(selectany) int x3;
+extern "C" {
+__declspec(selectany) int x4;
+}
+__declspec(selectany) int x5;
+// CHECK: @"\01?x1@@3HA" = weak_odr global i32 0, comdat, align 4
+// CHECK: @x2 = weak_odr global i32 0, comdat, align 4
+// CHECK: @"\01?x3@@3HA" = weak_odr global i32 0, comdat, align 4
+// CHECK: @x4 = weak_odr global i32 0, comdat, align 4
+// CHECK: @"\01?x5@@3HA" = weak_odr global i32 0, comdat, align 4
diff --git a/test/CodeGen/ms-setjmp.c b/test/CodeGen/ms-setjmp.c
index 78928bb..675c8dd 100644
--- a/test/CodeGen/ms-setjmp.c
+++ b/test/CodeGen/ms-setjmp.c
@@ -14,7 +14,7 @@
int test_setjmp() {
return _setjmp(jb);
// I386-LABEL: define i32 @test_setjmp
- // I386: %[[call:.*]] = call i32 (i8*, i32, ...)* @_setjmp3(i8* getelementptr inbounds ([1 x i8], [1 x i8]* @jb, i32 0, i32 0), i32 0)
+ // I386: %[[call:.*]] = call i32 (i8*, i32, ...) @_setjmp3(i8* getelementptr inbounds ([1 x i8], [1 x i8]* @jb, i32 0, i32 0), i32 0)
// I386-NEXT: ret i32 %[[call]]
// X64-LABEL: define i32 @test_setjmp
diff --git a/test/CodeGen/nvptx-cpus.c b/test/CodeGen/nvptx-cpus.c
index c9c7680..015f529 100644
--- a/test/CodeGen/nvptx-cpus.c
+++ b/test/CodeGen/nvptx-cpus.c
@@ -2,6 +2,7 @@
// RUN: %clang_cc1 -triple nvptx-unknown-unknown -target-cpu sm_21 -O3 -S -o %t %s -emit-llvm
// RUN: %clang_cc1 -triple nvptx-unknown-unknown -target-cpu sm_30 -O3 -S -o %t %s -emit-llvm
// RUN: %clang_cc1 -triple nvptx-unknown-unknown -target-cpu sm_35 -O3 -S -o %t %s -emit-llvm
+// RUN: %clang_cc1 -triple nvptx-unknown-unknown -target-cpu sm_37 -O3 -S -o %t %s -emit-llvm
// Make sure clang accepts all supported architectures.
diff --git a/test/CodeGen/pr5406.c b/test/CodeGen/pr5406.c
index 0f04a8e..69038ac 100644
--- a/test/CodeGen/pr5406.c
+++ b/test/CodeGen/pr5406.c
@@ -6,7 +6,7 @@
void foo (int i, ...);
-// CHECK: call void (i32, ...)* @foo(i32 1, [1 x i32] {{.*}})
+// CHECK: call void (i32, ...) @foo(i32 1, [1 x i32] {{.*}})
int main (void)
{
A0 a3;
diff --git a/test/CodeGen/systemz-abi-vector.c b/test/CodeGen/systemz-abi-vector.c
new file mode 100644
index 0000000..06c5f3f
--- /dev/null
+++ b/test/CodeGen/systemz-abi-vector.c
@@ -0,0 +1,245 @@
+// RUN: %clang_cc1 -triple s390x-linux-gnu -emit-llvm -o - %s | FileCheck %s
+
+// Vector types
+
+typedef __attribute__((vector_size(1))) char v1i8;
+
+typedef __attribute__((vector_size(2))) char v2i8;
+typedef __attribute__((vector_size(2))) short v1i16;
+
+typedef __attribute__((vector_size(4))) char v4i8;
+typedef __attribute__((vector_size(4))) short v2i16;
+typedef __attribute__((vector_size(4))) int v1i32;
+typedef __attribute__((vector_size(4))) float v1f32;
+
+typedef __attribute__((vector_size(8))) char v8i8;
+typedef __attribute__((vector_size(8))) short v4i16;
+typedef __attribute__((vector_size(8))) int v2i32;
+typedef __attribute__((vector_size(8))) long long v1i64;
+typedef __attribute__((vector_size(8))) float v2f32;
+typedef __attribute__((vector_size(8))) double v1f64;
+
+typedef __attribute__((vector_size(16))) char v16i8;
+typedef __attribute__((vector_size(16))) short v8i16;
+typedef __attribute__((vector_size(16))) int v4i32;
+typedef __attribute__((vector_size(16))) long long v2i64;
+typedef __attribute__((vector_size(16))) __int128 v1i128;
+typedef __attribute__((vector_size(16))) float v4f32;
+typedef __attribute__((vector_size(16))) double v2f64;
+typedef __attribute__((vector_size(16))) long double v1f128;
+
+typedef __attribute__((vector_size(32))) char v32i8;
+
+v1i8 pass_v1i8(v1i8 arg) { return arg; }
+// CHECK-LABEL: define void @pass_v1i8(<1 x i8>* noalias sret %{{.*}}, <1 x i8>*)
+
+v2i8 pass_v2i8(v2i8 arg) { return arg; }
+// CHECK-LABEL: define void @pass_v2i8(<2 x i8>* noalias sret %{{.*}}, <2 x i8>*)
+
+v4i8 pass_v4i8(v4i8 arg) { return arg; }
+// CHECK-LABEL: define void @pass_v4i8(<4 x i8>* noalias sret %{{.*}}, <4 x i8>*)
+
+v8i8 pass_v8i8(v8i8 arg) { return arg; }
+// CHECK-LABEL: define void @pass_v8i8(<8 x i8>* noalias sret %{{.*}}, <8 x i8>*)
+
+v16i8 pass_v16i8(v16i8 arg) { return arg; }
+// CHECK-LABEL: define void @pass_v16i8(<16 x i8>* noalias sret %{{.*}}, <16 x i8>*)
+
+v32i8 pass_v32i8(v32i8 arg) { return arg; }
+// CHECK-LABEL: define void @pass_v32i8(<32 x i8>* noalias sret %{{.*}}, <32 x i8>*)
+
+v1i16 pass_v1i16(v1i16 arg) { return arg; }
+// CHECK-LABEL: define void @pass_v1i16(<1 x i16>* noalias sret %{{.*}}, <1 x i16>*)
+
+v2i16 pass_v2i16(v2i16 arg) { return arg; }
+// CHECK-LABEL: define void @pass_v2i16(<2 x i16>* noalias sret %{{.*}}, <2 x i16>*)
+
+v4i16 pass_v4i16(v4i16 arg) { return arg; }
+// CHECK-LABEL: define void @pass_v4i16(<4 x i16>* noalias sret %{{.*}}, <4 x i16>*)
+
+v8i16 pass_v8i16(v8i16 arg) { return arg; }
+// CHECK-LABEL: define void @pass_v8i16(<8 x i16>* noalias sret %{{.*}}, <8 x i16>*)
+
+v1i32 pass_v1i32(v1i32 arg) { return arg; }
+// CHECK-LABEL: define void @pass_v1i32(<1 x i32>* noalias sret %{{.*}}, <1 x i32>*)
+
+v2i32 pass_v2i32(v2i32 arg) { return arg; }
+// CHECK-LABEL: define void @pass_v2i32(<2 x i32>* noalias sret %{{.*}}, <2 x i32>*)
+
+v4i32 pass_v4i32(v4i32 arg) { return arg; }
+// CHECK-LABEL: define void @pass_v4i32(<4 x i32>* noalias sret %{{.*}}, <4 x i32>*)
+
+v1i64 pass_v1i64(v1i64 arg) { return arg; }
+// CHECK-LABEL: define void @pass_v1i64(<1 x i64>* noalias sret %{{.*}}, <1 x i64>*)
+
+v2i64 pass_v2i64(v2i64 arg) { return arg; }
+// CHECK-LABEL: define void @pass_v2i64(<2 x i64>* noalias sret %{{.*}}, <2 x i64>*)
+
+v1i128 pass_v1i128(v1i128 arg) { return arg; }
+// CHECK-LABEL: define void @pass_v1i128(<1 x i128>* noalias sret %{{.*}}, <1 x i128>*)
+
+v1f32 pass_v1f32(v1f32 arg) { return arg; }
+// CHECK-LABEL: define void @pass_v1f32(<1 x float>* noalias sret %{{.*}}, <1 x float>*)
+
+v2f32 pass_v2f32(v2f32 arg) { return arg; }
+// CHECK-LABEL: define void @pass_v2f32(<2 x float>* noalias sret %{{.*}}, <2 x float>*)
+
+v4f32 pass_v4f32(v4f32 arg) { return arg; }
+// CHECK-LABEL: define void @pass_v4f32(<4 x float>* noalias sret %{{.*}}, <4 x float>*)
+
+v1f64 pass_v1f64(v1f64 arg) { return arg; }
+// CHECK-LABEL: define void @pass_v1f64(<1 x double>* noalias sret %{{.*}}, <1 x double>*)
+
+v2f64 pass_v2f64(v2f64 arg) { return arg; }
+// CHECK-LABEL: define void @pass_v2f64(<2 x double>* noalias sret %{{.*}}, <2 x double>*)
+
+v1f128 pass_v1f128(v1f128 arg) { return arg; }
+// CHECK-LABEL: define void @pass_v1f128(<1 x fp128>* noalias sret %{{.*}}, <1 x fp128>*)
+
+
+// Accessing variable argument lists
+
+v1i8 va_v1i8(__builtin_va_list l) { return __builtin_va_arg(l, v1i8); }
+// CHECK-LABEL: define void @va_v1i8(<1 x i8>* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}})
+// CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0
+// CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]]
+// CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5
+// CHECK: br i1 [[FITS_IN_REGS]],
+// CHECK: [[SCALED_REG_COUNT:%[^ ]+]] = mul i64 [[REG_COUNT]], 8
+// CHECK: [[REG_OFFSET:%[^ ]+]] = add i64 [[SCALED_REG_COUNT]], 16
+// CHECK: [[REG_SAVE_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 3
+// CHECK: [[REG_SAVE_AREA:%[^ ]+]] = load i8*, i8** [[REG_SAVE_AREA_PTR:[^ ]+]]
+// CHECK: [[RAW_REG_ADDR:%[^ ]+]] = getelementptr i8, i8* [[REG_SAVE_AREA]], i64 [[REG_OFFSET]]
+// CHECK: [[REG_ADDR:%[^ ]+]] = bitcast i8* [[RAW_REG_ADDR]] to <1 x i8>**
+// CHECK: [[REG_COUNT1:%[^ ]+]] = add i64 [[REG_COUNT]], 1
+// CHECK: store i64 [[REG_COUNT1]], i64* [[REG_COUNT_PTR]]
+// CHECK: [[OVERFLOW_ARG_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 2
+// CHECK: [[OVERFLOW_ARG_AREA:%[^ ]+]] = load i8*, i8** [[OVERFLOW_ARG_AREA_PTR]]
+// CHECK: [[RAW_MEM_ADDR:%[^ ]+]] = getelementptr i8, i8* [[OVERFLOW_ARG_AREA]], i64 0
+// CHECK: [[MEM_ADDR:%[^ ]+]] = bitcast i8* [[RAW_MEM_ADDR]] to <1 x i8>**
+// CHECK: [[OVERFLOW_ARG_AREA2:%[^ ]+]] = getelementptr i8, i8* [[OVERFLOW_ARG_AREA]], i64 8
+// CHECK: store i8* [[OVERFLOW_ARG_AREA2]], i8** [[OVERFLOW_ARG_AREA_PTR]]
+// CHECK: [[VA_ARG_ADDR:%[^ ]+]] = phi <1 x i8>** [ [[REG_ADDR]], %{{.*}} ], [ [[MEM_ADDR]], %{{.*}} ]
+// CHECK: [[INDIRECT_ARG:%[^ ]+]] = load <1 x i8>*, <1 x i8>** [[VA_ARG_ADDR]]
+// CHECK: ret void
+
+v2i8 va_v2i8(__builtin_va_list l) { return __builtin_va_arg(l, v2i8); }
+// CHECK-LABEL: define void @va_v2i8(<2 x i8>* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}})
+// CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0
+// CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]]
+// CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5
+// CHECK: br i1 [[FITS_IN_REGS]],
+// CHECK: [[SCALED_REG_COUNT:%[^ ]+]] = mul i64 [[REG_COUNT]], 8
+// CHECK: [[REG_OFFSET:%[^ ]+]] = add i64 [[SCALED_REG_COUNT]], 16
+// CHECK: [[REG_SAVE_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 3
+// CHECK: [[REG_SAVE_AREA:%[^ ]+]] = load i8*, i8** [[REG_SAVE_AREA_PTR:[^ ]+]]
+// CHECK: [[RAW_REG_ADDR:%[^ ]+]] = getelementptr i8, i8* [[REG_SAVE_AREA]], i64 [[REG_OFFSET]]
+// CHECK: [[REG_ADDR:%[^ ]+]] = bitcast i8* [[RAW_REG_ADDR]] to <2 x i8>**
+// CHECK: [[REG_COUNT1:%[^ ]+]] = add i64 [[REG_COUNT]], 1
+// CHECK: store i64 [[REG_COUNT1]], i64* [[REG_COUNT_PTR]]
+// CHECK: [[OVERFLOW_ARG_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 2
+// CHECK: [[OVERFLOW_ARG_AREA:%[^ ]+]] = load i8*, i8** [[OVERFLOW_ARG_AREA_PTR]]
+// CHECK: [[RAW_MEM_ADDR:%[^ ]+]] = getelementptr i8, i8* [[OVERFLOW_ARG_AREA]], i64 0
+// CHECK: [[MEM_ADDR:%[^ ]+]] = bitcast i8* [[RAW_MEM_ADDR]] to <2 x i8>**
+// CHECK: [[OVERFLOW_ARG_AREA2:%[^ ]+]] = getelementptr i8, i8* [[OVERFLOW_ARG_AREA]], i64 8
+// CHECK: store i8* [[OVERFLOW_ARG_AREA2]], i8** [[OVERFLOW_ARG_AREA_PTR]]
+// CHECK: [[VA_ARG_ADDR:%[^ ]+]] = phi <2 x i8>** [ [[REG_ADDR]], %{{.*}} ], [ [[MEM_ADDR]], %{{.*}} ]
+// CHECK: [[INDIRECT_ARG:%[^ ]+]] = load <2 x i8>*, <2 x i8>** [[VA_ARG_ADDR]]
+// CHECK: ret void
+
+v4i8 va_v4i8(__builtin_va_list l) { return __builtin_va_arg(l, v4i8); }
+// CHECK-LABEL: define void @va_v4i8(<4 x i8>* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}})
+// CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0
+// CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]]
+// CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5
+// CHECK: br i1 [[FITS_IN_REGS]],
+// CHECK: [[SCALED_REG_COUNT:%[^ ]+]] = mul i64 [[REG_COUNT]], 8
+// CHECK: [[REG_OFFSET:%[^ ]+]] = add i64 [[SCALED_REG_COUNT]], 16
+// CHECK: [[REG_SAVE_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 3
+// CHECK: [[REG_SAVE_AREA:%[^ ]+]] = load i8*, i8** [[REG_SAVE_AREA_PTR:[^ ]+]]
+// CHECK: [[RAW_REG_ADDR:%[^ ]+]] = getelementptr i8, i8* [[REG_SAVE_AREA]], i64 [[REG_OFFSET]]
+// CHECK: [[REG_ADDR:%[^ ]+]] = bitcast i8* [[RAW_REG_ADDR]] to <4 x i8>**
+// CHECK: [[REG_COUNT1:%[^ ]+]] = add i64 [[REG_COUNT]], 1
+// CHECK: store i64 [[REG_COUNT1]], i64* [[REG_COUNT_PTR]]
+// CHECK: [[OVERFLOW_ARG_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 2
+// CHECK: [[OVERFLOW_ARG_AREA:%[^ ]+]] = load i8*, i8** [[OVERFLOW_ARG_AREA_PTR]]
+// CHECK: [[RAW_MEM_ADDR:%[^ ]+]] = getelementptr i8, i8* [[OVERFLOW_ARG_AREA]], i64 0
+// CHECK: [[MEM_ADDR:%[^ ]+]] = bitcast i8* [[RAW_MEM_ADDR]] to <4 x i8>**
+// CHECK: [[OVERFLOW_ARG_AREA2:%[^ ]+]] = getelementptr i8, i8* [[OVERFLOW_ARG_AREA]], i64 8
+// CHECK: store i8* [[OVERFLOW_ARG_AREA2]], i8** [[OVERFLOW_ARG_AREA_PTR]]
+// CHECK: [[VA_ARG_ADDR:%[^ ]+]] = phi <4 x i8>** [ [[REG_ADDR]], %{{.*}} ], [ [[MEM_ADDR]], %{{.*}} ]
+// CHECK: [[INDIRECT_ARG:%[^ ]+]] = load <4 x i8>*, <4 x i8>** [[VA_ARG_ADDR]]
+// CHECK: ret void
+
+v8i8 va_v8i8(__builtin_va_list l) { return __builtin_va_arg(l, v8i8); }
+// CHECK-LABEL: define void @va_v8i8(<8 x i8>* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}})
+// CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0
+// CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]]
+// CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5
+// CHECK: br i1 [[FITS_IN_REGS]],
+// CHECK: [[SCALED_REG_COUNT:%[^ ]+]] = mul i64 [[REG_COUNT]], 8
+// CHECK: [[REG_OFFSET:%[^ ]+]] = add i64 [[SCALED_REG_COUNT]], 16
+// CHECK: [[REG_SAVE_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 3
+// CHECK: [[REG_SAVE_AREA:%[^ ]+]] = load i8*, i8** [[REG_SAVE_AREA_PTR:[^ ]+]]
+// CHECK: [[RAW_REG_ADDR:%[^ ]+]] = getelementptr i8, i8* [[REG_SAVE_AREA]], i64 [[REG_OFFSET]]
+// CHECK: [[REG_ADDR:%[^ ]+]] = bitcast i8* [[RAW_REG_ADDR]] to <8 x i8>**
+// CHECK: [[REG_COUNT1:%[^ ]+]] = add i64 [[REG_COUNT]], 1
+// CHECK: store i64 [[REG_COUNT1]], i64* [[REG_COUNT_PTR]]
+// CHECK: [[OVERFLOW_ARG_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 2
+// CHECK: [[OVERFLOW_ARG_AREA:%[^ ]+]] = load i8*, i8** [[OVERFLOW_ARG_AREA_PTR]]
+// CHECK: [[RAW_MEM_ADDR:%[^ ]+]] = getelementptr i8, i8* [[OVERFLOW_ARG_AREA]], i64 0
+// CHECK: [[MEM_ADDR:%[^ ]+]] = bitcast i8* [[RAW_MEM_ADDR]] to <8 x i8>**
+// CHECK: [[OVERFLOW_ARG_AREA2:%[^ ]+]] = getelementptr i8, i8* [[OVERFLOW_ARG_AREA]], i64 8
+// CHECK: store i8* [[OVERFLOW_ARG_AREA2]], i8** [[OVERFLOW_ARG_AREA_PTR]]
+// CHECK: [[VA_ARG_ADDR:%[^ ]+]] = phi <8 x i8>** [ [[REG_ADDR]], %{{.*}} ], [ [[MEM_ADDR]], %{{.*}} ]
+// CHECK: [[INDIRECT_ARG:%[^ ]+]] = load <8 x i8>*, <8 x i8>** [[VA_ARG_ADDR]]
+// CHECK: ret void
+
+v16i8 va_v16i8(__builtin_va_list l) { return __builtin_va_arg(l, v16i8); }
+// CHECK-LABEL: define void @va_v16i8(<16 x i8>* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}})
+// CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0
+// CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]]
+// CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5
+// CHECK: br i1 [[FITS_IN_REGS]],
+// CHECK: [[SCALED_REG_COUNT:%[^ ]+]] = mul i64 [[REG_COUNT]], 8
+// CHECK: [[REG_OFFSET:%[^ ]+]] = add i64 [[SCALED_REG_COUNT]], 16
+// CHECK: [[REG_SAVE_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 3
+// CHECK: [[REG_SAVE_AREA:%[^ ]+]] = load i8*, i8** [[REG_SAVE_AREA_PTR:[^ ]+]]
+// CHECK: [[RAW_REG_ADDR:%[^ ]+]] = getelementptr i8, i8* [[REG_SAVE_AREA]], i64 [[REG_OFFSET]]
+// CHECK: [[REG_ADDR:%[^ ]+]] = bitcast i8* [[RAW_REG_ADDR]] to <16 x i8>**
+// CHECK: [[REG_COUNT1:%[^ ]+]] = add i64 [[REG_COUNT]], 1
+// CHECK: store i64 [[REG_COUNT1]], i64* [[REG_COUNT_PTR]]
+// CHECK: [[OVERFLOW_ARG_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 2
+// CHECK: [[OVERFLOW_ARG_AREA:%[^ ]+]] = load i8*, i8** [[OVERFLOW_ARG_AREA_PTR]]
+// CHECK: [[RAW_MEM_ADDR:%[^ ]+]] = getelementptr i8, i8* [[OVERFLOW_ARG_AREA]], i64 0
+// CHECK: [[MEM_ADDR:%[^ ]+]] = bitcast i8* [[RAW_MEM_ADDR]] to <16 x i8>**
+// CHECK: [[OVERFLOW_ARG_AREA2:%[^ ]+]] = getelementptr i8, i8* [[OVERFLOW_ARG_AREA]], i64 8
+// CHECK: store i8* [[OVERFLOW_ARG_AREA2]], i8** [[OVERFLOW_ARG_AREA_PTR]]
+// CHECK: [[VA_ARG_ADDR:%[^ ]+]] = phi <16 x i8>** [ [[REG_ADDR]], %{{.*}} ], [ [[MEM_ADDR]], %{{.*}} ]
+// CHECK: [[INDIRECT_ARG:%[^ ]+]] = load <16 x i8>*, <16 x i8>** [[VA_ARG_ADDR]]
+// CHECK: ret void
+
+v32i8 va_v32i8(__builtin_va_list l) { return __builtin_va_arg(l, v32i8); }
+// CHECK-LABEL: define void @va_v32i8(<32 x i8>* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}})
+// CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0
+// CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]]
+// CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5
+// CHECK: br i1 [[FITS_IN_REGS]],
+// CHECK: [[SCALED_REG_COUNT:%[^ ]+]] = mul i64 [[REG_COUNT]], 8
+// CHECK: [[REG_OFFSET:%[^ ]+]] = add i64 [[SCALED_REG_COUNT]], 16
+// CHECK: [[REG_SAVE_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 3
+// CHECK: [[REG_SAVE_AREA:%[^ ]+]] = load i8*, i8** [[REG_SAVE_AREA_PTR:[^ ]+]]
+// CHECK: [[RAW_REG_ADDR:%[^ ]+]] = getelementptr i8, i8* [[REG_SAVE_AREA]], i64 [[REG_OFFSET]]
+// CHECK: [[REG_ADDR:%[^ ]+]] = bitcast i8* [[RAW_REG_ADDR]] to <32 x i8>**
+// CHECK: [[REG_COUNT1:%[^ ]+]] = add i64 [[REG_COUNT]], 1
+// CHECK: store i64 [[REG_COUNT1]], i64* [[REG_COUNT_PTR]]
+// CHECK: [[OVERFLOW_ARG_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 2
+// CHECK: [[OVERFLOW_ARG_AREA:%[^ ]+]] = load i8*, i8** [[OVERFLOW_ARG_AREA_PTR]]
+// CHECK: [[RAW_MEM_ADDR:%[^ ]+]] = getelementptr i8, i8* [[OVERFLOW_ARG_AREA]], i64 0
+// CHECK: [[MEM_ADDR:%[^ ]+]] = bitcast i8* [[RAW_MEM_ADDR]] to <32 x i8>**
+// CHECK: [[OVERFLOW_ARG_AREA2:%[^ ]+]] = getelementptr i8, i8* [[OVERFLOW_ARG_AREA]], i64 8
+// CHECK: store i8* [[OVERFLOW_ARG_AREA2]], i8** [[OVERFLOW_ARG_AREA_PTR]]
+// CHECK: [[VA_ARG_ADDR:%[^ ]+]] = phi <32 x i8>** [ [[REG_ADDR]], %{{.*}} ], [ [[MEM_ADDR]], %{{.*}} ]
+// CHECK: [[INDIRECT_ARG:%[^ ]+]] = load <32 x i8>*, <32 x i8>** [[VA_ARG_ADDR]]
+// CHECK: ret void
+
diff --git a/test/CodeGen/systemz-abi.c b/test/CodeGen/systemz-abi.c
new file mode 100644
index 0000000..5599c79
--- /dev/null
+++ b/test/CodeGen/systemz-abi.c
@@ -0,0 +1,586 @@
+// RUN: %clang_cc1 -triple s390x-linux-gnu -emit-llvm -o - %s | FileCheck %s
+
+// Scalar types
+
+char pass_char(char arg) { return arg; }
+// CHECK-LABEL: define signext i8 @pass_char(i8 signext %{{.*}})
+
+short pass_short(short arg) { return arg; }
+// CHECK-LABEL: define signext i16 @pass_short(i16 signext %{{.*}})
+
+int pass_int(int arg) { return arg; }
+// CHECK-LABEL: define signext i32 @pass_int(i32 signext %{{.*}})
+
+long pass_long(long arg) { return arg; }
+// CHECK-LABEL: define i64 @pass_long(i64 %{{.*}})
+
+long long pass_longlong(long long arg) { return arg; }
+// CHECK-LABEL: define i64 @pass_longlong(i64 %{{.*}})
+
+__int128 pass_int128(__int128 arg) { return arg; }
+// CHECK-LABEL: define void @pass_int128(i128* noalias sret %{{.*}}, i128*)
+
+float pass_float(float arg) { return arg; }
+// CHECK-LABEL: define float @pass_float(float %{{.*}})
+
+double pass_double(double arg) { return arg; }
+// CHECK-LABEL: define double @pass_double(double %{{.*}})
+
+long double pass_longdouble(long double arg) { return arg; }
+// CHECK-LABEL: define void @pass_longdouble(fp128* noalias sret %{{.*}}, fp128*)
+
+
+// Complex types
+
+_Complex char pass_complex_char(_Complex char arg) { return arg; }
+// CHECK-LABEL: define void @pass_complex_char({ i8, i8 }* noalias sret %{{.*}}, { i8, i8 }* %{{.*}}arg)
+
+_Complex short pass_complex_short(_Complex short arg) { return arg; }
+// CHECK-LABEL: define void @pass_complex_short({ i16, i16 }* noalias sret %{{.*}}, { i16, i16 }* %{{.*}}arg)
+
+_Complex int pass_complex_int(_Complex int arg) { return arg; }
+// CHECK-LABEL: define void @pass_complex_int({ i32, i32 }* noalias sret %{{.*}}, { i32, i32 }* %{{.*}}arg)
+
+_Complex long pass_complex_long(_Complex long arg) { return arg; }
+// CHECK-LABEL: define void @pass_complex_long({ i64, i64 }* noalias sret %{{.*}}, { i64, i64 }* %{{.*}}arg)
+
+_Complex long long pass_complex_longlong(_Complex long long arg) { return arg; }
+// CHECK-LABEL: define void @pass_complex_longlong({ i64, i64 }* noalias sret %{{.*}}, { i64, i64 }* %{{.*}}arg)
+
+_Complex float pass_complex_float(_Complex float arg) { return arg; }
+// CHECK-LABEL: define void @pass_complex_float({ float, float }* noalias sret %{{.*}}, { float, float }* %{{.*}}arg)
+
+_Complex double pass_complex_double(_Complex double arg) { return arg; }
+// CHECK-LABEL: define void @pass_complex_double({ double, double }* noalias sret %{{.*}}, { double, double }* %{{.*}}arg)
+
+_Complex long double pass_complex_longdouble(_Complex long double arg) { return arg; }
+// CHECK-LABEL: define void @pass_complex_longdouble({ fp128, fp128 }* noalias sret %{{.*}}, { fp128, fp128 }* %{{.*}}arg)
+
+
+// Aggregate types
+
+struct agg_1byte { char a[1]; };
+struct agg_1byte pass_agg_1byte(struct agg_1byte arg) { return arg; }
+// CHECK-LABEL: define void @pass_agg_1byte(%struct.agg_1byte* noalias sret %{{.*}}, i8 %{{.*}})
+
+struct agg_2byte { char a[2]; };
+struct agg_2byte pass_agg_2byte(struct agg_2byte arg) { return arg; }
+// CHECK-LABEL: define void @pass_agg_2byte(%struct.agg_2byte* noalias sret %{{.*}}, i16 %{{.*}})
+
+struct agg_3byte { char a[3]; };
+struct agg_3byte pass_agg_3byte(struct agg_3byte arg) { return arg; }
+// CHECK-LABEL: define void @pass_agg_3byte(%struct.agg_3byte* noalias sret %{{.*}}, %struct.agg_3byte* %{{.*}})
+
+struct agg_4byte { char a[4]; };
+struct agg_4byte pass_agg_4byte(struct agg_4byte arg) { return arg; }
+// CHECK-LABEL: define void @pass_agg_4byte(%struct.agg_4byte* noalias sret %{{.*}}, i32 %{{.*}})
+
+struct agg_5byte { char a[5]; };
+struct agg_5byte pass_agg_5byte(struct agg_5byte arg) { return arg; }
+// CHECK-LABEL: define void @pass_agg_5byte(%struct.agg_5byte* noalias sret %{{.*}}, %struct.agg_5byte* %{{.*}})
+
+struct agg_6byte { char a[6]; };
+struct agg_6byte pass_agg_6byte(struct agg_6byte arg) { return arg; }
+// CHECK-LABEL: define void @pass_agg_6byte(%struct.agg_6byte* noalias sret %{{.*}}, %struct.agg_6byte* %{{.*}})
+
+struct agg_7byte { char a[7]; };
+struct agg_7byte pass_agg_7byte(struct agg_7byte arg) { return arg; }
+// CHECK-LABEL: define void @pass_agg_7byte(%struct.agg_7byte* noalias sret %{{.*}}, %struct.agg_7byte* %{{.*}})
+
+struct agg_8byte { char a[8]; };
+struct agg_8byte pass_agg_8byte(struct agg_8byte arg) { return arg; }
+// CHECK-LABEL: define void @pass_agg_8byte(%struct.agg_8byte* noalias sret %{{.*}}, i64 %{{.*}})
+
+struct agg_16byte { char a[16]; };
+struct agg_16byte pass_agg_16byte(struct agg_16byte arg) { return arg; }
+// CHECK-LABEL: define void @pass_agg_16byte(%struct.agg_16byte* noalias sret %{{.*}}, %struct.agg_16byte* %{{.*}})
+
+
+// Float-like aggregate types
+
+struct agg_float { float a; };
+struct agg_float pass_agg_float(struct agg_float arg) { return arg; }
+// CHECK-LABEL: define void @pass_agg_float(%struct.agg_float* noalias sret %{{.*}}, float %{{.*}})
+
+struct agg_double { double a; };
+struct agg_double pass_agg_double(struct agg_double arg) { return arg; }
+// CHECK-LABEL: define void @pass_agg_double(%struct.agg_double* noalias sret %{{.*}}, double %{{.*}})
+
+struct agg_longdouble { long double a; };
+struct agg_longdouble pass_agg_longdouble(struct agg_longdouble arg) { return arg; }
+// CHECK-LABEL: define void @pass_agg_longdouble(%struct.agg_longdouble* noalias sret %{{.*}}, %struct.agg_longdouble* %{{.*}})
+
+struct agg_float_a8 { float a __attribute__((aligned (8))); };
+struct agg_float_a8 pass_agg_float_a8(struct agg_float_a8 arg) { return arg; }
+// CHECK-LABEL: define void @pass_agg_float_a8(%struct.agg_float_a8* noalias sret %{{.*}}, double %{{.*}})
+
+struct agg_float_a16 { float a __attribute__((aligned (16))); };
+struct agg_float_a16 pass_agg_float_a16(struct agg_float_a16 arg) { return arg; }
+// CHECK-LABEL: define void @pass_agg_float_a16(%struct.agg_float_a16* noalias sret %{{.*}}, %struct.agg_float_a16* %{{.*}})
+
+
+// Verify that the following are *not* float-like aggregate types
+
+struct agg_nofloat1 { float a; float b; };
+struct agg_nofloat1 pass_agg_nofloat1(struct agg_nofloat1 arg) { return arg; }
+// CHECK-LABEL: define void @pass_agg_nofloat1(%struct.agg_nofloat1* noalias sret %{{.*}}, i64 %{{.*}})
+
+struct agg_nofloat2 { float a; int b; };
+struct agg_nofloat2 pass_agg_nofloat2(struct agg_nofloat2 arg) { return arg; }
+// CHECK-LABEL: define void @pass_agg_nofloat2(%struct.agg_nofloat2* noalias sret %{{.*}}, i64 %{{.*}})
+
+struct agg_nofloat3 { float a; int : 0; };
+struct agg_nofloat3 pass_agg_nofloat3(struct agg_nofloat3 arg) { return arg; }
+// CHECK-LABEL: define void @pass_agg_nofloat3(%struct.agg_nofloat3* noalias sret %{{.*}}, i32 %{{.*}})
+
+
+// Accessing variable argument lists
+
+int va_int(__builtin_va_list l) { return __builtin_va_arg(l, int); }
+// CHECK-LABEL: define signext i32 @va_int(%struct.__va_list_tag* %{{.*}})
+// CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0
+// CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]]
+// CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5
+// CHECK: br i1 [[FITS_IN_REGS]],
+// CHECK: [[SCALED_REG_COUNT:%[^ ]+]] = mul i64 [[REG_COUNT]], 8
+// CHECK: [[REG_OFFSET:%[^ ]+]] = add i64 [[SCALED_REG_COUNT]], 20
+// CHECK: [[REG_SAVE_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 3
+// CHECK: [[REG_SAVE_AREA:%[^ ]+]] = load i8*, i8** [[REG_SAVE_AREA_PTR:[^ ]+]]
+// CHECK: [[RAW_REG_ADDR:%[^ ]+]] = getelementptr i8, i8* [[REG_SAVE_AREA]], i64 [[REG_OFFSET]]
+// CHECK: [[REG_ADDR:%[^ ]+]] = bitcast i8* [[RAW_REG_ADDR]] to i32*
+// CHECK: [[REG_COUNT1:%[^ ]+]] = add i64 [[REG_COUNT]], 1
+// CHECK: store i64 [[REG_COUNT1]], i64* [[REG_COUNT_PTR]]
+// CHECK: [[OVERFLOW_ARG_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 2
+// CHECK: [[OVERFLOW_ARG_AREA:%[^ ]+]] = load i8*, i8** [[OVERFLOW_ARG_AREA_PTR]]
+// CHECK: [[RAW_MEM_ADDR:%[^ ]+]] = getelementptr i8, i8* [[OVERFLOW_ARG_AREA]], i64 4
+// CHECK: [[MEM_ADDR:%[^ ]+]] = bitcast i8* [[RAW_MEM_ADDR]] to i32*
+// CHECK: [[OVERFLOW_ARG_AREA2:%[^ ]+]] = getelementptr i8, i8* [[OVERFLOW_ARG_AREA]], i64 8
+// CHECK: store i8* [[OVERFLOW_ARG_AREA2]], i8** [[OVERFLOW_ARG_AREA_PTR]]
+// CHECK: [[VA_ARG_ADDR:%[^ ]+]] = phi i32* [ [[REG_ADDR]], %{{.*}} ], [ [[MEM_ADDR]], %{{.*}} ]
+// CHECK: [[RET:%[^ ]+]] = load i32, i32* [[VA_ARG_ADDR]]
+// CHECK: ret i32 [[RET]]
+
+long va_long(__builtin_va_list l) { return __builtin_va_arg(l, long); }
+// CHECK-LABEL: define i64 @va_long(%struct.__va_list_tag* %{{.*}})
+// CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0
+// CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]]
+// CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5
+// CHECK: br i1 [[FITS_IN_REGS]],
+// CHECK: [[SCALED_REG_COUNT:%[^ ]+]] = mul i64 [[REG_COUNT]], 8
+// CHECK: [[REG_OFFSET:%[^ ]+]] = add i64 [[SCALED_REG_COUNT]], 16
+// CHECK: [[REG_SAVE_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 3
+// CHECK: [[REG_SAVE_AREA:%[^ ]+]] = load i8*, i8** [[REG_SAVE_AREA_PTR:[^ ]+]]
+// CHECK: [[RAW_REG_ADDR:%[^ ]+]] = getelementptr i8, i8* [[REG_SAVE_AREA]], i64 [[REG_OFFSET]]
+// CHECK: [[REG_ADDR:%[^ ]+]] = bitcast i8* [[RAW_REG_ADDR]] to i64*
+// CHECK: [[REG_COUNT1:%[^ ]+]] = add i64 [[REG_COUNT]], 1
+// CHECK: store i64 [[REG_COUNT1]], i64* [[REG_COUNT_PTR]]
+// CHECK: [[OVERFLOW_ARG_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 2
+// CHECK: [[OVERFLOW_ARG_AREA:%[^ ]+]] = load i8*, i8** [[OVERFLOW_ARG_AREA_PTR]]
+// CHECK: [[RAW_MEM_ADDR:%[^ ]+]] = getelementptr i8, i8* [[OVERFLOW_ARG_AREA]], i64 0
+// CHECK: [[MEM_ADDR:%[^ ]+]] = bitcast i8* [[RAW_MEM_ADDR]] to i64*
+// CHECK: [[OVERFLOW_ARG_AREA2:%[^ ]+]] = getelementptr i8, i8* [[OVERFLOW_ARG_AREA]], i64 8
+// CHECK: store i8* [[OVERFLOW_ARG_AREA2]], i8** [[OVERFLOW_ARG_AREA_PTR]]
+// CHECK: [[VA_ARG_ADDR:%[^ ]+]] = phi i64* [ [[REG_ADDR]], %{{.*}} ], [ [[MEM_ADDR]], %{{.*}} ]
+// CHECK: [[RET:%[^ ]+]] = load i64, i64* [[VA_ARG_ADDR]]
+// CHECK: ret i64 [[RET]]
+
+long long va_longlong(__builtin_va_list l) { return __builtin_va_arg(l, long long); }
+// CHECK-LABEL: define i64 @va_longlong(%struct.__va_list_tag* %{{.*}})
+// CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0
+// CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]]
+// CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5
+// CHECK: br i1 [[FITS_IN_REGS]],
+// CHECK: [[SCALED_REG_COUNT:%[^ ]+]] = mul i64 [[REG_COUNT]], 8
+// CHECK: [[REG_OFFSET:%[^ ]+]] = add i64 [[SCALED_REG_COUNT]], 16
+// CHECK: [[REG_SAVE_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 3
+// CHECK: [[REG_SAVE_AREA:%[^ ]+]] = load i8*, i8** [[REG_SAVE_AREA_PTR:[^ ]+]]
+// CHECK: [[RAW_REG_ADDR:%[^ ]+]] = getelementptr i8, i8* [[REG_SAVE_AREA]], i64 [[REG_OFFSET]]
+// CHECK: [[REG_ADDR:%[^ ]+]] = bitcast i8* [[RAW_REG_ADDR]] to i64*
+// CHECK: [[REG_COUNT1:%[^ ]+]] = add i64 [[REG_COUNT]], 1
+// CHECK: store i64 [[REG_COUNT1]], i64* [[REG_COUNT_PTR]]
+// CHECK: [[OVERFLOW_ARG_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 2
+// CHECK: [[OVERFLOW_ARG_AREA:%[^ ]+]] = load i8*, i8** [[OVERFLOW_ARG_AREA_PTR]]
+// CHECK: [[RAW_MEM_ADDR:%[^ ]+]] = getelementptr i8, i8* [[OVERFLOW_ARG_AREA]], i64 0
+// CHECK: [[MEM_ADDR:%[^ ]+]] = bitcast i8* [[RAW_MEM_ADDR]] to i64*
+// CHECK: [[OVERFLOW_ARG_AREA2:%[^ ]+]] = getelementptr i8, i8* [[OVERFLOW_ARG_AREA]], i64 8
+// CHECK: store i8* [[OVERFLOW_ARG_AREA2]], i8** [[OVERFLOW_ARG_AREA_PTR]]
+// CHECK: [[VA_ARG_ADDR:%[^ ]+]] = phi i64* [ [[REG_ADDR]], %{{.*}} ], [ [[MEM_ADDR]], %{{.*}} ]
+// CHECK: [[RET:%[^ ]+]] = load i64, i64* [[VA_ARG_ADDR]]
+// CHECK: ret i64 [[RET]]
+
+double va_double(__builtin_va_list l) { return __builtin_va_arg(l, double); }
+// CHECK-LABEL: define double @va_double(%struct.__va_list_tag* %{{.*}})
+// CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 1
+// CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]]
+// CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 4
+// CHECK: br i1 [[FITS_IN_REGS]],
+// CHECK: [[SCALED_REG_COUNT:%[^ ]+]] = mul i64 [[REG_COUNT]], 8
+// CHECK: [[REG_OFFSET:%[^ ]+]] = add i64 [[SCALED_REG_COUNT]], 128
+// CHECK: [[REG_SAVE_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 3
+// CHECK: [[REG_SAVE_AREA:%[^ ]+]] = load i8*, i8** [[REG_SAVE_AREA_PTR:[^ ]+]]
+// CHECK: [[RAW_REG_ADDR:%[^ ]+]] = getelementptr i8, i8* [[REG_SAVE_AREA]], i64 [[REG_OFFSET]]
+// CHECK: [[REG_ADDR:%[^ ]+]] = bitcast i8* [[RAW_REG_ADDR]] to double*
+// CHECK: [[REG_COUNT1:%[^ ]+]] = add i64 [[REG_COUNT]], 1
+// CHECK: store i64 [[REG_COUNT1]], i64* [[REG_COUNT_PTR]]
+// CHECK: [[OVERFLOW_ARG_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 2
+// CHECK: [[OVERFLOW_ARG_AREA:%[^ ]+]] = load i8*, i8** [[OVERFLOW_ARG_AREA_PTR]]
+// CHECK: [[RAW_MEM_ADDR:%[^ ]+]] = getelementptr i8, i8* [[OVERFLOW_ARG_AREA]], i64 0
+// CHECK: [[MEM_ADDR:%[^ ]+]] = bitcast i8* [[RAW_MEM_ADDR]] to double*
+// CHECK: [[OVERFLOW_ARG_AREA2:%[^ ]+]] = getelementptr i8, i8* [[OVERFLOW_ARG_AREA]], i64 8
+// CHECK: store i8* [[OVERFLOW_ARG_AREA2]], i8** [[OVERFLOW_ARG_AREA_PTR]]
+// CHECK: [[VA_ARG_ADDR:%[^ ]+]] = phi double* [ [[REG_ADDR]], %{{.*}} ], [ [[MEM_ADDR]], %{{.*}} ]
+// CHECK: [[RET:%[^ ]+]] = load double, double* [[VA_ARG_ADDR]]
+// CHECK: ret double [[RET]]
+
+long double va_longdouble(__builtin_va_list l) { return __builtin_va_arg(l, long double); }
+// CHECK-LABEL: define void @va_longdouble(fp128* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}})
+// CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0
+// CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]]
+// CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5
+// CHECK: br i1 [[FITS_IN_REGS]],
+// CHECK: [[SCALED_REG_COUNT:%[^ ]+]] = mul i64 [[REG_COUNT]], 8
+// CHECK: [[REG_OFFSET:%[^ ]+]] = add i64 [[SCALED_REG_COUNT]], 16
+// CHECK: [[REG_SAVE_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 3
+// CHECK: [[REG_SAVE_AREA:%[^ ]+]] = load i8*, i8** [[REG_SAVE_AREA_PTR:[^ ]+]]
+// CHECK: [[RAW_REG_ADDR:%[^ ]+]] = getelementptr i8, i8* [[REG_SAVE_AREA]], i64 [[REG_OFFSET]]
+// CHECK: [[REG_ADDR:%[^ ]+]] = bitcast i8* [[RAW_REG_ADDR]] to fp128**
+// CHECK: [[REG_COUNT1:%[^ ]+]] = add i64 [[REG_COUNT]], 1
+// CHECK: store i64 [[REG_COUNT1]], i64* [[REG_COUNT_PTR]]
+// CHECK: [[OVERFLOW_ARG_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 2
+// CHECK: [[OVERFLOW_ARG_AREA:%[^ ]+]] = load i8*, i8** [[OVERFLOW_ARG_AREA_PTR]]
+// CHECK: [[RAW_MEM_ADDR:%[^ ]+]] = getelementptr i8, i8* [[OVERFLOW_ARG_AREA]], i64 0
+// CHECK: [[MEM_ADDR:%[^ ]+]] = bitcast i8* [[RAW_MEM_ADDR]] to fp128**
+// CHECK: [[OVERFLOW_ARG_AREA2:%[^ ]+]] = getelementptr i8, i8* [[OVERFLOW_ARG_AREA]], i64 8
+// CHECK: store i8* [[OVERFLOW_ARG_AREA2]], i8** [[OVERFLOW_ARG_AREA_PTR]]
+// CHECK: [[VA_ARG_ADDR:%[^ ]+]] = phi fp128** [ [[REG_ADDR]], %{{.*}} ], [ [[MEM_ADDR]], %{{.*}} ]
+// CHECK: [[INDIRECT_ARG:%[^ ]+]] = load fp128*, fp128** [[VA_ARG_ADDR]]
+// CHECK: [[RET:%[^ ]+]] = load fp128, fp128* [[INDIRECT_ARG]]
+// CHECK: store fp128 [[RET]], fp128* %{{.*}}
+// CHECK: ret void
+
+_Complex char va_complex_char(__builtin_va_list l) { return __builtin_va_arg(l, _Complex char); }
+// CHECK-LABEL: define void @va_complex_char({ i8, i8 }* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}
+// CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0
+// CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]]
+// CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5
+// CHECK: br i1 [[FITS_IN_REGS]],
+// CHECK: [[SCALED_REG_COUNT:%[^ ]+]] = mul i64 [[REG_COUNT]], 8
+// CHECK: [[REG_OFFSET:%[^ ]+]] = add i64 [[SCALED_REG_COUNT]], 16
+// CHECK: [[REG_SAVE_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 3
+// CHECK: [[REG_SAVE_AREA:%[^ ]+]] = load i8*, i8** [[REG_SAVE_AREA_PTR:[^ ]+]]
+// CHECK: [[RAW_REG_ADDR:%[^ ]+]] = getelementptr i8, i8* [[REG_SAVE_AREA]], i64 [[REG_OFFSET]]
+// CHECK: [[REG_ADDR:%[^ ]+]] = bitcast i8* [[RAW_REG_ADDR]] to { i8, i8 }**
+// CHECK: [[REG_COUNT1:%[^ ]+]] = add i64 [[REG_COUNT]], 1
+// CHECK: store i64 [[REG_COUNT1]], i64* [[REG_COUNT_PTR]]
+// CHECK: [[OVERFLOW_ARG_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 2
+// CHECK: [[OVERFLOW_ARG_AREA:%[^ ]+]] = load i8*, i8** [[OVERFLOW_ARG_AREA_PTR]]
+// CHECK: [[RAW_MEM_ADDR:%[^ ]+]] = getelementptr i8, i8* [[OVERFLOW_ARG_AREA]], i64 0
+// CHECK: [[MEM_ADDR:%[^ ]+]] = bitcast i8* [[RAW_MEM_ADDR]] to { i8, i8 }**
+// CHECK: [[OVERFLOW_ARG_AREA2:%[^ ]+]] = getelementptr i8, i8* [[OVERFLOW_ARG_AREA]], i64 8
+// CHECK: store i8* [[OVERFLOW_ARG_AREA2]], i8** [[OVERFLOW_ARG_AREA_PTR]]
+// CHECK: [[VA_ARG_ADDR:%[^ ]+]] = phi { i8, i8 }** [ [[REG_ADDR]], %{{.*}} ], [ [[MEM_ADDR]], %{{.*}} ]
+// CHECK: [[INDIRECT_ARG:%[^ ]+]] = load { i8, i8 }*, { i8, i8 }** [[VA_ARG_ADDR]]
+// CHECK: ret void
+
+struct agg_1byte va_agg_1byte(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_1byte); }
+// CHECK-LABEL: define void @va_agg_1byte(%struct.agg_1byte* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}
+// CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0
+// CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]]
+// CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5
+// CHECK: br i1 [[FITS_IN_REGS]],
+// CHECK: [[SCALED_REG_COUNT:%[^ ]+]] = mul i64 [[REG_COUNT]], 8
+// CHECK: [[REG_OFFSET:%[^ ]+]] = add i64 [[SCALED_REG_COUNT]], 23
+// CHECK: [[REG_SAVE_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 3
+// CHECK: [[REG_SAVE_AREA:%[^ ]+]] = load i8*, i8** [[REG_SAVE_AREA_PTR:[^ ]+]]
+// CHECK: [[RAW_REG_ADDR:%[^ ]+]] = getelementptr i8, i8* [[REG_SAVE_AREA]], i64 [[REG_OFFSET]]
+// CHECK: [[REG_ADDR:%[^ ]+]] = bitcast i8* [[RAW_REG_ADDR]] to %struct.agg_1byte*
+// CHECK: [[REG_COUNT1:%[^ ]+]] = add i64 [[REG_COUNT]], 1
+// CHECK: store i64 [[REG_COUNT1]], i64* [[REG_COUNT_PTR]]
+// CHECK: [[OVERFLOW_ARG_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 2
+// CHECK: [[OVERFLOW_ARG_AREA:%[^ ]+]] = load i8*, i8** [[OVERFLOW_ARG_AREA_PTR]]
+// CHECK: [[RAW_MEM_ADDR:%[^ ]+]] = getelementptr i8, i8* [[OVERFLOW_ARG_AREA]], i64 7
+// CHECK: [[MEM_ADDR:%[^ ]+]] = bitcast i8* [[RAW_MEM_ADDR]] to %struct.agg_1byte*
+// CHECK: [[OVERFLOW_ARG_AREA2:%[^ ]+]] = getelementptr i8, i8* [[OVERFLOW_ARG_AREA]], i64 8
+// CHECK: store i8* [[OVERFLOW_ARG_AREA2]], i8** [[OVERFLOW_ARG_AREA_PTR]]
+// CHECK: [[VA_ARG_ADDR:%[^ ]+]] = phi %struct.agg_1byte* [ [[REG_ADDR]], %{{.*}} ], [ [[MEM_ADDR]], %{{.*}} ]
+// CHECK: ret void
+
+struct agg_2byte va_agg_2byte(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_2byte); }
+// CHECK-LABEL: define void @va_agg_2byte(%struct.agg_2byte* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}
+// CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0
+// CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]]
+// CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5
+// CHECK: br i1 [[FITS_IN_REGS]],
+// CHECK: [[SCALED_REG_COUNT:%[^ ]+]] = mul i64 [[REG_COUNT]], 8
+// CHECK: [[REG_OFFSET:%[^ ]+]] = add i64 [[SCALED_REG_COUNT]], 22
+// CHECK: [[REG_SAVE_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 3
+// CHECK: [[REG_SAVE_AREA:%[^ ]+]] = load i8*, i8** [[REG_SAVE_AREA_PTR:[^ ]+]]
+// CHECK: [[RAW_REG_ADDR:%[^ ]+]] = getelementptr i8, i8* [[REG_SAVE_AREA]], i64 [[REG_OFFSET]]
+// CHECK: [[REG_ADDR:%[^ ]+]] = bitcast i8* [[RAW_REG_ADDR]] to %struct.agg_2byte*
+// CHECK: [[REG_COUNT1:%[^ ]+]] = add i64 [[REG_COUNT]], 1
+// CHECK: store i64 [[REG_COUNT1]], i64* [[REG_COUNT_PTR]]
+// CHECK: [[OVERFLOW_ARG_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 2
+// CHECK: [[OVERFLOW_ARG_AREA:%[^ ]+]] = load i8*, i8** [[OVERFLOW_ARG_AREA_PTR]]
+// CHECK: [[RAW_MEM_ADDR:%[^ ]+]] = getelementptr i8, i8* [[OVERFLOW_ARG_AREA]], i64 6
+// CHECK: [[MEM_ADDR:%[^ ]+]] = bitcast i8* [[RAW_MEM_ADDR]] to %struct.agg_2byte*
+// CHECK: [[OVERFLOW_ARG_AREA2:%[^ ]+]] = getelementptr i8, i8* [[OVERFLOW_ARG_AREA]], i64 8
+// CHECK: store i8* [[OVERFLOW_ARG_AREA2]], i8** [[OVERFLOW_ARG_AREA_PTR]]
+// CHECK: [[VA_ARG_ADDR:%[^ ]+]] = phi %struct.agg_2byte* [ [[REG_ADDR]], %{{.*}} ], [ [[MEM_ADDR]], %{{.*}} ]
+// CHECK: ret void
+
+struct agg_3byte va_agg_3byte(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_3byte); }
+// CHECK-LABEL: define void @va_agg_3byte(%struct.agg_3byte* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}
+// CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0
+// CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]]
+// CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5
+// CHECK: br i1 [[FITS_IN_REGS]],
+// CHECK: [[SCALED_REG_COUNT:%[^ ]+]] = mul i64 [[REG_COUNT]], 8
+// CHECK: [[REG_OFFSET:%[^ ]+]] = add i64 [[SCALED_REG_COUNT]], 16
+// CHECK: [[REG_SAVE_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 3
+// CHECK: [[REG_SAVE_AREA:%[^ ]+]] = load i8*, i8** [[REG_SAVE_AREA_PTR:[^ ]+]]
+// CHECK: [[RAW_REG_ADDR:%[^ ]+]] = getelementptr i8, i8* [[REG_SAVE_AREA]], i64 [[REG_OFFSET]]
+// CHECK: [[REG_ADDR:%[^ ]+]] = bitcast i8* [[RAW_REG_ADDR]] to %struct.agg_3byte**
+// CHECK: [[REG_COUNT1:%[^ ]+]] = add i64 [[REG_COUNT]], 1
+// CHECK: store i64 [[REG_COUNT1]], i64* [[REG_COUNT_PTR]]
+// CHECK: [[OVERFLOW_ARG_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 2
+// CHECK: [[OVERFLOW_ARG_AREA:%[^ ]+]] = load i8*, i8** [[OVERFLOW_ARG_AREA_PTR]]
+// CHECK: [[RAW_MEM_ADDR:%[^ ]+]] = getelementptr i8, i8* [[OVERFLOW_ARG_AREA]], i64 0
+// CHECK: [[MEM_ADDR:%[^ ]+]] = bitcast i8* [[RAW_MEM_ADDR]] to %struct.agg_3byte**
+// CHECK: [[OVERFLOW_ARG_AREA2:%[^ ]+]] = getelementptr i8, i8* [[OVERFLOW_ARG_AREA]], i64 8
+// CHECK: store i8* [[OVERFLOW_ARG_AREA2]], i8** [[OVERFLOW_ARG_AREA_PTR]]
+// CHECK: [[VA_ARG_ADDR:%[^ ]+]] = phi %struct.agg_3byte** [ [[REG_ADDR]], %{{.*}} ], [ [[MEM_ADDR]], %{{.*}} ]
+// CHECK: [[INDIRECT_ARG:%[^ ]+]] = load %struct.agg_3byte*, %struct.agg_3byte** [[VA_ARG_ADDR]]
+// CHECK: ret void
+
+struct agg_4byte va_agg_4byte(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_4byte); }
+// CHECK-LABEL: define void @va_agg_4byte(%struct.agg_4byte* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}
+// CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0
+// CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]]
+// CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5
+// CHECK: br i1 [[FITS_IN_REGS]],
+// CHECK: [[SCALED_REG_COUNT:%[^ ]+]] = mul i64 [[REG_COUNT]], 8
+// CHECK: [[REG_OFFSET:%[^ ]+]] = add i64 [[SCALED_REG_COUNT]], 20
+// CHECK: [[REG_SAVE_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 3
+// CHECK: [[REG_SAVE_AREA:%[^ ]+]] = load i8*, i8** [[REG_SAVE_AREA_PTR:[^ ]+]]
+// CHECK: [[RAW_REG_ADDR:%[^ ]+]] = getelementptr i8, i8* [[REG_SAVE_AREA]], i64 [[REG_OFFSET]]
+// CHECK: [[REG_ADDR:%[^ ]+]] = bitcast i8* [[RAW_REG_ADDR]] to %struct.agg_4byte*
+// CHECK: [[REG_COUNT1:%[^ ]+]] = add i64 [[REG_COUNT]], 1
+// CHECK: store i64 [[REG_COUNT1]], i64* [[REG_COUNT_PTR]]
+// CHECK: [[OVERFLOW_ARG_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 2
+// CHECK: [[OVERFLOW_ARG_AREA:%[^ ]+]] = load i8*, i8** [[OVERFLOW_ARG_AREA_PTR]]
+// CHECK: [[RAW_MEM_ADDR:%[^ ]+]] = getelementptr i8, i8* [[OVERFLOW_ARG_AREA]], i64 4
+// CHECK: [[MEM_ADDR:%[^ ]+]] = bitcast i8* [[RAW_MEM_ADDR]] to %struct.agg_4byte*
+// CHECK: [[OVERFLOW_ARG_AREA2:%[^ ]+]] = getelementptr i8, i8* [[OVERFLOW_ARG_AREA]], i64 8
+// CHECK: store i8* [[OVERFLOW_ARG_AREA2]], i8** [[OVERFLOW_ARG_AREA_PTR]]
+// CHECK: [[VA_ARG_ADDR:%[^ ]+]] = phi %struct.agg_4byte* [ [[REG_ADDR]], %{{.*}} ], [ [[MEM_ADDR]], %{{.*}} ]
+// CHECK: ret void
+
+struct agg_8byte va_agg_8byte(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_8byte); }
+// CHECK-LABEL: define void @va_agg_8byte(%struct.agg_8byte* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}
+// CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0
+// CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]]
+// CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5
+// CHECK: br i1 [[FITS_IN_REGS]],
+// CHECK: [[SCALED_REG_COUNT:%[^ ]+]] = mul i64 [[REG_COUNT]], 8
+// CHECK: [[REG_OFFSET:%[^ ]+]] = add i64 [[SCALED_REG_COUNT]], 16
+// CHECK: [[REG_SAVE_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 3
+// CHECK: [[REG_SAVE_AREA:%[^ ]+]] = load i8*, i8** [[REG_SAVE_AREA_PTR:[^ ]+]]
+// CHECK: [[RAW_REG_ADDR:%[^ ]+]] = getelementptr i8, i8* [[REG_SAVE_AREA]], i64 [[REG_OFFSET]]
+// CHECK: [[REG_ADDR:%[^ ]+]] = bitcast i8* [[RAW_REG_ADDR]] to %struct.agg_8byte*
+// CHECK: [[REG_COUNT1:%[^ ]+]] = add i64 [[REG_COUNT]], 1
+// CHECK: store i64 [[REG_COUNT1]], i64* [[REG_COUNT_PTR]]
+// CHECK: [[OVERFLOW_ARG_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 2
+// CHECK: [[OVERFLOW_ARG_AREA:%[^ ]+]] = load i8*, i8** [[OVERFLOW_ARG_AREA_PTR]]
+// CHECK: [[RAW_MEM_ADDR:%[^ ]+]] = getelementptr i8, i8* [[OVERFLOW_ARG_AREA]], i64 0
+// CHECK: [[MEM_ADDR:%[^ ]+]] = bitcast i8* [[RAW_MEM_ADDR]] to %struct.agg_8byte*
+// CHECK: [[OVERFLOW_ARG_AREA2:%[^ ]+]] = getelementptr i8, i8* [[OVERFLOW_ARG_AREA]], i64 8
+// CHECK: store i8* [[OVERFLOW_ARG_AREA2]], i8** [[OVERFLOW_ARG_AREA_PTR]]
+// CHECK: [[VA_ARG_ADDR:%[^ ]+]] = phi %struct.agg_8byte* [ [[REG_ADDR]], %{{.*}} ], [ [[MEM_ADDR]], %{{.*}} ]
+// CHECK: ret void
+
+struct agg_float va_agg_float(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_float); }
+// CHECK-LABEL: define void @va_agg_float(%struct.agg_float* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}
+// CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 1
+// CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]]
+// CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 4
+// CHECK: br i1 [[FITS_IN_REGS]],
+// CHECK: [[SCALED_REG_COUNT:%[^ ]+]] = mul i64 [[REG_COUNT]], 8
+// CHECK: [[REG_OFFSET:%[^ ]+]] = add i64 [[SCALED_REG_COUNT]], 128
+// CHECK: [[REG_SAVE_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 3
+// CHECK: [[REG_SAVE_AREA:%[^ ]+]] = load i8*, i8** [[REG_SAVE_AREA_PTR:[^ ]+]]
+// CHECK: [[RAW_REG_ADDR:%[^ ]+]] = getelementptr i8, i8* [[REG_SAVE_AREA]], i64 [[REG_OFFSET]]
+// CHECK: [[REG_ADDR:%[^ ]+]] = bitcast i8* [[RAW_REG_ADDR]] to %struct.agg_float*
+// CHECK: [[REG_COUNT1:%[^ ]+]] = add i64 [[REG_COUNT]], 1
+// CHECK: store i64 [[REG_COUNT1]], i64* [[REG_COUNT_PTR]]
+// CHECK: [[OVERFLOW_ARG_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 2
+// CHECK: [[OVERFLOW_ARG_AREA:%[^ ]+]] = load i8*, i8** [[OVERFLOW_ARG_AREA_PTR]]
+// CHECK: [[RAW_MEM_ADDR:%[^ ]+]] = getelementptr i8, i8* [[OVERFLOW_ARG_AREA]], i64 4
+// CHECK: [[MEM_ADDR:%[^ ]+]] = bitcast i8* [[RAW_MEM_ADDR]] to %struct.agg_float*
+// CHECK: [[OVERFLOW_ARG_AREA2:%[^ ]+]] = getelementptr i8, i8* [[OVERFLOW_ARG_AREA]], i64 8
+// CHECK: store i8* [[OVERFLOW_ARG_AREA2]], i8** [[OVERFLOW_ARG_AREA_PTR]]
+// CHECK: [[VA_ARG_ADDR:%[^ ]+]] = phi %struct.agg_float* [ [[REG_ADDR]], %{{.*}} ], [ [[MEM_ADDR]], %{{.*}} ]
+// CHECK: ret void
+
+struct agg_double va_agg_double(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_double); }
+// CHECK-LABEL: define void @va_agg_double(%struct.agg_double* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}
+// CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 1
+// CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]]
+// CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 4
+// CHECK: br i1 [[FITS_IN_REGS]],
+// CHECK: [[SCALED_REG_COUNT:%[^ ]+]] = mul i64 [[REG_COUNT]], 8
+// CHECK: [[REG_OFFSET:%[^ ]+]] = add i64 [[SCALED_REG_COUNT]], 128
+// CHECK: [[REG_SAVE_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 3
+// CHECK: [[REG_SAVE_AREA:%[^ ]+]] = load i8*, i8** [[REG_SAVE_AREA_PTR:[^ ]+]]
+// CHECK: [[RAW_REG_ADDR:%[^ ]+]] = getelementptr i8, i8* [[REG_SAVE_AREA]], i64 [[REG_OFFSET]]
+// CHECK: [[REG_ADDR:%[^ ]+]] = bitcast i8* [[RAW_REG_ADDR]] to %struct.agg_double*
+// CHECK: [[REG_COUNT1:%[^ ]+]] = add i64 [[REG_COUNT]], 1
+// CHECK: store i64 [[REG_COUNT1]], i64* [[REG_COUNT_PTR]]
+// CHECK: [[OVERFLOW_ARG_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 2
+// CHECK: [[OVERFLOW_ARG_AREA:%[^ ]+]] = load i8*, i8** [[OVERFLOW_ARG_AREA_PTR]]
+// CHECK: [[RAW_MEM_ADDR:%[^ ]+]] = getelementptr i8, i8* [[OVERFLOW_ARG_AREA]], i64 0
+// CHECK: [[MEM_ADDR:%[^ ]+]] = bitcast i8* [[RAW_MEM_ADDR]] to %struct.agg_double*
+// CHECK: [[OVERFLOW_ARG_AREA2:%[^ ]+]] = getelementptr i8, i8* [[OVERFLOW_ARG_AREA]], i64 8
+// CHECK: store i8* [[OVERFLOW_ARG_AREA2]], i8** [[OVERFLOW_ARG_AREA_PTR]]
+// CHECK: [[VA_ARG_ADDR:%[^ ]+]] = phi %struct.agg_double* [ [[REG_ADDR]], %{{.*}} ], [ [[MEM_ADDR]], %{{.*}} ]
+// CHECK: ret void
+
+struct agg_longdouble va_agg_longdouble(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_longdouble); }
+// CHECK-LABEL: define void @va_agg_longdouble(%struct.agg_longdouble* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}
+// CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0
+// CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]]
+// CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5
+// CHECK: br i1 [[FITS_IN_REGS]],
+// CHECK: [[SCALED_REG_COUNT:%[^ ]+]] = mul i64 [[REG_COUNT]], 8
+// CHECK: [[REG_OFFSET:%[^ ]+]] = add i64 [[SCALED_REG_COUNT]], 16
+// CHECK: [[REG_SAVE_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 3
+// CHECK: [[REG_SAVE_AREA:%[^ ]+]] = load i8*, i8** [[REG_SAVE_AREA_PTR:[^ ]+]]
+// CHECK: [[RAW_REG_ADDR:%[^ ]+]] = getelementptr i8, i8* [[REG_SAVE_AREA]], i64 [[REG_OFFSET]]
+// CHECK: [[REG_ADDR:%[^ ]+]] = bitcast i8* [[RAW_REG_ADDR]] to %struct.agg_longdouble**
+// CHECK: [[REG_COUNT1:%[^ ]+]] = add i64 [[REG_COUNT]], 1
+// CHECK: store i64 [[REG_COUNT1]], i64* [[REG_COUNT_PTR]]
+// CHECK: [[OVERFLOW_ARG_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 2
+// CHECK: [[OVERFLOW_ARG_AREA:%[^ ]+]] = load i8*, i8** [[OVERFLOW_ARG_AREA_PTR]]
+// CHECK: [[RAW_MEM_ADDR:%[^ ]+]] = getelementptr i8, i8* [[OVERFLOW_ARG_AREA]], i64 0
+// CHECK: [[MEM_ADDR:%[^ ]+]] = bitcast i8* [[RAW_MEM_ADDR]] to %struct.agg_longdouble**
+// CHECK: [[OVERFLOW_ARG_AREA2:%[^ ]+]] = getelementptr i8, i8* [[OVERFLOW_ARG_AREA]], i64 8
+// CHECK: store i8* [[OVERFLOW_ARG_AREA2]], i8** [[OVERFLOW_ARG_AREA_PTR]]
+// CHECK: [[VA_ARG_ADDR:%[^ ]+]] = phi %struct.agg_longdouble** [ [[REG_ADDR]], %{{.*}} ], [ [[MEM_ADDR]], %{{.*}} ]
+// CHECK: [[INDIRECT_ARG:%[^ ]+]] = load %struct.agg_longdouble*, %struct.agg_longdouble** [[VA_ARG_ADDR]]
+// CHECK: ret void
+
+struct agg_float_a8 va_agg_float_a8(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_float_a8); }
+// CHECK-LABEL: define void @va_agg_float_a8(%struct.agg_float_a8* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}
+// CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 1
+// CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]]
+// CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 4
+// CHECK: br i1 [[FITS_IN_REGS]],
+// CHECK: [[SCALED_REG_COUNT:%[^ ]+]] = mul i64 [[REG_COUNT]], 8
+// CHECK: [[REG_OFFSET:%[^ ]+]] = add i64 [[SCALED_REG_COUNT]], 128
+// CHECK: [[REG_SAVE_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 3
+// CHECK: [[REG_SAVE_AREA:%[^ ]+]] = load i8*, i8** [[REG_SAVE_AREA_PTR:[^ ]+]]
+// CHECK: [[RAW_REG_ADDR:%[^ ]+]] = getelementptr i8, i8* [[REG_SAVE_AREA]], i64 [[REG_OFFSET]]
+// CHECK: [[REG_ADDR:%[^ ]+]] = bitcast i8* [[RAW_REG_ADDR]] to %struct.agg_float_a8*
+// CHECK: [[REG_COUNT1:%[^ ]+]] = add i64 [[REG_COUNT]], 1
+// CHECK: store i64 [[REG_COUNT1]], i64* [[REG_COUNT_PTR]]
+// CHECK: [[OVERFLOW_ARG_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 2
+// CHECK: [[OVERFLOW_ARG_AREA:%[^ ]+]] = load i8*, i8** [[OVERFLOW_ARG_AREA_PTR]]
+// CHECK: [[RAW_MEM_ADDR:%[^ ]+]] = getelementptr i8, i8* [[OVERFLOW_ARG_AREA]], i64 0
+// CHECK: [[MEM_ADDR:%[^ ]+]] = bitcast i8* [[RAW_MEM_ADDR]] to %struct.agg_float_a8*
+// CHECK: [[OVERFLOW_ARG_AREA2:%[^ ]+]] = getelementptr i8, i8* [[OVERFLOW_ARG_AREA]], i64 8
+// CHECK: store i8* [[OVERFLOW_ARG_AREA2]], i8** [[OVERFLOW_ARG_AREA_PTR]]
+// CHECK: [[VA_ARG_ADDR:%[^ ]+]] = phi %struct.agg_float_a8* [ [[REG_ADDR]], %{{.*}} ], [ [[MEM_ADDR]], %{{.*}} ]
+// CHECK: ret void
+
+struct agg_float_a16 va_agg_float_a16(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_float_a16); }
+// CHECK-LABEL: define void @va_agg_float_a16(%struct.agg_float_a16* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}
+// CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0
+// CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]]
+// CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5
+// CHECK: br i1 [[FITS_IN_REGS]],
+// CHECK: [[SCALED_REG_COUNT:%[^ ]+]] = mul i64 [[REG_COUNT]], 8
+// CHECK: [[REG_OFFSET:%[^ ]+]] = add i64 [[SCALED_REG_COUNT]], 16
+// CHECK: [[REG_SAVE_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 3
+// CHECK: [[REG_SAVE_AREA:%[^ ]+]] = load i8*, i8** [[REG_SAVE_AREA_PTR:[^ ]+]]
+// CHECK: [[RAW_REG_ADDR:%[^ ]+]] = getelementptr i8, i8* [[REG_SAVE_AREA]], i64 [[REG_OFFSET]]
+// CHECK: [[REG_ADDR:%[^ ]+]] = bitcast i8* [[RAW_REG_ADDR]] to %struct.agg_float_a16**
+// CHECK: [[REG_COUNT1:%[^ ]+]] = add i64 [[REG_COUNT]], 1
+// CHECK: store i64 [[REG_COUNT1]], i64* [[REG_COUNT_PTR]]
+// CHECK: [[OVERFLOW_ARG_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 2
+// CHECK: [[OVERFLOW_ARG_AREA:%[^ ]+]] = load i8*, i8** [[OVERFLOW_ARG_AREA_PTR]]
+// CHECK: [[RAW_MEM_ADDR:%[^ ]+]] = getelementptr i8, i8* [[OVERFLOW_ARG_AREA]], i64 0
+// CHECK: [[MEM_ADDR:%[^ ]+]] = bitcast i8* [[RAW_MEM_ADDR]] to %struct.agg_float_a16**
+// CHECK: [[OVERFLOW_ARG_AREA2:%[^ ]+]] = getelementptr i8, i8* [[OVERFLOW_ARG_AREA]], i64 8
+// CHECK: store i8* [[OVERFLOW_ARG_AREA2]], i8** [[OVERFLOW_ARG_AREA_PTR]]
+// CHECK: [[VA_ARG_ADDR:%[^ ]+]] = phi %struct.agg_float_a16** [ [[REG_ADDR]], %{{.*}} ], [ [[MEM_ADDR]], %{{.*}} ]
+// CHECK: [[INDIRECT_ARG:%[^ ]+]] = load %struct.agg_float_a16*, %struct.agg_float_a16** [[VA_ARG_ADDR]]
+// CHECK: ret void
+
+struct agg_nofloat1 va_agg_nofloat1(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_nofloat1); }
+// CHECK-LABEL: define void @va_agg_nofloat1(%struct.agg_nofloat1* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}
+// CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0
+// CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]]
+// CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5
+// CHECK: br i1 [[FITS_IN_REGS]],
+// CHECK: [[SCALED_REG_COUNT:%[^ ]+]] = mul i64 [[REG_COUNT]], 8
+// CHECK: [[REG_OFFSET:%[^ ]+]] = add i64 [[SCALED_REG_COUNT]], 16
+// CHECK: [[REG_SAVE_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 3
+// CHECK: [[REG_SAVE_AREA:%[^ ]+]] = load i8*, i8** [[REG_SAVE_AREA_PTR:[^ ]+]]
+// CHECK: [[RAW_REG_ADDR:%[^ ]+]] = getelementptr i8, i8* [[REG_SAVE_AREA]], i64 [[REG_OFFSET]]
+// CHECK: [[REG_ADDR:%[^ ]+]] = bitcast i8* [[RAW_REG_ADDR]] to %struct.agg_nofloat1*
+// CHECK: [[REG_COUNT1:%[^ ]+]] = add i64 [[REG_COUNT]], 1
+// CHECK: store i64 [[REG_COUNT1]], i64* [[REG_COUNT_PTR]]
+// CHECK: [[OVERFLOW_ARG_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 2
+// CHECK: [[OVERFLOW_ARG_AREA:%[^ ]+]] = load i8*, i8** [[OVERFLOW_ARG_AREA_PTR]]
+// CHECK: [[RAW_MEM_ADDR:%[^ ]+]] = getelementptr i8, i8* [[OVERFLOW_ARG_AREA]], i64 0
+// CHECK: [[MEM_ADDR:%[^ ]+]] = bitcast i8* [[RAW_MEM_ADDR]] to %struct.agg_nofloat1*
+// CHECK: [[OVERFLOW_ARG_AREA2:%[^ ]+]] = getelementptr i8, i8* [[OVERFLOW_ARG_AREA]], i64 8
+// CHECK: store i8* [[OVERFLOW_ARG_AREA2]], i8** [[OVERFLOW_ARG_AREA_PTR]]
+// CHECK: [[VA_ARG_ADDR:%[^ ]+]] = phi %struct.agg_nofloat1* [ [[REG_ADDR]], %{{.*}} ], [ [[MEM_ADDR]], %{{.*}} ]
+// CHECK: ret void
+
+struct agg_nofloat2 va_agg_nofloat2(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_nofloat2); }
+// CHECK-LABEL: define void @va_agg_nofloat2(%struct.agg_nofloat2* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}
+// CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0
+// CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]]
+// CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5
+// CHECK: br i1 [[FITS_IN_REGS]],
+// CHECK: [[SCALED_REG_COUNT:%[^ ]+]] = mul i64 [[REG_COUNT]], 8
+// CHECK: [[REG_OFFSET:%[^ ]+]] = add i64 [[SCALED_REG_COUNT]], 16
+// CHECK: [[REG_SAVE_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 3
+// CHECK: [[REG_SAVE_AREA:%[^ ]+]] = load i8*, i8** [[REG_SAVE_AREA_PTR:[^ ]+]]
+// CHECK: [[RAW_REG_ADDR:%[^ ]+]] = getelementptr i8, i8* [[REG_SAVE_AREA]], i64 [[REG_OFFSET]]
+// CHECK: [[REG_ADDR:%[^ ]+]] = bitcast i8* [[RAW_REG_ADDR]] to %struct.agg_nofloat2*
+// CHECK: [[REG_COUNT1:%[^ ]+]] = add i64 [[REG_COUNT]], 1
+// CHECK: store i64 [[REG_COUNT1]], i64* [[REG_COUNT_PTR]]
+// CHECK: [[OVERFLOW_ARG_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 2
+// CHECK: [[OVERFLOW_ARG_AREA:%[^ ]+]] = load i8*, i8** [[OVERFLOW_ARG_AREA_PTR]]
+// CHECK: [[RAW_MEM_ADDR:%[^ ]+]] = getelementptr i8, i8* [[OVERFLOW_ARG_AREA]], i64 0
+// CHECK: [[MEM_ADDR:%[^ ]+]] = bitcast i8* [[RAW_MEM_ADDR]] to %struct.agg_nofloat2*
+// CHECK: [[OVERFLOW_ARG_AREA2:%[^ ]+]] = getelementptr i8, i8* [[OVERFLOW_ARG_AREA]], i64 8
+// CHECK: store i8* [[OVERFLOW_ARG_AREA2]], i8** [[OVERFLOW_ARG_AREA_PTR]]
+// CHECK: [[VA_ARG_ADDR:%[^ ]+]] = phi %struct.agg_nofloat2* [ [[REG_ADDR]], %{{.*}} ], [ [[MEM_ADDR]], %{{.*}} ]
+// CHECK: ret void
+
+struct agg_nofloat3 va_agg_nofloat3(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_nofloat3); }
+// CHECK-LABEL: define void @va_agg_nofloat3(%struct.agg_nofloat3* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}
+// CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0
+// CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]]
+// CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5
+// CHECK: br i1 [[FITS_IN_REGS]],
+// CHECK: [[SCALED_REG_COUNT:%[^ ]+]] = mul i64 [[REG_COUNT]], 8
+// CHECK: [[REG_OFFSET:%[^ ]+]] = add i64 [[SCALED_REG_COUNT]], 20
+// CHECK: [[REG_SAVE_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 3
+// CHECK: [[REG_SAVE_AREA:%[^ ]+]] = load i8*, i8** [[REG_SAVE_AREA_PTR:[^ ]+]]
+// CHECK: [[RAW_REG_ADDR:%[^ ]+]] = getelementptr i8, i8* [[REG_SAVE_AREA]], i64 [[REG_OFFSET]]
+// CHECK: [[REG_ADDR:%[^ ]+]] = bitcast i8* [[RAW_REG_ADDR]] to %struct.agg_nofloat3*
+// CHECK: [[REG_COUNT1:%[^ ]+]] = add i64 [[REG_COUNT]], 1
+// CHECK: store i64 [[REG_COUNT1]], i64* [[REG_COUNT_PTR]]
+// CHECK: [[OVERFLOW_ARG_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 2
+// CHECK: [[OVERFLOW_ARG_AREA:%[^ ]+]] = load i8*, i8** [[OVERFLOW_ARG_AREA_PTR]]
+// CHECK: [[RAW_MEM_ADDR:%[^ ]+]] = getelementptr i8, i8* [[OVERFLOW_ARG_AREA]], i64 4
+// CHECK: [[MEM_ADDR:%[^ ]+]] = bitcast i8* [[RAW_MEM_ADDR]] to %struct.agg_nofloat3*
+// CHECK: [[OVERFLOW_ARG_AREA2:%[^ ]+]] = getelementptr i8, i8* [[OVERFLOW_ARG_AREA]], i64 8
+// CHECK: store i8* [[OVERFLOW_ARG_AREA2]], i8** [[OVERFLOW_ARG_AREA_PTR]]
+// CHECK: [[VA_ARG_ADDR:%[^ ]+]] = phi %struct.agg_nofloat3* [ [[REG_ADDR]], %{{.*}} ], [ [[MEM_ADDR]], %{{.*}} ]
+// CHECK: ret void
+
diff --git a/test/CodeGen/systemz-abi.cpp b/test/CodeGen/systemz-abi.cpp
new file mode 100644
index 0000000..0249e9f
--- /dev/null
+++ b/test/CodeGen/systemz-abi.cpp
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -triple s390x-linux-gnu -emit-llvm -x c++ -o - %s | FileCheck %s
+
+// For compatibility with GCC, this structure is passed in an FPR in C++,
+// but passed in a GPR in C (checked in systemz-abi.c).
+
+struct agg_float_cpp { float a; int : 0; };
+struct agg_float_cpp pass_agg_float_cpp(struct agg_float_cpp arg) { return arg; }
+// CHECK-LABEL: define void @_Z18pass_agg_float_cpp13agg_float_cpp(%struct.agg_float_cpp* noalias sret %{{.*}}, float %{{.*}})
+
diff --git a/test/CodeGen/target-data.c b/test/CodeGen/target-data.c
index 4cb7176..05fe7de 100644
--- a/test/CodeGen/target-data.c
+++ b/test/CodeGen/target-data.c
@@ -66,7 +66,7 @@
// RUN: FileCheck %s -check-prefix=X86_64-NACL
// X86_64-NACL: target datalayout = "e-m:e-p:32:32-i64:64-n8:16:32:64-S128"
-// RUN: %clang_cc1 -triple arm-nacl-gnueabi -o - -emit-llvm %s | \
+// RUN: %clang_cc1 -triple arm-nacl -o - -emit-llvm %s | \
// RUN: FileCheck %s -check-prefix=ARM-NACL
// ARM-NACL: target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S128"
diff --git a/test/CodeGen/variadic-null-win64.c b/test/CodeGen/variadic-null-win64.c
index 4f57e7b..3e079cb 100644
--- a/test/CodeGen/variadic-null-win64.c
+++ b/test/CodeGen/variadic-null-win64.c
@@ -12,6 +12,6 @@
v(f, 1, 2, 3, NULL);
}
// WINDOWS: define void @f(i8* %f)
-// WINDOWS: call void (i8*, ...)* @v(i8* {{.*}}, i32 1, i32 2, i32 3, i64 0)
+// WINDOWS: call void (i8*, ...) @v(i8* {{.*}}, i32 1, i32 2, i32 3, i64 0)
// LINUX: define void @f(i8* %f)
-// LINUX: call void (i8*, ...)* @v(i8* {{.*}}, i32 1, i32 2, i32 3, i32 0)
+// LINUX: call void (i8*, ...) @v(i8* {{.*}}, i32 1, i32 2, i32 3, i32 0)
diff --git a/test/CodeGen/x86_32-arguments-darwin.c b/test/CodeGen/x86_32-arguments-darwin.c
index 422e030..1536631 100644
--- a/test/CodeGen/x86_32-arguments-darwin.c
+++ b/test/CodeGen/x86_32-arguments-darwin.c
@@ -236,7 +236,7 @@
// CHECK: <8 x i32> %a10, %struct.s56_5* byval align 4,
// CHECK: <4 x double> %a12, %struct.s56_6* byval align 4)
-// CHECK: call void (i32, ...)* @f56_0(i32 1,
+// CHECK: call void (i32, ...) @f56_0(i32 1,
// CHECK: i32 %{{[^ ]*}}, %struct.s56_0* byval align 4 %{{[^ ]*}},
// CHECK: i64 %{{[^ ]*}}, %struct.s56_1* byval align 4 %{{[^ ]*}},
// CHECK: i64 %{{[^ ]*}}, %struct.s56_2* byval align 4 %{{[^ ]*}},
diff --git a/test/CodeGen/x86_32-arguments-linux.c b/test/CodeGen/x86_32-arguments-linux.c
index 1a8c600..02eac51 100644
--- a/test/CodeGen/x86_32-arguments-linux.c
+++ b/test/CodeGen/x86_32-arguments-linux.c
@@ -10,7 +10,7 @@
// CHECK: <8 x i32> %a10, %struct.s56_5* byval align 4,
// CHECK: <4 x double> %a12, %struct.s56_6* byval align 4)
-// CHECK: call void (i32, ...)* @f56_0(i32 1,
+// CHECK: call void (i32, ...) @f56_0(i32 1,
// CHECK: i32 %{{.*}}, %struct.s56_0* byval align 4 %{{[^ ]*}},
// CHECK: i64 %{{[^ ]*}}, %struct.s56_1* byval align 4 %{{[^ ]*}},
// CHECK: <1 x double> %{{[^ ]*}}, %struct.s56_2* byval align 4 %{{[^ ]*}},
diff --git a/test/CodeGen/x86_64-arguments.c b/test/CodeGen/x86_64-arguments.c
index a0e30c6..f52629c 100644
--- a/test/CodeGen/x86_64-arguments.c
+++ b/test/CodeGen/x86_64-arguments.c
@@ -404,7 +404,7 @@
// CHECK-LABEL: define void @test49(
// CHECK: [[T0:%.*]] = load double, double*
// CHECK-NEXT: [[T1:%.*]] = load double, double*
-// CHECK-NEXT: call void (double, ...)* @test49_helper(double [[T0]], double [[T1]])
+// CHECK-NEXT: call void (double, ...) @test49_helper(double [[T0]], double [[T1]])
void test50_helper();
void test50(double d, double e) {
@@ -413,7 +413,7 @@
// CHECK-LABEL: define void @test50(
// CHECK: [[T0:%.*]] = load double, double*
// CHECK-NEXT: [[T1:%.*]] = load double, double*
-// CHECK-NEXT: call void (double, double, ...)* bitcast (void (...)* @test50_helper to void (double, double, ...)*)(double [[T0]], double [[T1]])
+// CHECK-NEXT: call void (double, double, ...) bitcast (void (...)* @test50_helper to void (double, double, ...)*)(double [[T0]], double [[T1]])
struct test51_s { __uint128_t intval; };
void test51(struct test51_s *s, __builtin_va_list argList) {
diff --git a/test/CodeGenCXX/auto-variable-template.cpp b/test/CodeGenCXX/auto-variable-template.cpp
new file mode 100644
index 0000000..265d81d
--- /dev/null
+++ b/test/CodeGenCXX/auto-variable-template.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -std=c++14 %s -triple=x86_64-linux -emit-llvm -o - | FileCheck %s
+
+struct f {
+ void operator()() const {}
+};
+
+template <typename T> auto vtemplate = f{};
+
+int main() { vtemplate<int>(); }
+
+// CHECK: @_Z9vtemplateIiE = linkonce_odr global %struct.f undef, comdat
+
+// CHECK: define i32 @main()
+// CHECK: call void @_ZNK1fclEv(%struct.f* @_Z9vtemplateIiE)
diff --git a/test/CodeGenCXX/call-with-static-chain.cpp b/test/CodeGenCXX/call-with-static-chain.cpp
index 7cf9291..ac1149b 100644
--- a/test/CodeGenCXX/call-with-static-chain.cpp
+++ b/test/CodeGenCXX/call-with-static-chain.cpp
@@ -21,7 +21,7 @@
void test() {
A a;
- // CHECK32: call i32 bitcast (i32 (%struct.A*, %struct.A*, %struct.A*, %struct.A*)* @f1 to i32 (i8*, %struct.A*, %struct.A*, %struct.A*, %struct.A*)*)(i8* nest bitcast (i32 (%struct.A*, %struct.A*, %struct.A*, %struct.A*)* @f1 to i8*)
+ // CHECK32: call i32 bitcast (i32 (i32, i32, i32, i32, i32, i32, i32, i32)* @f1 to i32 (i8*, i32, i32, i32, i32, i32, i32, i32, i32)*)(i8* nest bitcast (i32 (i32, i32, i32, i32, i32, i32, i32, i32)* @f1 to i8*)
// CHECK64: call i32 bitcast (i32 (i64, i64, i64, i64, i64, i64, %struct.A*)* @f1 to i32 (i8*, i64, i64, i64, i64, i64, i64, %struct.A*)*)(i8* nest bitcast (i32 (i64, i64, i64, i64, i64, i64, %struct.A*)* @f1 to i8*)
__builtin_call_with_static_chain(f1(a, a, a, a), f1);
diff --git a/test/CodeGenCXX/cfi-nvcall.cpp b/test/CodeGenCXX/cfi-nvcall.cpp
new file mode 100644
index 0000000..b0db478
--- /dev/null
+++ b/test/CodeGenCXX/cfi-nvcall.cpp
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux -fsanitize=cfi-nvcall -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux -fsanitize=cfi-nvcall,cfi-cast-strict -emit-llvm -o - %s | FileCheck --check-prefix=CHECK-STRICT %s
+
+struct A {
+ virtual void f();
+};
+
+struct B : A {
+ int i;
+ void g();
+};
+
+struct C : A {
+ void g();
+};
+
+// CHECK-LABEL: @bg
+// CHECK-STRICT-LABEL: @bg
+extern "C" void bg(B *b) {
+ // CHECK: call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"1B")
+ // CHECK-STRICT: call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"1B")
+ b->g();
+}
+
+// CHECK-LABEL: @cg
+// CHECK-STRICT-LABEL: @cg
+extern "C" void cg(C *c) {
+ // http://clang.llvm.org/docs/ControlFlowIntegrity.html#strictness
+ // In this case C's layout is the same as its base class, so we allow
+ // c to be of type A in non-strict mode.
+
+ // CHECK: call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"1A")
+ // CHECK-STRICT: call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"1C")
+ c->g();
+}
diff --git a/test/CodeGenCXX/cfi-vptr.cpp b/test/CodeGenCXX/cfi-vcall.cpp
similarity index 88%
rename from test/CodeGenCXX/cfi-vptr.cpp
rename to test/CodeGenCXX/cfi-vcall.cpp
index 545f22c..bfbbcea 100644
--- a/test/CodeGenCXX/cfi-vptr.cpp
+++ b/test/CodeGenCXX/cfi-vcall.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-unknown-linux -fsanitize=cfi-vptr -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux -fsanitize=cfi-vcall -emit-llvm -o - %s | FileCheck %s
struct A {
A();
@@ -49,7 +49,7 @@
// CHECK: define internal void @_Z2dfPN12_GLOBAL__N_11DE
void df(D *d) {
- // CHECK: {{%[^ ]*}} = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"[{{.*}}cfi-vptr.cpp]N12_GLOBAL__N_11DE")
+ // CHECK: {{%[^ ]*}} = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"[{{.*}}cfi-vcall.cpp]N12_GLOBAL__N_11DE")
d->f();
}
@@ -67,7 +67,7 @@
// CHECK-DAG: !{!"1A", [10 x i8*]* @_ZTVN12_GLOBAL__N_11DE, i64 32}
// CHECK-DAG: !{!"1B", [10 x i8*]* @_ZTVN12_GLOBAL__N_11DE, i64 32}
// CHECK-DAG: !{!"1C", [10 x i8*]* @_ZTVN12_GLOBAL__N_11DE, i64 72}
-// CHECK-DAG: !{!"[{{.*}}cfi-vptr.cpp]N12_GLOBAL__N_11DE", [10 x i8*]* @_ZTVN12_GLOBAL__N_11DE, i64 32}
+// CHECK-DAG: !{!"[{{.*}}cfi-vcall.cpp]N12_GLOBAL__N_11DE", [10 x i8*]* @_ZTVN12_GLOBAL__N_11DE, i64 32}
// CHECK-DAG: !{!"1A", [5 x i8*]* @_ZTV1B, i64 32}
// CHECK-DAG: !{!"1B", [5 x i8*]* @_ZTV1B, i64 32}
// CHECK-DAG: !{!"1A", [5 x i8*]* @_ZTV1C, i64 32}
diff --git a/test/CodeGenCXX/compound-literals.cpp b/test/CodeGenCXX/compound-literals.cpp
index 4f8cf10..ce7d047 100644
--- a/test/CodeGenCXX/compound-literals.cpp
+++ b/test/CodeGenCXX/compound-literals.cpp
@@ -28,7 +28,7 @@
// CHECK-LABEL: define i32 @_Z1gv()
int g() {
- // CHECK: store [2 x i32]* @{{.*}}, [2 x i32]** [[V:%[a-z0-9.]+]]
+ // CHECK: store [2 x i32]* %{{[a-z0-9.]+}}, [2 x i32]** [[V:%[a-z0-9.]+]]
const int (&v)[2] = (int [2]) {1,2};
// CHECK: [[A:%[a-z0-9.]+]] = load [2 x i32]*, [2 x i32]** [[V]]
diff --git a/test/CodeGenCXX/conditional-gnu-ext.cpp b/test/CodeGenCXX/conditional-gnu-ext.cpp
index 174c67b..b073e0c 100644
--- a/test/CodeGenCXX/conditional-gnu-ext.cpp
+++ b/test/CodeGenCXX/conditional-gnu-ext.cpp
@@ -5,7 +5,7 @@
extern "C" int printf(...);
void test0() {
-// CHECK: call i32 (...)* @printf({{.*}}, i8* inttoptr (i64 3735928559 to i8*))
+// CHECK: call i32 (...) @printf({{.*}}, i8* inttoptr (i64 3735928559 to i8*))
printf("%p\n", (void *)0xdeadbeef ? : (void *)0xaaaaaa);
}
diff --git a/test/CodeGenCXX/convert-to-fptr.cpp b/test/CodeGenCXX/convert-to-fptr.cpp
index c3be962..283493e 100644
--- a/test/CodeGenCXX/convert-to-fptr.cpp
+++ b/test/CodeGenCXX/convert-to-fptr.cpp
@@ -38,5 +38,5 @@
return 0;
}
-// CHECK: call i32 (i32)* (%struct.A*)* @_ZN1AcvPFiiEEv
-// CHECK: call i32 (i32)* (%struct.B*)* @_ZN1BcvRFiiEEv
+// CHECK: call i32 (i32)* @_ZN1AcvPFiiEEv
+// CHECK: call i32 (i32)* @_ZN1BcvRFiiEEv
diff --git a/test/CodeGenCXX/cxx0x-initializer-references.cpp b/test/CodeGenCXX/cxx0x-initializer-references.cpp
index d4a8f20..318c8ea 100644
--- a/test/CodeGenCXX/cxx0x-initializer-references.cpp
+++ b/test/CodeGenCXX/cxx0x-initializer-references.cpp
@@ -79,3 +79,33 @@
}
}
+
+namespace PR23165 {
+struct AbstractClass {
+ virtual void foo() const = 0;
+};
+
+struct ChildClass : public AbstractClass {
+ virtual void foo() const {}
+};
+
+void helper(const AbstractClass ¶m) {
+ param.foo();
+}
+
+void foo() {
+// CHECK-LABEL: @_ZN7PR231653fooEv
+// CHECK: call {{.*}} @_ZN7PR2316510ChildClassC1Ev
+// CHECK: call void @_ZN7PR231656helperERKNS_13AbstractClassE
+ helper(ChildClass());
+}
+
+struct S { struct T { int a; } t; mutable int b; };
+void f() {
+// CHECK-LABEL: _ZN7PR231651fEv
+// CHECK: alloca
+// CHECK: alloca
+// CHECK: store
+ const S::T &r = S().t;
+}
+}
diff --git a/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp b/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp
index 1131ca9..6d5d397 100644
--- a/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp
+++ b/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp
@@ -510,7 +510,7 @@
void PR22940_helper(const pair<void*, int>&) { }
void PR22940() {
// CHECK-LABEL: @_ZN9B197730107PR22940Ev
- // CHECK-NOT: call {{.*}} @_ZN9B197730104pairIPviEC{{.}}Ev(
+ // CHECK: call {{.*}} @_ZN9B197730104pairIPviEC{{.}}Ev(
// CHECK: call {{.*}} @_ZN9B1977301014PR22940_helperERKNS_4pairIPviEE(
PR22940_helper(pair<void*, int>());
}
diff --git a/test/CodeGenCXX/dllexport.cpp b/test/CodeGenCXX/dllexport.cpp
index c6ab232..b7bd675 100644
--- a/test/CodeGenCXX/dllexport.cpp
+++ b/test/CodeGenCXX/dllexport.cpp
@@ -490,7 +490,7 @@
// M32-DAG: %[[this_addr:.*]] = alloca %struct.CtorWithClosure*, align 4
// M32-DAG: store %struct.CtorWithClosure* %this, %struct.CtorWithClosure** %[[this_addr]], align 4
// M32-DAG: %[[this:.*]] = load %struct.CtorWithClosure*, %struct.CtorWithClosure** %[[this_addr]]
-// M32-DAG: call %struct.CtorWithClosure* (%struct.CtorWithClosure*, ...)* @"\01??0CtorWithClosure@@QAA@ZZ"(%struct.CtorWithClosure* %[[this]])
+// M32-DAG: call %struct.CtorWithClosure* (%struct.CtorWithClosure*, ...) @"\01??0CtorWithClosure@@QAA@ZZ"(%struct.CtorWithClosure* %[[this]])
// M32-DAG: ret void
};
@@ -507,7 +507,7 @@
// M32-DAG: %[[this_addr:.*]] = alloca %struct.ClassWithClosure*, align 4
// M32-DAG: store %struct.ClassWithClosure* %this, %struct.ClassWithClosure** %[[this_addr]], align 4
// M32-DAG: %[[this:.*]] = load %struct.ClassWithClosure*, %struct.ClassWithClosure** %[[this_addr]]
-// M32-DAG: call %struct.ClassWithClosure* (%struct.ClassWithClosure*, ...)* @"\01??0ClassWithClosure@@QAA@ZZ"(%struct.ClassWithClosure* %[[this]])
+// M32-DAG: call %struct.ClassWithClosure* (%struct.ClassWithClosure*, ...) @"\01??0ClassWithClosure@@QAA@ZZ"(%struct.ClassWithClosure* %[[this]])
// M32-DAG: ret void
};
diff --git a/test/CodeGenCXX/exceptions-seh-filter-captures.cpp b/test/CodeGenCXX/exceptions-seh-filter-captures.cpp
new file mode 100644
index 0000000..5df418a
--- /dev/null
+++ b/test/CodeGenCXX/exceptions-seh-filter-captures.cpp
@@ -0,0 +1,80 @@
+// RUN: %clang_cc1 -std=c++11 -fblocks -fms-extensions %s -triple=x86_64-windows-msvc -emit-llvm \
+// RUN: -o - -mconstructor-aliases -fcxx-exceptions -fexceptions | \
+// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CXXEH
+
+extern "C" int basic_filter(int v, ...);
+extern "C" void might_crash();
+
+extern "C" void test_freefunc(int p1) {
+ int l1 = 13;
+ static int s1 = 42;
+ __try {
+ might_crash();
+ } __except(basic_filter(p1, l1, s1)) {
+ }
+}
+
+// CHECK-LABEL: define void @test_freefunc(i32 %p1)
+// CHECK: @llvm.frameescape(i32* %[[p1_ptr:[^, ]*]], i32* %[[l1_ptr:[^, ]*]])
+// CHECK: store i32 %p1, i32* %[[p1_ptr]], align 4
+// CHECK: store i32 13, i32* %[[l1_ptr]], align 4
+// CHECK: invoke void @might_crash()
+
+// CHECK-LABEL: define internal i32 @"\01?filt$0@0@test_freefunc@@"(i8* %exception_pointers, i8* %frame_pointer)
+// CHECK: %[[p1_i8:[^ ]*]] = call i8* @llvm.framerecover(i8* bitcast (void (i32)* @test_freefunc to i8*), i8* %frame_pointer, i32 0)
+// CHECK: %[[p1_ptr:[^ ]*]] = bitcast i8* %[[p1_i8]] to i32*
+// CHECK: %[[l1_i8:[^ ]*]] = call i8* @llvm.framerecover(i8* bitcast (void (i32)* @test_freefunc to i8*), i8* %frame_pointer, i32 1)
+// CHECK: %[[l1_ptr:[^ ]*]] = bitcast i8* %[[l1_i8]] to i32*
+// CHECK: %[[s1:[^ ]*]] = load i32, i32* @"\01?s1@?1??test_freefunc@@9@4HA", align 4
+// CHECK: %[[l1:[^ ]*]] = load i32, i32* %[[l1_ptr]]
+// CHECK: %[[p1:[^ ]*]] = load i32, i32* %[[p1_ptr]]
+// CHECK: call i32 (i32, ...) @basic_filter(i32 %[[p1]], i32 %[[l1]], i32 %[[s1]])
+
+struct S {
+ int m1;
+ void test_method(void);
+};
+
+void S::test_method() {
+ int l1 = 13;
+ __try {
+ might_crash();
+ } __except(basic_filter(l1)) {
+ // FIXME: Test capturing 'this' and 'm1'.
+ }
+}
+
+// CHECK-LABEL: define void @"\01?test_method@S@@QEAAXXZ"(%struct.S* %this)
+// CHECK: @llvm.frameescape(i32* %[[l1_addr:[^, ]*]])
+// CHECK: store i32 13, i32* %[[l1_addr]], align 4
+// CHECK: invoke void @might_crash()
+
+// CHECK-LABEL: define internal i32 @"\01?filt$0@0@test_method@S@@"(i8* %exception_pointers, i8* %frame_pointer)
+// CHECK: %[[l1_i8:[^ ]*]] = call i8* @llvm.framerecover(i8* bitcast (void (%struct.S*)* @"\01?test_method@S@@QEAAXXZ" to i8*), i8* %frame_pointer, i32 0)
+// CHECK: %[[l1_ptr:[^ ]*]] = bitcast i8* %[[l1_i8]] to i32*
+// CHECK: %[[l1:[^ ]*]] = load i32, i32* %[[l1_ptr]]
+// CHECK: call i32 (i32, ...) @basic_filter(i32 %[[l1]])
+
+void test_lambda() {
+ int l1 = 13;
+ auto lambda = [&]() {
+ int l2 = 42;
+ __try {
+ might_crash();
+ } __except(basic_filter(l2)) {
+ // FIXME: Test 'l1' when we can capture the lambda's 'this' decl.
+ }
+ };
+ lambda();
+}
+
+// CHECK-LABEL: define internal void @"\01??R<lambda_0>@?test_lambda@@YAXXZ@QEBAXXZ"(%class.anon* %this)
+// CHECK: @llvm.frameescape(i32* %[[l2_addr:[^, ]*]])
+// CHECK: store i32 42, i32* %[[l2_addr]], align 4
+// CHECK: invoke void @might_crash()
+
+// CHECK-LABEL: define internal i32 @"\01?filt$0@0@?R<lambda_0>@?test_lambda@@YAXXZ@"(i8* %exception_pointers, i8* %frame_pointer)
+// CHECK: %[[l2_i8:[^ ]*]] = call i8* @llvm.framerecover(i8* bitcast (void (%class.anon*)* @"\01??R<lambda_0>@?test_lambda@@YAXXZ@QEBAXXZ" to i8*), i8* %frame_pointer, i32 0)
+// CHECK: %[[l2_ptr:[^ ]*]] = bitcast i8* %[[l2_i8]] to i32*
+// CHECK: %[[l2:[^ ]*]] = load i32, i32* %[[l2_ptr]]
+// CHECK: call i32 (i32, ...) @basic_filter(i32 %[[l2]])
diff --git a/test/CodeGenCXX/exceptions-seh.cpp b/test/CodeGenCXX/exceptions-seh.cpp
index 5f93cb1..cb5f6df 100644
--- a/test/CodeGenCXX/exceptions-seh.cpp
+++ b/test/CodeGenCXX/exceptions-seh.cpp
@@ -5,6 +5,7 @@
// RUN: -o - -mconstructor-aliases -O1 -disable-llvm-optzns | \
// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=NOCXX
+extern "C" unsigned long _exception_code();
extern "C" void might_throw();
struct HasCleanup {
@@ -95,4 +96,47 @@
// CHECK: invoke void @might_throw() #[[NOINLINE]]
// CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*)
+static int my_unique_global;
+
+extern "C" inline void use_seh_in_inline_func() {
+ __try {
+ might_throw();
+ } __except(_exception_code() == 424242) {
+ }
+ __try {
+ might_throw();
+ } __finally {
+ my_unique_global = 1234;
+ }
+}
+
+void use_inline() {
+ use_seh_in_inline_func();
+}
+
+// CHECK-LABEL: define linkonce_odr void @use_seh_in_inline_func() #{{[0-9]+}} comdat {
+// CHECK: invoke void @might_throw()
+//
+// CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*)
+// CHECK-NEXT: catch i8* bitcast (i32 (i8*, i8*)* @"\01?filt$0@0@use_seh_in_inline_func@@" to i8*)
+//
+// CHECK: invoke void @might_throw()
+//
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: call void @"\01?fin$0@0@use_seh_in_inline_func@@"(i1 zeroext false, i8* %[[fp]])
+// CHECK: ret void
+//
+// CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*)
+// CHECK-NEXT: cleanup
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: call void @"\01?fin$0@0@use_seh_in_inline_func@@"(i1 zeroext true, i8* %[[fp]])
+
+// CHECK-LABEL: define internal i32 @"\01?filt$0@0@use_seh_in_inline_func@@"(i8* %exception_pointers, i8* %frame_pointer) #{{[0-9]+}} comdat($use_seh_in_inline_func)
+// CHECK: icmp eq i32 %{{.*}}, 424242
+// CHECK: zext i1 %{{.*}} to i32
+// CHECK: ret i32
+
+// CHECK-LABEL: define internal void @"\01?fin$0@0@use_seh_in_inline_func@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer) #{{[0-9]+}} comdat($use_seh_in_inline_func)
+// CHECK: store i32 1234, i32* @my_unique_global
+
// CHECK: attributes #[[NOINLINE]] = { {{.*noinline.*}} }
diff --git a/test/CodeGenCXX/mangle-lambdas.cpp b/test/CodeGenCXX/mangle-lambdas.cpp
index 1b784f3..8e2db03 100644
--- a/test/CodeGenCXX/mangle-lambdas.cpp
+++ b/test/CodeGenCXX/mangle-lambdas.cpp
@@ -1,10 +1,5 @@
// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-macosx10.7.0 -emit-llvm -o - %s -w | FileCheck %s
-// CHECK: @_ZZZN7PR12917IJicdEEC1EicdEd1_NKUlvE_clEvE1n = linkonce_odr global i32 0
-// CHECK: @_ZZZN7PR12917IJicdEEC1EicdEd0_NKUlvE_clEvE1n = linkonce_odr global i32 0
-// CHECK: @_ZZZN7PR12917IJicdEEC1EicdEd_NKUlvE_clEvE1n = linkonce_odr global i32 0
-// CHECK: @_ZZNK7PR12917IJiiEE1nMUlvE_clEvE1n = linkonce_odr global i32 0
-
// CHECK-LABEL: define linkonce_odr void @_Z11inline_funci
inline void inline_func(int n) {
// CHECK: call i32 @_ZZ11inline_funciENKUlvE_clEv
@@ -164,23 +159,6 @@
func_template<int>();
}
-
-template<typename...T> struct PR12917 {
- PR12917(T ...t = []{ static int n = 0; return ++n; }());
-
- static int n[3];
-};
-template<typename...T> int PR12917<T...>::n[3] = {
- []{ static int n = 0; return ++n; }()
-};
-
-// CHECK: call i32 @_ZZN7PR12917IJicdEEC1EicdEd1_NKUlvE_clEv(
-// CHECK: call i32 @_ZZN7PR12917IJicdEEC1EicdEd0_NKUlvE_clEv(
-// CHECK: call i32 @_ZZN7PR12917IJicdEEC1EicdEd_NKUlvE_clEv(
-// CHECK: call void @_ZN7PR12917IJicdEEC1Eicd(
-PR12917<int, char, double> pr12917;
-int *pr12917_p = PR12917<int, int>::n;
-
namespace std {
struct type_info;
}
diff --git a/test/CodeGenCXX/mangle-ms-cxx14.cpp b/test/CodeGenCXX/mangle-ms-cxx14.cpp
index a3a8685..51627dd 100644
--- a/test/CodeGenCXX/mangle-ms-cxx14.cpp
+++ b/test/CodeGenCXX/mangle-ms-cxx14.cpp
@@ -35,10 +35,10 @@
return LocalLambdaWithLocalType();
}
-// MSVC2013-DAG: "\01?ValueFromTemplateFuncionWithLocalLambda@@3ULocalType@?2???R<lambda_1>@??$TemplateFuncionWithLocalLambda@H@@YA?A?<auto>@@H@Z@QBA?A?3@XZ@A"
-// MSVC2013-DAG: "\01?ValueFromTemplateFuncionWithLocalLambda@@3ULocalType@?2???R<lambda_1>@??$TemplateFuncionWithLocalLambda@H@@YA?A?<auto>@@H@Z@QBA?A?3@XZ@A"
-// MSVC2015-DAG: "\01?ValueFromTemplateFuncionWithLocalLambda@@3ULocalType@?1???R<lambda_1>@??$TemplateFuncionWithLocalLambda@H@@YA?A?<auto>@@H@Z@QBA?A?3@XZ@A"
-// MSVC2015-DAG: "\01?ValueFromTemplateFuncionWithLocalLambda@@3ULocalType@?1???R<lambda_1>@??$TemplateFuncionWithLocalLambda@H@@YA?A?<auto>@@H@Z@QBA?A?3@XZ@A"
+// MSVC2013-DAG: "\01?ValueFromTemplateFuncionWithLocalLambda@@3ULocalType@?2???R<lambda_1>@??$TemplateFuncionWithLocalLambda@H@@YA?A?<auto>@@H@Z@QBE?A?3@XZ@A"
+// MSVC2013-DAG: "\01?ValueFromTemplateFuncionWithLocalLambda@@3ULocalType@?2???R<lambda_1>@??$TemplateFuncionWithLocalLambda@H@@YA?A?<auto>@@H@Z@QBE?A?3@XZ@A"
+// MSVC2015-DAG: "\01?ValueFromTemplateFuncionWithLocalLambda@@3ULocalType@?1???R<lambda_1>@??$TemplateFuncionWithLocalLambda@H@@YA?A?<auto>@@H@Z@QBE?A?3@XZ@A"
+// MSVC2015-DAG: "\01?ValueFromTemplateFuncionWithLocalLambda@@3ULocalType@?1???R<lambda_1>@??$TemplateFuncionWithLocalLambda@H@@YA?A?<auto>@@H@Z@QBE?A?3@XZ@A"
// CHECK: "\01??$TemplateFuncionWithLocalLambda@H@@YA?A?<auto>@@H@Z"
-// CHECK: "\01??R<lambda_1>@??$TemplateFuncionWithLocalLambda@H@@YA?A?<auto>@@H@Z@QBA?A?1@XZ"
+// CHECK: "\01??R<lambda_1>@??$TemplateFuncionWithLocalLambda@H@@YA?A?<auto>@@H@Z@QBE?A?1@XZ"
auto ValueFromTemplateFuncionWithLocalLambda = TemplateFuncionWithLocalLambda(0);
diff --git a/test/CodeGenCXX/member-functions.cpp b/test/CodeGenCXX/member-functions.cpp
index 1d2a60d..58f709c 100644
--- a/test/CodeGenCXX/member-functions.cpp
+++ b/test/CodeGenCXX/member-functions.cpp
@@ -16,7 +16,7 @@
// CHECK: call void @_ZN1C1fEv
c.f();
- // CHECK: call void (%struct.C*, i32, ...)* @_ZN1C1gEiz
+ // CHECK: call void (%struct.C*, i32, ...) @_ZN1C1gEiz
c.g(1, 2, 3);
}
diff --git a/test/CodeGenCXX/microsoft-abi-eh-catch.cpp b/test/CodeGenCXX/microsoft-abi-eh-catch.cpp
index f0e2033..292fad2 100644
--- a/test/CodeGenCXX/microsoft-abi-eh-catch.cpp
+++ b/test/CodeGenCXX/microsoft-abi-eh-catch.cpp
@@ -48,6 +48,18 @@
// WIN64: call void @handle_exception(i8* %[[e_i8]])
// WIN64: call void @llvm.eh.endcatch()
+extern "C" void catch_int_unnamed() {
+ try {
+ might_throw();
+ } catch (int) {
+ }
+}
+
+// WIN64-LABEL: define void @catch_int_unnamed()
+// WIN64: landingpad { i8*, i32 }
+// WIN64: call void @llvm.eh.begincatch(i8* %{{.*}}, i8* null)
+// WIN64: call void @llvm.eh.endcatch()
+
struct A {
A();
A(const A &o);
@@ -96,3 +108,11 @@
// WIN64: %[[eptr_i8:[^ ]*]] = bitcast %struct.A* %[[eptr]] to i8*
// WIN64: call void @handle_exception(i8* %[[eptr_i8]])
// WIN64: call void @llvm.eh.endcatch()
+
+extern "C" void fn_with_exc_spec() throw(int) {
+ might_throw();
+}
+
+// WIN64-LABEL: define void @fn_with_exc_spec()
+// WIN64: call void @might_throw()
+// WIN64-NEXT: ret void
diff --git a/test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp b/test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp
index 642d8e2..68f1430 100644
--- a/test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp
+++ b/test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp
@@ -165,6 +165,29 @@
// WIN32: getelementptr inbounds i8, i8* %{{.*}}, i64 4
// WIN32-NOT: load
// WIN32: bitcast i8* %{{.*}} to %"struct.crash_on_partial_destroy::A"*
-// WIN32: invoke x86_thiscallcc void @"\01??1A@crash_on_partial_destroy@@UAE@XZ"
+// WIN32: call x86_thiscallcc void @"\01??1A@crash_on_partial_destroy@@UAE@XZ"
// WIN32: }
}
+
+namespace dont_call_terminate {
+struct C {
+ ~C();
+};
+void g();
+void f() {
+ C c;
+ g();
+}
+
+// WIN32-LABEL: define void @"\01?f@dont_call_terminate@@YAXXZ"()
+// WIN32: invoke void @"\01?g@dont_call_terminate@@YAXXZ"()
+// WIN32-NEXT: to label %[[cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
+//
+// WIN32: [[cont]]
+// WIN32: call x86_thiscallcc void @"\01??1C@dont_call_terminate@@QAE@XZ"({{.*}})
+//
+// WIN32: [[lpad]]
+// WIN32-NEXT: landingpad
+// WIN32-NEXT: cleanup
+// WIN32: call x86_thiscallcc void @"\01??1C@dont_call_terminate@@QAE@XZ"({{.*}})
+}
diff --git a/test/CodeGenCXX/microsoft-abi-member-pointers.cpp b/test/CodeGenCXX/microsoft-abi-member-pointers.cpp
index 7784359..f1bff39 100644
--- a/test/CodeGenCXX/microsoft-abi-member-pointers.cpp
+++ b/test/CodeGenCXX/microsoft-abi-member-pointers.cpp
@@ -623,7 +623,7 @@
// CHECK: load void (%"struct.Test4::C"*, ...)**, void (%"struct.Test4::C"*, ...)*** %{{.*}}
// CHECK: getelementptr inbounds void (%"struct.Test4::C"*, ...)*, void (%"struct.Test4::C"*, ...)** %{{.*}}, i64 0
// CHECK-NOT: getelementptr
-// CHECK: musttail call x86_thiscallcc void (%"struct.Test4::C"*, ...)* %
+// CHECK: musttail call x86_thiscallcc void (%"struct.Test4::C"*, ...) %
}
diff --git a/test/CodeGenCXX/microsoft-abi-methods.cpp b/test/CodeGenCXX/microsoft-abi-methods.cpp
index aa3141c..e58d103 100644
--- a/test/CodeGenCXX/microsoft-abi-methods.cpp
+++ b/test/CodeGenCXX/microsoft-abi-methods.cpp
@@ -42,7 +42,7 @@
C instance;
instance.vararg_method("Hello");
// Make sure that the call uses the right calling convention:
-// CHECK: call void (%class.C*, i8*, ...)* @"\01?vararg_method@C@@QAAXPBDZZ"
+// CHECK: call void (%class.C*, i8*, ...) @"\01?vararg_method@C@@QAAXPBDZZ"
// CHECK: ret
// Make sure that the definition uses the right calling convention:
diff --git a/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp b/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp
index a4eaa1c..4c2d850 100644
--- a/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp
+++ b/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp
@@ -101,12 +101,12 @@
void small_arg(Small s) {}
-// LINUX-LABEL: define void @_Z9small_arg5Small(%struct.Small* byval align 4 %s)
+// LINUX-LABEL: define void @_Z9small_arg5Small(i32 %s.0)
// WIN32: define void @"\01?small_arg@@YAXUSmall@@@Z"(%struct.Small* byval align 4 %s)
// WIN64: define void @"\01?small_arg@@YAXUSmall@@@Z"(i32 %s.coerce)
void medium_arg(Medium s) {}
-// LINUX-LABEL: define void @_Z10medium_arg6Medium(%struct.Medium* byval align 4 %s)
+// LINUX-LABEL: define void @_Z10medium_arg6Medium(i32 %s.0, i32 %s.1)
// WIN32: define void @"\01?medium_arg@@YAXUMedium@@@Z"(%struct.Medium* byval align 4 %s)
// WIN64: define void @"\01?medium_arg@@YAXUMedium@@@Z"(i64 %s.coerce)
@@ -229,7 +229,7 @@
// WIN64: define linkonce_odr void @"\01?thiscall_method_arg@Class@@QEAAXUEmptyWithCtor@@@Z"(%class.Class* %this, i8 %s.coerce)
void thiscall_method_arg(Small s) {}
- // LINUX: define {{.*}} void @_ZN5Class19thiscall_method_argE5Small(%class.Class* %this, %struct.Small* byval align 4 %s)
+ // LINUX: define {{.*}} void @_ZN5Class19thiscall_method_argE5Small(%class.Class* %this, i32 %s.0)
// WIN32: define {{.*}} void @"\01?thiscall_method_arg@Class@@QAEXUSmall@@@Z"(%class.Class* %this, %struct.Small* byval align 4 %s)
// WIN64: define linkonce_odr void @"\01?thiscall_method_arg@Class@@QEAAXUSmall@@@Z"(%class.Class* %this, i32 %s.coerce)
diff --git a/test/CodeGenCXX/microsoft-abi-structors.cpp b/test/CodeGenCXX/microsoft-abi-structors.cpp
index 5ca0bb9..594dea4 100644
--- a/test/CodeGenCXX/microsoft-abi-structors.cpp
+++ b/test/CodeGenCXX/microsoft-abi-structors.cpp
@@ -420,7 +420,7 @@
// CHECK-LABEL: define void @"\01?construct_b@test1@@YAXXZ"()
// CHECK: call x86_thiscallcc %"struct.test1::B"* @"\01??0B@test1@@QAE@PAH@Z"
// CHECK: (%"struct.test1::B"* {{.*}}, i32* {{.*}}, i32 1)
-// CHECK: call %"struct.test1::B"* (%"struct.test1::B"*, i32, i8*, ...)* @"\01??0B@test1@@QAA@PBDZZ"
+// CHECK: call %"struct.test1::B"* (%"struct.test1::B"*, i32, i8*, ...) @"\01??0B@test1@@QAA@PBDZZ"
// CHECK: (%"struct.test1::B"* {{.*}}, i32 1, i8* {{.*}}, i32 1, i32 2)
}
diff --git a/test/CodeGenCXX/microsoft-abi-throw.cpp b/test/CodeGenCXX/microsoft-abi-throw.cpp
index 080a98e..080f1a0 100644
--- a/test/CodeGenCXX/microsoft-abi-throw.cpp
+++ b/test/CodeGenCXX/microsoft-abi-throw.cpp
@@ -16,6 +16,9 @@
// CHECK-DAG: @"_CT??_R0?AUVariadic@@@8??_OVariadic@@QAEXAAU0@@Z1" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 0, i8* bitcast (%rtti.TypeDescriptor14* @"\01??_R0?AUVariadic@@@8" to i8*), i32 0, i32 -1, i32 0, i32 1, i8* bitcast (void (%struct.Variadic*, %struct.Variadic*)* @"\01??_OVariadic@@QAEXAAU0@@Z" to i8*) }, section ".xdata", comdat
// CHECK-DAG: @"_CT??_R0?AUTemplateWithDefault@@@8??$?_OH@TemplateWithDefault@@QAEXAAU0@@Z1" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 0, i8* bitcast (%rtti.TypeDescriptor25* @"\01??_R0?AUTemplateWithDefault@@@8" to i8*), i32 0, i32 -1, i32 0, i32 1, i8* bitcast (void (%struct.TemplateWithDefault*, %struct.TemplateWithDefault*)* @"\01??$?_OH@TemplateWithDefault@@QAEXAAU0@@Z" to i8*) }, section ".xdata", comdat
// CHECK-DAG: @"_CTA2$$T" = linkonce_odr unnamed_addr constant %eh.CatchableTypeArray.2 { i32 2, [2 x %eh.CatchableType*] [%eh.CatchableType* @"_CT??_R0$$T@84", %eh.CatchableType* @"_CT??_R0PAX@84"] }, section ".xdata", comdat
+// CHECK-DAG: @"_CT??_R0P6AXXZ@84" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 1, i8* bitcast (%rtti.TypeDescriptor7* @"\01??_R0P6AXXZ@8" to i8*), i32 0, i32 -1, i32 0, i32 4, i8* null }, section ".xdata", comdat
+// CHECK-DAG: @_CTA1P6AXXZ = linkonce_odr unnamed_addr constant %eh.CatchableTypeArray.1 { i32 1, [1 x %eh.CatchableType*] [%eh.CatchableType* @"_CT??_R0P6AXXZ@84"] }, section ".xdata", comdat
+// CHECK-DAG: @_TI1P6AXXZ = linkonce_odr unnamed_addr constant %eh.ThrowInfo { i32 0, i8* null, i8* null, i8* bitcast (%eh.CatchableTypeArray.1* @_CTA1P6AXXZ to i8*) }, section ".xdata", comdat
struct N { ~N(); };
@@ -104,3 +107,9 @@
// CHECK: ret i8* bitcast (%eh.ThrowInfo* @_TI1H to i8*)
return std::__GetExceptionInfo(0);
}
+
+void *GetExceptionInfo_test1() {
+// CHECK-LABEL: @"\01?GetExceptionInfo_test1@@YAPAXXZ"
+// CHECK: ret i8* bitcast (%eh.ThrowInfo* @_TI1P6AXXZ to i8*)
+ return std::__GetExceptionInfo<void (*)()>(&h);
+}
diff --git a/test/CodeGenCXX/microsoft-abi-try-throw.cpp b/test/CodeGenCXX/microsoft-abi-try-throw.cpp
index c7bbcf2..fed3976 100644
--- a/test/CodeGenCXX/microsoft-abi-try-throw.cpp
+++ b/test/CodeGenCXX/microsoft-abi-try-throw.cpp
@@ -6,7 +6,7 @@
// THROW-DAG: @_CTA1H = linkonce_odr unnamed_addr constant %eh.CatchableTypeArray.1 { i32 1, [1 x %eh.CatchableType*] [%eh.CatchableType* @"_CT??_R0H@84"] }, section ".xdata", comdat
// THROW-DAG: @_TI1H = linkonce_odr unnamed_addr constant %eh.ThrowInfo { i32 0, i8* null, i8* null, i8* bitcast (%eh.CatchableTypeArray.1* @_CTA1H to i8*) }, section ".xdata", comdat
-// TRY-DAG: @llvm.eh.handlermapentry.const.PAH = private unnamed_addr constant %eh.HandlerMapEntry { i32 1, i8* bitcast (%rtti.TypeDescriptor4* @"\01??_R0PAH@8" to i8*) }, section "llvm.metadata"
+// TRY-DAG: @llvm.eh.handlertype.PAH.1 = private unnamed_addr constant %eh.CatchHandlerType { i32 1, i8* bitcast (%rtti.TypeDescriptor4* @"\01??_R0PAH@8" to i8*) }, section "llvm.metadata"
void external();
@@ -21,7 +21,7 @@
external(); // TRY: invoke void @"\01?external@@YAXXZ"
} catch (int) {
rv = 1;
- // TRY: call void @llvm.eh.begincatch(i8* %{{.*}}, i8* %{{.*}})
+ // TRY: call void @llvm.eh.begincatch(i8* %{{.*}}, i8* null)
// TRY: call void @llvm.eh.endcatch()
}
#endif
@@ -41,7 +41,7 @@
external();
} catch (const int *) {
}
- // TRY: catch %eh.HandlerMapEntry* @llvm.eh.handlermapentry.const.PAH
- // TRY: call i32 @llvm.eh.typeid.for(i8* bitcast (%eh.HandlerMapEntry* @llvm.eh.handlermapentry.const.PAH to i8*))
+ // TRY: catch %eh.CatchHandlerType* @llvm.eh.handlertype.PAH.1
+ // TRY: call i32 @llvm.eh.typeid.for(i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.PAH.1 to i8*))
}
#endif
diff --git a/test/CodeGenCXX/microsoft-abi-virtual-member-pointers.cpp b/test/CodeGenCXX/microsoft-abi-virtual-member-pointers.cpp
index fe64686..f6f7583 100644
--- a/test/CodeGenCXX/microsoft-abi-virtual-member-pointers.cpp
+++ b/test/CodeGenCXX/microsoft-abi-virtual-member-pointers.cpp
@@ -71,7 +71,7 @@
// CHECK32: comdat
// CHECK32: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, ...)*, void (%struct.C*, ...)** %{{.*}}, i64 0
// CHECK32: [[CALLEE:%.*]] = load void (%struct.C*, ...)*, void (%struct.C*, ...)** [[VPTR]]
-// CHECK32: musttail call x86_thiscallcc void (%struct.C*, ...)* [[CALLEE]](%struct.C* %{{.*}}, ...)
+// CHECK32: musttail call x86_thiscallcc void (%struct.C*, ...) [[CALLEE]](%struct.C* %{{.*}}, ...)
// CHECK32-NEXT: ret void
// CHECK32: }
//
@@ -81,7 +81,7 @@
// CHECK64: comdat
// CHECK64: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, ...)*, void (%struct.C*, ...)** %{{.*}}, i64 0
// CHECK64: [[CALLEE:%.*]] = load void (%struct.C*, ...)*, void (%struct.C*, ...)** [[VPTR]]
-// CHECK64: musttail call void (%struct.C*, ...)* [[CALLEE]](%struct.C* %{{.*}}, ...)
+// CHECK64: musttail call void (%struct.C*, ...) [[CALLEE]](%struct.C* %{{.*}}, ...)
// CHECK64-NEXT: ret void
// CHECK64: }
@@ -90,7 +90,7 @@
// CHECK32: #[[ATTR]] comdat
// CHECK32: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, ...)*, void (%struct.C*, ...)** %{{.*}}, i64 1
// CHECK32: [[CALLEE:%.*]] = load void (%struct.C*, ...)*, void (%struct.C*, ...)** [[VPTR]]
-// CHECK32: musttail call x86_thiscallcc void (%struct.C*, ...)* [[CALLEE]](%struct.C* %{{.*}}, ...)
+// CHECK32: musttail call x86_thiscallcc void (%struct.C*, ...) [[CALLEE]](%struct.C* %{{.*}}, ...)
// CHECK32-NEXT: ret void
// CHECK32: }
//
@@ -98,7 +98,7 @@
// CHECK64: #[[ATTR]] comdat
// CHECK64: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, ...)*, void (%struct.C*, ...)** %{{.*}}, i64 1
// CHECK64: [[CALLEE:%.*]] = load void (%struct.C*, ...)*, void (%struct.C*, ...)** [[VPTR]]
-// CHECK64: musttail call void (%struct.C*, ...)* [[CALLEE]](%struct.C* %{{.*}}, ...)
+// CHECK64: musttail call void (%struct.C*, ...) [[CALLEE]](%struct.C* %{{.*}}, ...)
// CHECK64-NEXT: ret void
// CHECK64: }
@@ -107,7 +107,7 @@
// CHECK32: #[[ATTR]] comdat
// CHECK32: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, ...)*, void (%struct.C*, ...)** %{{.*}}, i64 2
// CHECK32: [[CALLEE:%.*]] = load void (%struct.C*, ...)*, void (%struct.C*, ...)** [[VPTR]]
-// CHECK32: musttail call x86_thiscallcc void (%struct.C*, ...)* [[CALLEE]](%struct.C* %{{.*}}, ...)
+// CHECK32: musttail call x86_thiscallcc void (%struct.C*, ...) [[CALLEE]](%struct.C* %{{.*}}, ...)
// CHECK32-NEXT: ret void
// CHECK32: }
//
@@ -115,7 +115,7 @@
// CHECK64: #[[ATTR]] comdat
// CHECK64: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, ...)*, void (%struct.C*, ...)** %{{.*}}, i64 2
// CHECK64: [[CALLEE:%.*]] = load void (%struct.C*, ...)*, void (%struct.C*, ...)** [[VPTR]]
-// CHECK64: musttail call void (%struct.C*, ...)* [[CALLEE]](%struct.C* %{{.*}}, ...)
+// CHECK64: musttail call void (%struct.C*, ...) [[CALLEE]](%struct.C* %{{.*}}, ...)
// CHECK64-NEXT: ret void
// CHECK64: }
@@ -124,7 +124,7 @@
// CHECK32: #[[ATTR]]
// CHECK32: [[VPTR:%.*]] = getelementptr inbounds void (%"struct.(anonymous namespace)::D"*, ...)*, void (%"struct.(anonymous namespace)::D"*, ...)** %{{.*}}, i64 0
// CHECK32: [[CALLEE:%.*]] = load void (%"struct.(anonymous namespace)::D"*, ...)*, void (%"struct.(anonymous namespace)::D"*, ...)** [[VPTR]]
-// CHECK32: musttail call x86_thiscallcc void (%"struct.(anonymous namespace)::D"*, ...)* [[CALLEE]](%"struct.(anonymous namespace)::D"* %{{.*}}, ...)
+// CHECK32: musttail call x86_thiscallcc void (%"struct.(anonymous namespace)::D"*, ...) [[CALLEE]](%"struct.(anonymous namespace)::D"* %{{.*}}, ...)
// CHECK32-NEXT: ret void
// CHECK32: }
//
@@ -132,7 +132,7 @@
// CHECK64: #[[ATTR]]
// CHECK64: [[VPTR:%.*]] = getelementptr inbounds void (%"struct.(anonymous namespace)::D"*, ...)*, void (%"struct.(anonymous namespace)::D"*, ...)** %{{.*}}, i64 0
// CHECK64: [[CALLEE:%.*]] = load void (%"struct.(anonymous namespace)::D"*, ...)*, void (%"struct.(anonymous namespace)::D"*, ...)** [[VPTR]]
-// CHECK64: musttail call void (%"struct.(anonymous namespace)::D"*, ...)* [[CALLEE]](%"struct.(anonymous namespace)::D"* %{{.*}}, ...)
+// CHECK64: musttail call void (%"struct.(anonymous namespace)::D"*, ...) [[CALLEE]](%"struct.(anonymous namespace)::D"* %{{.*}}, ...)
// CHECK64-NEXT: ret void
// CHECK64: }
@@ -141,14 +141,14 @@
// CHECK32-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_9C@@$BM@AE"(%struct.C* %this, ...) {{.*}} comdat
// CHECK32: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, ...)*, void (%struct.C*, ...)** %{{.*}}, i64 3
// CHECK32: [[CALLEE:%.*]] = load void (%struct.C*, ...)*, void (%struct.C*, ...)** [[VPTR]]
-// CHECK32: musttail call x86_thiscallcc void (%struct.C*, ...)* [[CALLEE]](%struct.C* %{{.*}}, ...)
+// CHECK32: musttail call x86_thiscallcc void (%struct.C*, ...) [[CALLEE]](%struct.C* %{{.*}}, ...)
// CHECK32-NEXT: ret void
// CHECK32: }
//
// CHECK64-LABEL: define linkonce_odr void @"\01??_9C@@$BBI@AA"(%struct.C* %this, ...) {{.*}} comdat
// CHECK64: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, ...)*, void (%struct.C*, ...)** %{{.*}}, i64 3
// CHECK64: [[CALLEE:%.*]] = load void (%struct.C*, ...)*, void (%struct.C*, ...)** [[VPTR]]
-// CHECK64: musttail call void (%struct.C*, ...)* [[CALLEE]](%struct.C* %{{.*}}, ...)
+// CHECK64: musttail call void (%struct.C*, ...) [[CALLEE]](%struct.C* %{{.*}}, ...)
// CHECK64: ret void
// CHECK64: }
@@ -156,14 +156,14 @@
// CHECK32-LABEL: define linkonce_odr void @"\01??_9C@@$BBA@AA"(%struct.C* %this, ...) {{.*}} comdat align 2 {
// CHECK32: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, ...)*, void (%struct.C*, ...)** %{{.*}}, i64 4
// CHECK32: [[CALLEE:%.*]] = load void (%struct.C*, ...)*, void (%struct.C*, ...)** [[VPTR]]
-// CHECK32: musttail call void (%struct.C*, ...)* [[CALLEE]](%struct.C* %{{.*}}, ...)
+// CHECK32: musttail call void (%struct.C*, ...) [[CALLEE]](%struct.C* %{{.*}}, ...)
// CHECK32: ret void
// CHECK32: }
//
// CHECK64-LABEL: define linkonce_odr void @"\01??_9C@@$BCA@AA"(%struct.C* %this, ...) {{.*}} comdat align 2 {
// CHECK64: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, ...)*, void (%struct.C*, ...)** %{{.*}}, i64 4
// CHECK64: [[CALLEE:%.*]] = load void (%struct.C*, ...)*, void (%struct.C*, ...)** [[VPTR]]
-// CHECK64: musttail call void (%struct.C*, ...)* [[CALLEE]](%struct.C* %{{.*}}, ...)
+// CHECK64: musttail call void (%struct.C*, ...) [[CALLEE]](%struct.C* %{{.*}}, ...)
// CHECK64: ret void
// CHECK64: }
diff --git a/test/CodeGenCXX/microsoft-abi-vmemptr-conflicts.cpp b/test/CodeGenCXX/microsoft-abi-vmemptr-conflicts.cpp
index 0b00ef5..f8a12e6 100644
--- a/test/CodeGenCXX/microsoft-abi-vmemptr-conflicts.cpp
+++ b/test/CodeGenCXX/microsoft-abi-vmemptr-conflicts.cpp
@@ -24,7 +24,7 @@
// CHECK: call x86_thiscallcc void bitcast (void (%"struct.num_params::C"*, ...)* @"\01??_9C@num_params@@$BA@AE" to void (%"struct.num_params::C"*, i32, i32)*)(%"struct.num_params::C"* %{{.*}}, i32 0, i32 0)
// CHECK-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_9C@num_params@@$BA@AE"(%"struct.num_params::C"* %this, ...) {{.*}} comdat
-// CHECK: musttail call x86_thiscallcc void (%"struct.num_params::C"*, ...)* %{{.*}}(%"struct.num_params::C"* %{{.*}}, ...)
+// CHECK: musttail call x86_thiscallcc void (%"struct.num_params::C"*, ...) %{{.*}}(%"struct.num_params::C"* %{{.*}}, ...)
// CHECK-NEXT: ret void
namespace i64_return {
@@ -46,7 +46,7 @@
// CHECK: call x86_thiscallcc i64 bitcast (void (%"struct.i64_return::C"*, ...)* @"\01??_9C@i64_return@@$BA@AE" to i64 (%"struct.i64_return::C"*)*)(%"struct.i64_return::C"* %{{.*}})
// CHECK-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_9C@i64_return@@$BA@AE"(%"struct.i64_return::C"* %this, ...) {{.*}} comdat
-// CHECK: musttail call x86_thiscallcc void (%"struct.i64_return::C"*, ...)* %{{.*}}(%"struct.i64_return::C"* %{{.*}}, ...)
+// CHECK: musttail call x86_thiscallcc void (%"struct.i64_return::C"*, ...) %{{.*}}(%"struct.i64_return::C"* %{{.*}}, ...)
// CHECK-NEXT: ret void
namespace sret {
@@ -68,7 +68,7 @@
// CHECK: call x86_thiscallcc void bitcast (void (%"struct.sret::C"*, ...)* @"\01??_9C@sret@@$BA@AE" to void (%"struct.sret::C"*, %"struct.sret::Big"*)*)(%"struct.sret::C"* %{{.*}}, %"struct.sret::Big"* sret %{{.*}})
// CHECK-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_9C@sret@@$BA@AE"(%"struct.sret::C"* %this, ...) {{.*}} comdat
-// CHECK: musttail call x86_thiscallcc void (%"struct.sret::C"*, ...)* %{{.*}}(%"struct.sret::C"* %{{.*}}, ...)
+// CHECK: musttail call x86_thiscallcc void (%"struct.sret::C"*, ...) %{{.*}}(%"struct.sret::C"* %{{.*}}, ...)
// CHECK-NEXT: ret void
namespace cdecl_inalloca {
@@ -97,5 +97,5 @@
// CHECK: call void bitcast (void (%"struct.cdecl_inalloca::C"*, ...)* @"\01??_9C@cdecl_inalloca@@$BA@AA" to void (<{ %"struct.cdecl_inalloca::C"*, %"struct.cdecl_inalloca::Big" }>*)*)(<{ %"struct.cdecl_inalloca::C"*, %"struct.cdecl_inalloca::Big" }>* inalloca %{{.*}})
// CHECK-LABEL: define linkonce_odr void @"\01??_9C@cdecl_inalloca@@$BA@AA"(%"struct.cdecl_inalloca::C"* %this, ...) {{.*}} comdat
-// CHECK: musttail call void (%"struct.cdecl_inalloca::C"*, ...)* %{{.*}}(%"struct.cdecl_inalloca::C"* %{{.*}}, ...)
+// CHECK: musttail call void (%"struct.cdecl_inalloca::C"*, ...) %{{.*}}(%"struct.cdecl_inalloca::C"* %{{.*}}, ...)
// CHECK-NEXT: ret void
diff --git a/test/CodeGenCXX/static-data-member-single-emission.cpp b/test/CodeGenCXX/static-data-member-single-emission.cpp
new file mode 100644
index 0000000..8c04fab
--- /dev/null
+++ b/test/CodeGenCXX/static-data-member-single-emission.cpp
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+
+template <typename T>
+struct HasStaticInit {
+static const int index;
+};
+extern "C"
+int the_count = 0;
+template <typename T>
+const int HasStaticInit<T>::index = the_count++;
+
+template <typename T> int func_tmpl1() { return HasStaticInit<T>::index; }
+template <typename T> int func_tmpl2() { return HasStaticInit<T>::index; }
+template <typename T> int func_tmpl3() { return HasStaticInit<T>::index; }
+void useit() {
+ func_tmpl1<int>();
+ func_tmpl2<int>();
+ func_tmpl3<int>();
+}
+
+// Throw in a final explicit instantiation to see that it doesn't screw things
+// up.
+template struct HasStaticInit<int>;
+
+// There should only be one entry, not 3.
+// CHECK: @llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }]
+
+// There should only be one update to @the_count.
+// CHECK-NOT: store i32 %{{.*}}, i32* @the_count
+// CHECK: store i32 %{{.*}}, i32* @the_count
+// CHECK-NOT: store i32 %{{.*}}, i32* @the_count
diff --git a/test/CodeGenCXX/switch-case-folding-2.cpp b/test/CodeGenCXX/switch-case-folding-2.cpp
index 930bfeb..b0bbf32 100644
--- a/test/CodeGenCXX/switch-case-folding-2.cpp
+++ b/test/CodeGenCXX/switch-case-folding-2.cpp
@@ -18,4 +18,4 @@
return test(5);
}
-// CHECK: call i32 (i8*, ...)* @_Z6printfPKcz
+// CHECK: call i32 (i8*, ...) @_Z6printfPKcz
diff --git a/test/CodeGenCXX/unknown-anytype.cpp b/test/CodeGenCXX/unknown-anytype.cpp
index fe10b13..42ed472 100644
--- a/test/CodeGenCXX/unknown-anytype.cpp
+++ b/test/CodeGenCXX/unknown-anytype.cpp
@@ -24,15 +24,15 @@
extern "C" __unknown_anytype test2_any(...);
float test2() {
- // X86_64: call float (double, ...)* @test2_any(double {{[^,]+}})
- // I386: call float (double, ...)* @test2_any(double {{[^,]+}})
+ // X86_64: call float (double, ...) @test2_any(double {{[^,]+}})
+ // I386: call float (double, ...) @test2_any(double {{[^,]+}})
return (float) test2_any(0.5f);
}
extern "C" __unknown_anytype test2a_any(...);
float test2a() {
- // X86_64: call float (float, ...)* @test2a_any(float {{[^,]+}})
- // I386: call float (float, ...)* @test2a_any(float {{[^,]+}})
+ // X86_64: call float (float, ...) @test2a_any(float {{[^,]+}})
+ // I386: call float (float, ...) @test2a_any(float {{[^,]+}})
return (float) test2a_any((float) 0.5f);
}
@@ -119,7 +119,7 @@
extern "C" __unknown_anytype malloc(...);
void test11() {
void *s = (void*)malloc(12);
- // COMMON: call i8* (i32, ...)* @malloc(i32 12)
+ // COMMON: call i8* (i32, ...) @malloc(i32 12)
void *d = (void*)malloc(435);
- // COMMON: call i8* (i32, ...)* @malloc(i32 435)
+ // COMMON: call i8* (i32, ...) @malloc(i32 435)
}
diff --git a/test/CodeGenCXX/vararg-non-pod-ms-compat.cpp b/test/CodeGenCXX/vararg-non-pod-ms-compat.cpp
index 450860e..530a428 100644
--- a/test/CodeGenCXX/vararg-non-pod-ms-compat.cpp
+++ b/test/CodeGenCXX/vararg-non-pod-ms-compat.cpp
@@ -13,14 +13,14 @@
// CHECK-LABEL: define void @"\01?test@@YAXUX@@@Z"
// X86: %[[argmem:[^ ]*]] = alloca inalloca <{ %struct.X }>
- // X86: call void (<{ %struct.X }>*, ...)* bitcast (void (...)* @"\01?vararg@@YAXZZ" to void (<{ %struct.X }>*, ...)*)(<{ %struct.X }>* inalloca %[[argmem]])
+ // X86: call void (<{ %struct.X }>*, ...) bitcast (void (...)* @"\01?vararg@@YAXZZ" to void (<{ %struct.X }>*, ...)*)(<{ %struct.X }>* inalloca %[[argmem]])
// X64: alloca %struct.X
// X64: %[[agg:[^ ]*]] = alloca %struct.X
// X64: %[[valptr:[^ ]*]] = getelementptr %struct.X, %struct.X* %[[agg]], i32 0, i32 0
// X64: %[[val:[^ ]*]] = load i32, i32* %[[valptr]]
- // X64: call void (...)* @"\01?vararg@@YAXZZ"(i32 %[[val]])
+ // X64: call void (...) @"\01?vararg@@YAXZZ"(i32 %[[val]])
// CHECK-NOT: llvm.trap
vararg(x);
diff --git a/test/CodeGenCXX/varargs.cpp b/test/CodeGenCXX/varargs.cpp
index 3159dc6..1ea072e 100644
--- a/test/CodeGenCXX/varargs.cpp
+++ b/test/CodeGenCXX/varargs.cpp
@@ -12,7 +12,7 @@
return -1;
}
- // CHECK: call i32 (...)* @_ZN5test05test1Ez(i32 0)
+ // CHECK: call i32 (...) @_ZN5test05test1Ez(i32 0)
void test() {
test1(0);
}
@@ -38,6 +38,6 @@
// CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[T0]], i8* [[T1]], i64 8, i32 4, i1 false)
// CHECK-NEXT: [[T0:%.*]] = bitcast [[A]]* [[TMP]] to i64*
// CHECK-NEXT: [[T1:%.*]] = load i64, i64* [[T0]], align 1
- // CHECK-NEXT: call void (...)* @_ZN5test13fooEz(i64 [[T1]])
+ // CHECK-NEXT: call void (...) @_ZN5test13fooEz(i64 [[T1]])
// CHECK-NEXT: ret void
}
diff --git a/test/CodeGenCXX/vla-lambda-capturing.cpp b/test/CodeGenCXX/vla-lambda-capturing.cpp
index 27d263b..f2332bf 100644
--- a/test/CodeGenCXX/vla-lambda-capturing.cpp
+++ b/test/CodeGenCXX/vla-lambda-capturing.cpp
@@ -22,7 +22,7 @@
// CHECK: store [[INTPTR_T]]* %{{.+}}, [[INTPTR_T]]** [[CAP_BUFFER_ADDR]]
// CHECK: [[CAP_N_REF:%.+]] = getelementptr inbounds [[CAP_TYPE1]], [[CAP_TYPE1]]* [[CAP_ARG:%.+]], i{{.+}} 0, i{{.+}} 2
// CHECK: store [[INTPTR_T]]* [[N_ADDR]], [[INTPTR_T]]** [[CAP_N_REF]]
-// CHECK: call void [[G_LAMBDA:@.+]]([[CAP_TYPE1]]* [[CAP_ARG]])
+// CHECK: call{{( x86_thiscallcc)?}} void [[G_LAMBDA:@.+]]([[CAP_TYPE1]]* [[CAP_ARG]])
// CHECK: ret void
void g(intptr_t n) {
intptr_t buffer[n];
@@ -88,7 +88,7 @@
// CHECK: store [[INTPTR_T]] [[SIZE]], [[INTPTR_T]]* [[CAP_SIZE_REF]]
// CHECK: [[CAP_BUFFER_ADDR_REF:%.+]] = getelementptr inbounds [[CAP_TYPE2]], [[CAP_TYPE2]]* [[CAP_ARG]], i{{.+}} 0, i{{.+}} 1
// CHECK: store [[INTPTR_T]]* [[BUFFER_ADDR]], [[INTPTR_T]]** [[CAP_BUFFER_ADDR_REF]]
-// CHECK: call void [[F_INT_LAMBDA:@.+]]([[CAP_TYPE2]]* [[CAP_ARG]])
+// CHECK: call{{( x86_thiscallcc)?}} void [[F_INT_LAMBDA:@.+]]([[CAP_TYPE2]]* [[CAP_ARG]])
// CHECK: call void @llvm.stackrestore(
// CHECK: ret void
// CHECK: void [[B_INT]]([[INTPTR_T]]
@@ -107,11 +107,11 @@
// CHECK: store [[INTPTR_T]]* [[BUFFER1_ADDR]], [[INTPTR_T]]** [[CAP_BUFFER1_ADDR_REF]]
// CHECK: [[CAP_BUFFER2_ADDR_REF:%.+]] = getelementptr inbounds [[CAP_TYPE3]], [[CAP_TYPE3]]* [[CAP_ARG]], i{{.+}} 0, i{{.+}} 4
// CHECK: store [[INTPTR_T]]* [[BUFFER2_ADDR]], [[INTPTR_T]]** [[CAP_BUFFER2_ADDR_REF]]
-// CHECK: call void [[B_INT_LAMBDA:@.+]]([[CAP_TYPE3]]* [[CAP_ARG]])
+// CHECK: call{{( x86_thiscallcc)?}} void [[B_INT_LAMBDA:@.+]]([[CAP_TYPE3]]* [[CAP_ARG]])
// CHECK: call void @llvm.stackrestore(
// CHECK: ret void
-// CHECK: define linkonce_odr void [[F_INT_LAMBDA]]([[CAP_TYPE2]]*
+// CHECK: define linkonce_odr{{( x86_thiscallcc)?}} void [[F_INT_LAMBDA]]([[CAP_TYPE2]]*
// CHECK: [[THIS:%.+]] = load [[CAP_TYPE2]]*, [[CAP_TYPE2]]**
// CHECK: [[SIZE_REF:%.+]] = getelementptr inbounds [[CAP_TYPE2]], [[CAP_TYPE2]]* [[THIS]], i{{.+}} 0, i{{.+}} 0
// CHECK: [[SIZE:%.+]] = load [[INTPTR_T]], [[INTPTR_T]]* [[SIZE_REF]]
@@ -120,7 +120,7 @@
// CHECK: call void @llvm.stackrestore(
// CHECK: ret void
-// CHECK: define {{.*}} void [[B_INT_LAMBDA]]([[CAP_TYPE3]]*
+// CHECK: define linkonce_odr{{( x86_thiscallcc)?}} void [[B_INT_LAMBDA]]([[CAP_TYPE3]]*
// CHECK: [[SIZE2_REF:%.+]] = getelementptr inbounds [[CAP_TYPE3]], [[CAP_TYPE3]]* [[THIS:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
// CHECK: [[SIZE2:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[SIZE2_REF]]
// CHECK: [[SIZE1_REF:%.+]] = getelementptr inbounds [[CAP_TYPE3]], [[CAP_TYPE3]]* [[THIS]], i{{[0-9]+}} 0, i{{[0-9]+}} 2
@@ -152,10 +152,10 @@
// CHECK: [[BUFFER1_ADDR_REF_ORIG:%.+]] = getelementptr inbounds [[CAP_TYPE3]], [[CAP_TYPE3]]* [[THIS]], i{{[0-9]+}} 0, i{{[0-9]+}} 3
// CHECK: [[BUFFER1_ADDR_ORIG:%.+]] = load [[INTPTR_T]]*, [[INTPTR_T]]** [[BUFFER1_ADDR_REF_ORIG]]
// CHECK: store [[INTPTR_T]]* [[BUFFER1_ADDR_ORIG]], [[INTPTR_T]]** [[BUFFER1_ADDR_REF]]
-// CHECK: call void [[B_INT_LAMBDA_LAMBDA:@.+]]([[CAP_TYPE4]]* [[CAP]])
+// CHECK: call{{( x86_thiscallcc)?}} void [[B_INT_LAMBDA_LAMBDA:@.+]]([[CAP_TYPE4]]* [[CAP]])
// CHECK: ret void
-// CHECK: define {{.*}} void [[B_INT_LAMBDA_LAMBDA]]([[CAP_TYPE4]]*
+// CHECK: define linkonce_odr{{( x86_thiscallcc)?}} void [[B_INT_LAMBDA_LAMBDA]]([[CAP_TYPE4]]*
// CHECK: [[SIZE1_REF:%.+]] = getelementptr inbounds [[CAP_TYPE4]], [[CAP_TYPE4]]* [[THIS:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
// CHECK: [[SIZE1:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[SIZE1_REF]]
// CHECK: [[SIZE2_REF:%.+]] = getelementptr inbounds [[CAP_TYPE4]], [[CAP_TYPE4]]* [[THIS]], i{{[0-9]+}} 0, i{{[0-9]+}} 3
diff --git a/test/CodeGenObjC/arc-blocks.m b/test/CodeGenObjC/arc-blocks.m
index 76106bb..45599e2 100644
--- a/test/CodeGenObjC/arc-blocks.m
+++ b/test/CodeGenObjC/arc-blocks.m
@@ -87,7 +87,7 @@
// CHECK-NEXT: call void [[F1]](i8* [[BLOCK]], i8** [[TEMP]])
// CHECK-NEXT: [[T0:%.*]] = load i8*, i8** [[TEMP]]
// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]])
- // CHECK-NEXT: call void (...)* @clang.arc.use(i8* [[V]]) [[NUW]]
+ // CHECK-NEXT: call void (...) @clang.arc.use(i8* [[V]]) [[NUW]]
// CHECK-NEXT: [[T2:%.*]] = load i8*, i8** [[STRONG]]
// CHECK-NEXT: store i8* [[T1]], i8** [[STRONG]]
// CHECK-NEXT: call void @objc_release(i8* [[T2]])
diff --git a/test/CodeGenObjC/arc-literals.m b/test/CodeGenObjC/arc-literals.m
index cce4a79..bb7b975 100644
--- a/test/CodeGenObjC/arc-literals.m
+++ b/test/CodeGenObjC/arc-literals.m
@@ -56,7 +56,7 @@
// CHECK-NEXT: [[T2:%.*]] = bitcast [2 x i8*]* [[OBJECTS]] to i8**
// CHECK-NEXT: [[T3:%.*]] = call i8* bitcast ({{.*@objc_msgSend.*}})(i8* [[T1]], i8* [[SEL]], i8** [[T2]], i64 2)
// CHECK-NEXT: [[T4:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T3]])
- // CHECK: call void (...)* @clang.arc.use(i8* [[V0]], i8* [[V1]])
+ // CHECK: call void (...) @clang.arc.use(i8* [[V0]], i8* [[V1]])
id arr = @[a, b];
// CHECK: call void @objc_release
@@ -100,7 +100,7 @@
// CHECK-NEXT: [[T3:%.*]] = bitcast [2 x i8*]* [[KEYS]] to i8**
// CHECK-NEXT: [[T4:%.*]] = call i8* bitcast ({{.*@objc_msgSend.*}})(i8* [[T1]], i8* [[SEL]], i8** [[T2]], i8** [[T3]], i64 2)
// CHECK-NEXT: [[T5:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T4]])
- // CHECK-NEXT: call void (...)* @clang.arc.use(i8* [[V0]], i8* [[V1]], i8* [[V2]], i8* [[V3]])
+ // CHECK-NEXT: call void (...) @clang.arc.use(i8* [[V0]], i8* [[V1]], i8* [[V2]], i8* [[V3]])
id dict = @{ k1 : o1, k2 : o2 };
@@ -145,7 +145,7 @@
// CHECK-NEXT: [[T2:%.*]] = bitcast [1 x i8*]* [[OBJECTS]] to i8**
// CHECK-NEXT: [[T3:%.*]] = call i8* bitcast ({{.*}} @objc_msgSend to {{.*}}(i8* [[T1]], i8* [[SEL]], i8** [[T2]], i64 1)
// CHECK-NEXT: call i8* @objc_retainAutoreleasedReturnValue(i8* [[T3]])
- // CHECK-NEXT: call void (...)* @clang.arc.use(i8* [[V1]])
+ // CHECK-NEXT: call void (...) @clang.arc.use(i8* [[V1]])
// CHECK-NEXT: bitcast
// CHECK-NEXT: bitcast
// CHECK-NEXT: store
diff --git a/test/CodeGenObjC/arc-ternary-op.m b/test/CodeGenObjC/arc-ternary-op.m
index 3e96e40..b9848d7 100644
--- a/test/CodeGenObjC/arc-ternary-op.m
+++ b/test/CodeGenObjC/arc-ternary-op.m
@@ -67,7 +67,7 @@
// CHECK-NEXT: br i1 [[T0]],
// CHECK: [[T0:%.*]] = load i8*, i8** [[TEMP1]]
// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]])
- // CHECK-NEXT: call void (...)* @clang.arc.use(i8* [[W]]) [[NUW]]
+ // CHECK-NEXT: call void (...) @clang.arc.use(i8* [[W]]) [[NUW]]
// CHECK-NEXT: [[T2:%.*]] = load i8*, i8** [[ARG]]
// CHECK-NEXT: store i8* [[T1]], i8** [[ARG]]
// CHECK-NEXT: call void @objc_release(i8* [[T2]])
diff --git a/test/CodeGenObjC/arc.m b/test/CodeGenObjC/arc.m
index 148d8e1..4c96858 100644
--- a/test/CodeGenObjC/arc.m
+++ b/test/CodeGenObjC/arc.m
@@ -875,7 +875,7 @@
// CHECK-NEXT: [[T1:%.*]] = bitcast [[A_T]]* [[T0]] to i8*
// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]])
// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[A_T]]*
- // CHECK-NEXT: call void (...)* @clang.arc.use([[A_T]]* [[W0]]) [[NUW]]
+ // CHECK-NEXT: call void (...) @clang.arc.use([[A_T]]* [[W0]]) [[NUW]]
// CHECK-NEXT: [[T4:%.*]] = load [[A_T]]*, [[A_T]]** [[A]]
// CHECK-NEXT: store [[A_T]]* [[T3]], [[A_T]]** [[A]]
// CHECK-NEXT: [[T5:%.*]] = bitcast [[A_T]]* [[T4]] to i8*
@@ -891,7 +891,7 @@
// CHECK-NEXT: [[T1:%.*]] = bitcast [[A_T]]* [[T0]] to i8*
// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]])
// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[A_T]]*
- // CHECK-NEXT: call void (...)* @clang.arc.use([[A_T]]* [[W0]]) [[NUW]]
+ // CHECK-NEXT: call void (...) @clang.arc.use([[A_T]]* [[W0]]) [[NUW]]
// CHECK-NEXT: [[T4:%.*]] = load [[A_T]]*, [[A_T]]** [[A]]
// CHECK-NEXT: store [[A_T]]* [[T3]], [[A_T]]** [[A]]
// CHECK-NEXT: [[T5:%.*]] = bitcast [[A_T]]* [[T4]] to i8*
@@ -974,7 +974,7 @@
// CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST37]]* [[T1]] to i8*
// CHECK-NEXT: [[T3:%.*]] = call i8* @objc_retain(i8* [[T2]])
// CHECK-NEXT: [[T4:%.*]] = bitcast i8* [[T3]] to [[TEST37]]*
- // CHECK-NEXT: call void (...)* @clang.arc.use(i8* [[W1]]) [[NUW]]
+ // CHECK-NEXT: call void (...) @clang.arc.use(i8* [[W1]]) [[NUW]]
// CHECK-NEXT: [[T5:%.*]] = load [[TEST37]]*, [[TEST37]]** [[VAR]]
// CHECK-NEXT: store [[TEST37]]* [[T4]], [[TEST37]]** [[VAR]]
// CHECK-NEXT: [[T6:%.*]] = bitcast [[TEST37]]* [[T5]] to i8*
diff --git a/test/CodeGenObjC/blocks.m b/test/CodeGenObjC/blocks.m
index fa86e36..091331e 100644
--- a/test/CodeGenObjC/blocks.m
+++ b/test/CodeGenObjC/blocks.m
@@ -116,7 +116,7 @@
// CHECK-NEXT: [[T3:%.*]] = bitcast [[BLOCK_T]]* [[T1]] to i8*
// CHECK-NEXT: [[T4:%.*]] = load i8*, i8** [[T2]]
// CHECK-NEXT: [[T5:%.*]] = bitcast i8* [[T4]] to void (i8*, i32, ...)*
-// CHECK-NEXT: call void (i8*, i32, ...)* [[T5]](i8* [[T3]], i32 0, i32 1, i32 2, i32 3)
+// CHECK-NEXT: call void (i8*, i32, ...) [[T5]](i8* [[T3]], i32 0, i32 1, i32 2, i32 3)
// CHECK-NEXT: ret void
void test4(void (^block)()) {
diff --git a/test/CodeGenObjC/compound-literal-property-access.m b/test/CodeGenObjC/compound-literal-property-access.m
new file mode 100644
index 0000000..bc1bd78
--- /dev/null
+++ b/test/CodeGenObjC/compound-literal-property-access.m
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 %s -emit-llvm -triple x86_64-apple-darwin -o - | FileCheck %s
+// rdar://20407999
+
+typedef __attribute__((__ext_vector_type__(2))) float vector_float2;
+
+@interface GPAgent2D
+@property (nonatomic, assign) vector_float2 position;
+@end
+
+@interface GPGoal @end
+
+@implementation GPGoal
+-(void)getForce {
+ GPAgent2D* targetAgent;
+ (vector_float2){targetAgent.position.x, targetAgent.position.y};
+}
+@end
+
+// CHECK: [[CL:%.*]] = alloca <2 x float>, align 8
+// CHECK: store <2 x float> [[VECINIT:%.*]], <2 x float>* [[CL]]
+// CHECK: [[FOURTEEN:%.*]] = load <2 x float>, <2 x float>* [[CL]]
diff --git a/test/CodeGenObjC/objc2-protocol-metadata.m b/test/CodeGenObjC/objc2-protocol-metadata.m
new file mode 100644
index 0000000..191016b
--- /dev/null
+++ b/test/CodeGenObjC/objc2-protocol-metadata.m
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.10 -emit-llvm -o - %s | FileCheck %s
+// rdar://20286356
+
+@protocol P1
+- InstP;
++ ClsP;
+@end
+
+@interface INTF <P1>
+@end
+
+@implementation INTF
+- InstP { return 0; }
++ ClsP { return 0; }
+@end
+
+// CHECK: %struct._protocol_t = type { i8*, i8*, %struct._objc_protocol_list*, %struct.__method_list_t*, %struct.__method_list_t*, %struct.__method_list_t*, %struct.__method_list_t*, %struct._prop_list_t*, i32, i32, i8**, i8* }
diff --git a/test/CodeGenObjC/objfw.m b/test/CodeGenObjC/objfw.m
index 8e72867..918b9bf 100644
--- a/test/CodeGenObjC/objfw.m
+++ b/test/CodeGenObjC/objfw.m
@@ -9,7 +9,7 @@
[Test0 test];
}
// CHECK-LABEL: define void @test0()
-// CHECK: [[T0:%.*]] = call i8* (i8*, i8*, ...)* (i8*, i8*)* @objc_msg_lookup(i8* bitcast (i64* @_OBJC_CLASS_Test0 to i8*),
+// CHECK: [[T0:%.*]] = call i8* (i8*, i8*, ...)* @objc_msg_lookup(i8* bitcast (i64* @_OBJC_CLASS_Test0 to i8*),
// CHECK-NEXT: [[T1:%.*]] = bitcast i8* (i8*, i8*, ...)* [[T0]] to void (i8*, i8*)*
// CHECK-NEXT: call void [[T1]](i8* bitcast (i64* @_OBJC_CLASS_Test0 to i8*),
// CHECK-NEXT: ret void
diff --git a/test/CodeGenObjC/property.m b/test/CodeGenObjC/property.m
index ee11378..4d88411 100644
--- a/test/CodeGenObjC/property.m
+++ b/test/CodeGenObjC/property.m
@@ -99,7 +99,7 @@
extern int test4_printf(const char *, ...);
// CHECK: [[TMP:%.*]] = call float {{.*}} @objc_msgSend
// CHECK-NEXT: [[EXT:%.*]] = fpext float [[TMP]] to double
- // CHECK-NEXT: call i32 (i8*, ...)* @test4_printf(i8* {{.*}}, double [[EXT]])
+ // CHECK-NEXT: call i32 (i8*, ...) @test4_printf(i8* {{.*}}, double [[EXT]])
// CHECK-NEXT: ret void
test4_printf("%.2f", t.f);
}
diff --git a/test/CodeGenObjC/stret_lookup.m b/test/CodeGenObjC/stret_lookup.m
index 6682fac..9f14798 100644
--- a/test/CodeGenObjC/stret_lookup.m
+++ b/test/CodeGenObjC/stret_lookup.m
@@ -19,11 +19,11 @@
}
// HASSTRET-LABEL: define void @test0()
-// HASSTRET: [[T0:%.*]] = call i8* (i8*, i8*, ...)* (i8*, i8*)* @objc_msg_lookup_stret(i8* bitcast (i64* @_OBJC_CLASS_Test0 to i8*),
+// HASSTRET: [[T0:%.*]] = call i8* (i8*, i8*, ...)* @objc_msg_lookup_stret(i8* bitcast (i64* @_OBJC_CLASS_Test0 to i8*),
// HASSTRET-NEXT: [[T1:%.*]] = bitcast i8* (i8*, i8*, ...)* [[T0]] to void (%struct.test*, i8*, i8*)*
// HASSTRET-NEXT: call void [[T1]](%struct.test* sret {{.*}}, i8* bitcast (i64* @_OBJC_CLASS_Test0 to i8*),
// NOSTRET-LABEL: define void @test0()
-// NOSTRET: [[T0:%.*]] = call i8* (i8*, i8*, ...)* (i8*, i8*)* @objc_msg_lookup(i8*
+// NOSTRET: [[T0:%.*]] = call i8* (i8*, i8*, ...)* @objc_msg_lookup(i8*
// NOSTRET-NEXT: [[T1:%.*]] = bitcast i8* (i8*, i8*, ...)* [[T0]] to void (%struct.test*, i8*, i8*)*
// NOSTRET-NEXT: call void [[T1]](%struct.test* sret {{.*}}, i8* {{.*}}, i8* bitcast ([2 x { i8*, i8* }]*
diff --git a/test/CodeGenObjC/tentative-cfconstantstring.m b/test/CodeGenObjC/tentative-cfconstantstring.m
index 2f31916..5b3c3bd 100644
--- a/test/CodeGenObjC/tentative-cfconstantstring.m
+++ b/test/CodeGenObjC/tentative-cfconstantstring.m
@@ -38,6 +38,6 @@
// CHECK: [[ZERO:%.*]] = load %struct._class_t*, %struct._class_t** @"OBJC_CLASSLIST_REFERENCES_
// CHECK-NEXT: [[ONE:%.*]] = load i8*, i8** @OBJC_SELECTOR_REFERENCES_
// CHECK-NEXT: [[TWO:%.*]] = bitcast %struct._class_t* [[ZERO]] to i8*
-// CHECK-NEXT: call void (i8*, i8*, [[T:%.*]]*, ...)* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, [[T:%.*]]*, ...)*)(i8* [[TWO]], i8* [[ONE]], [[T:%.*]]* bitcast (%struct.NSConstantString* @_unnamed_cfstring_{{.*}} to [[T:%.*]]*))
+// CHECK-NEXT: call void (i8*, i8*, [[T:%.*]]*, ...) bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, [[T:%.*]]*, ...)*)(i8* [[TWO]], i8* [[ONE]], [[T:%.*]]* bitcast (%struct.NSConstantString* @_unnamed_cfstring_{{.*}} to [[T:%.*]]*))
// CHECK-NEXT: ret void
diff --git a/test/CodeGenObjC/variadic-sends.m b/test/CodeGenObjC/variadic-sends.m
index 726b497..3815bb3 100644
--- a/test/CodeGenObjC/variadic-sends.m
+++ b/test/CodeGenObjC/variadic-sends.m
@@ -20,8 +20,8 @@
}
void f2(A *a) {
- // CHECK-X86-32: call void (i8*, i8*, i32, ...)* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, i32, ...)*)
- // CHECK-X86-64: call void (i8*, i8*, i32, ...)* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, i32, ...)*)
+ // CHECK-X86-32: call void (i8*, i8*, i32, ...) bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, i32, ...)*)
+ // CHECK-X86-64: call void (i8*, i8*, i32, ...) bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, i32, ...)*)
[a im2: 1, 2];
}
@@ -33,8 +33,8 @@
[super im1: 1];
}
-(void) bar {
- // CHECK-X86-32: call void (%struct._objc_super*, i8*, i32, ...)* bitcast (i8* (%struct._objc_super*, i8*, ...)* @objc_msgSendSuper to void (%struct._objc_super*, i8*, i32, ...)*)
- // CHECK-X86-64: call void (%struct._objc_super*, i8*, i32, ...)* bitcast (i8* (%struct._objc_super*, i8*, ...)* @objc_msgSendSuper to void (%struct._objc_super*, i8*, i32, ...)*)
+ // CHECK-X86-32: call void (%struct._objc_super*, i8*, i32, ...) bitcast (i8* (%struct._objc_super*, i8*, ...)* @objc_msgSendSuper to void (%struct._objc_super*, i8*, i32, ...)*)
+ // CHECK-X86-64: call void (%struct._objc_super*, i8*, i32, ...) bitcast (i8* (%struct._objc_super*, i8*, ...)* @objc_msgSendSuper to void (%struct._objc_super*, i8*, i32, ...)*)
[super im2: 1, 2];
}
diff --git a/test/CodeGenObjCXX/arc.mm b/test/CodeGenObjCXX/arc.mm
index c66417b..e70af31 100644
--- a/test/CodeGenObjCXX/arc.mm
+++ b/test/CodeGenObjCXX/arc.mm
@@ -82,7 +82,7 @@
// CHECK-NEXT: br i1 [[T0]],
// CHECK: [[T0:%.*]] = load i8*, i8** [[TEMP1]]
// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]])
- // CHECK-NEXT: call void (...)* @clang.arc.use(i8* [[W0]])
+ // CHECK-NEXT: call void (...) @clang.arc.use(i8* [[W0]])
// CHECK-NEXT: [[T2:%.*]] = load i8*, i8** [[ARG]]
// CHECK-NEXT: store i8* [[T1]], i8** [[ARG]]
// CHECK-NEXT: call void @objc_release(i8* [[T2]])
diff --git a/test/CodeGenObjCXX/lambda-expressions.mm b/test/CodeGenObjCXX/lambda-expressions.mm
index 4d9b8d0..0c309c0 100644
--- a/test/CodeGenObjCXX/lambda-expressions.mm
+++ b/test/CodeGenObjCXX/lambda-expressions.mm
@@ -10,8 +10,8 @@
// MRC-LABEL: define internal i32 ()* @"_ZZ1fvENK3$_0cvU13block_pointerFivEEv"
// MRC: store i8* bitcast (i8** @_NSConcreteStackBlock to i8*)
// MRC: store i8* bitcast (i32 (i8*)* @"___ZZ1fvENK3$_0cvU13block_pointerFivEEv_block_invoke" to i8*)
-// MRC: call i32 ()* (i8*, i8*)* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i32 ()* (i8*, i8*)*)
-// MRC: call i32 ()* (i8*, i8*)* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i32 ()* (i8*, i8*)*)
+// MRC: call i32 ()* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i32 ()* (i8*, i8*)*)
+// MRC: call i32 ()* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i32 ()* (i8*, i8*)*)
// MRC: ret i32 ()*
// ARC-LABEL: define i32 ()* @_Z1fv(
diff --git a/test/CodeGenOpenCL/memcpy.cl b/test/CodeGenOpenCL/memcpy.cl
new file mode 100644
index 0000000..cb27803
--- /dev/null
+++ b/test/CodeGenOpenCL/memcpy.cl
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 %s -ffake-address-space-map -emit-llvm -o - | FileCheck %s
+
+// CHECK-LABEL: @test
+// CHECK-NOT: addrspacecast
+// CHECK: call void @llvm.memcpy.p1i8.p3i8
+kernel void test(global float *g, constant float *c) {
+ __builtin_memcpy(g, c, 32);
+}
diff --git a/test/CodeGenOpenCL/relaxed-fpmath.cl b/test/CodeGenOpenCL/relaxed-fpmath.cl
index 4222ea9..6f302b1 100644
--- a/test/CodeGenOpenCL/relaxed-fpmath.cl
+++ b/test/CodeGenOpenCL/relaxed-fpmath.cl
@@ -2,7 +2,6 @@
// RUN: %clang_cc1 %s -emit-llvm -cl-fast-relaxed-math -o - | FileCheck %s -check-prefix=FAST
// RUN: %clang_cc1 %s -emit-llvm -cl-finite-math-only -o - | FileCheck %s -check-prefix=FINITE
// RUN: %clang_cc1 %s -emit-llvm -cl-unsafe-math-optimizations -o - | FileCheck %s -check-prefix=UNSAFE
-// RUN: %clang_cc1 %s -emit-llvm -cl-no-signed-zeros -o - | FileCheck %s -check-prefix=NOSZ
typedef __attribute__(( ext_vector_type(4) )) float float4;
@@ -13,7 +12,6 @@
// FAST: fdiv fast float
// FINITE: fdiv nnan ninf float
// UNSAFE: fdiv nnan float
- // NOSZ: fdiv nsz float
return a / b;
}
// CHECK: attributes
diff --git a/test/Driver/aarch64-cpus.c b/test/Driver/aarch64-cpus.c
index 4380381..43e3ccd 100644
--- a/test/Driver/aarch64-cpus.c
+++ b/test/Driver/aarch64-cpus.c
@@ -88,3 +88,26 @@
// RUN: %clang -target aarch64 -mcpu=cortex-a72 -mtune=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=MCPU-MTUNE %s
// RUN: %clang -target aarch64 -mtune=cortex-a53 -mcpu=cortex-a72 -### -c %s 2>&1 | FileCheck -check-prefix=MCPU-MTUNE %s
// MCPU-MTUNE: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "cortex-a53"
+
+// RUN: %clang -target aarch64 -march=armv8.1a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV81A %s
+// RUN: %clang -target aarch64 -march=armv8.1-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV81A %s
+// RUN: %clang -target aarch64 -mlittle-endian -march=armv8.1a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV81A %s
+// RUN: %clang -target aarch64 -mlittle-endian -march=armv8.1-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV81A %s
+// RUN: %clang -target aarch64_be -mlittle-endian -march=armv8.1a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV81A %s
+// RUN: %clang -target aarch64_be -mlittle-endian -march=armv8.1-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV81A %s
+// GENERICV81A: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "generic" "-target-feature" "+neon" "-target-feature" "+v8.1a"
+
+// RUN: %clang -target arm64 -march=armv8.1a -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-GENERICV81A %s
+// RUN: %clang -target arm64 -march=armv8.1-a -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-GENERICV81A %s
+// RUN: %clang -target arm64 -mlittle-endian -march=armv8.1a -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-GENERICV81A %s
+// RUN: %clang -target arm64 -mlittle-endian -march=armv8.1-a -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-GENERICV81A %s
+// ARM64-GENERICV81A: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "generic" "-target-feature" "+neon" "-target-feature" "+v8.1a"
+
+// RUN: %clang -target aarch64_be -march=armv8.1a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV81A-BE %s
+// RUN: %clang -target aarch64_be -march=armv8.1-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV81A-BE %s
+// RUN: %clang -target aarch64 -mbig-endian -march=armv8.1a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV81A-BE %s
+// RUN: %clang -target aarch64 -mbig-endian -march=armv8.1-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV81A-BE %s
+// RUN: %clang -target aarch64_be -mbig-endian -march=armv8.1a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV81A-BE %s
+// RUN: %clang -target aarch64_be -mbig-endian -march=armv8.1-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV81A-BE %s
+// GENERICV81A-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic" "-target-feature" "+neon" "-target-feature" "+v8.1a"
+
diff --git a/test/Driver/arm-cortex-cpus.c b/test/Driver/arm-cortex-cpus.c
index 2d6c7e6..7810bdd 100644
--- a/test/Driver/arm-cortex-cpus.c
+++ b/test/Driver/arm-cortex-cpus.c
@@ -281,33 +281,41 @@
// CHECK-BE-CPUV7EM: "-cc1"{{.*}} "-triple" "thumbebv7em-{{.*}}
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-r4 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7R %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-r4f -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7R %s
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-r5 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7R %s
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-r7 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7R %s
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-r4 -mlittle-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7R %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-r4f -mlittle-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7R %s
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-r5 -mlittle-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7R %s
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-r7 -mlittle-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7R %s
// CHECK-CPUV7R: "-cc1"{{.*}} "-triple" "armv7r-{{.*}}
// RUN: %clang -target armeb-linux-gnueabi -mcpu=cortex-r4 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7R %s
+// RUN: %clang -target armeb-linux-gnueabi -mcpu=cortex-r4f -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7R %s
// RUN: %clang -target armeb-linux-gnueabi -mcpu=cortex-r5 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7R %s
// RUN: %clang -target armeb-linux-gnueabi -mcpu=cortex-r7 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7R %s
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-r4 -mbig-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7R %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-r4f -mbig-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7R %s
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-r5 -mbig-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7R %s
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-r7 -mbig-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7R %s
// CHECK-BE-CPUV7R: "-cc1"{{.*}} "-triple" "armebv7r-{{.*}}
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-r4 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7R-THUMB %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-r4f -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7R-THUMB %s
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-r5 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7R-THUMB %s
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-r7 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7R-THUMB %s
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-r4 -mlittle-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7R-THUMB %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-r4f -mlittle-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7R-THUMB %s
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-r5 -mlittle-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7R-THUMB %s
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-r7 -mlittle-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7R-THUMB %s
// CHECK-CPUV7R-THUMB: "-cc1"{{.*}} "-triple" "thumbv7r-{{.*}}
// RUN: %clang -target armeb-linux-gnueabi -mcpu=cortex-r4 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7R-THUMB %s
+// RUN: %clang -target armeb-linux-gnueabi -mcpu=cortex-r4f -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7R-THUMB %s
// RUN: %clang -target armeb-linux-gnueabi -mcpu=cortex-r5 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7R-THUMB %s
// RUN: %clang -target armeb-linux-gnueabi -mcpu=cortex-r7 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7R-THUMB %s
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-r4 -mbig-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7R-THUMB %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-r4f -mbig-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7R-THUMB %s
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-r5 -mbig-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7R-THUMB %s
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-r7 -mbig-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7R-THUMB %s
// CHECK-BE-CPUV7R-THUMB: "-cc1"{{.*}} "-triple" "thumbebv7r-{{.*}}
diff --git a/test/Driver/cl-options.c b/test/Driver/cl-options.c
index 3a22154..e36462d 100644
--- a/test/Driver/cl-options.c
+++ b/test/Driver/cl-options.c
@@ -30,6 +30,24 @@
// EP: "-P"
// EP: "-o" "-"
+// RUN: %clang_cl /fp:fast /fp:except -### -- %s 2>&1 | FileCheck -check-prefix=fpexcept %s
+// fpexcept-NOT: -menable-unsafe-fp-math
+
+// RUN: %clang_cl /fp:fast /fp:except /fp:except- -### -- %s 2>&1 | FileCheck -check-prefix=fpexcept_ %s
+// fpexcept_: -menable-unsafe-fp-math
+
+// RUN: %clang_cl /fp:precise /fp:fast -### -- %s 2>&1 | FileCheck -check-prefix=fpfast %s
+// fpfast: -menable-unsafe-fp-math
+// fpfast: -ffast-math
+
+// RUN: %clang_cl /fp:fast /fp:precise -### -- %s 2>&1 | FileCheck -check-prefix=fpprecise %s
+// fpprecise-NOT: -menable-unsafe-fp-math
+// fpprecise-NOT: -ffast-math
+
+// RUN: %clang_cl /fp:fast /fp:strict -### -- %s 2>&1 | FileCheck -check-prefix=fpstrict %s
+// fpstrict-NOT: -menable-unsafe-fp-math
+// fpstrict-NOT: -ffast-math
+
// RTTI is on by default; just check that we don't error.
// RUN: %clang_cl /Zs /GR -- %s 2>&1
@@ -243,7 +261,6 @@
// RUN: /Fifoo \
// RUN: /Fmfoo \
// RUN: /FpDebug\main.pch \
-// RUN: /fp:precise \
// RUN: /Frfoo \
// RUN: /FRfoo \
// RUN: /FU foo \
@@ -326,16 +343,22 @@
// ThreadSafeStatics-NOT: "-fno-threadsafe-statics"
// Accept "core" clang options.
-// (/Zs is for syntax-only)
+// (/Zs is for syntax-only, -Werror makes it fail hard on unknown options)
// RUN: %clang_cl \
// RUN: --driver-mode=cl \
+// RUN: -fcolor-diagnostics \
+// RUN: -fno-color-diagnostics \
+// RUN: -fdiagnostics-color \
+// RUN: -fno-diagnostics-color \
// RUN: -ferror-limit=10 \
// RUN: -fmsc-version=1800 \
// RUN: -fno-strict-aliasing \
// RUN: -fstrict-aliasing \
+// RUN: -fsyntax-only \
// RUN: -mllvm -disable-llvm-optzns \
-// RUN: -Wunused-variables \
-// RUN: /Zs -- %s 2>&1
+// RUN: -Wunused-variable \
+// RUN: -fmacro-backtrace-limit=0 \
+// RUN: -Werror /Zs -- %s 2>&1
void f() { }
diff --git a/test/Driver/darwin-version.c b/test/Driver/darwin-version.c
index 8e90927..3e7496b 100644
--- a/test/Driver/darwin-version.c
+++ b/test/Driver/darwin-version.c
@@ -30,6 +30,9 @@
// RUN: %clang -target x86_64-apple-macosx -mmacosx-version-min=10.10 -c %s -### 2>&1 | \
// RUN: FileCheck --check-prefix=CHECK-VERSION-OSX10 %s
// CHECK-VERSION-OSX10: "x86_64-apple-macosx10.10.0"
+// RUN: %clang -target x86_64-apple-macosx -mmacosx-version-min= -c %s -### 2>&1 | \
+// RUN: FileCheck --check-prefix=CHECK-VERSION-MISSING %s
+// CHECK-VERSION-MISSING: invalid version number
// Check environment variable gets interpreted correctly
// RUN: env MACOSX_DEPLOYMENT_TARGET=10.5 \
diff --git a/test/Driver/fast-math.c b/test/Driver/fast-math.c
index bacd7fe..24c3038 100644
--- a/test/Driver/fast-math.c
+++ b/test/Driver/fast-math.c
@@ -40,6 +40,21 @@
// CHECK-NO-SIGNED-ZEROS-NO-FAST-MATH: "-cc1"
// CHECK-NO-SIGNED-ZEROS-NO-FAST-MATH-NOT: "-fno-signed-zeros"
//
+// RUN: %clang -### -freciprocal-math -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-RECIPROCAL-MATH %s
+// CHECK-RECIPROCAL-MATH: "-cc1"
+// CHECK-RECIPROCAL-MATH: "-freciprocal-math"
+//
+// RUN: %clang -### -fno-fast-math -freciprocal-math -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NO-FAST-MATH-RECIPROCAL-MATH %s
+// CHECK-NO-FAST-MATH-RECIPROCAL-MATH: "-cc1"
+// CHECK-NO-FAST-MATH-RECIPROCAL-MATH: "-freciprocal-math"
+//
+// RUN: %clang -### -freciprocal-math -fno-fast-math -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-RECIPROCAL-MATH-NO-FAST-MATH %s
+// CHECK-RECIPROCAL-MATH-NO-FAST-MATH: "-cc1"
+// CHECK-RECIPROCAL-MATH-NO-FAST-MATH-NOT: "-freciprocal-math"
+//
// RUN: %clang -### -fno-honor-nans -c %s 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-NO-NANS %s
// CHECK-NO-NANS: "-cc1"
diff --git a/test/Driver/fsanitize.c b/test/Driver/fsanitize.c
index da8ace3..994b2b2 100644
--- a/test/Driver/fsanitize.c
+++ b/test/Driver/fsanitize.c
@@ -206,11 +206,13 @@
// RUN: %clang -target x86_64-linux-gnu -fsanitize=cfi -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI
// RUN: %clang -target x86_64-linux-gnu -fsanitize=cfi-derived-cast -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI-DCAST
// RUN: %clang -target x86_64-linux-gnu -fsanitize=cfi-unrelated-cast -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI-UCAST
-// RUN: %clang -target x86_64-linux-gnu -fsanitize=cfi-vptr -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI-VPTR
-// CHECK-CFI: -emit-llvm-bc{{.*}}-fsanitize=cfi-derived-cast,cfi-unrelated-cast,cfi-vptr
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=cfi-nvcall -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI-NVCALL
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=cfi-vcall -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI-VCALL
+// CHECK-CFI: -emit-llvm-bc{{.*}}-fsanitize=cfi-derived-cast,cfi-unrelated-cast,cfi-nvcall,cfi-vcall
// CHECK-CFI-DCAST: -emit-llvm-bc{{.*}}-fsanitize=cfi-derived-cast
// CHECK-CFI-UCAST: -emit-llvm-bc{{.*}}-fsanitize=cfi-unrelated-cast
-// CHECK-CFI-VPTR: -emit-llvm-bc{{.*}}-fsanitize=cfi-vptr
+// CHECK-CFI-NVCALL: -emit-llvm-bc{{.*}}-fsanitize=cfi-nvcall
+// CHECK-CFI-VCALL: -emit-llvm-bc{{.*}}-fsanitize=cfi-vcall
// RUN: %clang_cl -fsanitize=address -c -MDd -### -- %s 2>&1 | FileCheck %s -check-prefix=CHECK-ASAN-DEBUGRTL
// RUN: %clang_cl -fsanitize=address -c -MTd -### -- %s 2>&1 | FileCheck %s -check-prefix=CHECK-ASAN-DEBUGRTL
@@ -229,3 +231,11 @@
// RUN: %clang_cl -fsanitize=address -c -MDd -MD -### -- %s 2>&1 | FileCheck %s -check-prefix=CHECK-ASAN-RELEASERTL
// RUN: %clang_cl -fsanitize=address -c -LDd -LD -### -- %s 2>&1 | FileCheck %s -check-prefix=CHECK-ASAN-RELEASERTL
// CHECK-ASAN-RELEASERTL-NOT: error: invalid argument
+
+// RUN: %clang_cl -fsanitize=address -fsanitize-coverage=1 -c -### -- %s 2>&1 | FileCheck %s -check-prefix=CLANG-CL-COVERAGE
+// CLANG-CL-COVERAGE-NOT: error:
+// CLANG-CL-COVERAGE-NOT: warning:
+// CLANG-CL-COVERAGE-NOT: argument unused
+// CLANG-CL-COVERAGE-NOT: unknown argument
+// CLANG-CL-COVERAGE: -fsanitize=address
+// CLANG-CL-COVERAGE: -fsanitize-coverage=1
diff --git a/test/Driver/function-sections.c b/test/Driver/function-sections.c
index ba065b1..6c24319 100644
--- a/test/Driver/function-sections.c
+++ b/test/Driver/function-sections.c
@@ -72,3 +72,13 @@
// RUN: -target i386-unknown-linux \
// RUN: -fno-unique-section-names \
// RUN: | FileCheck --check-prefix=CHECK-NOUS %s
+
+// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
+// RUN: -target i386-unknown-linux \
+// RUN: -fno-integrated-as \
+// RUN: | FileCheck --check-prefix=CHECK-US %s
+
+// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
+// RUN: -target i386-unknown-linux \
+// RUN: -fintegrated-as \
+// RUN: | FileCheck --check-prefix=CHECK-NOUS %s
diff --git a/test/Driver/mglobal-merge.c b/test/Driver/mglobal-merge.c
new file mode 100644
index 0000000..ad76736
--- /dev/null
+++ b/test/Driver/mglobal-merge.c
@@ -0,0 +1,40 @@
+// RUN: %clang -target armv7-unknown-unknown -### -fsyntax-only %s 2> %t \
+// RUN: -mno-global-merge
+// RUN: FileCheck --check-prefix=CHECK-NGM-ARM < %t %s
+
+// RUN: %clang -target aarch64-unknown-unknown -### -fsyntax-only %s 2> %t \
+// RUN: -mno-global-merge
+// RUN: FileCheck --check-prefix=CHECK-NGM-AARCH64 < %t %s
+
+// RUN: %clang -target x86_64-unknown-unknown -### -fsyntax-only %s 2> %t \
+// RUN: -mno-global-merge
+// RUN: FileCheck --check-prefix=CHECK-NONE < %t %s
+
+// CHECK-NGM-ARM: "-backend-option" "-arm-global-merge=false"
+// CHECK-NGM-AARCH64: "-backend-option" "-aarch64-global-merge=false"
+
+// RUN: %clang -target armv7-unknown-unknown -### -fsyntax-only %s 2> %t \
+// RUN: -mglobal-merge
+// RUN: FileCheck --check-prefix=CHECK-GM-ARM < %t %s
+
+// RUN: %clang -target aarch64-unknown-unknown -### -fsyntax-only %s 2> %t \
+// RUN: -mglobal-merge
+// RUN: FileCheck --check-prefix=CHECK-GM-AARCH64 < %t %s
+
+// RUN: %clang -target x86_64-unknown-unknown -### -fsyntax-only %s 2> %t \
+// RUN: -mglobal-merge
+// RUN: FileCheck --check-prefix=CHECK-NONE < %t %s
+
+// CHECK-GM-ARM: "-backend-option" "-arm-global-merge=true"
+// CHECK-GM-AARCH64: "-backend-option" "-aarch64-global-merge=true"
+
+// RUN: %clang -target armv7-unknown-unknown -### -fsyntax-only %s 2> %t
+// RUN: FileCheck --check-prefix=CHECK-NONE < %t %s
+
+// RUN: %clang -target aarch64-unknown-unknown -### -fsyntax-only %s 2> %t
+// RUN: FileCheck --check-prefix=CHECK-NONE < %t %s
+
+// RUN: %clang -target x86_64-unknown-unknown -### -fsyntax-only %s 2> %t
+// RUN: FileCheck --check-prefix=CHECK-NONE < %t %s
+
+// CHECK-NONE-NOT: -global-merge=
diff --git a/test/Driver/mips-features.c b/test/Driver/mips-features.c
index f702230..5094f2b 100644
--- a/test/Driver/mips-features.c
+++ b/test/Driver/mips-features.c
@@ -105,13 +105,13 @@
// CHECK-NOMFP64: "-target-feature" "-fp64"
//
// -mnan=2008
-// RUN: %clang -target mips-linux-gnu -### -c %s \
+// RUN: %clang -target mips-linux-gnu -march=mips32r3 -### -c %s \
// RUN: -mnan=legacy -mnan=2008 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-NAN2008 %s
// CHECK-NAN2008: "-target-feature" "+nan2008"
//
// -mnan=legacy
-// RUN: %clang -target mips-linux-gnu -### -c %s \
+// RUN: %clang -target mips-linux-gnu -march=mips32r3 -### -c %s \
// RUN: -mnan=2008 -mnan=legacy 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-NANLEGACY %s
// CHECK-NANLEGACY: "-target-feature" "-nan2008"
diff --git a/test/Driver/mips-integrated-as.s b/test/Driver/mips-integrated-as.s
index 08adb20..2c298e7 100644
--- a/test/Driver/mips-integrated-as.s
+++ b/test/Driver/mips-integrated-as.s
@@ -62,7 +62,7 @@
// NAN-LEGACY: -cc1as
// NAN-LEGACY: "-target-feature" "-nan2008"
-// RUN: %clang -target mips-linux-gnu -### -fintegrated-as -c %s -mnan=2008 2>&1 | \
+// RUN: %clang -target mips-linux-gnu -march=mips32r6 -### -fintegrated-as -c %s -mnan=2008 2>&1 | \
// RUN: FileCheck -check-prefix=NAN-2008 %s
// NAN-2008: -cc1as
// NAN-2008: "-target-feature" "+nan2008"
diff --git a/test/Driver/mno-global-merge.c b/test/Driver/mno-global-merge.c
deleted file mode 100644
index a17848f..0000000
--- a/test/Driver/mno-global-merge.c
+++ /dev/null
@@ -1,20 +0,0 @@
-// RUN: %clang -target armv7-apple-darwin10 \
-// RUN: -mno-global-merge -### -fsyntax-only %s 2> %t
-// RUN: FileCheck --check-prefix=CHECK-NGM < %t %s
-
-// RUN: %clang -target arm64-apple-ios7 \
-// RUN: -mno-global-merge -### -fsyntax-only %s 2> %t
-// RUN: FileCheck --check-prefix=CHECK-NGM < %t %s
-
-// CHECK-NGM: "-mno-global-merge"
-
-// RUN: %clang -target armv7-apple-darwin10 \
-// RUN: -mglobal-merge -### -fsyntax-only %s 2> %t
-// RUN: FileCheck --check-prefix=CHECK-GM < %t %s
-
-// RUN: %clang -target arm64-apple-ios7 \
-// RUN: -mglobal-merge -### -fsyntax-only %s 2> %t
-// RUN: FileCheck --check-prefix=CHECK-GM < %t %s
-
-// CHECK-GM-NOT: "-mglobal-merge"
-
diff --git a/test/Driver/nacl-direct.c b/test/Driver/nacl-direct.c
new file mode 100644
index 0000000..9768eab
--- /dev/null
+++ b/test/Driver/nacl-direct.c
@@ -0,0 +1,111 @@
+// Test clang changes for NaCl Support including:
+// include paths, library paths, emulation, default static
+//
+// RUN: %clang -no-canonical-prefixes -### -o %t.o %s \
+// RUN: -target i686-unknown-nacl -resource-dir foo 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-I686 %s
+// CHECK-I686: {{.*}}clang{{.*}}" "-cc1"
+// CHECK-I686: "-fuse-init-array"
+// CHECK-I686: "-target-cpu" "pentium4"
+// CHECK-I686: "-resource-dir" "foo"
+// CHECK-I686: "-internal-isystem" "foo{{/|\\\\}}include"
+// CHECK-I686: "-internal-isystem" "{{.*}}{{/|\\\\}}..{{/|\\\\}}x86_64-nacl{{/|\\\\}}usr{{/|\\\\}}include"
+// CHECK-I686: "-internal-isystem" "{{.*}}{{/|\\\\}}..{{/|\\\\}}x86_64-nacl{{/|\\\\}}include"
+// CHECK-I686: as{{(.exe)?}}" "--32"
+// CHECK-I686: ld{{(.exe)?}}"
+// CHECK-I686: "--build-id"
+// CHECK-I686: "-m" "elf_i386_nacl"
+// CHECK-I686: "-static"
+// CHECK-I686: "-L{{.*}}{{/|\\\\}}..{{/|\\\\}}x86_64-nacl{{/|\\\\}}lib32"
+// CHECK-I686: "-L{{.*}}{{/|\\\\}}..{{/|\\\\}}x86_64-nacl{{/|\\\\}}usr{{/|\\\\}}lib32"
+// CHECK-I686: "-Lfoo{{/|\\\\}}lib{{/|\\\\}}i686-nacl"
+// CHECK-I686-NOT: -lpthread
+//
+// RUN: %clang -no-canonical-prefixes -### -o %t.o %s \
+// RUN: -target x86_64-unknown-nacl -resource-dir foo 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-x86_64 %s
+// CHECK-x86_64: {{.*}}clang{{.*}}" "-cc1"
+// CHECK-x86_64: "-fuse-init-array"
+// CHECK-x86_64: "-target-cpu" "x86-64"
+// CHECK-x86_64: "-resource-dir" "foo"
+// CHECK-x86_64: "-internal-isystem" "foo{{/|\\\\}}include"
+// CHECK-x86_64: "-internal-isystem" "{{.*}}{{/|\\\\}}..{{/|\\\\}}x86_64-nacl{{/|\\\\}}usr{{/|\\\\}}include"
+// CHECK-x86_64: "-internal-isystem" "{{.*}}{{/|\\\\}}..{{/|\\\\}}x86_64-nacl{{/|\\\\}}include"
+// CHECK-x86_64: as{{(.exe)?}}" "--64"
+// CHECK-x86_64: ld{{(.exe)?}}"
+// CHECK-x86_64: "--build-id"
+// CHECK-x86_64: "-m" "elf_x86_64_nacl"
+// CHECK-x86_64: "-static"
+// CHECK-x86_64: "-L{{.*}}{{/|\\\\}}..{{/|\\\\}}x86_64-nacl{{/|\\\\}}lib"
+// CHECK-x86_64: "-L{{.*}}{{/|\\\\}}..{{/|\\\\}}x86_64-nacl{{/|\\\\}}usr{{/|\\\\}}lib"
+// CHECK-x86_64: "-Lfoo{{/|\\\\}}lib{{/|\\\\}}x86_64-nacl"
+// CHECK-X86_64-NOT: -lpthread
+//
+// RUN: %clang -no-canonical-prefixes -### -o %t.o %s \
+// RUN: -target armv7a-unknown-nacl-gnueabihf -resource-dir foo 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-ARM %s
+// CHECK-ARM: {{.*}}clang{{.*}}" "-cc1"
+// CHECK-ARM: "-fuse-init-array"
+// CHECK-ARM: "-target-cpu" "cortex-a8"
+// CHECK-ARM: "-target-abi" "aapcs-linux"
+// CHECK-ARM: "-mfloat-abi" "hard"
+// CHECK-ARM: "-resource-dir" "foo"
+// CHECK-ARM: "-internal-isystem" "foo{{/|\\\\}}include"
+// CHECK-ARM: "-internal-isystem" "{{.*}}{{/|\\\\}}..{{/|\\\\}}arm-nacl{{/|\\\\}}usr{{/|\\\\}}include"
+// CHECK-ARM: "-internal-isystem" "{{.*}}{{/|\\\\}}..{{/|\\\\}}arm-nacl{{/|\\\\}}include"
+// CHECK-ARM: as{{(.exe)?}}"
+// CHECK-ARM: "-mfloat-abi=hard"
+// CHECK-ARM: ld{{(.exe)?}}"
+// CHECK-ARM: "--build-id"
+// CHECK-ARM: "-m" "armelf_nacl"
+// CHECK-ARM: "-static"
+// CHECK-ARM: "-L{{.*}}{{/|\\\\}}..{{/|\\\\}}arm-nacl{{/|\\\\}}lib"
+// CHECK-ARM: "-L{{.*}}{{/|\\\\}}..{{/|\\\\}}arm-nacl{{/|\\\\}}usr{{/|\\\\}}lib"
+// CHECK-ARM: "-Lfoo{{/|\\\\}}lib{{/|\\\\}}arm-nacl"
+// CHECK-ARM-NOT: -lpthread
+
+// Check that even when the target arch is just "arm" (as will be the case when
+// it is inferred from the binary name) that we get the right ABI flags
+// RUN: %clang -no-canonical-prefixes -### -o %t.o %s 2>&1 \
+// RUN: -target arm-nacl \
+// RUN: | FileCheck --check-prefix=CHECK-ARM-NOV7 %s
+// CHECK-ARM-NOV7: "-triple" "armv7--nacl-gnueabihf"
+// CHECK-ARM-NOV7: "-target-abi" "aapcs-linux"
+// CHECK-ARM-NOV7: "-mfloat-abi" "hard"
+// CHECK-ARM-NOV7: as{{(.exe)?}}"
+// CHECK-ARM-NOV7: "-mfloat-abi=hard"
+
+// Test clang c++ include dirs and link line when using clang++
+
+// RUN: %clangxx -no-canonical-prefixes -### -o %t.o %s \
+// RUN: -target armv7a-unknown-nacl-gnueabihf -resource-dir foo 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-ARM-CXX %s
+// CHECK-ARM-CXX: {{.*}}clang{{.*}}" "-cc1"
+// CHECK-ARM-CXX: "-resource-dir" "foo"
+// CHECK-ARM-CXX: "-internal-isystem" "{{.*}}{{/|\\\\}}..{{/|\\\\}}arm-nacl{{/|\\\\}}include{{/|\\\\}}c++{{/|\\\\}}v1"
+// CHECK-ARM-CXX: "-internal-isystem" "foo{{/|\\\\}}include"
+// CHECK-ARM-CXX: "-internal-isystem" "{{.*}}{{/|\\\\}}..{{/|\\\\}}arm-nacl{{/|\\\\}}usr{{/|\\\\}}include"
+// CHECK-ARM-CXX: "-internal-isystem" "{{.*}}{{/|\\\\}}..{{/|\\\\}}arm-nacl{{/|\\\\}}include"
+// CHECK-ARM-CXX: "-lpthread"
+
+// RUN: %clangxx -no-canonical-prefixes -### -o %t.o %s \
+// RUN: -target i686-unknown-nacl -resource-dir foo 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-I686-CXX %s
+// CHECK-I686-CXX: {{.*}}clang{{.*}}" "-cc1"
+// CHECK-I686-CXX: "-resource-dir" "foo"
+// CHECK-I686-CXX: "-internal-isystem" "{{.*}}{{/|\\\\}}..{{/|\\\\}}x86_64-nacl{{/|\\\\}}include{{/|\\\\}}c++{{/|\\\\}}v1"
+// CHECK-I686-CXX: "-internal-isystem" "foo{{/|\\\\}}include"
+// CHECK-I686-CXX: "-internal-isystem" "{{.*}}{{/|\\\\}}..{{/|\\\\}}x86_64-nacl{{/|\\\\}}usr{{/|\\\\}}include"
+// CHECK-I686-CXX: "-internal-isystem" "{{.*}}{{/|\\\\}}..{{/|\\\\}}x86_64-nacl{{/|\\\\}}include"
+// CHECK-I686-CXX: "-lpthread"
+
+// RUN: %clangxx -no-canonical-prefixes -### -o %t.o %s \
+// RUN: -target x86_64-unknown-nacl -resource-dir foo 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-x86_64-CXX %s
+// CHECK-x86_64-CXX: {{.*}}clang{{.*}}" "-cc1"
+// CHECK-x86_64-CXX: "-resource-dir" "foo"
+// CHECK-x86_64-CXX: "-internal-isystem" "{{.*}}{{/|\\\\}}..{{/|\\\\}}x86_64-nacl{{/|\\\\}}include{{/|\\\\}}c++{{/|\\\\}}v1"
+// CHECK-x86_64-CXX: "-internal-isystem" "foo{{/|\\\\}}include"
+// CHECK-x86_64-CXX: "-internal-isystem" "{{.*}}{{/|\\\\}}..{{/|\\\\}}x86_64-nacl{{/|\\\\}}usr{{/|\\\\}}include"
+// CHECK-x86_64-CXX: "-internal-isystem" "{{.*}}{{/|\\\\}}..{{/|\\\\}}x86_64-nacl{{/|\\\\}}include"
+// CHECK-x86_64-CXX: "-lpthread"
diff --git a/test/Driver/ppc-features.cpp b/test/Driver/ppc-features.cpp
index 39d6357..8ef8318 100644
--- a/test/Driver/ppc-features.cpp
+++ b/test/Driver/ppc-features.cpp
@@ -77,6 +77,12 @@
// RUN: %clang -target powerpc64-unknown-linux-gnu %s -mno-mfcrf -mmfcrf -### -o %t.o 2>&1 | FileCheck -check-prefix=CHECK-MFCRF %s
// CHECK-MFCRF: "-target-feature" "+mfocrf"
+// RUN: %clang -target powerpc64-unknown-linux-gnu %s -mno-isel -### -o %t.o 2>&1 | FileCheck -check-prefix=CHECK-NOISEL %s
+// CHECK-NOISEL: "-target-feature" "-isel"
+
+// RUN: %clang -target powerpc64-unknown-linux-gnu %s -mno-isel -misel -### -o %t.o 2>&1 | FileCheck -check-prefix=CHECK-ISEL %s
+// CHECK-ISEL: "-target-feature" "+isel"
+
// RUN: %clang -target powerpc64-unknown-linux-gnu %s -mno-popcntd -### -o %t.o 2>&1 | FileCheck -check-prefix=CHECK-NOPOPCNTD %s
// CHECK-NOPOPCNTD: "-target-feature" "-popcntd"
diff --git a/test/Driver/preserve-uselistorder.c b/test/Driver/preserve-uselistorder.c
new file mode 100644
index 0000000..aee75a6
--- /dev/null
+++ b/test/Driver/preserve-uselistorder.c
@@ -0,0 +1,9 @@
+// RUN: %clang -target x86_64-apple-darwin -emit-llvm -arch x86_64 %s -### 2>&1 \
+// RUN: | FileCheck %s
+// CHECK: "-emit-llvm-bc"
+// CHECK: "-emit-llvm-uselists"
+
+// RUN: %clang -target x86_64-apple-darwin -flto -arch x86_64 %s -### 2>&1 \
+// RUN: | FileCheck -check-prefix=LTO %s
+// LTO: "-emit-llvm-bc"
+// LTO-NOT: "-emit-llvm-uselists"
diff --git a/test/Driver/sanitizer-ld.c b/test/Driver/sanitizer-ld.c
index 97205f4..a95a833 100644
--- a/test/Driver/sanitizer-ld.c
+++ b/test/Driver/sanitizer-ld.c
@@ -227,8 +227,7 @@
// RUN: | FileCheck --check-prefix=CHECK-ASAN-UBSAN-LINUX %s
// CHECK-ASAN-UBSAN-LINUX: "{{.*}}ld{{(.exe)?}}"
// CHECK-ASAN-UBSAN-LINUX: "-whole-archive" "{{.*}}libclang_rt.asan-i386.a" "-no-whole-archive"
-// CHECK-ASAN-UBSAN-LINUX: "-whole-archive" "{{.*}}libclang_rt.ubsan-i386.a" "-no-whole-archive"
-// CHECK-ASAN-UBSAN-LINUX-NOT: libclang_rt.ubsan_cxx
+// CHECK-ASAN-UBSAN-LINUX-NOT: libclang_rt.ubsan
// CHECK-ASAN-UBSAN-LINUX-NOT: "-lstdc++"
// CHECK-ASAN-UBSAN-LINUX: "-lpthread"
@@ -238,8 +237,8 @@
// RUN: | FileCheck --check-prefix=CHECK-ASAN-UBSAN-LINUX-CXX %s
// CHECK-ASAN-UBSAN-LINUX-CXX: "{{.*}}ld{{(.exe)?}}"
// CHECK-ASAN-UBSAN-LINUX-CXX: "-whole-archive" "{{.*}}libclang_rt.asan-i386.a" "-no-whole-archive"
-// CHECK-ASAN-UBSAN-LINUX-CXX: "-whole-archive" "{{.*}}libclang_rt.ubsan-i386.a" "-no-whole-archive"
-// CHECK-ASAN-UBSAN-LINUX-CXX: "-whole-archive" "{{.*}}libclang_rt.ubsan_cxx-i386.a" "-no-whole-archive"
+// CHECK-ASAN-UBSAN-LINUX-CXX: "-whole-archive" "{{.*}}libclang_rt.asan_cxx-i386.a" "-no-whole-archive"
+// CHECK-ASAN-UBSAN-LINUX-CXX-NOT: libclang_rt.ubsan
// CHECK-ASAN-UBSAN-LINUX-CXX: "-lstdc++"
// CHECK-ASAN-UBSAN-LINUX-CXX: "-lpthread"
@@ -273,3 +272,12 @@
// CHECK-LSAN-ASAN-LINUX-NOT: libclang_rt.lsan
// CHECK-LSAN-ASAN-LINUX: libclang_rt.asan-x86_64
// CHECK-LSAN-ASAN-LINUX-NOT: libclang_rt.lsan
+
+// RUN: %clangxx -fsanitize=address %s -### -o %t.o 2>&1 \
+// RUN: -mmacosx-version-min=10.6 \
+// RUN: -target x86_64-apple-darwin13.4.0 \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: | FileCheck --check-prefix=CHECK-ASAN-DARWIN106-CXX %s
+// CHECK-ASAN-DARWIN106-CXX: "{{.*}}ld{{(.exe)?}}"
+// CHECK-ASAN-DARWIN106-CXX: libclang_rt.asan_osx_dynamic.dylib
+// CHECK-ASAN-DARWIN106-CXX-NOT: -lc++abi
diff --git a/test/Driver/save-temps.c b/test/Driver/save-temps.c
index 438d748..277a901 100644
--- a/test/Driver/save-temps.c
+++ b/test/Driver/save-temps.c
@@ -1,6 +1,7 @@
// RUN: %clang -target x86_64-apple-darwin -save-temps -arch x86_64 %s -### 2>&1 \
// RUN: | FileCheck %s
// CHECK: "-o" "save-temps.i"
+// CHECK: "-emit-llvm-uselists"
// CHECK: "-disable-llvm-optzns"
// CHECK: "-o" "save-temps.bc"
// CHECK: "-o" "save-temps.s"
@@ -12,6 +13,7 @@
// RUN: %clang -target x86_64-apple-darwin -save-temps=cwd -arch x86_64 %s -### 2>&1 \
// RUN: | FileCheck %s -check-prefix=CWD
// CWD: "-o" "save-temps.i"
+// CWD: "-emit-llvm-uselists"
// CWD: "-disable-llvm-optzns"
// CWD: "-o" "save-temps.bc"
// CWD: "-o" "save-temps.s"
diff --git a/test/Driver/systemz-features.cpp b/test/Driver/systemz-features.cpp
new file mode 100644
index 0000000..25937d1
--- /dev/null
+++ b/test/Driver/systemz-features.cpp
@@ -0,0 +1,15 @@
+
+// RUN: %clang -target s390x-unknown-linux-gnu %s -### -o %t.o 2>&1 | FileCheck -check-prefix=CHECK-DEFAULT %s
+// CHECK-DEFAULT-NOT: "-target-feature" "+transactional-execution"
+// CHECK-DEFAULT-NOT: "-target-feature" "-transactional-execution"
+
+// RUN: %clang -target s390x-unknown-linux-gnu %s -mhtm -### -o %t.o 2>&1 | FileCheck -check-prefix=CHECK-HTM %s
+// RUN: %clang -target s390x-unknown-linux-gnu %s -mno-htm -mhtm -### -o %t.o 2>&1 | FileCheck -check-prefix=CHECK-HTM %s
+// CHECK-HTM: "-target-feature" "+transactional-execution"
+// CHECK-HTM-NOT: "-target-feature" "-transactional-execution"
+
+// RUN: %clang -target s390x-unknown-linux-gnu %s -mno-htm -### -o %t.o 2>&1 | FileCheck -check-prefix=CHECK-NOHTM %s
+// RUN: %clang -target s390x-unknown-linux-gnu %s -mhtm -mno-htm -### -o %t.o 2>&1 | FileCheck -check-prefix=CHECK-NOHTM %s
+// CHECK-NOHTM: "-target-feature" "-transactional-execution"
+// CHECK-NOHTM-NOT: "-target-feature" "+transactional-execution"
+
diff --git a/test/FixIt/fixit-eof-space.c b/test/FixIt/fixit-eof-space.c
new file mode 100644
index 0000000..dc9a45d
--- /dev/null
+++ b/test/FixIt/fixit-eof-space.c
@@ -0,0 +1,9 @@
+// RUN: not %clang_cc1 %s -fsyntax-only -fdiagnostics-parseable-fixits 2>&1 | FileCheck %s
+// vim: set binary noeol:
+
+// This file intentionally ends without a \n on the last line. Make sure your
+// editor doesn't add one. The trailing space is also intentional.
+
+// CHECK: :9:8: warning: duplicate 'extern' declaration specifier
+// CHECK: fix-it:"{{.*}}":{9:8-9:15}:""
+extern extern
\ No newline at end of file
diff --git a/test/FixIt/fixit-recursive-block.c b/test/FixIt/fixit-recursive-block.c
index b276b41..3793f82 100644
--- a/test/FixIt/fixit-recursive-block.c
+++ b/test/FixIt/fixit-recursive-block.c
@@ -5,7 +5,7 @@
int main() {
void (^arc_fail)() = ^() { // expected-warning {{block pointer variable 'arc_fail' is uninitialized when captured by block}} \
- // expected-note {{maybe you meant to use __block 'arc_fail'}}
+ // expected-note {{did you mean to use __block 'arc_fail'}}
arc_fail(); // BOOM
};
}
diff --git a/test/FixIt/fixit.cpp b/test/FixIt/fixit.cpp
index 585c216..6c2fb7f 100644
--- a/test/FixIt/fixit.cpp
+++ b/test/FixIt/fixit.cpp
@@ -344,7 +344,7 @@
int f() {
Cl0 c;
- return c->a; // expected-error {{member reference type 'PR15045::Cl0' is not a pointer; maybe you meant to use '.'?}}
+ return c->a; // expected-error {{member reference type 'PR15045::Cl0' is not a pointer; did you mean to use '.'?}}
}
}
diff --git a/test/Headers/altivec-header.c b/test/Headers/altivec-header.c
index 7b6c516..0ea9e2b 100644
--- a/test/Headers/altivec-header.c
+++ b/test/Headers/altivec-header.c
@@ -1,16 +1,12 @@
-// REQUIRES: powerpc-registered-target
-// RUN: %clang_cc1 -triple powerpc64-unknown-unknown -faltivec -ffreestanding -S -o - %s | FileCheck %s
-// RUN: %clang_cc1 -triple powerpc64-unknown-unknown -faltivec -ffreestanding -fno-lax-vector-conversions -S -o - %s | FileCheck %s
-// RUN: %clang_cc1 -triple powerpc64-unknown-unknown -faltivec -ffreestanding -x c++ -S -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple powerpc64-unknown-unknown -faltivec -ffreestanding -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple powerpc64-unknown-unknown -faltivec -ffreestanding -emit-llvm -fno-lax-vector-conversions -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple powerpc64-unknown-unknown -faltivec -ffreestanding -emit-llvm -x c++ -o - %s | FileCheck %s
#include <altivec.h>
// Verify that simply including <altivec.h> does not generate any code
// (i.e. all inline routines in the header are marked "static")
-// CHECK: .text
-// CHECK-NEXT: .file
+// CHECK: target triple = "powerpc64-
// CHECK-NEXT: {{^$}}
-// CHECK-NEXT: .ident{{.*$}}
-// CHECK-NEXT: .section ".note.GNU-stack","",@progbits
-// CHECK-NOT: .
+// CHECK-NEXT: llvm.ident
diff --git a/test/Index/print-type-size.cpp b/test/Index/print-type-size.cpp
index 58f2e14..45de93f 100644
--- a/test/Index/print-type-size.cpp
+++ b/test/Index/print-type-size.cpp
@@ -65,12 +65,12 @@
int foo;
};
struct {
-//CHECK64: FieldDecl=bar:[[@LINE+1]]:11 (Definition) [type=int] [typekind=Int] [sizeof=4] [alignof=4] [offsetof=32]
+//CHECK64: FieldDecl=bar:[[@LINE+1]]:11 (Definition) [type=int] [typekind=Int] [sizeof=4] [alignof=4] [offsetof=32/0]
int bar;
};
struct {
struct {
-//CHECK64: FieldDecl=foobar:[[@LINE+1]]:15 (Definition) [type=int] [typekind=Int] [sizeof=4] [alignof=4] [offsetof=64]
+//CHECK64: FieldDecl=foobar:[[@LINE+1]]:15 (Definition) [type=int] [typekind=Int] [sizeof=4] [alignof=4] [offsetof=64/0]
int foobar;
};
};
@@ -160,6 +160,7 @@
struct {
struct {
struct {
+//CHECK64: FieldDecl=s4_e1:[[@LINE+1]]:17 (Definition) [type=int] [typekind=Int] [sizeof=4] [alignof=4] [offsetof=-1/0]
int s4_e1;
};
};
diff --git a/test/Index/print-type.cpp b/test/Index/print-type.cpp
index af5c556..f73f1b4 100644
--- a/test/Index/print-type.cpp
+++ b/test/Index/print-type.cpp
@@ -44,6 +44,7 @@
struct Blob {
int i;
+ int j;
};
int Blob::*member_pointer;
@@ -58,7 +59,7 @@
// CHECK: NonTypeTemplateParameter=U:8:32 (Definition) [type=unsigned int] [typekind=UInt] [isPOD=1]
// CHECK: TemplateTemplateParameter=W:8:60 (Definition) [type=] [typekind=Invalid] [isPOD=0]
// CHECK: Namespace=inner:14:11 (Definition) [type=] [typekind=Invalid] [isPOD=0]
-// CHECK: StructDecl=Bar:16:8 (Definition) [type=outer::inner::Bar] [typekind=Record] [isPOD=0]
+// CHECK: StructDecl=Bar:16:8 (Definition) [type=outer::inner::Bar] [typekind=Record] [isPOD=0] [nbFields=3]
// CHECK: CXXConstructor=Bar:17:3 (Definition) [type=void (outer::Foo<bool> *){{.*}}] [typekind=FunctionProto] [canonicaltype=void (outer::Foo<bool> *){{.*}}] [canonicaltypekind=FunctionProto] [resulttype=void] [resulttypekind=Void] [args= [outer::Foo<bool> *] [Pointer]] [isPOD=0]
// CHECK: ParmDecl=foo:17:25 (Definition) [type=outer::Foo<bool> *] [typekind=Pointer] [canonicaltype=outer::Foo<bool> *] [canonicaltypekind=Pointer] [isPOD=1] [pointeetype=outer::Foo<bool>] [pointeekind=Unexposed]
// CHECK: NamespaceRef=outer:1:11 [type=] [typekind=Invalid] [isPOD=0]
@@ -115,6 +116,6 @@
// CHECK: DeclStmt= [type=] [typekind=Invalid] [isPOD=0]
// CHECK: VarDecl=variable_array:43:47 (Definition) [type=int [i]] [typekind=VariableArray] [isPOD=1]
// CHECK: DeclRefExpr=i:43:14 [type=int] [typekind=Int] [isPOD=1]
-// CHECK: StructDecl=Blob:45:8 (Definition) [type=Blob] [typekind=Record] [isPOD=1]
+// CHECK: StructDecl=Blob:45:8 (Definition) [type=Blob] [typekind=Record] [isPOD=1] [nbFields=2]
// CHECK: FieldDecl=i:46:7 (Definition) [type=int] [typekind=Int] [isPOD=1]
-// CHECK: VarDecl=member_pointer:48:12 (Definition) [type=int Blob::*] [typekind=MemberPointer] [isPOD=1]
+// CHECK: VarDecl=member_pointer:49:12 (Definition) [type=int Blob::*] [typekind=MemberPointer] [isPOD=1]
diff --git a/test/Lexer/eof-number.c b/test/Lexer/eof-number.c
new file mode 100644
index 0000000..d97a6fe
--- /dev/null
+++ b/test/Lexer/eof-number.c
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 %s -verify -fsyntax-only -Wnewline-eof
+// vim: set binary noeol:
+
+// This file intentionally ends without a \n on the last line. Make sure your
+// editor doesn't add one.
+
+// expected-error@+2{{unterminated conditional directive}}
+// expected-warning@+1{{no newline at end of file}}
+#if 0
\ No newline at end of file
diff --git a/test/Misc/warning-flags.c b/test/Misc/warning-flags.c
index 657b44d..86274ad 100644
--- a/test/Misc/warning-flags.c
+++ b/test/Misc/warning-flags.c
@@ -18,7 +18,7 @@
The list of warnings below should NEVER grow. It should gradually shrink to 0.
-CHECK: Warnings without flags (94):
+CHECK: Warnings without flags (93):
CHECK-NEXT: ext_excess_initializers
CHECK-NEXT: ext_excess_initializers_in_char_array_initializer
CHECK-NEXT: ext_expected_semi_decl_list
@@ -68,7 +68,6 @@
CHECK-NEXT: warn_dup_category_def
CHECK-NEXT: warn_duplicate_protocol_def
CHECK-NEXT: warn_enum_value_overflow
-CHECK-NEXT: warn_exception_caught_by_earlier_handler
CHECK-NEXT: warn_expected_qualified_after_typename
CHECK-NEXT: warn_extraneous_char_constant
CHECK-NEXT: warn_fe_cc_log_diagnostics_failure
diff --git a/test/Modules/Inputs/redecl-add-after-load-decls.h b/test/Modules/Inputs/redecl-add-after-load-decls.h
index fbe6b93..a422797 100644
--- a/test/Modules/Inputs/redecl-add-after-load-decls.h
+++ b/test/Modules/Inputs/redecl-add-after-load-decls.h
@@ -16,9 +16,9 @@
constexpr int C_test(bool b) { return b ? C::variable : C::function(); }
struct D {
- struct A; // expected-note {{forward}}
+ struct A;
static const int variable;
- static constexpr int function(); // expected-note {{here}}
+ static constexpr int function();
};
typedef D::A DB;
-constexpr int D_test(bool b) { return b ? D::variable : D::function(); } // expected-note {{subexpression}} expected-note {{undefined}}
+constexpr int D_test(bool b) { return b ? D::variable : D::function(); }
diff --git a/test/Modules/Inputs/submodules-merge-defs/defs.h b/test/Modules/Inputs/submodules-merge-defs/defs.h
index 16f7184..89e4b23 100644
--- a/test/Modules/Inputs/submodules-merge-defs/defs.h
+++ b/test/Modules/Inputs/submodules-merge-defs/defs.h
@@ -1,13 +1,15 @@
struct A { int a_member; };
-namespace { inline int use_a(A a) { return a.a_member; } }
+inline int use_a(A a) { return a.a_member; }
class B {
struct Inner1 {};
public:
struct Inner2;
+ template<typename T> void f();
};
// Check that lookup and access checks are performed in the right context.
struct B::Inner2 : Inner1 {};
+template<typename T> void B::f() {}
// Check that base-specifiers are correctly disambiguated.
template<int N> struct C_Base { struct D { constexpr operator int() const { return 0; } }; };
@@ -17,4 +19,13 @@
typedef struct { int a; void f(); struct X; } D;
struct D::X { int dx; } extern dx;
-namespace { inline int use_dx(D::X dx) { return dx.dx; } }
+inline int use_dx(D::X dx) { return dx.dx; }
+
+template<typename T> int E(T t) { return t; }
+
+template<typename T> struct F {
+ int f();
+ template<typename U> int g();
+};
+template<typename T> int F<T>::f() { return 0; }
+template<typename T> template<typename U> int F<T>::g() { return 0; }
diff --git a/test/Modules/Inputs/submodules-merge-defs/merged-defs.h b/test/Modules/Inputs/submodules-merge-defs/merged-defs.h
new file mode 100644
index 0000000..31c69c6
--- /dev/null
+++ b/test/Modules/Inputs/submodules-merge-defs/merged-defs.h
@@ -0,0 +1 @@
+#include "defs.h"
diff --git a/test/Modules/Inputs/submodules-merge-defs/module.modulemap b/test/Modules/Inputs/submodules-merge-defs/module.modulemap
index 5c7ee8a..82abdb0 100644
--- a/test/Modules/Inputs/submodules-merge-defs/module.modulemap
+++ b/test/Modules/Inputs/submodules-merge-defs/module.modulemap
@@ -9,3 +9,8 @@
// Do not re-export stuff.use
use "stuff"
}
+
+module "merged-defs" {
+ header "merged-defs.h"
+ use "stuff"
+}
diff --git a/test/Modules/cxx-templates.cpp b/test/Modules/cxx-templates.cpp
index 41b0f2c..00fc38b 100644
--- a/test/Modules/cxx-templates.cpp
+++ b/test/Modules/cxx-templates.cpp
@@ -125,10 +125,7 @@
static_assert(Outer<int>::Inner<int>::f() == 1, "");
static_assert(Outer<int>::Inner<int>::g() == 2, "");
-// FIXME: We're too lazy in merging class definitions to find the definition
-// of this function.
-static_assert(MergeTemplateDefinitions<int>::f() == 1, ""); // expected-error {{constant expression}} expected-note {{undefined}}
-// expected-note@cxx-templates-c.h:10 {{here}}
+static_assert(MergeTemplateDefinitions<int>::f() == 1, "");
static_assert(MergeTemplateDefinitions<int>::g() == 2, "");
RedeclaredAsFriend<int> raf1;
diff --git a/test/Modules/redecl-add-after-load.cpp b/test/Modules/redecl-add-after-load.cpp
index 53e54c8..8ca70ad 100644
--- a/test/Modules/redecl-add-after-load.cpp
+++ b/test/Modules/redecl-add-after-load.cpp
@@ -2,8 +2,9 @@
// RUN: %clang_cc1 -x objective-c++ -fmodules -fno-modules-error-recovery -fmodules-cache-path=%t -I %S/Inputs %s -verify -std=c++11
// RUN: %clang_cc1 -x objective-c++ -fmodules -fno-modules-error-recovery -fmodules-cache-path=%t -I %S/Inputs %s -verify -std=c++11 -DIMPORT_DECLS
-#ifdef IMPORT_DECLS
// expected-no-diagnostics
+
+#ifdef IMPORT_DECLS
@import redecl_add_after_load_decls;
#else
typedef struct A B;
@@ -24,12 +25,12 @@
constexpr int C_test(bool b) { return b ? C::variable : C::function(); }
struct D {
- struct A; // expected-note {{forward}}
+ struct A;
static const int variable;
- static constexpr int function(); // expected-note {{here}}
+ static constexpr int function();
};
typedef D::A DB;
-constexpr int D_test(bool b) { return b ? D::variable : D::function(); } // expected-note {{undefined}}
+constexpr int D_test(bool b) { return b ? D::variable : D::function(); }
#endif
@import redecl_add_after_load;
@@ -46,14 +47,6 @@
constexpr int struct_variable_test = C_test(true);
constexpr int struct_function_test = C_test(false);
-// FIXME: We should accept this, but we're currently too lazy when merging class
-// definitions to determine that the definitions in redecl_add_after_load are
-// definitions of these entities.
DB merged_struct_struct_test;
constexpr int merged_struct_variable_test = D_test(true);
constexpr int merged_struct_function_test = D_test(false);
-#ifndef IMPORT_DECLS
-// expected-error@-4 {{incomplete}}
-// @-4: definition of D::variable must be emitted, so it gets imported eagerly
-// expected-error@-4 {{constant}} expected-note@-4 {{in call to}}
-#endif
diff --git a/test/Modules/submodules-merge-defs.cpp b/test/Modules/submodules-merge-defs.cpp
index cdda48e..79213ca 100644
--- a/test/Modules/submodules-merge-defs.cpp
+++ b/test/Modules/submodules-merge-defs.cpp
@@ -1,33 +1,54 @@
// RUN: rm -rf %t
+// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules-cache-path=%t -fmodules -I %S/Inputs/submodules-merge-defs %s -verify -fno-modules-error-recovery -DTEXTUAL
// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules-cache-path=%t -fmodules -I %S/Inputs/submodules-merge-defs %s -verify -fno-modules-error-recovery
// Trigger import of definitions, but don't make them visible.
#include "empty.h"
A pre_a; // expected-error {{must be imported}} expected-error {{must use 'struct'}}
-// expected-note@defs.h:1 {{here}}
+// expected-note@defs.h:1 +{{here}}
+// FIXME: We should warn that use_a is being used without being imported.
+int pre_use_a = use_a(pre_a); // expected-error {{'A' must be imported}}
B::Inner2 pre_bi; // expected-error +{{must be imported}}
// expected-note@defs.h:4 +{{here}}
-// expected-note@defs.h:10 +{{here}}
+// expected-note@defs.h:11 +{{here}}
C_Base<1> pre_cb1; // expected-error +{{must be imported}}
-// expected-note@defs.h:13 +{{here}}
-C1 pre_c1; // expected-error +{{must be imported}} expected-error {{must use 'struct'}}
// expected-note@defs.h:15 +{{here}}
+C1 pre_c1; // expected-error +{{must be imported}} expected-error {{must use 'struct'}}
+// expected-note@defs.h:17 +{{here}}
C2 pre_c2; // expected-error +{{must be imported}} expected-error {{must use 'struct'}}
-// expected-note@defs.h:16 +{{here}}
+// expected-note@defs.h:18 +{{here}}
D::X pre_dx; // expected-error +{{must be imported}}
-// expected-note@defs.h:18 +{{here}}
-// expected-note@defs.h:19 +{{here}}
+// expected-note@defs.h:20 +{{here}}
+// expected-note@defs.h:21 +{{here}}
+// FIXME: We should warn that use_dx is being used without being imported.
+int pre_use_dx = use_dx(pre_dx);
+
+int pre_e = E(0); // expected-error {{must be imported}}
+// expected-note@defs.h:24 +{{here}}
+
+int pre_ff = F<int>().f(); // expected-error +{{must be imported}}
+int pre_fg = F<int>().g<int>(); // expected-error +{{must be imported}}
+// expected-note@defs.h:26 +{{here}}
// Make definitions from second module visible.
+#ifdef TEXTUAL
#include "import-and-redefine.h"
+#else
+#include "merged-defs.h"
+#endif
A post_a;
+int post_use_a = use_a(post_a);
B::Inner2 post_bi;
C_Base<1> post_cb1;
C1 c1;
C2 c2;
D::X post_dx;
+int post_use_dx = use_dx(post_dx);
+int post_e = E(0);
+int post_ff = F<char>().f();
+int post_fg = F<char>().g<int>();
diff --git a/test/OpenMP/atomic_codegen.cpp b/test/OpenMP/atomic_codegen.cpp
index e78720d..9d1d516 100644
--- a/test/OpenMP/atomic_codegen.cpp
+++ b/test/OpenMP/atomic_codegen.cpp
@@ -29,6 +29,22 @@
// CHECK: invoke void @_ZN2StD1Ev(%struct.St* [[TEMP_ST_ADDR]])
#pragma omp atomic write
St().get() = b;
+ // CHECK: invoke void @_ZN2StC1Ev(%struct.St* [[TEMP_ST_ADDR:%.+]])
+ // CHECK: [[SCALAR_ADDR:%.+]] = invoke dereferenceable(4) i32* @_ZN2St3getEv(%struct.St* [[TEMP_ST_ADDR]])
+ // CHECK: [[B_VAL:%.+]] = load i32, i32* @b
+ // CHECK: [[OLD_VAL:%.+]] = load atomic i32, i32* [[SCALAR_ADDR]] monotonic,
+ // CHECK: br label %[[OMP_UPDATE:.+]]
+ // CHECK: [[OMP_UPDATE]]
+ // CHECK: [[OLD_PHI_VAL:%.+]] = phi i32 [ [[OLD_VAL]], %{{.+}} ], [ [[NEW_OLD_VAL:%.+]], %[[OMP_UPDATE]] ]
+ // CHECK: [[NEW_VAL:%.+]] = srem i32 [[OLD_PHI_VAL]], [[B_VAL]]
+ // CHECK: [[RES:%.+]] = cmpxchg i32* [[SCALAR_ADDR]], i32 [[OLD_PHI_VAL]], i32 [[NEW_VAL]] monotonic monotonic
+ // CHECK: [[NEW_OLD_VAL]] = extractvalue { i32, i1 } [[RES]], 0
+ // CHECK: [[COND:%.+]] = extractvalue { i32, i1 } [[RES]], 1
+ // CHECK: br i1 [[COND]], label %[[OMP_DONE:.+]], label %[[OMP_UPDATE]]
+ // CHECK: [[OMP_DONE]]
+ // CHECK: invoke void @_ZN2StD1Ev(%struct.St* [[TEMP_ST_ADDR]])
+#pragma omp atomic
+ St().get() %= b;
}
}
@@ -50,11 +66,19 @@
// TERM_DEBUG: unwind label %[[TERM_LPAD:.+]],
// TERM_DEBUG-NOT: __kmpc_global_thread_num
// TERM_DEBUG: store atomic i32 {{%.+}}, i32* @{{.+}} monotonic, {{.*}}!dbg [[WRITE_LOC:![0-9]+]]
- // TERM_DEBUG: [[TERM_LPAD]]
- // TERM_DEBUG: call void @__clang_call_terminate
- // TERM_DEBUG: unreachable
a = foo();
+#pragma omp atomic update
+ // TERM_DEBUG-NOT: __kmpc_global_thread_num
+ // TERM_DEBUG: invoke {{.*}}foo{{.*}}()
+ // TERM_DEBUG: unwind label %[[TERM_LPAD:.+]],
+ // TERM_DEBUG-NOT: __kmpc_global_thread_num
+ // TERM_DEBUG: atomicrmw add i32* @{{.+}}, i32 %{{.+}} monotonic, {{.*}}!dbg [[UPDATE_LOC:![0-9]+]]
+ a += foo();
}
+ // TERM_DEBUG: [[TERM_LPAD]]
+ // TERM_DEBUG: call void @__clang_call_terminate
+ // TERM_DEBUG: unreachable
}
-// TERM_DEBUG-DAG: [[READ_LOC]] = !MDLocation(line: 41,
-// TERM_DEBUG-DAG: [[WRITE_LOC]] = !MDLocation(line: 47,
+// TERM_DEBUG-DAG: [[READ_LOC]] = !MDLocation(line: [[@LINE-25]],
+// TERM_DEBUG-DAG: [[WRITE_LOC]] = !MDLocation(line: [[@LINE-20]],
+// TERM_DEBUG-DAG: [[UPDATE_LOC]] = !MDLocation(line: [[@LINE-14]],
diff --git a/test/OpenMP/atomic_messages.c b/test/OpenMP/atomic_messages.c
index 8d4ade6..294ce7e 100644
--- a/test/OpenMP/atomic_messages.c
+++ b/test/OpenMP/atomic_messages.c
@@ -193,3 +193,175 @@
return 0;
}
+int captureint() {
+ int a = 0, b = 0, c = 0;
+// Test for atomic capture
+#pragma omp atomic capture
+ // expected-error@+2 {{the statement for 'atomic capture' must be a compound statement of form '{v = x; x binop= expr;}', '{x binop= expr; v = x;}', '{v = x; x = x binop expr;}', '{v = x; x = expr binop x;}', '{x = x binop expr; v = x;}', '{x = expr binop x; v = x;}' or '{v = x; x = expr;}', '{v = x; x++;}', '{v = x; ++x;}', '{++x; v = x;}', '{x++; v = x;}', '{v = x; x--;}', '{v = x; --x;}', '{--x; v = x;}', '{x--; v = x;}' where x is an l-value expression with scalar type}}
+ // expected-note@+1 {{expected compound statement}}
+ ;
+#pragma omp atomic capture
+ // expected-error@+2 {{the statement for 'atomic capture' must be an expression statement of form 'v = ++x;', 'v = --x;', 'v = x++;', 'v = x--;', 'v = x binop= expr;', 'v = x = x binop expr' or 'v = x = expr binop x', where x and v are both l-value expressions with scalar type}}
+ // expected-note@+1 {{expected assignment expression}}
+ foo();
+#pragma omp atomic capture
+ // expected-error@+2 {{the statement for 'atomic capture' must be an expression statement of form 'v = ++x;', 'v = --x;', 'v = x++;', 'v = x--;', 'v = x binop= expr;', 'v = x = x binop expr' or 'v = x = expr binop x', where x and v are both l-value expressions with scalar type}}
+ // expected-note@+1 {{expected built-in binary or unary operator}}
+ a = b;
+#pragma omp atomic capture
+ // expected-error@+2 {{the statement for 'atomic capture' must be an expression statement of form 'v = ++x;', 'v = --x;', 'v = x++;', 'v = x--;', 'v = x binop= expr;', 'v = x = x binop expr' or 'v = x = expr binop x', where x and v are both l-value expressions with scalar type}}
+ // expected-note@+1 {{expected assignment expression}}
+ a = b || a;
+#pragma omp atomic capture
+ // expected-error@+2 {{the statement for 'atomic capture' must be an expression statement of form 'v = ++x;', 'v = --x;', 'v = x++;', 'v = x--;', 'v = x binop= expr;', 'v = x = x binop expr' or 'v = x = expr binop x', where x and v are both l-value expressions with scalar type}}
+ // expected-note@+1 {{expected one of '+', '*', '-', '/', '&', '^', '|', '<<', or '>>' built-in operations}}
+ b = a = a && b;
+#pragma omp atomic capture
+ // expected-error@+2 {{the statement for 'atomic capture' must be an expression statement of form 'v = ++x;', 'v = --x;', 'v = x++;', 'v = x--;', 'v = x binop= expr;', 'v = x = x binop expr' or 'v = x = expr binop x', where x and v are both l-value expressions with scalar type}}
+ // expected-note@+1 {{expected assignment expression}}
+ a = (float)a + b;
+#pragma omp atomic capture
+ // expected-error@+2 {{the statement for 'atomic capture' must be an expression statement of form 'v = ++x;', 'v = --x;', 'v = x++;', 'v = x--;', 'v = x binop= expr;', 'v = x = x binop expr' or 'v = x = expr binop x', where x and v are both l-value expressions with scalar type}}
+ // expected-note@+1 {{expected assignment expression}}
+ a = 2 * b;
+#pragma omp atomic capture
+ // expected-error@+2 {{the statement for 'atomic capture' must be an expression statement of form 'v = ++x;', 'v = --x;', 'v = x++;', 'v = x--;', 'v = x binop= expr;', 'v = x = x binop expr' or 'v = x = expr binop x', where x and v are both l-value expressions with scalar type}}
+ // expected-note@+1 {{expected assignment expression}}
+ a = b + *&a;
+#pragma omp atomic capture
+ // expected-error@+2 {{the statement for 'atomic capture' must be a compound statement of form '{v = x; x binop= expr;}', '{x binop= expr; v = x;}', '{v = x; x = x binop expr;}', '{v = x; x = expr binop x;}', '{x = x binop expr; v = x;}', '{x = expr binop x; v = x;}' or '{v = x; x = expr;}', '{v = x; x++;}', '{v = x; ++x;}', '{++x; v = x;}', '{x++; v = x;}', '{v = x; x--;}', '{v = x; --x;}', '{--x; v = x;}', '{x--; v = x;}' where x is an l-value expression with scalar type}}
+ // expected-note@+1 {{expected exactly two expression statements}}
+ { a = b; }
+#pragma omp atomic capture
+ // expected-error@+2 {{the statement for 'atomic capture' must be a compound statement of form '{v = x; x binop= expr;}', '{x binop= expr; v = x;}', '{v = x; x = x binop expr;}', '{v = x; x = expr binop x;}', '{x = x binop expr; v = x;}', '{x = expr binop x; v = x;}' or '{v = x; x = expr;}', '{v = x; x++;}', '{v = x; ++x;}', '{++x; v = x;}', '{x++; v = x;}', '{v = x; x--;}', '{v = x; --x;}', '{--x; v = x;}', '{x--; v = x;}' where x is an l-value expression with scalar type}}
+ // expected-note@+1 {{expected exactly two expression statements}}
+ {}
+#pragma omp atomic capture
+ // expected-error@+2 {{the statement for 'atomic capture' must be a compound statement of form '{v = x; x binop= expr;}', '{x binop= expr; v = x;}', '{v = x; x = x binop expr;}', '{v = x; x = expr binop x;}', '{x = x binop expr; v = x;}', '{x = expr binop x; v = x;}' or '{v = x; x = expr;}', '{v = x; x++;}', '{v = x; ++x;}', '{++x; v = x;}', '{x++; v = x;}', '{v = x; x--;}', '{v = x; --x;}', '{--x; v = x;}', '{x--; v = x;}' where x is an l-value expression with scalar type}}
+ // expected-note@+1 {{expected in right hand side of the first expression}}
+ {a = b;a = b;}
+#pragma omp atomic capture
+ // expected-error@+2 {{the statement for 'atomic capture' must be a compound statement of form '{v = x; x binop= expr;}', '{x binop= expr; v = x;}', '{v = x; x = x binop expr;}', '{v = x; x = expr binop x;}', '{x = x binop expr; v = x;}', '{x = expr binop x; v = x;}' or '{v = x; x = expr;}', '{v = x; x++;}', '{v = x; ++x;}', '{++x; v = x;}', '{x++; v = x;}', '{v = x; x--;}', '{v = x; --x;}', '{--x; v = x;}', '{x--; v = x;}' where x is an l-value expression with scalar type}}
+ // expected-note@+1 {{expected in right hand side of the first expression}}
+ {a = b; a = b || a;}
+#pragma omp atomic capture
+ {b = a; a = a && b;}
+#pragma omp atomic capture
+ // expected-error@+2 {{the statement for 'atomic capture' must be an expression statement of form 'v = ++x;', 'v = --x;', 'v = x++;', 'v = x--;', 'v = x binop= expr;', 'v = x = x binop expr' or 'v = x = expr binop x', where x and v are both l-value expressions with scalar type}}
+ // expected-note@+1 {{expected in right hand side of expression}}
+ b = a = (float)a + b;
+#pragma omp atomic capture
+ // expected-error@+2 {{the statement for 'atomic capture' must be an expression statement of form 'v = ++x;', 'v = --x;', 'v = x++;', 'v = x--;', 'v = x binop= expr;', 'v = x = x binop expr' or 'v = x = expr binop x', where x and v are both l-value expressions with scalar type}}
+ // expected-note@+1 {{expected in right hand side of expression}}
+ b = a = 2 * b;
+#pragma omp atomic capture
+ // expected-error@+2 {{the statement for 'atomic capture' must be an expression statement of form 'v = ++x;', 'v = --x;', 'v = x++;', 'v = x--;', 'v = x binop= expr;', 'v = x = x binop expr' or 'v = x = expr binop x', where x and v are both l-value expressions with scalar type}}
+ // expected-note@+1 {{expected in right hand side of expression}}
+ b = a = b + *&a;
+#pragma omp atomic capture
+ c = *&a = *&a + 2;
+#pragma omp atomic capture
+ c = a++;
+#pragma omp atomic capture
+ c = ++a;
+#pragma omp atomic capture
+ c = a--;
+#pragma omp atomic capture
+ c = --a;
+#pragma omp atomic capture
+ c = a += b;
+#pragma omp atomic capture
+ c = a %= b;
+#pragma omp atomic capture
+ c = a *= b;
+#pragma omp atomic capture
+ c = a -= b;
+#pragma omp atomic capture
+ c = a /= b;
+#pragma omp atomic capture
+ c = a &= b;
+#pragma omp atomic capture
+ c = a ^= b;
+#pragma omp atomic capture
+ c = a |= b;
+#pragma omp atomic capture
+ c = a <<= b;
+#pragma omp atomic capture
+ c = a >>= b;
+#pragma omp atomic capture
+ c = a = b + a;
+#pragma omp atomic capture
+ c = a = a * b;
+#pragma omp atomic capture
+ c = a = b - a;
+#pragma omp atomic capture
+ c = a = a / b;
+#pragma omp atomic capture
+ c = a = b & a;
+#pragma omp atomic capture
+ c = a = a ^ b;
+#pragma omp atomic capture
+ c = a = b | a;
+#pragma omp atomic capture
+ c = a = a << b;
+#pragma omp atomic capture
+ c = a = b >> a;
+#pragma omp atomic capture
+ { c = *&a; *&a = *&a + 2;}
+#pragma omp atomic capture
+ { *&a = *&a + 2; c = *&a;}
+#pragma omp atomic capture
+ {c = a; a++;}
+#pragma omp atomic capture
+ {++a;c = a;}
+#pragma omp atomic capture
+ {c = a;a--;}
+#pragma omp atomic capture
+ {--a;c = a;}
+#pragma omp atomic capture
+ {c = a; a += b;}
+#pragma omp atomic capture
+ {a %= b; c = a;}
+#pragma omp atomic capture
+ {c = a; a *= b;}
+#pragma omp atomic capture
+ {a -= b;c = a;}
+#pragma omp atomic capture
+ {c = a; a /= b;}
+#pragma omp atomic capture
+ {a &= b; c = a;}
+#pragma omp atomic capture
+ {c = a; a ^= b;}
+#pragma omp atomic capture
+ {a |= b; c = a;}
+#pragma omp atomic capture
+ {c = a; a <<= b;}
+#pragma omp atomic capture
+ {a >>= b; c = a;}
+#pragma omp atomic capture
+ {c = a; a = b + a;}
+#pragma omp atomic capture
+ {a = a * b; c = a;}
+#pragma omp atomic capture
+ {c = a; a = b - a;}
+#pragma omp atomic capture
+ {a = a / b; c = a;}
+#pragma omp atomic capture
+ {c = a; a = b & a;}
+#pragma omp atomic capture
+ {a = a ^ b; c = a;}
+#pragma omp atomic capture
+ {c = a; a = b | a;}
+#pragma omp atomic capture
+ {a = a << b; c = a;}
+#pragma omp atomic capture
+ {c = a; a = b >> a;}
+#pragma omp atomic capture
+ {c = a; a = foo();}
+ // expected-error@+1 {{directive '#pragma omp atomic' cannot contain more than one 'capture' clause}}
+#pragma omp atomic capture capture
+ b = a /= b;
+
+ return 0;
+}
+
diff --git a/test/OpenMP/atomic_messages.cpp b/test/OpenMP/atomic_messages.cpp
index b47fbbc..7466509 100644
--- a/test/OpenMP/atomic_messages.cpp
+++ b/test/OpenMP/atomic_messages.cpp
@@ -152,7 +152,7 @@
template <class T>
T update() {
- T a, b = 0;
+ T a = 0, b = 0, c = 0;
// Test for atomic update
#pragma omp atomic update
// expected-error@+2 {{the statement for 'atomic update' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x', where x is an l-value expression with scalar type}}
@@ -332,34 +332,347 @@
template <class T>
T capture() {
- T a, b = 0;
+ T a = 0, b = 0, c = 0;
// Test for atomic capture
#pragma omp atomic capture
- // expected-error@+1 {{the statement for 'atomic capture' must be an expression statement of form 'v = ++x;', 'v = --x;', 'v = x++;', 'v = x--;', 'v = x binop= expr;', 'v = x = x binop expr' or 'v = x = expr binop x', where x and v are both l-value expressions with scalar type}}
- ++a;
-#pragma omp atomic capture
- // expected-error@+1 {{the statement for 'atomic capture' must be a compound statement of form '{v = x; x binop= expr;}', '{x binop= expr; v = x;}', '{v = x; x = x binop expr;}', '{v = x; x = expr binop x;}', '{x = x binop expr; v = x;}', '{x = expr binop x; v = x;}' or '{v = x; x = expr;}', '{v = x; x++;}', '{v = x; ++x;}', '{++x; v = x;}', '{x++; v = x;}', '{v = x; x--;}', '{v = x; --x;}', '{--x; v = x;}', '{x--; v = x;}' where x is an l-value expression with scalar type}}
+ // expected-error@+2 {{the statement for 'atomic capture' must be a compound statement of form '{v = x; x binop= expr;}', '{x binop= expr; v = x;}', '{v = x; x = x binop expr;}', '{v = x; x = expr binop x;}', '{x = x binop expr; v = x;}', '{x = expr binop x; v = x;}' or '{v = x; x = expr;}', '{v = x; x++;}', '{v = x; ++x;}', '{++x; v = x;}', '{x++; v = x;}', '{v = x; x--;}', '{v = x; --x;}', '{--x; v = x;}', '{x--; v = x;}' where x is an l-value expression with scalar type}}
+ // expected-note@+1 {{expected compound statement}}
;
-// expected-error@+1 {{directive '#pragma omp atomic' cannot contain more than one 'capture' clause}}
+#pragma omp atomic capture
+ // expected-error@+2 {{the statement for 'atomic capture' must be an expression statement of form 'v = ++x;', 'v = --x;', 'v = x++;', 'v = x--;', 'v = x binop= expr;', 'v = x = x binop expr' or 'v = x = expr binop x', where x and v are both l-value expressions with scalar type}}
+ // expected-note@+1 {{expected assignment expression}}
+ foo();
+#pragma omp atomic capture
+ // expected-error@+2 {{the statement for 'atomic capture' must be an expression statement of form 'v = ++x;', 'v = --x;', 'v = x++;', 'v = x--;', 'v = x binop= expr;', 'v = x = x binop expr' or 'v = x = expr binop x', where x and v are both l-value expressions with scalar type}}
+ // expected-note@+1 {{expected built-in binary or unary operator}}
+ a = b;
+#pragma omp atomic capture
+ // expected-error@+2 {{the statement for 'atomic capture' must be an expression statement of form 'v = ++x;', 'v = --x;', 'v = x++;', 'v = x--;', 'v = x binop= expr;', 'v = x = x binop expr' or 'v = x = expr binop x', where x and v are both l-value expressions with scalar type}}
+ // expected-note@+1 {{expected assignment expression}}
+ a = b || a;
+#pragma omp atomic capture
+ // expected-error@+2 {{the statement for 'atomic capture' must be an expression statement of form 'v = ++x;', 'v = --x;', 'v = x++;', 'v = x--;', 'v = x binop= expr;', 'v = x = x binop expr' or 'v = x = expr binop x', where x and v are both l-value expressions with scalar type}}
+ // expected-note@+1 {{expected one of '+', '*', '-', '/', '&', '^', '|', '<<', or '>>' built-in operations}}
+ b = a = a && b;
+#pragma omp atomic capture
+ // expected-error@+2 {{the statement for 'atomic capture' must be an expression statement of form 'v = ++x;', 'v = --x;', 'v = x++;', 'v = x--;', 'v = x binop= expr;', 'v = x = x binop expr' or 'v = x = expr binop x', where x and v are both l-value expressions with scalar type}}
+ // expected-note@+1 {{expected assignment expression}}
+ a = (float)a + b;
+#pragma omp atomic capture
+ // expected-error@+2 {{the statement for 'atomic capture' must be an expression statement of form 'v = ++x;', 'v = --x;', 'v = x++;', 'v = x--;', 'v = x binop= expr;', 'v = x = x binop expr' or 'v = x = expr binop x', where x and v are both l-value expressions with scalar type}}
+ // expected-note@+1 {{expected assignment expression}}
+ a = 2 * b;
+#pragma omp atomic capture
+ // expected-error@+2 {{the statement for 'atomic capture' must be an expression statement of form 'v = ++x;', 'v = --x;', 'v = x++;', 'v = x--;', 'v = x binop= expr;', 'v = x = x binop expr' or 'v = x = expr binop x', where x and v are both l-value expressions with scalar type}}
+ // expected-note@+1 {{expected assignment expression}}
+ a = b + *&a;
+#pragma omp atomic capture
+ // expected-error@+2 {{the statement for 'atomic capture' must be a compound statement of form '{v = x; x binop= expr;}', '{x binop= expr; v = x;}', '{v = x; x = x binop expr;}', '{v = x; x = expr binop x;}', '{x = x binop expr; v = x;}', '{x = expr binop x; v = x;}' or '{v = x; x = expr;}', '{v = x; x++;}', '{v = x; ++x;}', '{++x; v = x;}', '{x++; v = x;}', '{v = x; x--;}', '{v = x; --x;}', '{--x; v = x;}', '{x--; v = x;}' where x is an l-value expression with scalar type}}
+ // expected-note@+1 {{expected exactly two expression statements}}
+ { a = b; }
+#pragma omp atomic capture
+ // expected-error@+2 {{the statement for 'atomic capture' must be a compound statement of form '{v = x; x binop= expr;}', '{x binop= expr; v = x;}', '{v = x; x = x binop expr;}', '{v = x; x = expr binop x;}', '{x = x binop expr; v = x;}', '{x = expr binop x; v = x;}' or '{v = x; x = expr;}', '{v = x; x++;}', '{v = x; ++x;}', '{++x; v = x;}', '{x++; v = x;}', '{v = x; x--;}', '{v = x; --x;}', '{--x; v = x;}', '{x--; v = x;}' where x is an l-value expression with scalar type}}
+ // expected-note@+1 {{expected exactly two expression statements}}
+ {}
+#pragma omp atomic capture
+ // expected-error@+2 {{the statement for 'atomic capture' must be a compound statement of form '{v = x; x binop= expr;}', '{x binop= expr; v = x;}', '{v = x; x = x binop expr;}', '{v = x; x = expr binop x;}', '{x = x binop expr; v = x;}', '{x = expr binop x; v = x;}' or '{v = x; x = expr;}', '{v = x; x++;}', '{v = x; ++x;}', '{++x; v = x;}', '{x++; v = x;}', '{v = x; x--;}', '{v = x; --x;}', '{--x; v = x;}', '{x--; v = x;}' where x is an l-value expression with scalar type}}
+ // expected-note@+1 {{expected in right hand side of the first expression}}
+ {a = b;a = b;}
+#pragma omp atomic capture
+ // expected-error@+2 {{the statement for 'atomic capture' must be a compound statement of form '{v = x; x binop= expr;}', '{x binop= expr; v = x;}', '{v = x; x = x binop expr;}', '{v = x; x = expr binop x;}', '{x = x binop expr; v = x;}', '{x = expr binop x; v = x;}' or '{v = x; x = expr;}', '{v = x; x++;}', '{v = x; ++x;}', '{++x; v = x;}', '{x++; v = x;}', '{v = x; x--;}', '{v = x; --x;}', '{--x; v = x;}', '{x--; v = x;}' where x is an l-value expression with scalar type}}
+ // expected-note@+1 {{expected in right hand side of the first expression}}
+ {a = b; a = b || a;}
+#pragma omp atomic capture
+ {b = a; a = a && b;}
+#pragma omp atomic capture
+ // expected-error@+2 {{the statement for 'atomic capture' must be an expression statement of form 'v = ++x;', 'v = --x;', 'v = x++;', 'v = x--;', 'v = x binop= expr;', 'v = x = x binop expr' or 'v = x = expr binop x', where x and v are both l-value expressions with scalar type}}
+ // expected-note@+1 {{expected in right hand side of expression}}
+ b = a = (float)a + b;
+#pragma omp atomic capture
+ // expected-error@+2 {{the statement for 'atomic capture' must be an expression statement of form 'v = ++x;', 'v = --x;', 'v = x++;', 'v = x--;', 'v = x binop= expr;', 'v = x = x binop expr' or 'v = x = expr binop x', where x and v are both l-value expressions with scalar type}}
+ // expected-note@+1 {{expected in right hand side of expression}}
+ b = a = 2 * b;
+#pragma omp atomic capture
+ // expected-error@+2 {{the statement for 'atomic capture' must be an expression statement of form 'v = ++x;', 'v = --x;', 'v = x++;', 'v = x--;', 'v = x binop= expr;', 'v = x = x binop expr' or 'v = x = expr binop x', where x and v are both l-value expressions with scalar type}}
+ // expected-note@+1 {{expected in right hand side of expression}}
+ b = a = b + *&a;
+#pragma omp atomic capture
+ c = *&a = *&a + 2;
+#pragma omp atomic capture
+ c = a++;
+#pragma omp atomic capture
+ c = ++a;
+#pragma omp atomic capture
+ c = a--;
+#pragma omp atomic capture
+ c = --a;
+#pragma omp atomic capture
+ c = a += b;
+#pragma omp atomic capture
+ c = a %= b;
+#pragma omp atomic capture
+ c = a *= b;
+#pragma omp atomic capture
+ c = a -= b;
+#pragma omp atomic capture
+ c = a /= b;
+#pragma omp atomic capture
+ c = a &= b;
+#pragma omp atomic capture
+ c = a ^= b;
+#pragma omp atomic capture
+ c = a |= b;
+#pragma omp atomic capture
+ c = a <<= b;
+#pragma omp atomic capture
+ c = a >>= b;
+#pragma omp atomic capture
+ c = a = b + a;
+#pragma omp atomic capture
+ c = a = a * b;
+#pragma omp atomic capture
+ c = a = b - a;
+#pragma omp atomic capture
+ c = a = a / b;
+#pragma omp atomic capture
+ c = a = b & a;
+#pragma omp atomic capture
+ c = a = a ^ b;
+#pragma omp atomic capture
+ c = a = b | a;
+#pragma omp atomic capture
+ c = a = a << b;
+#pragma omp atomic capture
+ c = a = b >> a;
+#pragma omp atomic capture
+ { c = *&a; *&a = *&a + 2;}
+#pragma omp atomic capture
+ { *&a = *&a + 2; c = *&a;}
+#pragma omp atomic capture
+ {c = a; a++;}
+#pragma omp atomic capture
+ {++a;c = a;}
+#pragma omp atomic capture
+ {c = a;a--;}
+#pragma omp atomic capture
+ {--a;c = a;}
+#pragma omp atomic capture
+ {c = a; a += b;}
+#pragma omp atomic capture
+ {a %= b; c = a;}
+#pragma omp atomic capture
+ {c = a; a *= b;}
+#pragma omp atomic capture
+ {a -= b;c = a;}
+#pragma omp atomic capture
+ {c = a; a /= b;}
+#pragma omp atomic capture
+ {a &= b; c = a;}
+#pragma omp atomic capture
+ {c = a; a ^= b;}
+#pragma omp atomic capture
+ {a |= b; c = a;}
+#pragma omp atomic capture
+ {c = a; a <<= b;}
+#pragma omp atomic capture
+ {a >>= b; c = a;}
+#pragma omp atomic capture
+ {c = a; a = b + a;}
+#pragma omp atomic capture
+ {a = a * b; c = a;}
+#pragma omp atomic capture
+ {c = a; a = b - a;}
+#pragma omp atomic capture
+ {a = a / b; c = a;}
+#pragma omp atomic capture
+ {c = a; a = b & a;}
+#pragma omp atomic capture
+ {a = a ^ b; c = a;}
+#pragma omp atomic capture
+ {c = a; a = b | a;}
+#pragma omp atomic capture
+ {a = a << b; c = a;}
+#pragma omp atomic capture
+ {c = a; a = b >> a;}
+#pragma omp atomic capture
+ {c = a; a = foo();}
+ // expected-error@+1 {{directive '#pragma omp atomic' cannot contain more than one 'capture' clause}}
#pragma omp atomic capture capture
- a = ++b;
+ b = a /= b;
return T();
}
int capture() {
- int a, b = 0;
+ int a = 0, b = 0, c = 0;
// Test for atomic capture
#pragma omp atomic capture
- // expected-error@+1 {{the statement for 'atomic capture' must be an expression statement of form 'v = ++x;', 'v = --x;', 'v = x++;', 'v = x--;', 'v = x binop= expr;', 'v = x = x binop expr' or 'v = x = expr binop x', where x and v are both l-value expressions with scalar type}}
- ++a;
-#pragma omp atomic capture
- // expected-error@+1 {{the statement for 'atomic capture' must be a compound statement of form '{v = x; x binop= expr;}', '{x binop= expr; v = x;}', '{v = x; x = x binop expr;}', '{v = x; x = expr binop x;}', '{x = x binop expr; v = x;}', '{x = expr binop x; v = x;}' or '{v = x; x = expr;}', '{v = x; x++;}', '{v = x; ++x;}', '{++x; v = x;}', '{x++; v = x;}', '{v = x; x--;}', '{v = x; --x;}', '{--x; v = x;}', '{x--; v = x;}' where x is an l-value expression with scalar type}}
+ // expected-error@+2 {{the statement for 'atomic capture' must be a compound statement of form '{v = x; x binop= expr;}', '{x binop= expr; v = x;}', '{v = x; x = x binop expr;}', '{v = x; x = expr binop x;}', '{x = x binop expr; v = x;}', '{x = expr binop x; v = x;}' or '{v = x; x = expr;}', '{v = x; x++;}', '{v = x; ++x;}', '{++x; v = x;}', '{x++; v = x;}', '{v = x; x--;}', '{v = x; --x;}', '{--x; v = x;}', '{x--; v = x;}' where x is an l-value expression with scalar type}}
+ // expected-note@+1 {{expected compound statement}}
;
-// expected-error@+1 {{directive '#pragma omp atomic' cannot contain more than one 'capture' clause}}
+#pragma omp atomic capture
+ // expected-error@+2 {{the statement for 'atomic capture' must be an expression statement of form 'v = ++x;', 'v = --x;', 'v = x++;', 'v = x--;', 'v = x binop= expr;', 'v = x = x binop expr' or 'v = x = expr binop x', where x and v are both l-value expressions with scalar type}}
+ // expected-note@+1 {{expected assignment expression}}
+ foo();
+#pragma omp atomic capture
+ // expected-error@+2 {{the statement for 'atomic capture' must be an expression statement of form 'v = ++x;', 'v = --x;', 'v = x++;', 'v = x--;', 'v = x binop= expr;', 'v = x = x binop expr' or 'v = x = expr binop x', where x and v are both l-value expressions with scalar type}}
+ // expected-note@+1 {{expected built-in binary or unary operator}}
+ a = b;
+#pragma omp atomic capture
+ // expected-error@+2 {{the statement for 'atomic capture' must be an expression statement of form 'v = ++x;', 'v = --x;', 'v = x++;', 'v = x--;', 'v = x binop= expr;', 'v = x = x binop expr' or 'v = x = expr binop x', where x and v are both l-value expressions with scalar type}}
+ // expected-note@+1 {{expected assignment expression}}
+ a = b || a;
+#pragma omp atomic capture
+ // expected-error@+2 {{the statement for 'atomic capture' must be an expression statement of form 'v = ++x;', 'v = --x;', 'v = x++;', 'v = x--;', 'v = x binop= expr;', 'v = x = x binop expr' or 'v = x = expr binop x', where x and v are both l-value expressions with scalar type}}
+ // expected-note@+1 {{expected one of '+', '*', '-', '/', '&', '^', '|', '<<', or '>>' built-in operations}}
+ b = a = a && b;
+#pragma omp atomic capture
+ // expected-error@+2 {{the statement for 'atomic capture' must be an expression statement of form 'v = ++x;', 'v = --x;', 'v = x++;', 'v = x--;', 'v = x binop= expr;', 'v = x = x binop expr' or 'v = x = expr binop x', where x and v are both l-value expressions with scalar type}}
+ // expected-note@+1 {{expected assignment expression}}
+ a = (float)a + b;
+#pragma omp atomic capture
+ // expected-error@+2 {{the statement for 'atomic capture' must be an expression statement of form 'v = ++x;', 'v = --x;', 'v = x++;', 'v = x--;', 'v = x binop= expr;', 'v = x = x binop expr' or 'v = x = expr binop x', where x and v are both l-value expressions with scalar type}}
+ // expected-note@+1 {{expected assignment expression}}
+ a = 2 * b;
+#pragma omp atomic capture
+ // expected-error@+2 {{the statement for 'atomic capture' must be an expression statement of form 'v = ++x;', 'v = --x;', 'v = x++;', 'v = x--;', 'v = x binop= expr;', 'v = x = x binop expr' or 'v = x = expr binop x', where x and v are both l-value expressions with scalar type}}
+ // expected-note@+1 {{expected assignment expression}}
+ a = b + *&a;
+#pragma omp atomic capture
+ // expected-error@+2 {{the statement for 'atomic capture' must be a compound statement of form '{v = x; x binop= expr;}', '{x binop= expr; v = x;}', '{v = x; x = x binop expr;}', '{v = x; x = expr binop x;}', '{x = x binop expr; v = x;}', '{x = expr binop x; v = x;}' or '{v = x; x = expr;}', '{v = x; x++;}', '{v = x; ++x;}', '{++x; v = x;}', '{x++; v = x;}', '{v = x; x--;}', '{v = x; --x;}', '{--x; v = x;}', '{x--; v = x;}' where x is an l-value expression with scalar type}}
+ // expected-note@+1 {{expected exactly two expression statements}}
+ { a = b; }
+#pragma omp atomic capture
+ // expected-error@+2 {{the statement for 'atomic capture' must be a compound statement of form '{v = x; x binop= expr;}', '{x binop= expr; v = x;}', '{v = x; x = x binop expr;}', '{v = x; x = expr binop x;}', '{x = x binop expr; v = x;}', '{x = expr binop x; v = x;}' or '{v = x; x = expr;}', '{v = x; x++;}', '{v = x; ++x;}', '{++x; v = x;}', '{x++; v = x;}', '{v = x; x--;}', '{v = x; --x;}', '{--x; v = x;}', '{x--; v = x;}' where x is an l-value expression with scalar type}}
+ // expected-note@+1 {{expected exactly two expression statements}}
+ {}
+#pragma omp atomic capture
+ // expected-error@+2 {{the statement for 'atomic capture' must be a compound statement of form '{v = x; x binop= expr;}', '{x binop= expr; v = x;}', '{v = x; x = x binop expr;}', '{v = x; x = expr binop x;}', '{x = x binop expr; v = x;}', '{x = expr binop x; v = x;}' or '{v = x; x = expr;}', '{v = x; x++;}', '{v = x; ++x;}', '{++x; v = x;}', '{x++; v = x;}', '{v = x; x--;}', '{v = x; --x;}', '{--x; v = x;}', '{x--; v = x;}' where x is an l-value expression with scalar type}}
+ // expected-note@+1 {{expected in right hand side of the first expression}}
+ {a = b;a = b;}
+#pragma omp atomic capture
+ // expected-error@+2 {{the statement for 'atomic capture' must be a compound statement of form '{v = x; x binop= expr;}', '{x binop= expr; v = x;}', '{v = x; x = x binop expr;}', '{v = x; x = expr binop x;}', '{x = x binop expr; v = x;}', '{x = expr binop x; v = x;}' or '{v = x; x = expr;}', '{v = x; x++;}', '{v = x; ++x;}', '{++x; v = x;}', '{x++; v = x;}', '{v = x; x--;}', '{v = x; --x;}', '{--x; v = x;}', '{x--; v = x;}' where x is an l-value expression with scalar type}}
+ // expected-note@+1 {{expected in right hand side of the first expression}}
+ {a = b; a = b || a;}
+#pragma omp atomic capture
+ {b = a; a = a && b;}
+#pragma omp atomic capture
+ // expected-error@+2 {{the statement for 'atomic capture' must be an expression statement of form 'v = ++x;', 'v = --x;', 'v = x++;', 'v = x--;', 'v = x binop= expr;', 'v = x = x binop expr' or 'v = x = expr binop x', where x and v are both l-value expressions with scalar type}}
+ // expected-note@+1 {{expected in right hand side of expression}}
+ b = a = (float)a + b;
+#pragma omp atomic capture
+ // expected-error@+2 {{the statement for 'atomic capture' must be an expression statement of form 'v = ++x;', 'v = --x;', 'v = x++;', 'v = x--;', 'v = x binop= expr;', 'v = x = x binop expr' or 'v = x = expr binop x', where x and v are both l-value expressions with scalar type}}
+ // expected-note@+1 {{expected in right hand side of expression}}
+ b = a = 2 * b;
+#pragma omp atomic capture
+ // expected-error@+2 {{the statement for 'atomic capture' must be an expression statement of form 'v = ++x;', 'v = --x;', 'v = x++;', 'v = x--;', 'v = x binop= expr;', 'v = x = x binop expr' or 'v = x = expr binop x', where x and v are both l-value expressions with scalar type}}
+ // expected-note@+1 {{expected in right hand side of expression}}
+ b = a = b + *&a;
+#pragma omp atomic capture
+ c = *&a = *&a + 2;
+#pragma omp atomic capture
+ c = a++;
+#pragma omp atomic capture
+ c = ++a;
+#pragma omp atomic capture
+ c = a--;
+#pragma omp atomic capture
+ c = --a;
+#pragma omp atomic capture
+ c = a += b;
+#pragma omp atomic capture
+ c = a %= b;
+#pragma omp atomic capture
+ c = a *= b;
+#pragma omp atomic capture
+ c = a -= b;
+#pragma omp atomic capture
+ c = a /= b;
+#pragma omp atomic capture
+ c = a &= b;
+#pragma omp atomic capture
+ c = a ^= b;
+#pragma omp atomic capture
+ c = a |= b;
+#pragma omp atomic capture
+ c = a <<= b;
+#pragma omp atomic capture
+ c = a >>= b;
+#pragma omp atomic capture
+ c = a = b + a;
+#pragma omp atomic capture
+ c = a = a * b;
+#pragma omp atomic capture
+ c = a = b - a;
+#pragma omp atomic capture
+ c = a = a / b;
+#pragma omp atomic capture
+ c = a = b & a;
+#pragma omp atomic capture
+ c = a = a ^ b;
+#pragma omp atomic capture
+ c = a = b | a;
+#pragma omp atomic capture
+ c = a = a << b;
+#pragma omp atomic capture
+ c = a = b >> a;
+#pragma omp atomic capture
+ { c = *&a; *&a = *&a + 2;}
+#pragma omp atomic capture
+ { *&a = *&a + 2; c = *&a;}
+#pragma omp atomic capture
+ {c = a; a++;}
+#pragma omp atomic capture
+ {++a;c = a;}
+#pragma omp atomic capture
+ {c = a;a--;}
+#pragma omp atomic capture
+ {--a;c = a;}
+#pragma omp atomic capture
+ {c = a; a += b;}
+#pragma omp atomic capture
+ {a %= b; c = a;}
+#pragma omp atomic capture
+ {c = a; a *= b;}
+#pragma omp atomic capture
+ {a -= b;c = a;}
+#pragma omp atomic capture
+ {c = a; a /= b;}
+#pragma omp atomic capture
+ {a &= b; c = a;}
+#pragma omp atomic capture
+ {c = a; a ^= b;}
+#pragma omp atomic capture
+ {a |= b; c = a;}
+#pragma omp atomic capture
+ {c = a; a <<= b;}
+#pragma omp atomic capture
+ {a >>= b; c = a;}
+#pragma omp atomic capture
+ {c = a; a = b + a;}
+#pragma omp atomic capture
+ {a = a * b; c = a;}
+#pragma omp atomic capture
+ {c = a; a = b - a;}
+#pragma omp atomic capture
+ {a = a / b; c = a;}
+#pragma omp atomic capture
+ {c = a; a = b & a;}
+#pragma omp atomic capture
+ {a = a ^ b; c = a;}
+#pragma omp atomic capture
+ {c = a; a = b | a;}
+#pragma omp atomic capture
+ {a = a << b; c = a;}
+#pragma omp atomic capture
+ {c = a; a = b >> a;}
+#pragma omp atomic capture
+ {c = a; a = foo();}
+ // expected-error@+1 {{directive '#pragma omp atomic' cannot contain more than one 'capture' clause}}
#pragma omp atomic capture capture
- a = ++b;
+ b = a /= b;
+ // expected-note@+1 {{in instantiation of function template specialization 'capture<int>' requested here}}
return capture<int>();
}
diff --git a/test/OpenMP/atomic_update_codegen.cpp b/test/OpenMP/atomic_update_codegen.cpp
new file mode 100644
index 0000000..ada2e41
--- /dev/null
+++ b/test/OpenMP/atomic_update_codegen.cpp
@@ -0,0 +1,1070 @@
+// RUN: %clang_cc1 -verify -triple x86_64-apple-darwin10 -fopenmp=libiomp5 -x c -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -fopenmp=libiomp5 -x c -triple x86_64-apple-darwin10 -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp=libiomp5 -x c -triple x86_64-apple-darwin10 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s
+// expected-no-diagnostics
+
+#ifndef HEADER
+#define HEADER
+
+_Bool bv, bx;
+char cv, cx;
+unsigned char ucv, ucx;
+short sv, sx;
+unsigned short usv, usx;
+int iv, ix;
+unsigned int uiv, uix;
+long lv, lx;
+unsigned long ulv, ulx;
+long long llv, llx;
+unsigned long long ullv, ullx;
+float fv, fx;
+double dv, dx;
+long double ldv, ldx;
+_Complex int civ, cix;
+_Complex float cfv, cfx;
+_Complex double cdv, cdx;
+
+typedef int int4 __attribute__((__vector_size__(16)));
+int4 int4x;
+
+struct BitFields {
+ int : 32;
+ int a : 31;
+} bfx;
+
+struct BitFields_packed {
+ int : 32;
+ int a : 31;
+} __attribute__ ((__packed__)) bfx_packed;
+
+struct BitFields2 {
+ int : 31;
+ int a : 1;
+} bfx2;
+
+struct BitFields2_packed {
+ int : 31;
+ int a : 1;
+} __attribute__ ((__packed__)) bfx2_packed;
+
+struct BitFields3 {
+ int : 11;
+ int a : 14;
+} bfx3;
+
+struct BitFields3_packed {
+ int : 11;
+ int a : 14;
+} __attribute__ ((__packed__)) bfx3_packed;
+
+struct BitFields4 {
+ short : 16;
+ int a: 1;
+ long b : 7;
+} bfx4;
+
+struct BitFields4_packed {
+ short : 16;
+ int a: 1;
+ long b : 7;
+} __attribute__ ((__packed__)) bfx4_packed;
+
+typedef float float2 __attribute__((ext_vector_type(2)));
+float2 float2x;
+
+register int rix __asm__("0");
+
+int main() {
+// CHECK: atomicrmw add i8* @{{.+}}, i8 1 monotonic
+#pragma omp atomic
+ bx++;
+// CHECK: atomicrmw add i8* @{{.+}}, i8 1 monotonic
+#pragma omp atomic update
+ ++cx;
+// CHECK: atomicrmw sub i8* @{{.+}}, i8 1 monotonic
+#pragma omp atomic
+ ucx--;
+// CHECK: atomicrmw sub i16* @{{.+}}, i16 1 monotonic
+#pragma omp atomic update
+ --sx;
+// CHECK: [[USV:%.+]] = load i16, i16* @{{.+}},
+// CHECK: [[EXPR:%.+]] = zext i16 [[USV]] to i32
+// CHECK: [[X:%.+]] = load atomic i16, i16* [[X_ADDR:@.+]] monotonic
+// CHECK: br label %[[CONT:.+]]
+// CHECK: [[CONT]]
+// CHECK: [[EXPECTED:%.+]] = phi i16 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ]
+// CHECK: [[CONV:%.+]] = zext i16 [[EXPECTED]] to i32
+// CHECK: [[ADD:%.+]] = add nsw i32 [[CONV]], [[EXPR]]
+// CHECK: [[DESIRED:%.+]] = trunc i32 [[ADD]] to i16
+// CHECK: [[RES:%.+]] = cmpxchg i16* [[X_ADDR]], i16 [[EXPECTED]], i16 [[DESIRED]] monotonic monotonic
+// CHECK: [[OLD_X]] = extractvalue { i16, i1 } [[RES]], 0
+// CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i16, i1 } [[RES]], 1
+// CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]]
+// CHECK: [[EXIT]]
+#pragma omp atomic
+ usx += usv;
+// CHECK: [[EXPR:%.+]] = load i32, i32* @{{.+}},
+// CHECK: [[X:%.+]] = load atomic i32, i32* [[X_ADDR:@.+]] monotonic
+// CHECK: br label %[[CONT:.+]]
+// CHECK: [[CONT]]
+// CHECK: [[EXPECTED:%.+]] = phi i32 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ]
+// CHECK: [[DESIRED:%.+]] = mul nsw i32 [[EXPECTED]], [[EXPR]]
+// CHECK: [[RES:%.+]] = cmpxchg i32* [[X_ADDR]], i32 [[EXPECTED]], i32 [[DESIRED]] monotonic monotonic
+// CHECK: [[OLD_X]] = extractvalue { i32, i1 } [[RES]], 0
+// CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i32, i1 } [[RES]], 1
+// CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]]
+// CHECK: [[EXIT]]
+#pragma omp atomic update
+ ix *= iv;
+// CHECK: [[EXPR:%.+]] = load i32, i32* @{{.+}},
+// CHECK: atomicrmw sub i32* @{{.+}}, i32 [[EXPR]] monotonic
+#pragma omp atomic
+ uix -= uiv;
+// CHECK: [[EXPR:%.+]] = load i32, i32* @{{.+}},
+// CHECK: [[X:%.+]] = load atomic i32, i32* [[X_ADDR:@.+]] monotonic
+// CHECK: br label %[[CONT:.+]]
+// CHECK: [[CONT]]
+// CHECK: [[EXPECTED:%.+]] = phi i32 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ]
+// CHECK: [[DESIRED:%.+]] = shl i32 [[EXPECTED]], [[EXPR]]
+// CHECK: [[RES:%.+]] = cmpxchg i32* [[X_ADDR]], i32 [[EXPECTED]], i32 [[DESIRED]] monotonic monotonic
+// CHECK: [[OLD_X]] = extractvalue { i32, i1 } [[RES]], 0
+// CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i32, i1 } [[RES]], 1
+// CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]]
+// CHECK: [[EXIT]]
+#pragma omp atomic update
+ ix <<= iv;
+// CHECK: [[EXPR:%.+]] = load i32, i32* @{{.+}},
+// CHECK: [[X:%.+]] = load atomic i32, i32* [[X_ADDR:@.+]] monotonic
+// CHECK: br label %[[CONT:.+]]
+// CHECK: [[CONT]]
+// CHECK: [[EXPECTED:%.+]] = phi i32 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ]
+// CHECK: [[DESIRED:%.+]] = lshr i32 [[EXPECTED]], [[EXPR]]
+// CHECK: [[RES:%.+]] = cmpxchg i32* [[X_ADDR]], i32 [[EXPECTED]], i32 [[DESIRED]] monotonic monotonic
+// CHECK: [[OLD_X]] = extractvalue { i32, i1 } [[RES]], 0
+// CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i32, i1 } [[RES]], 1
+// CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]]
+// CHECK: [[EXIT]]
+#pragma omp atomic
+ uix >>= uiv;
+// CHECK: [[EXPR:%.+]] = load i64, i64* @{{.+}},
+// CHECK: [[X:%.+]] = load atomic i64, i64* [[X_ADDR:@.+]] monotonic
+// CHECK: br label %[[CONT:.+]]
+// CHECK: [[CONT]]
+// CHECK: [[EXPECTED:%.+]] = phi i64 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ]
+// CHECK: [[DESIRED:%.+]] = sdiv i64 [[EXPECTED]], [[EXPR]]
+// CHECK: [[RES:%.+]] = cmpxchg i64* [[X_ADDR]], i64 [[EXPECTED]], i64 [[DESIRED]] monotonic monotonic
+// CHECK: [[OLD_X]] = extractvalue { i64, i1 } [[RES]], 0
+// CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i64, i1 } [[RES]], 1
+// CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]]
+// CHECK: [[EXIT]]
+#pragma omp atomic update
+ lx /= lv;
+// CHECK: [[EXPR:%.+]] = load i64, i64* @{{.+}},
+// CHECK: atomicrmw and i64* @{{.+}}, i64 [[EXPR]] monotonic
+#pragma omp atomic
+ ulx &= ulv;
+// CHECK: [[EXPR:%.+]] = load i64, i64* @{{.+}},
+// CHECK: atomicrmw xor i64* @{{.+}}, i64 [[EXPR]] monotonic
+#pragma omp atomic update
+ llx ^= llv;
+// CHECK: [[EXPR:%.+]] = load i64, i64* @{{.+}},
+// CHECK: atomicrmw or i64* @{{.+}}, i64 [[EXPR]] monotonic
+#pragma omp atomic
+ ullx |= ullv;
+// CHECK: [[EXPR:%.+]] = load float, float* @{{.+}},
+// CHECK: [[OLD:%.+]] = load atomic i32, i32* bitcast (float* [[X_ADDR:@.+]] to i32*) monotonic
+// CHECK: [[X:%.+]] = bitcast i32 [[OLD]] to float
+// CHECK: br label %[[CONT:.+]]
+// CHECK: [[CONT]]
+// CHECK: [[OLD:%.+]] = phi float [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ]
+// CHECK: [[ADD:%.+]] = fadd float [[OLD]], [[EXPR]]
+// CHECK: [[EXPECTED:%.+]] = bitcast float [[OLD]] to i32
+// CHECK: [[DESIRED:%.+]] = bitcast float [[ADD]] to i32
+// CHECK: [[RES:%.+]] = cmpxchg i32* bitcast (float* [[X_ADDR]] to i32*), i32 [[EXPECTED]], i32 [[DESIRED]] monotonic monotonic
+// CHECK: [[PREV:%.+]] = extractvalue { i32, i1 } [[RES]], 0
+// CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i32, i1 } [[RES]], 1
+// CHECK: [[OLD_X]] = bitcast i32 [[PREV]] to float
+// CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]]
+// CHECK: [[EXIT]]
+#pragma omp atomic update
+ fx = fx + fv;
+// CHECK: [[EXPR:%.+]] = load double, double* @{{.+}},
+// CHECK: [[OLD:%.+]] = load atomic i64, i64* bitcast (double* [[X_ADDR:@.+]] to i64*) monotonic
+// CHECK: [[X:%.+]] = bitcast i64 [[OLD]] to double
+// CHECK: br label %[[CONT:.+]]
+// CHECK: [[CONT]]
+// CHECK: [[OLD:%.+]] = phi double [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ]
+// CHECK: [[SUB:%.+]] = fsub double [[EXPR]], [[OLD]]
+// CHECK: [[EXPECTED:%.+]] = bitcast double [[OLD]] to i64
+// CHECK: [[DESIRED:%.+]] = bitcast double [[SUB]] to i64
+// CHECK: [[RES:%.+]] = cmpxchg i64* bitcast (double* [[X_ADDR]] to i64*), i64 [[EXPECTED]], i64 [[DESIRED]] monotonic monotonic
+// CHECK: [[PREV:%.+]] = extractvalue { i64, i1 } [[RES]], 0
+// CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i64, i1 } [[RES]], 1
+// CHECK: [[OLD_X]] = bitcast i64 [[PREV]] to double
+// CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]]
+// CHECK: [[EXIT]]
+#pragma omp atomic
+ dx = dv - dx;
+// CHECK: [[EXPR:%.+]] = load x86_fp80, x86_fp80* @{{.+}},
+// CHECK: [[OLD:%.+]] = load atomic i128, i128* bitcast (x86_fp80* [[X_ADDR:@.+]] to i128*) monotonic
+// CHECK: [[BITCAST:%.+]] = bitcast x86_fp80* [[TEMP:%.+]] to i128*
+// CHECK: store i128 [[OLD]], i128* [[BITCAST]]
+// CHECK: [[X:%.+]] = load x86_fp80, x86_fp80* [[TEMP]]
+// CHECK: br label %[[CONT:.+]]
+// CHECK: [[CONT]]
+// CHECK: [[OLD:%.+]] = phi x86_fp80 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ]
+// CHECK: [[MUL:%.+]] = fmul x86_fp80 [[OLD]], [[EXPR]]
+// CHECK: [[BITCAST:%.+]] = bitcast x86_fp80* [[TEMP:%.+]] to i8*
+// CHECK: call void @llvm.memset.p0i8.i64(i8* [[BITCAST]], i8 0, i64 16, i32 16, i1 false)
+// CHECK: store x86_fp80 [[OLD]], x86_fp80* [[TEMP]]
+// CHECK: [[BITCAST:%.+]] = bitcast x86_fp80* [[TEMP]] to i128*
+// CHECK: [[EXPECTED:%.+]] = load i128, i128* [[BITCAST]]
+// CHECK: [[BITCAST:%.+]] = bitcast x86_fp80* [[TEMP:%.+]] to i8*
+// CHECK: call void @llvm.memset.p0i8.i64(i8* [[BITCAST]], i8 0, i64 16, i32 16, i1 false)
+// CHECK: store x86_fp80 [[MUL]], x86_fp80* [[TEMP]]
+// CHECK: [[BITCAST:%.+]] = bitcast x86_fp80* [[TEMP]] to i128*
+// CHECK: [[DESIRED:%.+]] = load i128, i128* [[BITCAST]]
+// CHECK: [[RES:%.+]] = cmpxchg i128* bitcast (x86_fp80* [[X_ADDR]] to i128*), i128 [[EXPECTED]], i128 [[DESIRED]] monotonic monotonic
+// CHECK: [[PREV:%.+]] = extractvalue { i128, i1 } [[RES]], 0
+// CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i128, i1 } [[RES]], 1
+// CHECK: [[BITCAST:%.+]] = bitcast x86_fp80* [[TEMP:%.+]] to i128*
+// CHECK: store i128 [[PREV]], i128* [[BITCAST]]
+// CHECK: [[OLD_X]] = load x86_fp80, x86_fp80* [[TEMP]],
+// CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]]
+// CHECK: [[EXIT]]
+#pragma omp atomic update
+ ldx = ldx * ldv;
+// CHECK: [[EXPR_RE:%.+]] = load i32, i32* getelementptr inbounds ({ i32, i32 }, { i32, i32 }* @{{.+}}, i32 0, i32 0)
+// CHECK: [[EXPR_IM:%.+]] = load i32, i32* getelementptr inbounds ({ i32, i32 }, { i32, i32 }* @{{.+}}, i32 0, i32 1)
+// CHECK: [[BITCAST:%.+]] = bitcast { i32, i32 }* [[TEMP:%.+]] to i8*
+// CHECK: call void @__atomic_load(i64 8, i8* bitcast ({ i32, i32 }* [[X_ADDR:@.+]] to i8*), i8* [[BITCAST]], i32 0)
+// CHECK: [[LD_RE_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[TEMP]], i32 0, i32 0
+// CHECK: [[LD_RE:%.+]] = load i32, i32* [[LD_RE_ADDR]]
+// CHECK: [[LD_IM_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[TEMP]], i32 0, i32 1
+// CHECK: [[LD_IM:%.+]] = load i32, i32* [[LD_IM_ADDR]]
+// CHECK: [[LD_RE_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[TEMP:%.+]], i32 0, i32 0
+// CHECK: [[LD_IM_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[TEMP]], i32 0, i32 1
+// CHECK: store i32 [[LD_RE]], i32* [[LD_RE_ADDR]]
+// CHECK: store i32 [[LD_IM]], i32* [[LD_IM_ADDR]]
+// CHECK: [[BITCAST:%.+]] = bitcast { i32, i32 }* [[TEMP]] to i64*
+// CHECK: [[X:%.+]] = load i64, i64* [[BITCAST]]
+// CHECK: br label %[[CONT:.+]]
+// CHECK: [[CONT]]
+// CHECK: [[OLD:%.+]] = phi i64 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ]
+// CHECK: [[BITCAST:%.+]] = bitcast { i32, i32 }* [[TEMP:%.+]] to i64*
+// CHECK: store i64 [[OLD]], i64* [[BITCAST]]
+// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[TEMP]], i32 0, i32 0
+// CHECK: [[X_RE:%.+]] = load i32, i32* [[X_RE_ADDR]]
+// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[TEMP]], i32 0, i32 1
+// CHECK: [[X_IM:%.+]] = load i32, i32* [[X_IM_ADDR]]
+// <Skip checks for complex calculations>
+// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[EXPECTED_ADDR:%.+]], i32 0, i32 0
+// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[EXPECTED_ADDR]], i32 0, i32 1
+// CHECK: store i32 [[X_RE]], i32* [[X_RE_ADDR]]
+// CHECK: store i32 [[X_IM]], i32* [[X_IM_ADDR]]
+// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[DESIRED_ADDR:%.+]], i32 0, i32 0
+// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[DESIRED_ADDR]], i32 0, i32 1
+// CHECK: store i32 %{{.+}}, i32* [[X_RE_ADDR]]
+// CHECK: store i32 %{{.+}}, i32* [[X_IM_ADDR]]
+// CHECK: [[EXPECTED:%.+]] = bitcast { i32, i32 }* [[EXPECTED_ADDR]] to i8*
+// CHECK: [[DESIRED:%.+]] = bitcast { i32, i32 }* [[DESIRED_ADDR]] to i8*
+// CHECK: [[SUCCESS_FAIL:%.+]] = call zeroext i1 @__atomic_compare_exchange(i64 8, i8* bitcast ({ i32, i32 }* [[X_ADDR]] to i8*), i8* [[EXPECTED]], i8* [[DESIRED]], i32 0, i32 0)
+// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[TEMP:%.+]], i32 0, i32 0
+// CHECK: [[X_RE:%.+]] = load i32, i32* [[X_RE_ADDR]]
+// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[TEMP]], i32 0, i32 1
+// CHECK: [[X_IM:%.+]] = load i32, i32* [[X_IM_ADDR]]
+// CHECK: [[LD_RE_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[TEMP:%.+]], i32 0, i32 0
+// CHECK: [[LD_IM_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[TEMP]], i32 0, i32 1
+// CHECK: store i32 [[X_RE]], i32* [[LD_RE_ADDR]]
+// CHECK: store i32 [[X_IM]], i32* [[LD_IM_ADDR]]
+// CHECK: [[BITCAST:%.+]] = bitcast { i32, i32 }* [[TEMP]] to i64*
+// CHECK: [[OLD_X]] = load i64, i64* [[BITCAST]]
+// CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]]
+// CHECK: [[EXIT]]
+#pragma omp atomic
+ cix = civ / cix;
+// CHECK: [[EXPR_RE:%.+]] = load float, float* getelementptr inbounds ({ float, float }, { float, float }* @{{.+}}, i32 0, i32 0)
+// CHECK: [[EXPR_IM:%.+]] = load float, float* getelementptr inbounds ({ float, float }, { float, float }* @{{.+}}, i32 0, i32 1)
+// CHECK: [[BITCAST:%.+]] = bitcast { float, float }* [[TEMP:%.+]] to i8*
+// CHECK: call void @__atomic_load(i64 8, i8* bitcast ({ float, float }* [[X_ADDR:@.+]] to i8*), i8* [[BITCAST]], i32 0)
+// CHECK: [[LD_RE_ADDR:%.+]] = getelementptr inbounds { float, float }, { float, float }* [[TEMP]], i32 0, i32 0
+// CHECK: [[LD_RE:%.+]] = load float, float* [[LD_RE_ADDR]]
+// CHECK: [[LD_IM_ADDR:%.+]] = getelementptr inbounds { float, float }, { float, float }* [[TEMP]], i32 0, i32 1
+// CHECK: [[LD_IM:%.+]] = load float, float* [[LD_IM_ADDR]]
+// CHECK: [[LD_RE_ADDR:%.+]] = getelementptr inbounds { float, float }, { float, float }* [[TEMP:%.+]], i32 0, i32 0
+// CHECK: [[LD_IM_ADDR:%.+]] = getelementptr inbounds { float, float }, { float, float }* [[TEMP]], i32 0, i32 1
+// CHECK: store float [[LD_RE]], float* [[LD_RE_ADDR]]
+// CHECK: store float [[LD_IM]], float* [[LD_IM_ADDR]]
+// CHECK: [[BITCAST:%.+]] = bitcast { float, float }* [[TEMP]] to i64*
+// CHECK: [[X:%.+]] = load i64, i64* [[BITCAST]]
+// CHECK: br label %[[CONT:.+]]
+// CHECK: [[CONT]]
+// CHECK: [[OLD:%.+]] = phi i64 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ]
+// CHECK: [[BITCAST:%.+]] = bitcast { float, float }* [[TEMP:%.+]] to i64*
+// CHECK: store i64 [[OLD]], i64* [[BITCAST]]
+// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { float, float }, { float, float }* [[TEMP]], i32 0, i32 0
+// CHECK: [[X_RE:%.+]] = load float, float* [[X_RE_ADDR]]
+// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { float, float }, { float, float }* [[TEMP]], i32 0, i32 1
+// CHECK: [[X_IM:%.+]] = load float, float* [[X_IM_ADDR]]
+// <Skip checks for complex calculations>
+// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { float, float }, { float, float }* [[EXPECTED_ADDR:%.+]], i32 0, i32 0
+// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { float, float }, { float, float }* [[EXPECTED_ADDR]], i32 0, i32 1
+// CHECK: store float [[X_RE]], float* [[X_RE_ADDR]]
+// CHECK: store float [[X_IM]], float* [[X_IM_ADDR]]
+// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { float, float }, { float, float }* [[DESIRED_ADDR:%.+]], i32 0, i32 0
+// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { float, float }, { float, float }* [[DESIRED_ADDR]], i32 0, i32 1
+// CHECK: store float %{{.+}}, float* [[X_RE_ADDR]]
+// CHECK: store float %{{.+}}, float* [[X_IM_ADDR]]
+// CHECK: [[EXPECTED:%.+]] = bitcast { float, float }* [[EXPECTED_ADDR]] to i8*
+// CHECK: [[DESIRED:%.+]] = bitcast { float, float }* [[DESIRED_ADDR]] to i8*
+// CHECK: [[SUCCESS_FAIL:%.+]] = call zeroext i1 @__atomic_compare_exchange(i64 8, i8* bitcast ({ float, float }* [[X_ADDR]] to i8*), i8* [[EXPECTED]], i8* [[DESIRED]], i32 0, i32 0)
+// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { float, float }, { float, float }* [[TEMP:%.+]], i32 0, i32 0
+// CHECK: [[X_RE:%.+]] = load float, float* [[X_RE_ADDR]]
+// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { float, float }, { float, float }* [[TEMP]], i32 0, i32 1
+// CHECK: [[X_IM:%.+]] = load float, float* [[X_IM_ADDR]]
+// CHECK: [[LD_RE_ADDR:%.+]] = getelementptr inbounds { float, float }, { float, float }* [[TEMP:%.+]], i32 0, i32 0
+// CHECK: [[LD_IM_ADDR:%.+]] = getelementptr inbounds { float, float }, { float, float }* [[TEMP]], i32 0, i32 1
+// CHECK: store float [[X_RE]], float* [[LD_RE_ADDR]]
+// CHECK: store float [[X_IM]], float* [[LD_IM_ADDR]]
+// CHECK: [[BITCAST:%.+]] = bitcast { float, float }* [[TEMP]] to i64*
+// CHECK: [[OLD_X]] = load i64, i64* [[BITCAST]]
+// CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]]
+// CHECK: [[EXIT]]
+#pragma omp atomic update
+ cfx = cfv + cfx;
+// CHECK: [[EXPR_RE:%.+]] = load double, double* getelementptr inbounds ({ double, double }, { double, double }* @{{.+}}, i32 0, i32 0)
+// CHECK: [[EXPR_IM:%.+]] = load double, double* getelementptr inbounds ({ double, double }, { double, double }* @{{.+}}, i32 0, i32 1)
+// CHECK: [[BITCAST:%.+]] = bitcast { double, double }* [[TEMP:%.+]] to i8*
+// CHECK: call void @__atomic_load(i64 16, i8* bitcast ({ double, double }* [[X_ADDR:@.+]] to i8*), i8* [[BITCAST]], i32 5)
+// CHECK: [[LD_RE_ADDR:%.+]] = getelementptr inbounds { double, double }, { double, double }* [[TEMP]], i32 0, i32 0
+// CHECK: [[LD_RE:%.+]] = load double, double* [[LD_RE_ADDR]]
+// CHECK: [[LD_IM_ADDR:%.+]] = getelementptr inbounds { double, double }, { double, double }* [[TEMP]], i32 0, i32 1
+// CHECK: [[LD_IM:%.+]] = load double, double* [[LD_IM_ADDR]]
+// CHECK: [[LD_RE_ADDR:%.+]] = getelementptr inbounds { double, double }, { double, double }* [[TEMP:%.+]], i32 0, i32 0
+// CHECK: [[LD_IM_ADDR:%.+]] = getelementptr inbounds { double, double }, { double, double }* [[TEMP]], i32 0, i32 1
+// CHECK: store double [[LD_RE]], double* [[LD_RE_ADDR]]
+// CHECK: store double [[LD_IM]], double* [[LD_IM_ADDR]]
+// CHECK: [[BITCAST:%.+]] = bitcast { double, double }* [[TEMP]] to i128*
+// CHECK: [[X:%.+]] = load i128, i128* [[BITCAST]]
+// CHECK: br label %[[CONT:.+]]
+// CHECK: [[CONT]]
+// CHECK: [[OLD:%.+]] = phi i128 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ]
+// CHECK: [[BITCAST:%.+]] = bitcast { double, double }* [[TEMP:%.+]] to i128*
+// CHECK: store i128 [[OLD]], i128* [[BITCAST]]
+// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { double, double }, { double, double }* [[TEMP]], i32 0, i32 0
+// CHECK: [[X_RE:%.+]] = load double, double* [[X_RE_ADDR]]
+// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { double, double }, { double, double }* [[TEMP]], i32 0, i32 1
+// CHECK: [[X_IM:%.+]] = load double, double* [[X_IM_ADDR]]
+// <Skip checks for complex calculations>
+// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { double, double }, { double, double }* [[EXPECTED_ADDR:%.+]], i32 0, i32 0
+// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { double, double }, { double, double }* [[EXPECTED_ADDR]], i32 0, i32 1
+// CHECK: store double [[X_RE]], double* [[X_RE_ADDR]]
+// CHECK: store double [[X_IM]], double* [[X_IM_ADDR]]
+// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { double, double }, { double, double }* [[DESIRED_ADDR:%.+]], i32 0, i32 0
+// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { double, double }, { double, double }* [[DESIRED_ADDR]], i32 0, i32 1
+// CHECK: store double %{{.+}}, double* [[X_RE_ADDR]]
+// CHECK: store double %{{.+}}, double* [[X_IM_ADDR]]
+// CHECK: [[EXPECTED:%.+]] = bitcast { double, double }* [[EXPECTED_ADDR]] to i8*
+// CHECK: [[DESIRED:%.+]] = bitcast { double, double }* [[DESIRED_ADDR]] to i8*
+// CHECK: [[SUCCESS_FAIL:%.+]] = call zeroext i1 @__atomic_compare_exchange(i64 16, i8* bitcast ({ double, double }* [[X_ADDR]] to i8*), i8* [[EXPECTED]], i8* [[DESIRED]], i32 5, i32 5)
+// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { double, double }, { double, double }* [[TEMP:%.+]], i32 0, i32 0
+// CHECK: [[X_RE:%.+]] = load double, double* [[X_RE_ADDR]]
+// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { double, double }, { double, double }* [[TEMP]], i32 0, i32 1
+// CHECK: [[X_IM:%.+]] = load double, double* [[X_IM_ADDR]]
+// CHECK: [[LD_RE_ADDR:%.+]] = getelementptr inbounds { double, double }, { double, double }* [[TEMP:%.+]], i32 0, i32 0
+// CHECK: [[LD_IM_ADDR:%.+]] = getelementptr inbounds { double, double }, { double, double }* [[TEMP]], i32 0, i32 1
+// CHECK: store double [[X_RE]], double* [[LD_RE_ADDR]]
+// CHECK: store double [[X_IM]], double* [[LD_IM_ADDR]]
+// CHECK: [[BITCAST:%.+]] = bitcast { double, double }* [[TEMP]] to i128*
+// CHECK: [[OLD_X]] = load i128, i128* [[BITCAST]]
+// CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]]
+// CHECK: [[EXIT]]
+// CHECK: call{{.*}} @__kmpc_flush(
+#pragma omp atomic seq_cst
+ cdx = cdx - cdv;
+// CHECK: [[BV:%.+]] = load i8, i8* @{{.+}}
+// CHECK: [[BOOL:%.+]] = trunc i8 [[BV]] to i1
+// CHECK: [[EXPR:%.+]] = zext i1 [[BOOL]] to i64
+// CHECK: atomicrmw and i64* @{{.+}}, i64 [[EXPR]] monotonic
+#pragma omp atomic update
+ ulx = ulx & bv;
+// CHECK: [[CV:%.+]] = load i8, i8* @{{.+}}, align 1
+// CHECK: [[EXPR:%.+]] = sext i8 [[CV]] to i32
+// CHECK: [[BX:%.+]] = load atomic i8, i8* [[BX_ADDR:@.+]] monotonic
+// CHECK: [[X:%.+]] = trunc i8 [[BX]] to i1
+// CHECK: br label %[[CONT:.+]]
+// CHECK: [[CONT]]
+// CHECK: [[OLD:%.+]] = phi i1 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ]
+// CHECK: [[X_RVAL:%.+]] = zext i1 [[OLD]] to i32
+// CHECK: [[AND:%.+]] = and i32 [[EXPR]], [[X_RVAL]]
+// CHECK: [[CAST:%.+]] = icmp ne i32 [[AND]], 0
+// CHECK: [[EXPECTED:%.+]] = zext i1 [[OLD]] to i8
+// CHECK: [[DESIRED:%.+]] = zext i1 [[CAST]] to i8
+// CHECK: [[RES:%.+]] = cmpxchg i8* [[BX_ADDR]], i8 [[EXPECTED]], i8 [[DESIRED]] monotonic monotonic
+// CHECK: [[OLD:%.+]] = extractvalue { i8, i1 } [[RES]], 0
+// CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i8, i1 } [[RES]], 1
+// CHECK: [[OLD_X]] = trunc i8 [[OLD]] to i1
+// CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]]
+// CHECK: [[EXIT]]
+#pragma omp atomic
+ bx = cv & bx;
+// CHECK: [[UCV:%.+]] = load i8, i8* @{{.+}},
+// CHECK: [[EXPR:%.+]] = zext i8 [[UCV]] to i32
+// CHECK: [[X:%.+]] = load atomic i8, i8* [[CX_ADDR:@.+]] seq_cst
+// CHECK: br label %[[CONT:.+]]
+// CHECK: [[CONT]]
+// CHECK: [[EXPECTED:%.+]] = phi i8 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ]
+// CHECK: [[X_RVAL:%.+]] = sext i8 [[EXPECTED]] to i32
+// CHECK: [[ASHR:%.+]] = ashr i32 [[X_RVAL]], [[EXPR]]
+// CHECK: [[DESIRED:%.+]] = trunc i32 [[ASHR]] to i8
+// CHECK: [[RES:%.+]] = cmpxchg i8* [[CX_ADDR]], i8 [[EXPECTED]], i8 [[DESIRED]] seq_cst seq_cst
+// CHECK: [[OLD_X:%.+]] = extractvalue { i8, i1 } [[RES]], 0
+// CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i8, i1 } [[RES]], 1
+// CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]]
+// CHECK: [[EXIT]]
+// CHECK: call{{.*}} @__kmpc_flush(
+#pragma omp atomic update, seq_cst
+ cx = cx >> ucv;
+// CHECK: [[SV:%.+]] = load i16, i16* @{{.+}},
+// CHECK: [[EXPR:%.+]] = sext i16 [[SV]] to i32
+// CHECK: [[X:%.+]] = load atomic i64, i64* [[ULX_ADDR:@.+]] monotonic
+// CHECK: br label %[[CONT:.+]]
+// CHECK: [[CONT]]
+// CHECK: [[EXPECTED:%.+]] = phi i64 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ]
+// CHECK: [[X_RVAL:%.+]] = trunc i64 [[EXPECTED]] to i32
+// CHECK: [[SHL:%.+]] = shl i32 [[EXPR]], [[X_RVAL]]
+// CHECK: [[DESIRED:%.+]] = sext i32 [[SHL]] to i64
+// CHECK: [[RES:%.+]] = cmpxchg i64* [[ULX_ADDR]], i64 [[EXPECTED]], i64 [[DESIRED]] monotonic monotonic
+// CHECK: [[OLD_X:%.+]] = extractvalue { i64, i1 } [[RES]], 0
+// CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i64, i1 } [[RES]], 1
+// CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]]
+// CHECK: [[EXIT]]
+#pragma omp atomic update
+ ulx = sv << ulx;
+// CHECK: [[USV:%.+]] = load i16, i16* @{{.+}},
+// CHECK: [[EXPR:%.+]] = zext i16 [[USV]] to i64
+// CHECK: [[X:%.+]] = load atomic i64, i64* [[LX_ADDR:@.+]] monotonic
+// CHECK: br label %[[CONT:.+]]
+// CHECK: [[CONT]]
+// CHECK: [[EXPECTED:%.+]] = phi i64 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ]
+// CHECK: [[DESIRED:%.+]] = srem i64 [[EXPECTED]], [[EXPR]]
+// CHECK: [[RES:%.+]] = cmpxchg i64* [[LX_ADDR]], i64 [[EXPECTED]], i64 [[DESIRED]] monotonic monotonic
+// CHECK: [[OLD_X:%.+]] = extractvalue { i64, i1 } [[RES]], 0
+// CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i64, i1 } [[RES]], 1
+// CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]]
+// CHECK: [[EXIT]]
+#pragma omp atomic
+ lx = lx % usv;
+// CHECK: [[EXPR:%.+]] = load i32, i32* @{{.+}}
+// CHECK: atomicrmw or i32* @{{.+}}, i32 [[EXPR]] seq_cst
+// CHECK: call{{.*}} @__kmpc_flush(
+#pragma omp atomic seq_cst, update
+ uix = iv | uix;
+// CHECK: [[EXPR:%.+]] = load i32, i32* @{{.+}}
+// CHECK: atomicrmw and i32* @{{.+}}, i32 [[EXPR]] monotonic
+#pragma omp atomic
+ ix = ix & uiv;
+// CHECK: [[EXPR:%.+]] = load i64, i64* @{{.+}},
+// CHECK: [[BITCAST:%.+]] = bitcast { i32, i32 }* [[TEMP:%.+]] to i8*
+// CHECK: call void @__atomic_load(i64 8, i8* bitcast ({ i32, i32 }* [[X_ADDR:@.+]] to i8*), i8* [[BITCAST]], i32 0)
+// CHECK: [[LD_RE_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[TEMP]], i32 0, i32 0
+// CHECK: [[LD_RE:%.+]] = load i32, i32* [[LD_RE_ADDR]]
+// CHECK: [[LD_IM_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[TEMP]], i32 0, i32 1
+// CHECK: [[LD_IM:%.+]] = load i32, i32* [[LD_IM_ADDR]]
+// CHECK: [[LD_RE_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[TEMP:%.+]], i32 0, i32 0
+// CHECK: [[LD_IM_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[TEMP]], i32 0, i32 1
+// CHECK: store i32 [[LD_RE]], i32* [[LD_RE_ADDR]]
+// CHECK: store i32 [[LD_IM]], i32* [[LD_IM_ADDR]]
+// CHECK: [[BITCAST:%.+]] = bitcast { i32, i32 }* [[TEMP]] to i64*
+// CHECK: [[X:%.+]] = load i64, i64* [[BITCAST]]
+// CHECK: br label %[[CONT:.+]]
+// CHECK: [[CONT]]
+// CHECK: [[OLD:%.+]] = phi i64 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ]
+// CHECK: [[BITCAST:%.+]] = bitcast { i32, i32 }* [[TEMP:%.+]] to i64*
+// CHECK: store i64 [[OLD]], i64* [[BITCAST]]
+// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[TEMP]], i32 0, i32 0
+// CHECK: [[X_RE:%.+]] = load i32, i32* [[X_RE_ADDR]]
+// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[TEMP]], i32 0, i32 1
+// CHECK: [[X_IM:%.+]] = load i32, i32* [[X_IM_ADDR]]
+// <Skip checks for complex calculations>
+// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[EXPECTED_ADDR:%.+]], i32 0, i32 0
+// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[EXPECTED_ADDR]], i32 0, i32 1
+// CHECK: store i32 [[X_RE]], i32* [[X_RE_ADDR]]
+// CHECK: store i32 [[X_IM]], i32* [[X_IM_ADDR]]
+// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[DESIRED_ADDR:%.+]], i32 0, i32 0
+// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[DESIRED_ADDR]], i32 0, i32 1
+// CHECK: store i32 %{{.+}}, i32* [[X_RE_ADDR]]
+// CHECK: store i32 %{{.+}}, i32* [[X_IM_ADDR]]
+// CHECK: [[EXPECTED:%.+]] = bitcast { i32, i32 }* [[EXPECTED_ADDR]] to i8*
+// CHECK: [[DESIRED:%.+]] = bitcast { i32, i32 }* [[DESIRED_ADDR]] to i8*
+// CHECK: [[SUCCESS_FAIL:%.+]] = call zeroext i1 @__atomic_compare_exchange(i64 8, i8* bitcast ({ i32, i32 }* [[X_ADDR]] to i8*), i8* [[EXPECTED]], i8* [[DESIRED]], i32 0, i32 0)
+// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[TEMP:%.+]], i32 0, i32 0
+// CHECK: [[X_RE:%.+]] = load i32, i32* [[X_RE_ADDR]]
+// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[TEMP]], i32 0, i32 1
+// CHECK: [[X_IM:%.+]] = load i32, i32* [[X_IM_ADDR]]
+// CHECK: [[LD_RE_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[TEMP:%.+]], i32 0, i32 0
+// CHECK: [[LD_IM_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[TEMP]], i32 0, i32 1
+// CHECK: store i32 [[X_RE]], i32* [[LD_RE_ADDR]]
+// CHECK: store i32 [[X_IM]], i32* [[LD_IM_ADDR]]
+// CHECK: [[BITCAST:%.+]] = bitcast { i32, i32 }* [[TEMP]] to i64*
+// CHECK: [[OLD_X]] = load i64, i64* [[BITCAST]]
+// CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]]
+// CHECK: [[EXIT]]
+#pragma omp atomic update
+ cix = lv + cix;
+// CHECK: [[ULV:%.+]] = load i64, i64* @{{.+}},
+// CHECK: [[EXPR:%.+]] = uitofp i64 [[ULV]] to float
+// CHECK: [[OLD:%.+]] = load atomic i32, i32* bitcast (float* [[X_ADDR:@.+]] to i32*) monotonic
+// CHECK: [[X:%.+]] = bitcast i32 [[OLD]] to float
+// CHECK: br label %[[CONT:.+]]
+// CHECK: [[CONT]]
+// CHECK: [[OLD:%.+]] = phi float [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ]
+// CHECK: [[MUL:%.+]] = fmul float [[OLD]], [[EXPR]]
+// CHECK: [[EXPECTED:%.+]] = bitcast float [[OLD]] to i32
+// CHECK: [[DESIRED:%.+]] = bitcast float [[MUL]] to i32
+// CHECK: [[RES:%.+]] = cmpxchg i32* bitcast (float* [[X_ADDR]] to i32*), i32 [[EXPECTED]], i32 [[DESIRED]] monotonic monotonic
+// CHECK: [[PREV:%.+]] = extractvalue { i32, i1 } [[RES]], 0
+// CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i32, i1 } [[RES]], 1
+// CHECK: [[OLD_X]] = bitcast i32 [[PREV]] to float
+// CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]]
+// CHECK: [[EXIT]]
+#pragma omp atomic
+ fx = fx * ulv;
+// CHECK: [[LLV:%.+]] = load i64, i64* @{{.+}},
+// CHECK: [[EXPR:%.+]] = sitofp i64 [[LLV]] to double
+// CHECK: [[OLD:%.+]] = load atomic i64, i64* bitcast (double* [[X_ADDR:@.+]] to i64*) monotonic
+// CHECK: [[X:%.+]] = bitcast i64 [[OLD]] to double
+// CHECK: br label %[[CONT:.+]]
+// CHECK: [[CONT]]
+// CHECK: [[OLD:%.+]] = phi double [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ]
+// CHECK: [[DIV:%.+]] = fdiv double [[OLD]], [[EXPR]]
+// CHECK: [[EXPECTED:%.+]] = bitcast double [[OLD]] to i64
+// CHECK: [[DESIRED:%.+]] = bitcast double [[DIV]] to i64
+// CHECK: [[RES:%.+]] = cmpxchg i64* bitcast (double* [[X_ADDR]] to i64*), i64 [[EXPECTED]], i64 [[DESIRED]] monotonic monotonic
+// CHECK: [[PREV:%.+]] = extractvalue { i64, i1 } [[RES]], 0
+// CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i64, i1 } [[RES]], 1
+// CHECK: [[OLD_X]] = bitcast i64 [[PREV]] to double
+// CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]]
+// CHECK: [[EXIT]]
+#pragma omp atomic update
+ dx /= llv;
+// CHECK: [[ULLV:%.+]] = load i64, i64* @{{.+}},
+// CHECK: [[EXPR:%.+]] = uitofp i64 [[ULLV]] to x86_fp80
+// CHECK: [[OLD:%.+]] = load atomic i128, i128* bitcast (x86_fp80* [[X_ADDR:@.+]] to i128*) monotonic
+// CHECK: [[BITCAST:%.+]] = bitcast x86_fp80* [[TEMP:%.+]] to i128*
+// CHECK: store i128 [[OLD]], i128* [[BITCAST]]
+// CHECK: [[X:%.+]] = load x86_fp80, x86_fp80* [[TEMP]]
+// CHECK: br label %[[CONT:.+]]
+// CHECK: [[CONT]]
+// CHECK: [[OLD:%.+]] = phi x86_fp80 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ]
+// CHECK: [[SUB:%.+]] = fsub x86_fp80 [[OLD]], [[EXPR]]
+// CHECK: [[BITCAST:%.+]] = bitcast x86_fp80* [[TEMP:%.+]] to i8*
+// CHECK: call void @llvm.memset.p0i8.i64(i8* [[BITCAST]], i8 0, i64 16, i32 16, i1 false)
+// CHECK: store x86_fp80 [[OLD]], x86_fp80* [[TEMP]]
+// CHECK: [[BITCAST:%.+]] = bitcast x86_fp80* [[TEMP]] to i128*
+// CHECK: [[EXPECTED:%.+]] = load i128, i128* [[BITCAST]]
+// CHECK: [[BITCAST:%.+]] = bitcast x86_fp80* [[TEMP:%.+]] to i8*
+// CHECK: call void @llvm.memset.p0i8.i64(i8* [[BITCAST]], i8 0, i64 16, i32 16, i1 false)
+// CHECK: store x86_fp80 [[SUB]], x86_fp80* [[TEMP]]
+// CHECK: [[BITCAST:%.+]] = bitcast x86_fp80* [[TEMP]] to i128*
+// CHECK: [[DESIRED:%.+]] = load i128, i128* [[BITCAST]]
+// CHECK: [[RES:%.+]] = cmpxchg i128* bitcast (x86_fp80* [[X_ADDR]] to i128*), i128 [[EXPECTED]], i128 [[DESIRED]] monotonic monotonic
+// CHECK: [[PREV:%.+]] = extractvalue { i128, i1 } [[RES]], 0
+// CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i128, i1 } [[RES]], 1
+// CHECK: [[BITCAST:%.+]] = bitcast x86_fp80* [[TEMP:%.+]] to i128*
+// CHECK: store i128 [[PREV]], i128* [[BITCAST]]
+// CHECK: [[OLD_X]] = load x86_fp80, x86_fp80* [[TEMP]],
+// CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]]
+// CHECK: [[EXIT]]
+#pragma omp atomic
+ ldx -= ullv;
+// CHECK: [[EXPR:%.+]] = load float, float* @{{.+}},
+// CHECK: [[BITCAST:%.+]] = bitcast { i32, i32 }* [[TEMP:%.+]] to i8*
+// CHECK: call void @__atomic_load(i64 8, i8* bitcast ({ i32, i32 }* [[X_ADDR:@.+]] to i8*), i8* [[BITCAST]], i32 0)
+// CHECK: [[LD_RE_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[TEMP]], i32 0, i32 0
+// CHECK: [[LD_RE:%.+]] = load i32, i32* [[LD_RE_ADDR]]
+// CHECK: [[LD_IM_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[TEMP]], i32 0, i32 1
+// CHECK: [[LD_IM:%.+]] = load i32, i32* [[LD_IM_ADDR]]
+// CHECK: [[LD_RE_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[TEMP:%.+]], i32 0, i32 0
+// CHECK: [[LD_IM_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[TEMP]], i32 0, i32 1
+// CHECK: store i32 [[LD_RE]], i32* [[LD_RE_ADDR]]
+// CHECK: store i32 [[LD_IM]], i32* [[LD_IM_ADDR]]
+// CHECK: [[BITCAST:%.+]] = bitcast { i32, i32 }* [[TEMP]] to i64*
+// CHECK: [[X:%.+]] = load i64, i64* [[BITCAST]]
+// CHECK: br label %[[CONT:.+]]
+// CHECK: [[CONT]]
+// CHECK: [[OLD:%.+]] = phi i64 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ]
+// CHECK: [[BITCAST:%.+]] = bitcast { i32, i32 }* [[TEMP:%.+]] to i64*
+// CHECK: store i64 [[OLD]], i64* [[BITCAST]]
+// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[TEMP]], i32 0, i32 0
+// CHECK: [[X_RE:%.+]] = load i32, i32* [[X_RE_ADDR]]
+// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[TEMP]], i32 0, i32 1
+// CHECK: [[X_IM:%.+]] = load i32, i32* [[X_IM_ADDR]]
+// <Skip checks for complex calculations>
+// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[EXPECTED_ADDR:%.+]], i32 0, i32 0
+// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[EXPECTED_ADDR]], i32 0, i32 1
+// CHECK: store i32 [[X_RE]], i32* [[X_RE_ADDR]]
+// CHECK: store i32 [[X_IM]], i32* [[X_IM_ADDR]]
+// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[DESIRED_ADDR:%.+]], i32 0, i32 0
+// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[DESIRED_ADDR]], i32 0, i32 1
+// CHECK: store i32 %{{.+}}, i32* [[X_RE_ADDR]]
+// CHECK: store i32 %{{.+}}, i32* [[X_IM_ADDR]]
+// CHECK: [[EXPECTED:%.+]] = bitcast { i32, i32 }* [[EXPECTED_ADDR]] to i8*
+// CHECK: [[DESIRED:%.+]] = bitcast { i32, i32 }* [[DESIRED_ADDR]] to i8*
+// CHECK: [[SUCCESS_FAIL:%.+]] = call zeroext i1 @__atomic_compare_exchange(i64 8, i8* bitcast ({ i32, i32 }* [[X_ADDR]] to i8*), i8* [[EXPECTED]], i8* [[DESIRED]], i32 0, i32 0)
+// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[TEMP:%.+]], i32 0, i32 0
+// CHECK: [[X_RE:%.+]] = load i32, i32* [[X_RE_ADDR]]
+// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[TEMP]], i32 0, i32 1
+// CHECK: [[X_IM:%.+]] = load i32, i32* [[X_IM_ADDR]]
+// CHECK: [[LD_RE_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[TEMP:%.+]], i32 0, i32 0
+// CHECK: [[LD_IM_ADDR:%.+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* [[TEMP]], i32 0, i32 1
+// CHECK: store i32 [[X_RE]], i32* [[LD_RE_ADDR]]
+// CHECK: store i32 [[X_IM]], i32* [[LD_IM_ADDR]]
+// CHECK: [[BITCAST:%.+]] = bitcast { i32, i32 }* [[TEMP]] to i64*
+// CHECK: [[OLD_X]] = load i64, i64* [[BITCAST]]
+// CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]]
+// CHECK: [[EXIT]]
+#pragma omp atomic update
+ cix = fv / cix;
+// CHECK: [[EXPR:%.+]] = load double, double* @{{.+}},
+// CHECK: [[X:%.+]] = load atomic i16, i16* [[X_ADDR:@.+]] monotonic
+// CHECK: br label %[[CONT:.+]]
+// CHECK: [[CONT]]
+// CHECK: [[EXPECTED:%.+]] = phi i16 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ]
+// CHECK: [[CONV:%.+]] = sext i16 [[EXPECTED]] to i32
+// CHECK: [[X_RVAL:%.+]] = sitofp i32 [[CONV]] to double
+// CHECK: [[ADD:%.+]] = fadd double [[X_RVAL]], [[EXPR]]
+// CHECK: [[DESIRED:%.+]] = fptosi double [[ADD]] to i16
+// CHECK: [[RES:%.+]] = cmpxchg i16* [[X_ADDR]], i16 [[EXPECTED]], i16 [[DESIRED]] monotonic monotonic
+// CHECK: [[OLD_X]] = extractvalue { i16, i1 } [[RES]], 0
+// CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i16, i1 } [[RES]], 1
+// CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]]
+// CHECK: [[EXIT]]
+#pragma omp atomic
+ sx = sx + dv;
+// CHECK: [[EXPR:%.+]] = load x86_fp80, x86_fp80* @{{.+}},
+// CHECK: [[XI8:%.+]] = load atomic i8, i8* [[X_ADDR:@.+]] monotonic
+// CHECK: [[X:%.+]] = trunc i8 [[XI8]] to i1
+// CHECK: br label %[[CONT:.+]]
+// CHECK: [[CONT]]
+// CHECK: [[BOOL_EXPECTED:%.+]] = phi i1 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ]
+// CHECK: [[CONV:%.+]] = zext i1 [[BOOL_EXPECTED]] to i32
+// CHECK: [[X_RVAL:%.+]] = sitofp i32 [[CONV]] to x86_fp80
+// CHECK: [[MUL:%.+]] = fmul x86_fp80 [[EXPR]], [[X_RVAL]]
+// CHECK: [[BOOL_DESIRED:%.+]] = fcmp une x86_fp80 [[MUL]], 0xK00000000000000000000
+// CHECK: [[EXPECTED:%.+]] = zext i1 [[BOOL_EXPECTED]] to i8
+// CHECK: [[DESIRED:%.+]] = zext i1 [[BOOL_DESIRED]] to i8
+// CHECK: [[RES:%.+]] = cmpxchg i8* [[X_ADDR]], i8 [[EXPECTED]], i8 [[DESIRED]] monotonic monotonic
+// CHECK: [[OLD_XI8:%.+]] = extractvalue { i8, i1 } [[RES]], 0
+// CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i8, i1 } [[RES]], 1
+// CHECK: [[OLD_X]] = trunc i8 [[OLD_XI8]] to i1
+// CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]]
+// CHECK: [[EXIT]]
+#pragma omp atomic update
+ bx = ldv * bx;
+// CHECK: [[EXPR_RE:%.+]] = load i32, i32* getelementptr inbounds ({ i32, i32 }, { i32, i32 }* [[CIV_ADDR:@.+]], i32 0, i32 0),
+// CHECK: [[EXPR_IM:%.+]] = load i32, i32* getelementptr inbounds ({ i32, i32 }, { i32, i32 }* [[CIV_ADDR]], i32 0, i32 1),
+// CHECK: [[XI8:%.+]] = load atomic i8, i8* [[X_ADDR:@.+]] monotonic
+// CHECK: [[X:%.+]] = trunc i8 [[XI8]] to i1
+// CHECK: br label %[[CONT:.+]]
+// CHECK: [[CONT]]
+// CHECK: [[BOOL_EXPECTED:%.+]] = phi i1 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ]
+// CHECK: [[X_RVAL:%.+]] = zext i1 [[BOOL_EXPECTED]] to i32
+// CHECK: [[SUB_RE:%.+]] = sub i32 [[EXPR_RE:%.+]], [[X_RVAL]]
+// CHECK: [[SUB_IM:%.+]] = sub i32 [[EXPR_IM:%.+]], 0
+// CHECK: icmp ne i32 [[SUB_RE]], 0
+// CHECK: icmp ne i32 [[SUB_IM]], 0
+// CHECK: [[BOOL_DESIRED:%.+]] = or i1
+// CHECK: [[EXPECTED:%.+]] = zext i1 [[BOOL_EXPECTED]] to i8
+// CHECK: [[DESIRED:%.+]] = zext i1 [[BOOL_DESIRED]] to i8
+// CHECK: [[RES:%.+]] = cmpxchg i8* [[X_ADDR]], i8 [[EXPECTED]], i8 [[DESIRED]] monotonic monotonic
+// CHECK: [[OLD_XI8:%.+]] = extractvalue { i8, i1 } [[RES]], 0
+// CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i8, i1 } [[RES]], 1
+// CHECK: [[OLD_X]] = trunc i8 [[OLD_XI8]] to i1
+// CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]]
+// CHECK: [[EXIT]]
+#pragma omp atomic
+ bx = civ - bx;
+// CHECK: [[EXPR_RE:%.+]] = load float, float* getelementptr inbounds ({ float, float }, { float, float }* @{{.+}}, i32 0, i32 0)
+// CHECK: [[EXPR_IM:%.+]] = load float, float* getelementptr inbounds ({ float, float }, { float, float }* @{{.+}}, i32 0, i32 1)
+// CHECK: [[X:%.+]] = load atomic i16, i16* [[X_ADDR:@.+]] monotonic
+// CHECK: br label %[[CONT:.+]]
+// CHECK: [[CONT]]
+// CHECK: [[EXPECTED:%.+]] = phi i16 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ]
+// CHECK: [[CONV:%.+]] = zext i16 [[EXPECTED]] to i32
+// CHECK: [[X_RVAL:%.+]] = sitofp i32 [[CONV]] to float
+// <Skip checks for complex calculations>
+// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { float, float }, { float, float }* [[TEMP:%.+]], i32 0, i32 0
+// CHECK: [[X_RE:%.+]] = load float, float* [[X_RE_ADDR]]
+// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { float, float }, { float, float }* [[TEMP]], i32 0, i32 1
+// CHECK: [[X_IM:%.+]] = load float, float* [[X_IM_ADDR]]
+// CHECK: [[DESIRED:%.+]] = fptoui float [[X_RE]] to i16
+// CHECK: [[RES:%.+]] = cmpxchg i16* [[X_ADDR]], i16 [[EXPECTED]], i16 [[DESIRED]] monotonic monotonic
+// CHECK: [[OLD_X]] = extractvalue { i16, i1 } [[RES]], 0
+// CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i16, i1 } [[RES]], 1
+// CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]]
+// CHECK: [[EXIT]]
+#pragma omp atomic update
+ usx /= cfv;
+// CHECK: [[EXPR_RE:%.+]] = load double, double* getelementptr inbounds ({ double, double }, { double, double }* @{{.+}}, i32 0, i32 0)
+// CHECK: [[EXPR_IM:%.+]] = load double, double* getelementptr inbounds ({ double, double }, { double, double }* @{{.+}}, i32 0, i32 1)
+// CHECK: [[X:%.+]] = load atomic i64, i64* [[X_ADDR:@.+]] monotonic
+// CHECK: br label %[[CONT:.+]]
+// CHECK: [[CONT]]
+// CHECK: [[EXPECTED:%.+]] = phi i64 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ]
+// CHECK: [[X_RVAL:%.+]] = sitofp i64 [[EXPECTED]] to double
+// CHECK: [[ADD_RE:%.+]] = fadd double [[X_RVAL]], [[EXPR_RE]]
+// CHECK: [[ADD_IM:%.+]] = fadd double 0.000000e+00, [[EXPR_IM]]
+// CHECK: [[DESIRED:%.+]] = fptosi double [[ADD_RE]] to i64
+// CHECK: [[RES:%.+]] = cmpxchg i64* [[X_ADDR]], i64 [[EXPECTED]], i64 [[DESIRED]] monotonic monotonic
+// CHECK: [[OLD_X]] = extractvalue { i64, i1 } [[RES]], 0
+// CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i64, i1 } [[RES]], 1
+// CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]]
+// CHECK: [[EXIT]]
+#pragma omp atomic
+ llx += cdv;
+// CHECK: [[IDX:%.+]] = load i16, i16* @{{.+}}
+// CHECK: load i8, i8*
+// CHECK: [[VEC_ITEM_VAL:%.+]] = zext i1 %{{.+}} to i32
+// CHECK: [[I128VAL:%.+]] = load atomic i128, i128* bitcast (<4 x i32>* [[DEST:@.+]] to i128*) monotonic
+// CHECK: [[LD:%.+]] = bitcast i128 [[I128VAL]] to <4 x i32>
+// CHECK: br label %[[CONT:.+]]
+// CHECK: [[CONT]]
+// CHECK: [[OLD_VEC_VAL:%.+]] = phi <4 x i32> [ [[LD]], %{{.+}} ], [ [[FAILED_OLD_VAL:%.+]], %[[CONT]] ]
+// CHECK: store <4 x i32> [[OLD_VEC_VAL]], <4 x i32>* [[LDTEMP:%.+]],
+// CHECK: [[VEC_VAL:%.+]] = load <4 x i32>, <4 x i32>* [[LDTEMP]]
+// CHECK: [[ITEM:%.+]] = extractelement <4 x i32> [[VEC_VAL]], i16 [[IDX]]
+// CHECK: [[OR:%.+]] = or i32 [[ITEM]], [[VEC_ITEM_VAL]]
+// CHECK: [[VEC_VAL:%.+]] = load <4 x i32>, <4 x i32>* [[LDTEMP]]
+// CHECK: [[NEW_VEC_VAL:%.+]] = insertelement <4 x i32> [[VEC_VAL]], i32 [[OR]], i16 [[IDX]]
+// CHECK: store <4 x i32> [[NEW_VEC_VAL]], <4 x i32>* [[LDTEMP]]
+// CHECK: [[NEW_VEC_VAL:%.+]] = load <4 x i32>, <4 x i32>* [[LDTEMP]]
+// CHECK: [[OLD_I128:%.+]] = bitcast <4 x i32> [[OLD_VEC_VAL]] to i128
+// CHECK: [[NEW_I128:%.+]] = bitcast <4 x i32> [[NEW_VEC_VAL]] to i128
+// CHECK: [[RES:%.+]] = cmpxchg i128* bitcast (<4 x i32>* [[DEST]] to i128*), i128 [[OLD_I128]], i128 [[NEW_I128]] monotonic monotonic
+// CHECK: [[FAILED_I128_OLD_VAL:%.+]] = extractvalue { i128, i1 } [[RES]], 0
+// CHECK: [[FAIL_SUCCESS:%.+]] = extractvalue { i128, i1 } [[RES]], 1
+// CHECK: [[FAILED_OLD_VAL]] = bitcast i128 [[FAILED_I128_OLD_VAL]] to <4 x i32>
+// CHECK: br i1 [[FAIL_SUCCESS]], label %[[EXIT:.+]], label %[[CONT]]
+// CHECK: [[EXIT]]
+#pragma omp atomic update
+ int4x[sv] |= bv;
+// CHECK: [[EXPR:%.+]] = load x86_fp80, x86_fp80* @{{.+}}
+// CHECK: [[PREV_VALUE:%.+]] = load atomic i32, i32* bitcast (i8* getelementptr (i8, i8* bitcast (%struct.BitFields* @{{.+}} to i8*), i64 4) to i32*) monotonic
+// CHECK: br label %[[CONT:.+]]
+// CHECK: [[CONT]]
+// CHECK: [[OLD_BF_VALUE:%.+]] = phi i32 [ [[PREV_VALUE]], %[[EXIT]] ], [ [[FAILED_OLD_VAL:%.+]], %[[CONT]] ]
+// CHECK: store i32 [[OLD_BF_VALUE]], i32* [[TEMP:%.+]],
+// CHECK: [[A_LD:%.+]] = load i32, i32* [[TEMP]],
+// CHECK: [[A_SHL:%.+]] = shl i32 [[A_LD]], 1
+// CHECK: [[A_ASHR:%.+]] = ashr i32 [[A_SHL]], 1
+// CHECK: [[X_RVAL:%.+]] = sitofp i32 [[A_ASHR]] to x86_fp80
+// CHECK: [[SUB:%.+]] = fsub x86_fp80 [[X_RVAL]], [[EXPR]]
+// CHECK: [[CONV:%.+]] = fptosi x86_fp80 [[SUB]] to i32
+// CHECK: [[NEW_VAL:%.+]] = load i32, i32* [[TEMP]],
+// CHECK: [[BF_VALUE:%.+]] = and i32 [[CONV]], 2147483647
+// CHECK: [[BF_CLEAR:%.+]] = and i32 [[NEW_VAL]], -2147483648
+// CHECK: or i32 [[BF_CLEAR]], [[BF_VALUE]]
+// CHECK: store i32 %{{.+}}, i32* [[LDTEMP:%.+]]
+// CHECK: [[NEW_BF_VALUE:%.+]] = load i32, i32* [[LDTEMP]]
+// CHECK: [[RES:%.+]] = cmpxchg i32* bitcast (i8* getelementptr (i8, i8* bitcast (%struct.BitFields* @{{.+}} to i8*), i64 4) to i32*), i32 [[OLD_BF_VALUE]], i32 [[NEW_BF_VALUE]] monotonic monotonic
+// CHECK: [[FAILED_OLD_VAL]] = extractvalue { i32, i1 } [[RES]], 0
+// CHECK: [[FAIL_SUCCESS:%.+]] = extractvalue { i32, i1 } [[RES]], 1
+// CHECK: br i1 [[FAIL_SUCCESS]], label %[[EXIT:.+]], label %[[CONT]]
+// CHECK: [[EXIT]]
+#pragma omp atomic
+ bfx.a = bfx.a - ldv;
+// CHECK: [[EXPR:%.+]] = load x86_fp80, x86_fp80* @{{.+}}
+// CHECK: [[BITCAST:%.+]] = bitcast i32* [[LDTEMP:%.+]] to i8*
+// CHECK: call void @__atomic_load(i64 4, i8* getelementptr (i8, i8* bitcast (%struct.BitFields_packed* @{{.+}} to i8*), i64 4), i8* [[BITCAST]], i32 0)
+// CHECK: [[PREV_VALUE:%.+]] = load i32, i32* [[LDTEMP]]
+// CHECK: br label %[[CONT:.+]]
+// CHECK: [[CONT]]
+// CHECK: [[OLD_BF_VALUE:%.+]] = phi i32 [ [[PREV_VALUE]], %[[EXIT]] ], [ [[FAILED_OLD_VAL:%.+]], %[[CONT]] ]
+// CHECK: store i32 [[OLD_BF_VALUE]], i32* [[TEMP:%.+]],
+// CHECK: [[A_LD:%.+]] = load i32, i32* [[TEMP]],
+// CHECK: [[A_SHL:%.+]] = shl i32 [[A_LD]], 1
+// CHECK: [[A_ASHR:%.+]] = ashr i32 [[A_SHL]], 1
+// CHECK: [[X_RVAL:%.+]] = sitofp i32 [[A_ASHR]] to x86_fp80
+// CHECK: [[MUL:%.+]] = fmul x86_fp80 [[X_RVAL]], [[EXPR]]
+// CHECK: [[CONV:%.+]] = fptosi x86_fp80 [[MUL]] to i32
+// CHECK: [[NEW_VAL:%.+]] = load i32, i32* [[TEMP]],
+// CHECK: [[BF_VALUE:%.+]] = and i32 [[CONV]], 2147483647
+// CHECK: [[BF_CLEAR:%.+]] = and i32 [[NEW_VAL]], -2147483648
+// CHECK: or i32 [[BF_CLEAR]], [[BF_VALUE]]
+// CHECK: store i32 %{{.+}}, i32* [[LDTEMP:%.+]]
+// CHECK: [[NEW_BF_VALUE:%.+]] = load i32, i32* [[LDTEMP]]
+// CHECK: store i32 [[OLD_BF_VALUE]], i32* [[TEMP_OLD_BF_ADDR:%.+]],
+// CHECK: store i32 [[NEW_BF_VALUE]], i32* [[TEMP_NEW_BF_ADDR:%.+]],
+// CHECK: [[BITCAST_TEMP_OLD_BF_ADDR:%.+]] = bitcast i32* [[TEMP_OLD_BF_ADDR]] to i8*
+// CHECK: [[BITCAST_TEMP_NEW_BF_ADDR:%.+]] = bitcast i32* [[TEMP_NEW_BF_ADDR]] to i8*
+// CHECK: [[FAIL_SUCCESS:%.+]] = call zeroext i1 @__atomic_compare_exchange(i64 4, i8* getelementptr (i8, i8* bitcast (%struct.BitFields_packed* @{{.+}} to i8*), i64 4), i8* [[BITCAST_TEMP_OLD_BF_ADDR]], i8* [[BITCAST_TEMP_NEW_BF_ADDR]], i32 0, i32 0)
+// CHECK: [[FAILED_OLD_VAL]] = load i32, i32* [[TEMP_OLD_BF_ADDR]]
+// CHECK: br i1 [[FAIL_SUCCESS]], label %[[EXIT:.+]], label %[[CONT]]
+// CHECK: [[EXIT]]
+#pragma omp atomic update
+ bfx_packed.a *= ldv;
+// CHECK: [[EXPR:%.+]] = load x86_fp80, x86_fp80* @{{.+}}
+// CHECK: [[PREV_VALUE:%.+]] = load atomic i32, i32* getelementptr inbounds (%struct.BitFields2, %struct.BitFields2* @{{.+}}, i32 0, i32 0) monotonic
+// CHECK: br label %[[CONT:.+]]
+// CHECK: [[CONT]]
+// CHECK: [[OLD_BF_VALUE:%.+]] = phi i32 [ [[PREV_VALUE]], %[[EXIT]] ], [ [[FAILED_OLD_VAL:%.+]], %[[CONT]] ]
+// CHECK: store i32 [[OLD_BF_VALUE]], i32* [[TEMP:%.+]],
+// CHECK: [[A_LD:%.+]] = load i32, i32* [[TEMP]],
+// CHECK: [[A_ASHR:%.+]] = ashr i32 [[A_LD]], 31
+// CHECK: [[X_RVAL:%.+]] = sitofp i32 [[A_ASHR]] to x86_fp80
+// CHECK: [[SUB:%.+]] = fsub x86_fp80 [[X_RVAL]], [[EXPR]]
+// CHECK: [[CONV:%.+]] = fptosi x86_fp80 [[SUB]] to i32
+// CHECK: [[NEW_VAL:%.+]] = load i32, i32* [[TEMP]],
+// CHECK: [[BF_AND:%.+]] = and i32 [[CONV]], 1
+// CHECK: [[BF_VALUE:%.+]] = shl i32 [[BF_AND]], 31
+// CHECK: [[BF_CLEAR:%.+]] = and i32 [[NEW_VAL]], 2147483647
+// CHECK: or i32 [[BF_CLEAR]], [[BF_VALUE]]
+// CHECK: store i32 %{{.+}}, i32* [[LDTEMP:%.+]]
+// CHECK: [[NEW_BF_VALUE:%.+]] = load i32, i32* [[LDTEMP]]
+// CHECK: [[RES:%.+]] = cmpxchg i32* getelementptr inbounds (%struct.BitFields2, %struct.BitFields2* @{{.+}}, i32 0, i32 0), i32 [[OLD_BF_VALUE]], i32 [[NEW_BF_VALUE]] monotonic monotonic
+// CHECK: [[FAILED_OLD_VAL]] = extractvalue { i32, i1 } [[RES]], 0
+// CHECK: [[FAIL_SUCCESS:%.+]] = extractvalue { i32, i1 } [[RES]], 1
+// CHECK: br i1 [[FAIL_SUCCESS]], label %[[EXIT:.+]], label %[[CONT]]
+// CHECK: [[EXIT]]
+#pragma omp atomic
+ bfx2.a -= ldv;
+// CHECK: [[EXPR:%.+]] = load x86_fp80, x86_fp80* @{{.+}}
+// CHECK: [[PREV_VALUE:%.+]] = load atomic i8, i8* getelementptr (i8, i8* bitcast (%struct.BitFields2_packed* @{{.+}} to i8*), i64 3) monotonic
+// CHECK: br label %[[CONT:.+]]
+// CHECK: [[CONT]]
+// CHECK: [[OLD_BF_VALUE:%.+]] = phi i8 [ [[PREV_VALUE]], %[[EXIT]] ], [ [[FAILED_OLD_VAL:%.+]], %[[CONT]] ]
+// CHECK: [[BITCAST:%.+]] = bitcast i32* %{{.+}} to i8*
+// CHECK: store i8 [[OLD_BF_VALUE]], i8* [[BITCAST]],
+// CHECK: [[A_LD:%.+]] = load i8, i8* [[BITCAST]],
+// CHECK: [[A_ASHR:%.+]] = ashr i8 [[A_LD]], 7
+// CHECK: [[CAST:%.+]] = sext i8 [[A_ASHR]] to i32
+// CHECK: [[X_RVAL:%.+]] = sitofp i32 [[CAST]] to x86_fp80
+// CHECK: [[DIV:%.+]] = fdiv x86_fp80 [[EXPR]], [[X_RVAL]]
+// CHECK: [[NEW_VAL:%.+]] = fptosi x86_fp80 [[DIV]] to i32
+// CHECK: [[TRUNC:%.+]] = trunc i32 [[NEW_VAL]] to i8
+// CHECK: [[BF_LD:%.+]] = load i8, i8* [[BITCAST]],
+// CHECK: [[BF_AND:%.+]] = and i8 [[TRUNC]], 1
+// CHECK: [[BF_VALUE:%.+]] = shl i8 [[BF_AND]], 7
+// CHECK: [[BF_CLEAR:%.+]] = and i8 %{{.+}}, 127
+// CHECK: or i8 [[BF_CLEAR]], [[BF_VALUE]]
+// CHECK: store i8 %{{.+}}, i8* [[LDTEMP:%.+]]
+// CHECK: [[NEW_BF_VALUE:%.+]] = load i8, i8* [[LDTEMP]]
+// CHECK: [[RES:%.+]] = cmpxchg i8* getelementptr (i8, i8* bitcast (%struct.BitFields2_packed* @{{.+}} to i8*), i64 3), i8 [[OLD_BF_VALUE]], i8 [[NEW_BF_VALUE]] monotonic monotonic
+// CHECK: [[FAILED_OLD_VAL]] = extractvalue { i8, i1 } [[RES]], 0
+// CHECK: [[FAIL_SUCCESS:%.+]] = extractvalue { i8, i1 } [[RES]], 1
+// CHECK: br i1 [[FAIL_SUCCESS]], label %[[EXIT:.+]], label %[[CONT]]
+// CHECK: [[EXIT]]
+#pragma omp atomic update
+ bfx2_packed.a = ldv / bfx2_packed.a;
+// CHECK: [[EXPR:%.+]] = load x86_fp80, x86_fp80* @{{.+}}
+// CHECK: [[PREV_VALUE:%.+]] = load atomic i32, i32* getelementptr inbounds (%struct.BitFields3, %struct.BitFields3* @{{.+}}, i32 0, i32 0) monotonic
+// CHECK: br label %[[CONT:.+]]
+// CHECK: [[CONT]]
+// CHECK: [[OLD_BF_VALUE:%.+]] = phi i32 [ [[PREV_VALUE]], %[[EXIT]] ], [ [[FAILED_OLD_VAL:%.+]], %[[CONT]] ]
+// CHECK: store i32 [[OLD_BF_VALUE]], i32* [[TEMP:%.+]],
+// CHECK: [[A_LD:%.+]] = load i32, i32* [[TEMP]],
+// CHECK: [[A_SHL:%.+]] = shl i32 [[A_LD]], 7
+// CHECK: [[A_ASHR:%.+]] = ashr i32 [[A_SHL]], 18
+// CHECK: [[X_RVAL:%.+]] = sitofp i32 [[A_ASHR]] to x86_fp80
+// CHECK: [[DIV:%.+]] = fdiv x86_fp80 [[X_RVAL]], [[EXPR]]
+// CHECK: [[NEW_VAL:%.+]] = fptosi x86_fp80 [[DIV]] to i32
+// CHECK: [[BF_LD:%.+]] = load i32, i32* [[TEMP]],
+// CHECK: [[BF_AND:%.+]] = and i32 [[NEW_VAL]], 16383
+// CHECK: [[BF_VALUE:%.+]] = shl i32 [[BF_AND]], 11
+// CHECK: [[BF_CLEAR:%.+]] = and i32 %{{.+}}, -33552385
+// CHECK: or i32 [[BF_CLEAR]], [[BF_VALUE]]
+// CHECK: store i32 %{{.+}}, i32* [[LDTEMP:%.+]]
+// CHECK: [[NEW_BF_VALUE:%.+]] = load i32, i32* [[LDTEMP]]
+// CHECK: [[RES:%.+]] = cmpxchg i32* getelementptr inbounds (%struct.BitFields3, %struct.BitFields3* @{{.+}}, i32 0, i32 0), i32 [[OLD_BF_VALUE]], i32 [[NEW_BF_VALUE]] monotonic monotonic
+// CHECK: [[FAILED_OLD_VAL]] = extractvalue { i32, i1 } [[RES]], 0
+// CHECK: [[FAIL_SUCCESS:%.+]] = extractvalue { i32, i1 } [[RES]], 1
+// CHECK: br i1 [[FAIL_SUCCESS]], label %[[EXIT:.+]], label %[[CONT]]
+// CHECK: [[EXIT]]
+#pragma omp atomic
+ bfx3.a /= ldv;
+// CHECK: [[EXPR:%.+]] = load x86_fp80, x86_fp80* @{{.+}}
+// CHECK: [[LDTEMP:%.+]] = bitcast i32* %{{.+}} to i24*
+// CHECK: [[BITCAST:%.+]] = bitcast i24* %{{.+}} to i8*
+// CHECK: call void @__atomic_load(i64 3, i8* getelementptr (i8, i8* bitcast (%struct.BitFields3_packed* @{{.+}} to i8*), i64 1), i8* [[BITCAST]], i32 0)
+// CHECK: [[PREV_VALUE:%.+]] = load i24, i24* [[LDTEMP]]
+// CHECK: br label %[[CONT:.+]]
+// CHECK: [[CONT]]
+// CHECK: [[OLD_BF_VALUE:%.+]] = phi i24 [ [[PREV_VALUE]], %[[EXIT]] ], [ [[FAILED_OLD_VAL:%.+]], %[[CONT]] ]
+// CHECK: [[BITCAST:%.+]] = bitcast i32* %{{.+}} to i24*
+// CHECK: store i24 [[OLD_BF_VALUE]], i24* [[BITCAST]],
+// CHECK: [[A_LD:%.+]] = load i24, i24* [[BITCAST]],
+// CHECK: [[A_SHL:%.+]] = shl i24 [[A_LD]], 7
+// CHECK: [[A_ASHR:%.+]] = ashr i24 [[A_SHL]], 10
+// CHECK: [[CAST:%.+]] = sext i24 [[A_ASHR]] to i32
+// CHECK: [[X_RVAL:%.+]] = sitofp i32 [[CAST]] to x86_fp80
+// CHECK: [[ADD:%.+]] = fadd x86_fp80 [[X_RVAL]], [[EXPR]]
+// CHECK: [[NEW_VAL:%.+]] = fptosi x86_fp80 [[ADD]] to i32
+// CHECK: [[TRUNC:%.+]] = trunc i32 [[NEW_VAL]] to i24
+// CHECK: [[BF_LD:%.+]] = load i24, i24* [[BITCAST]],
+// CHECK: [[BF_AND:%.+]] = and i24 [[TRUNC]], 16383
+// CHECK: [[BF_VALUE:%.+]] = shl i24 [[BF_AND]], 3
+// CHECK: [[BF_CLEAR:%.+]] = and i24 [[BF_LD]], -131065
+// CHECK: or i24 [[BF_CLEAR]], [[BF_VALUE]]
+// CHECK: store i24 %{{.+}}, i24* [[LDTEMP:%.+]]
+// CHECK: [[NEW_BF_VALUE:%.+]] = load i24, i24* [[LDTEMP]]
+// CHECK: [[TEMP_OLD_BF_ADDR:%.+]] = bitcast i32* %{{.+}} to i24*
+// CHECK: store i24 [[OLD_BF_VALUE]], i24* [[TEMP_OLD_BF_ADDR]]
+// CHECK: [[TEMP_NEW_BF_ADDR:%.+]] = bitcast i32* %{{.+}} to i24*
+// CHECK: store i24 [[NEW_BF_VALUE]], i24* [[TEMP_NEW_BF_ADDR]]
+// CHECK: [[BITCAST_TEMP_OLD_BF_ADDR:%.+]] = bitcast i24* [[TEMP_OLD_BF_ADDR]] to i8*
+// CHECK: [[BITCAST_TEMP_NEW_BF_ADDR:%.+]] = bitcast i24* [[TEMP_NEW_BF_ADDR]] to i8*
+// CHECK: [[FAIL_SUCCESS:%.+]] = call zeroext i1 @__atomic_compare_exchange(i64 3, i8* getelementptr (i8, i8* bitcast (%struct.BitFields3_packed* @{{.+}} to i8*), i64 1), i8* [[BITCAST_TEMP_OLD_BF_ADDR]], i8* [[BITCAST_TEMP_NEW_BF_ADDR]], i32 0, i32 0)
+// CHECK: [[FAILED_OLD_VAL]] = load i24, i24* [[TEMP_OLD_BF_ADDR]]
+// CHECK: br i1 [[FAIL_SUCCESS]], label %[[EXIT:.+]], label %[[CONT]]
+// CHECK: [[EXIT]]
+#pragma omp atomic update
+ bfx3_packed.a += ldv;
+// CHECK: [[EXPR:%.+]] = load x86_fp80, x86_fp80* @{{.+}}
+// CHECK: [[PREV_VALUE:%.+]] = load atomic i64, i64* bitcast (%struct.BitFields4* @{{.+}} to i64*) monotonic
+// CHECK: br label %[[CONT:.+]]
+// CHECK: [[CONT]]
+// CHECK: [[OLD_BF_VALUE:%.+]] = phi i64 [ [[PREV_VALUE]], %[[EXIT]] ], [ [[FAILED_OLD_VAL:%.+]], %[[CONT]] ]
+// CHECK: store i64 [[OLD_BF_VALUE]], i64* [[TEMP:%.+]],
+// CHECK: [[A_LD:%.+]] = load i64, i64* [[TEMP]],
+// CHECK: [[A_SHL:%.+]] = shl i64 [[A_LD]], 47
+// CHECK: [[A_ASHR:%.+]] = ashr i64 [[A_SHL:%.+]], 63
+// CHECK: [[A_CAST:%.+]] = trunc i64 [[A_ASHR:%.+]] to i32
+// CHECK: [[X_RVAL:%.+]] = sitofp i32 [[CAST:%.+]] to x86_fp80
+// CHECK: [[MUL:%.+]] = fmul x86_fp80 [[X_RVAL]], [[EXPR]]
+// CHECK: [[NEW_VAL:%.+]] = fptosi x86_fp80 [[MUL]] to i32
+// CHECK: [[ZEXT:%.+]] = zext i32 [[NEW_VAL]] to i64
+// CHECK: [[BF_LD:%.+]] = load i64, i64* [[TEMP]],
+// CHECK: [[BF_AND:%.+]] = and i64 [[ZEXT]], 1
+// CHECK: [[BF_VALUE:%.+]] = shl i64 [[BF_AND]], 16
+// CHECK: [[BF_CLEAR:%.+]] = and i64 [[BF_LD]], -65537
+// CHECK: or i64 [[BF_CLEAR]], [[BF_VALUE]]
+// CHECK: store i64 %{{.+}}, i64* [[LDTEMP:%.+]]
+// CHECK: [[NEW_BF_VALUE:%.+]] = load i64, i64* [[LDTEMP]]
+// CHECK: [[RES:%.+]] = cmpxchg i64* bitcast (%struct.BitFields4* @{{.+}} to i64*), i64 [[OLD_BF_VALUE]], i64 [[NEW_BF_VALUE]] monotonic monotonic
+// CHECK: [[FAILED_OLD_VAL]] = extractvalue { i64, i1 } [[RES]], 0
+// CHECK: [[FAIL_SUCCESS:%.+]] = extractvalue { i64, i1 } [[RES]], 1
+// CHECK: br i1 [[FAIL_SUCCESS]], label %[[EXIT:.+]], label %[[CONT]]
+// CHECK: [[EXIT]]
+#pragma omp atomic
+ bfx4.a = bfx4.a * ldv;
+// CHECK: [[EXPR:%.+]] = load x86_fp80, x86_fp80* @{{.+}}
+// CHECK: [[PREV_VALUE:%.+]] = load atomic i8, i8* getelementptr inbounds (%struct.BitFields4_packed, %struct.BitFields4_packed* @{{.+}}, i32 0, i32 0, i64 2) monotonic
+// CHECK: br label %[[CONT:.+]]
+// CHECK: [[CONT]]
+// CHECK: [[OLD_BF_VALUE:%.+]] = phi i8 [ [[PREV_VALUE]], %{{.+}} ], [ [[FAILED_OLD_VAL:%.+]], %[[CONT]] ]
+// CHECK: [[BITCAST:%.+]] = bitcast i32* %{{.+}} to i8*
+// CHECK: store i8 [[OLD_BF_VALUE]], i8* [[BITCAST]],
+// CHECK: [[A_LD:%.+]] = load i8, i8* [[BITCAST]],
+// CHECK: [[A_SHL:%.+]] = shl i8 [[A_LD]], 7
+// CHECK: [[A_ASHR:%.+]] = ashr i8 [[A_SHL:%.+]], 7
+// CHECK: [[CAST:%.+]] = sext i8 [[A_ASHR:%.+]] to i32
+// CHECK: [[CONV:%.+]] = sitofp i32 [[CAST]] to x86_fp80
+// CHECK: [[SUB: %.+]] = fsub x86_fp80 [[CONV]], [[EXPR]]
+// CHECK: [[CONV:%.+]] = fptosi x86_fp80 [[SUB:%.+]] to i32
+// CHECK: [[NEW_VAL:%.+]] = trunc i32 [[CONV]] to i8
+// CHECK: [[BF_LD:%.+]] = load i8, i8* [[BITCAST]],
+// CHECK: [[BF_VALUE:%.+]] = and i8 [[NEW_VAL]], 1
+// CHECK: [[BF_CLEAR:%.+]] = and i8 [[BF_LD]], -2
+// CHECK: or i8 [[BF_CLEAR]], [[BF_VALUE]]
+// CHECK: store i8 %{{.+}}, i8* [[LDTEMP:%.+]]
+// CHECK: [[NEW_BF_VALUE:%.+]] = load i8, i8* [[LDTEMP]]
+// CHECK: [[RES:%.+]] = cmpxchg i8* getelementptr inbounds (%struct.BitFields4_packed, %struct.BitFields4_packed* @{{.+}}, i32 0, i32 0, i64 2), i8 [[OLD_BF_VALUE]], i8 [[NEW_BF_VALUE]] monotonic monotonic
+// CHECK: [[FAILED_OLD_VAL]] = extractvalue { i8, i1 } [[RES]], 0
+// CHECK: [[FAIL_SUCCESS:%.+]] = extractvalue { i8, i1 } [[RES]], 1
+// CHECK: br i1 [[FAIL_SUCCESS]], label %[[EXIT:.+]], label %[[CONT]]
+// CHECK: [[EXIT]]
+#pragma omp atomic update
+ bfx4_packed.a -= ldv;
+// CHECK: [[EXPR:%.+]] = load x86_fp80, x86_fp80* @{{.+}}
+// CHECK: [[PREV_VALUE:%.+]] = load atomic i64, i64* bitcast (%struct.BitFields4* @{{.+}} to i64*) monotonic
+// CHECK: br label %[[CONT:.+]]
+// CHECK: [[CONT]]
+// CHECK: [[OLD_BF_VALUE:%.+]] = phi i64 [ [[PREV_VALUE]], %[[EXIT]] ], [ [[FAILED_OLD_VAL:%.+]], %[[CONT]] ]
+// CHECK: store i64 [[OLD_BF_VALUE]], i64* [[TEMP:%.+]],
+// CHECK: [[A_LD:%.+]] = load i64, i64* [[TEMP]],
+// CHECK: [[A_SHL:%.+]] = shl i64 [[A_LD]], 40
+// CHECK: [[A_ASHR:%.+]] = ashr i64 [[A_SHL:%.+]], 57
+// CHECK: [[CONV:%.+]] = sitofp i64 [[A_ASHR]] to x86_fp80
+// CHECK: [[DIV:%.+]] = fdiv x86_fp80 [[CONV]], [[EXPR]]
+// CHECK: [[CONV:%.+]] = fptosi x86_fp80 [[DIV]] to i64
+// CHECK: [[BF_LD:%.+]] = load i64, i64* [[TEMP]],
+// CHECK: [[BF_AND:%.+]] = and i64 [[CONV]], 127
+// CHECK: [[BF_VALUE:%.+]] = shl i64 [[BF_AND:%.+]], 17
+// CHECK: [[BF_CLEAR:%.+]] = and i64 [[BF_LD]], -16646145
+// CHECK: [[VAL:%.+]] = or i64 [[BF_CLEAR]], [[BF_VALUE]]
+// CHECK: store i64 [[VAL]], i64* [[LDTEMP:%.+]]
+// CHECK: [[NEW_BF_VALUE:%.+]] = load i64, i64* [[LDTEMP]]
+// CHECK: [[RES:%.+]] = cmpxchg i64* bitcast (%struct.BitFields4* @{{.+}} to i64*), i64 [[OLD_BF_VALUE]], i64 [[NEW_BF_VALUE]] monotonic monotonic
+// CHECK: [[FAILED_OLD_VAL]] = extractvalue { i64, i1 } [[RES]], 0
+// CHECK: [[FAIL_SUCCESS:%.+]] = extractvalue { i64, i1 } [[RES]], 1
+// CHECK: br i1 [[FAIL_SUCCESS]], label %[[EXIT:.+]], label %[[CONT]]
+// CHECK: [[EXIT]]
+#pragma omp atomic
+ bfx4.b /= ldv;
+// CHECK: [[EXPR:%.+]] = load x86_fp80, x86_fp80* @{{.+}}
+// CHECK: [[PREV_VALUE:%.+]] = load atomic i8, i8* getelementptr inbounds (%struct.BitFields4_packed, %struct.BitFields4_packed* @{{.+}}, i32 0, i32 0, i64 2) monotonic
+// CHECK: br label %[[CONT:.+]]
+// CHECK: [[CONT]]
+// CHECK: [[OLD_BF_VALUE:%.+]] = phi i8 [ [[PREV_VALUE]], %[[EXIT]] ], [ [[FAILED_OLD_VAL:%.+]], %[[CONT]] ]
+// CHECK: [[BITCAST:%.+]] = bitcast i64* %{{.+}} to i8*
+// CHECK: store i8 [[OLD_BF_VALUE]], i8* [[BITCAST]],
+// CHECK: [[A_LD:%.+]] = load i8, i8* [[BITCAST]],
+// CHECK: [[A_ASHR:%.+]] = ashr i8 [[A_LD]], 1
+// CHECK: [[CAST:%.+]] = sext i8 [[A_ASHR]] to i64
+// CHECK: [[CONV:%.+]] = sitofp i64 [[CAST]] to x86_fp80
+// CHECK: [[ADD:%.+]] = fadd x86_fp80 [[CONV]], [[EXPR]]
+// CHECK: [[NEW_VAL:%.+]] = fptosi x86_fp80 [[ADD]] to i64
+// CHECK: [[TRUNC:%.+]] = trunc i64 [[NEW_VAL]] to i8
+// CHECK: [[BF_LD:%.+]] = load i8, i8* [[BITCAST]],
+// CHECK: [[BF_AND:%.+]] = and i8 [[TRUNC]], 127
+// CHECK: [[BF_VALUE:%.+]] = shl i8 [[BF_AND]], 1
+// CHECK: [[BF_CLEAR:%.+]] = and i8 [[BF_LD]], 1
+// CHECK: or i8 [[BF_CLEAR]], [[BF_VALUE]]
+// CHECK: store i8 %{{.+}}, i8* [[LDTEMP:%.+]]
+// CHECK: [[NEW_BF_VALUE:%.+]] = load i8, i8* [[LDTEMP]]
+// CHECK: [[RES:%.+]] = cmpxchg i8* getelementptr inbounds (%struct.BitFields4_packed, %struct.BitFields4_packed* @{{.+}}, i32 0, i32 0, i64 2), i8 [[OLD_BF_VALUE]], i8 [[NEW_BF_VALUE]] monotonic monotonic
+// CHECK: [[FAILED_OLD_VAL]] = extractvalue { i8, i1 } [[RES]], 0
+// CHECK: [[FAIL_SUCCESS:%.+]] = extractvalue { i8, i1 } [[RES]], 1
+// CHECK: br i1 [[FAIL_SUCCESS]], label %[[EXIT:.+]], label %[[CONT]]
+// CHECK: [[EXIT]]
+#pragma omp atomic update
+ bfx4_packed.b += ldv;
+// CHECK: load i64, i64*
+// CHECK: [[EXPR:%.+]] = uitofp i64 %{{.+}} to float
+// CHECK: [[I64VAL:%.+]] = load atomic i64, i64* bitcast (<2 x float>* [[DEST:@.+]] to i64*) monotonic
+// CHECK: [[LD:%.+]] = bitcast i64 [[I64VAL]] to <2 x float>
+// CHECK: br label %[[CONT:.+]]
+// CHECK: [[CONT]]
+// CHECK: [[OLD_VEC_VAL:%.+]] = phi <2 x float> [ [[LD]], %{{.+}} ], [ [[FAILED_OLD_VAL:%.+]], %[[CONT]] ]
+// CHECK: store <2 x float> [[OLD_VEC_VAL]], <2 x float>* [[LDTEMP:%.+]],
+// CHECK: [[VEC_VAL:%.+]] = load <2 x float>, <2 x float>* [[LDTEMP]]
+// CHECK: [[X:%.+]] = extractelement <2 x float> [[VEC_VAL]], i64 0
+// CHECK: [[VEC_ITEM_VAL:%.+]] = fsub float [[EXPR]], [[X]]
+// CHECK: [[VEC_VAL:%.+]] = load <2 x float>, <2 x float>* [[LDTEMP]],
+// CHECK: [[NEW_VEC_VAL:%.+]] = insertelement <2 x float> [[VEC_VAL]], float [[VEC_ITEM_VAL]], i64 0
+// CHECK: store <2 x float> [[NEW_VEC_VAL]], <2 x float>* [[LDTEMP]]
+// CHECK: [[NEW_VEC_VAL:%.+]] = load <2 x float>, <2 x float>* [[LDTEMP]]
+// CHECK: [[OLD_I64:%.+]] = bitcast <2 x float> [[OLD_VEC_VAL]] to i64
+// CHECK: [[NEW_I64:%.+]] = bitcast <2 x float> [[NEW_VEC_VAL]] to i64
+// CHECK: [[RES:%.+]] = cmpxchg i64* bitcast (<2 x float>* [[DEST]] to i64*), i64 [[OLD_I64]], i64 [[NEW_I64]] monotonic monotonic
+// CHECK: [[FAILED_I64_OLD_VAL:%.+]] = extractvalue { i64, i1 } [[RES]], 0
+// CHECK: [[FAIL_SUCCESS:%.+]] = extractvalue { i64, i1 } [[RES]], 1
+// CHECK: [[FAILED_OLD_VAL]] = bitcast i64 [[FAILED_I64_OLD_VAL]] to <2 x float>
+// CHECK: br i1 [[FAIL_SUCCESS]], label %[[EXIT:.+]], label %[[CONT]]
+// CHECK: [[EXIT]]
+#pragma omp atomic
+ float2x.x = ulv - float2x.x;
+// CHECK: [[EXPR:%.+]] = load double, double* @{{.+}},
+// CHECK: [[OLD_VAL:%.+]] = call i32 @llvm.read_register.i32([[REG:metadata ![0-9]+]])
+// CHECK: [[X_RVAL:%.+]] = sitofp i32 [[OLD_VAL]] to double
+// CHECK: [[DIV:%.+]] = fdiv double [[EXPR]], [[X_RVAL]]
+// CHECK: [[NEW_VAL:%.+]] = fptosi double [[DIV]] to i32
+// CHECK: call void @llvm.write_register.i32([[REG]], i32 [[NEW_VAL]])
+// CHECK: call{{.*}} @__kmpc_flush(
+#pragma omp atomic seq_cst
+ rix = dv / rix;
+ return 0;
+}
+
+#endif
diff --git a/test/OpenMP/critical_codegen.cpp b/test/OpenMP/critical_codegen.cpp
index fdba923..cf99a75 100644
--- a/test/OpenMP/critical_codegen.cpp
+++ b/test/OpenMP/critical_codegen.cpp
@@ -53,6 +53,6 @@
// TERM_DEBUG: unreachable
foo();
}
-// TERM_DEBUG-DAG: [[DBG_LOC_START]] = !MDLocation(line: 44,
-// TERM_DEBUG-DAG: [[DBG_LOC_END]] = !MDLocation(line: 44,
+// TERM_DEBUG-DAG: [[DBG_LOC_START]] = !MDLocation(line: [[@LINE-12]],
+// TERM_DEBUG-DAG: [[DBG_LOC_END]] = !MDLocation(line: [[@LINE-3]],
#endif
diff --git a/test/OpenMP/for_codegen.cpp b/test/OpenMP/for_codegen.cpp
index f24f97c..a53af80 100644
--- a/test/OpenMP/for_codegen.cpp
+++ b/test/OpenMP/for_codegen.cpp
@@ -8,10 +8,11 @@
#define HEADER
// CHECK: [[IDENT_T_TY:%.+]] = type { i32, i32, i32, i32, i8* }
+// CHECK: [[IMPLICIT_BARRIER_LOC:@.+]] = private unnamed_addr constant %{{.+}} { i32 0, i32 66, i32 0, i32 0, i8*
// CHECK-LABEL: define {{.*void}} @{{.*}}without_schedule_clause{{.*}}(float* {{.+}}, float* {{.+}}, float* {{.+}}, float* {{.+}})
void without_schedule_clause(float *a, float *b, float *c, float *d) {
// CHECK: [[GTID:%.+]] = call i32 @__kmpc_global_thread_num([[IDENT_T_TY]]* [[DEFAULT_LOC:[@%].+]])
- #pragma omp for
+ #pragma omp for nowait
// CHECK: call void @__kmpc_for_static_init_4([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], i32 34, i32* [[IS_LAST:%[^,]+]], i32* [[OMP_LB:%[^,]+]], i32* [[OMP_UB:%[^,]+]], i32* [[OMP_ST:%[^,]+]], i32 1, i32 1)
// UB = min(UB, GlobalUB)
// CHECK-NEXT: [[UB:%.+]] = load i32, i32* [[OMP_UB]]
@@ -44,7 +45,7 @@
}
// CHECK: [[LOOP1_END]]
// CHECK: call void @__kmpc_for_static_fini([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]])
-// CHECK: call {{.+}} @__kmpc_cancel_barrier([[IDENT_T_TY]]* [[DEFAULT_LOC_BARRIER:[@%].+]], i32 [[GTID]])
+// CHECK-NOT: __kmpc_cancel_barrier
// CHECK: ret void
}
@@ -84,7 +85,7 @@
}
// CHECK: [[LOOP1_END]]
// CHECK: call void @__kmpc_for_static_fini([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]])
-// CHECK: call {{.+}} @__kmpc_cancel_barrier([[IDENT_T_TY]]* [[DEFAULT_LOC_BARRIER:[@%].+]], i32 [[GTID]])
+// CHECK: call {{.+}} @__kmpc_cancel_barrier([[IDENT_T_TY]]* [[IMPLICIT_BARRIER_LOC]], i32 [[GTID]])
// CHECK: ret void
}
@@ -143,7 +144,7 @@
// CHECK: [[O_LOOP1_END]]
// CHECK: call void @__kmpc_for_static_fini([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]])
-// CHECK: call {{.+}} @__kmpc_cancel_barrier([[IDENT_T_TY]]* [[DEFAULT_LOC_BARRIER:[@%].+]], i32 [[GTID]])
+// CHECK: call {{.+}} @__kmpc_cancel_barrier([[IDENT_T_TY]]* [[IMPLICIT_BARRIER_LOC]], i32 [[GTID]])
// CHECK: ret void
}
@@ -184,7 +185,7 @@
}
// CHECK: [[LOOP1_END]]
// CHECK: [[O_LOOP1_END]]
-// CHECK: call {{.+}} @__kmpc_cancel_barrier([[IDENT_T_TY]]* [[DEFAULT_LOC_BARRIER:[@%].+]], i32 [[GTID]])
+// CHECK: call {{.+}} @__kmpc_cancel_barrier([[IDENT_T_TY]]* [[IMPLICIT_BARRIER_LOC]], i32 [[GTID]])
// CHECK: ret void
}
@@ -225,7 +226,7 @@
}
// CHECK: [[LOOP1_END]]
// CHECK: [[O_LOOP1_END]]
-// CHECK: call {{.+}} @__kmpc_cancel_barrier([[IDENT_T_TY]]* [[DEFAULT_LOC_BARRIER:[@%].+]], i32 [[GTID]])
+// CHECK: call {{.+}} @__kmpc_cancel_barrier([[IDENT_T_TY]]* [[IMPLICIT_BARRIER_LOC]], i32 [[GTID]])
// CHECK: ret void
}
@@ -269,7 +270,7 @@
}
// CHECK: [[LOOP1_END]]
// CHECK: [[O_LOOP1_END]]
-// CHECK: call {{.+}} @__kmpc_cancel_barrier([[IDENT_T_TY]]* [[DEFAULT_LOC_BARRIER:[@%].+]], i32 [[GTID]])
+// CHECK: call {{.+}} @__kmpc_cancel_barrier([[IDENT_T_TY]]* [[IMPLICIT_BARRIER_LOC]], i32 [[GTID]])
// CHECK: ret void
}
@@ -310,7 +311,7 @@
}
// CHECK: [[LOOP1_END]]
// CHECK: [[O_LOOP1_END]]
-// CHECK: call {{.+}} @__kmpc_cancel_barrier([[IDENT_T_TY]]* [[DEFAULT_LOC_BARRIER:[@%].+]], i32 [[GTID]])
+// CHECK: call {{.+}} @__kmpc_cancel_barrier([[IDENT_T_TY]]* [[IMPLICIT_BARRIER_LOC]], i32 [[GTID]])
// CHECK: ret void
}
diff --git a/test/OpenMP/for_firstprivate_codegen.cpp b/test/OpenMP/for_firstprivate_codegen.cpp
new file mode 100644
index 0000000..b2fe730
--- /dev/null
+++ b/test/OpenMP/for_firstprivate_codegen.cpp
@@ -0,0 +1,280 @@
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -x c++ -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -std=c++11 -triple x86_64-apple-darwin10 -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -triple x86_64-apple-darwin10 -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -x c++ -std=c++11 -DLAMBDA -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck -check-prefix=LAMBDA %s
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -x c++ -fblocks -DBLOCKS -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck -check-prefix=BLOCKS %s
+// expected-no-diagnostics
+#ifndef HEADER
+#define HEADER
+
+struct St {
+ int a, b;
+ St() : a(0), b(0) {}
+ St(const St &st) : a(st.a + st.b), b(0) {}
+ ~St() {}
+};
+
+volatile int g = 1212;
+
+template <class T>
+struct S {
+ T f;
+ S(T a) : f(a + g) {}
+ S() : f(g) {}
+ S(const S &s, St t = St()) : f(s.f + t.a) {}
+ operator T() { return T(); }
+ ~S() {}
+};
+
+// CHECK-DAG: [[S_FLOAT_TY:%.+]] = type { float }
+// CHECK-DAG: [[S_INT_TY:%.+]] = type { i{{[0-9]+}} }
+// CHECK-DAG: [[ST_TY:%.+]] = type { i{{[0-9]+}}, i{{[0-9]+}} }
+// CHECK-DAG: [[CAP_TMAIN_TY:%.+]] = type { i{{[0-9]+}}*, [2 x i{{[0-9]+}}]*, [2 x [[S_INT_TY]]]*, [[S_INT_TY]]* }
+
+template <typename T>
+T tmain() {
+ S<T> test;
+ T t_var = T();
+ T vec[] = {1, 2};
+ S<T> s_arr[] = {1, 2};
+ S<T> var(3);
+#pragma omp parallel
+#pragma omp for firstprivate(t_var, vec, s_arr, var)
+ for (int i = 0; i < 0; ++i) {
+ vec[i] = t_var;
+ s_arr[i] = var;
+ }
+ return T();
+}
+
+// CHECK: [[TEST:@.+]] = global [[S_FLOAT_TY]] zeroinitializer,
+S<float> test;
+// CHECK-DAG: [[T_VAR:@.+]] = global i{{[0-9]+}} 333,
+int t_var = 333;
+// CHECK-DAG: [[VEC:@.+]] = global [2 x i{{[0-9]+}}] [i{{[0-9]+}} 1, i{{[0-9]+}} 2],
+int vec[] = {1, 2};
+// CHECK-DAG: [[S_ARR:@.+]] = global [2 x [[S_FLOAT_TY]]] zeroinitializer,
+S<float> s_arr[] = {1, 2};
+// CHECK-DAG: [[VAR:@.+]] = global [[S_FLOAT_TY]] zeroinitializer,
+S<float> var(3);
+// CHECK-DAG: [[IMPLICIT_BARRIER_LOC:@.+]] = private unnamed_addr constant %{{.+}} { i32 0, i32 66, i32 0, i32 0, i8*
+
+// CHECK: call {{.*}} [[S_FLOAT_TY_DEF_CONSTR:@.+]]([[S_FLOAT_TY]]* [[TEST]])
+// CHECK: ([[S_FLOAT_TY]]*)* [[S_FLOAT_TY_DESTR:@[^ ]+]] {{[^,]+}}, {{.+}}([[S_FLOAT_TY]]* [[TEST]]
+int main() {
+#ifdef LAMBDA
+ // LAMBDA: [[G:@.+]] = global i{{[0-9]+}} 1212,
+ // LAMBDA-LABEL: @main
+ // LAMBDA: call void [[OUTER_LAMBDA:@.+]](
+ [&]() {
+// LAMBDA: define{{.*}} internal{{.*}} void [[OUTER_LAMBDA]](
+// LAMBDA: call void {{.+}} @__kmpc_fork_call({{.+}}, i32 1, {{.+}}* [[OMP_REGION:@.+]] to {{.+}}, i8* %{{.+}})
+#pragma omp parallel
+#pragma omp for firstprivate(g)
+ for (int i = 0; i < 2; ++i) {
+ // LAMBDA: define{{.*}} internal{{.*}} void [[OMP_REGION]](i32* %{{.+}}, i32* %{{.+}}, %{{.+}}* [[ARG:%.+]])
+ // Skip temp vars for loop
+ // LAMBDA: alloca i{{[0-9]+}},
+ // LAMBDA: alloca i{{[0-9]+}},
+ // LAMBDA: alloca i{{[0-9]+}},
+ // LAMBDA: alloca i{{[0-9]+}},
+ // LAMBDA: alloca i{{[0-9]+}},
+ // LAMBDA: [[G_PRIVATE_ADDR:%.+]] = alloca i{{[0-9]+}},
+ // LAMBDA: [[G_VAL:%.+]] = load volatile i{{[0-9]+}}, i{{[0-9]+}}* [[G]]
+ // LAMBDA: store i{{[0-9]+}} [[G_VAL]], i{{[0-9]+}}* [[G_PRIVATE_ADDR]]
+ // LAMBDA: call i32 @__kmpc_cancel_barrier(
+ g = 1;
+ // LAMBDA: call void @__kmpc_for_static_init_4(
+ // LAMBDA: store volatile i{{[0-9]+}} 1, i{{[0-9]+}}* [[G_PRIVATE_ADDR]],
+ // LAMBDA: [[G_PRIVATE_ADDR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // LAMBDA: store i{{[0-9]+}}* [[G_PRIVATE_ADDR]], i{{[0-9]+}}** [[G_PRIVATE_ADDR_REF]]
+ // LAMBDA: call void [[INNER_LAMBDA:@.+]](%{{.+}}* [[ARG]])
+ // LAMBDA: call void @__kmpc_for_static_fini(
+ // LAMBDA: call i32 @__kmpc_cancel_barrier(
+ [&]() {
+ // LAMBDA: define {{.+}} void [[INNER_LAMBDA]](%{{.+}}* [[ARG_PTR:%.+]])
+ // LAMBDA: store %{{.+}}* [[ARG_PTR]], %{{.+}}** [[ARG_PTR_REF:%.+]],
+ g = 2;
+ // LAMBDA: [[ARG_PTR:%.+]] = load %{{.+}}*, %{{.+}}** [[ARG_PTR_REF]]
+ // LAMBDA: [[G_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // LAMBDA: [[G_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[G_PTR_REF]]
+ // LAMBDA: store volatile i{{[0-9]+}} 2, i{{[0-9]+}}* [[G_REF]]
+ }();
+ }
+ }();
+ return 0;
+#elif defined(BLOCKS)
+ // BLOCKS: [[G:@.+]] = global i{{[0-9]+}} 1212,
+ // BLOCKS-LABEL: @main
+ // BLOCKS: call void {{%.+}}(i8
+ ^{
+// BLOCKS: define{{.*}} internal{{.*}} void {{.+}}(i8*
+// BLOCKS: call void {{.+}} @__kmpc_fork_call({{.+}}, i32 1, {{.+}}* [[OMP_REGION:@.+]] to {{.+}}, i8* %{{.+}})
+#pragma omp parallel
+#pragma omp for firstprivate(g)
+ for (int i = 0; i < 2; ++i) {
+ // BLOCKS: define{{.*}} internal{{.*}} void [[OMP_REGION]](i32* %{{.+}}, i32* %{{.+}}, %{{.+}}* [[ARG:%.+]])
+ // Skip temp vars for loop
+ // BLOCKS: alloca i{{[0-9]+}},
+ // BLOCKS: alloca i{{[0-9]+}},
+ // BLOCKS: alloca i{{[0-9]+}},
+ // BLOCKS: alloca i{{[0-9]+}},
+ // BLOCKS: alloca i{{[0-9]+}},
+ // BLOCKS: [[G_PRIVATE_ADDR:%.+]] = alloca i{{[0-9]+}},
+ // BLOCKS: [[G_VAL:%.+]] = load volatile i{{[0-9]+}}, i{{[0-9]+}}* [[G]]
+ // BLOCKS: store i{{[0-9]+}} [[G_VAL]], i{{[0-9]+}}* [[G_PRIVATE_ADDR]]
+ // BLOCKS: call i32 @__kmpc_cancel_barrier(
+ g = 1;
+ // BLOCKS: call void @__kmpc_for_static_init_4(
+ // BLOCKS: store volatile i{{[0-9]+}} 1, i{{[0-9]+}}* [[G_PRIVATE_ADDR]],
+ // BLOCKS-NOT: [[G]]{{[[^:word:]]}}
+ // BLOCKS: i{{[0-9]+}}* [[G_PRIVATE_ADDR]]
+ // BLOCKS-NOT: [[G]]{{[[^:word:]]}}
+ // BLOCKS: call void {{%.+}}(i8
+ // BLOCKS: call void @__kmpc_for_static_fini(
+ // BLOCKS: call i32 @__kmpc_cancel_barrier(
+ ^{
+ // BLOCKS: define {{.+}} void {{@.+}}(i8*
+ g = 2;
+ // BLOCKS-NOT: [[G]]{{[[^:word:]]}}
+ // BLOCKS: store volatile i{{[0-9]+}} 2, i{{[0-9]+}}*
+ // BLOCKS-NOT: [[G]]{{[[^:word:]]}}
+ // BLOCKS: ret
+ }();
+ }
+ }();
+ return 0;
+#else
+#pragma omp for firstprivate(t_var, vec, s_arr, var)
+ for (int i = 0; i < 0; ++i) {
+ vec[i] = t_var;
+ s_arr[i] = var;
+ }
+ return tmain<int>();
+#endif
+}
+
+// CHECK: define {{.*}}i{{[0-9]+}} @main()
+// CHECK: alloca i{{[0-9]+}},
+// Skip temp vars for loop
+// CHECK: alloca i{{[0-9]+}},
+// CHECK: alloca i{{[0-9]+}},
+// CHECK: alloca i{{[0-9]+}},
+// CHECK: alloca i{{[0-9]+}},
+// CHECK: alloca i{{[0-9]+}},
+// CHECK: [[T_VAR_PRIV:%.+]] = alloca i{{[0-9]+}},
+// CHECK: [[VEC_PRIV:%.+]] = alloca [2 x i{{[0-9]+}}],
+// CHECK: [[S_ARR_PRIV:%.+]] = alloca [2 x [[S_FLOAT_TY]]],
+// CHECK: [[VAR_PRIV:%.+]] = alloca [[S_FLOAT_TY]],
+// CHECK: [[GTID:%.+]] = call i32 @__kmpc_global_thread_num(
+
+// firstprivate t_var(t_var)
+// CHECK: [[T_VAR_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[T_VAR]],
+// CHECK: store i{{[0-9]+}} [[T_VAR_VAL]], i{{[0-9]+}}* [[T_VAR_PRIV]],
+
+// firstprivate vec(vec)
+// CHECK: [[VEC_DEST:%.+]] = bitcast [2 x i{{[0-9]+}}]* [[VEC_PRIV]] to i8*
+// CHECK: call void @llvm.memcpy.{{.+}}(i8* [[VEC_DEST]], i8* bitcast ([2 x i{{[0-9]+}}]* [[VEC]] to i8*),
+
+// firstprivate s_arr(s_arr)
+// CHECK: [[S_ARR_PRIV_BEGIN:%.+]] = getelementptr inbounds [2 x [[S_FLOAT_TY]]], [2 x [[S_FLOAT_TY]]]* [[S_ARR_PRIV]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+// CHECK: [[S_ARR_PRIV_END:%.+]] = getelementptr [[S_FLOAT_TY]], [[S_FLOAT_TY]]* [[S_ARR_PRIV_BEGIN]], i{{[0-9]+}} 2
+// CHECK: [[IS_EMPTY:%.+]] = icmp eq [[S_FLOAT_TY]]* [[S_ARR_PRIV_BEGIN]], [[S_ARR_PRIV_END]]
+// CHECK: br i1 [[IS_EMPTY]], label %[[S_ARR_BODY_DONE:.+]], label %[[S_ARR_BODY:.+]]
+// CHECK: [[S_ARR_BODY]]
+// CHECK: getelementptr inbounds ([2 x [[S_FLOAT_TY]]], [2 x [[S_FLOAT_TY]]]* [[S_ARR]], i{{[0-9]+}} 0, i{{[0-9]+}} 0)
+// CHECK: call {{.*}} [[ST_TY_DEFAULT_CONSTR:@.+]]([[ST_TY]]* [[ST_TY_TEMP:%.+]])
+// CHECK: call {{.*}} [[S_FLOAT_TY_COPY_CONSTR:@.+]]([[S_FLOAT_TY]]* {{.+}}, [[S_FLOAT_TY]]* {{.+}}, [[ST_TY]]* [[ST_TY_TEMP]])
+// CHECK: call {{.*}} [[ST_TY_DESTR:@.+]]([[ST_TY]]* [[ST_TY_TEMP]])
+// CHECK: br i1 {{.+}}, label %{{.+}}, label %[[S_ARR_BODY]]
+
+// firstprivate var(var)
+// CHECK: call {{.*}} [[ST_TY_DEFAULT_CONSTR]]([[ST_TY]]* [[ST_TY_TEMP:%.+]])
+// CHECK: call {{.*}} [[S_FLOAT_TY_COPY_CONSTR]]([[S_FLOAT_TY]]* [[VAR_PRIV]], [[S_FLOAT_TY]]* {{.*}} [[VAR]], [[ST_TY]]* [[ST_TY_TEMP]])
+// CHECK: call {{.*}} [[ST_TY_DESTR]]([[ST_TY]]* [[ST_TY_TEMP]])
+
+// Synchronization for initialization.
+// CHECK: call i32 @__kmpc_cancel_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]], i{{[0-9]+}} [[GTID]])
+
+// CHECK: call void @__kmpc_for_static_init_4(
+// CHECK: call void @__kmpc_for_static_fini(
+
+// ~(firstprivate var), ~(firstprivate s_arr)
+// CHECK-DAG: call {{.*}} [[S_FLOAT_TY_DESTR]]([[S_FLOAT_TY]]* [[VAR_PRIV]])
+// CHECK-DAG: call {{.*}} [[S_FLOAT_TY_DESTR]]([[S_FLOAT_TY]]*
+// CHECK: call i32 @__kmpc_cancel_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]], i{{[0-9]+}} [[GTID]])
+
+// CHECK: = call {{.*}}i{{.+}} [[TMAIN_INT:@.+]]()
+
+// CHECK: ret void
+
+// CHECK: define {{.*}} i{{[0-9]+}} [[TMAIN_INT]]()
+// CHECK: [[TEST:%.+]] = alloca [[S_INT_TY]],
+// CHECK: call {{.*}} [[S_INT_TY_DEF_CONSTR:@.+]]([[S_INT_TY]]* [[TEST]])
+// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [[CAP_TMAIN_TY]]*)* [[TMAIN_MICROTASK:@.+]] to void
+// CHECK: call {{.*}} [[S_INT_TY_DESTR:@.+]]([[S_INT_TY]]*
+// CHECK: ret
+//
+// CHECK: define internal void [[TMAIN_MICROTASK]](i{{[0-9]+}}* [[GTID_ADDR:%.+]], i{{[0-9]+}}* %{{.+}}, [[CAP_TMAIN_TY]]* %{{.+}})
+// Skip temp vars for loop
+// CHECK: alloca i{{[0-9]+}},
+// CHECK: alloca i{{[0-9]+}},
+// CHECK: alloca i{{[0-9]+}},
+// CHECK: alloca i{{[0-9]+}},
+// CHECK: alloca i{{[0-9]+}},
+// CHECK: [[T_VAR_PRIV:%.+]] = alloca i{{[0-9]+}},
+// CHECK: [[VEC_PRIV:%.+]] = alloca [2 x i{{[0-9]+}}],
+// CHECK: [[S_ARR_PRIV:%.+]] = alloca [2 x [[S_INT_TY]]],
+// CHECK: [[VAR_PRIV:%.+]] = alloca [[S_INT_TY]],
+// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]],
+
+// firstprivate t_var(t_var)
+// CHECK: [[T_VAR_PTR_REF:%.+]] = getelementptr inbounds [[CAP_TMAIN_TY]], [[CAP_TMAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 0
+// CHECK: [[T_VAR_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[T_VAR_PTR_REF]],
+// CHECK: [[T_VAR_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[T_VAR_REF]],
+// CHECK: store i{{[0-9]+}} [[T_VAR_VAL]], i{{[0-9]+}}* [[T_VAR_PRIV]],
+
+// firstprivate vec(vec)
+// CHECK: [[VEC_PTR_REF:%.+]] = getelementptr inbounds [[CAP_TMAIN_TY]], [[CAP_TMAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 1
+// CHECK: [[VEC_REF:%.+]] = load [2 x i{{[0-9]+}}]*, [2 x i{{[0-9]+}}]** [[VEC_PTR_REF:%.+]],
+// CHECK: [[VEC_DEST:%.+]] = bitcast [2 x i{{[0-9]+}}]* [[VEC_PRIV]] to i8*
+// CHECK: [[VEC_SRC:%.+]] = bitcast [2 x i{{[0-9]+}}]* [[VEC_REF]] to i8*
+// CHECK: call void @llvm.memcpy.{{.+}}(i8* [[VEC_DEST]], i8* [[VEC_SRC]],
+
+// firstprivate s_arr(s_arr)
+// CHECK: [[S_ARR_REF:%.+]] = getelementptr inbounds [[CAP_TMAIN_TY]], [[CAP_TMAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 2
+// CHECK: [[S_ARR:%.+]] = load [2 x [[S_INT_TY]]]*, [2 x [[S_INT_TY]]]** [[S_ARR_REF]],
+// CHECK: [[S_ARR_PRIV_BEGIN:%.+]] = getelementptr inbounds [2 x [[S_INT_TY]]], [2 x [[S_INT_TY]]]* [[S_ARR_PRIV]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+// CHECK: [[S_ARR_PRIV_END:%.+]] = getelementptr [[S_INT_TY]], [[S_INT_TY]]* [[S_ARR_PRIV_BEGIN]], i{{[0-9]+}} 2
+// CHECK: [[IS_EMPTY:%.+]] = icmp eq [[S_INT_TY]]* [[S_ARR_PRIV_BEGIN]], [[S_ARR_PRIV_END]]
+// CHECK: br i1 [[IS_EMPTY]], label %[[S_ARR_BODY_DONE:.+]], label %[[S_ARR_BODY:.+]]
+// CHECK: [[S_ARR_BODY]]
+// CHECK: call {{.*}} [[ST_TY_DEFAULT_CONSTR:@.+]]([[ST_TY]]* [[ST_TY_TEMP:%.+]])
+// CHECK: call {{.*}} [[S_INT_TY_COPY_CONSTR:@.+]]([[S_INT_TY]]* {{.+}}, [[S_INT_TY]]* {{.+}}, [[ST_TY]]* [[ST_TY_TEMP]])
+// CHECK: call {{.*}} [[ST_TY_DESTR:@.+]]([[ST_TY]]* [[ST_TY_TEMP]])
+// CHECK: br i1 {{.+}}, label %{{.+}}, label %[[S_ARR_BODY]]
+
+// firstprivate var(var)
+// CHECK: [[VAR_REF_PTR:%.+]] = getelementptr inbounds [[CAP_TMAIN_TY]], [[CAP_TMAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 3
+// CHECK: [[VAR_REF:%.+]] = load [[S_INT_TY]]*, [[S_INT_TY]]** [[VAR_REF_PTR]],
+// CHECK: call {{.*}} [[ST_TY_DEFAULT_CONSTR]]([[ST_TY]]* [[ST_TY_TEMP:%.+]])
+// CHECK: call {{.*}} [[S_INT_TY_COPY_CONSTR]]([[S_INT_TY]]* [[VAR_PRIV]], [[S_INT_TY]]* {{.*}} [[VAR_REF]], [[ST_TY]]* [[ST_TY_TEMP]])
+// CHECK: call {{.*}} [[ST_TY_DESTR]]([[ST_TY]]* [[ST_TY_TEMP]])
+
+// Synchronization for initialization.
+// CHECK: [[GTID_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[GTID_ADDR_ADDR]]
+// CHECK: [[GTID:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[GTID_REF]]
+// CHECK: call i32 @__kmpc_cancel_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]], i{{[0-9]+}} [[GTID]])
+
+// CHECK: call void @__kmpc_for_static_init_4(
+// CHECK: call void @__kmpc_for_static_fini(
+
+// ~(firstprivate var), ~(firstprivate s_arr)
+// CHECK-DAG: call {{.*}} [[S_INT_TY_DESTR]]([[S_INT_TY]]* [[VAR_PRIV]])
+// CHECK-DAG: call {{.*}} [[S_INT_TY_DESTR]]([[S_INT_TY]]*
+// CHECK: [[GTID_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[GTID_ADDR_ADDR]]
+// CHECK: [[GTID:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[GTID_REF]]
+// CHECK: call i32 @__kmpc_cancel_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]], i{{[0-9]+}} [[GTID]])
+// CHECK: ret void
+#endif
+
diff --git a/test/OpenMP/for_firstprivate_messages.cpp b/test/OpenMP/for_firstprivate_messages.cpp
index 6aa977b..a733371 100644
--- a/test/OpenMP/for_firstprivate_messages.cpp
+++ b/test/OpenMP/for_firstprivate_messages.cpp
@@ -26,8 +26,8 @@
S3 &operator=(const S3 &s3);
public:
- S3() : a(0) {} // expected-note {{candidate constructor not viable: requires 0 arguments, but 1 was provided}}
- S3(S3 &s3) : a(s3.a) {} // expected-note {{candidate constructor not viable: 1st argument ('const S3') would lose const qualifier}}
+ S3() : a(0) {} // expected-note 2 {{candidate constructor not viable: requires 0 arguments, but 1 was provided}}
+ S3(S3 &s3) : a(s3.a) {} // expected-note 2 {{candidate constructor not viable: 1st argument ('const S3') would lose const qualifier}}
};
const S3 c;
const S3 ca[5];
@@ -152,6 +152,14 @@
return 0;
}
+namespace A {
+double x;
+#pragma omp threadprivate(x) // expected-note {{defined as threadprivate or thread local}}
+}
+namespace B {
+using A::x;
+}
+
int main(int argc, char **argv) {
const int d = 5;
const int da[5] = {0};
@@ -194,7 +202,7 @@
for (i = 0; i < argc; ++i)
foo();
#pragma omp parallel
-#pragma omp for firstprivate(a, b, c, d, f) // expected-error {{firstprivate variable with incomplete type 'S1'}} expected-error {{no matching constructor for initialization of 'const S3'}}
+#pragma omp for firstprivate(a, b, c, d, f) // expected-error {{firstprivate variable with incomplete type 'S1'}} expected-error {{no matching constructor for initialization of 'S3'}}
for (i = 0; i < argc; ++i)
foo();
#pragma omp parallel
@@ -210,7 +218,7 @@
for (i = 0; i < argc; ++i)
foo();
#pragma omp parallel
-#pragma omp for firstprivate(ca) // OK
+#pragma omp for firstprivate(ca) // expected-error {{no matching constructor for initialization of 'S3'}}
for (i = 0; i < argc; ++i)
foo();
#pragma omp parallel
@@ -288,6 +296,10 @@
#pragma omp for firstprivate(i) // expected-error {{firstprivate variable must be shared}}
for (i = 0; i < argc; ++i)
foo();
+#pragma omp parallel
+#pragma omp for firstprivate(B::x) // expected-error {{threadprivate or thread local variable cannot be firstprivate}}
+ for (i = 0; i < argc; ++i)
+ foo();
return foomain<S4, S5>(argc, argv); // expected-note {{in instantiation of function template specialization 'foomain<S4, S5>' requested here}}
}
diff --git a/test/OpenMP/for_lastprivate_codegen.cpp b/test/OpenMP/for_lastprivate_codegen.cpp
new file mode 100644
index 0000000..b9e23ce
--- /dev/null
+++ b/test/OpenMP/for_lastprivate_codegen.cpp
@@ -0,0 +1,361 @@
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -x c++ -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -std=c++11 -triple x86_64-apple-darwin10 -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -triple x86_64-apple-darwin10 -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -x c++ -std=c++11 -DLAMBDA -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck -check-prefix=LAMBDA %s
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -x c++ -fblocks -DBLOCKS -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck -check-prefix=BLOCKS %s
+// expected-no-diagnostics
+#ifndef HEADER
+#define HEADER
+
+template <class T>
+struct S {
+ T f;
+ S(T a) : f(a) {}
+ S() : f() {}
+ S<T> &operator=(const S<T> &);
+ operator T() { return T(); }
+ ~S() {}
+};
+
+volatile int g = 1212;
+
+// CHECK: [[S_FLOAT_TY:%.+]] = type { float }
+// CHECK: [[CAP_MAIN_TY:%.+]] = type { i{{[0-9]+}}*, [2 x i{{[0-9]+}}]*, [2 x [[S_FLOAT_TY]]]*, [[S_FLOAT_TY]]* }
+// CHECK: [[S_INT_TY:%.+]] = type { i32 }
+// CHECK: [[CAP_TMAIN_TY:%.+]] = type { i{{[0-9]+}}*, [2 x i{{[0-9]+}}]*, [2 x [[S_INT_TY]]]*, [[S_INT_TY]]* }
+// CHECK-DAG: [[IMPLICIT_BARRIER_LOC:@.+]] = private unnamed_addr constant %{{.+}} { i32 0, i32 66, i32 0, i32 0, i8*
+// CHECK-DAG: [[X:@.+]] = global double 0.0
+template <typename T>
+T tmain() {
+ S<T> test;
+ T t_var = T();
+ T vec[] = {1, 2};
+ S<T> s_arr[] = {1, 2};
+ S<T> var(3);
+#pragma omp parallel
+#pragma omp for lastprivate(t_var, vec, s_arr, var)
+ for (int i = 0; i < 2; ++i) {
+ vec[i] = t_var;
+ s_arr[i] = var;
+ }
+ return T();
+}
+
+namespace A {
+double x;
+}
+namespace B {
+using A::x;
+}
+
+int main() {
+#ifdef LAMBDA
+ // LAMBDA: [[G:@.+]] = global i{{[0-9]+}} 1212,
+ // LAMBDA-LABEL: @main
+ // LAMBDA: call void [[OUTER_LAMBDA:@.+]](
+ [&]() {
+ // LAMBDA: define{{.*}} internal{{.*}} void [[OUTER_LAMBDA]](
+ // LAMBDA: call void {{.+}} @__kmpc_fork_call({{.+}}, i32 1, {{.+}}* [[OMP_REGION:@.+]] to {{.+}}, i8* %{{.+}})
+#pragma omp parallel
+#pragma omp for lastprivate(g)
+ for (int i = 0; i < 2; ++i) {
+ // LAMBDA: define{{.*}} internal{{.*}} void [[OMP_REGION]](i32* %{{.+}}, i32* %{{.+}}, %{{.+}}* [[ARG:%.+]])
+ // LAMBDA: alloca i{{[0-9]+}},
+ // LAMBDA: alloca i{{[0-9]+}},
+ // LAMBDA: alloca i{{[0-9]+}},
+ // LAMBDA: alloca i{{[0-9]+}},
+ // LAMBDA: alloca i{{[0-9]+}},
+ // LAMBDA: [[G_PRIVATE_ADDR:%.+]] = alloca i{{[0-9]+}},
+ // LAMBDA: store %{{.+}}* [[ARG]], %{{.+}}** [[ARG_REF:%.+]],
+ // LAMBDA: call {{.+}} @__kmpc_for_static_init_4(%{{.+}}* @{{.+}}, i32 %{{.+}}, i32 34, i32* [[IS_LAST_ADDR:%.+]], i32* %{{.+}}, i32* %{{.+}}, i32* %{{.+}}, i32 1, i32 1)
+ // LAMBDA: store volatile i{{[0-9]+}} 1, i{{[0-9]+}}* [[G_PRIVATE_ADDR]],
+ // LAMBDA: [[G_PRIVATE_ADDR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // LAMBDA: store i{{[0-9]+}}* [[G_PRIVATE_ADDR]], i{{[0-9]+}}** [[G_PRIVATE_ADDR_REF]]
+ // LAMBDA: call void [[INNER_LAMBDA:@.+]](%{{.+}}* [[ARG]])
+ // LAMBDA: call void @__kmpc_for_static_fini(%{{.+}}* @{{.+}}, i32 %{{.+}})
+ g = 1;
+ // Check for final copying of private values back to original vars.
+ // LAMBDA: [[IS_LAST_VAL:%.+]] = load i32, i32* [[IS_LAST_ADDR]],
+ // LAMBDA: [[IS_LAST_ITER:%.+]] = icmp ne i32 [[IS_LAST_VAL]], 0
+ // LAMBDA: br i1 [[IS_LAST_ITER:%.+]], label %[[LAST_THEN:.+]], label %[[LAST_DONE:.+]]
+ // LAMBDA: [[LAST_THEN]]
+ // Actual copying.
+
+ // original g=private_g;
+ // LAMBDA: [[G_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[G_PRIVATE_ADDR]],
+ // LAMBDA: store volatile i{{[0-9]+}} [[G_VAL]], i{{[0-9]+}}* [[G]],
+ // LAMBDA: br label %[[LAST_DONE]]
+ // LAMBDA: [[LAST_DONE]]
+ // LAMBDA: [[GTID_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** %{{.+}}
+ // LAMBDA: [[GTID:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[GTID_REF]]
+ // LAMBDA: call i32 @__kmpc_cancel_barrier(%{{.+}}* @{{.+}}, i{{[0-9]+}} [[GTID]])
+ [&]() {
+ // LAMBDA: define {{.+}} void [[INNER_LAMBDA]](%{{.+}}* [[ARG_PTR:%.+]])
+ // LAMBDA: store %{{.+}}* [[ARG_PTR]], %{{.+}}** [[ARG_PTR_REF:%.+]],
+ g = 2;
+ // LAMBDA: [[ARG_PTR:%.+]] = load %{{.+}}*, %{{.+}}** [[ARG_PTR_REF]]
+ // LAMBDA: [[G_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // LAMBDA: [[G_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[G_PTR_REF]]
+ // LAMBDA: store volatile i{{[0-9]+}} 2, i{{[0-9]+}}* [[G_REF]]
+ }();
+ }
+ }();
+ return 0;
+#elif defined(BLOCKS)
+ // BLOCKS: [[G:@.+]] = global i{{[0-9]+}} 1212,
+ // BLOCKS-LABEL: @main
+ // BLOCKS: call void {{%.+}}(i8
+ ^{
+ // BLOCKS: define{{.*}} internal{{.*}} void {{.+}}(i8*
+ // BLOCKS: call void {{.+}} @__kmpc_fork_call({{.+}}, i32 1, {{.+}}* [[OMP_REGION:@.+]] to {{.+}}, i8* %{{.+}})
+#pragma omp parallel
+#pragma omp for lastprivate(g)
+ for (int i = 0; i < 2; ++i) {
+ // BLOCKS: define{{.*}} internal{{.*}} void [[OMP_REGION]](i32* %{{.+}}, i32* %{{.+}}, %{{.+}}* [[ARG:%.+]])
+ // BLOCKS: alloca i{{[0-9]+}},
+ // BLOCKS: alloca i{{[0-9]+}},
+ // BLOCKS: alloca i{{[0-9]+}},
+ // BLOCKS: alloca i{{[0-9]+}},
+ // BLOCKS: alloca i{{[0-9]+}},
+ // BLOCKS: [[G_PRIVATE_ADDR:%.+]] = alloca i{{[0-9]+}},
+ // BLOCKS: store %{{.+}}* [[ARG]], %{{.+}}** [[ARG_REF:%.+]],
+ // BLOCKS: call {{.+}} @__kmpc_for_static_init_4(%{{.+}}* @{{.+}}, i32 %{{.+}}, i32 34, i32* [[IS_LAST_ADDR:%.+]], i32* %{{.+}}, i32* %{{.+}}, i32* %{{.+}}, i32 1, i32 1)
+ // BLOCKS: store volatile i{{[0-9]+}} 1, i{{[0-9]+}}* [[G_PRIVATE_ADDR]],
+ // BLOCKS-NOT: [[G]]{{[[^:word:]]}}
+ // BLOCKS: i{{[0-9]+}}* [[G_PRIVATE_ADDR]]
+ // BLOCKS-NOT: [[G]]{{[[^:word:]]}}
+ // BLOCKS: call void {{%.+}}(i8
+ // BLOCKS: call void @__kmpc_for_static_fini(%{{.+}}* @{{.+}}, i32 %{{.+}})
+ g = 1;
+ // Check for final copying of private values back to original vars.
+ // BLOCKS: [[IS_LAST_VAL:%.+]] = load i32, i32* [[IS_LAST_ADDR]],
+ // BLOCKS: [[IS_LAST_ITER:%.+]] = icmp ne i32 [[IS_LAST_VAL]], 0
+ // BLOCKS: br i1 [[IS_LAST_ITER:%.+]], label %[[LAST_THEN:.+]], label %[[LAST_DONE:.+]]
+ // BLOCKS: [[LAST_THEN]]
+ // Actual copying.
+
+ // original g=private_g;
+ // BLOCKS: [[G_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[G_PRIVATE_ADDR]],
+ // BLOCKS: store volatile i{{[0-9]+}} [[G_VAL]], i{{[0-9]+}}* [[G]],
+ // BLOCKS: br label %[[LAST_DONE]]
+ // BLOCKS: [[LAST_DONE]]
+ // BLOCKS: [[GTID_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** %{{.+}}
+ // BLOCKS: [[GTID:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[GTID_REF]]
+ // BLOCKS: call i32 @__kmpc_cancel_barrier(%{{.+}}* @{{.+}}, i{{[0-9]+}} [[GTID]])
+ g = 1;
+ ^{
+ // BLOCKS: define {{.+}} void {{@.+}}(i8*
+ g = 2;
+ // BLOCKS-NOT: [[G]]{{[[^:word:]]}}
+ // BLOCKS: store volatile i{{[0-9]+}} 2, i{{[0-9]+}}*
+ // BLOCKS-NOT: [[G]]{{[[^:word:]]}}
+ // BLOCKS: ret
+ }();
+ }
+ }();
+ return 0;
+#else
+ S<float> test;
+ int t_var = 0;
+ int vec[] = {1, 2};
+ S<float> s_arr[] = {1, 2};
+ S<float> var(3);
+#pragma omp parallel
+#pragma omp for lastprivate(t_var, vec, s_arr, var)
+ for (int i = 0; i < 2; ++i) {
+ vec[i] = t_var;
+ s_arr[i] = var;
+ }
+#pragma omp parallel
+#pragma omp for lastprivate(A::x, B::x)
+ for (int i = 0; i < 2; ++i) {
+ A::x++;
+ }
+ return tmain<int>();
+#endif
+}
+
+// CHECK: define i{{[0-9]+}} @main()
+// CHECK: [[TEST:%.+]] = alloca [[S_FLOAT_TY]],
+// CHECK: call {{.*}} [[S_FLOAT_TY_DEF_CONSTR:@.+]]([[S_FLOAT_TY]]* [[TEST]])
+// CHECK: %{{.+}} = bitcast [[CAP_MAIN_TY]]*
+// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [[CAP_MAIN_TY]]*)* [[MAIN_MICROTASK:@.+]] to void
+// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, %{{.+}}*)* [[MAIN_MICROTASK1:@.+]] to void
+// CHECK: = call {{.+}} [[TMAIN_INT:@.+]]()
+// CHECK: call void [[S_FLOAT_TY_DESTR:@.+]]([[S_FLOAT_TY]]*
+// CHECK: ret
+
+// CHECK: define internal void [[MAIN_MICROTASK]](i{{[0-9]+}}* [[GTID_ADDR:%.+]], i{{[0-9]+}}* %{{.+}}, [[CAP_MAIN_TY]]* %{{.+}})
+// CHECK: alloca i{{[0-9]+}},
+// CHECK: alloca i{{[0-9]+}},
+// CHECK: alloca i{{[0-9]+}},
+// CHECK: alloca i{{[0-9]+}},
+// CHECK: alloca i{{[0-9]+}},
+// CHECK: [[T_VAR_PRIV:%.+]] = alloca i{{[0-9]+}},
+// CHECK: [[VEC_PRIV:%.+]] = alloca [2 x i{{[0-9]+}}],
+// CHECK: [[S_ARR_PRIV:%.+]] = alloca [2 x [[S_FLOAT_TY]]],
+// CHECK: [[VAR_PRIV:%.+]] = alloca [[S_FLOAT_TY]],
+// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_REF:%.+]]
+
+// Check for default initialization.
+// CHECK: [[T_VAR_PTR_REF:%.+]] = getelementptr inbounds [[CAP_MAIN_TY]], [[CAP_MAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 0
+// CHECK: [[T_VAR_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[T_VAR_PTR_REF]],
+// CHECK-NOT: [[T_VAR_PRIV]]
+// CHECK: [[VEC_PTR_REF:%.+]] = getelementptr inbounds [[CAP_MAIN_TY]], [[CAP_MAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 1
+// CHECK: [[VEC_REF:%.+]] = load [2 x i{{[0-9]+}}]*, [2 x i{{[0-9]+}}]** [[VEC_PTR_REF:%.+]],
+// CHECK-NOT: [[VEC_PRIV]]
+// CHECK: [[S_ARR_REF_PTR:%.+]] = getelementptr inbounds [[CAP_MAIN_TY]], [[CAP_MAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 2
+// CHECK: [[S_ARR_REF:%.+]] = load [2 x [[S_FLOAT_TY]]]*, [2 x [[S_FLOAT_TY]]]** [[S_ARR_REF_PTR]],
+// CHECK: [[S_ARR_PRIV_ITEM:%.+]] = phi [[S_FLOAT_TY]]*
+// CHECK: call {{.*}} [[S_FLOAT_TY_DEF_CONSTR]]([[S_FLOAT_TY]]* [[S_ARR_PRIV_ITEM]])
+// CHECK: [[VAR_REF_PTR:%.+]] = getelementptr inbounds [[CAP_MAIN_TY]], [[CAP_MAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 3
+// CHECK: [[VAR_REF:%.+]] = load [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** [[VAR_REF_PTR]],
+// CHECK: call {{.*}} [[S_FLOAT_TY_DEF_CONSTR]]([[S_FLOAT_TY]]* [[VAR_PRIV]])
+// CHECK: call {{.+}} @__kmpc_for_static_init_4(%{{.+}}* @{{.+}}, i32 %{{.+}}, i32 34, i32* [[IS_LAST_ADDR:%.+]], i32* %{{.+}}, i32* %{{.+}}, i32* %{{.+}}, i32 1, i32 1)
+// <Skip loop body>
+// CHECK: call void @__kmpc_for_static_fini(%{{.+}}* @{{.+}}, i32 %{{.+}})
+
+// Check for final copying of private values back to original vars.
+// CHECK: [[IS_LAST_VAL:%.+]] = load i32, i32* [[IS_LAST_ADDR]],
+// CHECK: [[IS_LAST_ITER:%.+]] = icmp ne i32 [[IS_LAST_VAL]], 0
+// CHECK: br i1 [[IS_LAST_ITER:%.+]], label %[[LAST_THEN:.+]], label %[[LAST_DONE:.+]]
+// CHECK: [[LAST_THEN]]
+// Actual copying.
+
+// original t_var=private_t_var;
+// CHECK: [[T_VAR_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[T_VAR_PRIV]],
+// CHECK: store i{{[0-9]+}} [[T_VAR_VAL]], i{{[0-9]+}}* [[T_VAR_REF]],
+
+// original vec[]=private_vec[];
+// CHECK: [[VEC_DEST:%.+]] = bitcast [2 x i{{[0-9]+}}]* [[VEC_REF]] to i8*
+// CHECK: [[VEC_SRC:%.+]] = bitcast [2 x i{{[0-9]+}}]* [[VEC_PRIV]] to i8*
+// CHECK: call void @llvm.memcpy.{{.+}}(i8* [[VEC_DEST]], i8* [[VEC_SRC]],
+
+// original s_arr[]=private_s_arr[];
+// CHECK: [[S_ARR_BEGIN:%.+]] = getelementptr inbounds [2 x [[S_FLOAT_TY]]], [2 x [[S_FLOAT_TY]]]* [[S_ARR_REF]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+// CHECK: [[S_ARR_PRIV_BEGIN:%.+]] = bitcast [2 x [[S_FLOAT_TY]]]* [[S_ARR_PRIV]] to [[S_FLOAT_TY]]*
+// CHECK: [[S_ARR_END:%.+]] = getelementptr [[S_FLOAT_TY]], [[S_FLOAT_TY]]* [[S_ARR_BEGIN]], i{{[0-9]+}} 2
+// CHECK: [[IS_EMPTY:%.+]] = icmp eq [[S_FLOAT_TY]]* [[S_ARR_BEGIN]], [[S_ARR_END]]
+// CHECK: br i1 [[IS_EMPTY]], label %[[S_ARR_BODY_DONE:.+]], label %[[S_ARR_BODY:.+]]
+// CHECK: [[S_ARR_BODY]]
+// CHECK: call {{.*}} [[S_FLOAT_TY_COPY_ASSIGN:@.+]]([[S_FLOAT_TY]]* {{.+}}, [[S_FLOAT_TY]]* {{.+}})
+// CHECK: br i1 {{.+}}, label %[[S_ARR_BODY_DONE]], label %[[S_ARR_BODY]]
+// CHECK: [[S_ARR_BODY_DONE]]
+
+// original var=private_var;
+// CHECK: call {{.*}} [[S_FLOAT_TY_COPY_ASSIGN:@.+]]([[S_FLOAT_TY]]* [[VAR_REF]], [[S_FLOAT_TY]]* {{.*}} [[VAR_PRIV]])
+// CHECK: br label %[[LAST_DONE]]
+// CHECK: [[LAST_DONE]]
+// CHECK-DAG: call void [[S_FLOAT_TY_DESTR]]([[S_FLOAT_TY]]* [[VAR_PRIV]])
+// CHECK-DAG: call void [[S_FLOAT_TY_DESTR]]([[S_FLOAT_TY]]*
+// CHECK: [[GTID_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[GTID_ADDR_REF]]
+// CHECK: [[GTID:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[GTID_REF]]
+// CHECK: call i32 @__kmpc_cancel_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]], i{{[0-9]+}} [[GTID]])
+// CHECK: ret void
+
+//
+// CHECK: define internal void [[MAIN_MICROTASK1]](i{{[0-9]+}}* [[GTID_ADDR:%.+]], i{{[0-9]+}}* %{{.+}}, %{{.+}}* %{{.+}})
+// CHECK: [[X_PRIV:%.+]] = alloca double,
+// CHECK-NOT: alloca double
+
+// Check for default initialization.
+// CHECK-NOT: [[X_PRIV]]
+
+// CHECK: call {{.+}} @__kmpc_for_static_init_4(%{{.+}}* @{{.+}}, i32 %{{.+}}, i32 34, i32* [[IS_LAST_ADDR:%.+]], i32* %{{.+}}, i32* %{{.+}}, i32* %{{.+}}, i32 1, i32 1)
+// <Skip loop body>
+// CHECK: call void @__kmpc_for_static_fini(%{{.+}}* @{{.+}}, i32 %{{.+}})
+
+// Check for final copying of private values back to original vars.
+// CHECK: [[IS_LAST_VAL:%.+]] = load i32, i32* [[IS_LAST_ADDR]],
+// CHECK: [[IS_LAST_ITER:%.+]] = icmp ne i32 [[IS_LAST_VAL]], 0
+// CHECK: br i1 [[IS_LAST_ITER:%.+]], label %[[LAST_THEN:.+]], label %[[LAST_DONE:.+]]
+// CHECK: [[LAST_THEN]]
+// Actual copying.
+
+// original x=private_x;
+// CHECK: [[X_VAL:%.+]] = load double, double* [[X_PRIV]],
+// CHECK: store double [[X_VAL]], double* [[X]],
+// CHECK-NEXT: br label %[[LAST_DONE]]
+// CHECK: [[LAST_DONE]]
+
+// CHECK: [[GTID_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[GTID_ADDR_REF]]
+// CHECK: [[GTID:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[GTID_REF]]
+// CHECK: call i32 @__kmpc_cancel_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]], i{{[0-9]+}} [[GTID]])
+// CHECK: ret void
+
+// CHECK: define {{.*}} i{{[0-9]+}} [[TMAIN_INT]]()
+// CHECK: [[TEST:%.+]] = alloca [[S_INT_TY]],
+// CHECK: call {{.*}} [[S_INT_TY_DEF_CONSTR:@.+]]([[S_INT_TY]]* [[TEST]])
+// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [[CAP_TMAIN_TY]]*)* [[TMAIN_MICROTASK:@.+]] to void
+// CHECK: call void [[S_INT_TY_DESTR:@.+]]([[S_INT_TY]]*
+// CHECK: ret
+//
+// CHECK: define internal void [[TMAIN_MICROTASK]](i{{[0-9]+}}* [[GTID_ADDR:%.+]], i{{[0-9]+}}* %{{.+}}, [[CAP_TMAIN_TY]]* %{{.+}})
+// CHECK: alloca i{{[0-9]+}},
+// CHECK: alloca i{{[0-9]+}},
+// CHECK: alloca i{{[0-9]+}},
+// CHECK: alloca i{{[0-9]+}},
+// CHECK: alloca i{{[0-9]+}},
+// CHECK: [[T_VAR_PRIV:%.+]] = alloca i{{[0-9]+}},
+// CHECK: [[VEC_PRIV:%.+]] = alloca [2 x i{{[0-9]+}}],
+// CHECK: [[S_ARR_PRIV:%.+]] = alloca [2 x [[S_INT_TY]]],
+// CHECK: [[VAR_PRIV:%.+]] = alloca [[S_INT_TY]],
+// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_REF:%.+]]
+
+// Check for default initialization.
+// CHECK: [[T_VAR_PTR_REF:%.+]] = getelementptr inbounds [[CAP_TMAIN_TY]], [[CAP_TMAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 0
+// CHECK: [[T_VAR_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[T_VAR_PTR_REF]],
+// CHECK-NOT: [[T_VAR_PRIV]]
+// CHECK: [[VEC_PTR_REF:%.+]] = getelementptr inbounds [[CAP_TMAIN_TY]], [[CAP_TMAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 1
+// CHECK: [[VEC_REF:%.+]] = load [2 x i{{[0-9]+}}]*, [2 x i{{[0-9]+}}]** [[VEC_PTR_REF:%.+]],
+// CHECK-NOT: [[VEC_PRIV]]
+// CHECK: [[S_ARR_REF_PTR:%.+]] = getelementptr inbounds [[CAP_TMAIN_TY]], [[CAP_TMAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 2
+// CHECK: [[S_ARR_REF:%.+]] = load [2 x [[S_INT_TY]]]*, [2 x [[S_INT_TY]]]** [[S_ARR_REF_PTR]],
+// CHECK: [[S_ARR_PRIV_ITEM:%.+]] = phi [[S_INT_TY]]*
+// CHECK: call {{.*}} [[S_INT_TY_DEF_CONSTR]]([[S_INT_TY]]* [[S_ARR_PRIV_ITEM]])
+// CHECK: [[VAR_REF_PTR:%.+]] = getelementptr inbounds [[CAP_TMAIN_TY]], [[CAP_TMAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 3
+// CHECK: [[VAR_REF:%.+]] = load [[S_INT_TY]]*, [[S_INT_TY]]** [[VAR_REF_PTR]],
+// CHECK: call {{.*}} [[S_INT_TY_DEF_CONSTR]]([[S_INT_TY]]* [[VAR_PRIV]])
+// CHECK: call {{.+}} @__kmpc_for_static_init_4(%{{.+}}* @{{.+}}, i32 %{{.+}}, i32 34, i32* [[IS_LAST_ADDR:%.+]], i32* %{{.+}}, i32* %{{.+}}, i32* %{{.+}}, i32 1, i32 1)
+// <Skip loop body>
+// CHECK: call void @__kmpc_for_static_fini(%{{.+}}* @{{.+}}, i32 %{{.+}})
+
+// Check for final copying of private values back to original vars.
+// CHECK: [[IS_LAST_VAL:%.+]] = load i32, i32* [[IS_LAST_ADDR]],
+// CHECK: [[IS_LAST_ITER:%.+]] = icmp ne i32 [[IS_LAST_VAL]], 0
+// CHECK: br i1 [[IS_LAST_ITER:%.+]], label %[[LAST_THEN:.+]], label %[[LAST_DONE:.+]]
+// CHECK: [[LAST_THEN]]
+// Actual copying.
+
+// original t_var=private_t_var;
+// CHECK: [[T_VAR_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[T_VAR_PRIV]],
+// CHECK: store i{{[0-9]+}} [[T_VAR_VAL]], i{{[0-9]+}}* [[T_VAR_REF]],
+
+// original vec[]=private_vec[];
+// CHECK: [[VEC_DEST:%.+]] = bitcast [2 x i{{[0-9]+}}]* [[VEC_REF]] to i8*
+// CHECK: [[VEC_SRC:%.+]] = bitcast [2 x i{{[0-9]+}}]* [[VEC_PRIV]] to i8*
+// CHECK: call void @llvm.memcpy.{{.+}}(i8* [[VEC_DEST]], i8* [[VEC_SRC]],
+
+// original s_arr[]=private_s_arr[];
+// CHECK: [[S_ARR_BEGIN:%.+]] = getelementptr inbounds [2 x [[S_INT_TY]]], [2 x [[S_INT_TY]]]* [[S_ARR_REF]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+// CHECK: [[S_ARR_PRIV_BEGIN:%.+]] = bitcast [2 x [[S_INT_TY]]]* [[S_ARR_PRIV]] to [[S_INT_TY]]*
+// CHECK: [[S_ARR_END:%.+]] = getelementptr [[S_INT_TY]], [[S_INT_TY]]* [[S_ARR_BEGIN]], i{{[0-9]+}} 2
+// CHECK: [[IS_EMPTY:%.+]] = icmp eq [[S_INT_TY]]* [[S_ARR_BEGIN]], [[S_ARR_END]]
+// CHECK: br i1 [[IS_EMPTY]], label %[[S_ARR_BODY_DONE:.+]], label %[[S_ARR_BODY:.+]]
+// CHECK: [[S_ARR_BODY]]
+// CHECK: call {{.*}} [[S_INT_TY_COPY_ASSIGN:@.+]]([[S_INT_TY]]* {{.+}}, [[S_INT_TY]]* {{.+}})
+// CHECK: br i1 {{.+}}, label %[[S_ARR_BODY_DONE]], label %[[S_ARR_BODY]]
+// CHECK: [[S_ARR_BODY_DONE]]
+
+// original var=private_var;
+// CHECK: call {{.*}} [[S_INT_TY_COPY_ASSIGN:@.+]]([[S_INT_TY]]* [[VAR_REF]], [[S_INT_TY]]* {{.*}} [[VAR_PRIV]])
+// CHECK: br label %[[LAST_DONE]]
+// CHECK: [[LAST_DONE]]
+// CHECK-DAG: call void [[S_INT_TY_DESTR]]([[S_INT_TY]]* [[VAR_PRIV]])
+// CHECK-DAG: call void [[S_INT_TY_DESTR]]([[S_INT_TY]]*
+// CHECK: [[GTID_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[GTID_ADDR_REF]]
+// CHECK: [[GTID:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[GTID_REF]]
+// CHECK: call i32 @__kmpc_cancel_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]], i{{[0-9]+}} [[GTID]])
+// CHECK: ret void
+#endif
+
diff --git a/test/OpenMP/for_lastprivate_messages.cpp b/test/OpenMP/for_lastprivate_messages.cpp
index a3a1c4b..632ed84 100644
--- a/test/OpenMP/for_lastprivate_messages.cpp
+++ b/test/OpenMP/for_lastprivate_messages.cpp
@@ -15,15 +15,17 @@
public:
S2() : a(0) {}
S2(S2 &s2) : a(s2.a) {}
+ const S2 &operator =(const S2&) const;
+ S2 &operator =(const S2&);
static float S2s; // expected-note {{static data member is predetermined as shared}}
static const float S2sc;
};
const float S2::S2sc = 0; // expected-note {{static data member is predetermined as shared}}
const S2 b;
const S2 ba[5];
-class S3 { // expected-note 2 {{'S3' declared here}}
+class S3 {
int a;
- S3 &operator=(const S3 &s3);
+ S3 &operator=(const S3 &s3); // expected-note 2 {{implicitly declared private here}}
public:
S3() : a(0) {}
@@ -32,17 +34,17 @@
const S3 c; // expected-note {{global variable is predetermined as shared}}
const S3 ca[5]; // expected-note {{global variable is predetermined as shared}}
extern const int f; // expected-note {{global variable is predetermined as shared}}
-class S4 { // expected-note 3 {{'S4' declared here}}
+class S4 {
int a;
- S4();
+ S4(); // expected-note 3 {{implicitly declared private here}}
S4(const S4 &s4);
public:
S4(int v) : a(v) {}
};
-class S5 { // expected-note {{'S5' declared here}}
+class S5 {
int a;
- S5() : a(0) {}
+ S5() : a(0) {} // expected-note {{implicitly declared private here}}
public:
S5(const S5 &s5) : a(s5.a) {}
@@ -62,8 +64,8 @@
template <class I, class C>
int foomain(int argc, char **argv) {
- I e(4); // expected-note {{'e' defined here}}
- I g(5); // expected-note {{'g' defined here}}
+ I e(4);
+ I g(5);
int i;
int &j = i; // expected-note {{'j' defined here}}
#pragma omp parallel
@@ -107,7 +109,7 @@
for (int k = 0; k < argc; ++k)
++k;
#pragma omp parallel
-#pragma omp for lastprivate(e, g) // expected-error 2 {{lastprivate variable must have an accessible, unambiguous default constructor}}
+#pragma omp for lastprivate(e, g) // expected-error 2 {{calling a private constructor of class 'S4'}}
for (int k = 0; k < argc; ++k)
++k;
#pragma omp parallel
@@ -140,12 +142,20 @@
return 0;
}
+namespace A {
+double x;
+#pragma omp threadprivate(x) // expected-note {{defined as threadprivate or thread local}}
+}
+namespace B {
+using A::x;
+}
+
int main(int argc, char **argv) {
const int d = 5; // expected-note {{constant variable is predetermined as shared}}
const int da[5] = {0}; // expected-note {{constant variable is predetermined as shared}}
- S4 e(4); // expected-note {{'e' defined here}}
- S5 g(5); // expected-note {{'g' defined here}}
- S3 m; // expected-note 2 {{'m' defined here}}
+ S4 e(4);
+ S5 g(5);
+ S3 m;
S6 n(2);
int i;
int &j = i; // expected-note {{'j' defined here}}
@@ -223,11 +233,11 @@
for (i = 0; i < argc; ++i)
foo();
#pragma omp parallel
-#pragma omp for lastprivate(e, g) // expected-error 2 {{lastprivate variable must have an accessible, unambiguous default constructor}}
+#pragma omp for lastprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
for (i = 0; i < argc; ++i)
foo();
#pragma omp parallel
-#pragma omp for lastprivate(m) // expected-error {{lastprivate variable must have an accessible, unambiguous copy assignment operator}}
+#pragma omp for lastprivate(m) // expected-error {{'operator=' is a private member of 'S3'}}
for (i = 0; i < argc; ++i)
foo();
#pragma omp parallel
@@ -235,6 +245,10 @@
for (i = 0; i < argc; ++i)
foo();
#pragma omp parallel
+#pragma omp for lastprivate(B::x) // expected-error {{threadprivate or thread local variable cannot be lastprivate}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
#pragma omp for private(xa), lastprivate(xa) // expected-error {{private variable cannot be lastprivate}} expected-note {{defined as private}}
for (i = 0; i < argc; ++i)
foo();
@@ -255,7 +269,7 @@
for (i = 0; i < argc; ++i)
foo();
#pragma omp parallel
-#pragma omp for firstprivate(m) lastprivate(m) // expected-error {{lastprivate variable must have an accessible, unambiguous copy assignment operator}}
+#pragma omp for firstprivate(m) lastprivate(m) // expected-error {{'operator=' is a private member of 'S3'}}
for (i = 0; i < argc; ++i)
foo();
#pragma omp parallel
diff --git a/test/OpenMP/for_private_messages.cpp b/test/OpenMP/for_private_messages.cpp
index 45c8683..635a17d 100644
--- a/test/OpenMP/for_private_messages.cpp
+++ b/test/OpenMP/for_private_messages.cpp
@@ -108,6 +108,14 @@
return 0;
}
+namespace A {
+double x;
+#pragma omp threadprivate(x) // expected-note {{defined as threadprivate or thread local}}
+}
+namespace B {
+using A::x;
+}
+
int main(int argc, char **argv) {
S4 e(4);
S5 g(5);
@@ -149,6 +157,9 @@
#pragma omp for private(h) // expected-error {{threadprivate or thread local variable cannot be private}}
for (int k = 0; k < argc; ++k)
++k;
+#pragma omp for private(B::x) // expected-error {{threadprivate or thread local variable cannot be private}}
+ for (int k = 0; k < argc; ++k)
+ ++k;
#pragma omp for shared(i) // expected-error {{unexpected OpenMP clause 'shared' in directive '#pragma omp for'}}
for (int k = 0; k < argc; ++k)
++k;
diff --git a/test/OpenMP/for_reduction_messages.cpp b/test/OpenMP/for_reduction_messages.cpp
index 62fee52..5ebb7b7 100644
--- a/test/OpenMP/for_reduction_messages.cpp
+++ b/test/OpenMP/for_reduction_messages.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -ferror-limit 100 -o - %s
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -ferror-limit 150 -o - %s
void foo() {
}
@@ -11,7 +11,7 @@
extern S1 a;
class S2 {
mutable int a;
- S2 &operator+=(const S2 &arg) { return (*this); }
+ S2 &operator+(const S2 &arg) { return (*this); } // expected-note 4 {{implicitly declared private here}}
public:
S2() : a(0) {}
@@ -28,17 +28,17 @@
public:
S3() : a(0) {}
S3(const S3 &s3) : a(s3.a) {}
- S3 operator+=(const S3 &arg1) { return arg1; }
+ S3 operator+(const S3 &arg1) { return arg1; }
};
-int operator+=(const S3 &arg1, const S3 &arg2) { return 5; }
+int operator+(const S3 &arg1, const S3 &arg2) { return 5; }
S3 c; // expected-note 2 {{'c' defined here}}
const S3 ca[5]; // expected-note 2 {{'ca' defined here}}
extern const int f; // expected-note 4 {{'f' declared here}}
-class S4 { // expected-note {{'S4' declared here}}
+class S4 {
int a;
- S4();
+ S4(); // expected-note {{implicitly declared private here}}
S4(const S4 &s4);
- S4 &operator+=(const S4 &arg) { return (*this); }
+ S4 &operator+(const S4 &arg) { return (*this); }
public:
S4(int v) : a(v) {}
@@ -46,26 +46,26 @@
S4 &operator&=(S4 &arg1, S4 &arg2) { return arg1; }
class S5 {
int a;
- S5() : a(0) {}
+ S5() : a(0) {} // expected-note {{implicitly declared private here}}
S5(const S5 &s5) : a(s5.a) {}
- S5 &operator+=(const S5 &arg);
+ S5 &operator+(const S5 &arg);
public:
S5(int v) : a(v) {}
};
-class S6 {
+class S6 { // expected-note 2 {{candidate function (the implicit copy assignment operator) not viable: no known conversion from 'int' to 'const S6' for 1st argument}}
int a;
public:
S6() : a(6) {}
operator int() { return 6; }
-} o; // expected-note 2 {{'o' defined here}}
+} o;
S3 h, k;
#pragma omp threadprivate(h) // expected-note 2 {{defined as threadprivate or thread local}}
template <class T> // expected-note {{declared here}}
-T tmain(T argc) { // expected-note 2 {{'argc' defined here}}
+T tmain(T argc) {
const T d = T(); // expected-note 4 {{'d' defined here}}
const T da[5] = {T()}; // expected-note 2 {{'da' defined here}}
T qa[5] = {T()};
@@ -74,7 +74,7 @@
S3 &p = k; // expected-note 2 {{'p' defined here}}
const T &r = da[(int)i]; // expected-note 2 {{'r' defined here}}
T &q = qa[(int)i]; // expected-note 2 {{'q' defined here}}
- T fl; // expected-note {{'fl' defined here}}
+ T fl;
#pragma omp parallel
#pragma omp for reduction // expected-error {{expected '(' after 'reduction'}}
for (int i = 0; i < 10; ++i)
@@ -104,11 +104,11 @@
for (int i = 0; i < 10; ++i)
foo();
#pragma omp parallel
-#pragma omp for reduction(& : argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{variable of type 'float' is not valid for specified reduction operation}}
+#pragma omp for reduction(& : argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{invalid operands to binary expression ('float' and 'float')}}
for (int i = 0; i < 10; ++i)
foo();
#pragma omp parallel
-#pragma omp for reduction(| : argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{variable of type 'float' is not valid for specified reduction operation}}
+#pragma omp for reduction(| : argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{invalid operands to binary expression ('float' and 'float')}}
for (int i = 0; i < 10; ++i)
foo();
#pragma omp parallel
@@ -128,7 +128,7 @@
for (int i = 0; i < 10; ++i)
foo();
#pragma omp parallel
-#pragma omp for reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 3 {{const-qualified variable cannot be reduction}}
+#pragma omp for reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 3 {{const-qualified variable cannot be reduction}} expected-error 3 {{'operator+' is a private member of 'S2'}}
for (int i = 0; i < 10; ++i)
foo();
#pragma omp parallel
@@ -152,7 +152,7 @@
for (int i = 0; i < 10; ++i)
foo();
#pragma omp parallel
-#pragma omp for reduction(^ : fl) // expected-error {{variable of type 'float' is not valid for specified reduction operation}}
+#pragma omp for reduction(^ : fl) // expected-error {{invalid operands to binary expression ('float' and 'float')}}
for (int i = 0; i < 10; ++i)
foo();
#pragma omp parallel
@@ -168,7 +168,7 @@
for (int i = 0; i < 10; ++i)
foo();
#pragma omp parallel
-#pragma omp for reduction(+ : o) // expected-error {{variable of type 'class S6' is not valid for specified reduction operation}}
+#pragma omp for reduction(+ : o) // expected-error {{no viable overloaded '='}}
for (int i = 0; i < 10; ++i)
foo();
#pragma omp parallel
@@ -204,18 +204,26 @@
return T();
}
+namespace A {
+double x;
+#pragma omp threadprivate(x) // expected-note {{defined as threadprivate or thread local}}
+}
+namespace B {
+using A::x;
+}
+
int main(int argc, char **argv) {
const int d = 5; // expected-note 2 {{'d' defined here}}
const int da[5] = {0}; // expected-note {{'da' defined here}}
int qa[5] = {0};
- S4 e(4); // expected-note {{'e' defined here}}
- S5 g(5); // expected-note {{'g' defined here}}
+ S4 e(4);
+ S5 g(5);
int i;
int &j = i; // expected-note 2 {{'j' defined here}}
S3 &p = k; // expected-note 2 {{'p' defined here}}
const int &r = da[i]; // expected-note {{'r' defined here}}
int &q = qa[i]; // expected-note {{'q' defined here}}
- float fl; // expected-note {{'fl' defined here}}
+ float fl;
#pragma omp parallel
#pragma omp for reduction // expected-error {{expected '(' after 'reduction'}}
for (int i = 0; i < 10; ++i)
@@ -269,7 +277,7 @@
for (int i = 0; i < 10; ++i)
foo();
#pragma omp parallel
-#pragma omp for reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{const-qualified variable cannot be reduction}}
+#pragma omp for reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{const-qualified variable cannot be reduction}} expected-error {{'operator+' is a private member of 'S2'}}
for (int i = 0; i < 10; ++i)
foo();
#pragma omp parallel
@@ -293,7 +301,7 @@
for (int i = 0; i < 10; ++i)
foo();
#pragma omp parallel
-#pragma omp for reduction(^ : fl) // expected-error {{variable of type 'float' is not valid for specified reduction operation}}
+#pragma omp for reduction(^ : fl) // expected-error {{invalid operands to binary expression ('float' and 'float')}}
for (int i = 0; i < 10; ++i)
foo();
#pragma omp parallel
@@ -305,7 +313,7 @@
for (int i = 0; i < 10; ++i)
foo();
#pragma omp parallel
-#pragma omp for reduction(& : e, g) // expected-error {{reduction variable must have an accessible, unambiguous default constructor}} expected-error {{variable of type 'S5' is not valid for specified reduction operation}}
+#pragma omp for reduction(& : e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}} expected-error {{invalid operands to binary expression ('S4' and 'S4')}} expected-error {{invalid operands to binary expression ('S5' and 'S5')}}
for (int i = 0; i < 10; ++i)
foo();
#pragma omp parallel
@@ -313,7 +321,11 @@
for (int i = 0; i < 10; ++i)
foo();
#pragma omp parallel
-#pragma omp for reduction(+ : o) // expected-error {{variable of type 'class S6' is not valid for specified reduction operation}}
+#pragma omp for reduction(+ : B::x, k) // expected-error {{threadprivate or thread local variable cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for reduction(+ : o) // expected-error {{no viable overloaded '='}}
for (int i = 0; i < 10; ++i)
foo();
#pragma omp parallel
diff --git a/test/OpenMP/for_simd_firstprivate_messages.cpp b/test/OpenMP/for_simd_firstprivate_messages.cpp
index 1345bfc..194656b 100644
--- a/test/OpenMP/for_simd_firstprivate_messages.cpp
+++ b/test/OpenMP/for_simd_firstprivate_messages.cpp
@@ -152,6 +152,14 @@
return 0;
}
+namespace A {
+double x;
+#pragma omp threadprivate(x) // expected-note {{defined as threadprivate or thread local}}
+}
+namespace B {
+using A::x;
+}
+
int main(int argc, char **argv) {
const int d = 5;
const int da[5] = {0};
@@ -247,6 +255,10 @@
for (i = 0; i < argc; ++i)
foo();
#pragma omp parallel
+#pragma omp for simd firstprivate(B::x) // expected-error {{threadprivate or thread local variable cannot be firstprivate}}
+ for (i = 0; i < argc; ++i)
+ foo();
+#pragma omp parallel
#pragma omp for simd private(xa), firstprivate(xa) // expected-error {{private variable cannot be firstprivate}} expected-note {{defined as private}}
for (i = 0; i < argc; ++i)
foo();
diff --git a/test/OpenMP/for_simd_lastprivate_messages.cpp b/test/OpenMP/for_simd_lastprivate_messages.cpp
index 38651e5..8eff052 100644
--- a/test/OpenMP/for_simd_lastprivate_messages.cpp
+++ b/test/OpenMP/for_simd_lastprivate_messages.cpp
@@ -15,15 +15,17 @@
public:
S2() : a(0) {}
S2(S2 &s2) : a(s2.a) {}
+ S2 &operator =(const S2&);
+ const S2 &operator =(const S2&) const;
static float S2s; // expected-note {{static data member is predetermined as shared}}
static const float S2sc;
};
const float S2::S2sc = 0; // expected-note {{static data member is predetermined as shared}}
const S2 b;
const S2 ba[5];
-class S3 { // expected-note 2 {{'S3' declared here}}
+class S3 {
int a;
- S3 &operator=(const S3 &s3);
+ S3 &operator=(const S3 &s3); // expected-note 2 {{implicitly declared private here}}
public:
S3() : a(0) {}
@@ -32,17 +34,17 @@
const S3 c; // expected-note {{global variable is predetermined as shared}}
const S3 ca[5]; // expected-note {{global variable is predetermined as shared}}
extern const int f; // expected-note {{global variable is predetermined as shared}}
-class S4 { // expected-note 3 {{'S4' declared here}}
+class S4 {
int a;
- S4();
+ S4(); // expected-note 3 {{implicitly declared private here}}
S4(const S4 &s4);
public:
S4(int v) : a(v) {}
};
-class S5 { // expected-note {{'S5' declared here}}
+class S5 {
int a;
- S5() : a(0) {}
+ S5() : a(0) {} // expected-note {{implicitly declared private here}}
public:
S5(const S5 &s5) : a(s5.a) {}
@@ -62,8 +64,8 @@
template <class I, class C>
int foomain(int argc, char **argv) {
- I e(4); // expected-note {{'e' defined here}}
- I g(5); // expected-note {{'g' defined here}}
+ I e(4);
+ I g(5);
int i;
int &j = i; // expected-note {{'j' defined here}}
#pragma omp parallel
@@ -107,7 +109,7 @@
for (int k = 0; k < argc; ++k)
++k;
#pragma omp parallel
-#pragma omp for simd lastprivate(e, g) // expected-error 2 {{lastprivate variable must have an accessible, unambiguous default constructor}}
+#pragma omp for simd lastprivate(e, g) // expected-error 2 {{calling a private constructor of class 'S4'}}
for (int k = 0; k < argc; ++k)
++k;
#pragma omp parallel
@@ -140,12 +142,20 @@
return 0;
}
+namespace A {
+double x;
+#pragma omp threadprivate(x) // expected-note {{defined as threadprivate or thread local}}
+}
+namespace B {
+using A::x;
+}
+
int main(int argc, char **argv) {
const int d = 5; // expected-note {{constant variable is predetermined as shared}}
const int da[5] = {0}; // expected-note {{constant variable is predetermined as shared}}
- S4 e(4); // expected-note {{'e' defined here}}
- S5 g(5); // expected-note {{'g' defined here}}
- S3 m; // expected-note 2 {{'m' defined here}}
+ S4 e(4);
+ S5 g(5);
+ S3 m;
S6 n(2);
int i;
int &j = i; // expected-note {{'j' defined here}}
@@ -223,15 +233,15 @@
for (i = 0; i < argc; ++i)
foo();
#pragma omp parallel
-#pragma omp for simd lastprivate(e, g) // expected-error 2 {{lastprivate variable must have an accessible, unambiguous default constructor}}
+#pragma omp for simd lastprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
for (i = 0; i < argc; ++i)
foo();
#pragma omp parallel
-#pragma omp for simd lastprivate(m) // expected-error {{lastprivate variable must have an accessible, unambiguous copy assignment operator}}
+#pragma omp for simd lastprivate(m) // expected-error {{'operator=' is a private member of 'S3'}}
for (i = 0; i < argc; ++i)
foo();
#pragma omp parallel
-#pragma omp for simd lastprivate(h) // expected-error {{threadprivate or thread local variable cannot be lastprivate}}
+#pragma omp for simd lastprivate(h, B::x) // expected-error 2 {{threadprivate or thread local variable cannot be lastprivate}}
for (i = 0; i < argc; ++i)
foo();
#pragma omp parallel
@@ -255,7 +265,7 @@
for (i = 0; i < argc; ++i)
foo();
#pragma omp parallel
-#pragma omp for simd firstprivate(m) lastprivate(m) // expected-error {{lastprivate variable must have an accessible, unambiguous copy assignment operator}}
+#pragma omp for simd firstprivate(m) lastprivate(m) // expected-error {{'operator=' is a private member of 'S3'}}
for (i = 0; i < argc; ++i)
foo();
#pragma omp parallel
diff --git a/test/OpenMP/for_simd_linear_messages.cpp b/test/OpenMP/for_simd_linear_messages.cpp
index 9a935c3..705c9f5 100644
--- a/test/OpenMP/for_simd_linear_messages.cpp
+++ b/test/OpenMP/for_simd_linear_messages.cpp
@@ -148,6 +148,14 @@
return 0;
}
+namespace A {
+double x;
+#pragma omp threadprivate(x) // expected-note {{defined as threadprivate or thread local}}
+}
+namespace C {
+using A::x;
+}
+
int main(int argc, char **argv) {
double darr[100];
// expected-note@+1 {{in instantiation of function template specialization 'test_template<-4, double, int>' requested here}}
@@ -185,7 +193,7 @@
// expected-error@+1 {{argument of a linear clause should be of integral or pointer type, not 'S5'}}
#pragma omp for simd linear(e, g)
for (int k = 0; k < argc; ++k) ++k;
- #pragma omp for simd linear(h) // expected-error {{threadprivate or thread local variable cannot be linear}}
+ #pragma omp for simd linear(h, C::x) // expected-error 2 {{threadprivate or thread local variable cannot be linear}}
for (int k = 0; k < argc; ++k) ++k;
#pragma omp parallel
{
diff --git a/test/OpenMP/for_simd_private_messages.cpp b/test/OpenMP/for_simd_private_messages.cpp
index 016a5ec..3f7cb26 100644
--- a/test/OpenMP/for_simd_private_messages.cpp
+++ b/test/OpenMP/for_simd_private_messages.cpp
@@ -108,6 +108,14 @@
return 0;
}
+namespace A {
+double x;
+#pragma omp threadprivate(x) // expected-note {{defined as threadprivate or thread local}}
+}
+namespace B {
+using A::x;
+}
+
int main(int argc, char **argv) {
S4 e(4);
S5 g(5);
@@ -146,7 +154,7 @@
#pragma omp for simd private(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
for (int k = 0; k < argc; ++k)
++k;
-#pragma omp for simd private(h) // expected-error {{threadprivate or thread local variable cannot be private}}
+#pragma omp for simd private(h, B::x) // expected-error 2 {{threadprivate or thread local variable cannot be private}}
for (int k = 0; k < argc; ++k)
++k;
#pragma omp for simd shared(i) // expected-error {{unexpected OpenMP clause 'shared' in directive '#pragma omp for simd'}}
diff --git a/test/OpenMP/for_simd_reduction_messages.cpp b/test/OpenMP/for_simd_reduction_messages.cpp
index 708973b..b4099d5 100644
--- a/test/OpenMP/for_simd_reduction_messages.cpp
+++ b/test/OpenMP/for_simd_reduction_messages.cpp
@@ -11,7 +11,7 @@
extern S1 a;
class S2 {
mutable int a;
- S2 &operator+=(const S2 &arg) { return (*this); }
+ S2 &operator+(const S2 &arg) { return (*this); } // expected-note 4 {{implicitly declared private here}}
public:
S2() : a(0) {}
@@ -28,17 +28,17 @@
public:
S3() : a(0) {}
S3(const S3 &s3) : a(s3.a) {}
- S3 operator+=(const S3 &arg1) { return arg1; }
+ S3 operator+(const S3 &arg1) { return arg1; }
};
-int operator+=(const S3 &arg1, const S3 &arg2) { return 5; }
+int operator+(const S3 &arg1, const S3 &arg2) { return 5; }
S3 c; // expected-note 2 {{'c' defined here}}
const S3 ca[5]; // expected-note 2 {{'ca' defined here}}
extern const int f; // expected-note 4 {{'f' declared here}}
-class S4 { // expected-note {{'S4' declared here}}
+class S4 {
int a;
- S4();
+ S4(); // expected-note {{implicitly declared private here}}
S4(const S4 &s4);
- S4 &operator+=(const S4 &arg) { return (*this); }
+ S4 &operator+(const S4 &arg) { return (*this); }
public:
S4(int v) : a(v) {}
@@ -46,26 +46,26 @@
S4 &operator&=(S4 &arg1, S4 &arg2) { return arg1; }
class S5 {
int a;
- S5() : a(0) {}
+ S5() : a(0) {} // expected-note {{implicitly declared private here}}
S5(const S5 &s5) : a(s5.a) {}
- S5 &operator+=(const S5 &arg);
+ S5 &operator+(const S5 &arg);
public:
S5(int v) : a(v) {}
};
-class S6 {
+class S6 { // expected-note 2 {{candidate function (the implicit copy assignment operator) not viable: no known conversion from 'int' to 'const S6' for 1st argument}}
int a;
public:
S6() : a(6) {}
operator int() { return 6; }
-} o; // expected-note 2 {{'o' defined here}}
+} o;
S3 h, k;
#pragma omp threadprivate(h) // expected-note 2 {{defined as threadprivate or thread local}}
template <class T> // expected-note {{declared here}}
-T tmain(T argc) { // expected-note 2 {{'argc' defined here}}
+T tmain(T argc) {
const T d = T(); // expected-note 4 {{'d' defined here}}
const T da[5] = {T()}; // expected-note 2 {{'da' defined here}}
T qa[5] = {T()};
@@ -74,7 +74,7 @@
S3 &p = k; // expected-note 2 {{'p' defined here}}
const T &r = da[(int)i]; // expected-note 2 {{'r' defined here}}
T &q = qa[(int)i]; // expected-note 2 {{'q' defined here}}
- T fl; // expected-note {{'fl' defined here}}
+ T fl;
#pragma omp parallel
#pragma omp for simd reduction // expected-error {{expected '(' after 'reduction'}}
for (int i = 0; i < 10; ++i)
@@ -104,11 +104,11 @@
for (int i = 0; i < 10; ++i)
foo();
#pragma omp parallel
-#pragma omp for simd reduction(& : argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{variable of type 'float' is not valid for specified reduction operation}}
+#pragma omp for simd reduction(& : argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{invalid operands to binary expression ('float' and 'float')}}
for (int i = 0; i < 10; ++i)
foo();
#pragma omp parallel
-#pragma omp for simd reduction(| : argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{variable of type 'float' is not valid for specified reduction operation}}
+#pragma omp for simd reduction(| : argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{invalid operands to binary expression ('float' and 'float')}}
for (int i = 0; i < 10; ++i)
foo();
#pragma omp parallel
@@ -128,7 +128,7 @@
for (int i = 0; i < 10; ++i)
foo();
#pragma omp parallel
-#pragma omp for simd reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 3 {{const-qualified variable cannot be reduction}}
+#pragma omp for simd reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 3 {{const-qualified variable cannot be reduction}} expected-error 3 {{'operator+' is a private member of 'S2'}}
for (int i = 0; i < 10; ++i)
foo();
#pragma omp parallel
@@ -152,7 +152,7 @@
for (int i = 0; i < 10; ++i)
foo();
#pragma omp parallel
-#pragma omp for simd reduction(^ : fl) // expected-error {{variable of type 'float' is not valid for specified reduction operation}}
+#pragma omp for simd reduction(^ : fl) // expected-error {{invalid operands to binary expression ('float' and 'float')}}
for (int i = 0; i < 10; ++i)
foo();
#pragma omp parallel
@@ -168,7 +168,7 @@
for (int i = 0; i < 10; ++i)
foo();
#pragma omp parallel
-#pragma omp for simd reduction(+ : o) // expected-error {{variable of type 'class S6' is not valid for specified reduction operation}}
+#pragma omp for simd reduction(+ : o) // expected-error {{no viable overloaded '='}}
for (int i = 0; i < 10; ++i)
foo();
#pragma omp parallel
@@ -204,18 +204,26 @@
return T();
}
+namespace A {
+double x;
+#pragma omp threadprivate(x) // expected-note {{defined as threadprivate or thread local}}
+}
+namespace B {
+using A::x;
+}
+
int main(int argc, char **argv) {
const int d = 5; // expected-note 2 {{'d' defined here}}
const int da[5] = {0}; // expected-note {{'da' defined here}}
int qa[5] = {0};
- S4 e(4); // expected-note {{'e' defined here}}
- S5 g(5); // expected-note {{'g' defined here}}
+ S4 e(4);
+ S5 g(5);
int i;
int &j = i; // expected-note 2 {{'j' defined here}}
S3 &p = k; // expected-note 2 {{'p' defined here}}
const int &r = da[i]; // expected-note {{'r' defined here}}
int &q = qa[i]; // expected-note {{'q' defined here}}
- float fl; // expected-note {{'fl' defined here}}
+ float fl;
#pragma omp parallel
#pragma omp for simd reduction // expected-error {{expected '(' after 'reduction'}}
for (int i = 0; i < 10; ++i)
@@ -269,7 +277,7 @@
for (int i = 0; i < 10; ++i)
foo();
#pragma omp parallel
-#pragma omp for simd reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{const-qualified variable cannot be reduction}}
+#pragma omp for simd reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{const-qualified variable cannot be reduction}} expected-error {{'operator+' is a private member of 'S2'}}
for (int i = 0; i < 10; ++i)
foo();
#pragma omp parallel
@@ -293,7 +301,7 @@
for (int i = 0; i < 10; ++i)
foo();
#pragma omp parallel
-#pragma omp for simd reduction(^ : fl) // expected-error {{variable of type 'float' is not valid for specified reduction operation}}
+#pragma omp for simd reduction(^ : fl) // expected-error {{invalid operands to binary expression ('float' and 'float')}}
for (int i = 0; i < 10; ++i)
foo();
#pragma omp parallel
@@ -305,15 +313,15 @@
for (int i = 0; i < 10; ++i)
foo();
#pragma omp parallel
-#pragma omp for simd reduction(& : e, g) // expected-error {{reduction variable must have an accessible, unambiguous default constructor}} expected-error {{variable of type 'S5' is not valid for specified reduction operation}}
+#pragma omp for simd reduction(& : e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{invalid operands to binary expression ('S4' and 'S4')}} expected-error {{calling a private constructor of class 'S5'}} expected-error {{invalid operands to binary expression ('S5' and 'S5')}}
for (int i = 0; i < 10; ++i)
foo();
#pragma omp parallel
-#pragma omp for simd reduction(+ : h, k) // expected-error {{threadprivate or thread local variable cannot be reduction}}
+#pragma omp for simd reduction(+ : h, k, B::x) // expected-error 2 {{threadprivate or thread local variable cannot be reduction}}
for (int i = 0; i < 10; ++i)
foo();
#pragma omp parallel
-#pragma omp for simd reduction(+ : o) // expected-error {{variable of type 'class S6' is not valid for specified reduction operation}}
+#pragma omp for simd reduction(+ : o) // expected-error {{no viable overloaded '='}}
for (int i = 0; i < 10; ++i)
foo();
#pragma omp parallel
diff --git a/test/OpenMP/master_codegen.cpp b/test/OpenMP/master_codegen.cpp
index 25438f1..8dfd53c 100644
--- a/test/OpenMP/master_codegen.cpp
+++ b/test/OpenMP/master_codegen.cpp
@@ -61,7 +61,7 @@
// TERM_DEBUG: unreachable
foo();
}
-// TERM_DEBUG-DAG: [[DBG_LOC_START]] = !MDLocation(line: 52,
-// TERM_DEBUG-DAG: [[DBG_LOC_END]] = !MDLocation(line: 52,
+// TERM_DEBUG-DAG: [[DBG_LOC_START]] = !MDLocation(line: [[@LINE-12]],
+// TERM_DEBUG-DAG: [[DBG_LOC_END]] = !MDLocation(line: [[@LINE-3]],
#endif
diff --git a/test/OpenMP/parallel_codegen.cpp b/test/OpenMP/parallel_codegen.cpp
index 73c4d41..88c7f7b 100644
--- a/test/OpenMP/parallel_codegen.cpp
+++ b/test/OpenMP/parallel_codegen.cpp
@@ -39,7 +39,7 @@
// CHECK: [[ARGC_REF:%.+]] = getelementptr inbounds %struct.anon, %struct.anon* [[AGG_CAPTURED]], i32 0, i32 0
// CHECK-NEXT: store i32* {{%[a-z0-9.]+}}, i32** [[ARGC_REF]]
// CHECK-NEXT: [[BITCAST:%.+]] = bitcast %struct.anon* [[AGG_CAPTURED]] to i8*
-// CHECK-NEXT: call void (%ident_t*, i32, void (i32*, i32*, ...)*, ...)* @__kmpc_fork_call(%ident_t* [[DEF_LOC_2]], i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, %struct.anon*)* @.omp_outlined. to void (i32*, i32*, ...)*), i8* [[BITCAST]])
+// CHECK-NEXT: call void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%ident_t* [[DEF_LOC_2]], i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, %struct.anon*)* [[OMP_OUTLINED:@.+]] to void (i32*, i32*, ...)*), i8* [[BITCAST]])
// CHECK-NEXT: [[ARGV:%.+]] = load i8**, i8*** {{%[a-z0-9.]+}}
// CHECK-NEXT: [[RET:%.+]] = call {{[a-z]*[ ]?i32}} [[TMAIN:@.+tmain.+]](i8** [[ARGV]])
// CHECK-NEXT: ret i32 [[RET]]
@@ -55,13 +55,13 @@
// CHECK-DEBUG-NEXT: [[KMPC_LOC_PSOURCE_REF:%.+]] = getelementptr inbounds %ident_t, %ident_t* [[LOC_2_ADDR]], i32 0, i32 4
// CHECK-DEBUG-NEXT: store i8* getelementptr inbounds ([{{.+}} x i8], [{{.+}} x i8]* [[LOC1]], i32 0, i32 0), i8** [[KMPC_LOC_PSOURCE_REF]]
// CHECK-DEBUG-NEXT: [[BITCAST:%.+]] = bitcast %struct.anon* [[AGG_CAPTURED]] to i8*
-// CHECK-DEBUG-NEXT: call void (%ident_t*, i32, void (i32*, i32*, ...)*, ...)* @__kmpc_fork_call(%ident_t* [[LOC_2_ADDR]], i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, %struct.anon*)* @.omp_outlined. to void (i32*, i32*, ...)*), i8* [[BITCAST]])
+// CHECK-DEBUG-NEXT: call void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%ident_t* [[LOC_2_ADDR]], i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, %struct.anon*)* [[OMP_OUTLINED:@.+]] to void (i32*, i32*, ...)*), i8* [[BITCAST]])
// CHECK-DEBUG-NEXT: [[ARGV:%.+]] = load i8**, i8*** {{%[a-z0-9.]+}}
// CHECK-DEBUG-NEXT: [[RET:%.+]] = call i32 [[TMAIN:@.+tmain.+]](i8** [[ARGV]])
// CHECK-DEBUG-NEXT: ret i32 [[RET]]
// CHECK-DEBUG-NEXT: }
-// CHECK-LABEL: define internal void @.omp_outlined.(i32* %.global_tid., i32* %.bound_tid., %struct.anon* %__context)
+// CHECK: define internal void [[OMP_OUTLINED]](i32* %.global_tid., i32* %.bound_tid., %struct.anon* %__context)
// CHECK: #[[FN_ATTRS:[0-9]+]]
// CHECK: [[CONTEXT_ADDR:%.+]] = alloca %struct.anon*
// CHECK: store %struct.anon* %__context, %struct.anon** [[CONTEXT_ADDR]]
@@ -70,11 +70,12 @@
// CHECK-NEXT: [[ARGC_REF:%.+]] = load i32*, i32** [[ARGC_PTR_REF]]
// CHECK-NEXT: [[ARGC:%.+]] = load i32, i32* [[ARGC_REF]]
// CHECK-NEXT: invoke void [[FOO:@.+foo.+]](i32{{[ ]?[a-z]*}} [[ARGC]])
+// CHECK: call {{.+}} @__kmpc_cancel_barrier(
// CHECK: ret void
// CHECK: call void @{{.+terminate.*|abort}}(
// CHECK-NEXT: unreachable
// CHECK-NEXT: }
-// CHECK-DEBUG-LABEL: define internal void @.omp_outlined.(i32* %.global_tid., i32* %.bound_tid., %struct.anon* %__context)
+// CHECK-DEBUG: define internal void [[OMP_OUTLINED]](i32* %.global_tid., i32* %.bound_tid., %struct.anon* %__context)
// CHECK-DEBUG: #[[FN_ATTRS:[0-9]+]]
// CHECK-DEBUG: [[CONTEXT_ADDR:%.+]] = alloca %struct.anon*
// CHECK-DEBUG: store %struct.anon* %__context, %struct.anon** [[CONTEXT_ADDR]]
@@ -83,6 +84,7 @@
// CHECK-DEBUG-NEXT: [[ARGC_REF:%.+]] = load i32*, i32** [[ARGC_PTR_REF]]
// CHECK-DEBUG-NEXT: [[ARGC:%.+]] = load i32, i32* [[ARGC_REF]]
// CHECK-DEBUG-NEXT: invoke void [[FOO:@.+foo.+]](i32 [[ARGC]])
+// CHECK-DEBUG: call {{.+}} @__kmpc_cancel_barrier(
// CHECK-DEBUG: ret void
// CHECK-DEBUG: call void @{{.+terminate.*|abort}}(
// CHECK-DEBUG-NEXT: unreachable
@@ -98,7 +100,7 @@
// CHECK: [[ARGC_REF:%.+]] = getelementptr inbounds %struct.anon.0, %struct.anon.0* [[AGG_CAPTURED]], i32 0, i32 0
// CHECK-NEXT: store i8*** {{%[a-z0-9.]+}}, i8**** [[ARGC_REF]]
// CHECK-NEXT: [[BITCAST:%.+]] = bitcast %struct.anon.0* [[AGG_CAPTURED]] to i8*
-// CHECK-NEXT: call void (%ident_t*, i32, void (i32*, i32*, ...)*, ...)* @__kmpc_fork_call(%ident_t* [[DEF_LOC_2]], i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, %struct.anon.0*)* @.omp_outlined.1 to void (i32*, i32*, ...)*), i8* [[BITCAST]])
+// CHECK-NEXT: call void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%ident_t* [[DEF_LOC_2]], i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, %struct.anon.0*)* [[OMP_OUTLINED:@.+]] to void (i32*, i32*, ...)*), i8* [[BITCAST]])
// CHECK-NEXT: ret i32 0
// CHECK-NEXT: }
// CHECK-DEBUG: define linkonce_odr i32 [[TMAIN]](i8** %argc)
@@ -112,11 +114,11 @@
// CHECK-DEBUG-NEXT: [[KMPC_LOC_PSOURCE_REF:%.+]] = getelementptr inbounds %ident_t, %ident_t* [[LOC_2_ADDR]], i32 0, i32 4
// CHECK-DEBUG-NEXT: store i8* getelementptr inbounds ([{{.+}} x i8], [{{.+}} x i8]* [[LOC2]], i32 0, i32 0), i8** [[KMPC_LOC_PSOURCE_REF]]
// CHECK-DEBUG-NEXT: [[BITCAST:%.+]] = bitcast %struct.anon.0* [[AGG_CAPTURED]] to i8*
-// CHECK-DEBUG-NEXT: call void (%ident_t*, i32, void (i32*, i32*, ...)*, ...)* @__kmpc_fork_call(%ident_t* [[LOC_2_ADDR]], i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, %struct.anon.0*)* @.omp_outlined.1 to void (i32*, i32*, ...)*), i8* [[BITCAST]])
+// CHECK-DEBUG-NEXT: call void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%ident_t* [[LOC_2_ADDR]], i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, %struct.anon.0*)* [[OMP_OUTLINED:@.+]] to void (i32*, i32*, ...)*), i8* [[BITCAST]])
// CHECK-DEBUG-NEXT: ret i32 0
// CHECK-DEBUG-NEXT: }
-// CHECK-LABEL: define internal void @.omp_outlined.1(i32* %.global_tid., i32* %.bound_tid., %struct.anon.0* %__context)
+// CHECK: define internal void [[OMP_OUTLINED]](i32* %.global_tid., i32* %.bound_tid., %struct.anon.0* %__context)
// CHECK: [[CONTEXT_ADDR:%.+]] = alloca %struct.anon.0*
// CHECK: store %struct.anon.0* %__context, %struct.anon.0** [[CONTEXT_ADDR]]
// CHECK: [[CONTEXT_PTR:%.+]] = load %struct.anon.0*, %struct.anon.0** [[CONTEXT_ADDR]]
@@ -124,11 +126,12 @@
// CHECK-NEXT: [[ARGC_REF:%.+]] = load i8***, i8**** [[ARGC_PTR_REF]]
// CHECK-NEXT: [[ARGC:%.+]] = load i8**, i8*** [[ARGC_REF]]
// CHECK-NEXT: invoke void [[FOO1:@.+foo.+]](i8** [[ARGC]])
+// CHECK: call {{.+}} @__kmpc_cancel_barrier(
// CHECK: ret void
// CHECK: call void @{{.+terminate.*|abort}}(
// CHECK-NEXT: unreachable
// CHECK-NEXT: }
-// CHECK-DEBUG-LABEL: define internal void @.omp_outlined.1(i32* %.global_tid., i32* %.bound_tid., %struct.anon.0* %__context)
+// CHECK-DEBUG: define internal void [[OMP_OUTLINED]](i32* %.global_tid., i32* %.bound_tid., %struct.anon.0* %__context)
// CHECK-DEBUG: [[CONTEXT_ADDR:%.+]] = alloca %struct.anon.0*
// CHECK-DEBUG: store %struct.anon.0* %__context, %struct.anon.0** [[CONTEXT_ADDR]]
// CHECK-DEBUG: [[CONTEXT_PTR:%.+]] = load %struct.anon.0*, %struct.anon.0** [[CONTEXT_ADDR]]
@@ -136,6 +139,7 @@
// CHECK-DEBUG-NEXT: [[ARGC_REF:%.+]] = load i8***, i8**** [[ARGC_PTR_REF]]
// CHECK-DEBUG-NEXT: [[ARGC:%.+]] = load i8**, i8*** [[ARGC_REF]]
// CHECK-DEBUG-NEXT: invoke void [[FOO1:@.+foo.+]](i8** [[ARGC]])
+// CHECK-DEBUG: call {{.+}} @__kmpc_cancel_barrier(
// CHECK-DEBUG: ret void
// CHECK-DEBUG: call void @{{.+terminate.*|abort}}(
// CHECK-DEBUG-NEXT: unreachable
diff --git a/test/OpenMP/parallel_copyin_codegen.cpp b/test/OpenMP/parallel_copyin_codegen.cpp
new file mode 100644
index 0000000..0bb4369
--- /dev/null
+++ b/test/OpenMP/parallel_copyin_codegen.cpp
@@ -0,0 +1,272 @@
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -x c++ -triple %itanium_abi_triple -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -std=c++11 -triple %itanium_abi_triple -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -triple %itanium_abi_triple -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -x c++ -std=c++11 -DLAMBDA -triple %itanium_abi_triple -emit-llvm %s -o - | FileCheck -check-prefix=LAMBDA %s
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -x c++ -fblocks -DBLOCKS -triple %itanium_abi_triple -emit-llvm %s -o - | FileCheck -check-prefix=BLOCKS %s
+// expected-no-diagnostics
+#ifndef HEADER
+#define HEADER
+
+volatile int g = 1212;
+#pragma omp threadprivate(g)
+
+template <class T>
+struct S {
+ T f;
+ S(T a) : f(a + g) {}
+ S() : f(g) {}
+ S &operator=(const S &) { return *this; };
+ operator T() { return T(); }
+ ~S() {}
+};
+
+// CHECK-DAG: [[S_FLOAT_TY:%.+]] = type { float }
+// CHECK-DAG: [[S_INT_TY:%.+]] = type { i{{[0-9]+}} }
+// CHECK-DAG: [[IMPLICIT_BARRIER_LOC:@.+]] = private unnamed_addr constant %{{.+}} { i32 0, i32 66, i32 0, i32 0, i8*
+
+
+// CHECK-DAG: [[T_VAR:@.+]] = internal global i{{[0-9]+}} 1122,
+// CHECK-DAG: [[VEC:@.+]] = internal global [2 x i{{[0-9]+}}] [i{{[0-9]+}} 1, i{{[0-9]+}} 2],
+// CHECK-DAG: [[S_ARR:@.+]] = internal global [2 x [[S_FLOAT_TY]]] zeroinitializer,
+// CHECK-DAG: [[VAR:@.+]] = internal global [[S_FLOAT_TY]] zeroinitializer,
+// CHECK-DAG: [[TMAIN_T_VAR:@.+]] = linkonce_odr global i{{[0-9]+}} 333,
+// CHECK-DAG: [[TMAIN_VEC:@.+]] = linkonce_odr global [2 x i{{[0-9]+}}] [i{{[0-9]+}} 3, i{{[0-9]+}} 3],
+// CHECK-DAG: [[TMAIN_S_ARR:@.+]] = linkonce_odr global [2 x [[S_INT_TY]]] zeroinitializer,
+// CHECK-DAG: [[TMAIN_VAR:@.+]] = linkonce_odr global [[S_INT_TY]] zeroinitializer,
+template <typename T>
+T tmain() {
+ S<T> test;
+ test = S<T>();
+ static T t_var = 333;
+ static T vec[] = {3, 3};
+ static S<T> s_arr[] = {1, 2};
+ static S<T> var(3);
+#pragma omp threadprivate(t_var, vec, s_arr, var)
+#pragma omp parallel copyin(t_var, vec, s_arr, var)
+ {
+ vec[0] = t_var;
+ s_arr[0] = var;
+ }
+#pragma omp parallel copyin(t_var)
+ {}
+ return T();
+}
+
+int main() {
+#ifdef LAMBDA
+ // LAMBDA: [[G:@.+]] = global i{{[0-9]+}} 1212,
+ // LAMBDA-LABEL: @main
+ // LAMBDA: call{{( x86_thiscallcc)?}} void [[OUTER_LAMBDA:@.+]](
+ [&]() {
+ // LAMBDA: define{{.*}} internal{{.*}} void [[OUTER_LAMBDA]](
+ // LAMBDA: call void {{.+}} @__kmpc_fork_call({{.+}}, i32 1, {{.+}}* [[OMP_REGION:@.+]] to {{.+}}, i8*
+#pragma omp parallel copyin(g)
+ {
+ // LAMBDA: define{{.*}} internal{{.*}} void [[OMP_REGION]](i32* %{{.+}}, i32* %{{.+}}, %{{.+}}* [[ARG:%.+]])
+
+ // threadprivate_g = g;
+ // LAMBDA: call i8* @__kmpc_threadprivate_cached({{.+}} [[G]]
+ // LAMBDA: ptrtoint i{{[0-9]+}}* %{{.+}} to i{{[0-9]+}}
+ // LAMBDA: icmp ne i{{[0-9]+}} ptrtoint (i{{[0-9]+}}* [[G]] to i{{[0-9]+}}), %{{.+}}
+ // LAMBDA: br i1 %{{.+}}, label %[[NOT_MASTER:.+]], label %[[DONE:.+]]
+ // LAMBDA: [[NOT_MASTER]]
+ // LAMBDA: load i{{[0-9]+}}, i{{[0-9]+}}* [[G]],
+ // LAMBDA: store volatile i{{[0-9]+}} %{{.+}}, i{{[0-9]+}}* %{{.+}},
+ // LAMBDA: [[DONE]]
+
+ // LAMBDA: call i32 @__kmpc_cancel_barrier(
+ g = 1;
+ // LAMBDA: call{{( x86_thiscallcc)?}} void [[INNER_LAMBDA:@.+]](%{{.+}}*
+ [&]() {
+ // LAMBDA: define {{.+}} void [[INNER_LAMBDA]](%{{.+}}* [[ARG_PTR:%.+]])
+ // LAMBDA: store %{{.+}}* [[ARG_PTR]], %{{.+}}** [[ARG_PTR_REF:%.+]],
+ g = 2;
+ // LAMBDA: [[ARG_PTR:%.+]] = load %{{.+}}*, %{{.+}}** [[ARG_PTR_REF]]
+ }();
+ }
+ }();
+ return 0;
+#elif defined(BLOCKS)
+ // BLOCKS: [[G:@.+]] = global i{{[0-9]+}} 1212,
+ // BLOCKS-LABEL: @main
+ // BLOCKS: call void {{%.+}}(i8
+ ^{
+ // BLOCKS: define{{.*}} internal{{.*}} void {{.+}}(i8*
+ // BLOCKS: call void {{.+}} @__kmpc_fork_call({{.+}}, i32 1, {{.+}}* [[OMP_REGION:@.+]] to {{.+}}, i8*
+#pragma omp parallel copyin(g)
+ {
+ // BLOCKS: define{{.*}} internal{{.*}} void [[OMP_REGION]](i32* %{{.+}}, i32* %{{.+}}, %{{.+}}* [[ARG:%.+]])
+
+ // threadprivate_g = g;
+ // BLOCKS: call i8* @__kmpc_threadprivate_cached({{.+}} [[G]]
+ // BLOCKS: ptrtoint i{{[0-9]+}}* %{{.+}} to i{{[0-9]+}}
+ // BLOCKS: icmp ne i{{[0-9]+}} ptrtoint (i{{[0-9]+}}* [[G]] to i{{[0-9]+}}), %{{.+}}
+ // BLOCKS: br i1 %{{.+}}, label %[[NOT_MASTER:.+]], label %[[DONE:.+]]
+ // BLOCKS: [[NOT_MASTER]]
+ // BLOCKS: load i{{[0-9]+}}, i{{[0-9]+}}* [[G]],
+ // BLOCKS: store volatile i{{[0-9]+}} %{{.+}}, i{{[0-9]+}}* %{{.+}},
+ // BLOCKS: [[DONE]]
+
+ // BLOCKS: call i32 @__kmpc_cancel_barrier(
+ g = 1;
+ // BLOCKS: store volatile i{{[0-9]+}} 1, i{{[0-9]+}}*
+ // BLOCKS-NOT: [[G]]{{[[^:word:]]}}
+ // BLOCKS: call void {{%.+}}(i8
+ ^{
+ // BLOCKS: define {{.+}} void {{@.+}}(i8*
+ g = 2;
+ // BLOCKS-NOT: [[G]]{{[[^:word:]]}}
+ // BLOCKS: call i8* @__kmpc_threadprivate_cached({{.+}} [[G]]
+ // BLOCKS: store volatile i{{[0-9]+}} 2, i{{[0-9]+}}*
+ // BLOCKS-NOT: [[G]]{{[[^:word:]]}}
+ // BLOCKS: ret
+ }();
+ }
+ }();
+ return 0;
+#else
+ S<float> test;
+ test = S<float>();
+ static int t_var = 1122;
+ static int vec[] = {1, 2};
+ static S<float> s_arr[] = {1, 2};
+ static S<float> var(3);
+#pragma omp threadprivate(t_var, vec, s_arr, var)
+#pragma omp parallel copyin(t_var, vec, s_arr, var)
+ {
+ vec[0] = t_var;
+ s_arr[0] = var;
+ }
+#pragma omp parallel copyin(t_var)
+ {}
+ return tmain<int>();
+#endif
+}
+
+// CHECK-LABEL: @main
+// CHECK: [[TEST:%.+]] = alloca [[S_FLOAT_TY]],
+// CHECK: call {{.*}} [[S_FLOAT_TY_COPY_ASSIGN:@.+]]([[S_FLOAT_TY]]* [[TEST]], [[S_FLOAT_TY]]*
+// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, {{%.+}}*)* [[MAIN_MICROTASK:@.+]] to void (i32*, i32*, ...)*), i8* %{{.+}})
+// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, {{%.+}}*)* [[MAIN_MICROTASK1:@.+]] to void (i32*, i32*, ...)*), i8* %{{.+}})
+// CHECK: = call {{.*}}i{{.+}} [[TMAIN_INT:@.+]]()
+// CHECK: call {{.*}} [[S_FLOAT_TY_DESTR:@.+]]([[S_FLOAT_TY]]*
+// CHECK: ret
+//
+// CHECK: define internal void [[MAIN_MICROTASK]](i{{[0-9]+}}* [[GTID_ADDR:%.+]], i{{[0-9]+}}* %{{.+}}, {{%.+}}* %{{.+}})
+// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]],
+// CHECK: [[GTID_ADDR:%.+]] = load i32*, i32** [[GTID_ADDR_ADDR]],
+// CHECK: [[GTID:%.+]] = load i32, i32* [[GTID_ADDR]],
+
+// threadprivate_t_var = t_var;
+// CHECK: call i8* @__kmpc_threadprivate_cached({{.+}} [[T_VAR]]
+// CHECK: ptrtoint i{{[0-9]+}}* %{{.+}} to i{{[0-9]+}}
+// CHECK: icmp ne i{{[0-9]+}} ptrtoint (i{{[0-9]+}}* [[T_VAR]] to i{{[0-9]+}}), %{{.+}}
+// CHECK: br i1 %{{.+}}, label %[[NOT_MASTER:.+]], label %[[DONE:.+]]
+// CHECK: [[NOT_MASTER]]
+// CHECK: load i{{[0-9]+}}, i{{[0-9]+}}* [[T_VAR]],
+// CHECK: store i{{[0-9]+}} %{{.+}}, i{{[0-9]+}}* %{{.+}},
+
+// threadprivate_vec = vec;
+// CHECK: call i8* @__kmpc_threadprivate_cached({{.+}} [[VEC]]
+// CHECK: call void @llvm.memcpy{{.*}}(i8* %{{.+}}, i8* bitcast ([2 x i{{[0-9]+}}]* [[VEC]] to i8*),
+
+// threadprivate_s_arr = s_arr;
+// CHECK: call i8* @__kmpc_threadprivate_cached({{.+}} [[S_ARR]]
+// CHECK: [[S_ARR_PRIV_BEGIN:%.+]] = getelementptr inbounds [2 x [[S_FLOAT_TY]]], [2 x [[S_FLOAT_TY]]]* {{%.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 0
+// CHECK: [[S_ARR_PRIV_END:%.+]] = getelementptr [[S_FLOAT_TY]], [[S_FLOAT_TY]]* [[S_ARR_PRIV_BEGIN]], i{{[0-9]+}} 2
+// CHECK: [[IS_EMPTY:%.+]] = icmp eq [[S_FLOAT_TY]]* [[S_ARR_PRIV_BEGIN]], [[S_ARR_PRIV_END]]
+// CHECK: br i1 [[IS_EMPTY]], label %[[S_ARR_BODY_DONE:.+]], label %[[S_ARR_BODY:.+]]
+// CHECK: [[S_ARR_BODY]]
+// CHECK: call {{.*}} [[S_FLOAT_TY_COPY_ASSIGN]]([[S_FLOAT_TY]]* {{.+}}, [[S_FLOAT_TY]]* {{.+}})
+// CHECK: br i1 {{.+}}, label %{{.+}}, label %[[S_ARR_BODY]]
+
+// threadprivate_var = var;
+// CHECK: call i8* @__kmpc_threadprivate_cached({{.+}} [[VAR]]
+// CHECK: call {{.*}} [[S_FLOAT_TY_COPY_ASSIGN]]([[S_FLOAT_TY]]* {{%.+}}, [[S_FLOAT_TY]]* {{.*}}[[VAR]])
+// CHECK: [[DONE]]
+
+// CHECK: call i32 @__kmpc_cancel_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]], i32 [[GTID]])
+// CHECK: ret void
+
+// CHECK: define internal void [[MAIN_MICROTASK1]](i{{[0-9]+}}* [[GTID_ADDR:%.+]], i{{[0-9]+}}* %{{.+}}, {{%.+}}* %{{.+}})
+// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]],
+// CHECK: [[GTID_ADDR:%.+]] = load i32*, i32** [[GTID_ADDR_ADDR]],
+// CHECK: [[GTID:%.+]] = load i32, i32* [[GTID_ADDR]],
+
+// threadprivate_t_var = t_var;
+// CHECK: call i8* @__kmpc_threadprivate_cached({{.+}} [[T_VAR]]
+// CHECK: ptrtoint i{{[0-9]+}}* %{{.+}} to i{{[0-9]+}}
+// CHECK: icmp ne i{{[0-9]+}} ptrtoint (i{{[0-9]+}}* [[T_VAR]] to i{{[0-9]+}}), %{{.+}}
+// CHECK: br i1 %{{.+}}, label %[[NOT_MASTER:.+]], label %[[DONE:.+]]
+// CHECK: [[NOT_MASTER]]
+// CHECK: load i{{[0-9]+}}, i{{[0-9]+}}* [[T_VAR]],
+// CHECK: store i{{[0-9]+}} %{{.+}}, i{{[0-9]+}}* %{{.+}},
+// CHECK: [[DONE]]
+
+// CHECK: call i32 @__kmpc_cancel_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]], i32 [[GTID]])
+// CHECK: ret void
+
+// CHECK: define {{.*}} i{{[0-9]+}} [[TMAIN_INT]]()
+// CHECK: [[TEST:%.+]] = alloca [[S_INT_TY]],
+// CHECK: call {{.*}} [[S_INT_TY_COPY_ASSIGN:@.+]]([[S_INT_TY]]* [[TEST]], [[S_INT_TY]]*
+// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, {{%.+}}*)* [[TMAIN_MICROTASK:@.+]] to void (i32*, i32*, ...)*), i8* %{{.+}})
+// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, {{%.+}}*)* [[TMAIN_MICROTASK1:@.+]] to void (i32*, i32*, ...)*), i8* %{{.+}})
+// CHECK: call {{.*}} [[S_INT_TY_DESTR:@.+]]([[S_INT_TY]]*
+// CHECK: ret
+//
+// CHECK: define internal void [[TMAIN_MICROTASK]](i{{[0-9]+}}* [[GTID_ADDR:%.+]], i{{[0-9]+}}* %{{.+}}, {{%.+}}* %{{.+}})
+// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]],
+// CHECK: [[GTID_ADDR:%.+]] = load i32*, i32** [[GTID_ADDR_ADDR]],
+// CHECK: [[GTID:%.+]] = load i32, i32* [[GTID_ADDR]],
+
+// threadprivate_t_var = t_var;
+// CHECK: call i8* @__kmpc_threadprivate_cached({{.+}} [[TMAIN_T_VAR]]
+// CHECK: ptrtoint i{{[0-9]+}}* %{{.+}} to i{{[0-9]+}}
+// CHECK: icmp ne i{{[0-9]+}} ptrtoint (i{{[0-9]+}}* [[TMAIN_T_VAR]] to i{{[0-9]+}}), %{{.+}}
+// CHECK: br i1 %{{.+}}, label %[[NOT_MASTER:.+]], label %[[DONE:.+]]
+// CHECK: [[NOT_MASTER]]
+// CHECK: load i{{[0-9]+}}, i{{[0-9]+}}* [[TMAIN_T_VAR]],
+// CHECK: store i{{[0-9]+}} %{{.+}}, i{{[0-9]+}}* %{{.+}},
+
+// threadprivate_vec = vec;
+// CHECK: call i8* @__kmpc_threadprivate_cached({{.+}} [[TMAIN_VEC]]
+// CHECK: call void @llvm.memcpy{{.*}}(i8* %{{.+}}, i8* bitcast ([2 x i{{[0-9]+}}]* [[TMAIN_VEC]] to i8*),
+
+// threadprivate_s_arr = s_arr;
+// CHECK: call i8* @__kmpc_threadprivate_cached({{.+}} [[TMAIN_S_ARR]]
+// CHECK: [[S_ARR_PRIV_BEGIN:%.+]] = getelementptr inbounds [2 x [[S_INT_TY]]], [2 x [[S_INT_TY]]]* {{%.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 0
+// CHECK: [[S_ARR_PRIV_END:%.+]] = getelementptr [[S_INT_TY]], [[S_INT_TY]]* [[S_ARR_PRIV_BEGIN]], i{{[0-9]+}} 2
+// CHECK: [[IS_EMPTY:%.+]] = icmp eq [[S_INT_TY]]* [[S_ARR_PRIV_BEGIN]], [[S_ARR_PRIV_END]]
+// CHECK: br i1 [[IS_EMPTY]], label %[[S_ARR_BODY_DONE:.+]], label %[[S_ARR_BODY:.+]]
+// CHECK: [[S_ARR_BODY]]
+// CHECK: call {{.*}} [[S_INT_TY_COPY_ASSIGN]]([[S_INT_TY]]* {{.+}}, [[S_INT_TY]]* {{.+}})
+// CHECK: br i1 {{.+}}, label %{{.+}}, label %[[S_ARR_BODY]]
+
+// threadprivate_var = var;
+// CHECK: call i8* @__kmpc_threadprivate_cached({{.+}} [[TMAIN_VAR]]
+// CHECK: call {{.*}} [[S_INT_TY_COPY_ASSIGN]]([[S_INT_TY]]* {{%.+}}, [[S_INT_TY]]* {{.*}}[[TMAIN_VAR]])
+// CHECK: [[DONE]]
+
+// CHECK: call i32 @__kmpc_cancel_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]], i32 [[GTID]])
+// CHECK: ret void
+
+// CHECK: define internal void [[TMAIN_MICROTASK1]](i{{[0-9]+}}* [[GTID_ADDR:%.+]], i{{[0-9]+}}* %{{.+}}, {{%.+}}* %{{.+}})
+// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]],
+// CHECK: [[GTID_ADDR:%.+]] = load i32*, i32** [[GTID_ADDR_ADDR]],
+// CHECK: [[GTID:%.+]] = load i32, i32* [[GTID_ADDR]],
+
+// threadprivate_t_var = t_var;
+// CHECK: call i8* @__kmpc_threadprivate_cached({{.+}} [[TMAIN_T_VAR]]
+// CHECK: ptrtoint i{{[0-9]+}}* %{{.+}} to i{{[0-9]+}}
+// CHECK: icmp ne i{{[0-9]+}} ptrtoint (i{{[0-9]+}}* [[TMAIN_T_VAR]] to i{{[0-9]+}}), %{{.+}}
+// CHECK: br i1 %{{.+}}, label %[[NOT_MASTER:.+]], label %[[DONE:.+]]
+// CHECK: [[NOT_MASTER]]
+// CHECK: load i{{[0-9]+}}, i{{[0-9]+}}* [[TMAIN_T_VAR]],
+// CHECK: store i{{[0-9]+}} %{{.+}}, i{{[0-9]+}}* %{{.+}},
+// CHECK: [[DONE]]
+
+// CHECK: call i32 @__kmpc_cancel_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]], i32 [[GTID]])
+// CHECK: ret void
+
+#endif
+
diff --git a/test/OpenMP/parallel_copyin_messages.cpp b/test/OpenMP/parallel_copyin_messages.cpp
index c1ce363..4a9fa2a 100644
--- a/test/OpenMP/parallel_copyin_messages.cpp
+++ b/test/OpenMP/parallel_copyin_messages.cpp
@@ -20,17 +20,17 @@
S3():a(0) { }
S3 &operator =(S3 &s3) { return *this; }
};
-class S4 { // expected-note {{'S4' declared here}}
+class S4 {
int a;
S4();
- S4 &operator =(const S4 &s4);
+ S4 &operator =(const S4 &s4); // expected-note {{implicitly declared private here}}
public:
S4(int v):a(v) { }
};
-class S5 { // expected-note {{'S5' declared here}}
+class S5 {
int a;
S5():a(0) {}
- S5 &operator =(const S5 &s5) { return *this; }
+ S5 &operator =(const S5 &s5) { return *this; } // expected-note {{implicitly declared private here}}
public:
S5(int v):a(v) { }
};
@@ -40,11 +40,18 @@
static T s;
};
+namespace A {
+double x;
+#pragma omp threadprivate(x)
+}
+namespace B {
+using A::x;
+}
S2 k;
S3 h;
-S4 l(3); // expected-note {{'l' defined here}}
-S5 m(4); // expected-note {{'m' defined here}}
+S4 l(3);
+S5 m(4);
#pragma omp threadprivate(h, k, l, m)
int main(int argc, char **argv) {
@@ -55,12 +62,13 @@
#pragma omp parallel copyin (k // expected-error {{expected ')'}} expected-note {{to match this '('}}
#pragma omp parallel copyin (h, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
#pragma omp parallel copyin (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
- #pragma omp parallel copyin (l) // expected-error {{copyin variable must have an accessible, unambiguous copy assignment operator}}
+ #pragma omp parallel copyin (l) // expected-error {{'operator=' is a private member of 'S4'}}
#pragma omp parallel copyin (S1) // expected-error {{'S1' does not refer to a value}}
#pragma omp parallel copyin (argv[1]) // expected-error {{expected variable name}}
#pragma omp parallel copyin(i) // expected-error {{copyin variable must be threadprivate}}
- #pragma omp parallel copyin(m) // expected-error {{copyin variable must have an accessible, unambiguous copy assignment operator}}
+ #pragma omp parallel copyin(m) // expected-error {{'operator=' is a private member of 'S5'}}
#pragma omp parallel copyin(ST<int>::s) // expected-error {{copyin variable must be threadprivate}}
+ #pragma omp parallel copyin(B::x)
foo();
return 0;
diff --git a/test/OpenMP/parallel_firstprivate_codegen.cpp b/test/OpenMP/parallel_firstprivate_codegen.cpp
index 7adf8e2..25a0921 100644
--- a/test/OpenMP/parallel_firstprivate_codegen.cpp
+++ b/test/OpenMP/parallel_firstprivate_codegen.cpp
@@ -45,6 +45,8 @@
vec[0] = t_var;
s_arr[0] = var;
}
+#pragma omp parallel firstprivate(t_var)
+ {}
return T();
}
@@ -52,13 +54,13 @@
#ifdef LAMBDA
// LAMBDA: [[G:@.+]] = global i{{[0-9]+}} 1212,
// LAMBDA-LABEL: @main
- // LAMBDA: call void [[OUTER_LAMBDA:@.+]](
+ // LAMBDA: call{{( x86_thiscallcc)?}} void [[OUTER_LAMBDA:@.+]](
[&]() {
// LAMBDA: define{{.*}} internal{{.*}} void [[OUTER_LAMBDA]](
// LAMBDA: [[G_LOCAL_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[AGG_CAPTURED:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
// LAMBDA: store i{{[0-9]+}}* [[G]], i{{[0-9]+}}** [[G_LOCAL_REF]]
// LAMBDA: [[ARG:%.+]] = bitcast %{{.+}}* [[AGG_CAPTURED]] to i8*
- // LAMBDA: call void {{.+}}* @__kmpc_fork_call({{.+}}, i32 1, {{.+}}* [[OMP_REGION:@.+]] to {{.+}}, i8* [[ARG]])
+ // LAMBDA: call void {{.+}} @__kmpc_fork_call({{.+}}, i32 1, {{.+}}* [[OMP_REGION:@.+]] to {{.+}}, i8* [[ARG]])
#pragma omp parallel firstprivate(g)
{
// LAMBDA: define{{.*}} internal{{.*}} void [[OMP_REGION]](i32* %{{.+}}, i32* %{{.+}}, %{{.+}}* [[ARG:%.+]])
@@ -68,13 +70,13 @@
// LAMBDA: [[G_REF_ADDR:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
// LAMBDA: [[G_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[G_REF_ADDR]]
// LAMBDA: [[G_VAL:%.+]] = load volatile i{{[0-9]+}}, i{{[0-9]+}}* [[G_REF]]
- // LAMBDA: store volatile i{{[0-9]+}} [[G_VAL]], i{{[0-9]+}}* [[G_PRIVATE_ADDR]]
+ // LAMBDA: store i{{[0-9]+}} [[G_VAL]], i{{[0-9]+}}* [[G_PRIVATE_ADDR]]
// LAMBDA: call i32 @__kmpc_cancel_barrier(
g = 1;
// LAMBDA: store volatile i{{[0-9]+}} 1, i{{[0-9]+}}* [[G_PRIVATE_ADDR]],
// LAMBDA: [[G_PRIVATE_ADDR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
// LAMBDA: store i{{[0-9]+}}* [[G_PRIVATE_ADDR]], i{{[0-9]+}}** [[G_PRIVATE_ADDR_REF]]
- // LAMBDA: call void [[INNER_LAMBDA:@.+]](%{{.+}}* [[ARG]])
+ // LAMBDA: call{{( x86_thiscallcc)?}} void [[INNER_LAMBDA:@.+]](%{{.+}}* [[ARG]])
[&]() {
// LAMBDA: define {{.+}} void [[INNER_LAMBDA]](%{{.+}}* [[ARG_PTR:%.+]])
// LAMBDA: store %{{.+}}* [[ARG_PTR]], %{{.+}}** [[ARG_PTR_REF:%.+]],
@@ -90,13 +92,13 @@
#elif defined(BLOCKS)
// BLOCKS: [[G:@.+]] = global i{{[0-9]+}} 1212,
// BLOCKS-LABEL: @main
- // BLOCKS: call void {{%.+}}(i8*
+ // BLOCKS: call void {{%.+}}(i8
^{
// BLOCKS: define{{.*}} internal{{.*}} void {{.+}}(i8*
// BLOCKS: [[G_LOCAL_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[AGG_CAPTURED:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
// BLOCKS: store i{{[0-9]+}}* [[G]], i{{[0-9]+}}** [[G_LOCAL_REF]]
// BLOCKS: [[ARG:%.+]] = bitcast %{{.+}}* [[AGG_CAPTURED]] to i8*
- // BLOCKS: call void {{.+}}* @__kmpc_fork_call({{.+}}, i32 1, {{.+}}* [[OMP_REGION:@.+]] to {{.+}}, i8* [[ARG]])
+ // BLOCKS: call void {{.+}} @__kmpc_fork_call({{.+}}, i32 1, {{.+}}* [[OMP_REGION:@.+]] to {{.+}}, i8* [[ARG]])
#pragma omp parallel firstprivate(g)
{
// BLOCKS: define{{.*}} internal{{.*}} void [[OMP_REGION]](i32* %{{.+}}, i32* %{{.+}}, %{{.+}}* [[ARG:%.+]])
@@ -106,14 +108,14 @@
// BLOCKS: [[G_REF_ADDR:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
// BLOCKS: [[G_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[G_REF_ADDR]]
// BLOCKS: [[G_VAL:%.+]] = load volatile i{{[0-9]+}}, i{{[0-9]+}}* [[G_REF]]
- // BLOCKS: store volatile i{{[0-9]+}} [[G_VAL]], i{{[0-9]+}}* [[G_PRIVATE_ADDR]]
+ // BLOCKS: store i{{[0-9]+}} [[G_VAL]], i{{[0-9]+}}* [[G_PRIVATE_ADDR]]
// BLOCKS: call i32 @__kmpc_cancel_barrier(
g = 1;
// BLOCKS: store volatile i{{[0-9]+}} 1, i{{[0-9]+}}* [[G_PRIVATE_ADDR]],
// BLOCKS-NOT: [[G]]{{[[^:word:]]}}
// BLOCKS: i{{[0-9]+}}* [[G_PRIVATE_ADDR]]
// BLOCKS-NOT: [[G]]{{[[^:word:]]}}
- // BLOCKS: call void {{%.+}}(i8*
+ // BLOCKS: call void {{%.+}}(i8
^{
// BLOCKS: define {{.+}} void {{@.+}}(i8*
g = 2;
@@ -136,6 +138,8 @@
vec[0] = t_var;
s_arr[0] = var;
}
+#pragma omp parallel firstprivate(t_var)
+ {}
return tmain<int>();
#endif
}
@@ -144,7 +148,7 @@
// CHECK: [[TEST:%.+]] = alloca [[S_FLOAT_TY]],
// CHECK: call {{.*}} [[S_FLOAT_TY_DEF_CONSTR:@.+]]([[S_FLOAT_TY]]* [[TEST]])
// CHECK: %{{.+}} = bitcast [[CAP_MAIN_TY]]*
-// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...)* @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [[CAP_MAIN_TY]]*)* [[MAIN_MICROTASK:@.+]] to void
+// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [[CAP_MAIN_TY]]*)* [[MAIN_MICROTASK:@.+]] to void
// CHECK: = call {{.*}}i{{.+}} [[TMAIN_INT:@.+]]()
// CHECK: call {{.*}} [[S_FLOAT_TY_DESTR:@.+]]([[S_FLOAT_TY]]*
// CHECK: ret
@@ -161,20 +165,13 @@
// CHECK: store i{{[0-9]+}} [[T_VAR_VAL]], i{{[0-9]+}}* [[T_VAR_PRIV]],
// CHECK: [[VEC_PTR_REF:%.+]] = getelementptr inbounds [[CAP_MAIN_TY]], [[CAP_MAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 0
// CHECK: [[VEC_REF:%.+]] = load [2 x i{{[0-9]+}}]*, [2 x i{{[0-9]+}}]** [[VEC_PTR_REF:%.+]],
-// CHECK: br label %[[VEC_PRIV_INIT:.+]]
-// CHECK: [[VEC_PRIV_INIT]]
// CHECK: [[VEC_DEST:%.+]] = bitcast [2 x i{{[0-9]+}}]* [[VEC_PRIV]] to i8*
// CHECK: [[VEC_SRC:%.+]] = bitcast [2 x i{{[0-9]+}}]* [[VEC_REF]] to i8*
// CHECK: call void @llvm.memcpy.{{.+}}(i8* [[VEC_DEST]], i8* [[VEC_SRC]],
-// CHECK: br label %[[VEC_PRIV_INIT_END:.+]]
-// CHECK: [[VEC_PRIV_INIT_END]]
// CHECK: [[S_ARR_REF_PTR:%.+]] = getelementptr inbounds [[CAP_MAIN_TY]], [[CAP_MAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 2
// CHECK: [[S_ARR_REF:%.+]] = load [2 x [[S_FLOAT_TY]]]*, [2 x [[S_FLOAT_TY]]]** [[S_ARR_REF_PTR]],
-// CHECK: br label %[[S_ARR_PRIV_INIT:.+]]
-// CHECK: [[S_ARR_PRIV_INIT]]
-// CHECK: [[S_ARR_BEGIN:%.+]] = getelementptr inbounds [2 x [[S_FLOAT_TY]]], [2 x [[S_FLOAT_TY]]]* [[S_ARR_REF]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
// CHECK: [[S_ARR_PRIV_BEGIN:%.+]] = getelementptr inbounds [2 x [[S_FLOAT_TY]]], [2 x [[S_FLOAT_TY]]]* [[S_ARR_PRIV]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
-// CHECK: [[S_ARR_END:%.+]] = getelementptr [[S_FLOAT_TY]], [[S_FLOAT_TY]]* [[S_ARR_BEGIN]], i{{[0-9]+}} 2
+// CHECK: [[S_ARR_BEGIN:%.+]] = bitcast [2 x [[S_FLOAT_TY]]]* [[S_ARR_REF]] to [[S_FLOAT_TY]]*
// CHECK: [[S_ARR_PRIV_END:%.+]] = getelementptr [[S_FLOAT_TY]], [[S_FLOAT_TY]]* [[S_ARR_PRIV_BEGIN]], i{{[0-9]+}} 2
// CHECK: [[IS_EMPTY:%.+]] = icmp eq [[S_FLOAT_TY]]* [[S_ARR_PRIV_BEGIN]], [[S_ARR_PRIV_END]]
// CHECK: br i1 [[IS_EMPTY]], label %[[S_ARR_BODY_DONE:.+]], label %[[S_ARR_BODY:.+]]
@@ -183,8 +180,6 @@
// CHECK: call {{.*}} [[S_FLOAT_TY_COPY_CONSTR:@.+]]([[S_FLOAT_TY]]* {{.+}}, [[S_FLOAT_TY]]* {{.+}}, [[ST_TY]]* [[ST_TY_TEMP]])
// CHECK: call {{.*}} [[ST_TY_DESTR:@.+]]([[ST_TY]]* [[ST_TY_TEMP]])
// CHECK: br i1 {{.+}}, label %{{.+}}, label %[[S_ARR_BODY]]
-// CHECK: br label %[[S_ARR_PRIV_INIT_END:.+]]
-// CHECK: [[S_ARR_PRIV_INIT_END]]
// CHECK: [[VAR_REF_PTR:%.+]] = getelementptr inbounds [[CAP_MAIN_TY]], [[CAP_MAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 3
// CHECK: [[VAR_REF:%.+]] = load [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** [[VAR_REF_PTR]],
// CHECK: call {{.*}} [[ST_TY_DEFAULT_CONSTR]]([[ST_TY]]* [[ST_TY_TEMP:%.+]])
@@ -200,7 +195,7 @@
// CHECK: define {{.*}} i{{[0-9]+}} [[TMAIN_INT]]()
// CHECK: [[TEST:%.+]] = alloca [[S_INT_TY]],
// CHECK: call {{.*}} [[S_INT_TY_DEF_CONSTR:@.+]]([[S_INT_TY]]* [[TEST]])
-// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...)* @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [[CAP_TMAIN_TY]]*)* [[TMAIN_MICROTASK:@.+]] to void
+// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [[CAP_TMAIN_TY]]*)* [[TMAIN_MICROTASK:@.+]] to void
// CHECK: call {{.*}} [[S_INT_TY_DESTR:@.+]]([[S_INT_TY]]*
// CHECK: ret
//
@@ -216,20 +211,13 @@
// CHECK: store i{{[0-9]+}} [[T_VAR_VAL]], i{{[0-9]+}}* [[T_VAR_PRIV]],
// CHECK: [[VEC_PTR_REF:%.+]] = getelementptr inbounds [[CAP_TMAIN_TY]], [[CAP_TMAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 0
// CHECK: [[VEC_REF:%.+]] = load [2 x i{{[0-9]+}}]*, [2 x i{{[0-9]+}}]** [[VEC_PTR_REF:%.+]],
-// CHECK: br label %[[VEC_PRIV_INIT:.+]]
-// CHECK: [[VEC_PRIV_INIT]]
// CHECK: [[VEC_DEST:%.+]] = bitcast [2 x i{{[0-9]+}}]* [[VEC_PRIV]] to i8*
// CHECK: [[VEC_SRC:%.+]] = bitcast [2 x i{{[0-9]+}}]* [[VEC_REF]] to i8*
// CHECK: call void @llvm.memcpy.{{.+}}(i8* [[VEC_DEST]], i8* [[VEC_SRC]],
-// CHECK: br label %[[VEC_PRIV_INIT_END:.+]]
-// CHECK: [[VEC_PRIV_INIT_END]]
// CHECK: [[S_ARR_REF_PTR:%.+]] = getelementptr inbounds [[CAP_TMAIN_TY]], [[CAP_TMAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 2
// CHECK: [[S_ARR_REF:%.+]] = load [2 x [[S_INT_TY]]]*, [2 x [[S_INT_TY]]]** [[S_ARR_REF_PTR]],
-// CHECK: br label %[[S_ARR_PRIV_INIT:.+]]
-// CHECK: [[S_ARR_PRIV_INIT]]
-// CHECK: [[S_ARR_BEGIN:%.+]] = getelementptr inbounds [2 x [[S_INT_TY]]], [2 x [[S_INT_TY]]]* [[S_ARR_REF]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
// CHECK: [[S_ARR_PRIV_BEGIN:%.+]] = getelementptr inbounds [2 x [[S_INT_TY]]], [2 x [[S_INT_TY]]]* [[S_ARR_PRIV]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
-// CHECK: [[S_ARR_END:%.+]] = getelementptr [[S_INT_TY]], [[S_INT_TY]]* [[S_ARR_BEGIN]], i{{[0-9]+}} 2
+// CHECK: [[S_ARR_BEGIN:%.+]] = bitcast [2 x [[S_INT_TY]]]* [[S_ARR_REF]] to [[S_INT_TY]]*
// CHECK: [[S_ARR_PRIV_END:%.+]] = getelementptr [[S_INT_TY]], [[S_INT_TY]]* [[S_ARR_PRIV_BEGIN]], i{{[0-9]+}} 2
// CHECK: [[IS_EMPTY:%.+]] = icmp eq [[S_INT_TY]]* [[S_ARR_PRIV_BEGIN]], [[S_ARR_PRIV_END]]
// CHECK: br i1 [[IS_EMPTY]], label %[[S_ARR_BODY_DONE:.+]], label %[[S_ARR_BODY:.+]]
@@ -238,8 +226,6 @@
// CHECK: call {{.*}} [[S_INT_TY_COPY_CONSTR:@.+]]([[S_INT_TY]]* {{.+}}, [[S_INT_TY]]* {{.+}}, [[ST_TY]]* [[ST_TY_TEMP]])
// CHECK: call {{.*}} [[ST_TY_DESTR]]([[ST_TY]]* [[ST_TY_TEMP]])
// CHECK: br i1 {{.+}}, label %{{.+}}, label %[[S_ARR_BODY]]
-// CHECK: br label %[[S_ARR_PRIV_INIT_END:.+]]
-// CHECK: [[S_ARR_PRIV_INIT_END]]
// CHECK: [[VAR_REF_PTR:%.+]] = getelementptr inbounds [[CAP_TMAIN_TY]], [[CAP_TMAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 3
// CHECK: [[VAR_REF:%.+]] = load [[S_INT_TY]]*, [[S_INT_TY]]** [[VAR_REF_PTR]],
// CHECK: call {{.*}} [[ST_TY_DEFAULT_CONSTR]]([[ST_TY]]* [[ST_TY_TEMP:%.+]])
diff --git a/test/OpenMP/parallel_firstprivate_messages.cpp b/test/OpenMP/parallel_firstprivate_messages.cpp
index 7d1e359..fe534b4 100644
--- a/test/OpenMP/parallel_firstprivate_messages.cpp
+++ b/test/OpenMP/parallel_firstprivate_messages.cpp
@@ -47,6 +47,14 @@
S3 h;
#pragma omp threadprivate(h) // expected-note {{defined as threadprivate or thread local}}
+namespace A {
+double x;
+#pragma omp threadprivate(x) // expected-note {{defined as threadprivate or thread local}}
+}
+namespace B {
+using A::x;
+}
+
int main(int argc, char **argv) {
const int d = 5;
const int da[5] = { 0 };
@@ -70,7 +78,7 @@
#pragma omp parallel firstprivate(S2::S2s)
#pragma omp parallel firstprivate(S2::S2sc)
#pragma omp parallel firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
- #pragma omp parallel firstprivate(h) // expected-error {{threadprivate or thread local variable cannot be firstprivate}}
+ #pragma omp parallel firstprivate(h, B::x) // expected-error 2 {{threadprivate or thread local variable cannot be firstprivate}}
#pragma omp parallel private(i), firstprivate(i) // expected-error {{private variable cannot be firstprivate}} expected-note{{defined as private}}
foo();
#pragma omp parallel shared(i)
diff --git a/test/OpenMP/parallel_for_codegen.cpp b/test/OpenMP/parallel_for_codegen.cpp
new file mode 100644
index 0000000..63ae11b
--- /dev/null
+++ b/test/OpenMP/parallel_for_codegen.cpp
@@ -0,0 +1,398 @@
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -x c++ -triple x86_64-unknown-unknown -emit-llvm %s -fexceptions -fcxx-exceptions -o - | FileCheck %s
+// RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -std=c++11 -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -verify -triple x86_64-apple-darwin10 -fopenmp=libiomp5 -fexceptions -fcxx-exceptions -gline-tables-only -x c++ -emit-llvm %s -o - | FileCheck %s --check-prefix=TERM_DEBUG
+//
+// expected-no-diagnostics
+#ifndef HEADER
+#define HEADER
+
+// CHECK: [[IDENT_T_TY:%.+]] = type { i32, i32, i32, i32, i8* }
+// CHECK-LABEL: define {{.*void}} @{{.*}}without_schedule_clause{{.*}}(float* {{.+}}, float* {{.+}}, float* {{.+}}, float* {{.+}})
+void without_schedule_clause(float *a, float *b, float *c, float *d) {
+ #pragma omp parallel for
+// CHECK: call void ([[IDENT_T_TY]]*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call([[IDENT_T_TY]]* [[DEFAULT_LOC:[@%].+]], i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, %{{.+}}*)* [[OMP_PARALLEL_FUNC:@.+]] to void (i32*, i32*, ...)*), i8* %{{.+}})
+// CHECK: define internal void [[OMP_PARALLEL_FUNC]](i32* [[GTID_PARAM_ADDR:%.+]], i32* %{{.+}}, %{{.+}}* %{{.+}})
+// CHECK: store i32* [[GTID_PARAM_ADDR]], i32** [[GTID_REF_ADDR:%.+]],
+// CHECK: [[GTID_REF:%.+]] = load i32*, i32** [[GTID_REF_ADDR]],
+// CHECK: [[GTID:%.+]] = load i32, i32* [[GTID_REF]],
+// CHECK: call void @__kmpc_for_static_init_4([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], i32 34, i32* [[IS_LAST:%[^,]+]], i32* [[OMP_LB:%[^,]+]], i32* [[OMP_UB:%[^,]+]], i32* [[OMP_ST:%[^,]+]], i32 1, i32 1)
+// UB = min(UB, GlobalUB)
+// CHECK-NEXT: [[UB:%.+]] = load i32, i32* [[OMP_UB]]
+// CHECK-NEXT: [[UBCMP:%.+]] = icmp sgt i32 [[UB]], 4571423
+// CHECK-NEXT: br i1 [[UBCMP]], label [[UB_TRUE:%[^,]+]], label [[UB_FALSE:%[^,]+]]
+// CHECK: [[UBRESULT:%.+]] = phi i32 [ 4571423, [[UB_TRUE]] ], [ [[UBVAL:%[^,]+]], [[UB_FALSE]] ]
+// CHECK-NEXT: store i32 [[UBRESULT]], i32* [[OMP_UB]]
+// CHECK-NEXT: [[LB:%.+]] = load i32, i32* [[OMP_LB]]
+// CHECK-NEXT: store i32 [[LB]], i32* [[OMP_IV:[^,]+]]
+// Loop header
+// CHECK: [[IV:%.+]] = load i32, i32* [[OMP_IV]]
+// CHECK-NEXT: [[UB:%.+]] = load i32, i32* [[OMP_UB]]
+// CHECK-NEXT: [[CMP:%.+]] = icmp sle i32 [[IV]], [[UB]]
+// CHECK-NEXT: br i1 [[CMP]], label %[[LOOP1_BODY:[^,]+]], label %[[LOOP1_END:[^,]+]]
+ for (int i = 33; i < 32000000; i += 7) {
+// CHECK: [[LOOP1_BODY]]
+// Start of body: calculate i from IV:
+// CHECK: [[IV1_1:%.+]] = load i32, i32* [[OMP_IV]]
+// CHECK-NEXT: [[CALC_I_1:%.+]] = mul nsw i32 [[IV1_1]], 7
+// CHECK-NEXT: [[CALC_I_2:%.+]] = add nsw i32 33, [[CALC_I_1]]
+// CHECK-NEXT: store i32 [[CALC_I_2]], i32* [[LC_I:.+]]
+// ... loop body ...
+// End of body: store into a[i]:
+// CHECK: store float [[RESULT:%.+]], float* {{%.+}}
+ a[i] = b[i] * c[i] * d[i];
+// CHECK: [[IV1_2:%.+]] = load i32, i32* [[OMP_IV]]{{.*}}
+// CHECK-NEXT: [[ADD1_2:%.+]] = add nsw i32 [[IV1_2]], 1
+// CHECK-NEXT: store i32 [[ADD1_2]], i32* [[OMP_IV]]
+// CHECK-NEXT: br label %{{.+}}
+ }
+// CHECK: [[LOOP1_END]]
+// CHECK: [[GTID_REF:%.+]] = load i32*, i32** [[GTID_REF_ADDR]],
+// CHECK: [[GTID:%.+]] = load i32, i32* [[GTID_REF]],
+// CHECK: call void @__kmpc_for_static_fini([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]])
+// CHECK: [[GTID_REF:%.+]] = load i32*, i32** [[GTID_REF_ADDR]],
+// CHECK: [[GTID:%.+]] = load i32, i32* [[GTID_REF]],
+// CHECK: call {{.+}} @__kmpc_cancel_barrier([[IDENT_T_TY]]* [[DEFAULT_LOC_BARRIER:[@%].+]], i32 [[GTID]])
+// CHECK: ret void
+}
+
+// CHECK-LABEL: define {{.*void}} @{{.*}}static_not_chunked{{.*}}(float* {{.+}}, float* {{.+}}, float* {{.+}}, float* {{.+}})
+void static_not_chunked(float *a, float *b, float *c, float *d) {
+ #pragma omp parallel for schedule(static)
+// CHECK: call void ([[IDENT_T_TY]]*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, %{{.+}}*)* [[OMP_PARALLEL_FUNC:@.+]] to void (i32*, i32*, ...)*), i8* %{{.+}})
+// CHECK: define internal void [[OMP_PARALLEL_FUNC]](i32* [[GTID_PARAM_ADDR:%.+]], i32* %{{.+}}, %{{.+}}* %{{.+}})
+// CHECK: store i32* [[GTID_PARAM_ADDR]], i32** [[GTID_REF_ADDR:%.+]],
+// CHECK: [[GTID_REF:%.+]] = load i32*, i32** [[GTID_REF_ADDR]],
+// CHECK: [[GTID:%.+]] = load i32, i32* [[GTID_REF]],
+// CHECK: call void @__kmpc_for_static_init_4([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], i32 34, i32* [[IS_LAST:%[^,]+]], i32* [[OMP_LB:%[^,]+]], i32* [[OMP_UB:%[^,]+]], i32* [[OMP_ST:%[^,]+]], i32 1, i32 1)
+// UB = min(UB, GlobalUB)
+// CHECK-NEXT: [[UB:%.+]] = load i32, i32* [[OMP_UB]]
+// CHECK-NEXT: [[UBCMP:%.+]] = icmp sgt i32 [[UB]], 4571423
+// CHECK-NEXT: br i1 [[UBCMP]], label [[UB_TRUE:%[^,]+]], label [[UB_FALSE:%[^,]+]]
+// CHECK: [[UBRESULT:%.+]] = phi i32 [ 4571423, [[UB_TRUE]] ], [ [[UBVAL:%[^,]+]], [[UB_FALSE]] ]
+// CHECK-NEXT: store i32 [[UBRESULT]], i32* [[OMP_UB]]
+// CHECK-NEXT: [[LB:%.+]] = load i32, i32* [[OMP_LB]]
+// CHECK-NEXT: store i32 [[LB]], i32* [[OMP_IV:[^,]+]]
+// Loop header
+// CHECK: [[IV:%.+]] = load i32, i32* [[OMP_IV]]
+// CHECK-NEXT: [[UB:%.+]] = load i32, i32* [[OMP_UB]]
+// CHECK-NEXT: [[CMP:%.+]] = icmp sle i32 [[IV]], [[UB]]
+// CHECK-NEXT: br i1 [[CMP]], label %[[LOOP1_BODY:[^,]+]], label %[[LOOP1_END:[^,]+]]
+ for (int i = 32000000; i > 33; i += -7) {
+// CHECK: [[LOOP1_BODY]]
+// Start of body: calculate i from IV:
+// CHECK: [[IV1_1:%.+]] = load i32, i32* [[OMP_IV]]
+// CHECK-NEXT: [[CALC_I_1:%.+]] = mul nsw i32 [[IV1_1]], 7
+// CHECK-NEXT: [[CALC_I_2:%.+]] = sub nsw i32 32000000, [[CALC_I_1]]
+// CHECK-NEXT: store i32 [[CALC_I_2]], i32* [[LC_I:.+]]
+// ... loop body ...
+// End of body: store into a[i]:
+// CHECK: store float [[RESULT:%.+]], float* {{%.+}}
+ a[i] = b[i] * c[i] * d[i];
+// CHECK: [[IV1_2:%.+]] = load i32, i32* [[OMP_IV]]{{.*}}
+// CHECK-NEXT: [[ADD1_2:%.+]] = add nsw i32 [[IV1_2]], 1
+// CHECK-NEXT: store i32 [[ADD1_2]], i32* [[OMP_IV]]
+// CHECK-NEXT: br label %{{.+}}
+ }
+// CHECK: [[LOOP1_END]]
+// CHECK: [[GTID_REF:%.+]] = load i32*, i32** [[GTID_REF_ADDR]],
+// CHECK: [[GTID:%.+]] = load i32, i32* [[GTID_REF]],
+// CHECK: call void @__kmpc_for_static_fini([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]])
+// CHECK: [[GTID_REF:%.+]] = load i32*, i32** [[GTID_REF_ADDR]],
+// CHECK: [[GTID:%.+]] = load i32, i32* [[GTID_REF]],
+// CHECK: call {{.+}} @__kmpc_cancel_barrier([[IDENT_T_TY]]* [[DEFAULT_LOC_BARRIER:[@%].+]], i32 [[GTID]])
+// CHECK: ret void
+}
+
+// CHECK-LABEL: define {{.*void}} @{{.*}}static_chunked{{.*}}(float* {{.+}}, float* {{.+}}, float* {{.+}}, float* {{.+}})
+void static_chunked(float *a, float *b, float *c, float *d) {
+ #pragma omp parallel for schedule(static, 5)
+// CHECK: call void ([[IDENT_T_TY]]*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, %{{.+}}*)* [[OMP_PARALLEL_FUNC:@.+]] to void (i32*, i32*, ...)*), i8* %{{.+}})
+// CHECK: define internal void [[OMP_PARALLEL_FUNC]](i32* [[GTID_PARAM_ADDR:%.+]], i32* %{{.+}}, %{{.+}}* %{{.+}})
+// CHECK: store i32* [[GTID_PARAM_ADDR]], i32** [[GTID_REF_ADDR:%.+]],
+// CHECK: [[GTID_REF:%.+]] = load i32*, i32** [[GTID_REF_ADDR]],
+// CHECK: [[GTID:%.+]] = load i32, i32* [[GTID_REF]],
+// CHECK: call void @__kmpc_for_static_init_4u([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], i32 33, i32* [[IS_LAST:%[^,]+]], i32* [[OMP_LB:%[^,]+]], i32* [[OMP_UB:%[^,]+]], i32* [[OMP_ST:%[^,]+]], i32 1, i32 5)
+// UB = min(UB, GlobalUB)
+// CHECK: [[UB:%.+]] = load i32, i32* [[OMP_UB]]
+// CHECK-NEXT: [[UBCMP:%.+]] = icmp ugt i32 [[UB]], 16908288
+// CHECK-NEXT: br i1 [[UBCMP]], label [[UB_TRUE:%[^,]+]], label [[UB_FALSE:%[^,]+]]
+// CHECK: [[UBRESULT:%.+]] = phi i32 [ 16908288, [[UB_TRUE]] ], [ [[UBVAL:%[^,]+]], [[UB_FALSE]] ]
+// CHECK-NEXT: store i32 [[UBRESULT]], i32* [[OMP_UB]]
+// CHECK-NEXT: [[LB:%.+]] = load i32, i32* [[OMP_LB]]
+// CHECK-NEXT: store i32 [[LB]], i32* [[OMP_IV:[^,]+]]
+
+// Outer loop header
+// CHECK: [[O_IV:%.+]] = load i32, i32* [[OMP_IV]]
+// CHECK-NEXT: [[O_UB:%.+]] = load i32, i32* [[OMP_UB]]
+// CHECK-NEXT: [[O_CMP:%.+]] = icmp ule i32 [[O_IV]], [[O_UB]]
+// CHECK-NEXT: br i1 [[O_CMP]], label %[[O_LOOP1_BODY:[^,]+]], label %[[O_LOOP1_END:[^,]+]]
+
+// Loop header
+// CHECK: [[O_LOOP1_BODY]]
+// CHECK: [[IV:%.+]] = load i32, i32* [[OMP_IV]]
+// CHECK-NEXT: [[UB:%.+]] = load i32, i32* [[OMP_UB]]
+// CHECK-NEXT: [[CMP:%.+]] = icmp ule i32 [[IV]], [[UB]]
+// CHECK-NEXT: br i1 [[CMP]], label %[[LOOP1_BODY:[^,]+]], label %[[LOOP1_END:[^,]+]]
+ for (unsigned i = 131071; i <= 2147483647; i += 127) {
+// CHECK: [[LOOP1_BODY]]
+// Start of body: calculate i from IV:
+// CHECK: [[IV1_1:%.+]] = load i32, i32* [[OMP_IV]]
+// CHECK-NEXT: [[CALC_I_1:%.+]] = mul i32 [[IV1_1]], 127
+// CHECK-NEXT: [[CALC_I_2:%.+]] = add i32 131071, [[CALC_I_1]]
+// CHECK-NEXT: store i32 [[CALC_I_2]], i32* [[LC_I:.+]]
+// ... loop body ...
+// End of body: store into a[i]:
+// CHECK: store float [[RESULT:%.+]], float* {{%.+}}
+ a[i] = b[i] * c[i] * d[i];
+// CHECK: [[IV1_2:%.+]] = load i32, i32* [[OMP_IV]]{{.*}}
+// CHECK-NEXT: [[ADD1_2:%.+]] = add i32 [[IV1_2]], 1
+// CHECK-NEXT: store i32 [[ADD1_2]], i32* [[OMP_IV]]
+// CHECK-NEXT: br label %{{.+}}
+ }
+// CHECK: [[LOOP1_END]]
+// Update the counters, adding stride
+// CHECK: [[LB:%.+]] = load i32, i32* [[OMP_LB]]
+// CHECK-NEXT: [[ST:%.+]] = load i32, i32* [[OMP_ST]]
+// CHECK-NEXT: [[ADD_LB:%.+]] = add i32 [[LB]], [[ST]]
+// CHECK-NEXT: store i32 [[ADD_LB]], i32* [[OMP_LB]]
+// CHECK-NEXT: [[UB:%.+]] = load i32, i32* [[OMP_UB]]
+// CHECK-NEXT: [[ST:%.+]] = load i32, i32* [[OMP_ST]]
+// CHECK-NEXT: [[ADD_UB:%.+]] = add i32 [[UB]], [[ST]]
+// CHECK-NEXT: store i32 [[ADD_UB]], i32* [[OMP_UB]]
+
+// CHECK: [[O_LOOP1_END]]
+// CHECK: [[GTID_REF:%.+]] = load i32*, i32** [[GTID_REF_ADDR]],
+// CHECK: [[GTID:%.+]] = load i32, i32* [[GTID_REF]],
+// CHECK: call void @__kmpc_for_static_fini([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]])
+// CHECK: [[GTID_REF:%.+]] = load i32*, i32** [[GTID_REF_ADDR]],
+// CHECK: [[GTID:%.+]] = load i32, i32* [[GTID_REF]],
+// CHECK: call {{.+}} @__kmpc_cancel_barrier([[IDENT_T_TY]]* [[DEFAULT_LOC_BARRIER:[@%].+]], i32 [[GTID]])
+// CHECK: ret void
+}
+
+// CHECK-LABEL: define {{.*void}} @{{.*}}dynamic1{{.*}}(float* {{.+}}, float* {{.+}}, float* {{.+}}, float* {{.+}})
+void dynamic1(float *a, float *b, float *c, float *d) {
+ #pragma omp parallel for schedule(dynamic)
+// CHECK: call void ([[IDENT_T_TY]]*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, %{{.+}}*)* [[OMP_PARALLEL_FUNC:@.+]] to void (i32*, i32*, ...)*), i8* %{{.+}})
+// CHECK: define internal void [[OMP_PARALLEL_FUNC]](i32* [[GTID_PARAM_ADDR:%.+]], i32* %{{.+}}, %{{.+}}* %{{.+}})
+// CHECK: store i32* [[GTID_PARAM_ADDR]], i32** [[GTID_REF_ADDR:%.+]],
+// CHECK: [[GTID_REF:%.+]] = load i32*, i32** [[GTID_REF_ADDR]],
+// CHECK: [[GTID:%.+]] = load i32, i32* [[GTID_REF]],
+// CHECK: call void @__kmpc_dispatch_init_8u([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], i32 35, i64 0, i64 16908287, i64 1, i64 1)
+//
+// CHECK: [[GTID_REF:%.+]] = load i32*, i32** [[GTID_REF_ADDR]],
+// CHECK: [[GTID:%.+]] = load i32, i32* [[GTID_REF]],
+// CHECK: [[HASWORK:%.+]] = call i32 @__kmpc_dispatch_next_8u([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], i32* [[OMP_ISLAST:%[^,]+]], i64* [[OMP_LB:%[^,]+]], i64* [[OMP_UB:%[^,]+]], i64* [[OMP_ST:%[^,]+]])
+// CHECK-NEXT: [[O_CMP:%.+]] = icmp ne i32 [[HASWORK]], 0
+// CHECK-NEXT: br i1 [[O_CMP]], label %[[O_LOOP1_BODY:[^,]+]], label %[[O_LOOP1_END:[^,]+]]
+
+// Loop header
+// CHECK: [[O_LOOP1_BODY]]
+// CHECK: [[LB:%.+]] = load i64, i64* [[OMP_LB]]
+// CHECK-NEXT: store i64 [[LB]], i64* [[OMP_IV:[^,]+]]
+// CHECK: [[IV:%.+]] = load i64, i64* [[OMP_IV]]
+
+// CHECK-NEXT: [[UB:%.+]] = load i64, i64* [[OMP_UB]]
+// CHECK-NEXT: [[CMP:%.+]] = icmp ule i64 [[IV]], [[UB]]
+// CHECK-NEXT: br i1 [[CMP]], label %[[LOOP1_BODY:[^,]+]], label %[[LOOP1_END:[^,]+]]
+ for (unsigned long long i = 131071; i < 2147483647; i += 127) {
+// CHECK: [[LOOP1_BODY]]
+// Start of body: calculate i from IV:
+// CHECK: [[IV1_1:%.+]] = load i64, i64* [[OMP_IV]]
+// CHECK-NEXT: [[CALC_I_1:%.+]] = mul i64 [[IV1_1]], 127
+// CHECK-NEXT: [[CALC_I_2:%.+]] = add i64 131071, [[CALC_I_1]]
+// CHECK-NEXT: store i64 [[CALC_I_2]], i64* [[LC_I:.+]]
+// ... loop body ...
+// End of body: store into a[i]:
+// CHECK: store float [[RESULT:%.+]], float* {{%.+}}
+ a[i] = b[i] * c[i] * d[i];
+// CHECK: [[IV1_2:%.+]] = load i64, i64* [[OMP_IV]]{{.*}}
+// CHECK-NEXT: [[ADD1_2:%.+]] = add i64 [[IV1_2]], 1
+// CHECK-NEXT: store i64 [[ADD1_2]], i64* [[OMP_IV]]
+// CHECK-NEXT: br label %{{.+}}
+ }
+// CHECK: [[LOOP1_END]]
+// CHECK: [[O_LOOP1_END]]
+// CHECK: [[GTID_REF:%.+]] = load i32*, i32** [[GTID_REF_ADDR]],
+// CHECK: [[GTID:%.+]] = load i32, i32* [[GTID_REF]],
+// CHECK: call {{.+}} @__kmpc_cancel_barrier([[IDENT_T_TY]]* [[DEFAULT_LOC_BARRIER:[@%].+]], i32 [[GTID]])
+// CHECK: ret void
+}
+
+// CHECK-LABEL: define {{.*void}} @{{.*}}guided7{{.*}}(float* {{.+}}, float* {{.+}}, float* {{.+}}, float* {{.+}})
+void guided7(float *a, float *b, float *c, float *d) {
+ #pragma omp parallel for schedule(guided, 7)
+// CHECK: call void ([[IDENT_T_TY]]*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, %{{.+}}*)* [[OMP_PARALLEL_FUNC:@.+]] to void (i32*, i32*, ...)*), i8* %{{.+}})
+// CHECK: define internal void [[OMP_PARALLEL_FUNC]](i32* [[GTID_PARAM_ADDR:%.+]], i32* %{{.+}}, %{{.+}}* %{{.+}})
+// CHECK: store i32* [[GTID_PARAM_ADDR]], i32** [[GTID_REF_ADDR:%.+]],
+// CHECK: [[GTID_REF:%.+]] = load i32*, i32** [[GTID_REF_ADDR]],
+// CHECK: [[GTID:%.+]] = load i32, i32* [[GTID_REF]],
+// CHECK: call void @__kmpc_dispatch_init_8u([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], i32 36, i64 0, i64 16908287, i64 1, i64 7)
+//
+// CHECK: [[GTID_REF:%.+]] = load i32*, i32** [[GTID_REF_ADDR]],
+// CHECK: [[GTID:%.+]] = load i32, i32* [[GTID_REF]],
+// CHECK: [[HASWORK:%.+]] = call i32 @__kmpc_dispatch_next_8u([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], i32* [[OMP_ISLAST:%[^,]+]], i64* [[OMP_LB:%[^,]+]], i64* [[OMP_UB:%[^,]+]], i64* [[OMP_ST:%[^,]+]])
+// CHECK-NEXT: [[O_CMP:%.+]] = icmp ne i32 [[HASWORK]], 0
+// CHECK-NEXT: br i1 [[O_CMP]], label %[[O_LOOP1_BODY:[^,]+]], label %[[O_LOOP1_END:[^,]+]]
+
+// Loop header
+// CHECK: [[O_LOOP1_BODY]]
+// CHECK: [[LB:%.+]] = load i64, i64* [[OMP_LB]]
+// CHECK-NEXT: store i64 [[LB]], i64* [[OMP_IV:[^,]+]]
+// CHECK: [[IV:%.+]] = load i64, i64* [[OMP_IV]]
+
+// CHECK-NEXT: [[UB:%.+]] = load i64, i64* [[OMP_UB]]
+// CHECK-NEXT: [[CMP:%.+]] = icmp ule i64 [[IV]], [[UB]]
+// CHECK-NEXT: br i1 [[CMP]], label %[[LOOP1_BODY:[^,]+]], label %[[LOOP1_END:[^,]+]]
+ for (unsigned long long i = 131071; i < 2147483647; i += 127) {
+// CHECK: [[LOOP1_BODY]]
+// Start of body: calculate i from IV:
+// CHECK: [[IV1_1:%.+]] = load i64, i64* [[OMP_IV]]
+// CHECK-NEXT: [[CALC_I_1:%.+]] = mul i64 [[IV1_1]], 127
+// CHECK-NEXT: [[CALC_I_2:%.+]] = add i64 131071, [[CALC_I_1]]
+// CHECK-NEXT: store i64 [[CALC_I_2]], i64* [[LC_I:.+]]
+// ... loop body ...
+// End of body: store into a[i]:
+// CHECK: store float [[RESULT:%.+]], float* {{%.+}}
+ a[i] = b[i] * c[i] * d[i];
+// CHECK: [[IV1_2:%.+]] = load i64, i64* [[OMP_IV]]{{.*}}
+// CHECK-NEXT: [[ADD1_2:%.+]] = add i64 [[IV1_2]], 1
+// CHECK-NEXT: store i64 [[ADD1_2]], i64* [[OMP_IV]]
+// CHECK-NEXT: br label %{{.+}}
+ }
+// CHECK: [[LOOP1_END]]
+// CHECK: [[O_LOOP1_END]]
+// CHECK: [[GTID_REF:%.+]] = load i32*, i32** [[GTID_REF_ADDR]],
+// CHECK: [[GTID:%.+]] = load i32, i32* [[GTID_REF]],
+// CHECK: call {{.+}} @__kmpc_cancel_barrier([[IDENT_T_TY]]* [[DEFAULT_LOC_BARRIER:[@%].+]], i32 [[GTID]])
+// CHECK: ret void
+}
+
+// CHECK-LABEL: define {{.*void}} @{{.*}}test_auto{{.*}}(float* {{.+}}, float* {{.+}}, float* {{.+}}, float* {{.+}})
+void test_auto(float *a, float *b, float *c, float *d) {
+ unsigned int x = 0;
+ unsigned int y = 0;
+ #pragma omp parallel for schedule(auto) collapse(2)
+// CHECK: call void ([[IDENT_T_TY]]*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, %{{.+}}*)* [[OMP_PARALLEL_FUNC:@.+]] to void (i32*, i32*, ...)*), i8* %{{.+}})
+// CHECK: define internal void [[OMP_PARALLEL_FUNC]](i32* [[GTID_PARAM_ADDR:%.+]], i32* %{{.+}}, %{{.+}}* %{{.+}})
+// CHECK: store i32* [[GTID_PARAM_ADDR]], i32** [[GTID_REF_ADDR:%.+]],
+// CHECK: [[GTID_REF:%.+]] = load i32*, i32** [[GTID_REF_ADDR]],
+// CHECK: [[GTID:%.+]] = load i32, i32* [[GTID_REF]],
+// CHECK: call void @__kmpc_dispatch_init_8([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], i32 38, i64 0, i64 [[LAST_ITER:%[^,]+]], i64 1, i64 1)
+//
+// CHECK: [[GTID_REF:%.+]] = load i32*, i32** [[GTID_REF_ADDR]],
+// CHECK: [[GTID:%.+]] = load i32, i32* [[GTID_REF]],
+// CHECK: [[HASWORK:%.+]] = call i32 @__kmpc_dispatch_next_8([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], i32* [[OMP_ISLAST:%[^,]+]], i64* [[OMP_LB:%[^,]+]], i64* [[OMP_UB:%[^,]+]], i64* [[OMP_ST:%[^,]+]])
+// CHECK-NEXT: [[O_CMP:%.+]] = icmp ne i32 [[HASWORK]], 0
+// CHECK-NEXT: br i1 [[O_CMP]], label %[[O_LOOP1_BODY:[^,]+]], label %[[O_LOOP1_END:[^,]+]]
+
+// Loop header
+// CHECK: [[O_LOOP1_BODY]]
+// CHECK: [[LB:%.+]] = load i64, i64* [[OMP_LB]]
+// CHECK-NEXT: store i64 [[LB]], i64* [[OMP_IV:[^,]+]]
+// CHECK: [[IV:%.+]] = load i64, i64* [[OMP_IV]]
+
+// CHECK-NEXT: [[UB:%.+]] = load i64, i64* [[OMP_UB]]
+// CHECK-NEXT: [[CMP:%.+]] = icmp sle i64 [[IV]], [[UB]]
+// CHECK-NEXT: br i1 [[CMP]], label %[[LOOP1_BODY:[^,]+]], label %[[LOOP1_END:[^,]+]]
+// FIXME: When the iteration count of some nested loop is not a known constant,
+// we should pre-calculate it, like we do for the total number of iterations!
+ for (char i = static_cast<char>(y); i <= '9'; ++i)
+ for (x = 11; x > 0; --x) {
+// CHECK: [[LOOP1_BODY]]
+// Start of body: indices are calculated from IV:
+// CHECK: store i8 {{%[^,]+}}, i8* {{%[^,]+}}
+// CHECK: store i32 {{%[^,]+}}, i32* {{%[^,]+}}
+// ... loop body ...
+// End of body: store into a[i]:
+// CHECK: store float [[RESULT:%.+]], float* {{%.+}}
+ a[i] = b[i] * c[i] * d[i];
+// CHECK: [[IV1_2:%.+]] = load i64, i64* [[OMP_IV]]{{.*}}
+// CHECK-NEXT: [[ADD1_2:%.+]] = add nsw i64 [[IV1_2]], 1
+// CHECK-NEXT: store i64 [[ADD1_2]], i64* [[OMP_IV]]
+// CHECK-NEXT: br label %{{.+}}
+ }
+// CHECK: [[LOOP1_END]]
+// CHECK: [[O_LOOP1_END]]
+// CHECK: [[GTID_REF:%.+]] = load i32*, i32** [[GTID_REF_ADDR]],
+// CHECK: [[GTID:%.+]] = load i32, i32* [[GTID_REF]],
+// CHECK: call {{.+}} @__kmpc_cancel_barrier([[IDENT_T_TY]]* [[DEFAULT_LOC_BARRIER:[@%].+]], i32 [[GTID]])
+// CHECK: ret void
+}
+
+// CHECK-LABEL: define {{.*void}} @{{.*}}runtime{{.*}}(float* {{.+}}, float* {{.+}}, float* {{.+}}, float* {{.+}})
+void runtime(float *a, float *b, float *c, float *d) {
+ int x = 0;
+ #pragma omp parallel for collapse(2) schedule(runtime)
+// CHECK: call void ([[IDENT_T_TY]]*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, %{{.+}}*)* [[OMP_PARALLEL_FUNC:@.+]] to void (i32*, i32*, ...)*), i8* %{{.+}})
+// CHECK: define internal void [[OMP_PARALLEL_FUNC]](i32* [[GTID_PARAM_ADDR:%.+]], i32* %{{.+}}, %{{.+}}* %{{.+}})
+// CHECK: store i32* [[GTID_PARAM_ADDR]], i32** [[GTID_REF_ADDR:%.+]],
+// CHECK: [[GTID_REF:%.+]] = load i32*, i32** [[GTID_REF_ADDR]],
+// CHECK: [[GTID:%.+]] = load i32, i32* [[GTID_REF]],
+// CHECK: call void @__kmpc_dispatch_init_4([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], i32 37, i32 0, i32 199, i32 1, i32 1)
+//
+// CHECK: [[GTID_REF:%.+]] = load i32*, i32** [[GTID_REF_ADDR]],
+// CHECK: [[GTID:%.+]] = load i32, i32* [[GTID_REF]],
+// CHECK: [[HASWORK:%.+]] = call i32 @__kmpc_dispatch_next_4([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], i32* [[OMP_ISLAST:%[^,]+]], i32* [[OMP_LB:%[^,]+]], i32* [[OMP_UB:%[^,]+]], i32* [[OMP_ST:%[^,]+]])
+// CHECK-NEXT: [[O_CMP:%.+]] = icmp ne i32 [[HASWORK]], 0
+// CHECK-NEXT: br i1 [[O_CMP]], label %[[O_LOOP1_BODY:[^,]+]], label %[[O_LOOP1_END:[^,]+]]
+
+// Loop header
+// CHECK: [[O_LOOP1_BODY]]
+// CHECK: [[LB:%.+]] = load i32, i32* [[OMP_LB]]
+// CHECK-NEXT: store i32 [[LB]], i32* [[OMP_IV:[^,]+]]
+// CHECK: [[IV:%.+]] = load i32, i32* [[OMP_IV]]
+
+// CHECK-NEXT: [[UB:%.+]] = load i32, i32* [[OMP_UB]]
+// CHECK-NEXT: [[CMP:%.+]] = icmp sle i32 [[IV]], [[UB]]
+// CHECK-NEXT: br i1 [[CMP]], label %[[LOOP1_BODY:[^,]+]], label %[[LOOP1_END:[^,]+]]
+ for (unsigned char i = '0' ; i <= '9'; ++i)
+ for (x = -10; x < 10; ++x) {
+// CHECK: [[LOOP1_BODY]]
+// Start of body: indices are calculated from IV:
+// CHECK: store i8 {{%[^,]+}}, i8* {{%[^,]+}}
+// CHECK: store i32 {{%[^,]+}}, i32* {{%[^,]+}}
+// ... loop body ...
+// End of body: store into a[i]:
+// CHECK: store float [[RESULT:%.+]], float* {{%.+}}
+ a[i] = b[i] * c[i] * d[i];
+// CHECK: [[IV1_2:%.+]] = load i32, i32* [[OMP_IV]]{{.*}}
+// CHECK-NEXT: [[ADD1_2:%.+]] = add nsw i32 [[IV1_2]], 1
+// CHECK-NEXT: store i32 [[ADD1_2]], i32* [[OMP_IV]]
+// CHECK-NEXT: br label %{{.+}}
+ }
+// CHECK: [[LOOP1_END]]
+// CHECK: [[O_LOOP1_END]]
+// CHECK: [[GTID_REF:%.+]] = load i32*, i32** [[GTID_REF_ADDR]],
+// CHECK: [[GTID:%.+]] = load i32, i32* [[GTID_REF]],
+// CHECK: call {{.+}} @__kmpc_cancel_barrier([[IDENT_T_TY]]* [[DEFAULT_LOC_BARRIER:[@%].+]], i32 [[GTID]])
+// CHECK: ret void
+}
+
+// TERM_DEBUG-LABEL: foo
+int foo() {return 0;};
+
+// TERM_DEBUG-LABEL: parallel_for
+void parallel_for(float *a) {
+#pragma omp parallel for schedule(static, 5)
+ // TERM_DEBUG-NOT: __kmpc_global_thread_num
+ // TERM_DEBUG: call void @__kmpc_for_static_init_4u({{.+}}), !dbg [[DBG_LOC_START:![0-9]+]]
+ // TERM_DEBUG: invoke i32 {{.*}}foo{{.*}}()
+ // TERM_DEBUG: unwind label %[[TERM_LPAD:.+]],
+ // TERM_DEBUG-NOT: __kmpc_global_thread_num
+ // TERM_DEBUG: call void @__kmpc_for_static_fini({{.+}}), !dbg [[DBG_LOC_END:![0-9]+]]
+ // TERM_DEBUG: call {{.+}} @__kmpc_cancel_barrier({{.+}}), !dbg [[DBG_LOC_CANCEL:![0-9]+]]
+ // TERM_DEBUG: [[TERM_LPAD]]
+ // TERM_DEBUG: call void @__clang_call_terminate
+ // TERM_DEBUG: unreachable
+ for (unsigned i = 131071; i <= 2147483647; i += 127)
+ a[i] += foo();
+}
+// Check source line corresponds to "#pragma omp parallel for schedule(static, 5)" above:
+// TERM_DEBUG-DAG: [[DBG_LOC_START]] = !MDLocation(line: [[@LINE-4]],
+// TERM_DEBUG-DAG: [[DBG_LOC_END]] = !MDLocation(line: [[@LINE-16]],
+// TERM_DEBUG-DAG: [[DBG_LOC_CANCEL]] = !MDLocation(line: [[@LINE-17]],
+
+#endif // HEADER
+
diff --git a/test/OpenMP/parallel_for_copyin_messages.cpp b/test/OpenMP/parallel_for_copyin_messages.cpp
index 2ebc2de..f1368e9 100644
--- a/test/OpenMP/parallel_for_copyin_messages.cpp
+++ b/test/OpenMP/parallel_for_copyin_messages.cpp
@@ -22,18 +22,18 @@
S3() : a(0) {}
S3 &operator=(S3 &s3) { return *this; }
};
-class S4 { // expected-note {{'S4' declared here}}
+class S4 {
int a;
S4();
- S4 &operator=(const S4 &s4);
+ S4 &operator=(const S4 &s4); // expected-note {{implicitly declared private here}}
public:
S4(int v) : a(v) {}
};
-class S5 { // expected-note {{'S5' declared here}}
+class S5 {
int a;
S5() : a(0) {}
- S5 &operator=(const S5 &s5) { return *this; }
+ S5 &operator=(const S5 &s5) { return *this; } // expected-note {{implicitly declared private here}}
public:
S5(int v) : a(v) {}
@@ -46,10 +46,18 @@
S2 k;
S3 h;
-S4 l(3); // expected-note {{'l' defined here}}
-S5 m(4); // expected-note {{'m' defined here}}
+S4 l(3);
+S5 m(4);
#pragma omp threadprivate(h, k, l, m)
+namespace A {
+double x;
+#pragma omp threadprivate(x)
+}
+namespace B {
+using A::x;
+}
+
int main(int argc, char **argv) {
int i;
#pragma omp parallel for copyin // expected-error {{expected '(' after 'copyin'}}
@@ -70,7 +78,7 @@
#pragma omp parallel for copyin(argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
for (i = 0; i < argc; ++i)
foo();
-#pragma omp parallel for copyin(l) // expected-error {{copyin variable must have an accessible, unambiguous copy assignment operator}}
+#pragma omp parallel for copyin(l) // expected-error {{'operator=' is a private member of 'S4'}}
for (i = 0; i < argc; ++i)
foo();
#pragma omp parallel for copyin(S1) // expected-error {{'S1' does not refer to a value}}
@@ -82,10 +90,10 @@
#pragma omp parallel for copyin(i) // expected-error {{copyin variable must be threadprivate}}
for (i = 0; i < argc; ++i)
foo();
-#pragma omp parallel for copyin(m) // expected-error {{copyin variable must have an accessible, unambiguous copy assignment operator}}
+#pragma omp parallel for copyin(m) // expected-error {{'operator=' is a private member of 'S5'}}
for (i = 0; i < argc; ++i)
foo();
-#pragma omp parallel for copyin(ST < int > ::s) // expected-error {{copyin variable must be threadprivate}}
+#pragma omp parallel for copyin(ST<int>::s, B::x) // expected-error {{copyin variable must be threadprivate}}
for (i = 0; i < argc; ++i)
foo();
diff --git a/test/OpenMP/parallel_for_firstprivate_messages.cpp b/test/OpenMP/parallel_for_firstprivate_messages.cpp
index b495873..37239bc 100644
--- a/test/OpenMP/parallel_for_firstprivate_messages.cpp
+++ b/test/OpenMP/parallel_for_firstprivate_messages.cpp
@@ -137,6 +137,14 @@
return 0;
}
+namespace A {
+double x;
+#pragma omp threadprivate(x) // expected-note {{defined as threadprivate or thread local}}
+}
+namespace B {
+using A::x;
+}
+
int main(int argc, char **argv) {
const int d = 5;
const int da[5] = {0};
@@ -207,7 +215,7 @@
#pragma omp parallel for firstprivate(m) // OK
for (i = 0; i < argc; ++i)
foo();
-#pragma omp parallel for firstprivate(h) // expected-error {{threadprivate or thread local variable cannot be firstprivate}}
+#pragma omp parallel for firstprivate(h, B::x) // expected-error 2 {{threadprivate or thread local variable cannot be firstprivate}}
for (i = 0; i < argc; ++i)
foo();
#pragma omp parallel for private(xa), firstprivate(xa) // expected-error {{private variable cannot be firstprivate}} expected-note {{defined as private}}
diff --git a/test/OpenMP/parallel_for_lastprivate_messages.cpp b/test/OpenMP/parallel_for_lastprivate_messages.cpp
index 915cbf7..6f0945a 100644
--- a/test/OpenMP/parallel_for_lastprivate_messages.cpp
+++ b/test/OpenMP/parallel_for_lastprivate_messages.cpp
@@ -15,15 +15,17 @@
public:
S2() : a(0) {}
S2(S2 &s2) : a(s2.a) {}
+ S2 &operator=(const S2 &);
+ const S2 &operator=(const S2 &) const;
static float S2s;
static const float S2sc;
};
const float S2::S2sc = 0; // expected-note {{static data member is predetermined as shared}}
const S2 b;
const S2 ba[5];
-class S3 { // expected-note 2 {{'S3' declared here}}
+class S3 {
int a;
- S3 &operator=(const S3 &s3);
+ S3 &operator=(const S3 &s3); // expected-note 2 {{implicitly declared private here}}
public:
S3() : a(0) {}
@@ -32,17 +34,17 @@
const S3 c; // expected-note {{global variable is predetermined as shared}}
const S3 ca[5]; // expected-note {{global variable is predetermined as shared}}
extern const int f; // expected-note {{global variable is predetermined as shared}}
-class S4 { // expected-note 3 {{'S4' declared here}}
+class S4 {
int a;
- S4();
+ S4(); // expected-note 3 {{implicitly declared private here}}
S4(const S4 &s4);
public:
S4(int v) : a(v) {}
};
-class S5 { // expected-note {{'S5' declared here}}
+class S5 {
int a;
- S5() : a(0) {}
+ S5() : a(0) {} // expected-note {{implicitly declared private here}}
public:
S5(const S5 &s5) : a(s5.a) {}
@@ -62,8 +64,8 @@
template <class I, class C>
int foomain(int argc, char **argv) {
- I e(4); // expected-note {{'e' defined here}}
- I g(5); // expected-note {{'g' defined here}}
+ I e(4);
+ I g(5);
int i;
int &j = i; // expected-note {{'j' defined here}}
#pragma omp parallel for lastprivate // expected-error {{expected '(' after 'lastprivate'}}
@@ -96,7 +98,7 @@
#pragma omp parallel for lastprivate(argv[1]) // expected-error {{expected variable name}}
for (int k = 0; k < argc; ++k)
++k;
-#pragma omp parallel for lastprivate(e, g) // expected-error 2 {{lastprivate variable must have an accessible, unambiguous default constructor}}
+#pragma omp parallel for lastprivate(e, g) // expected-error 2 {{calling a private constructor of class 'S4'}}
for (int k = 0; k < argc; ++k)
++k;
#pragma omp parallel for lastprivate(h) // expected-error {{threadprivate or thread local variable cannot be lastprivate}}
@@ -126,12 +128,20 @@
return 0;
}
+namespace A {
+double x;
+#pragma omp threadprivate(x) // expected-note {{defined as threadprivate or thread local}}
+}
+namespace B {
+using A::x;
+}
+
int main(int argc, char **argv) {
const int d = 5; // expected-note {{constant variable is predetermined as shared}}
const int da[5] = {0}; // expected-note {{constant variable is predetermined as shared}}
- S4 e(4); // expected-note {{'e' defined here}}
- S5 g(5); // expected-note {{'g' defined here}}
- S3 m; // expected-note 2 {{'m' defined here}}
+ S4 e(4);
+ S5 g(5);
+ S3 m;
S6 n(2);
int i;
int &j = i; // expected-note {{'j' defined here}}
@@ -190,13 +200,13 @@
#pragma omp parallel for safelen(5) // expected-error {{unexpected OpenMP clause 'safelen' in directive '#pragma omp parallel for'}}
for (i = 0; i < argc; ++i)
foo();
-#pragma omp parallel for lastprivate(e, g) // expected-error 2 {{lastprivate variable must have an accessible, unambiguous default constructor}}
+#pragma omp parallel for lastprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
for (i = 0; i < argc; ++i)
foo();
-#pragma omp parallel for lastprivate(m) // expected-error {{lastprivate variable must have an accessible, unambiguous copy assignment operator}}
+#pragma omp parallel for lastprivate(m) // expected-error {{'operator=' is a private member of 'S3'}}
for (i = 0; i < argc; ++i)
foo();
-#pragma omp parallel for lastprivate(h) // expected-error {{threadprivate or thread local variable cannot be lastprivate}}
+#pragma omp parallel for lastprivate(h, B::x) // expected-error 2 {{threadprivate or thread local variable cannot be lastprivate}}
for (i = 0; i < argc; ++i)
foo();
#pragma omp parallel for private(xa), lastprivate(xa) // expected-error {{private variable cannot be lastprivate}} expected-note {{defined as private}}
@@ -216,7 +226,7 @@
#pragma omp parallel for lastprivate(j) // expected-error {{arguments of OpenMP clause 'lastprivate' cannot be of reference type}}
for (i = 0; i < argc; ++i)
foo();
-#pragma omp parallel for firstprivate(m) lastprivate(m) // expected-error {{lastprivate variable must have an accessible, unambiguous copy assignment operator}}
+#pragma omp parallel for firstprivate(m) lastprivate(m) // expected-error {{'operator=' is a private member of 'S3'}}
for (i = 0; i < argc; ++i)
foo();
#pragma omp parallel for lastprivate(n) firstprivate(n) // OK
diff --git a/test/OpenMP/parallel_for_private_messages.cpp b/test/OpenMP/parallel_for_private_messages.cpp
index 31b8458..8d0ba62 100644
--- a/test/OpenMP/parallel_for_private_messages.cpp
+++ b/test/OpenMP/parallel_for_private_messages.cpp
@@ -108,6 +108,14 @@
return 0;
}
+namespace A {
+double x;
+#pragma omp threadprivate(x) // expected-note {{defined as threadprivate or thread local}}
+}
+namespace B {
+using A::x;
+}
+
int main(int argc, char **argv) {
S4 e(4);
S5 g(5);
@@ -146,7 +154,7 @@
#pragma omp parallel for private(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
for (int k = 0; k < argc; ++k)
++k;
-#pragma omp parallel for private(h) // expected-error {{threadprivate or thread local variable cannot be private}}
+#pragma omp parallel for private(h, B::x) // expected-error 2 {{threadprivate or thread local variable cannot be private}}
for (int k = 0; k < argc; ++k)
++k;
#pragma omp parallel for nowait // expected-error {{unexpected OpenMP clause 'nowait' in directive '#pragma omp parallel for'}}
diff --git a/test/OpenMP/parallel_for_reduction_messages.cpp b/test/OpenMP/parallel_for_reduction_messages.cpp
index 676b86f..1f60757 100644
--- a/test/OpenMP/parallel_for_reduction_messages.cpp
+++ b/test/OpenMP/parallel_for_reduction_messages.cpp
@@ -11,7 +11,7 @@
extern S1 a;
class S2 {
mutable int a;
- S2 &operator+=(const S2 &arg) { return (*this); }
+ S2 &operator+(const S2 &arg) { return (*this); } // expected-note 4 {{implicitly declared private here}}
public:
S2() : a(0) {}
@@ -28,17 +28,17 @@
public:
S3() : a(0) {}
S3(const S3 &s3) : a(s3.a) {}
- S3 operator+=(const S3 &arg1) { return arg1; }
+ S3 operator+(const S3 &arg1) { return arg1; }
};
-int operator+=(const S3 &arg1, const S3 &arg2) { return 5; }
+int operator+(const S3 &arg1, const S3 &arg2) { return 5; }
S3 c; // expected-note 2 {{'c' defined here}}
const S3 ca[5]; // expected-note 2 {{'ca' defined here}}
extern const int f; // expected-note 4 {{'f' declared here}}
-class S4 { // expected-note {{'S4' declared here}}
+class S4 {
int a;
- S4();
+ S4(); // expected-note {{implicitly declared private here}}
S4(const S4 &s4);
- S4 &operator+=(const S4 &arg) { return (*this); }
+ S4 &operator+(const S4 &arg) { return (*this); }
public:
S4(int v) : a(v) {}
@@ -46,26 +46,26 @@
S4 &operator&=(S4 &arg1, S4 &arg2) { return arg1; }
class S5 {
int a;
- S5() : a(0) {}
+ S5() : a(0) {} // expected-note {{implicitly declared private here}}
S5(const S5 &s5) : a(s5.a) {}
- S5 &operator+=(const S5 &arg);
+ S5 &operator+(const S5 &arg);
public:
S5(int v) : a(v) {}
};
-class S6 {
+class S6 { // expected-note 2 {{candidate function (the implicit copy assignment operator) not viable: no known conversion from 'int' to 'const S6' for 1st argument}}
int a;
public:
S6() : a(6) {}
operator int() { return 6; }
-} o; // expected-note 2 {{'o' defined here}}
+} o;
S3 h, k;
#pragma omp threadprivate(h) // expected-note 2 {{defined as threadprivate or thread local}}
template <class T> // expected-note {{declared here}}
-T tmain(T argc) { // expected-note 2 {{'argc' defined here}}
+T tmain(T argc) {
const T d = T(); // expected-note 4 {{'d' defined here}}
const T da[5] = {T()}; // expected-note 2 {{'da' defined here}}
T qa[5] = {T()};
@@ -74,7 +74,7 @@
S3 &p = k; // expected-note 2 {{'p' defined here}}
const T &r = da[(int)i]; // expected-note 2 {{'r' defined here}}
T &q = qa[(int)i]; // expected-note 2 {{'q' defined here}}
- T fl; // expected-note {{'fl' defined here}}
+ T fl;
#pragma omp parallel for reduction // expected-error {{expected '(' after 'reduction'}}
for (int i = 0; i < 10; ++i)
foo();
@@ -96,10 +96,10 @@
#pragma omp parallel for reduction(\) // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}}
for (int i = 0; i < 10; ++i)
foo();
-#pragma omp parallel for reduction(& : argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{variable of type 'float' is not valid for specified reduction operation}}
+#pragma omp parallel for reduction(& : argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{invalid operands to binary expression ('float' and 'float')}}
for (int i = 0; i < 10; ++i)
foo();
-#pragma omp parallel for reduction(| : argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{variable of type 'float' is not valid for specified reduction operation}}
+#pragma omp parallel for reduction(| : argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{invalid operands to binary expression ('float' and 'float')}}
for (int i = 0; i < 10; ++i)
foo();
#pragma omp parallel for reduction(|| : argc ? i : argc) // expected-error 2 {{expected variable name}}
@@ -114,7 +114,7 @@
#pragma omp parallel for reduction(^ : T) // expected-error {{'T' does not refer to a value}}
for (int i = 0; i < 10; ++i)
foo();
-#pragma omp parallel for reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 3 {{const-qualified variable cannot be reduction}}
+#pragma omp parallel for reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 3 {{const-qualified variable cannot be reduction}} expected-error 3 {{'operator+' is a private member of 'S2'}}
for (int i = 0; i < 10; ++i)
foo();
#pragma omp parallel for reduction(min : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{arguments of OpenMP clause 'reduction' for 'min' or 'max' must be of arithmetic type}} expected-error 3 {{const-qualified variable cannot be reduction}}
@@ -132,7 +132,7 @@
#pragma omp parallel for reduction(- : da) // expected-error {{a reduction variable with array type 'const int [5]'}} expected-error {{a reduction variable with array type 'const float [5]'}}
for (int i = 0; i < 10; ++i)
foo();
-#pragma omp parallel for reduction(^ : fl) // expected-error {{variable of type 'float' is not valid for specified reduction operation}}
+#pragma omp parallel for reduction(^ : fl) // expected-error {{invalid operands to binary expression ('float' and 'float')}}
for (int i = 0; i < 10; ++i)
foo();
#pragma omp parallel for reduction(&& : S2::S2s)
@@ -144,7 +144,7 @@
#pragma omp parallel for reduction(+ : h, k) // expected-error {{threadprivate or thread local variable cannot be reduction}}
for (int i = 0; i < 10; ++i)
foo();
-#pragma omp parallel for reduction(+ : o) // expected-error {{variable of type 'class S6' is not valid for specified reduction operation}}
+#pragma omp parallel for reduction(+ : o) // expected-error {{no viable overloaded '='}}
for (int i = 0; i < 10; ++i)
foo();
#pragma omp parallel for private(i), reduction(+ : j), reduction(+ : q) // expected-error 4 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}}
@@ -177,18 +177,26 @@
return T();
}
+namespace A {
+double x;
+#pragma omp threadprivate(x) // expected-note {{defined as threadprivate or thread local}}
+}
+namespace B {
+using A::x;
+}
+
int main(int argc, char **argv) {
const int d = 5; // expected-note 2 {{'d' defined here}}
const int da[5] = {0}; // expected-note {{'da' defined here}}
int qa[5] = {0};
- S4 e(4); // expected-note {{'e' defined here}}
- S5 g(5); // expected-note {{'g' defined here}}
+ S4 e(4);
+ S5 g(5);
int i;
int &j = i; // expected-note 2 {{'j' defined here}}
S3 &p = k; // expected-note 2 {{'p' defined here}}
const int &r = da[i]; // expected-note {{'r' defined here}}
int &q = qa[i]; // expected-note {{'q' defined here}}
- float fl; // expected-note {{'fl' defined here}}
+ float fl;
#pragma omp parallel for reduction // expected-error {{expected '(' after 'reduction'}}
for (int i = 0; i < 10; ++i)
foo();
@@ -228,7 +236,7 @@
#pragma omp parallel for reduction(^ : S1) // expected-error {{'S1' does not refer to a value}}
for (int i = 0; i < 10; ++i)
foo();
-#pragma omp parallel for reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{const-qualified variable cannot be reduction}}
+#pragma omp parallel for reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{const-qualified variable cannot be reduction}} expected-error {{'operator+' is a private member of 'S2'}}
for (int i = 0; i < 10; ++i)
foo();
#pragma omp parallel for reduction(min : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{arguments of OpenMP clause 'reduction' for 'min' or 'max' must be of arithmetic type}} expected-error 2 {{const-qualified variable cannot be reduction}}
@@ -246,7 +254,7 @@
#pragma omp parallel for reduction(- : da) // expected-error {{a reduction variable with array type 'const int [5]'}}
for (int i = 0; i < 10; ++i)
foo();
-#pragma omp parallel for reduction(^ : fl) // expected-error {{variable of type 'float' is not valid for specified reduction operation}}
+#pragma omp parallel for reduction(^ : fl) // expected-error {{invalid operands to binary expression ('float' and 'float')}}
for (int i = 0; i < 10; ++i)
foo();
#pragma omp parallel for reduction(&& : S2::S2s)
@@ -255,13 +263,13 @@
#pragma omp parallel for reduction(&& : S2::S2sc) // expected-error {{const-qualified variable cannot be reduction}}
for (int i = 0; i < 10; ++i)
foo();
-#pragma omp parallel for reduction(& : e, g) // expected-error {{reduction variable must have an accessible, unambiguous default constructor}} expected-error {{variable of type 'S5' is not valid for specified reduction operation}}
+#pragma omp parallel for reduction(& : e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{invalid operands to binary expression ('S4' and 'S4')}} expected-error {{calling a private constructor of class 'S5'}} expected-error {{invalid operands to binary expression ('S5' and 'S5')}}
for (int i = 0; i < 10; ++i)
foo();
-#pragma omp parallel for reduction(+ : h, k) // expected-error {{threadprivate or thread local variable cannot be reduction}}
+#pragma omp parallel for reduction(+ : h, k, B::x) // expected-error 2 {{threadprivate or thread local variable cannot be reduction}}
for (int i = 0; i < 10; ++i)
foo();
-#pragma omp parallel for reduction(+ : o) // expected-error {{variable of type 'class S6' is not valid for specified reduction operation}}
+#pragma omp parallel for reduction(+ : o) // expected-error {{no viable overloaded '='}}
for (int i = 0; i < 10; ++i)
foo();
#pragma omp parallel for private(i), reduction(+ : j), reduction(+ : q) // expected-error 2 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}}
diff --git a/test/OpenMP/parallel_for_simd_copyin_messages.cpp b/test/OpenMP/parallel_for_simd_copyin_messages.cpp
index e0b7e63..9ddd92d 100644
--- a/test/OpenMP/parallel_for_simd_copyin_messages.cpp
+++ b/test/OpenMP/parallel_for_simd_copyin_messages.cpp
@@ -22,18 +22,18 @@
S3() : a(0) {}
S3 &operator=(S3 &s3) { return *this; }
};
-class S4 { // expected-note {{'S4' declared here}}
+class S4 {
int a;
S4();
- S4 &operator=(const S4 &s4);
+ S4 &operator=(const S4 &s4); // expected-note {{implicitly declared private here}}
public:
S4(int v) : a(v) {}
};
-class S5 { // expected-note {{'S5' declared here}}
+class S5 {
int a;
S5() : a(0) {}
- S5 &operator=(const S5 &s5) { return *this; }
+ S5 &operator=(const S5 &s5) { return *this; } // expected-note {{implicitly declared private here}}
public:
S5(int v) : a(v) {}
@@ -46,10 +46,18 @@
S2 k;
S3 h;
-S4 l(3); // expected-note {{'l' defined here}}
-S5 m(4); // expected-note {{'m' defined here}}
+S4 l(3);
+S5 m(4);
#pragma omp threadprivate(h, k, l, m)
+namespace A {
+double x;
+#pragma omp threadprivate(x)
+}
+namespace B {
+using A::x;
+}
+
int main(int argc, char **argv) {
int i;
#pragma omp parallel for simd copyin // expected-error {{expected '(' after 'copyin'}}
@@ -70,7 +78,7 @@
#pragma omp parallel for simd copyin(argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
for (i = 0; i < argc; ++i)
foo();
-#pragma omp parallel for simd copyin(l) // expected-error {{copyin variable must have an accessible, unambiguous copy assignment operator}}
+#pragma omp parallel for simd copyin(l) // expected-error {{'operator=' is a private member of 'S4'}}
for (i = 0; i < argc; ++i)
foo();
#pragma omp parallel for simd copyin(S1) // expected-error {{'S1' does not refer to a value}}
@@ -82,10 +90,10 @@
#pragma omp parallel for simd copyin(i) // expected-error {{copyin variable must be threadprivate}}
for (i = 0; i < argc; ++i)
foo();
-#pragma omp parallel for simd copyin(m) // expected-error {{copyin variable must have an accessible, unambiguous copy assignment operator}}
+#pragma omp parallel for simd copyin(m) // expected-error {{'operator=' is a private member of 'S5'}}
for (i = 0; i < argc; ++i)
foo();
-#pragma omp parallel for simd copyin(ST < int > ::s) // expected-error {{copyin variable must be threadprivate}}
+#pragma omp parallel for simd copyin(ST < int > ::s, B::x) // expected-error {{copyin variable must be threadprivate}}
for (i = 0; i < argc; ++i)
foo();
diff --git a/test/OpenMP/parallel_for_simd_firstprivate_messages.cpp b/test/OpenMP/parallel_for_simd_firstprivate_messages.cpp
index 876d422..ef74e3c 100644
--- a/test/OpenMP/parallel_for_simd_firstprivate_messages.cpp
+++ b/test/OpenMP/parallel_for_simd_firstprivate_messages.cpp
@@ -136,6 +136,14 @@
return 0;
}
+namespace A {
+double x;
+#pragma omp threadprivate(x) // expected-note {{defined as threadprivate or thread local}}
+}
+namespace B {
+using A::x;
+}
+
int main(int argc, char **argv) {
const int d = 5;
const int da[5] = {0};
@@ -206,7 +214,7 @@
#pragma omp parallel for simd firstprivate(m) // OK
for (i = 0; i < argc; ++i)
foo();
-#pragma omp parallel for simd firstprivate(h) // expected-error {{threadprivate or thread local variable cannot be firstprivate}}
+#pragma omp parallel for simd firstprivate(h, B::x) // expected-error 2 {{threadprivate or thread local variable cannot be firstprivate}}
for (i = 0; i < argc; ++i)
foo();
#pragma omp parallel for simd private(xa), firstprivate(xa) // expected-error {{private variable cannot be firstprivate}} expected-note {{defined as private}}
diff --git a/test/OpenMP/parallel_for_simd_lastprivate_messages.cpp b/test/OpenMP/parallel_for_simd_lastprivate_messages.cpp
index 3d53259..64d6ccc 100644
--- a/test/OpenMP/parallel_for_simd_lastprivate_messages.cpp
+++ b/test/OpenMP/parallel_for_simd_lastprivate_messages.cpp
@@ -15,15 +15,16 @@
public:
S2() : a(0) {}
S2(S2 &s2) : a(s2.a) {}
+ const S2 &operator=(const S2 &) const;
static float S2s;
static const float S2sc;
};
const float S2::S2sc = 0; // expected-note {{static data member is predetermined as shared}}
const S2 b;
const S2 ba[5];
-class S3 { // expected-note 2 {{'S3' declared here}}
+class S3 {
int a;
- S3 &operator=(const S3 &s3);
+ S3 &operator=(const S3 &s3); // expected-note 2 {{implicitly declared private here}}
public:
S3() : a(0) {}
@@ -32,17 +33,17 @@
const S3 c; // expected-note {{global variable is predetermined as shared}}
const S3 ca[5]; // expected-note {{global variable is predetermined as shared}}
extern const int f; // expected-note {{global variable is predetermined as shared}}
-class S4 { // expected-note 3 {{'S4' declared here}}
+class S4 {
int a;
- S4();
+ S4(); // expected-note 3 {{implicitly declared private here}}
S4(const S4 &s4);
public:
S4(int v) : a(v) {}
};
-class S5 { // expected-note {{'S5' declared here}}
+class S5 {
int a;
- S5() : a(0) {}
+ S5() : a(0) {} // expected-note {{implicitly declared private here}}
public:
S5(const S5 &s5) : a(s5.a) {}
@@ -62,8 +63,8 @@
template <class I, class C>
int foomain(int argc, char **argv) {
- I e(4); // expected-note {{'e' defined here}}
- I g(5); // expected-note {{'g' defined here}}
+ I e(4);
+ I g(5);
int i;
int &j = i; // expected-note {{'j' defined here}}
#pragma omp parallel for simd lastprivate // expected-error {{expected '(' after 'lastprivate'}}
@@ -96,7 +97,7 @@
#pragma omp parallel for simd lastprivate(argv[1]) // expected-error {{expected variable name}}
for (int k = 0; k < argc; ++k)
++k;
-#pragma omp parallel for simd lastprivate(e, g) // expected-error 2 {{lastprivate variable must have an accessible, unambiguous default constructor}}
+#pragma omp parallel for simd lastprivate(e, g) // expected-error 2 {{calling a private constructor of class 'S4'}}
for (int k = 0; k < argc; ++k)
++k;
#pragma omp parallel for simd lastprivate(h) // expected-error {{threadprivate or thread local variable cannot be lastprivate}}
@@ -126,12 +127,20 @@
return 0;
}
+namespace A {
+double x;
+#pragma omp threadprivate(x) // expected-note {{defined as threadprivate or thread local}}
+}
+namespace B {
+using A::x;
+}
+
int main(int argc, char **argv) {
const int d = 5; // expected-note {{constant variable is predetermined as shared}}
const int da[5] = {0}; // expected-note {{constant variable is predetermined as shared}}
- S4 e(4); // expected-note {{'e' defined here}}
- S5 g(5); // expected-note {{'g' defined here}}
- S3 m; // expected-note 2 {{'m' defined here}}
+ S4 e(4);
+ S5 g(5);
+ S3 m;
S6 n(2);
int i;
int &j = i; // expected-note {{'j' defined here}}
@@ -190,13 +199,13 @@
#pragma omp parallel for simd safelen(5)
for (i = 0; i < argc; ++i)
foo();
-#pragma omp parallel for simd lastprivate(e, g) // expected-error 2 {{lastprivate variable must have an accessible, unambiguous default constructor}}
+#pragma omp parallel for simd lastprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
for (i = 0; i < argc; ++i)
foo();
-#pragma omp parallel for simd lastprivate(m) // expected-error {{lastprivate variable must have an accessible, unambiguous copy assignment operator}}
+#pragma omp parallel for simd lastprivate(m) // expected-error {{'operator=' is a private member of 'S3'}}
for (i = 0; i < argc; ++i)
foo();
-#pragma omp parallel for simd lastprivate(h) // expected-error {{threadprivate or thread local variable cannot be lastprivate}}
+#pragma omp parallel for simd lastprivate(h, B::x) // expected-error 2 {{threadprivate or thread local variable cannot be lastprivate}}
for (i = 0; i < argc; ++i)
foo();
#pragma omp parallel for simd private(xa), lastprivate(xa) // expected-error {{private variable cannot be lastprivate}} expected-note {{defined as private}}
@@ -216,7 +225,7 @@
#pragma omp parallel for simd lastprivate(j) // expected-error {{arguments of OpenMP clause 'lastprivate' cannot be of reference type}}
for (i = 0; i < argc; ++i)
foo();
-#pragma omp parallel for simd firstprivate(m) lastprivate(m) // expected-error {{lastprivate variable must have an accessible, unambiguous copy assignment operator}}
+#pragma omp parallel for simd firstprivate(m) lastprivate(m) // expected-error {{'operator=' is a private member of 'S3'}}
for (i = 0; i < argc; ++i)
foo();
#pragma omp parallel for simd lastprivate(n) firstprivate(n) // OK
diff --git a/test/OpenMP/parallel_for_simd_linear_messages.cpp b/test/OpenMP/parallel_for_simd_linear_messages.cpp
index 3918de2..7dcaca0 100644
--- a/test/OpenMP/parallel_for_simd_linear_messages.cpp
+++ b/test/OpenMP/parallel_for_simd_linear_messages.cpp
@@ -148,6 +148,14 @@
return 0;
}
+namespace A {
+double x;
+#pragma omp threadprivate(x) // expected-note {{defined as threadprivate or thread local}}
+}
+namespace C {
+using A::x;
+}
+
int main(int argc, char **argv) {
double darr[100];
// expected-note@+1 {{in instantiation of function template specialization 'test_template<-4, double, int>' requested here}}
@@ -185,7 +193,7 @@
// expected-error@+1 {{argument of a linear clause should be of integral or pointer type, not 'S5'}}
#pragma omp parallel for simd linear(e, g)
for (int k = 0; k < argc; ++k) ++k;
- #pragma omp parallel for simd linear(h) // expected-error {{threadprivate or thread local variable cannot be linear}}
+ #pragma omp parallel for simd linear(h, C::x) // expected-error 2 {{threadprivate or thread local variable cannot be linear}}
for (int k = 0; k < argc; ++k) ++k;
#pragma omp parallel
{
diff --git a/test/OpenMP/parallel_for_simd_private_messages.cpp b/test/OpenMP/parallel_for_simd_private_messages.cpp
index 67d8813..f2719d9 100644
--- a/test/OpenMP/parallel_for_simd_private_messages.cpp
+++ b/test/OpenMP/parallel_for_simd_private_messages.cpp
@@ -108,6 +108,14 @@
return 0;
}
+namespace A {
+double x;
+#pragma omp threadprivate(x) // expected-note {{defined as threadprivate or thread local}}
+}
+namespace B {
+using A::x;
+}
+
int main(int argc, char **argv) {
S4 e(4);
S5 g(5);
@@ -146,7 +154,7 @@
#pragma omp parallel for simd private(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
for (int k = 0; k < argc; ++k)
++k;
-#pragma omp parallel for simd private(h) // expected-error {{threadprivate or thread local variable cannot be private}}
+#pragma omp parallel for simd private(h, B::x) // expected-error 2 {{threadprivate or thread local variable cannot be private}}
for (int k = 0; k < argc; ++k)
++k;
#pragma omp parallel for simd nowait // expected-error {{unexpected OpenMP clause 'nowait' in directive '#pragma omp parallel for simd'}}
diff --git a/test/OpenMP/parallel_for_simd_reduction_messages.cpp b/test/OpenMP/parallel_for_simd_reduction_messages.cpp
index 2395cbd..f92a9cc 100644
--- a/test/OpenMP/parallel_for_simd_reduction_messages.cpp
+++ b/test/OpenMP/parallel_for_simd_reduction_messages.cpp
@@ -11,7 +11,7 @@
extern S1 a;
class S2 {
mutable int a;
- S2 &operator+=(const S2 &arg) { return (*this); }
+ S2 &operator+(const S2 &arg) { return (*this); } // expected-note 4 {{implicitly declared private here}}
public:
S2() : a(0) {}
@@ -28,17 +28,17 @@
public:
S3() : a(0) {}
S3(const S3 &s3) : a(s3.a) {}
- S3 operator+=(const S3 &arg1) { return arg1; }
+ S3 operator+(const S3 &arg1) { return arg1; }
};
-int operator+=(const S3 &arg1, const S3 &arg2) { return 5; }
+int operator+(const S3 &arg1, const S3 &arg2) { return 5; }
S3 c; // expected-note 2 {{'c' defined here}}
const S3 ca[5]; // expected-note 2 {{'ca' defined here}}
extern const int f; // expected-note 4 {{'f' declared here}}
-class S4 { // expected-note {{'S4' declared here}}
+class S4 {
int a;
- S4();
+ S4(); // expected-note {{implicitly declared private here}}
S4(const S4 &s4);
- S4 &operator+=(const S4 &arg) { return (*this); }
+ S4 &operator+(const S4 &arg) { return (*this); }
public:
S4(int v) : a(v) {}
@@ -46,26 +46,26 @@
S4 &operator&=(S4 &arg1, S4 &arg2) { return arg1; }
class S5 {
int a;
- S5() : a(0) {}
+ S5() : a(0) {} // expected-note {{implicitly declared private here}}
S5(const S5 &s5) : a(s5.a) {}
- S5 &operator+=(const S5 &arg);
+ S5 &operator+(const S5 &arg);
public:
S5(int v) : a(v) {}
};
-class S6 {
+class S6 { // expected-note 2 {{candidate function (the implicit copy assignment operator) not viable: no known conversion from 'int' to 'const S6' for 1st argument}}
int a;
public:
S6() : a(6) {}
operator int() { return 6; }
-} o; // expected-note 2 {{'o' defined here}}
+} o;
S3 h, k;
#pragma omp threadprivate(h) // expected-note 2 {{defined as threadprivate or thread local}}
template <class T> // expected-note {{declared here}}
-T tmain(T argc) { // expected-note 2 {{'argc' defined here}}
+T tmain(T argc) {
const T d = T(); // expected-note 4 {{'d' defined here}}
const T da[5] = {T()}; // expected-note 2 {{'da' defined here}}
T qa[5] = {T()};
@@ -74,7 +74,7 @@
S3 &p = k; // expected-note 2 {{'p' defined here}}
const T &r = da[(int)i]; // expected-note 2 {{'r' defined here}}
T &q = qa[(int)i]; // expected-note 2 {{'q' defined here}}
- T fl; // expected-note {{'fl' defined here}}
+ T fl;
#pragma omp parallel for simd reduction // expected-error {{expected '(' after 'reduction'}}
for (int i = 0; i < 10; ++i)
foo();
@@ -96,10 +96,10 @@
#pragma omp parallel for simd reduction(\) // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}}
for (int i = 0; i < 10; ++i)
foo();
-#pragma omp parallel for simd reduction(& : argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{variable of type 'float' is not valid for specified reduction operation}}
+#pragma omp parallel for simd reduction(& : argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{invalid operands to binary expression ('float' and 'float')}}
for (int i = 0; i < 10; ++i)
foo();
-#pragma omp parallel for simd reduction(| : argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{variable of type 'float' is not valid for specified reduction operation}}
+#pragma omp parallel for simd reduction(| : argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{invalid operands to binary expression ('float' and 'float')}}
for (int i = 0; i < 10; ++i)
foo();
#pragma omp parallel for simd reduction(|| : argc ? i : argc) // expected-error 2 {{expected variable name}}
@@ -114,7 +114,7 @@
#pragma omp parallel for simd reduction(^ : T) // expected-error {{'T' does not refer to a value}}
for (int i = 0; i < 10; ++i)
foo();
-#pragma omp parallel for simd reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 3 {{const-qualified variable cannot be reduction}}
+#pragma omp parallel for simd reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 3 {{const-qualified variable cannot be reduction}} expected-error 3 {{'operator+' is a private member of 'S2'}}
for (int i = 0; i < 10; ++i)
foo();
#pragma omp parallel for simd reduction(min : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{arguments of OpenMP clause 'reduction' for 'min' or 'max' must be of arithmetic type}} expected-error 3 {{const-qualified variable cannot be reduction}}
@@ -132,7 +132,7 @@
#pragma omp parallel for simd reduction(- : da) // expected-error {{a reduction variable with array type 'const int [5]'}} expected-error {{a reduction variable with array type 'const float [5]'}}
for (int i = 0; i < 10; ++i)
foo();
-#pragma omp parallel for simd reduction(^ : fl) // expected-error {{variable of type 'float' is not valid for specified reduction operation}}
+#pragma omp parallel for simd reduction(^ : fl) // expected-error {{invalid operands to binary expression ('float' and 'float')}}
for (int i = 0; i < 10; ++i)
foo();
#pragma omp parallel for simd reduction(&& : S2::S2s)
@@ -144,7 +144,7 @@
#pragma omp parallel for simd reduction(+ : h, k) // expected-error {{threadprivate or thread local variable cannot be reduction}}
for (int i = 0; i < 10; ++i)
foo();
-#pragma omp parallel for simd reduction(+ : o) // expected-error {{variable of type 'class S6' is not valid for specified reduction operation}}
+#pragma omp parallel for simd reduction(+ : o) // expected-error {{no viable overloaded '='}}
for (int i = 0; i < 10; ++i)
foo();
#pragma omp parallel for simd private(i), reduction(+ : j), reduction(+ : q) // expected-error 4 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}}
@@ -177,18 +177,26 @@
return T();
}
+namespace A {
+double x;
+#pragma omp threadprivate(x) // expected-note {{defined as threadprivate or thread local}}
+}
+namespace B {
+using A::x;
+}
+
int main(int argc, char **argv) {
const int d = 5; // expected-note 2 {{'d' defined here}}
const int da[5] = {0}; // expected-note {{'da' defined here}}
int qa[5] = {0};
- S4 e(4); // expected-note {{'e' defined here}}
- S5 g(5); // expected-note {{'g' defined here}}
+ S4 e(4);
+ S5 g(5);
int i;
int &j = i; // expected-note 2 {{'j' defined here}}
S3 &p = k; // expected-note 2 {{'p' defined here}}
const int &r = da[i]; // expected-note {{'r' defined here}}
int &q = qa[i]; // expected-note {{'q' defined here}}
- float fl; // expected-note {{'fl' defined here}}
+ float fl;
#pragma omp parallel for simd reduction // expected-error {{expected '(' after 'reduction'}}
for (int i = 0; i < 10; ++i)
foo();
@@ -228,7 +236,7 @@
#pragma omp parallel for simd reduction(^ : S1) // expected-error {{'S1' does not refer to a value}}
for (int i = 0; i < 10; ++i)
foo();
-#pragma omp parallel for simd reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{const-qualified variable cannot be reduction}}
+#pragma omp parallel for simd reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{const-qualified variable cannot be reduction}} expected-error {{'operator+' is a private member of 'S2'}}
for (int i = 0; i < 10; ++i)
foo();
#pragma omp parallel for simd reduction(min : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{arguments of OpenMP clause 'reduction' for 'min' or 'max' must be of arithmetic type}} expected-error 2 {{const-qualified variable cannot be reduction}}
@@ -246,7 +254,7 @@
#pragma omp parallel for simd reduction(- : da) // expected-error {{a reduction variable with array type 'const int [5]'}}
for (int i = 0; i < 10; ++i)
foo();
-#pragma omp parallel for simd reduction(^ : fl) // expected-error {{variable of type 'float' is not valid for specified reduction operation}}
+#pragma omp parallel for simd reduction(^ : fl) // expected-error {{invalid operands to binary expression ('float' and 'float')}}
for (int i = 0; i < 10; ++i)
foo();
#pragma omp parallel for simd reduction(&& : S2::S2s)
@@ -255,13 +263,13 @@
#pragma omp parallel for simd reduction(&& : S2::S2sc) // expected-error {{const-qualified variable cannot be reduction}}
for (int i = 0; i < 10; ++i)
foo();
-#pragma omp parallel for simd reduction(& : e, g) // expected-error {{reduction variable must have an accessible, unambiguous default constructor}} expected-error {{variable of type 'S5' is not valid for specified reduction operation}}
+#pragma omp parallel for simd reduction(& : e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{invalid operands to binary expression ('S4' and 'S4')}} expected-error {{calling a private constructor of class 'S5'}} expected-error {{invalid operands to binary expression ('S5' and 'S5')}}
for (int i = 0; i < 10; ++i)
foo();
-#pragma omp parallel for simd reduction(+ : h, k) // expected-error {{threadprivate or thread local variable cannot be reduction}}
+#pragma omp parallel for simd reduction(+ : h, k, B::x) // expected-error 2 {{threadprivate or thread local variable cannot be reduction}}
for (int i = 0; i < 10; ++i)
foo();
-#pragma omp parallel for simd reduction(+ : o) // expected-error {{variable of type 'class S6' is not valid for specified reduction operation}}
+#pragma omp parallel for simd reduction(+ : o) // expected-error {{no viable overloaded '='}}
for (int i = 0; i < 10; ++i)
foo();
#pragma omp parallel for simd private(i), reduction(+ : j), reduction(+ : q) // expected-error 2 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}}
diff --git a/test/OpenMP/parallel_if_codegen.cpp b/test/OpenMP/parallel_if_codegen.cpp
index 256f410..7f67dce 100644
--- a/test/OpenMP/parallel_if_codegen.cpp
+++ b/test/OpenMP/parallel_if_codegen.cpp
@@ -16,7 +16,7 @@
// CHECK-LABEL: define void @{{.+}}gtid_test
void gtid_test() {
-// CHECK: call void {{.+}}* @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{.+}} 1, {{.+}}* [[GTID_TEST_REGION1:@.+]] to void
+// CHECK: call void {{.+}} @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{.+}} 1, {{.+}}* [[GTID_TEST_REGION1:@.+]] to void
#pragma omp parallel
#pragma omp parallel if (false)
gtid_test();
diff --git a/test/OpenMP/parallel_num_threads_codegen.cpp b/test/OpenMP/parallel_num_threads_codegen.cpp
index f4f7038..4026d88 100644
--- a/test/OpenMP/parallel_num_threads_codegen.cpp
+++ b/test/OpenMP/parallel_num_threads_codegen.cpp
@@ -48,11 +48,11 @@
// CHECK: [[S_CHAR_OP:%.+]] = invoke{{.*}} i8 [[S_TY_CHAR_OP:@.+]]([[S_TY]]* [[S_ADDR]])
// CHECK: store i8 [[S_CHAR_OP]], i8* [[A_ADDR]]
// CHECK: call void @__kmpc_push_num_threads([[IDENT_T_TY]]* [[DEF_LOC_2]], i32 [[GTID]], i32 2)
-// CHECK: call void {{.*}}* @__kmpc_fork_call(
+// CHECK: call void {{.*}} @__kmpc_fork_call(
// CHECK: [[A_VAL:%.+]] = load i8, i8* [[A_ADDR]]
// CHECK: [[RES:%.+]] = sext i8 [[A_VAL]] to i32
// CHECK: call void @__kmpc_push_num_threads([[IDENT_T_TY]]* [[DEF_LOC_2]], i32 [[GTID]], i32 [[RES]])
-// CHECK: call void {{.*}}* @__kmpc_fork_call(
+// CHECK: call void {{.*}} @__kmpc_fork_call(
// CHECK: invoke{{.*}} [[INT_TY:i[0-9]+]] [[TMAIN_CHAR_5:@.+]]()
// CHECK: invoke{{.*}} [[INT_TY]] [[TMAIN_S_1:@.+]]()
// CHECK: call {{.*}} [[S_TY_DESTR:@.+]]([[S_TY]]* [[S_ADDR]])
@@ -62,22 +62,22 @@
// CHECK: define{{.*}} [[INT_TY]] [[TMAIN_CHAR_5]]()
// CHECK: [[GTID:%.+]] = call i32 @__kmpc_global_thread_num([[IDENT_T_TY]]* [[DEF_LOC_2]])
// CHECK: call void @__kmpc_push_num_threads([[IDENT_T_TY]]* [[DEF_LOC_2]], i32 [[GTID]], i32 5)
-// CHECK: call void {{.*}}* @__kmpc_fork_call(
+// CHECK: call void {{.*}} @__kmpc_fork_call(
// CHECK: call void @__kmpc_push_num_threads([[IDENT_T_TY]]* [[DEF_LOC_2]], i32 [[GTID]], i32 23)
-// CHECK: call void {{.*}}* @__kmpc_fork_call(
+// CHECK: call void {{.*}} @__kmpc_fork_call(
// CHECK: ret [[INT_TY]] 0
// CHECK-NEXT: }
// CHECK: define{{.*}} [[INT_TY]] [[TMAIN_S_1]]()
// CHECK: [[GTID:%.+]] = call i32 @__kmpc_global_thread_num([[IDENT_T_TY]]* [[DEF_LOC_2]])
// CHECK: call void @__kmpc_push_num_threads([[IDENT_T_TY]]* [[DEF_LOC_2]], i32 [[GTID]], i32 1)
-// CHECK: call void {{.*}}* @__kmpc_fork_call(
+// CHECK: call void {{.*}} @__kmpc_fork_call(
// CHECK: call {{.*}} [[S_TY_CONSTR]]([[S_TY]]* [[S_TEMP:%.+]], [[INTPTR_T_TY]] [[INTPTR_T_TY_ATTR]]23)
// CHECK: [[S_CHAR_OP:%.+]] = invoke{{.*}} i8 [[S_TY_CHAR_OP]]([[S_TY]]* [[S_TEMP]])
// CHECK: [[RES:%.+]] = sext {{.*}}i8 [[S_CHAR_OP]] to i32
// CHECK: call void @__kmpc_push_num_threads([[IDENT_T_TY]]* [[DEF_LOC_2]], i32 [[GTID]], i32 [[RES]])
// CHECK: call {{.*}} [[S_TY_DESTR]]([[S_TY]]* [[S_TEMP]])
-// CHECK: call void {{.*}}* @__kmpc_fork_call(
+// CHECK: call void {{.*}} @__kmpc_fork_call(
// CHECK: ret [[INT_TY]] 0
// CHECK: }
diff --git a/test/OpenMP/parallel_private_codegen.cpp b/test/OpenMP/parallel_private_codegen.cpp
index 7094e4f..0744c8c 100644
--- a/test/OpenMP/parallel_private_codegen.cpp
+++ b/test/OpenMP/parallel_private_codegen.cpp
@@ -22,7 +22,6 @@
// CHECK: [[CAP_MAIN_TY:%.+]] = type { [2 x i{{[0-9]+}}]*, i{{[0-9]+}}*, [2 x [[S_FLOAT_TY]]]*, [[S_FLOAT_TY]]* }
// CHECK: [[S_INT_TY:%.+]] = type { i{{[0-9]+}} }
// CHECK: [[CAP_TMAIN_TY:%.+]] = type { [2 x i{{[0-9]+}}]*, i{{[0-9]+}}*, [2 x [[S_INT_TY]]]*, [[S_INT_TY]]* }
-// CHECK: [[IMPLICIT_BARRIER_LOC:@.+]] = private unnamed_addr constant %{{.+}} { i32 0, i32 66, i32 0, i32 0, i8*
template <typename T>
T tmain() {
S<T> test;
@@ -42,24 +41,23 @@
#ifdef LAMBDA
// LAMBDA: [[G:@.+]] = global i{{[0-9]+}} 1212,
// LAMBDA-LABEL: @main
- // LAMBDA: call void [[OUTER_LAMBDA:@.+]](
+ // LAMBDA: call{{( x86_thiscallcc)?}} void [[OUTER_LAMBDA:@.+]](
[&]() {
// LAMBDA: define{{.*}} internal{{.*}} void [[OUTER_LAMBDA]](
// LAMBDA: [[G_LOCAL_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[AGG_CAPTURED:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
// LAMBDA: store i{{[0-9]+}}* [[G]], i{{[0-9]+}}** [[G_LOCAL_REF]]
// LAMBDA: [[ARG:%.+]] = bitcast %{{.+}}* [[AGG_CAPTURED]] to i8*
- // LAMBDA: call void {{.+}}* @__kmpc_fork_call({{.+}}, i32 1, {{.+}}* [[OMP_REGION:@.+]] to {{.+}}, i8* [[ARG]])
+ // LAMBDA: call void {{.+}} @__kmpc_fork_call({{.+}}, i32 1, {{.+}}* [[OMP_REGION:@.+]] to {{.+}}, i8* [[ARG]])
#pragma omp parallel private(g)
{
// LAMBDA: define{{.*}} internal{{.*}} void [[OMP_REGION]](i32* %{{.+}}, i32* %{{.+}}, %{{.+}}* [[ARG:%.+]])
// LAMBDA: [[G_PRIVATE_ADDR:%.+]] = alloca i{{[0-9]+}},
// LAMBDA: store %{{.+}}* [[ARG]], %{{.+}}** [[ARG_REF:%.+]],
- // LAMBDA: call i32 @__kmpc_cancel_barrier(
g = 1;
// LAMBDA: store volatile i{{[0-9]+}} 1, i{{[0-9]+}}* [[G_PRIVATE_ADDR]],
// LAMBDA: [[G_PRIVATE_ADDR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
// LAMBDA: store i{{[0-9]+}}* [[G_PRIVATE_ADDR]], i{{[0-9]+}}** [[G_PRIVATE_ADDR_REF]]
- // LAMBDA: call void [[INNER_LAMBDA:@.+]](%{{.+}}* [[ARG]])
+ // LAMBDA: call{{( x86_thiscallcc)?}} void [[INNER_LAMBDA:@.+]](%{{.+}}* [[ARG]])
[&]() {
// LAMBDA: define {{.+}} void [[INNER_LAMBDA]](%{{.+}}* [[ARG_PTR:%.+]])
// LAMBDA: store %{{.+}}* [[ARG_PTR]], %{{.+}}** [[ARG_PTR_REF:%.+]],
@@ -75,25 +73,24 @@
#elif defined(BLOCKS)
// BLOCKS: [[G:@.+]] = global i{{[0-9]+}} 1212,
// BLOCKS-LABEL: @main
- // BLOCKS: call void {{%.+}}(i8*
+ // BLOCKS: call void {{%.+}}(i8
^{
// BLOCKS: define{{.*}} internal{{.*}} void {{.+}}(i8*
// BLOCKS: [[G_LOCAL_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[AGG_CAPTURED:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
// BLOCKS: store i{{[0-9]+}}* [[G]], i{{[0-9]+}}** [[G_LOCAL_REF]]
// BLOCKS: [[ARG:%.+]] = bitcast %{{.+}}* [[AGG_CAPTURED]] to i8*
- // BLOCKS: call void {{.+}}* @__kmpc_fork_call({{.+}}, i32 1, {{.+}}* [[OMP_REGION:@.+]] to {{.+}}, i8* [[ARG]])
+ // BLOCKS: call void {{.+}} @__kmpc_fork_call({{.+}}, i32 1, {{.+}}* [[OMP_REGION:@.+]] to {{.+}}, i8* [[ARG]])
#pragma omp parallel private(g)
{
// BLOCKS: define{{.*}} internal{{.*}} void [[OMP_REGION]](i32* %{{.+}}, i32* %{{.+}}, %{{.+}}* [[ARG:%.+]])
// BLOCKS: [[G_PRIVATE_ADDR:%.+]] = alloca i{{[0-9]+}},
// BLOCKS: store %{{.+}}* [[ARG]], %{{.+}}** [[ARG_REF:%.+]],
- // BLOCKS: call i32 @__kmpc_cancel_barrier(
g = 1;
// BLOCKS: store volatile i{{[0-9]+}} 1, i{{[0-9]+}}* [[G_PRIVATE_ADDR]],
// BLOCKS-NOT: [[G]]{{[[^:word:]]}}
// BLOCKS: i{{[0-9]+}}* [[G_PRIVATE_ADDR]]
// BLOCKS-NOT: [[G]]{{[[^:word:]]}}
- // BLOCKS: call void {{%.+}}(i8*
+ // BLOCKS: call void {{%.+}}(i8
^{
// BLOCKS: define {{.+}} void {{@.+}}(i8*
g = 2;
@@ -124,7 +121,7 @@
// CHECK: [[TEST:%.+]] = alloca [[S_FLOAT_TY]],
// CHECK: call {{.*}} [[S_FLOAT_TY_DEF_CONSTR:@.+]]([[S_FLOAT_TY]]* [[TEST]])
// CHECK: %{{.+}} = bitcast [[CAP_MAIN_TY]]*
-// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...)* @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [[CAP_MAIN_TY]]*)* [[MAIN_MICROTASK:@.+]] to void
+// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [[CAP_MAIN_TY]]*)* [[MAIN_MICROTASK:@.+]] to void
// CHECK: = call i{{.+}} [[TMAIN_INT:@.+]]()
// CHECK: call void [[S_FLOAT_TY_DESTR:@.+]]([[S_FLOAT_TY]]*
// CHECK: ret
@@ -143,9 +140,6 @@
// CHECK-NOT: [[T_VAR_PRIV]]
// CHECK-NOT: [[VEC_PRIV]]
// CHECK: call {{.*}} [[S_FLOAT_TY_DEF_CONSTR]]([[S_FLOAT_TY]]* [[VAR_PRIV]])
-// CHECK: [[GTID_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[GTID_ADDR_REF]]
-// CHECK: [[GTID:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[GTID_REF]]
-// CHECK: call i32 @__kmpc_cancel_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]], i{{[0-9]+}} [[GTID]])
// CHECK-DAG: call void [[S_FLOAT_TY_DESTR]]([[S_FLOAT_TY]]* [[VAR_PRIV]])
// CHECK-DAG: call void [[S_FLOAT_TY_DESTR]]([[S_FLOAT_TY]]*
// CHECK: ret void
@@ -153,7 +147,7 @@
// CHECK: define {{.*}} i{{[0-9]+}} [[TMAIN_INT]]()
// CHECK: [[TEST:%.+]] = alloca [[S_INT_TY]],
// CHECK: call {{.*}} [[S_INT_TY_DEF_CONSTR:@.+]]([[S_INT_TY]]* [[TEST]])
-// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...)* @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [[CAP_TMAIN_TY]]*)* [[TMAIN_MICROTASK:@.+]] to void
+// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [[CAP_TMAIN_TY]]*)* [[TMAIN_MICROTASK:@.+]] to void
// CHECK: call void [[S_INT_TY_DESTR:@.+]]([[S_INT_TY]]*
// CHECK: ret
//
@@ -171,9 +165,6 @@
// CHECK-NOT: [[T_VAR_PRIV]]
// CHECK-NOT: [[VEC_PRIV]]
// CHECK: call {{.*}} [[S_INT_TY_DEF_CONSTR]]([[S_INT_TY]]* [[VAR_PRIV]])
-// CHECK: [[GTID_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[GTID_ADDR_REF]]
-// CHECK: [[GTID:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[GTID_REF]]
-// CHECK: call i32 @__kmpc_cancel_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]], i{{[0-9]+}} [[GTID]])
// CHECK-DAG: call void [[S_INT_TY_DESTR]]([[S_INT_TY]]* [[VAR_PRIV]])
// CHECK-DAG: call void [[S_INT_TY_DESTR]]([[S_INT_TY]]*
// CHECK: ret void
diff --git a/test/OpenMP/parallel_private_messages.cpp b/test/OpenMP/parallel_private_messages.cpp
index 74949ba..850b403 100644
--- a/test/OpenMP/parallel_private_messages.cpp
+++ b/test/OpenMP/parallel_private_messages.cpp
@@ -41,6 +41,14 @@
int threadvar;
#pragma omp threadprivate(threadvar) // expected-note {{defined as threadprivate or thread local}}
+namespace A {
+double x;
+#pragma omp threadprivate(x) // expected-note {{defined as threadprivate or thread local}}
+}
+namespace B {
+using A::x;
+}
+
int main(int argc, char **argv) {
const int d = 5; // expected-note {{constant variable is predetermined as shared}}
const int da[5] = { 0 }; // expected-note {{constant variable is predetermined as shared}}
@@ -63,7 +71,7 @@
#pragma omp parallel private(da) // expected-error {{shared variable cannot be private}}
#pragma omp parallel private(S2::S2s)
#pragma omp parallel private(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
- #pragma omp parallel private(threadvar) // expected-error {{threadprivate or thread local variable cannot be private}}
+ #pragma omp parallel private(threadvar, B::x) // expected-error 2 {{threadprivate or thread local variable cannot be private}}
#pragma omp parallel shared(i), private(i) // expected-error {{shared variable cannot be private}} expected-note {{defined as shared}}
foo();
#pragma omp parallel firstprivate(i) private(i) // expected-error {{firstprivate variable cannot be private}} expected-note {{defined as firstprivate}}
diff --git a/test/OpenMP/parallel_reduction_codegen.cpp b/test/OpenMP/parallel_reduction_codegen.cpp
new file mode 100644
index 0000000..0c00e26
--- /dev/null
+++ b/test/OpenMP/parallel_reduction_codegen.cpp
@@ -0,0 +1,697 @@
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -x c++ -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -std=c++11 -triple x86_64-apple-darwin10 -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -triple x86_64-apple-darwin10 -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -x c++ -std=c++11 -DLAMBDA -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck -check-prefix=LAMBDA %s
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -x c++ -fblocks -DBLOCKS -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck -check-prefix=BLOCKS %s
+// expected-no-diagnostics
+#ifndef HEADER
+#define HEADER
+
+volatile int g = 1212;
+
+template <class T>
+struct S {
+ T f;
+ S(T a) : f(a + g) {}
+ S() : f(g) {}
+ operator T() { return T(); }
+ S &operator&(const S &) { return *this; }
+ ~S() {}
+};
+
+// CHECK-DAG: [[S_FLOAT_TY:%.+]] = type { float }
+// CHECK-DAG: [[S_INT_TY:%.+]] = type { i{{[0-9]+}} }
+// CHECK-DAG: [[CAP_MAIN_TY:%.+]] = type { [2 x i{{[0-9]+}}]*, float*, [2 x [[S_FLOAT_TY]]]*, [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]*, float* }
+// CHECK-DAG: [[CAP_TMAIN_TY:%.+]] = type { [2 x i{{[0-9]+}}]*, i{{[0-9]+}}*, [2 x [[S_INT_TY]]]*, [[S_INT_TY]]*, [[S_INT_TY]]*, i{{[0-9]+}}* }
+// CHECK-DAG: [[IMPLICIT_BARRIER_LOC:@.+]] = private unnamed_addr constant %{{.+}} { i32 0, i32 66, i32 0, i32 0, i8*
+// CHECK-DAG: [[REDUCTION_LOC:@.+]] = private unnamed_addr constant %{{.+}} { i32 0, i32 18, i32 0, i32 0, i8*
+// CHECK-DAG: [[REDUCTION_LOCK:@.+]] = common global [8 x i32] zeroinitializer
+
+template <typename T>
+T tmain() {
+ T t;
+ S<T> test;
+ T t_var = T(), t_var1;
+ T vec[] = {1, 2};
+ S<T> s_arr[] = {1, 2};
+ S<T> var(3), var1;
+#pragma omp parallel reduction(+:t_var) reduction(&:var) reduction(&& : var1) reduction(min: t_var1)
+ {
+ vec[0] = t_var;
+ s_arr[0] = var;
+ }
+ return T();
+}
+
+int main() {
+#ifdef LAMBDA
+ // LAMBDA: [[G:@.+]] = global i{{[0-9]+}} 1212,
+ // LAMBDA-LABEL: @main
+ // LAMBDA: call void [[OUTER_LAMBDA:@.+]](
+ [&]() {
+ // LAMBDA: define{{.*}} internal{{.*}} void [[OUTER_LAMBDA]](
+ // LAMBDA: [[G_LOCAL_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[AGG_CAPTURED:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // LAMBDA: store i{{[0-9]+}}* [[G]], i{{[0-9]+}}** [[G_LOCAL_REF]]
+ // LAMBDA: [[ARG:%.+]] = bitcast %{{.+}}* [[AGG_CAPTURED]] to i8*
+ // LAMBDA: call void {{.+}} @__kmpc_fork_call({{.+}}, i32 1, {{.+}}* [[OMP_REGION:@.+]] to {{.+}}, i8* [[ARG]])
+#pragma omp parallel reduction(+:g)
+ {
+ // LAMBDA: define{{.*}} internal{{.*}} void [[OMP_REGION]](i32* %{{.+}}, i32* %{{.+}}, %{{.+}}* [[ARG:%.+]])
+ // LAMBDA: [[G_PRIVATE_ADDR:%.+]] = alloca i{{[0-9]+}},
+
+ // Reduction list for runtime.
+ // LAMBDA: [[RED_LIST:%.+]] = alloca [1 x i8*],
+
+ // LAMBDA: store %{{.+}}* [[ARG]], %{{.+}}** [[ARG_REF:%.+]],
+ // LAMBDA: [[ARG:%.+]] = load %{{.+}}*, %{{.+}}** [[ARG_REF]]
+ // LAMBDA: [[G_REF_ADDR:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // LAMBDA: [[G_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[G_REF_ADDR]]
+ // LAMBDA: store i{{[0-9]+}} 0, i{{[0-9]+}}* [[G_PRIVATE_ADDR]]
+ g = 1;
+ // LAMBDA: store volatile i{{[0-9]+}} 1, i{{[0-9]+}}* [[G_PRIVATE_ADDR]],
+ // LAMBDA: [[G_PRIVATE_ADDR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // LAMBDA: store i{{[0-9]+}}* [[G_PRIVATE_ADDR]], i{{[0-9]+}}** [[G_PRIVATE_ADDR_REF]]
+ // LAMBDA: call void [[INNER_LAMBDA:@.+]](%{{.+}}* [[ARG]])
+
+ // LAMBDA: [[G_PRIV_REF:%.+]] = getelementptr inbounds [1 x i8*], [1 x i8*]* [[RED_LIST]], i32 0, i32 0
+ // LAMBDA: [[BITCAST:%.+]] = bitcast i32* [[G_PRIVATE_ADDR]] to i8*
+ // LAMBDA: store i8* [[BITCAST]], i8** [[G_PRIV_REF]],
+ // LAMBDA: call i32 @__kmpc_reduce_nowait(
+ // LAMBDA: switch i32 %{{.+}}, label %[[REDUCTION_DONE:.+]] [
+ // LAMBDA: i32 1, label %[[CASE1:.+]]
+ // LAMBDA: i32 2, label %[[CASE2:.+]]
+ // LAMBDA: [[CASE1]]
+ // LAMBDA: [[G_VAL:%.+]] = load i32, i32* [[G_REF]]
+ // LAMBDA: [[G_PRIV_VAL:%.+]] = load i32, i32* [[G_PRIVATE_ADDR]]
+ // LAMBDA: [[ADD:%.+]] = add nsw i32 [[G_VAL]], [[G_PRIV_VAL]]
+ // LAMBDA: store i32 [[ADD]], i32* [[G_REF]]
+ // LAMBDA: call void @__kmpc_end_reduce_nowait(
+ // LAMBDA: br label %[[REDUCTION_DONE]]
+ // LAMBDA: [[CASE2]]
+ // LAMBDA: [[G_PRIV_VAL:%.+]] = load i32, i32* [[G_PRIVATE_ADDR]]
+ // LAMBDA: atomicrmw add i32* [[G_REF]], i32 [[G_PRIV_VAL]] monotonic
+ // LAMBDA: br label %[[REDUCTION_DONE]]
+ // LAMBDA: [[REDUCTION_DONE]]
+ // LAMBDA: ret void
+ [&]() {
+ // LAMBDA: define {{.+}} void [[INNER_LAMBDA]](%{{.+}}* [[ARG_PTR:%.+]])
+ // LAMBDA: store %{{.+}}* [[ARG_PTR]], %{{.+}}** [[ARG_PTR_REF:%.+]],
+ g = 2;
+ // LAMBDA: [[ARG_PTR:%.+]] = load %{{.+}}*, %{{.+}}** [[ARG_PTR_REF]]
+ // LAMBDA: [[G_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // LAMBDA: [[G_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[G_PTR_REF]]
+ // LAMBDA: store volatile i{{[0-9]+}} 2, i{{[0-9]+}}* [[G_REF]]
+ }();
+ }
+ }();
+ return 0;
+#elif defined(BLOCKS)
+ // BLOCKS: [[G:@.+]] = global i{{[0-9]+}} 1212,
+ // BLOCKS-LABEL: @main
+ // BLOCKS: call void {{%.+}}(i8
+ ^{
+ // BLOCKS: define{{.*}} internal{{.*}} void {{.+}}(i8*
+ // BLOCKS: [[G_LOCAL_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[AGG_CAPTURED:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // BLOCKS: store i{{[0-9]+}}* [[G]], i{{[0-9]+}}** [[G_LOCAL_REF]]
+ // BLOCKS: [[ARG:%.+]] = bitcast %{{.+}}* [[AGG_CAPTURED]] to i8*
+ // BLOCKS: call void {{.+}} @__kmpc_fork_call({{.+}}, i32 1, {{.+}}* [[OMP_REGION:@.+]] to {{.+}}, i8* [[ARG]])
+#pragma omp parallel reduction(-:g)
+ {
+ // BLOCKS: define{{.*}} internal{{.*}} void [[OMP_REGION]](i32* %{{.+}}, i32* %{{.+}}, %{{.+}}* [[ARG:%.+]])
+ // BLOCKS: [[G_PRIVATE_ADDR:%.+]] = alloca i{{[0-9]+}},
+
+ // Reduction list for runtime.
+ // BLOCKS: [[RED_LIST:%.+]] = alloca [1 x i8*],
+
+ // BLOCKS: store %{{.+}}* [[ARG]], %{{.+}}** [[ARG_REF:%.+]],
+ // BLOCKS: [[ARG:%.+]] = load %{{.+}}*, %{{.+}}** [[ARG_REF]]
+ // BLOCKS: [[G_REF_ADDR:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // BLOCKS: [[G_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[G_REF_ADDR]]
+ // BLOCKS: store i{{[0-9]+}} 0, i{{[0-9]+}}* [[G_PRIVATE_ADDR]]
+ g = 1;
+ // BLOCKS: store volatile i{{[0-9]+}} 1, i{{[0-9]+}}* [[G_PRIVATE_ADDR]],
+ // BLOCKS-NOT: [[G]]{{[[^:word:]]}}
+ // BLOCKS: i{{[0-9]+}}* [[G_PRIVATE_ADDR]]
+ // BLOCKS-NOT: [[G]]{{[[^:word:]]}}
+ // BLOCKS: call void {{%.+}}(i8
+
+ // BLOCKS: [[G_PRIV_REF:%.+]] = getelementptr inbounds [1 x i8*], [1 x i8*]* [[RED_LIST]], i32 0, i32 0
+ // BLOCKS: [[BITCAST:%.+]] = bitcast i32* [[G_PRIVATE_ADDR]] to i8*
+ // BLOCKS: store i8* [[BITCAST]], i8** [[G_PRIV_REF]],
+ // BLOCKS: call i32 @__kmpc_reduce_nowait(
+ // BLOCKS: switch i32 %{{.+}}, label %[[REDUCTION_DONE:.+]] [
+ // BLOCKS: i32 1, label %[[CASE1:.+]]
+ // BLOCKS: i32 2, label %[[CASE2:.+]]
+ // BLOCKS: [[CASE1]]
+ // BLOCKS: [[G_VAL:%.+]] = load i32, i32* [[G_REF]]
+ // BLOCKS: [[G_PRIV_VAL:%.+]] = load i32, i32* [[G_PRIVATE_ADDR]]
+ // BLOCKS: [[ADD:%.+]] = add nsw i32 [[G_VAL]], [[G_PRIV_VAL]]
+ // BLOCKS: store i32 [[ADD]], i32* [[G_REF]]
+ // BLOCKS: call void @__kmpc_end_reduce_nowait(
+ // BLOCKS: br label %[[REDUCTION_DONE]]
+ // BLOCKS: [[CASE2]]
+ // BLOCKS: [[G_PRIV_VAL:%.+]] = load i32, i32* [[G_PRIVATE_ADDR]]
+ // BLOCKS: atomicrmw add i32* [[G_REF]], i32 [[G_PRIV_VAL]] monotonic
+ // BLOCKS: br label %[[REDUCTION_DONE]]
+ // BLOCKS: [[REDUCTION_DONE]]
+ // BLOCKS: ret void
+ ^{
+ // BLOCKS: define {{.+}} void {{@.+}}(i8*
+ g = 2;
+ // BLOCKS-NOT: [[G]]{{[[^:word:]]}}
+ // BLOCKS: store volatile i{{[0-9]+}} 2, i{{[0-9]+}}*
+ // BLOCKS-NOT: [[G]]{{[[^:word:]]}}
+ // BLOCKS: ret
+ }();
+ }
+ }();
+ return 0;
+#else
+ S<float> test;
+ float t_var = 0, t_var1;
+ int vec[] = {1, 2};
+ S<float> s_arr[] = {1, 2};
+ S<float> var(3), var1;
+#pragma omp parallel reduction(+:t_var) reduction(&:var) reduction(&& : var1) reduction(min: t_var1)
+ {
+ vec[0] = t_var;
+ s_arr[0] = var;
+ }
+ return tmain<int>();
+#endif
+}
+
+// CHECK: define {{.*}}i{{[0-9]+}} @main()
+// CHECK: [[TEST:%.+]] = alloca [[S_FLOAT_TY]],
+// CHECK: call {{.*}} [[S_FLOAT_TY_CONSTR:@.+]]([[S_FLOAT_TY]]* [[TEST]])
+// CHECK: %{{.+}} = bitcast [[CAP_MAIN_TY]]*
+// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [[CAP_MAIN_TY]]*)* [[MAIN_MICROTASK:@.+]] to void
+// CHECK: = call {{.*}}i{{.+}} [[TMAIN_INT:@.+]]()
+// CHECK: call {{.*}} [[S_FLOAT_TY_DESTR:@.+]]([[S_FLOAT_TY]]*
+// CHECK: ret
+//
+// CHECK: define internal void [[MAIN_MICROTASK]](i{{[0-9]+}}* [[GTID_ADDR:%.+]], i{{[0-9]+}}* %{{.+}}, [[CAP_MAIN_TY]]* %{{.+}})
+// CHECK: [[T_VAR_PRIV:%.+]] = alloca float,
+// CHECK: [[VAR_PRIV:%.+]] = alloca [[S_FLOAT_TY]],
+// CHECK: [[VAR1_PRIV:%.+]] = alloca [[S_FLOAT_TY]],
+// CHECK: [[T_VAR1_PRIV:%.+]] = alloca float,
+
+// Reduction list for runtime.
+// CHECK: [[RED_LIST:%.+]] = alloca [4 x i8*],
+
+// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]],
+
+// CHECK: [[T_VAR_PTR_REF:%.+]] = getelementptr inbounds [[CAP_MAIN_TY]], [[CAP_MAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} {{[0-9]+}}
+// CHECK: [[T_VAR_REF:%.+]] = load float*, float** [[T_VAR_PTR_REF]],
+// For + reduction operation initial value of private variable is 0.
+// CHECK: store float 0.0{{.+}}, float* [[T_VAR_PRIV]],
+
+// CHECK: [[VAR_PTR_REF:%.+]] = getelementptr inbounds [[CAP_MAIN_TY]], [[CAP_MAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} {{[0-9]+}}
+// CHECK: [[VAR_REF:%.+]] = load [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** [[VAR_PTR_REF:%.+]],
+// For & reduction operation initial value of private variable is ones in all bits.
+// CHECK: call {{.*}} [[S_FLOAT_TY_CONSTR:@.+]]([[S_FLOAT_TY]]* [[VAR_PRIV]])
+
+// CHECK: [[VAR1_PTR_REF:%.+]] = getelementptr inbounds [[CAP_MAIN_TY]], [[CAP_MAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} {{[0-9]+}}
+// CHECK: [[VAR1_REF:%.+]] = load [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** [[VAR_PTR_REF:%.+]],
+// For && reduction operation initial value of private variable is 1.0.
+// CHECK: call {{.*}} [[S_FLOAT_TY_CONSTR:@.+]]([[S_FLOAT_TY]]* [[VAR1_PRIV]])
+
+// CHECK: [[T_VAR1_PTR_REF:%.+]] = getelementptr inbounds [[CAP_MAIN_TY]], [[CAP_MAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} {{[0-9]+}}
+// CHECK: [[T_VAR1_REF:%.+]] = load float*, float** [[T_VAR1_PTR_REF]],
+// For min reduction operation initial value of private variable is largest repesentable value.
+// CHECK: store float 0x47EFFFFFE0000000, float* [[T_VAR1_PRIV]],
+
+// Skip checks for internal operations.
+
+// void *RedList[<n>] = {<ReductionVars>[0], ..., <ReductionVars>[<n>-1]};
+
+// CHECK: [[T_VAR_PRIV_REF:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[RED_LIST]], i32 0, i32 0
+// CHECK: [[BITCAST:%.+]] = bitcast float* [[T_VAR_PRIV]] to i8*
+// CHECK: store i8* [[BITCAST]], i8** [[T_VAR_PRIV_REF]],
+// CHECK: [[VAR_PRIV_REF:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[RED_LIST]], i32 0, i32 1
+// CHECK: [[BITCAST:%.+]] = bitcast [[S_FLOAT_TY]]* [[VAR_PRIV]] to i8*
+// CHECK: store i8* [[BITCAST]], i8** [[VAR_PRIV_REF]],
+// CHECK: [[VAR1_PRIV_REF:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[RED_LIST]], i32 0, i32 2
+// CHECK: [[BITCAST:%.+]] = bitcast [[S_FLOAT_TY]]* [[VAR1_PRIV]] to i8*
+// CHECK: store i8* [[BITCAST]], i8** [[VAR1_PRIV_REF]],
+// CHECK: [[T_VAR1_PRIV_REF:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[RED_LIST]], i32 0, i32 3
+// CHECK: [[BITCAST:%.+]] = bitcast float* [[T_VAR1_PRIV]] to i8*
+// CHECK: store i8* [[BITCAST]], i8** [[T_VAR1_PRIV_REF]],
+
+// res = __kmpc_reduce_nowait(<loc>, <gtid>, <n>, sizeof(RedList), RedList, reduce_func, &<lock>);
+
+// CHECK: [[GTID_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[GTID_ADDR_ADDR]]
+// CHECK: [[GTID:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[GTID_REF]]
+// CHECK: [[BITCAST:%.+]] = bitcast [4 x i8*]* [[RED_LIST]] to i8*
+// CHECK: [[RES:%.+]] = call i32 @__kmpc_reduce_nowait(%{{.+}}* [[REDUCTION_LOC]], i32 [[GTID]], i32 4, i64 32, i8* [[BITCAST]], void (i8*, i8*)* [[REDUCTION_FUNC:@.+]], [8 x i32]* [[REDUCTION_LOCK]])
+
+// switch(res)
+// CHECK: switch i32 [[RES]], label %[[RED_DONE:.+]] [
+// CHECK: i32 1, label %[[CASE1:.+]]
+// CHECK: i32 2, label %[[CASE2:.+]]
+// CHECK: ]
+
+// case 1:
+// t_var += t_var_reduction;
+// CHECK: [[T_VAR_VAL:%.+]] = load float, float* [[T_VAR_REF]],
+// CHECK: [[T_VAR_PRIV_VAL:%.+]] = load float, float* [[T_VAR_PRIV]],
+// CHECK: [[UP:%.+]] = fadd float [[T_VAR_VAL]], [[T_VAR_PRIV_VAL]]
+// CHECK: store float [[UP]], float* [[T_VAR_REF]],
+
+// var = var.operator &(var_reduction);
+// CHECK: [[UP:%.+]] = call dereferenceable(4) [[S_FLOAT_TY]]* @{{.+}}([[S_FLOAT_TY]]* [[VAR_REF]], [[S_FLOAT_TY]]* dereferenceable(4) [[VAR_PRIV]])
+// CHECK: [[BC1:%.+]] = bitcast [[S_FLOAT_TY]]* [[VAR_REF]] to i8*
+// CHECK: [[BC2:%.+]] = bitcast [[S_FLOAT_TY]]* [[UP]] to i8*
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[BC1]], i8* [[BC2]], i64 4, i32 4, i1 false)
+
+// var1 = var1.operator &&(var1_reduction);
+// CHECK: [[TO_FLOAT:%.+]] = call float @{{.+}}([[S_FLOAT_TY]]* [[VAR1_REF]])
+// CHECK: [[VAR1_BOOL:%.+]] = fcmp une float [[TO_FLOAT]], 0.0
+// CHECK: br i1 [[VAR1_BOOL]], label %[[TRUE:.+]], label %[[FALSE:.+]]
+// CHECK: [[TRUE]]
+// CHECK: [[TO_FLOAT:%.+]] = call float @{{.+}}([[S_FLOAT_TY]]* [[VAR1_PRIV]])
+// CHECK: [[VAR1_REDUCTION_BOOL:%.+]] = fcmp une float [[TO_FLOAT]], 0.0
+// CHECK: br i1 [[VAR1_REDUCTION_BOOL]], label %[[TRUE2:.+]], label %[[FALSE2:.+]]
+// CHECK: [[TRUE2]]
+// CHECK: br label %[[END2:.+]]
+// CHECK: [[FALSE2]]
+// CHECK: br label %[[END2]]
+// CHECK: [[END2]]
+// CHECK: [[COND_LVALUE:%.+]] = phi [[S_FLOAT_TY]]* [ [[VAR1_REF]], %[[TRUE2]] ], [ [[VAR1_PRIV]], %[[FALSE2]] ]
+// CHECK: [[BC1:%.+]] = bitcast [[S_FLOAT_TY]]* [[VAR1_REF]] to i8*
+// CHECK: [[BC2:%.+]] = bitcast [[S_FLOAT_TY]]* [[COND_LVALUE]] to i8*
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[BC1]], i8* [[BC2]], i64 4, i32 4, i1 false)
+
+// t_var1 = min(t_var1, t_var1_reduction);
+// CHECK: [[T_VAR1_VAL:%.+]] = load float, float* [[T_VAR1_REF]],
+// CHECK: [[T_VAR1_PRIV_VAL:%.+]] = load float, float* [[T_VAR1_PRIV]],
+// CHECK: [[CMP:%.+]] = fcmp olt float [[T_VAR1_VAL]], [[T_VAR1_PRIV_VAL]]
+// CHECK: [[UP:%.+]] = uitofp i1 [[CMP]] to float
+// CHECK: store float [[UP]], float* [[T_VAR1_REF]],
+
+// __kmpc_end_reduce_nowait(<loc>, <gtid>, &<lock>);
+// CHECK: call void @__kmpc_end_reduce_nowait(%{{.+}}* [[REDUCTION_LOC]], i32 [[GTID]], [8 x i32]* [[REDUCTION_LOCK]])
+
+// break;
+// CHECK: br label %[[RED_DONE]]
+
+// case 2:
+// t_var += t_var_reduction;
+// CHECK: load float, float* [[T_VAR_PRIV]]
+// CHECK: [[T_VAR_REF_INT:%.+]] = bitcast float* [[T_VAR_REF]] to i32*
+// CHECK: load atomic i32, i32* [[T_VAR_REF_INT]] monotonic,
+// CHECK: [[OLD1:%.+]] = bitcast i32 %{{.+}} to float
+// CHECK: br label %[[CONT:.+]]
+// CHECK: [[CONT]]
+// CHECK: [[ORIG_OLD:%.+]] = phi float [ [[OLD1]], %{{.+}} ], [ [[OLD2:%.+]], %[[CONT]] ]
+// CHECK: [[UP:%.+]] = fadd float
+// CHECK: [[ORIG_OLD_INT:%.+]] = bitcast float [[ORIG_OLD]] to i32
+// CHECK: [[UP_INT:%.+]] = bitcast float [[UP]] to i32
+// CHECK: [[T_VAR_REF_INT:%.+]] = bitcast float* [[T_VAR_REF]] to i32*
+// CHECK: [[RES:%.+]] = cmpxchg i32* [[T_VAR_REF_INT]], i32 [[ORIG_OLD_INT]], i32 [[UP_INT]] monotonic monotonic
+// CHECK: [[OLD_VAL_INT:%.+]] = extractvalue { i32, i1 } [[RES]], 0
+// CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i32, i1 } [[RES]], 1
+// CHECK: [[OLD2]] = bitcast i32 [[OLD_VAL_INT]] to float
+// CHECK: br i1 [[SUCCESS_FAIL]], label %[[ATOMIC_DONE:.+]], label %[[CONT]]
+// CHECK: [[ATOMIC_DONE]]
+
+// var = var.operator &(var_reduction);
+// CHECK: call void @__kmpc_critical(
+// CHECK: [[UP:%.+]] = call dereferenceable(4) [[S_FLOAT_TY]]* @{{.+}}([[S_FLOAT_TY]]* [[VAR_REF]], [[S_FLOAT_TY]]* dereferenceable(4) [[VAR_PRIV]])
+// CHECK: [[BC1:%.+]] = bitcast [[S_FLOAT_TY]]* [[VAR_REF]] to i8*
+// CHECK: [[BC2:%.+]] = bitcast [[S_FLOAT_TY]]* [[UP]] to i8*
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[BC1]], i8* [[BC2]], i64 4, i32 4, i1 false)
+// CHECK: call void @__kmpc_end_critical(
+
+// var1 = var1.operator &&(var1_reduction);
+// CHECK: call void @__kmpc_critical(
+// CHECK: [[TO_FLOAT:%.+]] = call float @{{.+}}([[S_FLOAT_TY]]* [[VAR1_REF]])
+// CHECK: [[VAR1_BOOL:%.+]] = fcmp une float [[TO_FLOAT]], 0.0
+// CHECK: br i1 [[VAR1_BOOL]], label %[[TRUE:.+]], label %[[FALSE:.+]]
+// CHECK: [[TRUE]]
+// CHECK: [[TO_FLOAT:%.+]] = call float @{{.+}}([[S_FLOAT_TY]]* [[VAR1_PRIV]])
+// CHECK: [[VAR1_REDUCTION_BOOL:%.+]] = fcmp une float [[TO_FLOAT]], 0.0
+// CHECK: br i1 [[VAR1_REDUCTION_BOOL]], label %[[TRUE2:.+]], label %[[FALSE2:.+]]
+// CHECK: [[TRUE2]]
+// CHECK: br label %[[END2:.+]]
+// CHECK: [[FALSE2]]
+// CHECK: br label %[[END2]]
+// CHECK: [[END2]]
+// CHECK: [[COND_LVALUE:%.+]] = phi [[S_FLOAT_TY]]* [ [[VAR1_REF]], %[[TRUE2]] ], [ [[VAR1_PRIV]], %[[FALSE2]] ]
+// CHECK: [[BC1:%.+]] = bitcast [[S_FLOAT_TY]]* [[VAR1_REF]] to i8*
+// CHECK: [[BC2:%.+]] = bitcast [[S_FLOAT_TY]]* [[COND_LVALUE]] to i8*
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[BC1]], i8* [[BC2]], i64 4, i32 4, i1 false)
+// CHECK: call void @__kmpc_end_critical(
+
+// t_var1 = min(t_var1, t_var1_reduction);
+// CHECK: load float, float* [[T_VAR1_PRIV]]
+// CHECK: [[T_VAR1_REF_INT:%.+]] = bitcast float* [[T_VAR1_REF]] to i32*
+// CHECK: load atomic i32, i32* [[T_VAR1_REF_INT]] monotonic,
+// CHECK: [[OLD1:%.+]] = bitcast i32 %{{.+}} to float
+// CHECK: br label %[[CONT:.+]]
+// CHECK: [[CONT]]
+// CHECK: [[ORIG_OLD:%.+]] = phi float [ [[OLD1]], %{{.+}} ], [ [[OLD2:%.+]], %[[CONT]] ]
+// CHECK: [[CMP:%.+]] = fcmp olt float
+// CHECK: [[UP:%.+]] = uitofp i1 [[CMP]] to float
+// CHECK: [[ORIG_OLD_INT:%.+]] = bitcast float [[ORIG_OLD]] to i32
+// CHECK: [[UP_INT:%.+]] = bitcast float [[UP]] to i32
+// CHECK: [[T_VAR1_REF_INT:%.+]] = bitcast float* [[T_VAR1_REF]] to i32*
+// CHECK: [[RES:%.+]] = cmpxchg i32* [[T_VAR1_REF_INT]], i32 [[ORIG_OLD_INT]], i32 [[UP_INT]] monotonic monotonic
+// CHECK: [[OLD_VAL_INT:%.+]] = extractvalue { i32, i1 } [[RES]], 0
+// CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i32, i1 } [[RES]], 1
+// CHECK: [[OLD2]] = bitcast i32 [[OLD_VAL_INT]] to float
+// CHECK: br i1 [[SUCCESS_FAIL]], label %[[ATOMIC_DONE:.+]], label %[[CONT]]
+// CHECK: [[ATOMIC_DONE]]
+
+// break;
+// CHECK: br label %[[RED_DONE]]
+// CHECK: [[RED_DONE]]
+// CHECK: call i32 @__kmpc_cancel_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]], i{{[0-9]+}} [[GTID]])
+
+// CHECK-DAG: call {{.*}} [[S_FLOAT_TY_DESTR]]([[S_FLOAT_TY]]* [[VAR_PRIV]])
+// CHECK-DAG: call {{.*}} [[S_FLOAT_TY_DESTR]]([[S_FLOAT_TY]]*
+// CHECK: ret void
+
+// void reduce_func(void *lhs[<n>], void *rhs[<n>]) {
+// *(Type0*)lhs[0] = ReductionOperation0(*(Type0*)lhs[0], *(Type0*)rhs[0]);
+// ...
+// *(Type<n>-1*)lhs[<n>-1] = ReductionOperation<n>-1(*(Type<n>-1*)lhs[<n>-1],
+// *(Type<n>-1*)rhs[<n>-1]);
+// }
+// CHECK: define internal void [[REDUCTION_FUNC]](i8*, i8*)
+// t_var_lhs = (float*)lhs[0];
+// CHECK: [[T_VAR_RHS_REF:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[RED_LIST_RHS:%.+]], i32 0, i32 0
+// CHECK: [[T_VAR_RHS_VOID:%.+]] = load i8*, i8** [[T_VAR_RHS_REF]],
+// CHECK: [[T_VAR_RHS:%.+]] = bitcast i8* [[T_VAR_RHS_VOID]] to float*
+// t_var_rhs = (float*)rhs[0];
+// CHECK: [[T_VAR_LHS_REF:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[RED_LIST_LHS:%.+]], i32 0, i32 0
+// CHECK: [[T_VAR_LHS_VOID:%.+]] = load i8*, i8** [[T_VAR_LHS_REF]],
+// CHECK: [[T_VAR_LHS:%.+]] = bitcast i8* [[T_VAR_LHS_VOID]] to float*
+
+// var_lhs = (S<float>*)lhs[1];
+// CHECK: [[VAR_RHS_REF:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[RED_LIST_RHS]], i32 0, i32 1
+// CHECK: [[VAR_RHS_VOID:%.+]] = load i8*, i8** [[VAR_RHS_REF]],
+// CHECK: [[VAR_RHS:%.+]] = bitcast i8* [[VAR_RHS_VOID]] to [[S_FLOAT_TY]]*
+// var_rhs = (S<float>*)rhs[1];
+// CHECK: [[VAR_LHS_REF:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[RED_LIST_LHS]], i32 0, i32 1
+// CHECK: [[VAR_LHS_VOID:%.+]] = load i8*, i8** [[VAR_LHS_REF]],
+// CHECK: [[VAR_LHS:%.+]] = bitcast i8* [[VAR_LHS_VOID]] to [[S_FLOAT_TY]]*
+
+// var1_lhs = (S<float>*)lhs[2];
+// CHECK: [[VAR1_RHS_REF:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[RED_LIST_RHS]], i32 0, i32 2
+// CHECK: [[VAR1_RHS_VOID:%.+]] = load i8*, i8** [[VAR1_RHS_REF]],
+// CHECK: [[VAR1_RHS:%.+]] = bitcast i8* [[VAR1_RHS_VOID]] to [[S_FLOAT_TY]]*
+// var1_rhs = (S<float>*)rhs[2];
+// CHECK: [[VAR1_LHS_REF:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[RED_LIST_LHS]], i32 0, i32 2
+// CHECK: [[VAR1_LHS_VOID:%.+]] = load i8*, i8** [[VAR1_LHS_REF]],
+// CHECK: [[VAR1_LHS:%.+]] = bitcast i8* [[VAR1_LHS_VOID]] to [[S_FLOAT_TY]]*
+
+// t_var1_lhs = (float*)lhs[3];
+// CHECK: [[T_VAR1_RHS_REF:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[RED_LIST_RHS]], i32 0, i32 3
+// CHECK: [[T_VAR1_RHS_VOID:%.+]] = load i8*, i8** [[T_VAR1_RHS_REF]],
+// CHECK: [[T_VAR1_RHS:%.+]] = bitcast i8* [[T_VAR1_RHS_VOID]] to float*
+// t_var1_rhs = (float*)rhs[3];
+// CHECK: [[T_VAR1_LHS_REF:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[RED_LIST_LHS]], i32 0, i32 3
+// CHECK: [[T_VAR1_LHS_VOID:%.+]] = load i8*, i8** [[T_VAR1_LHS_REF]],
+// CHECK: [[T_VAR1_LHS:%.+]] = bitcast i8* [[T_VAR1_LHS_VOID]] to float*
+
+// t_var_lhs += t_var_rhs;
+// CHECK: [[T_VAR_LHS_VAL:%.+]] = load float, float* [[T_VAR_LHS]],
+// CHECK: [[T_VAR_RHS_VAL:%.+]] = load float, float* [[T_VAR_RHS]],
+// CHECK: [[UP:%.+]] = fadd float [[T_VAR_LHS_VAL]], [[T_VAR_RHS_VAL]]
+// CHECK: store float [[UP]], float* [[T_VAR_LHS]],
+
+// var_lhs = var_lhs.operator &(var_rhs);
+// CHECK: [[UP:%.+]] = call dereferenceable(4) [[S_FLOAT_TY]]* @{{.+}}([[S_FLOAT_TY]]* [[VAR_LHS]], [[S_FLOAT_TY]]* dereferenceable(4) [[VAR_RHS]])
+// CHECK: [[BC1:%.+]] = bitcast [[S_FLOAT_TY]]* [[VAR_LHS]] to i8*
+// CHECK: [[BC2:%.+]] = bitcast [[S_FLOAT_TY]]* [[UP]] to i8*
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[BC1]], i8* [[BC2]], i64 4, i32 4, i1 false)
+
+// var1_lhs = var1_lhs.operator &&(var1_rhs);
+// CHECK: [[TO_FLOAT:%.+]] = call float @{{.+}}([[S_FLOAT_TY]]* [[VAR1_LHS]])
+// CHECK: [[VAR1_BOOL:%.+]] = fcmp une float [[TO_FLOAT]], 0.0
+// CHECK: br i1 [[VAR1_BOOL]], label %[[TRUE:.+]], label %[[FALSE:.+]]
+// CHECK: [[TRUE]]
+// CHECK: [[TO_FLOAT:%.+]] = call float @{{.+}}([[S_FLOAT_TY]]* [[VAR1_RHS]])
+// CHECK: [[VAR1_REDUCTION_BOOL:%.+]] = fcmp une float [[TO_FLOAT]], 0.0
+// CHECK: br i1 [[VAR1_REDUCTION_BOOL]], label %[[TRUE2:.+]], label %[[FALSE2:.+]]
+// CHECK: [[TRUE2]]
+// CHECK: br label %[[END2:.+]]
+// CHECK: [[FALSE2]]
+// CHECK: br label %[[END2]]
+// CHECK: [[END2]]
+// CHECK: [[COND_LVALUE:%.+]] = phi [[S_FLOAT_TY]]* [ [[VAR1_LHS]], %[[TRUE2]] ], [ [[VAR1_RHS]], %[[FALSE2]] ]
+// CHECK: [[BC1:%.+]] = bitcast [[S_FLOAT_TY]]* [[VAR1_LHS]] to i8*
+// CHECK: [[BC2:%.+]] = bitcast [[S_FLOAT_TY]]* [[COND_LVALUE]] to i8*
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[BC1]], i8* [[BC2]], i64 4, i32 4, i1 false)
+
+// t_var1_lhs = min(t_var1_lhs, t_var1_rhs);
+// CHECK: [[T_VAR1_LHS_VAL:%.+]] = load float, float* [[T_VAR1_LHS]],
+// CHECK: [[T_VAR1_RHS_VAL:%.+]] = load float, float* [[T_VAR1_RHS]],
+// CHECK: [[CMP:%.+]] = fcmp olt float [[T_VAR1_LHS_VAL]], [[T_VAR1_RHS_VAL]]
+// CHECK: [[UP:%.+]] = uitofp i1 [[CMP]] to float
+// CHECK: store float [[UP]], float* [[T_VAR1_LHS]],
+// CHECK: ret void
+
+// CHECK: define {{.*}} i{{[0-9]+}} [[TMAIN_INT]]()
+// CHECK: [[TEST:%.+]] = alloca [[S_INT_TY]],
+// CHECK: call {{.*}} [[S_INT_TY_CONSTR:@.+]]([[S_INT_TY]]* [[TEST]])
+// CHECK: %{{.+}} = bitcast [[CAP_TMAIN_TY]]*
+// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [[CAP_TMAIN_TY]]*)* [[TMAIN_MICROTASK:@.+]] to void
+// CHECK: call {{.*}} [[S_INT_TY_DESTR:@.+]]([[S_INT_TY]]*
+// CHECK: ret
+//
+// CHECK: define internal void [[TMAIN_MICROTASK]](i{{[0-9]+}}* [[GTID_ADDR:%.+]], i{{[0-9]+}}* %{{.+}}, [[CAP_TMAIN_TY]]* %{{.+}})
+// CHECK: [[T_VAR_PRIV:%.+]] = alloca i{{[0-9]+}},
+// CHECK: [[VAR_PRIV:%.+]] = alloca [[S_INT_TY]],
+// CHECK: [[VAR1_PRIV:%.+]] = alloca [[S_INT_TY]],
+// CHECK: [[T_VAR1_PRIV:%.+]] = alloca i{{[0-9]+}},
+
+// Reduction list for runtime.
+// CHECK: [[RED_LIST:%.+]] = alloca [4 x i8*],
+
+// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]],
+
+// CHECK: [[T_VAR_PTR_REF:%.+]] = getelementptr inbounds [[CAP_TMAIN_TY]], [[CAP_TMAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} {{[0-9]+}}
+// CHECK: [[T_VAR_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[T_VAR_PTR_REF]],
+// For + reduction operation initial value of private variable is 0.
+// CHECK: store i{{[0-9]+}} 0, i{{[0-9]+}}* [[T_VAR_PRIV]],
+
+// CHECK: [[VAR_PTR_REF:%.+]] = getelementptr inbounds [[CAP_TMAIN_TY]], [[CAP_TMAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} {{[0-9]+}}
+// CHECK: [[VAR_REF:%.+]] = load [[S_INT_TY]]*, [[S_INT_TY]]** [[VAR_PTR_REF:%.+]],
+// For & reduction operation initial value of private variable is ones in all bits.
+// CHECK: call {{.*}} [[S_INT_TY_CONSTR:@.+]]([[S_INT_TY]]* [[VAR_PRIV]])
+
+// CHECK: [[VAR1_PTR_REF:%.+]] = getelementptr inbounds [[CAP_TMAIN_TY]], [[CAP_TMAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} {{[0-9]+}}
+// CHECK: [[VAR1_REF:%.+]] = load [[S_INT_TY]]*, [[S_INT_TY]]** [[VAR_PTR_REF:%.+]],
+// For && reduction operation initial value of private variable is 1.0.
+// CHECK: call {{.*}} [[S_INT_TY_CONSTR:@.+]]([[S_INT_TY]]* [[VAR1_PRIV]])
+
+// CHECK: [[T_VAR1_PTR_REF:%.+]] = getelementptr inbounds [[CAP_TMAIN_TY]], [[CAP_TMAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} {{[0-9]+}}
+// CHECK: [[T_VAR1_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[T_VAR1_PTR_REF]],
+// For min reduction operation initial value of private variable is largest repesentable value.
+// CHECK: store i{{[0-9]+}} 2147483647, i{{[0-9]+}}* [[T_VAR1_PRIV]],
+
+// Skip checks for internal operations.
+
+// void *RedList[<n>] = {<ReductionVars>[0], ..., <ReductionVars>[<n>-1]};
+
+// CHECK: [[T_VAR_PRIV_REF:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[RED_LIST]], i32 0, i32 0
+// CHECK: [[BITCAST:%.+]] = bitcast i{{[0-9]+}}* [[T_VAR_PRIV]] to i8*
+// CHECK: store i8* [[BITCAST]], i8** [[T_VAR_PRIV_REF]],
+// CHECK: [[VAR_PRIV_REF:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[RED_LIST]], i32 0, i32 1
+// CHECK: [[BITCAST:%.+]] = bitcast [[S_INT_TY]]* [[VAR_PRIV]] to i8*
+// CHECK: store i8* [[BITCAST]], i8** [[VAR_PRIV_REF]],
+// CHECK: [[VAR1_PRIV_REF:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[RED_LIST]], i32 0, i32 2
+// CHECK: [[BITCAST:%.+]] = bitcast [[S_INT_TY]]* [[VAR1_PRIV]] to i8*
+// CHECK: store i8* [[BITCAST]], i8** [[VAR1_PRIV_REF]],
+// CHECK: [[T_VAR1_PRIV_REF:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[RED_LIST]], i32 0, i32 3
+// CHECK: [[BITCAST:%.+]] = bitcast i{{[0-9]+}}* [[T_VAR1_PRIV]] to i8*
+// CHECK: store i8* [[BITCAST]], i8** [[T_VAR1_PRIV_REF]],
+
+// res = __kmpc_reduce_nowait(<loc>, <gtid>, <n>, sizeof(RedList), RedList, reduce_func, &<lock>);
+
+// CHECK: [[GTID_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[GTID_ADDR_ADDR]]
+// CHECK: [[GTID:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[GTID_REF]]
+// CHECK: [[BITCAST:%.+]] = bitcast [4 x i8*]* [[RED_LIST]] to i8*
+// CHECK: [[RES:%.+]] = call i32 @__kmpc_reduce_nowait(%{{.+}}* [[REDUCTION_LOC]], i32 [[GTID]], i32 4, i64 32, i8* [[BITCAST]], void (i8*, i8*)* [[REDUCTION_FUNC:@.+]], [8 x i32]* [[REDUCTION_LOCK]])
+
+// switch(res)
+// CHECK: switch i32 [[RES]], label %[[RED_DONE:.+]] [
+// CHECK: i32 1, label %[[CASE1:.+]]
+// CHECK: i32 2, label %[[CASE2:.+]]
+// CHECK: ]
+
+// case 1:
+// t_var += t_var_reduction;
+// CHECK: [[T_VAR_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[T_VAR_REF]],
+// CHECK: [[T_VAR_PRIV_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[T_VAR_PRIV]],
+// CHECK: [[UP:%.+]] = add nsw i{{[0-9]+}} [[T_VAR_VAL]], [[T_VAR_PRIV_VAL]]
+// CHECK: store i{{[0-9]+}} [[UP]], i{{[0-9]+}}* [[T_VAR_REF]],
+
+// var = var.operator &(var_reduction);
+// CHECK: [[UP:%.+]] = call dereferenceable(4) [[S_INT_TY]]* @{{.+}}([[S_INT_TY]]* [[VAR_REF]], [[S_INT_TY]]* dereferenceable(4) [[VAR_PRIV]])
+// CHECK: [[BC1:%.+]] = bitcast [[S_INT_TY]]* [[VAR_REF]] to i8*
+// CHECK: [[BC2:%.+]] = bitcast [[S_INT_TY]]* [[UP]] to i8*
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[BC1]], i8* [[BC2]], i64 4, i32 4, i1 false)
+
+// var1 = var1.operator &&(var1_reduction);
+// CHECK: [[TO_INT:%.+]] = call i{{[0-9]+}} @{{.+}}([[S_INT_TY]]* [[VAR1_REF]])
+// CHECK: [[VAR1_BOOL:%.+]] = icmp ne i{{[0-9]+}} [[TO_INT]], 0
+// CHECK: br i1 [[VAR1_BOOL]], label %[[TRUE:.+]], label %[[FALSE:.+]]
+// CHECK: [[TRUE]]
+// CHECK: [[TO_INT:%.+]] = call i{{[0-9]+}} @{{.+}}([[S_INT_TY]]* [[VAR1_PRIV]])
+// CHECK: [[VAR1_REDUCTION_BOOL:%.+]] = icmp ne i{{[0-9]+}} [[TO_INT]], 0
+// CHECK: br i1 [[VAR1_REDUCTION_BOOL]], label %[[TRUE2:.+]], label %[[FALSE2:.+]]
+// CHECK: [[TRUE2]]
+// CHECK: br label %[[END2:.+]]
+// CHECK: [[FALSE2]]
+// CHECK: br label %[[END2]]
+// CHECK: [[END2]]
+// CHECK: [[COND_LVALUE:%.+]] = phi [[S_INT_TY]]* [ [[VAR1_REF]], %[[TRUE2]] ], [ [[VAR1_PRIV]], %[[FALSE2]] ]
+// CHECK: [[BC1:%.+]] = bitcast [[S_INT_TY]]* [[VAR1_REF]] to i8*
+// CHECK: [[BC2:%.+]] = bitcast [[S_INT_TY]]* [[COND_LVALUE]] to i8*
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[BC1]], i8* [[BC2]], i64 4, i32 4, i1 false)
+
+// t_var1 = min(t_var1, t_var1_reduction);
+// CHECK: [[T_VAR1_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[T_VAR1_REF]],
+// CHECK: [[T_VAR1_PRIV_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[T_VAR1_PRIV]],
+// CHECK: [[CMP:%.+]] = icmp slt i{{[0-9]+}} [[T_VAR1_VAL]], [[T_VAR1_PRIV_VAL]]
+// CHECK: [[UP:%.+]] = zext i1 [[CMP]] to i{{[0-9]+}}
+// CHECK: store i{{[0-9]+}} [[UP]], i{{[0-9]+}}* [[T_VAR1_REF]],
+
+// __kmpc_end_reduce_nowait(<loc>, <gtid>, &<lock>);
+// CHECK: call void @__kmpc_end_reduce_nowait(%{{.+}}* [[REDUCTION_LOC]], i32 [[GTID]], [8 x i32]* [[REDUCTION_LOCK]])
+
+// break;
+// CHECK: br label %[[RED_DONE]]
+
+// case 2:
+// t_var += t_var_reduction;
+// CHECK: [[T_VAR_PRIV_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[T_VAR_PRIV]]
+// CHECK: atomicrmw add i32* [[T_VAR_REF]], i32 [[T_VAR_PRIV_VAL]] monotonic
+
+// var = var.operator &(var_reduction);
+// CHECK: call void @__kmpc_critical(
+// CHECK: [[UP:%.+]] = call dereferenceable(4) [[S_INT_TY]]* @{{.+}}([[S_INT_TY]]* [[VAR_REF]], [[S_INT_TY]]* dereferenceable(4) [[VAR_PRIV]])
+// CHECK: [[BC1:%.+]] = bitcast [[S_INT_TY]]* [[VAR_REF]] to i8*
+// CHECK: [[BC2:%.+]] = bitcast [[S_INT_TY]]* [[UP]] to i8*
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[BC1]], i8* [[BC2]], i64 4, i32 4, i1 false)
+// CHECK: call void @__kmpc_end_critical(
+
+// var1 = var1.operator &&(var1_reduction);
+// CHECK: call void @__kmpc_critical(
+// CHECK: [[TO_INT:%.+]] = call i{{[0-9]+}} @{{.+}}([[S_INT_TY]]* [[VAR1_REF]])
+// CHECK: [[VAR1_BOOL:%.+]] = icmp ne i{{[0-9]+}} [[TO_INT]], 0
+// CHECK: br i1 [[VAR1_BOOL]], label %[[TRUE:.+]], label %[[FALSE:.+]]
+// CHECK: [[TRUE]]
+// CHECK: [[TO_INT:%.+]] = call i{{[0-9]+}} @{{.+}}([[S_INT_TY]]* [[VAR1_PRIV]])
+// CHECK: [[VAR1_REDUCTION_BOOL:%.+]] = icmp ne i{{[0-9]+}} [[TO_INT]], 0
+// CHECK: br i1 [[VAR1_REDUCTION_BOOL]], label %[[TRUE2:.+]], label %[[FALSE2:.+]]
+// CHECK: [[TRUE2]]
+// CHECK: br label %[[END2:.+]]
+// CHECK: [[FALSE2]]
+// CHECK: br label %[[END2]]
+// CHECK: [[END2]]
+// CHECK: [[COND_LVALUE:%.+]] = phi [[S_INT_TY]]* [ [[VAR1_REF]], %[[TRUE2]] ], [ [[VAR1_PRIV]], %[[FALSE2]] ]
+// CHECK: [[BC1:%.+]] = bitcast [[S_INT_TY]]* [[VAR1_REF]] to i8*
+// CHECK: [[BC2:%.+]] = bitcast [[S_INT_TY]]* [[COND_LVALUE]] to i8*
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[BC1]], i8* [[BC2]], i64 4, i32 4, i1 false)
+// CHECK: call void @__kmpc_end_critical(
+
+// t_var1 = min(t_var1, t_var1_reduction);
+// CHECK: [[T_VAR1_PRIV_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[T_VAR1_PRIV]]
+// CHECK: atomicrmw min i32* [[T_VAR1_REF]], i32 [[T_VAR1_PRIV_VAL]] monotonic
+
+// break;
+// CHECK: br label %[[RED_DONE]]
+// CHECK: [[RED_DONE]]
+// CHECK: call i32 @__kmpc_cancel_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]], i{{[0-9]+}} [[GTID]])
+
+// CHECK-DAG: call {{.*}} [[S_INT_TY_DESTR]]([[S_INT_TY]]* [[VAR_PRIV]])
+// CHECK-DAG: call {{.*}} [[S_INT_TY_DESTR]]([[S_INT_TY]]*
+// CHECK: ret void
+
+// void reduce_func(void *lhs[<n>], void *rhs[<n>]) {
+// *(Type0*)lhs[0] = ReductionOperation0(*(Type0*)lhs[0], *(Type0*)rhs[0]);
+// ...
+// *(Type<n>-1*)lhs[<n>-1] = ReductionOperation<n>-1(*(Type<n>-1*)lhs[<n>-1],
+// *(Type<n>-1*)rhs[<n>-1]);
+// }
+// CHECK: define internal void [[REDUCTION_FUNC]](i8*, i8*)
+// t_var_lhs = (i{{[0-9]+}}*)lhs[0];
+// CHECK: [[T_VAR_RHS_REF:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[RED_LIST_RHS:%.+]], i32 0, i32 0
+// CHECK: [[T_VAR_RHS_VOID:%.+]] = load i8*, i8** [[T_VAR_RHS_REF]],
+// CHECK: [[T_VAR_RHS:%.+]] = bitcast i8* [[T_VAR_RHS_VOID]] to i{{[0-9]+}}*
+// t_var_rhs = (i{{[0-9]+}}*)rhs[0];
+// CHECK: [[T_VAR_LHS_REF:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[RED_LIST_LHS:%.+]], i32 0, i32 0
+// CHECK: [[T_VAR_LHS_VOID:%.+]] = load i8*, i8** [[T_VAR_LHS_REF]],
+// CHECK: [[T_VAR_LHS:%.+]] = bitcast i8* [[T_VAR_LHS_VOID]] to i{{[0-9]+}}*
+
+// var_lhs = (S<i{{[0-9]+}}>*)lhs[1];
+// CHECK: [[VAR_RHS_REF:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[RED_LIST_RHS]], i32 0, i32 1
+// CHECK: [[VAR_RHS_VOID:%.+]] = load i8*, i8** [[VAR_RHS_REF]],
+// CHECK: [[VAR_RHS:%.+]] = bitcast i8* [[VAR_RHS_VOID]] to [[S_INT_TY]]*
+// var_rhs = (S<i{{[0-9]+}}>*)rhs[1];
+// CHECK: [[VAR_LHS_REF:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[RED_LIST_LHS]], i32 0, i32 1
+// CHECK: [[VAR_LHS_VOID:%.+]] = load i8*, i8** [[VAR_LHS_REF]],
+// CHECK: [[VAR_LHS:%.+]] = bitcast i8* [[VAR_LHS_VOID]] to [[S_INT_TY]]*
+
+// var1_lhs = (S<i{{[0-9]+}}>*)lhs[2];
+// CHECK: [[VAR1_RHS_REF:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[RED_LIST_RHS]], i32 0, i32 2
+// CHECK: [[VAR1_RHS_VOID:%.+]] = load i8*, i8** [[VAR1_RHS_REF]],
+// CHECK: [[VAR1_RHS:%.+]] = bitcast i8* [[VAR1_RHS_VOID]] to [[S_INT_TY]]*
+// var1_rhs = (S<i{{[0-9]+}}>*)rhs[2];
+// CHECK: [[VAR1_LHS_REF:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[RED_LIST_LHS]], i32 0, i32 2
+// CHECK: [[VAR1_LHS_VOID:%.+]] = load i8*, i8** [[VAR1_LHS_REF]],
+// CHECK: [[VAR1_LHS:%.+]] = bitcast i8* [[VAR1_LHS_VOID]] to [[S_INT_TY]]*
+
+// t_var1_lhs = (i{{[0-9]+}}*)lhs[3];
+// CHECK: [[T_VAR1_RHS_REF:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[RED_LIST_RHS]], i32 0, i32 3
+// CHECK: [[T_VAR1_RHS_VOID:%.+]] = load i8*, i8** [[T_VAR1_RHS_REF]],
+// CHECK: [[T_VAR1_RHS:%.+]] = bitcast i8* [[T_VAR1_RHS_VOID]] to i{{[0-9]+}}*
+// t_var1_rhs = (i{{[0-9]+}}*)rhs[3];
+// CHECK: [[T_VAR1_LHS_REF:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[RED_LIST_LHS]], i32 0, i32 3
+// CHECK: [[T_VAR1_LHS_VOID:%.+]] = load i8*, i8** [[T_VAR1_LHS_REF]],
+// CHECK: [[T_VAR1_LHS:%.+]] = bitcast i8* [[T_VAR1_LHS_VOID]] to i{{[0-9]+}}*
+
+// t_var_lhs += t_var_rhs;
+// CHECK: [[T_VAR_LHS_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[T_VAR_LHS]],
+// CHECK: [[T_VAR_RHS_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[T_VAR_RHS]],
+// CHECK: [[UP:%.+]] = add nsw i{{[0-9]+}} [[T_VAR_LHS_VAL]], [[T_VAR_RHS_VAL]]
+// CHECK: store i{{[0-9]+}} [[UP]], i{{[0-9]+}}* [[T_VAR_LHS]],
+
+// var_lhs = var_lhs.operator &(var_rhs);
+// CHECK: [[UP:%.+]] = call dereferenceable(4) [[S_INT_TY]]* @{{.+}}([[S_INT_TY]]* [[VAR_LHS]], [[S_INT_TY]]* dereferenceable(4) [[VAR_RHS]])
+// CHECK: [[BC1:%.+]] = bitcast [[S_INT_TY]]* [[VAR_LHS]] to i8*
+// CHECK: [[BC2:%.+]] = bitcast [[S_INT_TY]]* [[UP]] to i8*
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[BC1]], i8* [[BC2]], i64 4, i32 4, i1 false)
+
+// var1_lhs = var1_lhs.operator &&(var1_rhs);
+// CHECK: [[TO_INT:%.+]] = call i{{[0-9]+}} @{{.+}}([[S_INT_TY]]* [[VAR1_LHS]])
+// CHECK: [[VAR1_BOOL:%.+]] = icmp ne i{{[0-9]+}} [[TO_INT]], 0
+// CHECK: br i1 [[VAR1_BOOL]], label %[[TRUE:.+]], label %[[FALSE:.+]]
+// CHECK: [[TRUE]]
+// CHECK: [[TO_INT:%.+]] = call i{{[0-9]+}} @{{.+}}([[S_INT_TY]]* [[VAR1_RHS]])
+// CHECK: [[VAR1_REDUCTION_BOOL:%.+]] = icmp ne i{{[0-9]+}} [[TO_INT]], 0
+// CHECK: br i1 [[VAR1_REDUCTION_BOOL]], label %[[TRUE2:.+]], label %[[FALSE2:.+]]
+// CHECK: [[TRUE2]]
+// CHECK: br label %[[END2:.+]]
+// CHECK: [[FALSE2]]
+// CHECK: br label %[[END2]]
+// CHECK: [[END2]]
+// CHECK: [[COND_LVALUE:%.+]] = phi [[S_INT_TY]]* [ [[VAR1_LHS]], %[[TRUE2]] ], [ [[VAR1_RHS]], %[[FALSE2]] ]
+// CHECK: [[BC1:%.+]] = bitcast [[S_INT_TY]]* [[VAR1_LHS]] to i8*
+// CHECK: [[BC2:%.+]] = bitcast [[S_INT_TY]]* [[COND_LVALUE]] to i8*
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[BC1]], i8* [[BC2]], i64 4, i32 4, i1 false)
+
+// t_var1_lhs = min(t_var1_lhs, t_var1_rhs);
+// CHECK: [[T_VAR1_LHS_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[T_VAR1_LHS]],
+// CHECK: [[T_VAR1_RHS_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[T_VAR1_RHS]],
+// CHECK: [[CMP:%.+]] = icmp slt i{{[0-9]+}} [[T_VAR1_LHS_VAL]], [[T_VAR1_RHS_VAL]]
+// CHECK: [[UP:%.+]] = zext i1 [[CMP]] to i{{[0-9]+}}
+// CHECK: store i{{[0-9]+}} [[UP]], i{{[0-9]+}}* [[T_VAR1_LHS]],
+// CHECK: ret void
+
+#endif
+
diff --git a/test/OpenMP/parallel_reduction_messages.cpp b/test/OpenMP/parallel_reduction_messages.cpp
index 46bc7a5..f6883d2 100644
--- a/test/OpenMP/parallel_reduction_messages.cpp
+++ b/test/OpenMP/parallel_reduction_messages.cpp
@@ -11,7 +11,7 @@
extern S1 a;
class S2 {
mutable int a;
- S2 &operator+=(const S2 &arg) { return (*this); }
+ S2 &operator+(const S2 &arg) { return (*this); } // expected-note 4 {{implicitly declared private here}}
public:
S2() : a(0) {}
@@ -28,17 +28,17 @@
public:
S3() : a(0) {}
S3(const S3 &s3) : a(s3.a) {}
- S3 operator+=(const S3 &arg1) { return arg1; }
+ S3 operator+(const S3 &arg1) { return arg1; }
};
-int operator+=(const S3 &arg1, const S3 &arg2) { return 5; }
+int operator+(const S3 &arg1, const S3 &arg2) { return 5; }
S3 c; // expected-note 2 {{'c' defined here}}
const S3 ca[5]; // expected-note 2 {{'ca' defined here}}
extern const int f; // expected-note 4 {{'f' declared here}}
-class S4 { // expected-note {{'S4' declared here}}
+class S4 {
int a;
- S4();
+ S4(); // expected-note {{implicitly declared private here}}
S4(const S4 &s4);
- S4 &operator+=(const S4 &arg) { return (*this); }
+ S4 &operator+(const S4 &arg) { return (*this); }
public:
S4(int v) : a(v) {}
@@ -46,26 +46,26 @@
S4 &operator&=(S4 &arg1, S4 &arg2) { return arg1; }
class S5 {
int a;
- S5() : a(0) {}
+ S5() : a(0) {} // expected-note {{implicitly declared private here}}
S5(const S5 &s5) : a(s5.a) {}
- S5 &operator+=(const S5 &arg);
+ S5 &operator+(const S5 &arg);
public:
S5(int v) : a(v) {}
};
-class S6 {
+class S6 { // expected-note 2 {{candidate function (the implicit copy assignment operator) not viable: no known conversion from 'int' to 'const S6' for 1st argument}}
int a;
public:
S6() : a(6) {}
operator int() { return 6; }
-} o; // expected-note 2 {{'o' defined here}}
+} o;
S3 h, k;
#pragma omp threadprivate(h) // expected-note 2 {{defined as threadprivate or thread local}}
template <class T> // expected-note {{declared here}}
-T tmain(T argc) { // expected-note 2 {{'argc' defined here}}
+T tmain(T argc) {
const T d = T(); // expected-note 4 {{'d' defined here}}
const T da[5] = {T()}; // expected-note 2 {{'da' defined here}}
T qa[5] = {T()};
@@ -74,7 +74,7 @@
S3 &p = k; // expected-note 2 {{'p' defined here}}
const T &r = da[(int)i]; // expected-note 2 {{'r' defined here}}
T &q = qa[(int)i]; // expected-note 2 {{'q' defined here}}
- T fl; // expected-note {{'fl' defined here}}
+ T fl;
#pragma omp parallel reduction // expected-error {{expected '(' after 'reduction'}}
foo();
#pragma omp parallel reduction + // expected-error {{expected '(' after 'reduction'}} expected-warning {{extra tokens at the end of '#pragma omp parallel' are ignored}}
@@ -89,9 +89,9 @@
foo();
#pragma omp parallel reduction(\) // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}}
foo();
-#pragma omp parallel reduction(& : argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{variable of type 'float' is not valid for specified reduction operation}}
+#pragma omp parallel reduction(& : argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{invalid operands to binary expression ('float' and 'float')}}
foo();
-#pragma omp parallel reduction(| : argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{variable of type 'float' is not valid for specified reduction operation}}
+#pragma omp parallel reduction(| : argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{invalid operands to binary expression ('float' and 'float')}}
foo();
#pragma omp parallel reduction(|| : argc ? i : argc) // expected-error 2 {{expected variable name}}
foo();
@@ -101,7 +101,7 @@
foo();
#pragma omp parallel reduction(^ : T) // expected-error {{'T' does not refer to a value}}
foo();
-#pragma omp parallel reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 3 {{const-qualified variable cannot be reduction}}
+#pragma omp parallel reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 3 {{const-qualified variable cannot be reduction}} expected-error 3 {{'operator+' is a private member of 'S2'}}
foo();
#pragma omp parallel reduction(min : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{arguments of OpenMP clause 'reduction' for 'min' or 'max' must be of arithmetic type}} expected-error 3 {{const-qualified variable cannot be reduction}}
foo();
@@ -113,7 +113,7 @@
foo();
#pragma omp parallel reduction(- : da) // expected-error {{a reduction variable with array type 'const int [5]'}} expected-error {{a reduction variable with array type 'const float [5]'}}
foo();
-#pragma omp parallel reduction(^ : fl) // expected-error {{variable of type 'float' is not valid for specified reduction operation}}
+#pragma omp parallel reduction(^ : fl) // expected-error {{invalid operands to binary expression ('float' and 'float')}}
foo();
#pragma omp parallel reduction(&& : S2::S2s)
foo();
@@ -121,7 +121,7 @@
foo();
#pragma omp parallel reduction(+ : h, k) // expected-error {{threadprivate or thread local variable cannot be reduction}}
foo();
-#pragma omp parallel reduction(+ : o) // expected-error {{variable of type 'class S6' is not valid for specified reduction operation}}
+#pragma omp parallel reduction(+ : o) // expected-error {{no viable overloaded '='}}
foo();
#pragma omp parallel private(i), reduction(+ : j), reduction(+ : q) // expected-error 4 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}}
foo();
@@ -150,18 +150,26 @@
return T();
}
+namespace A {
+double x;
+#pragma omp threadprivate(x) // expected-note {{defined as threadprivate or thread local}}
+}
+namespace B {
+using A::x;
+}
+
int main(int argc, char **argv) {
const int d = 5; // expected-note 2 {{'d' defined here}}
const int da[5] = {0}; // expected-note {{'da' defined here}}
int qa[5] = {0};
- S4 e(4); // expected-note {{'e' defined here}}
- S5 g(5); // expected-note {{'g' defined here}}
+ S4 e(4);
+ S5 g(5);
int i;
int &j = i; // expected-note 2 {{'j' defined here}}
S3 &p = k; // expected-note 2 {{'p' defined here}}
const int &r = da[i]; // expected-note {{'r' defined here}}
int &q = qa[i]; // expected-note {{'q' defined here}}
- float fl; // expected-note {{'fl' defined here}}
+ float fl;
#pragma omp parallel reduction // expected-error {{expected '(' after 'reduction'}}
foo();
#pragma omp parallel reduction + // expected-error {{expected '(' after 'reduction'}} expected-warning {{extra tokens at the end of '#pragma omp parallel' are ignored}}
@@ -188,7 +196,7 @@
foo();
#pragma omp parallel reduction(^ : S1) // expected-error {{'S1' does not refer to a value}}
foo();
-#pragma omp parallel reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{const-qualified variable cannot be reduction}}
+#pragma omp parallel reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{const-qualified variable cannot be reduction}} expected-error {{'operator+' is a private member of 'S2'}}
foo();
#pragma omp parallel reduction(min : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{arguments of OpenMP clause 'reduction' for 'min' or 'max' must be of arithmetic type}} expected-error 2 {{const-qualified variable cannot be reduction}}
foo();
@@ -200,17 +208,17 @@
foo();
#pragma omp parallel reduction(- : da) // expected-error {{a reduction variable with array type 'const int [5]'}}
foo();
-#pragma omp parallel reduction(^ : fl) // expected-error {{variable of type 'float' is not valid for specified reduction operation}}
+#pragma omp parallel reduction(^ : fl) // expected-error {{invalid operands to binary expression ('float' and 'float')}}
foo();
#pragma omp parallel reduction(&& : S2::S2s)
foo();
#pragma omp parallel reduction(&& : S2::S2sc) // expected-error {{const-qualified variable cannot be reduction}}
foo();
-#pragma omp parallel reduction(& : e, g) // expected-error {{reduction variable must have an accessible, unambiguous default constructor}} expected-error {{variable of type 'S5' is not valid for specified reduction operation}}
+#pragma omp parallel reduction(& : e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{nvalid operands to binary expression ('S4' and 'S4')}} expected-error {{calling a private constructor of class 'S5'}} expected-error {{invalid operands to binary expression ('S5' and 'S5')}}
foo();
-#pragma omp parallel reduction(+ : h, k) // expected-error {{threadprivate or thread local variable cannot be reduction}}
+#pragma omp parallel reduction(+ : h, k, B::x) // expected-error 2 {{threadprivate or thread local variable cannot be reduction}}
foo();
-#pragma omp parallel reduction(+ : o) // expected-error {{variable of type 'class S6' is not valid for specified reduction operation}}
+#pragma omp parallel reduction(+ : o) // expected-error {{no viable overloaded '='}}
foo();
#pragma omp parallel private(i), reduction(+ : j), reduction(+ : q) // expected-error 2 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}}
foo();
diff --git a/test/OpenMP/parallel_sections_codegen.cpp b/test/OpenMP/parallel_sections_codegen.cpp
new file mode 100644
index 0000000..89ed37e
--- /dev/null
+++ b/test/OpenMP/parallel_sections_codegen.cpp
@@ -0,0 +1,98 @@
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -x c++ -emit-llvm -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -o - %s | FileCheck %s
+// RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -std=c++11 -fexceptions -fcxx-exceptions -triple x86_64-unknown-unknown -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -std=c++11 -include-pch %t -fsyntax-only -verify %s -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -emit-llvm -o - | FileCheck %s
+// expected-no-diagnostics
+
+#ifndef HEADER
+#define HEADER
+// CHECK: [[IMPLICIT_BARRIER_LOC:@.+]] = private unnamed_addr constant %{{.+}} { i32 0, i32 66, i32 0, i32 0, i8*
+// CHECK-LABEL: foo
+void foo() {};
+// CHECK-LABEL: bar
+void bar() {};
+
+template <class T>
+T tmain() {
+#pragma omp parallel sections
+ {
+ foo();
+ }
+ return T();
+}
+
+// CHECK-LABEL: @main
+int main() {
+// CHECK: call void (%{{.+}}*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, %{{.+}}*)* [[OMP_PARALLEL_FUNC:@.+]] to void (i32*, i32*, ...)*), i8* %{{.+}})
+// CHECK-LABEL: }
+// CHECK: define internal void [[OMP_PARALLEL_FUNC]](i32* [[GTID_PARAM_ADDR:%.+]], i32* %{{.+}}, %{{.+}}* %{{.+}})
+// CHECK: store i32* [[GTID_PARAM_ADDR]], i32** [[GTID_REF_ADDR:%.+]],
+#pragma omp parallel sections
+ {
+// CHECK: store i32 0, i32* [[LB_PTR:%.+]],
+// CHECK: store i32 1, i32* [[UB_PTR:%.+]],
+// CHECK: [[GTID_REF:%.+]] = load i32*, i32** [[GTID_REF_ADDR]],
+// CHECK: [[GTID:%.+]] = load i32, i32* [[GTID_REF]],
+// CHECK: call void @__kmpc_for_static_init_4(%{{.+}}* @{{.+}}, i32 [[GTID]], i32 34, i32* [[IS_LAST_PTR:%.+]], i32* [[LB_PTR]], i32* [[UB_PTR]], i32* [[STRIDE_PTR:%.+]], i32 1, i32 1)
+// <<UB = min(UB, GlobalUB);>>
+// CHECK: [[UB:%.+]] = load i32, i32* [[UB_PTR]]
+// CHECK: [[CMP:%.+]] = icmp slt i32 [[UB]], 1
+// CHECK: [[MIN_UB_GLOBALUB:%.+]] = select i1 [[CMP]], i32 [[UB]], i32 1
+// CHECK: store i32 [[MIN_UB_GLOBALUB]], i32* [[UB_PTR]]
+// <<IV = LB;>>
+// CHECK: [[LB:%.+]] = load i32, i32* [[LB_PTR]]
+// CHECK: store i32 [[LB]], i32* [[IV_PTR:%.+]]
+// CHECK: br label %[[INNER_FOR_COND:.+]]
+// CHECK: [[INNER_FOR_COND]]
+// <<IV <= UB?>>
+// CHECK: [[IV:%.+]] = load i32, i32* [[IV_PTR]]
+// CHECK: [[UB:%.+]] = load i32, i32* [[UB_PTR]]
+// CHECK: [[CMP:%.+]] = icmp sle i32 [[IV]], [[UB]]
+// CHECK: br i1 [[CMP]], label %[[INNER_LOOP_BODY:.+]], label %[[INNER_LOOP_END:.+]]
+// CHECK: [[INNER_LOOP_BODY]]
+// <<TRUE>> - > <BODY>
+// CHECK: [[IV:%.+]] = load i32, i32* [[IV_PTR]]
+// CHECK: switch i32 [[IV]], label %[[SECTIONS_EXIT:.+]] [
+// CHECK-NEXT: i32 0, label %[[SECTIONS_CASE0:.+]]
+// CHECK-NEXT: i32 1, label %[[SECTIONS_CASE1:.+]]
+#pragma omp section
+// CHECK: [[SECTIONS_CASE0]]
+// CHECK-NEXT: invoke void @{{.*}}foo{{.*}}()
+// CHECK: br label %[[SECTIONS_EXIT]]
+ foo();
+#pragma omp section
+// CHECK: [[SECTIONS_CASE1]]
+// CHECK-NEXT: invoke void @{{.*}}bar{{.*}}()
+// CHECK: br label %[[SECTIONS_EXIT]]
+ bar();
+// CHECK: [[SECTIONS_EXIT]]
+// <<++IV;>>
+// CHECK: [[IV:%.+]] = load i32, i32* [[IV_PTR]]
+// CHECK-NEXT: [[INC:%.+]] = add nsw i32 [[IV]], 1
+// CHECK-NEXT: store i32 [[INC]], i32* [[IV_PTR]]
+// CHECK-NEXT: br label %[[INNER_FOR_COND]]
+// CHECK: [[INNER_LOOP_END]]
+ }
+// CHECK: call void @__kmpc_for_static_fini(%{{.+}}* @{{.+}}, i32 [[GTID]])
+// CHECK: call i32 @__kmpc_cancel_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]],
+ return tmain<int>();
+}
+
+// CHECK-LABEL: tmain
+// CHECK: call void {{.*}} @__kmpc_fork_call(
+// CHECK-NOT: __kmpc_global_thread_num
+// CHECK: [[RES:%.+]] = call i32 @__kmpc_single(
+// CHECK-NEXT: [[BOOLRES:%.+]] = icmp ne i32 [[RES]], 0
+// CHECK-NEXT: br i1 [[BOOLRES]], label %[[THEN:.+]], label %[[END:.+]]
+// CHECK: [[THEN]]
+// CHECK-NEXT: invoke void @{{.*}}foo{{.*}}()
+// CHECK-NEXT: unwind label %[[TERM_LPAD:.+]]
+// CHECK: call void @__kmpc_end_single(
+// CHECK-NEXT: br label %[[END]]
+// CHECK: [[END]]
+// CHECK-NEXT: call i32 @__kmpc_cancel_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]],
+// CHECK-NEXT: ret
+// CHECK: [[TERM_LPAD]]
+// CHECK: call void @__clang_call_terminate(i8*
+// CHECK-NEXT: unreachable
+
+#endif
diff --git a/test/OpenMP/parallel_sections_copyin_messages.cpp b/test/OpenMP/parallel_sections_copyin_messages.cpp
index 500417e..d76e580 100644
--- a/test/OpenMP/parallel_sections_copyin_messages.cpp
+++ b/test/OpenMP/parallel_sections_copyin_messages.cpp
@@ -22,18 +22,18 @@
S3() : a(0) {}
S3 &operator=(S3 &s3) { return *this; }
};
-class S4 { // expected-note {{'S4' declared here}}
+class S4 {
int a;
S4();
- S4 &operator=(const S4 &s4);
+ S4 &operator=(const S4 &s4); // expected-note {{implicitly declared private here}}
public:
S4(int v) : a(v) {}
};
-class S5 { // expected-note {{'S5' declared here}}
+class S5 {
int a;
S5() : a(0) {}
- S5 &operator=(const S5 &s5) { return *this; }
+ S5 &operator=(const S5 &s5) { return *this; } // expected-note {{implicitly declared private here}}
public:
S5(int v) : a(v) {}
@@ -46,10 +46,18 @@
S2 k;
S3 h;
-S4 l(3); // expected-note {{'l' defined here}}
-S5 m(4); // expected-note {{'m' defined here}}
+S4 l(3);
+S5 m(4);
#pragma omp threadprivate(h, k, l, m)
+namespace A {
+double x;
+#pragma omp threadprivate(x)
+}
+namespace B {
+using A::x;
+}
+
int main(int argc, char **argv) {
int i;
#pragma omp parallel sections copyin // expected-error {{expected '(' after 'copyin'}}
@@ -76,7 +84,7 @@
{
foo();
}
-#pragma omp parallel sections copyin(l) // expected-error {{copyin variable must have an accessible, unambiguous copy assignment operator}}
+#pragma omp parallel sections copyin(l) // expected-error {{'operator=' is a private member of 'S4'}}
{
foo();
}
@@ -92,11 +100,11 @@
{
foo();
}
-#pragma omp parallel sections copyin(m) // expected-error {{copyin variable must have an accessible, unambiguous copy assignment operator}}
+#pragma omp parallel sections copyin(m) // expected-error {{'operator=' is a private member of 'S5'}}
{
foo();
}
-#pragma omp parallel sections copyin(ST < int > ::s) // expected-error {{copyin variable must be threadprivate}}
+#pragma omp parallel sections copyin(ST < int > ::s, B::x) // expected-error {{copyin variable must be threadprivate}}
{
foo();
}
diff --git a/test/OpenMP/parallel_sections_firstprivate_messages.cpp b/test/OpenMP/parallel_sections_firstprivate_messages.cpp
index 2d27b1a..23ae128 100644
--- a/test/OpenMP/parallel_sections_firstprivate_messages.cpp
+++ b/test/OpenMP/parallel_sections_firstprivate_messages.cpp
@@ -155,6 +155,14 @@
return 0;
}
+namespace A {
+double x;
+#pragma omp threadprivate(x) // expected-note {{defined as threadprivate or thread local}}
+}
+namespace B {
+using A::x;
+}
+
int main(int argc, char **argv) {
const int d = 5;
const int da[5] = {0};
@@ -245,7 +253,7 @@
{
foo();
}
-#pragma omp parallel sections firstprivate(h) // expected-error {{threadprivate or thread local variable cannot be firstprivate}}
+#pragma omp parallel sections firstprivate(h, B::x) // expected-error 2 {{threadprivate or thread local variable cannot be firstprivate}}
{
foo();
}
diff --git a/test/OpenMP/parallel_sections_lastprivate_messages.cpp b/test/OpenMP/parallel_sections_lastprivate_messages.cpp
index 6d790e4..067a597 100644
--- a/test/OpenMP/parallel_sections_lastprivate_messages.cpp
+++ b/test/OpenMP/parallel_sections_lastprivate_messages.cpp
@@ -15,15 +15,16 @@
public:
S2() : a(0) {}
S2(S2 &s2) : a(s2.a) {}
+ const S2 &operator=(const S2 &) const;
static float S2s;
static const float S2sc;
};
const float S2::S2sc = 0; // expected-note {{static data member is predetermined as shared}}
const S2 b;
const S2 ba[5];
-class S3 { // expected-note 2 {{'S3' declared here}}
+class S3 {
int a;
- S3 &operator=(const S3 &s3);
+ S3 &operator=(const S3 &s3); // expected-note 2 {{implicitly declared private here}}
public:
S3() : a(0) {}
@@ -32,17 +33,17 @@
const S3 c; // expected-note {{global variable is predetermined as shared}}
const S3 ca[5]; // expected-note {{global variable is predetermined as shared}}
extern const int f; // expected-note {{global variable is predetermined as shared}}
-class S4 { // expected-note 3 {{'S4' declared here}}
+class S4 {
int a;
- S4();
+ S4(); // expected-note 3 {{implicitly declared private here}}
S4(const S4 &s4);
public:
S4(int v) : a(v) {}
};
-class S5 { // expected-note {{'S5' declared here}}
+class S5 {
int a;
- S5() : a(0) {}
+ S5() : a(0) {} // expected-note {{implicitly declared private here}}
public:
S5(const S5 &s5) : a(s5.a) {}
@@ -62,8 +63,8 @@
template <class I, class C>
int foomain(int argc, char **argv) {
- I e(4); // expected-note {{'e' defined here}}
- I g(5); // expected-note {{'g' defined here}}
+ I e(4);
+ I g(5);
int i;
int &j = i; // expected-note {{'j' defined here}}
#pragma omp parallel sections lastprivate // expected-error {{expected '(' after 'lastprivate'}}
@@ -106,7 +107,7 @@
{
foo();
}
-#pragma omp parallel sections lastprivate(e, g) // expected-error 2 {{lastprivate variable must have an accessible, unambiguous default constructor}}
+#pragma omp parallel sections lastprivate(e, g) // expected-error 2 {{calling a private constructor of class 'S4'}}
{
foo();
}
@@ -141,12 +142,20 @@
return 0;
}
+namespace A {
+double x;
+#pragma omp threadprivate(x) // expected-note {{defined as threadprivate or thread local}}
+}
+namespace B {
+using A::x;
+}
+
int main(int argc, char **argv) {
const int d = 5; // expected-note {{constant variable is predetermined as shared}}
const int da[5] = {0}; // expected-note {{constant variable is predetermined as shared}}
- S4 e(4); // expected-note {{'e' defined here}}
- S5 g(5); // expected-note {{'g' defined here}}
- S3 m; // expected-note 2 {{'m' defined here}}
+ S4 e(4);
+ S5 g(5);
+ S3 m;
S6 n(2);
int i;
int &j = i; // expected-note {{'j' defined here}}
@@ -223,15 +232,15 @@
{
foo();
}
-#pragma omp parallel sections lastprivate(e, g) // expected-error 2 {{lastprivate variable must have an accessible, unambiguous default constructor}}
+#pragma omp parallel sections lastprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
{
foo();
}
-#pragma omp parallel sections lastprivate(m) // expected-error {{lastprivate variable must have an accessible, unambiguous copy assignment operator}}
+#pragma omp parallel sections lastprivate(m) // expected-error {{'operator=' is a private member of 'S3'}}
{
foo();
}
-#pragma omp parallel sections lastprivate(h) // expected-error {{threadprivate or thread local variable cannot be lastprivate}}
+#pragma omp parallel sections lastprivate(h, B::x) // expected-error 2 {{threadprivate or thread local variable cannot be lastprivate}}
{
foo();
}
@@ -257,7 +266,7 @@
{
foo();
}
-#pragma omp parallel sections firstprivate(m) lastprivate(m) // expected-error {{lastprivate variable must have an accessible, unambiguous copy assignment operator}}
+#pragma omp parallel sections firstprivate(m) lastprivate(m) // expected-error {{'operator=' is a private member of 'S3'}}
{
foo();
}
diff --git a/test/OpenMP/parallel_sections_private_messages.cpp b/test/OpenMP/parallel_sections_private_messages.cpp
index e0b7488..47c904d 100644
--- a/test/OpenMP/parallel_sections_private_messages.cpp
+++ b/test/OpenMP/parallel_sections_private_messages.cpp
@@ -123,6 +123,14 @@
return 0;
}
+namespace A {
+double x;
+#pragma omp threadprivate(x) // expected-note {{defined as threadprivate or thread local}}
+}
+namespace B {
+using A::x;
+}
+
int main(int argc, char **argv) {
S4 e(4);
S5 g(5);
@@ -172,7 +180,7 @@
{
foo();
}
-#pragma omp parallel sections private(h) // expected-error {{threadprivate or thread local variable cannot be private}}
+#pragma omp parallel sections private(h, B::x) // expected-error 2 {{threadprivate or thread local variable cannot be private}}
{
foo();
}
diff --git a/test/OpenMP/parallel_sections_reduction_messages.cpp b/test/OpenMP/parallel_sections_reduction_messages.cpp
index 68f494f..d152f49 100644
--- a/test/OpenMP/parallel_sections_reduction_messages.cpp
+++ b/test/OpenMP/parallel_sections_reduction_messages.cpp
@@ -11,7 +11,7 @@
extern S1 a;
class S2 {
mutable int a;
- S2 &operator+=(const S2 &arg) { return (*this); }
+ S2 &operator+(const S2 &arg) { return (*this); } // expected-note 4 {{implicitly declared private here}}
public:
S2() : a(0) {}
@@ -28,17 +28,17 @@
public:
S3() : a(0) {}
S3(const S3 &s3) : a(s3.a) {}
- S3 operator+=(const S3 &arg1) { return arg1; }
+ S3 operator+(const S3 &arg1) { return arg1; }
};
-int operator+=(const S3 &arg1, const S3 &arg2) { return 5; }
+int operator+(const S3 &arg1, const S3 &arg2) { return 5; }
S3 c; // expected-note 2 {{'c' defined here}}
const S3 ca[5]; // expected-note 2 {{'ca' defined here}}
extern const int f; // expected-note 4 {{'f' declared here}}
-class S4 { // expected-note {{'S4' declared here}}
+class S4 {
int a;
- S4();
+ S4(); // expected-note {{implicitly declared private here}}
S4(const S4 &s4);
- S4 &operator+=(const S4 &arg) { return (*this); }
+ S4 &operator+(const S4 &arg) { return (*this); }
public:
S4(int v) : a(v) {}
@@ -46,26 +46,26 @@
S4 &operator&=(S4 &arg1, S4 &arg2) { return arg1; }
class S5 {
int a;
- S5() : a(0) {}
+ S5() : a(0) {} // expected-note {{implicitly declared private here}}
S5(const S5 &s5) : a(s5.a) {}
- S5 &operator+=(const S5 &arg);
+ S5 &operator+(const S5 &arg);
public:
S5(int v) : a(v) {}
};
-class S6 {
+class S6 { // expected-note 2 {{candidate function (the implicit copy assignment operator) not viable: no known conversion from 'int' to 'const S6' for 1st argument}}
int a;
public:
S6() : a(6) {}
operator int() { return 6; }
-} o; // expected-note 2 {{'o' defined here}}
+} o;
S3 h, k;
#pragma omp threadprivate(h) // expected-note 2 {{defined as threadprivate or thread local}}
template <class T> // expected-note {{declared here}}
-T tmain(T argc) { // expected-note 2 {{'argc' defined here}}
+T tmain(T argc) {
const T d = T(); // expected-note 4 {{'d' defined here}}
const T da[5] = {T()}; // expected-note 2 {{'da' defined here}}
T qa[5] = {T()};
@@ -74,7 +74,7 @@
S3 &p = k; // expected-note 2 {{'p' defined here}}
const T &r = da[(int)i]; // expected-note 2 {{'r' defined here}}
T &q = qa[(int)i]; // expected-note 2 {{'q' defined here}}
- T fl; // expected-note {{'fl' defined here}}
+ T fl;
#pragma omp parallel sections reduction // expected-error {{expected '(' after 'reduction'}}
{
foo();
@@ -103,11 +103,11 @@
{
foo();
}
-#pragma omp parallel sections reduction(& : argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{variable of type 'float' is not valid for specified reduction operation}}
+#pragma omp parallel sections reduction(& : argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{invalid operands to binary expression ('float' and 'float')}}
{
foo();
}
-#pragma omp parallel sections reduction(| : argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{variable of type 'float' is not valid for specified reduction operation}}
+#pragma omp parallel sections reduction(| : argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{invalid operands to binary expression ('float' and 'float')}}
{
foo();
}
@@ -127,7 +127,7 @@
{
foo();
}
-#pragma omp parallel sections reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 3 {{const-qualified variable cannot be reduction}}
+#pragma omp parallel sections reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 3 {{const-qualified variable cannot be reduction}} expected-error 3 {{'operator+' is a private member of 'S2'}}
{
foo();
}
@@ -151,7 +151,7 @@
{
foo();
}
-#pragma omp parallel sections reduction(^ : fl) // expected-error {{variable of type 'float' is not valid for specified reduction operation}}
+#pragma omp parallel sections reduction(^ : fl) // expected-error {{invalid operands to binary expression ('float' and 'float')}}
{
foo();
}
@@ -167,7 +167,7 @@
{
foo();
}
-#pragma omp parallel sections reduction(+ : o) // expected-error {{variable of type 'class S6' is not valid for specified reduction operation}}
+#pragma omp parallel sections reduction(+ : o) // expected-error {{no viable overloaded '='}}
{
foo();
}
@@ -208,18 +208,26 @@
return T();
}
+namespace A {
+double x;
+#pragma omp threadprivate(x) // expected-note {{defined as threadprivate or thread local}}
+}
+namespace B {
+using A::x;
+}
+
int main(int argc, char **argv) {
const int d = 5; // expected-note 2 {{'d' defined here}}
const int da[5] = {0}; // expected-note {{'da' defined here}}
int qa[5] = {0};
- S4 e(4); // expected-note {{'e' defined here}}
- S5 g(5); // expected-note {{'g' defined here}}
+ S4 e(4);
+ S5 g(5);
int i;
int &j = i; // expected-note 2 {{'j' defined here}}
S3 &p = k; // expected-note 2 {{'p' defined here}}
const int &r = da[i]; // expected-note {{'r' defined here}}
int &q = qa[i]; // expected-note {{'q' defined here}}
- float fl; // expected-note {{'fl' defined here}}
+ float fl;
#pragma omp parallel sections reduction // expected-error {{expected '(' after 'reduction'}}
{
foo();
@@ -272,7 +280,7 @@
{
foo();
}
-#pragma omp parallel sections reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{const-qualified variable cannot be reduction}}
+#pragma omp parallel sections reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{const-qualified variable cannot be reduction}} expected-error {{'operator+' is a private member of 'S2'}}
{
foo();
}
@@ -296,7 +304,7 @@
{
foo();
}
-#pragma omp parallel sections reduction(^ : fl) // expected-error {{variable of type 'float' is not valid for specified reduction operation}}
+#pragma omp parallel sections reduction(^ : fl) // expected-error {{invalid operands to binary expression ('float' and 'float')}}
{
foo();
}
@@ -308,15 +316,15 @@
{
foo();
}
-#pragma omp parallel sections reduction(& : e, g) // expected-error {{reduction variable must have an accessible, unambiguous default constructor}} expected-error {{variable of type 'S5' is not valid for specified reduction operation}}
+#pragma omp parallel sections reduction(& : e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{invalid operands to binary expression ('S4' and 'S4')}} expected-error {{calling a private constructor of class 'S5'}} expected-error {{invalid operands to binary expression ('S5' and 'S5')}}
{
foo();
}
-#pragma omp parallel sections reduction(+ : h, k) // expected-error {{threadprivate or thread local variable cannot be reduction}}
+#pragma omp parallel sections reduction(+ : h, k, B::x) // expected-error 2 {{threadprivate or thread local variable cannot be reduction}}
{
foo();
}
-#pragma omp parallel sections reduction(+ : o) // expected-error {{variable of type 'class S6' is not valid for specified reduction operation}}
+#pragma omp parallel sections reduction(+ : o) // expected-error {{no viable overloaded '='}}
{
foo();
}
diff --git a/test/OpenMP/parallel_sections_shared_messages.cpp b/test/OpenMP/parallel_sections_shared_messages.cpp
index d4915c8..0f7a147 100644
--- a/test/OpenMP/parallel_sections_shared_messages.cpp
+++ b/test/OpenMP/parallel_sections_shared_messages.cpp
@@ -48,6 +48,14 @@
S3 h;
#pragma omp threadprivate(h) // expected-note {{defined as threadprivate or thread local}}
+namespace A {
+double x;
+#pragma omp threadprivate(x) // expected-note {{defined as threadprivate or thread local}}
+}
+namespace B {
+using A::x;
+}
+
int main(int argc, char **argv) {
const int d = 5;
const int da[5] = {0};
@@ -83,7 +91,7 @@
{ foo(); }
#pragma omp parallel sections shared(e, g)
{ foo(); }
-#pragma omp parallel sections shared(h) // expected-error {{threadprivate or thread local variable cannot be shared}}
+#pragma omp parallel sections shared(h, B::x) // expected-error 2 {{threadprivate or thread local variable cannot be shared}}
{ foo(); }
#pragma omp parallel sections private(i), shared(i) // expected-error {{private variable cannot be shared}} expected-note {{defined as private}}
{ foo(); }
diff --git a/test/OpenMP/parallel_shared_messages.cpp b/test/OpenMP/parallel_shared_messages.cpp
index 8363989..7cbc791 100644
--- a/test/OpenMP/parallel_shared_messages.cpp
+++ b/test/OpenMP/parallel_shared_messages.cpp
@@ -44,6 +44,14 @@
S3 h;
#pragma omp threadprivate(h) // expected-note {{defined as threadprivate or thread local}}
+namespace A {
+double x;
+#pragma omp threadprivate(x) // expected-note {{defined as threadprivate or thread local}}
+}
+namespace B {
+using A::x;
+}
+
int main(int argc, char **argv) {
const int d = 5;
const int da[5] = { 0 };
@@ -65,7 +73,7 @@
#pragma omp parallel shared(ca)
#pragma omp parallel shared(da)
#pragma omp parallel shared(e, g)
- #pragma omp parallel shared(h) // expected-error {{threadprivate or thread local variable cannot be shared}}
+ #pragma omp parallel shared(h, B::x) // expected-error 2 {{threadprivate or thread local variable cannot be shared}}
#pragma omp parallel private(i), shared(i) // expected-error {{private variable cannot be shared}} expected-note {{defined as private}}
foo();
#pragma omp parallel firstprivate(i), shared(i) // expected-error {{firstprivate variable cannot be shared}} expected-note {{defined as firstprivate}}
diff --git a/test/OpenMP/sections_codegen.cpp b/test/OpenMP/sections_codegen.cpp
index 9485d9f..3a1d126 100644
--- a/test/OpenMP/sections_codegen.cpp
+++ b/test/OpenMP/sections_codegen.cpp
@@ -5,7 +5,8 @@
#ifndef HEADER
#define HEADER
-
+// CHECK: [[IMPLICIT_BARRIER_SECTIONS_LOC:@.+]] = private unnamed_addr constant %{{.+}} { i32 0, i32 194, i32 0, i32 0, i8*
+// CHECK: [[IMPLICIT_BARRIER_SINGLE_LOC:@.+]] = private unnamed_addr constant %{{.+}} { i32 0, i32 322, i32 0, i32 0, i8*
// CHECK-LABEL: foo
void foo() {};
// CHECK-LABEL: bar
@@ -26,7 +27,7 @@
float l = 0.0; // Used as a base point in checks.
// CHECK: [[GTID:%.+]] = call{{.*}} i32 @__kmpc_global_thread_num({{.*}})
// CHECK: store float
-#pragma omp sections nowait
+#pragma omp sections
{
// CHECK: store i32 0, i32* [[LB_PTR:%.+]],
// CHECK: store i32 1, i32* [[UB_PTR:%.+]],
@@ -71,6 +72,13 @@
// CHECK: [[INNER_LOOP_END]]
}
// CHECK: call void @__kmpc_for_static_fini(%{{.+}}* @{{.+}}, i32 [[GTID]])
+// CHECK: call i32 @__kmpc_cancel_barrier(%{{.+}}* [[IMPLICIT_BARRIER_SECTIONS_LOC]],
+#pragma omp sections nowait
+ {
+ foo();
+#pragma omp section
+ bar();
+ }
// CHECK-NOT: __kmpc_cancel_barrier
return tmain<int>();
}
@@ -87,6 +95,7 @@
// CHECK: call void @__kmpc_end_single(
// CHECK-NEXT: br label %[[END]]
// CHECK: [[END]]
+// CHECK-NEXT: call i32 @__kmpc_cancel_barrier(%{{.+}}* [[IMPLICIT_BARRIER_SINGLE_LOC]],
// CHECK-NEXT: call i32 @__kmpc_cancel_barrier(
// CHECK-NEXT: ret
// CHECK: [[TERM_LPAD]]
diff --git a/test/OpenMP/sections_firstprivate_messages.cpp b/test/OpenMP/sections_firstprivate_messages.cpp
index ecee459..6f9f502 100644
--- a/test/OpenMP/sections_firstprivate_messages.cpp
+++ b/test/OpenMP/sections_firstprivate_messages.cpp
@@ -170,6 +170,14 @@
return 0;
}
+namespace A {
+double x;
+#pragma omp threadprivate(x) // expected-note {{defined as threadprivate or thread local}}
+}
+namespace B {
+using A::x;
+}
+
int main(int argc, char **argv) {
const int d = 5;
const int da[5] = {0};
@@ -281,7 +289,7 @@
foo();
}
#pragma omp parallel
-#pragma omp sections firstprivate(h) // expected-error {{threadprivate or thread local variable cannot be firstprivate}}
+#pragma omp sections firstprivate(h, B::x) // expected-error 2 {{threadprivate or thread local variable cannot be firstprivate}}
{
foo();
}
diff --git a/test/OpenMP/sections_lastprivate_messages.cpp b/test/OpenMP/sections_lastprivate_messages.cpp
index 54c6005..f513d89 100644
--- a/test/OpenMP/sections_lastprivate_messages.cpp
+++ b/test/OpenMP/sections_lastprivate_messages.cpp
@@ -15,15 +15,16 @@
public:
S2() : a(0) {}
S2(S2 &s2) : a(s2.a) {}
+ const S2 &operator=(const S2 &) const;
static float S2s; // expected-note {{static data member is predetermined as shared}}
static const float S2sc;
};
const float S2::S2sc = 0; // expected-note {{static data member is predetermined as shared}}
const S2 b;
const S2 ba[5];
-class S3 { // expected-note 2 {{'S3' declared here}}
+class S3 {
int a;
- S3 &operator=(const S3 &s3);
+ S3 &operator=(const S3 &s3); // expected-note 2 {{implicitly declared private here}}
public:
S3() : a(0) {}
@@ -32,17 +33,17 @@
const S3 c; // expected-note {{global variable is predetermined as shared}}
const S3 ca[5]; // expected-note {{global variable is predetermined as shared}}
extern const int f; // expected-note {{global variable is predetermined as shared}}
-class S4 { // expected-note 3 {{'S4' declared here}}
+class S4 {
int a;
- S4();
+ S4(); // expected-note 3 {{implicitly declared private here}}
S4(const S4 &s4);
public:
S4(int v) : a(v) {}
};
-class S5 { // expected-note {{'S5' declared here}}
+class S5 {
int a;
- S5() : a(0) {}
+ S5() : a(0) {} // expected-note {{implicitly declared private here}}
public:
S5(const S5 &s5) : a(s5.a) {}
@@ -62,8 +63,8 @@
template <class I, class C>
int foomain(int argc, char **argv) {
- I e(4); // expected-note {{'e' defined here}}
- I g(5); // expected-note {{'g' defined here}}
+ I e(4);
+ I g(5);
int i;
int &j = i; // expected-note {{'j' defined here}}
#pragma omp parallel
@@ -117,7 +118,7 @@
foo();
}
#pragma omp parallel
-#pragma omp sections lastprivate(e, g) // expected-error 2 {{lastprivate variable must have an accessible, unambiguous default constructor}}
+#pragma omp sections lastprivate(e, g) // expected-error 2 {{calling a private constructor of class 'S4'}}
{
foo();
}
@@ -155,12 +156,20 @@
return 0;
}
+namespace A {
+double x;
+#pragma omp threadprivate(x) // expected-note {{defined as threadprivate or thread local}}
+}
+namespace B {
+using A::x;
+}
+
int main(int argc, char **argv) {
const int d = 5; // expected-note {{constant variable is predetermined as shared}}
const int da[5] = {0}; // expected-note {{constant variable is predetermined as shared}}
- S4 e(4); // expected-note {{'e' defined here}}
- S5 g(5); // expected-note {{'g' defined here}}
- S3 m; // expected-note 2 {{'m' defined here}}
+ S4 e(4);
+ S5 g(5);
+ S3 m;
S6 n(2);
int i;
int &j = i; // expected-note {{'j' defined here}}
@@ -256,17 +265,17 @@
foo();
}
#pragma omp parallel
-#pragma omp sections lastprivate(e, g) // expected-error 2 {{lastprivate variable must have an accessible, unambiguous default constructor}}
+#pragma omp sections lastprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
{
foo();
}
#pragma omp parallel
-#pragma omp sections lastprivate(m) // expected-error {{lastprivate variable must have an accessible, unambiguous copy assignment operator}}
+#pragma omp sections lastprivate(m) // expected-error {{'operator=' is a private member of 'S3'}}
{
foo();
}
#pragma omp parallel
-#pragma omp sections lastprivate(h) // expected-error {{threadprivate or thread local variable cannot be lastprivate}}
+#pragma omp sections lastprivate(h, B::x) // expected-error 2 {{threadprivate or thread local variable cannot be lastprivate}}
{
foo();
}
@@ -296,7 +305,7 @@
foo();
}
#pragma omp parallel
-#pragma omp sections firstprivate(m) lastprivate(m) // expected-error {{lastprivate variable must have an accessible, unambiguous copy assignment operator}}
+#pragma omp sections firstprivate(m) lastprivate(m) // expected-error {{'operator=' is a private member of 'S3'}}
{
foo();
}
diff --git a/test/OpenMP/sections_private_messages.cpp b/test/OpenMP/sections_private_messages.cpp
index 8b330bf..ea5fe39 100644
--- a/test/OpenMP/sections_private_messages.cpp
+++ b/test/OpenMP/sections_private_messages.cpp
@@ -123,6 +123,14 @@
return 0;
}
+namespace A {
+double x;
+#pragma omp threadprivate(x) // expected-note {{defined as threadprivate or thread local}}
+}
+namespace B {
+using A::x;
+}
+
int main(int argc, char **argv) {
S4 e(4);
S5 g(5);
@@ -172,7 +180,7 @@
{
foo();
}
-#pragma omp sections private(h) // expected-error {{threadprivate or thread local variable cannot be private}}
+#pragma omp sections private(h, B::x) // expected-error 2 {{threadprivate or thread local variable cannot be private}}
{
foo();
}
diff --git a/test/OpenMP/sections_reduction_messages.cpp b/test/OpenMP/sections_reduction_messages.cpp
index 8c4bdcc..6560937 100644
--- a/test/OpenMP/sections_reduction_messages.cpp
+++ b/test/OpenMP/sections_reduction_messages.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -ferror-limit 100 -o - %s
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -ferror-limit 150 -o - %s
void foo() {
}
@@ -11,7 +11,7 @@
extern S1 a;
class S2 {
mutable int a;
- S2 &operator+=(const S2 &arg) { return (*this); }
+ S2 &operator+(const S2 &arg) { return (*this); } // expected-note 4 {{implicitly declared private here}}
public:
S2() : a(0) {}
@@ -28,17 +28,17 @@
public:
S3() : a(0) {}
S3(const S3 &s3) : a(s3.a) {}
- S3 operator+=(const S3 &arg1) { return arg1; }
+ S3 operator+(const S3 &arg1) { return arg1; }
};
-int operator+=(const S3 &arg1, const S3 &arg2) { return 5; }
+int operator+(const S3 &arg1, const S3 &arg2) { return 5; }
S3 c; // expected-note 2 {{'c' defined here}}
const S3 ca[5]; // expected-note 2 {{'ca' defined here}}
extern const int f; // expected-note 4 {{'f' declared here}}
-class S4 { // expected-note {{'S4' declared here}}
+class S4 {
int a;
- S4();
+ S4(); // expected-note {{implicitly declared private here}}
S4(const S4 &s4);
- S4 &operator+=(const S4 &arg) { return (*this); }
+ S4 &operator+(const S4 &arg) { return (*this); }
public:
S4(int v) : a(v) {}
@@ -46,26 +46,26 @@
S4 &operator&=(S4 &arg1, S4 &arg2) { return arg1; }
class S5 {
int a;
- S5() : a(0) {}
+ S5() : a(0) {} // expected-note {{implicitly declared private here}}
S5(const S5 &s5) : a(s5.a) {}
- S5 &operator+=(const S5 &arg);
+ S5 &operator+(const S5 &arg);
public:
S5(int v) : a(v) {}
};
-class S6 {
+class S6 { // expected-note 2 {{candidate function (the implicit copy assignment operator) not viable: no known conversion from 'int' to 'const S6' for 1st argument}}
int a;
public:
S6() : a(6) {}
operator int() { return 6; }
-} o; // expected-note 2 {{'o' defined here}}
+} o;
S3 h, k;
#pragma omp threadprivate(h) // expected-note 2 {{defined as threadprivate or thread local}}
template <class T> // expected-note {{declared here}}
-T tmain(T argc) { // expected-note 2 {{'argc' defined here}}
+T tmain(T argc) {
const T d = T(); // expected-note 4 {{'d' defined here}}
const T da[5] = {T()}; // expected-note 2 {{'da' defined here}}
T qa[5] = {T()};
@@ -74,7 +74,7 @@
S3 &p = k; // expected-note 2 {{'p' defined here}}
const T &r = da[(int)i]; // expected-note 2 {{'r' defined here}}
T &q = qa[(int)i]; // expected-note 2 {{'q' defined here}}
- T fl; // expected-note {{'fl' defined here}}
+ T fl;
#pragma omp parallel
#pragma omp sections reduction // expected-error {{expected '(' after 'reduction'}}
{
@@ -111,12 +111,12 @@
foo();
}
#pragma omp parallel
-#pragma omp sections reduction(& : argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{variable of type 'float' is not valid for specified reduction operation}}
+#pragma omp sections reduction(& : argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{invalid operands to binary expression ('float' and 'float')}}
{
foo();
}
#pragma omp parallel
-#pragma omp sections reduction(| : argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{variable of type 'float' is not valid for specified reduction operation}}
+#pragma omp sections reduction(| : argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{invalid operands to binary expression ('float' and 'float')}}
{
foo();
}
@@ -141,7 +141,7 @@
foo();
}
#pragma omp parallel
-#pragma omp sections reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 3 {{const-qualified variable cannot be reduction}}
+#pragma omp sections reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 3 {{const-qualified variable cannot be reduction}} expected-error 3 {{'operator+' is a private member of 'S2'}}
{
foo();
}
@@ -171,7 +171,7 @@
foo();
}
#pragma omp parallel
-#pragma omp sections reduction(^ : fl) // expected-error {{variable of type 'float' is not valid for specified reduction operation}}
+#pragma omp sections reduction(^ : fl) // expected-error {{invalid operands to binary expression ('float' and 'float')}}
{
foo();
}
@@ -191,7 +191,7 @@
foo();
}
#pragma omp parallel
-#pragma omp sections reduction(+ : o) // expected-error {{variable of type 'class S6' is not valid for specified reduction operation}}
+#pragma omp sections reduction(+ : o) // expected-error {{no viable overloaded '='}}
{
foo();
}
@@ -235,18 +235,26 @@
return T();
}
+namespace A {
+double x;
+#pragma omp threadprivate(x) // expected-note {{defined as threadprivate or thread local}}
+}
+namespace B {
+using A::x;
+}
+
int main(int argc, char **argv) {
const int d = 5; // expected-note 2 {{'d' defined here}}
const int da[5] = {0}; // expected-note {{'da' defined here}}
int qa[5] = {0};
- S4 e(4); // expected-note {{'e' defined here}}
- S5 g(5); // expected-note {{'g' defined here}}
+ S4 e(4);
+ S5 g(5);
int i;
int &j = i; // expected-note 2 {{'j' defined here}}
S3 &p = k; // expected-note 2 {{'p' defined here}}
const int &r = da[i]; // expected-note {{'r' defined here}}
int &q = qa[i]; // expected-note {{'q' defined here}}
- float fl; // expected-note {{'fl' defined here}}
+ float fl;
#pragma omp parallel
#pragma omp sections reduction // expected-error {{expected '(' after 'reduction'}}
{
@@ -313,7 +321,7 @@
foo();
}
#pragma omp parallel
-#pragma omp sections reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{const-qualified variable cannot be reduction}}
+#pragma omp sections reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{const-qualified variable cannot be reduction}} expected-error {{'operator+' is a private member of 'S2'}}
{
foo();
}
@@ -343,7 +351,7 @@
foo();
}
#pragma omp parallel
-#pragma omp sections reduction(^ : fl) // expected-error {{variable of type 'float' is not valid for specified reduction operation}}
+#pragma omp sections reduction(^ : fl) // expected-error {{invalid operands to binary expression ('float' and 'float')}}
{
foo();
}
@@ -358,17 +366,17 @@
foo();
}
#pragma omp parallel
-#pragma omp sections reduction(& : e, g) // expected-error {{reduction variable must have an accessible, unambiguous default constructor}} expected-error {{variable of type 'S5' is not valid for specified reduction operation}}
+#pragma omp sections reduction(& : e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{invalid operands to binary expression ('S4' and 'S4')}} expected-error {{calling a private constructor of class 'S5'}} expected-error {{invalid operands to binary expression ('S5' and 'S5')}}
{
foo();
}
#pragma omp parallel
-#pragma omp sections reduction(+ : h, k) // expected-error {{threadprivate or thread local variable cannot be reduction}}
+#pragma omp sections reduction(+ : h, k, B::x) // expected-error 2 {{threadprivate or thread local variable cannot be reduction}}
{
foo();
}
#pragma omp parallel
-#pragma omp sections reduction(+ : o) // expected-error {{variable of type 'class S6' is not valid for specified reduction operation}}
+#pragma omp sections reduction(+ : o) // expected-error {{no viable overloaded '='}}
{
foo();
}
diff --git a/test/OpenMP/simd_lastprivate_messages.cpp b/test/OpenMP/simd_lastprivate_messages.cpp
index 55f6058..24cee01 100644
--- a/test/OpenMP/simd_lastprivate_messages.cpp
+++ b/test/OpenMP/simd_lastprivate_messages.cpp
@@ -15,15 +15,16 @@
public:
S2() : a(0) {}
S2(S2 &s2) : a(s2.a) {}
+ const S2 &operator=(const S2 &) const;
static float S2s; // expected-note {{static data member is predetermined as shared}}
static const float S2sc;
};
const float S2::S2sc = 0; // expected-note {{static data member is predetermined as shared}}
const S2 b;
const S2 ba[5];
-class S3 { // expected-note {{'S3' declared here}}
+class S3 {
int a;
- S3 &operator=(const S3 &s3);
+ S3 &operator=(const S3 &s3); // expected-note {{implicitly declared private here}}
public:
S3() : a(0) {}
@@ -32,17 +33,17 @@
const S3 c; // expected-note {{global variable is predetermined as shared}}
const S3 ca[5]; // expected-note {{global variable is predetermined as shared}}
extern const int f; // expected-note {{global variable is predetermined as shared}}
-class S4 { // expected-note {{'S4' declared here}}
+class S4 {
int a;
- S4();
+ S4(); // expected-note {{implicitly declared private here}}
S4(const S4 &s4);
public:
S4(int v) : a(v) {}
};
-class S5 { // expected-note {{'S5' declared here}}
+class S5 {
int a;
- S5() : a(0) {}
+ S5() : a(0) {} // expected-note {{implicitly declared private here}}
public:
S5(const S5 &s5) : a(s5.a) {}
@@ -52,6 +53,14 @@
S3 h;
#pragma omp threadprivate(h) // expected-note 2 {{defined as threadprivate or thread local}}
+namespace A {
+double x;
+#pragma omp threadprivate(x) // expected-note {{defined as threadprivate or thread local}}
+}
+namespace B {
+using A::x;
+}
+
template <class I, class C>
int foomain(I argc, C **argv) {
I e(4);
@@ -91,7 +100,7 @@
#pragma omp simd lastprivate(e, g)
for (int k = 0; k < argc; ++k)
++k;
-#pragma omp simd lastprivate(h) // expected-error {{threadprivate or thread local variable cannot be lastprivate}}
+#pragma omp simd lastprivate(h, B::x) // expected-error 2 {{threadprivate or thread local variable cannot be lastprivate}}
for (int k = 0; k < argc; ++k)
++k;
#pragma omp simd firstprivate(i) // expected-error {{unexpected OpenMP clause 'firstprivate' in directive '#pragma omp simd'}}
@@ -121,9 +130,9 @@
int main(int argc, char **argv) {
const int d = 5; // expected-note {{constant variable is predetermined as shared}}
const int da[5] = {0}; // expected-note {{constant variable is predetermined as shared}}
- S4 e(4); // expected-note {{'e' defined here}}
- S5 g(5); // expected-note {{'g' defined here}}
- S3 m; // expected-note {{'m' defined here}}
+ S4 e(4);
+ S5 g(5);
+ S3 m;
int i;
int &j = i; // expected-note {{'j' defined here}}
#pragma omp simd lastprivate // expected-error {{expected '(' after 'lastprivate'}}
@@ -181,10 +190,10 @@
#pragma omp simd firstprivate(g) // expected-error {{unexpected OpenMP clause 'firstprivate' in directive '#pragma omp simd'}}
for (i = 0; i < argc; ++i)
foo();
-#pragma omp simd lastprivate(e, g) // expected-error 2 {{lastprivate variable must have an accessible, unambiguous default constructor}}
+#pragma omp simd lastprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
for (i = 0; i < argc; ++i)
foo();
-#pragma omp simd lastprivate(m) // expected-error {{lastprivate variable must have an accessible, unambiguous copy assignment operator}}
+#pragma omp simd lastprivate(m) // expected-error {{'operator=' is a private member of 'S3'}}
for (i = 0; i < argc; ++i)
foo();
#pragma omp simd lastprivate(h) // expected-error {{threadprivate or thread local variable cannot be lastprivate}}
diff --git a/test/OpenMP/simd_linear_messages.cpp b/test/OpenMP/simd_linear_messages.cpp
index b8b7831..94780fd 100644
--- a/test/OpenMP/simd_linear_messages.cpp
+++ b/test/OpenMP/simd_linear_messages.cpp
@@ -148,6 +148,14 @@
return 0;
}
+namespace A {
+double x;
+#pragma omp threadprivate(x) // expected-note {{defined as threadprivate or thread local}}
+}
+namespace C {
+using A::x;
+}
+
int main(int argc, char **argv) {
double darr[100];
// expected-note@+1 {{in instantiation of function template specialization 'test_template<-4, double, int>' requested here}}
@@ -177,7 +185,7 @@
for (int k = 0; k < argc; ++k) ++k;
// expected-error@+2 {{linear variable with incomplete type 'S1'}}
// expected-error@+1 {{const-qualified variable cannot be linear}}
- #pragma omp simd linear (a, b)
+ #pragma omp simd linear(a, b)
for (int k = 0; k < argc; ++k) ++k;
#pragma omp simd linear (argv[1]) // expected-error {{expected variable name}}
for (int k = 0; k < argc; ++k) ++k;
@@ -185,7 +193,7 @@
// expected-error@+1 {{argument of a linear clause should be of integral or pointer type, not 'S5'}}
#pragma omp simd linear(e, g)
for (int k = 0; k < argc; ++k) ++k;
- #pragma omp simd linear(h) // expected-error {{threadprivate or thread local variable cannot be linear}}
+ #pragma omp simd linear(h, C::x) // expected-error 2 {{threadprivate or thread local variable cannot be linear}}
for (int k = 0; k < argc; ++k) ++k;
#pragma omp parallel
{
diff --git a/test/OpenMP/simd_private_messages.cpp b/test/OpenMP/simd_private_messages.cpp
index 56922e8..47e6e31 100644
--- a/test/OpenMP/simd_private_messages.cpp
+++ b/test/OpenMP/simd_private_messages.cpp
@@ -85,6 +85,14 @@
return 0;
}
+namespace A {
+double x;
+#pragma omp threadprivate(x) // expected-note {{defined as threadprivate or thread local}}
+}
+namespace B {
+using A::x;
+}
+
int main(int argc, char **argv) {
S4 e(4);
S5 g(5);
@@ -112,7 +120,7 @@
for (int k = 0; k < argc; ++k) ++k;
#pragma omp simd private(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
for (int k = 0; k < argc; ++k) ++k;
- #pragma omp simd private(h) // expected-error {{threadprivate or thread local variable cannot be private}}
+ #pragma omp simd private(h, B::x) // expected-error 2 {{threadprivate or thread local variable cannot be private}}
for (int k = 0; k < argc; ++k) ++k;
#pragma omp simd shared(i) // expected-error {{unexpected OpenMP clause 'shared' in directive '#pragma omp simd'}}
for (int k = 0; k < argc; ++k) ++k;
diff --git a/test/OpenMP/simd_reduction_messages.cpp b/test/OpenMP/simd_reduction_messages.cpp
index 347a5c1..530f743 100644
--- a/test/OpenMP/simd_reduction_messages.cpp
+++ b/test/OpenMP/simd_reduction_messages.cpp
@@ -11,7 +11,7 @@
extern S1 a;
class S2 {
mutable int a;
- S2 &operator+=(const S2 &arg) { return (*this); }
+ S2 &operator+(const S2 &arg) { return (*this); } // expected-note 4 {{implicitly declared private here}}
public:
S2() : a(0) {}
@@ -28,17 +28,17 @@
public:
S3() : a(0) {}
S3(const S3 &s3) : a(s3.a) {}
- S3 operator+=(const S3 &arg1) { return arg1; }
+ S3 operator+(const S3 &arg1) { return arg1; }
};
-int operator+=(const S3 &arg1, const S3 &arg2) { return 5; }
+int operator+(const S3 &arg1, const S3 &arg2) { return 5; }
S3 c; // expected-note 2 {{'c' defined here}}
const S3 ca[5]; // expected-note 2 {{'ca' defined here}}
extern const int f; // expected-note 4 {{'f' declared here}}
-class S4 { // expected-note {{'S4' declared here}}
+class S4 {
int a;
- S4();
+ S4(); // expected-note {{implicitly declared private here}}
S4(const S4 &s4);
- S4 &operator+=(const S4 &arg) { return (*this); }
+ S4 &operator+(const S4 &arg) { return (*this); }
public:
S4(int v) : a(v) {}
@@ -46,26 +46,26 @@
S4 &operator&=(S4 &arg1, S4 &arg2) { return arg1; }
class S5 {
int a;
- S5() : a(0) {}
+ S5() : a(0) {} // expected-note {{implicitly declared private here}}
S5(const S5 &s5) : a(s5.a) {}
- S5 &operator+=(const S5 &arg);
+ S5 &operator+(const S5 &arg);
public:
S5(int v) : a(v) {}
};
-class S6 {
+class S6 { // expected-note 2 {{candidate function (the implicit copy assignment operator) not viable: no known conversion from 'int' to 'const S6' for 1st argument}}
int a;
public:
S6() : a(6) {}
operator int() { return 6; }
-} o; // expected-note 2 {{'o' defined here}}
+} o;
S3 h, k;
#pragma omp threadprivate(h) // expected-note 2 {{defined as threadprivate or thread local}}
template <class T> // expected-note {{declared here}}
-T tmain(T argc) { // expected-note 2 {{'argc' defined here}}
+T tmain(T argc) {
const T d = T(); // expected-note 4 {{'d' defined here}}
const T da[5] = {T()}; // expected-note 2 {{'da' defined here}}
T qa[5] = {T()};
@@ -74,7 +74,7 @@
S3 &p = k; // expected-note 2 {{'p' defined here}}
const T &r = da[(int)i]; // expected-note 2 {{'r' defined here}}
T &q = qa[(int)i]; // expected-note 2 {{'q' defined here}}
- T fl; // expected-note {{'fl' defined here}}
+ T fl;
#pragma omp simd reduction // expected-error {{expected '(' after 'reduction'}}
for (int i = 0; i < 10; ++i)
foo();
@@ -96,10 +96,10 @@
#pragma omp simd reduction(\) // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}}
for (int i = 0; i < 10; ++i)
foo();
-#pragma omp simd reduction(& : argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{variable of type 'float' is not valid for specified reduction operation}}
+#pragma omp simd reduction(& : argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{invalid operands to binary expression ('float' and 'float')}}
for (int i = 0; i < 10; ++i)
foo();
-#pragma omp simd reduction(| : argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{variable of type 'float' is not valid for specified reduction operation}}
+#pragma omp simd reduction(| : argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{invalid operands to binary expression ('float' and 'float')}}
for (int i = 0; i < 10; ++i)
foo();
#pragma omp simd reduction(|| : argc ? i : argc) // expected-error 2 {{expected variable name}}
@@ -114,7 +114,7 @@
#pragma omp simd reduction(^ : T) // expected-error {{'T' does not refer to a value}}
for (int i = 0; i < 10; ++i)
foo();
-#pragma omp simd reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 3 {{const-qualified variable cannot be reduction}}
+#pragma omp simd reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 3 {{const-qualified variable cannot be reduction}} expected-error 3 {{'operator+' is a private member of 'S2'}}
for (int i = 0; i < 10; ++i)
foo();
#pragma omp simd reduction(min : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{arguments of OpenMP clause 'reduction' for 'min' or 'max' must be of arithmetic type}} expected-error 3 {{const-qualified variable cannot be reduction}}
@@ -132,7 +132,7 @@
#pragma omp simd reduction(- : da) // expected-error {{a reduction variable with array type 'const int [5]'}} expected-error {{a reduction variable with array type 'const float [5]'}}
for (int i = 0; i < 10; ++i)
foo();
-#pragma omp simd reduction(^ : fl) // expected-error {{variable of type 'float' is not valid for specified reduction operation}}
+#pragma omp simd reduction(^ : fl) // expected-error {{invalid operands to binary expression ('float' and 'float')}}
for (int i = 0; i < 10; ++i)
foo();
#pragma omp simd reduction(&& : S2::S2s) // expected-error {{shared variable cannot be reduction}}
@@ -144,7 +144,7 @@
#pragma omp simd reduction(+ : h, k) // expected-error {{threadprivate or thread local variable cannot be reduction}}
for (int i = 0; i < 10; ++i)
foo();
-#pragma omp simd reduction(+ : o) // expected-error {{variable of type 'class S6' is not valid for specified reduction operation}}
+#pragma omp simd reduction(+ : o) // expected-error {{no viable overloaded '='}}
for (int i = 0; i < 10; ++i)
foo();
#pragma omp simd private(i), reduction(+ : j), reduction(+ : q) // expected-error 4 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}}
@@ -180,18 +180,26 @@
return T();
}
+namespace A {
+double x;
+#pragma omp threadprivate(x) // expected-note {{defined as threadprivate or thread local}}
+}
+namespace B {
+using A::x;
+}
+
int main(int argc, char **argv) {
const int d = 5; // expected-note 2 {{'d' defined here}}
const int da[5] = {0}; // expected-note {{'da' defined here}}
int qa[5] = {0};
- S4 e(4); // expected-note {{'e' defined here}}
- S5 g(5); // expected-note {{'g' defined here}}
+ S4 e(4);
+ S5 g(5);
int i;
int &j = i; // expected-note 2 {{'j' defined here}}
S3 &p = k; // expected-note 2 {{'p' defined here}}
const int &r = da[i]; // expected-note {{'r' defined here}}
int &q = qa[i]; // expected-note {{'q' defined here}}
- float fl; // expected-note {{'fl' defined here}}
+ float fl;
#pragma omp simd reduction // expected-error {{expected '(' after 'reduction'}}
for (int i = 0; i < 10; ++i)
foo();
@@ -231,7 +239,7 @@
#pragma omp simd reduction(^ : S1) // expected-error {{'S1' does not refer to a value}}
for (int i = 0; i < 10; ++i)
foo();
-#pragma omp simd reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{const-qualified variable cannot be reduction}}
+#pragma omp simd reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{const-qualified variable cannot be reduction}} expected-error {{'operator+' is a private member of 'S2'}}
for (int i = 0; i < 10; ++i)
foo();
#pragma omp simd reduction(min : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{arguments of OpenMP clause 'reduction' for 'min' or 'max' must be of arithmetic type}} expected-error 2 {{const-qualified variable cannot be reduction}}
@@ -249,7 +257,7 @@
#pragma omp simd reduction(- : da) // expected-error {{a reduction variable with array type 'const int [5]'}}
for (int i = 0; i < 10; ++i)
foo();
-#pragma omp simd reduction(^ : fl) // expected-error {{variable of type 'float' is not valid for specified reduction operation}}
+#pragma omp simd reduction(^ : fl) // expected-error {{invalid operands to binary expression ('float' and 'float')}}
for (int i = 0; i < 10; ++i)
foo();
#pragma omp simd reduction(&& : S2::S2s) // expected-error {{shared variable cannot be reduction}}
@@ -258,13 +266,13 @@
#pragma omp simd reduction(&& : S2::S2sc) // expected-error {{const-qualified variable cannot be reduction}}
for (int i = 0; i < 10; ++i)
foo();
-#pragma omp simd reduction(& : e, g) // expected-error {{reduction variable must have an accessible, unambiguous default constructor}} expected-error {{variable of type 'S5' is not valid for specified reduction operation}}
+#pragma omp simd reduction(& : e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{invalid operands to binary expression ('S4' and 'S4')}} expected-error {{calling a private constructor of class 'S5'}} expected-error {{invalid operands to binary expression ('S5' and 'S5')}}
for (int i = 0; i < 10; ++i)
foo();
-#pragma omp simd reduction(+ : h, k) // expected-error {{threadprivate or thread local variable cannot be reduction}}
+#pragma omp simd reduction(+ : h, k, B::x) // expected-error 2 {{threadprivate or thread local variable cannot be reduction}}
for (int i = 0; i < 10; ++i)
foo();
-#pragma omp simd reduction(+ : o) // expected-error {{variable of type 'class S6' is not valid for specified reduction operation}}
+#pragma omp simd reduction(+ : o) // expected-error {{no viable overloaded '='}}
for (int i = 0; i < 10; ++i)
foo();
#pragma omp simd private(i), reduction(+ : j), reduction(+ : q) // expected-error 2 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}}
diff --git a/test/OpenMP/single_codegen.cpp b/test/OpenMP/single_codegen.cpp
index 2b8a9cd..298b050 100644
--- a/test/OpenMP/single_codegen.cpp
+++ b/test/OpenMP/single_codegen.cpp
@@ -18,11 +18,13 @@
// CHECK-DAG: [[TEST_CLASS_TY:%.+]] = type { i{{[0-9]+}} }
// CHECK: [[IDENT_T_TY:%.+]] = type { i32, i32, i32, i32, i8* }
+// CHECK: [[IMPLICIT_BARRIER_SINGLE_LOC:@.+]] = private unnamed_addr constant %{{.+}} { i32 0, i32 322, i32 0, i32 0, i8*
// CHECK: define void [[FOO:@.+]]()
TestClass tc;
-#pragma omp threadprivate(tc)
+TestClass tc2[2];
+#pragma omp threadprivate(tc, tc2)
void foo() {}
@@ -30,13 +32,15 @@
// TERM_DEBUG-LABEL: @main
int main() {
// CHECK-DAG: [[A_ADDR:%.+]] = alloca i8
+ // CHECK-DAG: [[A2_ADDR:%.+]] = alloca [2 x i8]
// CHECK-DAG: [[C_ADDR:%.+]] = alloca [[TEST_CLASS_TY]]
char a;
+ char a2[2];
TestClass c;
// CHECK: [[GTID:%.+]] = call i32 @__kmpc_global_thread_num([[IDENT_T_TY]]* [[DEFAULT_LOC:@.+]])
// CHECK-DAG: [[DID_IT:%.+]] = alloca i32,
-// CHECK-DAG: [[COPY_LIST:%.+]] = alloca [3 x i8*],
+// CHECK-DAG: [[COPY_LIST:%.+]] = alloca [5 x i8*],
// CHECK: store i32 0, i32* [[DID_IT]]
// CHECK: [[RES:%.+]] = call i32 @__kmpc_single([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]])
@@ -47,6 +51,7 @@
// CHECK-NEXT: call void @__kmpc_end_single([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]])
// CHECK-NEXT: br label {{%?}}[[EXIT]]
// CHECK: [[EXIT]]
+// CHECK-NOT: __kmpc_cancel_barrier
#pragma omp single nowait
a = 2;
// CHECK: [[RES:%.+]] = call i32 @__kmpc_single([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]])
@@ -60,21 +65,29 @@
// CHECK: call void @__kmpc_end_single([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]])
// CHECK-NEXT: br label {{%?}}[[EXIT]]
// CHECK: [[EXIT]]
-// CHECK: [[A_PTR_REF:%.+]] = getelementptr inbounds [3 x i8*], [3 x i8*]* [[COPY_LIST]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+// CHECK: [[A_PTR_REF:%.+]] = getelementptr inbounds [5 x i8*], [5 x i8*]* [[COPY_LIST]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
// CHECK: store i8* [[A_ADDR]], i8** [[A_PTR_REF]],
-// CHECK: [[C_PTR_REF:%.+]] = getelementptr inbounds [3 x i8*], [3 x i8*]* [[COPY_LIST]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+// CHECK: [[C_PTR_REF:%.+]] = getelementptr inbounds [5 x i8*], [5 x i8*]* [[COPY_LIST]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
// CHECK: [[C_PTR_REF_VOID_PTR:%.+]] = bitcast [[TEST_CLASS_TY]]* [[C_ADDR]] to i8*
// CHECK: store i8* [[C_PTR_REF_VOID_PTR]], i8** [[C_PTR_REF]],
-// CHECK: [[TC_PTR_REF:%.+]] = getelementptr inbounds [3 x i8*], [3 x i8*]* [[COPY_LIST]], i{{[0-9]+}} 0, i{{[0-9]+}} 2
+// CHECK: [[TC_PTR_REF:%.+]] = getelementptr inbounds [5 x i8*], [5 x i8*]* [[COPY_LIST]], i{{[0-9]+}} 0, i{{[0-9]+}} 2
// CHECK: [[TC_THREADPRIVATE_ADDR_VOID_PTR:%.+]] = call{{.*}} i8* @__kmpc_threadprivate_cached
// CHECK: [[TC_THREADPRIVATE_ADDR:%.+]] = bitcast i8* [[TC_THREADPRIVATE_ADDR_VOID_PTR]] to [[TEST_CLASS_TY]]*
// CHECK: [[TC_PTR_REF_VOID_PTR:%.+]] = bitcast [[TEST_CLASS_TY]]* [[TC_THREADPRIVATE_ADDR]] to i8*
// CHECK: store i8* [[TC_PTR_REF_VOID_PTR]], i8** [[TC_PTR_REF]],
-// CHECK: [[COPY_LIST_VOID_PTR:%.+]] = bitcast [3 x i8*]* [[COPY_LIST]] to i8*
+// CHECK: [[A2_PTR_REF:%.+]] = getelementptr inbounds [5 x i8*], [5 x i8*]* [[COPY_LIST]], i{{[0-9]+}} 0, i{{[0-9]+}} 3
+// CHECK: [[BITCAST:%.+]] = bitcast [2 x i8]* [[A2_ADDR]] to i8*
+// CHECK: store i8* [[BITCAST]], i8** [[A2_PTR_REF]],
+// CHECK: [[TC2_PTR_REF:%.+]] = getelementptr inbounds [5 x i8*], [5 x i8*]* [[COPY_LIST]], i{{[0-9]+}} 0, i{{[0-9]+}} 4
+// CHECK: [[TC2_THREADPRIVATE_ADDR_VOID_PTR:%.+]] = call{{.*}} i8* @__kmpc_threadprivate_cached
+// CHECK: [[TC2_THREADPRIVATE_ADDR:%.+]] = bitcast i8* [[TC2_THREADPRIVATE_ADDR_VOID_PTR]] to [2 x [[TEST_CLASS_TY]]]*
+// CHECK: [[TC2_PTR_REF_VOID_PTR:%.+]] = bitcast [2 x [[TEST_CLASS_TY]]]* [[TC2_THREADPRIVATE_ADDR]] to i8*
+// CHECK: store i8* [[TC2_PTR_REF_VOID_PTR]], i8** [[TC2_PTR_REF]],
+// CHECK: [[COPY_LIST_VOID_PTR:%.+]] = bitcast [5 x i8*]* [[COPY_LIST]] to i8*
// CHECK: [[DID_IT_VAL:%.+]] = load i32, i32* [[DID_IT]],
-// CHECK: call void @__kmpc_copyprivate([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], i32 24, i8* [[COPY_LIST_VOID_PTR]], void (i8*, i8*)* [[COPY_FUNC:@.+]], i32 [[DID_IT_VAL]])
-// CHECK: call{{.*}} @__kmpc_cancel_barrier([[IDENT_T_TY]]* {{@.+}}, i32 [[GTID]])
-#pragma omp single copyprivate(a, c, tc)
+// CHECK: call void @__kmpc_copyprivate([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], i32 40, i8* [[COPY_LIST_VOID_PTR]], void (i8*, i8*)* [[COPY_FUNC:@.+]], i32 [[DID_IT_VAL]])
+// CHECK: call{{.*}} @__kmpc_cancel_barrier([[IDENT_T_TY]]* [[IMPLICIT_BARRIER_SINGLE_LOC]], i32 [[GTID]])
+#pragma omp single copyprivate(a, c, tc, a2, tc2)
foo();
// CHECK-NOT: call i32 @__kmpc_single
// CHECK-NOT: call void @__kmpc_end_single
@@ -85,29 +98,43 @@
// CHECK: store i8* %0, i8** [[DST_ADDR_REF:%.+]],
// CHECK: store i8* %1, i8** [[SRC_ADDR_REF:%.+]],
// CHECK: [[DST_ADDR_VOID_PTR:%.+]] = load i8*, i8** [[DST_ADDR_REF]],
-// CHECK: [[DST_ADDR:%.+]] = bitcast i8* [[DST_ADDR_VOID_PTR]] to [3 x i8*]*
+// CHECK: [[DST_ADDR:%.+]] = bitcast i8* [[DST_ADDR_VOID_PTR]] to [5 x i8*]*
// CHECK: [[SRC_ADDR_VOID_PTR:%.+]] = load i8*, i8** [[SRC_ADDR_REF]],
-// CHECK: [[SRC_ADDR:%.+]] = bitcast i8* [[SRC_ADDR_VOID_PTR]] to [3 x i8*]*
-// CHECK: [[SRC_A_ADDR_REF:%.+]] = getelementptr inbounds [3 x i8*], [3 x i8*]* [[SRC_ADDR]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
-// CHECK: [[SRC_A_ADDR:%.+]] = load i8*, i8** [[SRC_A_ADDR_REF]],
-// CHECK: [[DST_A_ADDR_REF:%.+]] = getelementptr inbounds [3 x i8*], [3 x i8*]* [[DST_ADDR]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+// CHECK: [[SRC_ADDR:%.+]] = bitcast i8* [[SRC_ADDR_VOID_PTR]] to [5 x i8*]*
+// CHECK: [[DST_A_ADDR_REF:%.+]] = getelementptr inbounds [5 x i8*], [5 x i8*]* [[DST_ADDR]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
// CHECK: [[DST_A_ADDR:%.+]] = load i8*, i8** [[DST_A_ADDR_REF]],
-// CHECK: [[SRC_C_ADDR_REF:%.+]] = getelementptr inbounds [3 x i8*], [3 x i8*]* [[SRC_ADDR]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
-// CHECK: [[SRC_C_ADDR_VOID_PTR:%.+]] = load i8*, i8** [[SRC_C_ADDR_REF]],
-// CHECK: [[SRC_C_ADDR:%.+]] = bitcast i8* [[SRC_C_ADDR_VOID_PTR:%.+]] to [[TEST_CLASS_TY]]*
-// CHECK: [[DST_C_ADDR_REF:%.+]] = getelementptr inbounds [3 x i8*], [3 x i8*]* [[DST_ADDR]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
-// CHECK: [[DST_C_ADDR_VOID_PTR:%.+]] = load i8*, i8** [[DST_C_ADDR_REF]],
-// CHECK: [[DST_C_ADDR:%.+]] = bitcast i8* [[DST_C_ADDR_VOID_PTR:%.+]] to [[TEST_CLASS_TY]]*
-// CHECK: [[SRC_TC_ADDR_REF:%.+]] = getelementptr inbounds [3 x i8*], [3 x i8*]* [[SRC_ADDR]], i{{[0-9]+}} 0, i{{[0-9]+}} 2
-// CHECK: [[SRC_TC_ADDR_VOID_PTR:%.+]] = load i8*, i8** [[SRC_TC_ADDR_REF]],
-// CHECK: [[SRC_TC_ADDR:%.+]] = bitcast i8* [[SRC_TC_ADDR_VOID_PTR:%.+]] to [[TEST_CLASS_TY]]*
-// CHECK: [[DST_TC_ADDR_REF:%.+]] = getelementptr inbounds [3 x i8*], [3 x i8*]* [[DST_ADDR]], i{{[0-9]+}} 0, i{{[0-9]+}} 2
-// CHECK: [[DST_TC_ADDR_VOID_PTR:%.+]] = load i8*, i8** [[DST_TC_ADDR_REF]],
-// CHECK: [[DST_TC_ADDR:%.+]] = bitcast i8* [[DST_TC_ADDR_VOID_PTR:%.+]] to [[TEST_CLASS_TY]]*
+// CHECK: [[SRC_A_ADDR_REF:%.+]] = getelementptr inbounds [5 x i8*], [5 x i8*]* [[SRC_ADDR]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+// CHECK: [[SRC_A_ADDR:%.+]] = load i8*, i8** [[SRC_A_ADDR_REF]],
// CHECK: [[SRC_A_VAL:%.+]] = load i8, i8* [[SRC_A_ADDR]],
// CHECK: store i8 [[SRC_A_VAL]], i8* [[DST_A_ADDR]],
+// CHECK: [[DST_C_ADDR_REF:%.+]] = getelementptr inbounds [5 x i8*], [5 x i8*]* [[DST_ADDR]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+// CHECK: [[DST_C_ADDR_VOID_PTR:%.+]] = load i8*, i8** [[DST_C_ADDR_REF]],
+// CHECK: [[DST_C_ADDR:%.+]] = bitcast i8* [[DST_C_ADDR_VOID_PTR]] to [[TEST_CLASS_TY]]*
+// CHECK: [[SRC_C_ADDR_REF:%.+]] = getelementptr inbounds [5 x i8*], [5 x i8*]* [[SRC_ADDR]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+// CHECK: [[SRC_C_ADDR_VOID_PTR:%.+]] = load i8*, i8** [[SRC_C_ADDR_REF]],
+// CHECK: [[SRC_C_ADDR:%.+]] = bitcast i8* [[SRC_C_ADDR_VOID_PTR]] to [[TEST_CLASS_TY]]*
// CHECK: call{{.*}} [[TEST_CLASS_TY_ASSIGN:@.+]]([[TEST_CLASS_TY]]* [[DST_C_ADDR]], [[TEST_CLASS_TY]]* {{.*}}[[SRC_C_ADDR]])
-// CHECK: call{{.*}} [[TEST_CLASS_TY_ASSIGN:@.+]]([[TEST_CLASS_TY]]* [[DST_TC_ADDR]], [[TEST_CLASS_TY]]* {{.*}}[[SRC_TC_ADDR]])
+// CHECK: [[DST_TC_ADDR_REF:%.+]] = getelementptr inbounds [5 x i8*], [5 x i8*]* [[DST_ADDR]], i{{[0-9]+}} 0, i{{[0-9]+}} 2
+// CHECK: [[DST_TC_ADDR_VOID_PTR:%.+]] = load i8*, i8** [[DST_TC_ADDR_REF]],
+// CHECK: [[DST_TC_ADDR:%.+]] = bitcast i8* [[DST_TC_ADDR_VOID_PTR]] to [[TEST_CLASS_TY]]*
+// CHECK: [[SRC_TC_ADDR_REF:%.+]] = getelementptr inbounds [5 x i8*], [5 x i8*]* [[SRC_ADDR]], i{{[0-9]+}} 0, i{{[0-9]+}} 2
+// CHECK: [[SRC_TC_ADDR_VOID_PTR:%.+]] = load i8*, i8** [[SRC_TC_ADDR_REF]],
+// CHECK: [[SRC_TC_ADDR:%.+]] = bitcast i8* [[SRC_TC_ADDR_VOID_PTR]] to [[TEST_CLASS_TY]]*
+// CHECK: call{{.*}} [[TEST_CLASS_TY_ASSIGN]]([[TEST_CLASS_TY]]* [[DST_TC_ADDR]], [[TEST_CLASS_TY]]* {{.*}}[[SRC_TC_ADDR]])
+// CHECK: [[DST_A2_ADDR_REF:%.+]] = getelementptr inbounds [5 x i8*], [5 x i8*]* [[DST_ADDR]], i{{[0-9]+}} 0, i{{[0-9]+}} 3
+// CHECK: [[DST_A2_ADDR:%.+]] = load i8*, i8** [[DST_A2_ADDR_REF]],
+// CHECK: [[SRC_A2_ADDR_REF:%.+]] = getelementptr inbounds [5 x i8*], [5 x i8*]* [[SRC_ADDR]], i{{[0-9]+}} 0, i{{[0-9]+}} 3
+// CHECK: [[SRC_A2_ADDR:%.+]] = load i8*, i8** [[SRC_A2_ADDR_REF]],
+// CHECK: call void @llvm.memcpy.{{.+}}(i8* [[DST_A2_ADDR]], i8* [[SRC_A2_ADDR]], i{{[0-9]+}} 2, i{{[0-9]+}} 1, i1 false)
+// CHECK: [[DST_TC2_ADDR_REF:%.+]] = getelementptr inbounds [5 x i8*], [5 x i8*]* [[DST_ADDR]], i{{[0-9]+}} 0, i{{[0-9]+}} 4
+// CHECK: [[DST_TC2_ADDR_VOID_PTR:%.+]] = load i8*, i8** [[DST_TC2_ADDR_REF]],
+// CHECK: [[DST_TC2_ADDR:%.+]] = bitcast i8* [[DST_TC2_ADDR_VOID_PTR]] to [[TEST_CLASS_TY]]*
+// CHECK: [[SRC_TC2_ADDR_REF:%.+]] = getelementptr inbounds [5 x i8*], [5 x i8*]* [[SRC_ADDR]], i{{[0-9]+}} 0, i{{[0-9]+}} 4
+// CHECK: [[SRC_TC2_ADDR_VOID_PTR:%.+]] = load i8*, i8** [[SRC_TC2_ADDR_REF]],
+// CHECK: [[SRC_TC2_ADDR:%.+]] = bitcast i8* [[SRC_TC2_ADDR_VOID_PTR]] to [[TEST_CLASS_TY]]*
+// CHECK: br i1
+// CHECK: call{{.*}} [[TEST_CLASS_TY_ASSIGN]]([[TEST_CLASS_TY]]* %{{.+}}, [[TEST_CLASS_TY]]* {{.*}})
+// CHECK: br i1
// CHECK: ret void
// CHECK-LABEL: parallel_single
@@ -127,6 +154,6 @@
foo();
}
// TERM_DEBUG-DAG: [[DBG_LOC_START]] = !MDLocation(line: [[@LINE-12]],
-// TERM_DEBUG-DAG: [[DBG_LOC_END]] = !MDLocation(line: [[@LINE-13]],
+// TERM_DEBUG-DAG: [[DBG_LOC_END]] = !MDLocation(line: [[@LINE-3]],
#endif
diff --git a/test/OpenMP/single_copyprivate_messages.cpp b/test/OpenMP/single_copyprivate_messages.cpp
index de51bc6..793b4d5 100644
--- a/test/OpenMP/single_copyprivate_messages.cpp
+++ b/test/OpenMP/single_copyprivate_messages.cpp
@@ -105,6 +105,14 @@
return T();
}
+namespace A {
+double x;
+#pragma omp threadprivate(x)
+}
+namespace B {
+using A::x;
+}
+
int main(int argc, char **argv) {
int i;
static int intA;
@@ -121,7 +129,7 @@
#pragma omp parallel
#pragma omp single copyprivate(argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
#pragma omp parallel
-#pragma omp single copyprivate(l) // expected-error {{'operator=' is a private member of 'S4'}}
+#pragma omp single copyprivate(l, B::x) // expected-error {{'operator=' is a private member of 'S4'}}
#pragma omp parallel
#pragma omp single copyprivate(S1) // expected-error {{'S1' does not refer to a value}}
#pragma omp parallel
diff --git a/test/OpenMP/single_firstprivate_messages.cpp b/test/OpenMP/single_firstprivate_messages.cpp
index 9f6f160..b4c4712 100644
--- a/test/OpenMP/single_firstprivate_messages.cpp
+++ b/test/OpenMP/single_firstprivate_messages.cpp
@@ -132,6 +132,14 @@
return 0;
}
+namespace A {
+double x;
+#pragma omp threadprivate(x) // expected-note {{defined as threadprivate or thread local}}
+}
+namespace B {
+using A::x;
+}
+
int main(int argc, char **argv) {
const int d = 5;
const int da[5] = {0};
@@ -203,7 +211,7 @@
#pragma omp single firstprivate(m) // OK
foo();
#pragma omp parallel
-#pragma omp single firstprivate(h) // expected-error {{threadprivate or thread local variable cannot be firstprivate}}
+#pragma omp single firstprivate(h, B::x) // expected-error 2 {{threadprivate or thread local variable cannot be firstprivate}}
foo();
#pragma omp parallel
#pragma omp single private(xa), firstprivate(xa) // expected-error {{private variable cannot be firstprivate}} expected-note {{defined as private}}
diff --git a/test/OpenMP/single_private_messages.cpp b/test/OpenMP/single_private_messages.cpp
index 8bdc48f..964fc3a 100644
--- a/test/OpenMP/single_private_messages.cpp
+++ b/test/OpenMP/single_private_messages.cpp
@@ -91,6 +91,14 @@
return 0;
}
+namespace A {
+double x;
+#pragma omp threadprivate(x) // expected-note {{defined as threadprivate or thread local}}
+}
+namespace B {
+using A::x;
+}
+
int main(int argc, char **argv) {
S4 e(4);
S5 g(5);
@@ -118,7 +126,7 @@
foo();
#pragma omp single private(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
foo();
-#pragma omp single private(h) // expected-error {{threadprivate or thread local variable cannot be private}}
+#pragma omp single private(h, B::x) // expected-error 2 {{threadprivate or thread local variable cannot be private}}
foo();
#pragma omp single shared(i) // expected-error {{unexpected OpenMP clause 'shared' in directive '#pragma omp single'}}
foo();
diff --git a/test/OpenMP/task_firstprivate_messages.cpp b/test/OpenMP/task_firstprivate_messages.cpp
index 6c5ccfc..c3c2ae0 100644
--- a/test/OpenMP/task_firstprivate_messages.cpp
+++ b/test/OpenMP/task_firstprivate_messages.cpp
@@ -51,6 +51,14 @@
S3 h;
#pragma omp threadprivate(h) // expected-note {{defined as threadprivate or thread local}}
+namespace A {
+double x;
+#pragma omp threadprivate(x) // expected-note {{defined as threadprivate or thread local}}
+}
+namespace B {
+using A::x;
+}
+
int main(int argc, char **argv) {
const int d = 5;
const int da[5] = {0};
@@ -74,7 +82,7 @@
#pragma omp task firstprivate(S2::S2s)
#pragma omp task firstprivate(S2::S2sc)
#pragma omp task firstprivate(e, g) // expected-error 2 {{calling a private constructor of class 'S4'}} expected-error 2 {{calling a private constructor of class 'S5'}}
-#pragma omp task firstprivate(h) // expected-error {{threadprivate or thread local variable cannot be firstprivate}}
+#pragma omp task firstprivate(h, B::x) // expected-error 2 {{threadprivate or thread local variable cannot be firstprivate}}
#pragma omp task private(i), firstprivate(i) // expected-error {{private variable cannot be firstprivate}} expected-note{{defined as private}}
foo();
#pragma omp task shared(i)
diff --git a/test/OpenMP/task_private_messages.cpp b/test/OpenMP/task_private_messages.cpp
index 0352694..bf2a24a 100644
--- a/test/OpenMP/task_private_messages.cpp
+++ b/test/OpenMP/task_private_messages.cpp
@@ -45,6 +45,14 @@
int threadvar;
#pragma omp threadprivate(threadvar) // expected-note {{defined as threadprivate or thread local}}
+namespace A {
+double x;
+#pragma omp threadprivate(x) // expected-note {{defined as threadprivate or thread local}}
+}
+namespace B {
+using A::x;
+}
+
int main(int argc, char **argv) {
const int d = 5; // expected-note {{constant variable is predetermined as shared}}
const int da[5] = {0}; // expected-note {{constant variable is predetermined as shared}}
@@ -67,7 +75,7 @@
#pragma omp task private(da) // expected-error {{shared variable cannot be private}}
#pragma omp task private(S2::S2s)
#pragma omp task private(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
-#pragma omp task private(threadvar) // expected-error {{threadprivate or thread local variable cannot be private}}
+#pragma omp task private(threadvar, B::x) // expected-error 2 {{threadprivate or thread local variable cannot be private}}
#pragma omp task shared(i), private(i) // expected-error {{shared variable cannot be private}} expected-note {{defined as shared}}
foo();
#pragma omp task firstprivate(i) private(i) // expected-error {{firstprivate variable cannot be private}} expected-note {{defined as firstprivate}}
diff --git a/test/OpenMP/task_shared_messages.cpp b/test/OpenMP/task_shared_messages.cpp
index 7479237..2dda25a 100644
--- a/test/OpenMP/task_shared_messages.cpp
+++ b/test/OpenMP/task_shared_messages.cpp
@@ -48,6 +48,14 @@
S3 h;
#pragma omp threadprivate(h) // expected-note {{defined as threadprivate or thread local}}
+namespace A {
+double x;
+#pragma omp threadprivate(x) // expected-note {{defined as threadprivate or thread local}}
+}
+namespace B {
+using A::x;
+}
+
int main(int argc, char **argv) {
const int d = 5;
const int da[5] = {0};
@@ -83,7 +91,7 @@
foo();
#pragma omp task shared(e, g)
foo();
-#pragma omp task shared(h) // expected-error {{threadprivate or thread local variable cannot be shared}}
+#pragma omp task shared(h, B::x) // expected-error 2 {{threadprivate or thread local variable cannot be shared}}
foo();
#pragma omp task private(i), shared(i) // expected-error {{private variable cannot be shared}} expected-note {{defined as private}}
foo();
diff --git a/test/OpenMP/teams_firstprivate_messages.cpp b/test/OpenMP/teams_firstprivate_messages.cpp
index 3d4a219..c18a22f 100644
--- a/test/OpenMP/teams_firstprivate_messages.cpp
+++ b/test/OpenMP/teams_firstprivate_messages.cpp
@@ -49,6 +49,14 @@
S3 h;
#pragma omp threadprivate(h) // expected-note {{defined as threadprivate or thread local}}
+namespace A {
+double x;
+#pragma omp threadprivate(x) // expected-note {{defined as threadprivate or thread local}}
+}
+namespace B {
+using A::x;
+}
+
int main(int argc, char **argv) {
const int d = 5;
const int da[5] = {0};
@@ -105,7 +113,7 @@
#pragma omp teams firstprivate(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
foo();
#pragma omp target
-#pragma omp teams firstprivate(h) // expected-error {{threadprivate or thread local variable cannot be firstprivate}}
+#pragma omp teams firstprivate(h, B::x) // expected-error 2 {{threadprivate or thread local variable cannot be firstprivate}}
foo();
#pragma omp target
#pragma omp teams private(i), firstprivate(i) // expected-error {{private variable cannot be firstprivate}} expected-note{{defined as private}}
diff --git a/test/OpenMP/teams_private_messages.cpp b/test/OpenMP/teams_private_messages.cpp
index 65caaed..771b8d3 100644
--- a/test/OpenMP/teams_private_messages.cpp
+++ b/test/OpenMP/teams_private_messages.cpp
@@ -41,6 +41,14 @@
int threadvar;
#pragma omp threadprivate(threadvar) // expected-note {{defined as threadprivate or thread local}}
+namespace A {
+double x;
+#pragma omp threadprivate(x) // expected-note {{defined as threadprivate or thread local}}
+}
+namespace B {
+using A::x;
+}
+
int main(int argc, char **argv) {
const int d = 5; // expected-note {{constant variable is predetermined as shared}}
const int da[5] = { 0 }; // expected-note {{constant variable is predetermined as shared}}
@@ -94,7 +102,7 @@
#pragma omp teams private(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
foo();
#pragma omp target
- #pragma omp teams private(threadvar) // expected-error {{threadprivate or thread local variable cannot be private}}
+ #pragma omp teams private(threadvar, B::x) // expected-error 2 {{threadprivate or thread local variable cannot be private}}
foo();
#pragma omp target
#pragma omp teams shared(i), private(i) // expected-error {{shared variable cannot be private}} expected-note {{defined as shared}}
diff --git a/test/OpenMP/teams_reduction_messages.cpp b/test/OpenMP/teams_reduction_messages.cpp
index 18b7cd4..df2c2e8 100644
--- a/test/OpenMP/teams_reduction_messages.cpp
+++ b/test/OpenMP/teams_reduction_messages.cpp
@@ -11,7 +11,7 @@
extern S1 a;
class S2 {
mutable int a;
- S2 &operator+=(const S2 &arg) { return (*this); }
+ S2 &operator+(const S2 &arg) { return (*this); } // expected-note 4 {{implicitly declared private here}}
public:
S2() : a(0) {}
@@ -28,17 +28,17 @@
public:
S3() : a(0) {}
S3(const S3 &s3) : a(s3.a) {}
- S3 operator+=(const S3 &arg1) { return arg1; }
+ S3 operator+(const S3 &arg1) { return arg1; }
};
-int operator+=(const S3 &arg1, const S3 &arg2) { return 5; }
+int operator+(const S3 &arg1, const S3 &arg2) { return 5; }
S3 c; // expected-note 2 {{'c' defined here}}
const S3 ca[5]; // expected-note 2 {{'ca' defined here}}
extern const int f; // expected-note 4 {{'f' declared here}}
-class S4 { // expected-note {{'S4' declared here}}
+class S4 {
int a;
- S4();
+ S4(); // expected-note {{implicitly declared private here}}
S4(const S4 &s4);
- S4 &operator+=(const S4 &arg) { return (*this); }
+ S4 &operator+(const S4 &arg) { return (*this); }
public:
S4(int v) : a(v) {}
@@ -46,26 +46,26 @@
S4 &operator&=(S4 &arg1, S4 &arg2) { return arg1; }
class S5 {
int a;
- S5() : a(0) {}
+ S5() : a(0) {} // expected-note {{implicitly declared private here}}
S5(const S5 &s5) : a(s5.a) {}
- S5 &operator+=(const S5 &arg);
+ S5 &operator+(const S5 &arg);
public:
S5(int v) : a(v) {}
};
-class S6 {
+class S6 { // expected-note 2 {{candidate function (the implicit copy assignment operator) not viable: no known conversion from 'int' to 'const S6' for 1st argument}}
int a;
public:
S6() : a(6) {}
operator int() { return 6; }
-} o; // expected-note 2 {{'o' defined here}}
+} o;
S3 h, k;
#pragma omp threadprivate(h) // expected-note 2 {{defined as threadprivate or thread local}}
template <class T> // expected-note {{declared here}}
-T tmain(T argc) { // expected-note 2 {{'argc' defined here}}
+T tmain(T argc) {
const T d = T(); // expected-note 4 {{'d' defined here}}
const T da[5] = {T()}; // expected-note 2 {{'da' defined here}}
T qa[5] = {T()};
@@ -74,7 +74,7 @@
S3 &p = k; // expected-note 2 {{'p' defined here}}
const T &r = da[(int)i]; // expected-note 2 {{'r' defined here}}
T &q = qa[(int)i]; // expected-note 2 {{'q' defined here}}
- T fl; // expected-note {{'fl' defined here}}
+ T fl;
#pragma omp target
#pragma omp teams reduction // expected-error {{expected '(' after 'reduction'}}
foo();
@@ -97,10 +97,10 @@
#pragma omp teams reduction(\) // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}}
foo();
#pragma omp target
-#pragma omp teams reduction(& : argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{variable of type 'float' is not valid for specified reduction operation}}
+#pragma omp teams reduction(& : argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{invalid operands to binary expression ('float' and 'float')}}
foo();
#pragma omp target
-#pragma omp teams reduction(| : argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{variable of type 'float' is not valid for specified reduction operation}}
+#pragma omp teams reduction(| : argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{invalid operands to binary expression ('float' and 'float')}}
foo();
#pragma omp target
#pragma omp teams reduction(|| : argc ? i : argc) // expected-error 2 {{expected variable name}}
@@ -115,7 +115,7 @@
#pragma omp teams reduction(^ : T) // expected-error {{'T' does not refer to a value}}
foo();
#pragma omp target
-#pragma omp teams reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 3 {{const-qualified variable cannot be reduction}}
+#pragma omp teams reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 3 {{const-qualified variable cannot be reduction}} expected-error 3 {{'operator+' is a private member of 'S2'}}
foo();
#pragma omp target
#pragma omp teams reduction(min : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{arguments of OpenMP clause 'reduction' for 'min' or 'max' must be of arithmetic type}} expected-error 3 {{const-qualified variable cannot be reduction}}
@@ -133,7 +133,7 @@
#pragma omp teams reduction(- : da) // expected-error {{a reduction variable with array type 'const int [5]'}} expected-error {{a reduction variable with array type 'const float [5]'}}
foo();
#pragma omp target
-#pragma omp teams reduction(^ : fl) // expected-error {{variable of type 'float' is not valid for specified reduction operation}}
+#pragma omp teams reduction(^ : fl) // expected-error {{invalid operands to binary expression ('float' and 'float')}}
foo();
#pragma omp target
#pragma omp teams reduction(&& : S2::S2s)
@@ -145,7 +145,7 @@
#pragma omp teams reduction(+ : h, k) // expected-error {{threadprivate or thread local variable cannot be reduction}}
foo();
#pragma omp target
-#pragma omp teams reduction(+ : o) // expected-error {{variable of type 'class S6' is not valid for specified reduction operation}}
+#pragma omp teams reduction(+ : o) // expected-error {{no viable overloaded '='}}
foo();
#pragma omp target
#pragma omp teams private(i), reduction(+ : j), reduction(+ : q) // expected-error 4 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}}
@@ -183,18 +183,26 @@
return T();
}
+namespace A {
+double x;
+#pragma omp threadprivate(x) // expected-note {{defined as threadprivate or thread local}}
+}
+namespace B {
+using A::x;
+}
+
int main(int argc, char **argv) {
const int d = 5; // expected-note 2 {{'d' defined here}}
const int da[5] = {0}; // expected-note {{'da' defined here}}
int qa[5] = {0};
- S4 e(4); // expected-note {{'e' defined here}}
- S5 g(5); // expected-note {{'g' defined here}}
+ S4 e(4);
+ S5 g(5);
int i;
int &j = i; // expected-note 2 {{'j' defined here}}
S3 &p = k; // expected-note 2 {{'p' defined here}}
const int &r = da[i]; // expected-note {{'r' defined here}}
int &q = qa[i]; // expected-note {{'q' defined here}}
- float fl; // expected-note {{'fl' defined here}}
+ float fl;
#pragma omp target
#pragma omp teams reduction // expected-error {{expected '(' after 'reduction'}}
foo();
@@ -235,7 +243,7 @@
#pragma omp teams reduction(^ : S1) // expected-error {{'S1' does not refer to a value}}
foo();
#pragma omp target
-#pragma omp teams reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{const-qualified variable cannot be reduction}}
+#pragma omp teams reduction(+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{const-qualified variable cannot be reduction}} expected-error {{'operator+' is a private member of 'S2'}}
foo();
#pragma omp target
#pragma omp teams reduction(min : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{arguments of OpenMP clause 'reduction' for 'min' or 'max' must be of arithmetic type}} expected-error 2 {{const-qualified variable cannot be reduction}}
@@ -253,7 +261,7 @@
#pragma omp teams reduction(- : da) // expected-error {{a reduction variable with array type 'const int [5]'}}
foo();
#pragma omp target
-#pragma omp teams reduction(^ : fl) // expected-error {{variable of type 'float' is not valid for specified reduction operation}}
+#pragma omp teams reduction(^ : fl) // expected-error {{invalid operands to binary expression ('float' and 'float')}}
foo();
#pragma omp target
#pragma omp teams reduction(&& : S2::S2s)
@@ -262,13 +270,13 @@
#pragma omp teams reduction(&& : S2::S2sc) // expected-error {{const-qualified variable cannot be reduction}}
foo();
#pragma omp target
-#pragma omp teams reduction(& : e, g) // expected-error {{reduction variable must have an accessible, unambiguous default constructor}} expected-error {{variable of type 'S5' is not valid for specified reduction operation}}
+#pragma omp teams reduction(& : e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{invalid operands to binary expression ('S4' and 'S4')}} expected-error {{calling a private constructor of class 'S5'}} expected-error {{invalid operands to binary expression ('S5' and 'S5')}}
foo();
#pragma omp target
-#pragma omp teams reduction(+ : h, k) // expected-error {{threadprivate or thread local variable cannot be reduction}}
+#pragma omp teams reduction(+ : h, k, B::x) // expected-error 2 {{threadprivate or thread local variable cannot be reduction}}
foo();
#pragma omp target
-#pragma omp teams reduction(+ : o) // expected-error {{variable of type 'class S6' is not valid for specified reduction operation}}
+#pragma omp teams reduction(+ : o) // expected-error {{no viable overloaded '='}}
foo();
#pragma omp target
#pragma omp teams private(i), reduction(+ : j), reduction(+ : q) // expected-error 2 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}}
diff --git a/test/OpenMP/teams_shared_messages.cpp b/test/OpenMP/teams_shared_messages.cpp
index ce2f917..630f449 100644
--- a/test/OpenMP/teams_shared_messages.cpp
+++ b/test/OpenMP/teams_shared_messages.cpp
@@ -44,6 +44,14 @@
S3 h;
#pragma omp threadprivate(h) // expected-note {{defined as threadprivate or thread local}}
+namespace A {
+double x;
+#pragma omp threadprivate(x) // expected-note {{defined as threadprivate or thread local}}
+}
+namespace B {
+using A::x;
+}
+
int main(int argc, char **argv) {
const int d = 5;
const int da[5] = { 0 };
@@ -94,7 +102,7 @@
#pragma omp teams shared(e, g)
foo();
#pragma omp target
- #pragma omp teams shared(h) // expected-error {{threadprivate or thread local variable cannot be shared}}
+ #pragma omp teams shared(h, B::x) // expected-error 2 {{threadprivate or thread local variable cannot be shared}}
foo();
#pragma omp target
#pragma omp teams private(i), shared(i) // expected-error {{private variable cannot be shared}} expected-note {{defined as private}}
diff --git a/test/OpenMP/threadprivate_ast_print.cpp b/test/OpenMP/threadprivate_ast_print.cpp
index 4d0d40e..3227822 100644
--- a/test/OpenMP/threadprivate_ast_print.cpp
+++ b/test/OpenMP/threadprivate_ast_print.cpp
@@ -22,6 +22,8 @@
// CHECK: int a;
// CHECK: int b;
#pragma omp threadprivate(a)
+#pragma omp threadprivate(a)
+// CHECK-NEXT: #pragma omp threadprivate(a)
// CHECK-NEXT: #pragma omp threadprivate(a)
#pragma omp threadprivate(d, b)
// CHECK-NEXT: #pragma omp threadprivate(d,b)
diff --git a/test/OpenMP/threadprivate_codegen.cpp b/test/OpenMP/threadprivate_codegen.cpp
index c775893..03bc08a 100644
--- a/test/OpenMP/threadprivate_codegen.cpp
+++ b/test/OpenMP/threadprivate_codegen.cpp
@@ -133,25 +133,25 @@
// CHECK-DEBUG-DAG: [[ST_FLOAT_ST:@.+]] = linkonce_odr global float 2.300000e+01
// CHECK-DEBUG-DAG: [[ST_S4_ST:@.+]] = linkonce_odr global %struct.S4 zeroinitializer
// CHECK-DEBUG-DAG: [[LOC1:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;;162;9;;\00"
-// CHECK-DEBUG-DAG: [[LOC2:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;;216;9;;\00"
-// CHECK-DEBUG-DAG: [[LOC3:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;;303;19;;\00"
-// CHECK-DEBUG-DAG: [[LOC4:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;main;328;9;;\00"
-// CHECK-DEBUG-DAG: [[LOC5:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;main;341;9;;\00"
-// CHECK-DEBUG-DAG: [[LOC6:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;main;358;10;;\00"
-// CHECK-DEBUG-DAG: [[LOC7:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;main;375;10;;\00"
-// CHECK-DEBUG-DAG: [[LOC8:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;main;401;10;;\00"
-// CHECK-DEBUG-DAG: [[LOC9:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;main;422;10;;\00"
-// CHECK-DEBUG-DAG: [[LOC10:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;main;437;10;;\00"
-// CHECK-DEBUG-DAG: [[LOC11:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;main;454;27;;\00"
-// CHECK-DEBUG-DAG: [[LOC12:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;main;471;10;;\00"
-// CHECK-DEBUG-DAG: [[LOC13:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;foobar;550;9;;\00"
-// CHECK-DEBUG-DAG: [[LOC14:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;foobar;567;10;;\00"
-// CHECK-DEBUG-DAG: [[LOC15:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;foobar;593;10;;\00"
-// CHECK-DEBUG-DAG: [[LOC16:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;foobar;614;10;;\00"
-// CHECK-DEBUG-DAG: [[LOC17:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;foobar;629;10;;\00"
-// CHECK-DEBUG-DAG: [[LOC18:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;foobar;646;27;;\00"
-// CHECK-DEBUG-DAG: [[LOC19:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;foobar;663;10;;\00"
-// CHECK-DEBUG-DAG: [[LOC20:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;;275;9;;\00"
+// CHECK-DEBUG-DAG: [[LOC2:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;;217;9;;\00"
+// CHECK-DEBUG-DAG: [[LOC3:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;;304;19;;\00"
+// CHECK-DEBUG-DAG: [[LOC4:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;main;329;9;;\00"
+// CHECK-DEBUG-DAG: [[LOC5:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;main;342;9;;\00"
+// CHECK-DEBUG-DAG: [[LOC6:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;main;359;10;;\00"
+// CHECK-DEBUG-DAG: [[LOC7:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;main;376;10;;\00"
+// CHECK-DEBUG-DAG: [[LOC8:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;main;402;10;;\00"
+// CHECK-DEBUG-DAG: [[LOC9:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;main;423;10;;\00"
+// CHECK-DEBUG-DAG: [[LOC10:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;main;438;10;;\00"
+// CHECK-DEBUG-DAG: [[LOC11:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;main;455;27;;\00"
+// CHECK-DEBUG-DAG: [[LOC12:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;main;472;10;;\00"
+// CHECK-DEBUG-DAG: [[LOC13:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;foobar;551;9;;\00"
+// CHECK-DEBUG-DAG: [[LOC14:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;foobar;568;10;;\00"
+// CHECK-DEBUG-DAG: [[LOC15:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;foobar;594;10;;\00"
+// CHECK-DEBUG-DAG: [[LOC16:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;foobar;615;10;;\00"
+// CHECK-DEBUG-DAG: [[LOC17:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;foobar;630;10;;\00"
+// CHECK-DEBUG-DAG: [[LOC18:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;foobar;647;27;;\00"
+// CHECK-DEBUG-DAG: [[LOC19:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;foobar;664;10;;\00"
+// CHECK-DEBUG-DAG: [[LOC20:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;;276;9;;\00"
struct Static {
static S3 s;
@@ -160,6 +160,7 @@
static S1 gs1(5);
#pragma omp threadprivate(gs1)
+#pragma omp threadprivate(gs1)
// CHECK: define {{.*}} [[S1_CTOR:@.*]]([[S1]]* {{.*}},
// CHECK: define {{.*}} [[S1_DTOR:@.*]]([[S1]]* {{.*}})
// CHECK: define internal {{.*}}i8* [[GS1_CTOR:@\.__kmpc_global_ctor_\..*]](i8*)
diff --git a/test/OpenMP/threadprivate_messages.cpp b/test/OpenMP/threadprivate_messages.cpp
index 1aaf2d0..bf26c4f 100644
--- a/test/OpenMP/threadprivate_messages.cpp
+++ b/test/OpenMP/threadprivate_messages.cpp
@@ -17,7 +17,7 @@
#pragma omp threadprivate(a)
#pragma omp threadprivate(u) // expected-error {{use of undeclared identifier 'u'}}
-#pragma omp threadprivate(d, a) // expected-error {{'#pragma omp threadprivate' must precede all references to variable 'a'}}
+#pragma omp threadprivate(d, a)
int foo() { // expected-note {{declared here}}
static int l;
#pragma omp threadprivate(l)) // expected-warning {{extra tokens at the end of '#pragma omp threadprivate' are ignored}}
@@ -25,21 +25,20 @@
}
#pragma omp threadprivate (a) (
-// expected-error@-1 {{'#pragma omp threadprivate' must precede all references to variable 'a'}} expected-warning@-1 {{extra tokens at the end of '#pragma omp threadprivate' are ignored}}
-#pragma omp threadprivate (a) [ // expected-error {{'#pragma omp threadprivate' must precede all references to variable 'a'}} expected-warning {{extra tokens at the end of '#pragma omp threadprivate' are ignored}}
-#pragma omp threadprivate (a) { // expected-error {{'#pragma omp threadprivate' must precede all references to variable 'a'}} expected-warning {{extra tokens at the end of '#pragma omp threadprivate' are ignored}}
-#pragma omp threadprivate (a) ) // expected-error {{'#pragma omp threadprivate' must precede all references to variable 'a'}} expected-warning {{extra tokens at the end of '#pragma omp threadprivate' are ignored}}
-#pragma omp threadprivate (a) ] // expected-error {{'#pragma omp threadprivate' must precede all references to variable 'a'}} expected-warning {{extra tokens at the end of '#pragma omp threadprivate' are ignored}}
-#pragma omp threadprivate (a) } // expected-error {{'#pragma omp threadprivate' must precede all references to variable 'a'}} expected-warning {{extra tokens at the end of '#pragma omp threadprivate' are ignored}}
+// expected-warning@-1 {{extra tokens at the end of '#pragma omp threadprivate' are ignored}}
+#pragma omp threadprivate (a) [ // expected-warning {{extra tokens at the end of '#pragma omp threadprivate' are ignored}}
+#pragma omp threadprivate (a) { // expected-warning {{extra tokens at the end of '#pragma omp threadprivate' are ignored}}
+#pragma omp threadprivate (a) ) // expected-warning {{extra tokens at the end of '#pragma omp threadprivate' are ignored}}
+#pragma omp threadprivate (a) ] // expected-warning {{extra tokens at the end of '#pragma omp threadprivate' are ignored}}
+#pragma omp threadprivate (a) } // expected-warning {{extra tokens at the end of '#pragma omp threadprivate' are ignored}}
#pragma omp threadprivate a // expected-error {{expected '(' after 'threadprivate'}}
-#pragma omp threadprivate(d // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{'#pragma omp threadprivate' must precede all references to variable 'd'}}
-#pragma omp threadprivate(d)) // expected-error {{'#pragma omp threadprivate' must precede all references to variable 'd'}} expected-warning {{extra tokens at the end of '#pragma omp threadprivate' are ignored}}
+#pragma omp threadprivate(d // expected-error {{expected ')'}} expected-note {{to match this '('}}
+#pragma omp threadprivate(d)) // expected-warning {{extra tokens at the end of '#pragma omp threadprivate' are ignored}}
int x, y;
#pragma omp threadprivate(x)) // expected-warning {{extra tokens at the end of '#pragma omp threadprivate' are ignored}}
#pragma omp threadprivate(y)),
// expected-warning@-1 {{extra tokens at the end of '#pragma omp threadprivate' are ignored}}
#pragma omp threadprivate(a,d)
-// expected-error@-1 {{'#pragma omp threadprivate' must precede all references to variable 'a'}} expected-error@-1 {{'#pragma omp threadprivate' must precede all references to variable 'd'}}
#pragma omp threadprivate(d.a) // expected-error {{expected identifier}}
#pragma omp threadprivate((float)a) // expected-error {{expected unqualified-id}}
int foa; // expected-note {{'foa' declared here}}
@@ -73,8 +72,8 @@
#pragma omp threadprivate (m)
}
#pragma omp threadprivate (m) // expected-error {{use of undeclared identifier 'm'}}
-#pragma omp threadprivate (ns::m) // expected-error {{'#pragma omp threadprivate' must precede all references to variable 'ns::m'}}
-#pragma omp threadprivate (ns:m) // expected-error {{unexpected ':' in nested name specifier; did you mean '::'?}} expected-error {{'#pragma omp threadprivate' must precede all references to variable 'ns::m'}}
+#pragma omp threadprivate (ns::m)
+#pragma omp threadprivate (ns:m) // expected-error {{unexpected ':' in nested name specifier; did you mean '::'?}}
const int h = 12;
const volatile int i = 10;
@@ -104,10 +103,10 @@
namespace {
int o; // expected-note {{candidate found by name lookup is '(anonymous namespace)::o'}}
#pragma omp threadprivate (o)
-#pragma omp threadprivate (o) // expected-error {{'#pragma omp threadprivate' must precede all references to variable '(anonymous namespace)::o'}}
+#pragma omp threadprivate (o)
}
#pragma omp threadprivate (o) // expected-error {{reference to 'o' is ambiguous}}
-#pragma omp threadprivate (::o) // expected-error {{'#pragma omp threadprivate' must precede all references to variable 'o'}}
+#pragma omp threadprivate (::o)
int main(int argc, char **argv) { // expected-note {{'argc' defined here}}
diff --git a/test/PCH/cxx1y-lambdas.mm b/test/PCH/cxx1y-lambdas.mm
index 1cd2706..5235fc5 100644
--- a/test/PCH/cxx1y-lambdas.mm
+++ b/test/PCH/cxx1y-lambdas.mm
@@ -1,58 +1,58 @@
-// RUN: %clang_cc1 -pedantic-errors -fblocks -std=c++1y -emit-pch %s -o %t-cxx1y
-// RUN: %clang_cc1 -ast-print -pedantic-errors -fblocks -std=c++1y -include-pch %t-cxx1y %s | FileCheck -check-prefix=CHECK-PRINT %s
-
-#ifndef HEADER_INCLUDED
-
-#define HEADER_INCLUDED
-template<typename T>
-T add_slowly(const T& x, const T &y) {
- return [](auto z, int y = 0) { return z + y; }(5);
-};
-
-inline int add_int_slowly_twice(int x, int y) {
- int i = add_slowly(x, y);
- auto lambda = [](auto z) { return z + z; };
- return i + lambda(y);
-}
-
-inline int sum_array(int n) {
- auto lambda = [](auto N) -> int {
- int sum = 0;
- int array[5] = { 1, 2, 3, 4, 5};
-
- for (unsigned I = 0; I < N; ++I)
- sum += array[N];
- return sum;
- };
-
- return lambda(n);
-}
-
-inline int to_block_pointer(int n) {
- auto lambda = [=](int m) { return n + m; };
- int (^block)(int) = lambda;
- return block(17);
-}
-
-template<typename T>
-int init_capture(T t) {
- return [&, x(t)] { return sizeof(x); };
-}
-
-#else
-
-// CHECK-PRINT: T add_slowly
-// CHECK-PRINT: return []
-template float add_slowly(const float&, const float&);
-
-int add(int x, int y) {
- return add_int_slowly_twice(x, y) + sum_array(4) + to_block_pointer(5);
-}
-
-// CHECK-PRINT: inline int add_int_slowly_twice
-// CHECK-PRINT: lambda = [] (type-parameter-0-0 z
-
-// CHECK-PRINT: init_capture
-// CHECK-PRINT: [&, x(t)]
-
-#endif
+// RUN: %clang_cc1 -pedantic-errors -fblocks -std=c++1y -emit-pch %s -o %t-cxx1y
+// RUN: %clang_cc1 -ast-print -pedantic-errors -fblocks -std=c++1y -include-pch %t-cxx1y %s | FileCheck -check-prefix=CHECK-PRINT %s
+
+#ifndef HEADER_INCLUDED
+
+#define HEADER_INCLUDED
+template<typename T>
+T add_slowly(const T& x, const T &y) {
+ return [](auto z, int y = 0) { return z + y; }(5);
+};
+
+inline int add_int_slowly_twice(int x, int y) {
+ int i = add_slowly(x, y);
+ auto lambda = [](auto z) { return z + z; };
+ return i + lambda(y);
+}
+
+inline int sum_array(int n) {
+ auto lambda = [](auto N) -> int {
+ int sum = 0;
+ int array[5] = { 1, 2, 3, 4, 5};
+
+ for (unsigned I = 0; I < N; ++I)
+ sum += array[N];
+ return sum;
+ };
+
+ return lambda(n);
+}
+
+inline int to_block_pointer(int n) {
+ auto lambda = [=](int m) { return n + m; };
+ int (^block)(int) = lambda;
+ return block(17);
+}
+
+template<typename T>
+int init_capture(T t) {
+ return [&, x(t)] { return sizeof(x); };
+}
+
+#else
+
+// CHECK-PRINT: T add_slowly
+// CHECK-PRINT: return []
+template float add_slowly(const float&, const float&);
+
+int add(int x, int y) {
+ return add_int_slowly_twice(x, y) + sum_array(4) + to_block_pointer(5);
+}
+
+// CHECK-PRINT: inline int add_int_slowly_twice
+// CHECK-PRINT: lambda = [] (type-parameter-0-0 z
+
+// CHECK-PRINT: init_capture
+// CHECK-PRINT: [&, x(t)]
+
+#endif
diff --git a/test/PCH/emit-pth.c b/test/PCH/emit-pth.c
new file mode 100644
index 0000000..2c0fba7
--- /dev/null
+++ b/test/PCH/emit-pth.c
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-pth -o %t1 %s
+// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-pth -o - %s > %t2
+// RUN: cmp %t1 %t2
+// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-pth -o - %s | \
+// RUN: FileCheck %s
+
+// CHECK: cfe-pth
diff --git a/test/Parser/atomic.c b/test/Parser/atomic.c
index 07a83dd..e435518 100644
--- a/test/Parser/atomic.c
+++ b/test/Parser/atomic.c
@@ -36,3 +36,5 @@
struct S
_Atomic atomic_s_no_missing_semicolon;
+
+int *const _Atomic atomic_return_type();
diff --git a/test/Parser/cxx-class.cpp b/test/Parser/cxx-class.cpp
index 215c941..f46e752 100644
--- a/test/Parser/cxx-class.cpp
+++ b/test/Parser/cxx-class.cpp
@@ -159,6 +159,7 @@
~D::D() throw(X) {} // expected-error {{'~' in destructor name should be after nested name specifier}}
~Undeclared::Undeclared() {} // expected-error {{use of undeclared identifier 'Undeclared'}} expected-error {{'~' in destructor name should be after nested name specifier}}
+ ~Undeclared:: {} // expected-error {{expected identifier}} expected-error {{'~' in destructor name should be after nested name specifier}}
struct S {
// For another struct's destructor, emit the same diagnostic like for
diff --git a/test/Parser/cxx0x-attributes.cpp b/test/Parser/cxx0x-attributes.cpp
index 33987f9..7eec576 100644
--- a/test/Parser/cxx0x-attributes.cpp
+++ b/test/Parser/cxx0x-attributes.cpp
@@ -346,3 +346,10 @@
deprecated
]] void bad();
}
+
+#define attr_name bitand
+#define attr_name_2(x) x
+#define attr_name_3(x, y) x##y
+[[attr_name, attr_name_2(bitor), attr_name_3(com, pl)]] int macro_attrs; // expected-warning {{unknown attribute 'compl' ignored}} \
+ expected-warning {{unknown attribute 'bitor' ignored}} \
+ expected-warning {{unknown attribute 'bitand' ignored}}
diff --git a/test/Preprocessor/aarch64-target-features.c b/test/Preprocessor/aarch64-target-features.c
index 45a6c89..85c0f24 100644
--- a/test/Preprocessor/aarch64-target-features.c
+++ b/test/Preprocessor/aarch64-target-features.c
@@ -109,3 +109,11 @@
// RUN: %clang -target aarch64 -march=armv8-a+neon -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-ERROR-NEON %s
// RUN: %clang -target aarch64 -march=armv8-a+noneon -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-ERROR-NEON %s
// CHECK-ERROR-NEON: error: [no]neon is not accepted as modifier, please use [no]simd instead
+
+// RUN: %clang -target aarch64 -march=armv8.1a+crypto -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V81A-FEATURE-1 %s
+// RUN: %clang -target aarch64 -march=armv8.1a+nocrypto -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V81A-FEATURE-2 %s
+// RUN: %clang -target aarch64 -march=armv8.1a+nosimd -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V81A-FEATURE-3 %s
+// CHECK-V81A-FEATURE-1: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+neon" "-target-feature" "+v8.1a" "-target-feature" "+crypto"
+// CHECK-V81A-FEATURE-2: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+neon" "-target-feature" "+v8.1a" "-target-feature" "-crypto"
+// CHECK-V81A-FEATURE-3: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8.1a" "-target-feature" "-neon"
+
diff --git a/test/Preprocessor/arm-target-features.c b/test/Preprocessor/arm-target-features.c
index 926a753..b16b744 100644
--- a/test/Preprocessor/arm-target-features.c
+++ b/test/Preprocessor/arm-target-features.c
@@ -264,6 +264,24 @@
// A53-THUMB:#define __ARM_ARCH_EXT_IDIV__ 1
// A53-THUMB:#define __ARM_FEATURE_DSP
+// Test whether predefines are as expected when targeting cortex-r4.
+// RUN: %clang -target armv7 -mcpu=cortex-r4 -x c -E -dM %s -o - | FileCheck --check-prefix=R4-ARM %s
+// R4-ARM-NOT:#define __ARM_ARCH_EXT_IDIV__
+// R4-ARM:#define __ARM_FEATURE_DSP
+
+// RUN: %clang -target armv7 -mthumb -mcpu=cortex-r4 -x c -E -dM %s -o - | FileCheck --check-prefix=R4-THUMB %s
+// R4-THUMB:#define __ARM_ARCH_EXT_IDIV__ 1
+// R4-THUMB:#define __ARM_FEATURE_DSP
+
+// Test whether predefines are as expected when targeting cortex-r4f.
+// RUN: %clang -target armv7 -mcpu=cortex-r4f -x c -E -dM %s -o - | FileCheck --check-prefix=R4F-ARM %s
+// R4F-ARM-NOT:#define __ARM_ARCH_EXT_IDIV__
+// R4F-ARM:#define __ARM_FEATURE_DSP
+
+// RUN: %clang -target armv7 -mthumb -mcpu=cortex-r4f -x c -E -dM %s -o - | FileCheck --check-prefix=R4F-THUMB %s
+// R4F-THUMBT:#define __ARM_ARCH_EXT_IDIV__ 1
+// R4F-THUMB:#define __ARM_FEATURE_DSP
+
// Test whether predefines are as expected when targeting cortex-r5.
// RUN: %clang -target armv7 -mcpu=cortex-r5 -x c -E -dM %s -o - | FileCheck --check-prefix=R5-ARM %s
// R5-ARM:#define __ARM_ARCH_EXT_IDIV__ 1
diff --git a/test/Preprocessor/has_include.c b/test/Preprocessor/has_include.c
index 131e519..ad73293 100644
--- a/test/Preprocessor/has_include.c
+++ b/test/Preprocessor/has_include.c
@@ -163,6 +163,18 @@
#if __has_include
#endif
+// expected-error@+1 {{missing '(' after '__has_include'}}
+#if __has_include'x'
+#endif
+
+// expected-error@+1 {{expected "FILENAME" or <FILENAME>}}
+#if __has_include('x'
+#endif
+
+// expected-error@+1 {{expected "FILENAME" or <FILENAME}} expected-error@+1 {{expected end of line in preprocessor expression}}
+#if __has_include('x')
+#endif
+
// expected-error@+1 {{missing ')' after '__has_include'}} // expected-error@+1 {{expected value in expression}} // expected-note@+1 {{to match this '('}}
#if __has_include(<stdint.h>
#endif
diff --git a/test/Preprocessor/init.c b/test/Preprocessor/init.c
index ad63d01..91ec4d7 100644
--- a/test/Preprocessor/init.c
+++ b/test/Preprocessor/init.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -E -dM -x assembler-with-cpp < /dev/null | FileCheck -check-prefix ASM %s
+/PtrDiffType / RUN: %clang_cc1 -E -dM -x assembler-with-cpp < /dev/null | FileCheck -check-prefix ASM %s
//
// ASM:#define __ASSEMBLER__ 1
//
@@ -4416,11 +4416,16 @@
// RUN: | FileCheck -check-prefix MIPS-MSA %s
// MIPS-MSA:#define __mips_msa 1
//
-// RUN: %clang_cc1 -target-feature +nan2008 \
+// RUN: %clang_cc1 -target-cpu mips32r3 -target-feature +nan2008 \
// RUN: -E -dM -triple=mips-none-none < /dev/null \
// RUN: | FileCheck -check-prefix MIPS-NAN2008 %s
// MIPS-NAN2008:#define __mips_nan2008 1
//
+// RUN: %clang_cc1 -target-cpu mips32r3 -target-feature -nan2008 \
+// RUN: -E -dM -triple=mips-none-none < /dev/null \
+// RUN: | FileCheck -check-prefix NOMIPS-NAN2008 %s
+// NOMIPS-NAN2008-NOT:#define __mips_nan2008 1
+//
// RUN: %clang_cc1 -target-feature -fp64 \
// RUN: -E -dM -triple=mips-none-none < /dev/null \
// RUN: | FileCheck -check-prefix MIPS32-MFP32 %s
@@ -4769,7 +4774,7 @@
// NVPTX32:#define __NVPTX__ 1
// NVPTX32:#define __POINTER_WIDTH__ 32
// NVPTX32:#define __PRAGMA_REDEFINE_EXTNAME 1
-// NVPTX32:#define __PTRDIFF_TYPE__ unsigned int
+// NVPTX32:#define __PTRDIFF_TYPE__ int
// NVPTX32:#define __PTRDIFF_WIDTH__ 32
// NVPTX32:#define __PTX__ 1
// NVPTX32:#define __SCHAR_MAX__ 127
@@ -4898,10 +4903,10 @@
// NVPTX64:#define __INTMAX_MAX__ 9223372036854775807LL
// NVPTX64:#define __INTMAX_TYPE__ long long int
// NVPTX64:#define __INTMAX_WIDTH__ 64
-// NVPTX64:#define __INTPTR_FMTd__ "lld"
-// NVPTX64:#define __INTPTR_FMTi__ "lli"
-// NVPTX64:#define __INTPTR_MAX__ 9223372036854775807LL
-// NVPTX64:#define __INTPTR_TYPE__ long long int
+// NVPTX64:#define __INTPTR_FMTd__ "ld"
+// NVPTX64:#define __INTPTR_FMTi__ "li"
+// NVPTX64:#define __INTPTR_MAX__ 9223372036854775807L
+// NVPTX64:#define __INTPTR_TYPE__ long int
// NVPTX64:#define __INTPTR_WIDTH__ 64
// NVPTX64:#define __INT_FAST16_FMTd__ "hd"
// NVPTX64:#define __INT_FAST16_FMTi__ "hi"
@@ -4956,7 +4961,7 @@
// NVPTX64:#define __NVPTX__ 1
// NVPTX64:#define __POINTER_WIDTH__ 64
// NVPTX64:#define __PRAGMA_REDEFINE_EXTNAME 1
-// NVPTX64:#define __PTRDIFF_TYPE__ long long unsigned int
+// NVPTX64:#define __PTRDIFF_TYPE__ long int
// NVPTX64:#define __PTRDIFF_WIDTH__ 64
// NVPTX64:#define __PTX__ 1
// NVPTX64:#define __SCHAR_MAX__ 127
@@ -4976,7 +4981,7 @@
// NVPTX64:#define __SIZEOF_WCHAR_T__ 4
// NVPTX64:#define __SIZEOF_WINT_T__ 4
// NVPTX64:#define __SIZE_MAX__ 18446744073709551615UL
-// NVPTX64:#define __SIZE_TYPE__ long long unsigned int
+// NVPTX64:#define __SIZE_TYPE__ long unsigned int
// NVPTX64:#define __SIZE_WIDTH__ 64
// NVPTX64:#define __UINT16_C_SUFFIX__ {{$}}
// NVPTX64:#define __UINT16_MAX__ 65535
@@ -4994,8 +4999,8 @@
// NVPTX64:#define __UINTMAX_MAX__ 18446744073709551615ULL
// NVPTX64:#define __UINTMAX_TYPE__ long long unsigned int
// NVPTX64:#define __UINTMAX_WIDTH__ 64
-// NVPTX64:#define __UINTPTR_MAX__ 18446744073709551615ULL
-// NVPTX64:#define __UINTPTR_TYPE__ long long unsigned int
+// NVPTX64:#define __UINTPTR_MAX__ 18446744073709551615UL
+// NVPTX64:#define __UINTPTR_TYPE__ long unsigned int
// NVPTX64:#define __UINTPTR_WIDTH__ 64
// NVPTX64:#define __UINT_FAST16_MAX__ 65535
// NVPTX64:#define __UINT_FAST16_TYPE__ unsigned short
@@ -6641,21 +6646,21 @@
// S390X:#define __INT32_FMTi__ "i"
// S390X:#define __INT32_MAX__ 2147483647
// S390X:#define __INT32_TYPE__ int
-// S390X:#define __INT64_C_SUFFIX__ LL
-// S390X:#define __INT64_FMTd__ "lld"
-// S390X:#define __INT64_FMTi__ "lli"
-// S390X:#define __INT64_MAX__ 9223372036854775807LL
-// S390X:#define __INT64_TYPE__ long long int
+// S390X:#define __INT64_C_SUFFIX__ L
+// S390X:#define __INT64_FMTd__ "ld"
+// S390X:#define __INT64_FMTi__ "li"
+// S390X:#define __INT64_MAX__ 9223372036854775807L
+// S390X:#define __INT64_TYPE__ long int
// S390X:#define __INT8_C_SUFFIX__ {{$}}
// S390X:#define __INT8_FMTd__ "hhd"
// S390X:#define __INT8_FMTi__ "hhi"
// S390X:#define __INT8_MAX__ 127
// S390X:#define __INT8_TYPE__ signed char
-// S390X:#define __INTMAX_C_SUFFIX__ LL
-// S390X:#define __INTMAX_FMTd__ "lld"
-// S390X:#define __INTMAX_FMTi__ "lli"
-// S390X:#define __INTMAX_MAX__ 9223372036854775807LL
-// S390X:#define __INTMAX_TYPE__ long long int
+// S390X:#define __INTMAX_C_SUFFIX__ L
+// S390X:#define __INTMAX_FMTd__ "ld"
+// S390X:#define __INTMAX_FMTi__ "li"
+// S390X:#define __INTMAX_MAX__ 9223372036854775807L
+// S390X:#define __INTMAX_TYPE__ long int
// S390X:#define __INTMAX_WIDTH__ 64
// S390X:#define __INTPTR_FMTd__ "ld"
// S390X:#define __INTPTR_FMTi__ "li"
@@ -6738,15 +6743,15 @@
// S390X:#define __UINT32_C_SUFFIX__ U
// S390X:#define __UINT32_MAX__ 4294967295U
// S390X:#define __UINT32_TYPE__ unsigned int
-// S390X:#define __UINT64_C_SUFFIX__ ULL
-// S390X:#define __UINT64_MAX__ 18446744073709551615ULL
-// S390X:#define __UINT64_TYPE__ long long unsigned int
+// S390X:#define __UINT64_C_SUFFIX__ UL
+// S390X:#define __UINT64_MAX__ 18446744073709551615UL
+// S390X:#define __UINT64_TYPE__ long unsigned int
// S390X:#define __UINT8_C_SUFFIX__ {{$}}
// S390X:#define __UINT8_MAX__ 255
// S390X:#define __UINT8_TYPE__ unsigned char
-// S390X:#define __UINTMAX_C_SUFFIX__ ULL
-// S390X:#define __UINTMAX_MAX__ 18446744073709551615ULL
-// S390X:#define __UINTMAX_TYPE__ long long unsigned int
+// S390X:#define __UINTMAX_C_SUFFIX__ UL
+// S390X:#define __UINTMAX_MAX__ 18446744073709551615UL
+// S390X:#define __UINTMAX_TYPE__ long unsigned int
// S390X:#define __UINTMAX_WIDTH__ 64
// S390X:#define __UINTPTR_MAX__ 18446744073709551615UL
// S390X:#define __UINTPTR_TYPE__ long unsigned int
diff --git a/test/Preprocessor/predefined-arch-macros.c b/test/Preprocessor/predefined-arch-macros.c
index 6e3743d..9fee3b6 100644
--- a/test/Preprocessor/predefined-arch-macros.c
+++ b/test/Preprocessor/predefined-arch-macros.c
@@ -1675,3 +1675,30 @@
//
// CHECK_PPC_CRYPTO_M64: #define __CRYPTO__
//
+
+// Begin SystemZ/GCC/Linux tests ----------------
+//
+// RUN: %clang -march=z10 -E -dM %s -o - 2>&1 \
+// RUN: -target s390x-unknown-linux \
+// RUN: | FileCheck %s -check-prefix=CHECK_SYSTEMZ_Z10
+//
+// CHECK_SYSTEMZ_Z10: #define __LONG_DOUBLE_128__ 1
+// CHECK_SYSTEMZ_Z10: #define __s390__ 1
+// CHECK_SYSTEMZ_Z10: #define __s390x__ 1
+// CHECK_SYSTEMZ_Z10: #define __zarch__ 1
+//
+// RUN: %clang -march=zEC12 -E -dM %s -o - 2>&1 \
+// RUN: -target s390x-unknown-linux \
+// RUN: | FileCheck %s -check-prefix=CHECK_SYSTEMZ_ZEC12
+//
+// CHECK_SYSTEMZ_ZEC12: #define __HTM__ 1
+// CHECK_SYSTEMZ_ZEC12: #define __LONG_DOUBLE_128__ 1
+// CHECK_SYSTEMZ_ZEC12: #define __s390__ 1
+// CHECK_SYSTEMZ_ZEC12: #define __s390x__ 1
+// CHECK_SYSTEMZ_ZEC12: #define __zarch__ 1
+//
+// RUN: %clang -mhtm -E -dM %s -o - 2>&1 \
+// RUN: -target s390x-unknown-linux \
+// RUN: | FileCheck %s -check-prefix=CHECK_SYSTEMZ_HTM
+//
+// CHECK_SYSTEMZ_HTM: #define __HTM__ 1
diff --git a/test/Preprocessor/stdint.c b/test/Preprocessor/stdint.c
index 9bc1aa7..28ccfef 100644
--- a/test/Preprocessor/stdint.c
+++ b/test/Preprocessor/stdint.c
@@ -851,8 +851,8 @@
//
// RUN: %clang_cc1 -E -ffreestanding -triple=s390x-none-none %s | FileCheck -check-prefix S390X %s
//
-// S390X:typedef long long int int64_t;
-// S390X:typedef long long unsigned int uint64_t;
+// S390X:typedef long int int64_t;
+// S390X:typedef long unsigned int uint64_t;
// S390X:typedef int64_t int_least64_t;
// S390X:typedef uint64_t uint_least64_t;
// S390X:typedef int64_t int_fast64_t;
@@ -882,8 +882,8 @@
// S390X:typedef int64_t intptr_t;
// S390X:typedef uint64_t uintptr_t;
//
-// S390X:typedef long long int intmax_t;
-// S390X:typedef long long unsigned int uintmax_t;
+// S390X:typedef long int intmax_t;
+// S390X:typedef long unsigned int uintmax_t;
//
// S390X:INT8_MAX_ 127
// S390X:INT8_MIN_ (-127 -1)
@@ -916,23 +916,23 @@
// S390X:UINT_FAST32_MAX_ 4294967295U
//
// S390X:INT64_MAX_ 9223372036854775807L
-// S390X:INT64_MIN_ (-9223372036854775807LL -1)
+// S390X:INT64_MIN_ (-9223372036854775807L -1)
// S390X:UINT64_MAX_ 18446744073709551615UL
-// S390X:INT_LEAST64_MIN_ (-9223372036854775807LL -1)
+// S390X:INT_LEAST64_MIN_ (-9223372036854775807L -1)
// S390X:INT_LEAST64_MAX_ 9223372036854775807L
// S390X:UINT_LEAST64_MAX_ 18446744073709551615UL
-// S390X:INT_FAST64_MIN_ (-9223372036854775807LL -1)
+// S390X:INT_FAST64_MIN_ (-9223372036854775807L -1)
// S390X:INT_FAST64_MAX_ 9223372036854775807L
// S390X:UINT_FAST64_MAX_ 18446744073709551615UL
//
-// S390X:INTPTR_MIN_ (-9223372036854775807LL -1)
+// S390X:INTPTR_MIN_ (-9223372036854775807L -1)
// S390X:INTPTR_MAX_ 9223372036854775807L
// S390X:UINTPTR_MAX_ 18446744073709551615UL
-// S390X:PTRDIFF_MIN_ (-9223372036854775807LL -1)
+// S390X:PTRDIFF_MIN_ (-9223372036854775807L -1)
// S390X:PTRDIFF_MAX_ 9223372036854775807L
// S390X:SIZE_MAX_ 18446744073709551615UL
//
-// S390X:INTMAX_MIN_ (-9223372036854775807LL -1)
+// S390X:INTMAX_MIN_ (-9223372036854775807L -1)
// S390X:INTMAX_MAX_ 9223372036854775807L
// S390X:UINTMAX_MAX_ 18446744073709551615UL
//
diff --git a/test/Profile/cxx-lambda.cpp b/test/Profile/cxx-lambda.cpp
index 6790149..34e1857 100644
--- a/test/Profile/cxx-lambda.cpp
+++ b/test/Profile/cxx-lambda.cpp
@@ -19,8 +19,8 @@
void lambdas() {
int i = 1;
- // LMBGEN-LABEL: define internal{{( zeroext)?}} i1 @"_ZZ7lambdasvENK3$_0clEi"(
- // LMBUSE-LABEL: define internal{{( zeroext)?}} i1 @"_ZZ7lambdasvENK3$_0clEi"(
+ // LMBGEN-LABEL: define internal{{( x86_thiscallcc)?( zeroext)?}} i1 @"_ZZ7lambdasvENK3$_0clEi"(
+ // LMBUSE-LABEL: define internal{{( x86_thiscallcc)?( zeroext)?}} i1 @"_ZZ7lambdasvENK3$_0clEi"(
// LMBGEN: store {{.*}} @[[LFC]], i64 0, i64 0
auto f = [&i](int k) {
// LMBGEN: store {{.*}} @[[LFC]], i64 0, i64 1
diff --git a/test/Profile/profile-does-not-exist.c b/test/Profile/profile-does-not-exist.c
new file mode 100644
index 0000000..89609bd
--- /dev/null
+++ b/test/Profile/profile-does-not-exist.c
@@ -0,0 +1,4 @@
+// RUN: not %clang_cc1 -emit-llvm %s -o - -fprofile-instr-use=%t.nonexistent.profdata 2>&1 | FileCheck %s
+
+// CHECK: error: Could not read profile:
+// CHECK-NOT: Assertion failed
diff --git a/test/Rewriter/objc-modern-boxing.mm b/test/Rewriter/objc-modern-boxing.mm
index 40eeafb..22d092f 100644
--- a/test/Rewriter/objc-modern-boxing.mm
+++ b/test/Rewriter/objc-modern-boxing.mm
@@ -61,12 +61,12 @@
NSString *duplicateString = @(strdup("Hello"));
}
-// CHECK: NSNumber *theLetterZ = ((NSNumber *(*)(id, SEL, char))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithChar:"), ('Z'));
-// CHECK: NSNumber *fortyTwo = ((NSNumber *(*)(id, SEL, int))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithInt:"), (42));
-// CHECK: NSNumber *fortyTwoUnsigned = ((NSNumber *(*)(id, SEL, unsigned int))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithUnsignedInt:"), (42U));
-// CHECK: NSNumber *fortyTwoLong = ((NSNumber *(*)(id, SEL, long))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithLong:"), (42L));
-// CHECK: NSNumber *fortyTwoLongLong = ((NSNumber *(*)(id, SEL, long long))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithLongLong:"), (42LL));
-// CHECK: NSNumber *piFloat = ((NSNumber *(*)(id, SEL, float))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithFloat:"), (3.14159274F));
-// CHECK: NSNumber *piDouble = ((NSNumber *(*)(id, SEL, double))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithDouble:"), (3.1415926535000001));
-// CHECK: NSNumber *nsb = ((NSNumber *(*)(id, SEL, BOOL))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithBool:"), (BOOL)(b));
-// CHECK: NSString *duplicateString = ((NSString *(*)(id, SEL, const char *))(void *)objc_msgSend)(objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), (const char *)(strdup("Hello")));
+// CHECK: NSNumber *theLetterZ = ((NSNumber *(*)(Class, SEL, char))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithChar:"), ('Z'));
+// CHECK: NSNumber *fortyTwo = ((NSNumber *(*)(Class, SEL, int))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithInt:"), (42));
+// CHECK: NSNumber *fortyTwoUnsigned = ((NSNumber *(*)(Class, SEL, unsigned int))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithUnsignedInt:"), (42U));
+// CHECK: NSNumber *fortyTwoLong = ((NSNumber *(*)(Class, SEL, long))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithLong:"), (42L));
+// CHECK: NSNumber *fortyTwoLongLong = ((NSNumber *(*)(Class, SEL, long long))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithLongLong:"), (42LL));
+// CHECK: NSNumber *piFloat = ((NSNumber *(*)(Class, SEL, float))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithFloat:"), (3.14159274F));
+// CHECK: NSNumber *piDouble = ((NSNumber *(*)(Class, SEL, double))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithDouble:"), (3.1415926535000001));
+// CHECK: NSNumber *nsb = ((NSNumber *(*)(Class, SEL, BOOL))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithBool:"), (BOOL)(b));
+// CHECK: NSString *duplicateString = ((NSString *(*)(Class, SEL, const char *))(void *)objc_msgSend)(objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), (const char *)(strdup("Hello")));
diff --git a/test/Rewriter/objc-modern-numeric-literal.mm b/test/Rewriter/objc-modern-numeric-literal.mm
index 57f7ca2..aff1d47 100644
--- a/test/Rewriter/objc-modern-numeric-literal.mm
+++ b/test/Rewriter/objc-modern-numeric-literal.mm
@@ -56,14 +56,14 @@
NSNumber *falseNumber = @false; // equivalent to [NSNumber numberWithBool:(BOOL)false]
}
-// CHECK: NSNumber *theLetterZ = ((NSNumber *(*)(id, SEL, char))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithChar:"), 'Z');
-// CHECK: NSNumber *fortyTwo = ((NSNumber *(*)(id, SEL, int))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithInt:"), 42);
-// CHECK: NSNumber *fortyTwoUnsigned = ((NSNumber *(*)(id, SEL, unsigned int))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithUnsignedInt:"), 42U);
-// CHECK: NSNumber *fortyTwoLong = ((NSNumber *(*)(id, SEL, long))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithLong:"), 42L);
-// CHECK: NSNumber *fortyTwoLongLong = ((NSNumber *(*)(id, SEL, long long))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithLongLong:"), 42LL);
-// CHECK: NSNumber *piFloat = ((NSNumber *(*)(id, SEL, float))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithFloat:"), 3.14159274F);
-// CHECK: NSNumber *piDouble = ((NSNumber *(*)(id, SEL, double))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithDouble:"), 3.1415926535000001);
-// CHECK: NSNumber *yesNumber = ((NSNumber *(*)(id, SEL, BOOL))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithBool:"), true);
-// CHECK: NSNumber *noNumber = ((NSNumber *(*)(id, SEL, BOOL))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithBool:"), false);
-// CHECK: NSNumber *trueNumber = ((NSNumber *(*)(id, SEL, BOOL))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithBool:"), true);
-// CHECK: NSNumber *falseNumber = ((NSNumber *(*)(id, SEL, BOOL))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithBool:"), false);
+// CHECK: NSNumber *theLetterZ = ((NSNumber *(*)(Class, SEL, char))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithChar:"), 'Z');
+// CHECK: NSNumber *fortyTwo = ((NSNumber *(*)(Class, SEL, int))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithInt:"), 42);
+// CHECK: NSNumber *fortyTwoUnsigned = ((NSNumber *(*)(Class, SEL, unsigned int))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithUnsignedInt:"), 42U);
+// CHECK: NSNumber *fortyTwoLong = ((NSNumber *(*)(Class, SEL, long))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithLong:"), 42L);
+// CHECK: NSNumber *fortyTwoLongLong = ((NSNumber *(*)(Class, SEL, long long))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithLongLong:"), 42LL);
+// CHECK: NSNumber *piFloat = ((NSNumber *(*)(Class, SEL, float))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithFloat:"), 3.14159274F);
+// CHECK: NSNumber *piDouble = ((NSNumber *(*)(Class, SEL, double))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithDouble:"), 3.1415926535000001);
+// CHECK: NSNumber *yesNumber = ((NSNumber *(*)(Class, SEL, BOOL))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithBool:"), true);
+// CHECK: NSNumber *noNumber = ((NSNumber *(*)(Class, SEL, BOOL))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithBool:"), false);
+// CHECK: NSNumber *trueNumber = ((NSNumber *(*)(Class, SEL, BOOL))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithBool:"), true);
+// CHECK: NSNumber *falseNumber = ((NSNumber *(*)(Class, SEL, BOOL))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithBool:"), false);
diff --git a/test/Rewriter/rewrite-modern-array-literal.mm b/test/Rewriter/rewrite-modern-array-literal.mm
index 208e646..c1431ea 100644
--- a/test/Rewriter/rewrite-modern-array-literal.mm
+++ b/test/Rewriter/rewrite-modern-array-literal.mm
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -x objective-c++ -fms-extensions -rewrite-objc %s -o %t-rw.cpp
-// RUN: %clang_cc1 -fsyntax-only -Wno-address-of-temporary -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp
+// RUN: %clang_cc1 -fsyntax-only -Wno-address-of-temporary -D"Class=void*" -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp
// rdar://10803676
extern "C" void *sel_registerName(const char *);
diff --git a/test/Rewriter/rewrite-modern-container-literal.mm b/test/Rewriter/rewrite-modern-container-literal.mm
index 2c2f61d..8a52791 100644
--- a/test/Rewriter/rewrite-modern-container-literal.mm
+++ b/test/Rewriter/rewrite-modern-container-literal.mm
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -x objective-c++ -fms-extensions -rewrite-objc %s -o %t-rw.cpp
-// RUN: %clang_cc1 -fsyntax-only -Wno-address-of-temporary -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp
+// RUN: %clang_cc1 -fsyntax-only -Wno-address-of-temporary -D"Class=void*" -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp
// rdar://10803676
void *sel_registerName(const char *);
diff --git a/test/Sema/__try.c b/test/Sema/__try.c
index 925dbcc..8be93dd 100644
--- a/test/Sema/__try.c
+++ b/test/Sema/__try.c
@@ -281,3 +281,9 @@
}();
}
}
+
+void test_typo_in_except() {
+ __try {
+ } __except(undeclared_identifier) { // expected-error {{use of undeclared identifier 'undeclared_identifier'}} expected-error {{expected expression}}
+ }
+}
diff --git a/test/Sema/anonymous-struct-union.c b/test/Sema/anonymous-struct-union.c
index 652383e..c33bc52 100644
--- a/test/Sema/anonymous-struct-union.c
+++ b/test/Sema/anonymous-struct-union.c
@@ -22,6 +22,7 @@
};
void test_unqual_references(struct X x, const struct X xc) {
+ // expected-note@-1 3{{variable 'xc' declared const here}}
x.i = 0;
x.f = 0.0;
x.f2 = x.f;
@@ -29,9 +30,9 @@
x.f3 = 0; // expected-error{{no member named 'f3'}}
x.a = 0;
- xc.d = 0.0; // expected-error{{read-only variable is not assignable}}
- xc.f = 0; // expected-error{{read-only variable is not assignable}}
- xc.a = 0; // expected-error{{read-only variable is not assignable}}
+ xc.d = 0.0; // expected-error{{cannot assign to variable 'xc' with const-qualified type 'const struct X'}}
+ xc.f = 0; // expected-error{{cannot assign to variable 'xc' with const-qualified type 'const struct X'}}
+ xc.a = 0; // expected-error{{cannot assign to variable 'xc' with const-qualified type 'const struct X'}}
}
diff --git a/test/Sema/assign.c b/test/Sema/assign.c
index 2d57029..1fff778 100644
--- a/test/Sema/assign.c
+++ b/test/Sema/assign.c
@@ -3,7 +3,10 @@
void *test1(void) { return 0; }
void test2 (const struct {int a;} *x) {
- x->a = 10; // expected-error {{read-only variable is not assignable}}
+ // expected-note@-1 {{variable 'x' declared const here}}
+
+ x->a = 10;
+ // expected-error-re@-1 {{cannot assign to variable 'x' with const-qualified type 'const struct (anonymous struct at {{.*}}assign.c:5:19) *'}}
}
typedef int arr[10];
diff --git a/test/Sema/block-misc.c b/test/Sema/block-misc.c
index 0ca4f20..c57b3e1 100644
--- a/test/Sema/block-misc.c
+++ b/test/Sema/block-misc.c
@@ -184,8 +184,8 @@
}
void test18() {
- void (^const blockA)(void) = ^{ };
- blockA = ^{ }; // expected-error {{read-only variable is not assignable}}
+ void (^const blockA)(void) = ^{ }; // expected-note {{variable 'blockA' declared const here}}
+ blockA = ^{ }; // expected-error {{cannot assign to variable 'blockA' with const-qualified type 'void (^const)(void)}}
}
// rdar://7072507
diff --git a/test/Sema/builtin-assume.c b/test/Sema/builtin-assume.c
index 512eeec..43b3137 100644
--- a/test/Sema/builtin-assume.c
+++ b/test/Sema/builtin-assume.c
@@ -1,16 +1,28 @@
// RUN: %clang_cc1 -triple i386-mingw32 -fms-extensions -fsyntax-only -verify %s
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fsyntax-only -verify %s
+int nonconst(void);
+int isconst(void) __attribute__((const));
+int ispure(int) __attribute__((pure));
+
int foo(int *a, int i) {
#ifdef _MSC_VER
__assume(i != 4);
__assume(++i > 2); //expected-warning {{the argument to '__assume' has side effects that will be discarded}}
+ __assume(nonconst() > 2); //expected-warning {{the argument to '__assume' has side effects that will be discarded}}
+ __assume(isconst() > 2);
+ __assume(ispure(i) > 2);
+ __assume(ispure(++i) > 2); //expected-warning {{the argument to '__assume' has side effects that will be discarded}}
int test = sizeof(struct{char qq[(__assume(i != 5), 7)];});
#else
__builtin_assume(i != 4);
__builtin_assume(++i > 2); //expected-warning {{the argument to '__builtin_assume' has side effects that will be discarded}}
-
+ __builtin_assume(nonconst() > 2); //expected-warning {{the argument to '__builtin_assume' has side effects that will be discarded}}
+ __builtin_assume(isconst() > 2);
+ __builtin_assume(ispure(i) > 2);
+ __builtin_assume(ispure(++i) > 2); //expected-warning {{the argument to '__builtin_assume' has side effects that will be discarded}}
+
int test = sizeof(struct{char qq[(__builtin_assume(i != 5), 7)];});
#endif
return a[i];
diff --git a/test/Sema/builtins-ppc.c b/test/Sema/builtins-ppc.c
new file mode 100644
index 0000000..60872a6
--- /dev/null
+++ b/test/Sema/builtins-ppc.c
@@ -0,0 +1,51 @@
+// REQUIRES: powerpc-registered-target
+// RUN: %clang_cc1 -faltivec -target-feature +htm \
+// RUN: -triple powerpc64-unknown-unknown -DTEST_HTM -fsyntax-only \
+// RUN: -verify %s
+
+// RUN: %clang_cc1 -faltivec -target-feature +crypto \
+// RUN: -triple powerpc64le-unknown-unknown -DTEST_CRYPTO -fsyntax-only \
+// RUN: -verify %s
+
+#ifdef TEST_HTM
+void test_htm() {
+ __builtin_tbegin(4); // expected-error {{argument should be a value from 0 to 1}}
+ __builtin_tend(-1); // expected-error {{argument should be a value from 0 to 1}}
+ __builtin_tsr(55); // expected-error {{argument should be a value from 0 to 7}}
+ __builtin_tabortwc(-5, 2, 3); // expected-error {{argument should be a value from 0 to 31}}
+ __builtin_tabortdc(55, 2, 3); // expected-error {{argument should be a value from 0 to 31}}
+ __builtin_tabortwci(-5, 2, 5); // expected-error {{argument should be a value from 0 to 31}}
+ __builtin_tabortwci(5, 2, 55); // expected-error {{argument should be a value from 0 to 31}}
+ __builtin_tabortdci(-5, 2, 5); // expected-error {{argument should be a value from 0 to 31}}
+ __builtin_tabortdci(5, 2, 55); // expected-error {{argument should be a value from 0 to 31}}
+}
+#endif
+
+
+#ifdef TEST_CRYPTO
+#include <altivec.h>
+
+#define W_INIT { 0x01020304, 0x05060708, 0x090A0B0C, 0x0D0E0F10 };
+#define D_INIT { 0x0102030405060708, 0x090A0B0C0D0E0F10 };
+vector unsigned int test_vshasigmaw_or(void)
+{
+ vector unsigned int a = W_INIT
+ vector unsigned int b = __builtin_crypto_vshasigmaw(a, 2, 15); // expected-error {{argument should be a value from 0 to 1}}
+ vector unsigned int c = __builtin_crypto_vshasigmaw(a, -1, 15); // expected-error {{argument should be a value from 0 to 1}}
+ vector unsigned int d = __builtin_crypto_vshasigmaw(a, 0, 85); // expected-error {{argument should be a value from 0 to 15}}
+ vector unsigned int e = __builtin_crypto_vshasigmaw(a, 1, -15); // expected-error {{argument should be a value from 0 to 15}}
+ return __builtin_crypto_vshasigmaw(a, 1, 15);
+}
+
+vector unsigned long long test_vshasigmad_or(void)
+{
+ vector unsigned long long a = D_INIT
+ vector unsigned long long b = __builtin_crypto_vshasigmad(a, 2, 15); // expected-error {{argument should be a value from 0 to 1}}
+ vector unsigned long long c = __builtin_crypto_vshasigmad(a, -1, 15); // expected-error {{argument should be a value from 0 to 1}}
+ vector unsigned long long d = __builtin_crypto_vshasigmad(a, 0, 85); // expected-error {{argument should be a value from 0 to 1}}
+ vector unsigned long long e = __builtin_crypto_vshasigmad(a, 1, -15); // expected-error {{argument should be a value from 0 to 1}}
+ return __builtin_crypto_vshasigmad(a, 0, 15);
+}
+
+#endif
+
diff --git a/test/Sema/builtins.cl b/test/Sema/builtins.cl
new file mode 100644
index 0000000..8cde8f3
--- /dev/null
+++ b/test/Sema/builtins.cl
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 %s -fsyntax-only -verify -pedantic
+// expected-no-diagnostics
+
+kernel void test(global float *out, global float *in, global int* in2) {
+ out[0] = __builtin_nanf("");
+ __builtin_memcpy(out, in, 32);
+ out[0] = __builtin_frexpf(in[0], in2);
+}
diff --git a/test/Sema/member-reference.c b/test/Sema/member-reference.c
index 8939fd5..4004673 100644
--- a/test/Sema/member-reference.c
+++ b/test/Sema/member-reference.c
@@ -20,5 +20,5 @@
}
int PR17762(struct simple c) {
- return c->i; // expected-error {{member reference type 'struct simple' is not a pointer; maybe you meant to use '.'?}}
+ return c->i; // expected-error {{member reference type 'struct simple' is not a pointer; did you mean to use '.'?}}
}
diff --git a/test/Sema/pragma-section-invalid.c b/test/Sema/pragma-section-invalid.c
new file mode 100644
index 0000000..b9075c4
--- /dev/null
+++ b/test/Sema/pragma-section-invalid.c
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -fms-extensions %s -triple x86_64-apple-darwin
+
+// expected-error@+1 {{argument to 'section' attribute is not valid for this target: mach-o section specifier requires a segment and section separated by a comma}}
+#pragma data_seg(".my_const")
+int a = 1;
+#pragma data_seg("__THINGY,thingy")
+int b = 1;
diff --git a/test/Sema/vla.c b/test/Sema/vla.c
index e03dda8..b9576bf 100644
--- a/test/Sema/vla.c
+++ b/test/Sema/vla.c
@@ -61,6 +61,9 @@
{
}
+void pr23151(int (*p1)[*]) // expected-error {{variable length array must be bound in function definition}}
+{}
+
// Make sure this isn't treated as an error
int TransformBug(int a) {
return sizeof(*(int(*)[({ goto v; v: a;})]) 0); // expected-warning {{use of GNU statement expression extension}}
diff --git a/test/Sema/warn-documentation.cpp b/test/Sema/warn-documentation.cpp
index 4375cfc..5d86635 100644
--- a/test/Sema/warn-documentation.cpp
+++ b/test/Sema/warn-documentation.cpp
@@ -1038,6 +1038,12 @@
///@param x@param y
int test_nocrash13(int x, int y);
+/**
+ * \verbatim
+ * Aaa
+ **/
+int test_nocrash14();
+
// rdar://12379114
// expected-warning@+2 {{'@union' command should not be used in a comment attached to a non-union declaration}}
/*!
diff --git a/test/SemaCUDA/function-target-disabled-check.cu b/test/SemaCUDA/function-target-disabled-check.cu
new file mode 100644
index 0000000..979d4ed
--- /dev/null
+++ b/test/SemaCUDA/function-target-disabled-check.cu
@@ -0,0 +1,26 @@
+// Test that we can disable cross-target call checks in Sema with the
+// -fcuda-disable-target-call-checks flag. Without this flag we'd get a bunch
+// of errors here, since there are invalid cross-target calls present.
+
+// RUN: %clang_cc1 -fsyntax-only -verify %s -fcuda-disable-target-call-checks
+// RUN: %clang_cc1 -fsyntax-only -fcuda-is-device -verify %s -fcuda-disable-target-call-checks
+
+// expected-no-diagnostics
+
+#define __device__ __attribute__((device))
+#define __global__ __attribute__((global))
+#define __host__ __attribute__((host))
+
+__attribute__((host)) void h1();
+
+__attribute__((device)) void d1() {
+ h1();
+}
+
+__attribute__((host)) void h2() {
+ d1();
+}
+
+__attribute__((global)) void g1() {
+ h2();
+}
diff --git a/test/SemaCXX/alignof.cpp b/test/SemaCXX/alignof.cpp
index f51146c..e3690ea 100644
--- a/test/SemaCXX/alignof.cpp
+++ b/test/SemaCXX/alignof.cpp
@@ -84,3 +84,16 @@
static_assert(sizeof(k) == alignof(long long), "");
}
template void n(long long);
+
+namespace PR22042 {
+template <typename T>
+void Fun(T A) {
+ typedef int __attribute__((__aligned__(A))) T1; // expected-error {{requested alignment is dependent but declaration is not dependent}}
+ int k1[__alignof__(T1)];
+}
+
+template <int N>
+struct S {
+ typedef __attribute__((aligned(N))) int Field[sizeof(N)]; // expected-error {{requested alignment is dependent but declaration is not dependent}}
+};
+}
diff --git a/test/SemaCXX/anonymous-union.cpp b/test/SemaCXX/anonymous-union.cpp
index 46d426c..3520245 100644
--- a/test/SemaCXX/anonymous-union.cpp
+++ b/test/SemaCXX/anonymous-union.cpp
@@ -39,13 +39,14 @@
a = 0;
}
-void X::test_unqual_references_const() const {
+void X::test_unqual_references_const() const { // expected-note 2{{member function 'X::test_unqual_references_const' is declared const here}}
d = 0.0;
- f2 = 0; // expected-error{{read-only variable is not assignable}}
- a = 0; // expected-error{{read-only variable is not assignable}}
+ f2 = 0; // expected-error{{cannot assign to non-static data member within const member function 'test_unqual_references_const'}}
+ a = 0; // expected-error{{cannot assign to non-static data member within const member function 'test_unqual_references_const'}}
}
void test_unqual_references(X x, const X xc) {
+ // expected-note@-1 2{{variable 'xc' declared const here}}
x.i = 0;
x.f = 0.0;
x.f2 = x.f;
@@ -54,8 +55,8 @@
x.a = 0;
xc.d = 0.0;
- xc.f = 0; // expected-error{{read-only variable is not assignable}}
- xc.a = 0; // expected-error{{read-only variable is not assignable}}
+ xc.f = 0; // expected-error{{cannot assign to variable 'xc' with const-qualified type 'const X'}}
+ xc.a = 0; // expected-error{{cannot assign to variable 'xc' with const-qualified type 'const X'}}
}
diff --git a/test/SemaCXX/captured-statements.cpp b/test/SemaCXX/captured-statements.cpp
index 5fb686c..d8f77e6 100644
--- a/test/SemaCXX/captured-statements.cpp
+++ b/test/SemaCXX/captured-statements.cpp
@@ -81,11 +81,11 @@
}
template <typename S, typename T>
-S template_capture_var(S x, T y) {
+S template_capture_var(S x, T y) { // expected-note{{variable 'y' declared const here}}
#pragma clang _debug captured
{
x++;
- y++; // expected-error{{read-only variable is not assignable}}
+ y++; // expected-error{{cannot assign to variable 'y' with const-qualified type 'const int'}}
}
return x;
diff --git a/test/SemaCXX/cxx0x-constexpr-const.cpp b/test/SemaCXX/cxx0x-constexpr-const.cpp
index 197edeb..a4398b3 100644
--- a/test/SemaCXX/cxx0x-constexpr-const.cpp
+++ b/test/SemaCXX/cxx0x-constexpr-const.cpp
@@ -1,10 +1,10 @@
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
-constexpr int x = 1;
+constexpr int x = 1; // expected-note {{variable 'x' declared const here}}
constexpr int id(int x) { return x; }
void foo(void) {
- x = 2; // expected-error {{read-only variable is not assignable}}
+ x = 2; // expected-error {{cannot assign to variable 'x' with const-qualified type 'const int'}}
int (*idp)(int) = id;
}
diff --git a/test/SemaCXX/cxx11-ast-print.cpp b/test/SemaCXX/cxx11-ast-print.cpp
index 5604374..27726de 100644
--- a/test/SemaCXX/cxx11-ast-print.cpp
+++ b/test/SemaCXX/cxx11-ast-print.cpp
@@ -38,6 +38,11 @@
const char *p9 = 0x42e3F_fritz;
// CHECK: const char *p10 = 3.300e+15_fritz;
const char *p10 = 3.300e+15_fritz;
+
+template <class C, C...> const char *operator"" _suffix();
+// CHECK: const char *PR23120 = operator "" _suffix<char32_t, 66615>();
+const char *PR23120 = U"𐐷"_suffix;
+
// CHECK: ;
;
// CHECK-NOT: ;
diff --git a/test/SemaCXX/cxx11-call-to-deleted-constructor.cpp b/test/SemaCXX/cxx11-call-to-deleted-constructor.cpp
new file mode 100644
index 0000000..dd04345
--- /dev/null
+++ b/test/SemaCXX/cxx11-call-to-deleted-constructor.cpp
@@ -0,0 +1,40 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// rdar://20281011
+
+namespace std {
+template<class _Ep> class initializer_list { };
+}
+
+namespace cva {
+
+template <class VT, unsigned int ROWS = 0, unsigned int COLS = 0>
+class Matrix {
+public:
+
+ typedef VT value_type;
+ inline __attribute__((always_inline)) value_type& at();
+};
+
+template <class VT, unsigned int SIZE> using Vector = Matrix<VT, SIZE, 1>;
+
+template <class VT>
+using RGBValue = Vector<VT, 3>;
+using RGBFValue = RGBValue<float>;
+
+template <class VT> class Matrix<VT, 0, 0> { // expected-note {{passing argument to parameter here}}
+public:
+ typedef VT value_type;
+ Matrix(const unsigned int nRows, const unsigned int nColumns, const value_type* data = nullptr);
+
+ Matrix(const std::initializer_list<value_type>& list) = delete; // expected-note {{'Matrix' has been explicitly marked deleted here}}
+
+};
+
+void getLaplacianClosedForm()
+{
+ Matrix<double> winI(0, 3);
+ RGBFValue* inputPreL;
+ winI = { inputPreL->at() }; // expected-error {{call to deleted constructor of 'cva::Matrix<double, 0, 0> &&'}}
+}
+
+}
diff --git a/test/SemaCXX/decl-microsoft-call-conv.cpp b/test/SemaCXX/decl-microsoft-call-conv.cpp
index a4b68cd..6c392ea 100644
--- a/test/SemaCXX/decl-microsoft-call-conv.cpp
+++ b/test/SemaCXX/decl-microsoft-call-conv.cpp
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -triple i686-pc-win32 -fms-extensions -verify %s
-// RUN: %clang_cc1 -triple i686-pc-mingw32 -verify %s
-// RUN: %clang_cc1 -triple i686-pc-mingw32 -fms-extensions -verify %s
+// RUN: %clang_cc1 -std=c++14 -triple i686-pc-win32 -fms-extensions -verify %s
+// RUN: %clang_cc1 -std=c++14 -triple i686-pc-mingw32 -verify %s
+// RUN: %clang_cc1 -std=c++14 -triple i686-pc-mingw32 -fms-extensions -verify %s
typedef void void_fun_t();
typedef void __cdecl cdecl_fun_t();
@@ -242,3 +242,19 @@
s.f(p); // expected-note {{in instantiation of member function 'test8::S<void *>::f' requested here}}
}
}
+
+namespace test9 {
+ // Used to fail when we forgot to make lambda call operators use __thiscall.
+ template <typename F>
+ decltype(auto) deduce(F f) {
+ return &decltype(f)::operator();
+ }
+ template <typename C, typename R, typename A>
+ decltype(auto) signaturehelper(R (C::*f)(A) const) {
+ return R();
+ }
+ void f() {
+ auto l = [](int x) { return x * 2; };
+ decltype(signaturehelper(deduce(l))) p;
+ }
+}
diff --git a/test/SemaCXX/enum-bitfield.cpp b/test/SemaCXX/enum-bitfield.cpp
index ec849b7..676ae44 100644
--- a/test/SemaCXX/enum-bitfield.cpp
+++ b/test/SemaCXX/enum-bitfield.cpp
@@ -28,3 +28,11 @@
A::B : C;
};
}
+
+enum WithUnderlying : unsigned { wu_value };
+struct WithUnderlyingBitfield {
+ WithUnderlying wu : 3;
+} wu = { wu_value };
+int want_unsigned(unsigned);
+int want_unsigned(int) = delete;
+int check_enum_bitfield_promotes_correctly = want_unsigned(wu.wu);
diff --git a/test/SemaCXX/err_typecheck_assign_const.cpp b/test/SemaCXX/err_typecheck_assign_const.cpp
new file mode 100644
index 0000000..376b6e6
--- /dev/null
+++ b/test/SemaCXX/err_typecheck_assign_const.cpp
@@ -0,0 +1,124 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
+
+const int global = 5; // expected-note{{variable 'global' declared const here}}
+void test1() {
+ global = 2; // expected-error{{cannot assign to variable 'global' with const-qualified type 'const int'}}
+}
+
+void test2 () {
+ const int local = 5; // expected-note{{variable 'local' declared const here}}
+ local = 0; // expected-error{{cannot assign to variable 'local' with const-qualified type 'const int'}}
+}
+
+void test2 (const int parameter) { // expected-note{{variable 'parameter' declared const here}}
+ parameter = 2; // expected-error{{cannot assign to variable 'parameter' with const-qualified type 'const int'}}
+}
+
+class test3 {
+ int field;
+ const int const_field = 1; // expected-note 2{{non-static data member 'const_field' declared const here}}
+ static const int static_const_field = 1; // expected-note 2{{variable 'static_const_field' declared const here}}
+ void test() {
+ const_field = 4; // expected-error{{cannot assign to non-static data member 'const_field' with const-qualified type 'const int'}}
+ static_const_field = 4; // expected-error{{cannot assign to variable 'static_const_field' with const-qualified type 'const int'}}
+ }
+ void test_const() const { // expected-note 2{{member function 'test3::test_const' is declared const here}}
+ field = 4; // expected-error{{cannot assign to non-static data member within const member function 'test_const'}}
+ const_field = 4 ; // expected-error{{cannot assign to non-static data member 'const_field' with const-qualified type 'const int'}}
+ static_const_field = 4; // expected-error{{cannot assign to variable 'static_const_field' with const-qualified type 'const int'}}
+ }
+};
+
+const int &return_const_ref(); // expected-note{{function 'return_const_ref' which returns const-qualified type 'const int &' declared here}}
+
+void test4() {
+ return_const_ref() = 10; // expected-error{{cannot assign to return value because function 'return_const_ref' returns a const value}}
+}
+
+struct S5 {
+ int field;
+ const int const_field = 4; // expected-note {{non-static data member 'const_field' declared const here}}
+};
+
+void test5() {
+ S5 s5;
+ s5.field = 5;
+ s5.const_field = 5; // expected-error{{cannot assign to non-static data member 'const_field' with const-qualified type 'const int'}}
+}
+
+struct U1 {
+ int a = 5;
+};
+
+struct U2 {
+ U1 u1;
+};
+
+struct U3 {
+ const U2 u2 = U2(); // expected-note{{non-static data member 'u2' declared const here}}
+};
+
+struct U4 {
+ U3 u3;
+};
+
+void test6() {
+ U4 u4;
+ u4.u3.u2.u1.a = 5; // expected-error{{cannot assign to non-static data member 'u2' with const-qualified type 'const U2'}}
+}
+
+struct A {
+ int z;
+};
+struct B {
+ A a;
+};
+struct C {
+ B b;
+ C();
+};
+const C &getc(); // expected-note{{function 'getc' which returns const-qualified type 'const C &' declared here}}
+void test7() {
+ const C c; // expected-note{{variable 'c' declared const here}}
+ c.b.a.z = 5; // expected-error{{cannot assign to variable 'c' with const-qualified type 'const C'}}
+
+ getc().b.a.z = 5; // expected-error{{cannot assign to return value because function 'getc' returns a const value}}
+}
+
+struct D { const int n; }; // expected-note 2{{non-static data member 'n' declared const here}}
+struct E { D *const d = 0; };
+void test8() {
+ extern D *const d;
+ d->n = 0; // expected-error{{cannot assign to non-static data member 'n' with const-qualified type 'const int'}}
+
+ E e;
+ e.d->n = 0; // expected-error{{cannot assign to non-static data member 'n' with const-qualified type 'const int'}}
+}
+
+struct F { int n; };
+struct G { const F *f; }; // expected-note{{non-static data member 'f' declared const here}}
+void test10() {
+ const F *f; // expected-note{{variable 'f' declared const here}}
+ f->n = 0; // expected-error{{cannot assign to variable 'f' with const-qualified type 'const F *'}}
+
+ G g;
+ g.f->n = 0; // expected-error{{cannot assign to non-static data member 'f' with const-qualified type 'const F *'}}
+}
+
+void test11(
+ const int x, // expected-note{{variable 'x' declared const here}}
+ const int& y // expected-note{{variable 'y' declared const here}}
+ ) {
+ x = 5; // expected-error{{cannot assign to variable 'x' with const-qualified type 'const int'}}
+ y = 5; // expected-error{{cannot assign to variable 'y' with const-qualified type 'const int &'}}
+}
+
+struct H {
+ const int a = 0; // expected-note{{non-static data member 'a' declared const here}}
+ const int &b = a; // expected-note{{non-static data member 'b' declared const here}}
+};
+
+void test12(H h) {
+ h.a = 1; // expected-error {{cannot assign to non-static data member 'a' with const-qualified type 'const int'}}
+ h.b = 2; // expected-error {{cannot assign to non-static data member 'b' with const-qualified type 'const int &'}}
+}
diff --git a/test/SemaCXX/err_typecheck_assign_const_filecheck.cpp b/test/SemaCXX/err_typecheck_assign_const_filecheck.cpp
new file mode 100644
index 0000000..0d29b1e
--- /dev/null
+++ b/test/SemaCXX/err_typecheck_assign_const_filecheck.cpp
@@ -0,0 +1,252 @@
+// RUN: not %clang_cc1 -fsyntax-only -std=c++11 %s 2>&1 | FileCheck %s
+
+struct E {
+ int num;
+ const int Cnum = 0;
+ mutable int Mnum;
+ static int Snum;
+ const static int CSnum;
+};
+
+struct D {
+ E e;
+ const E Ce;
+ mutable E Me;
+ static E Se;
+ const static E CSe;
+ E &getE() const;
+ const E &getCE() const;
+};
+
+struct C {
+ D d;
+ const D Cd;
+ mutable D Md;
+ static D Sd;
+ const static D CSd;
+ D &getD() const;
+ const D &getCD() const;
+};
+
+struct B {
+ C c;
+ const C Cc;
+ mutable C Mc;
+ static C Sc;
+ const static C CSc;
+ C &getC() const;
+ static C &getSC();
+ const C &getCC() const;
+ static const C &getSCC();
+};
+
+struct A {
+ B b;
+ const B Cb;
+ mutable B Mb;
+ static B Sb;
+ const static B CSb;
+ B &getB() const;
+ static B &getSB();
+ const B &getCB() const;
+ static const B &getSCB();
+};
+
+A& getA();
+
+// Valid assignment
+void test1(A a, const A Ca) {
+ a.b.c.d.e.num = 5;
+ a.b.c.d.e.Mnum = 5;
+ Ca.b.c.d.e.Mnum = 5;
+ a.b.c.d.e.Snum = 5;
+ Ca.b.c.d.e.Snum = 5;
+ Ca.b.c.Md.e.num = 5;
+ Ca.Mb.Cc.d.e.Mnum = 5;
+ Ca.Mb.getC().d.e.num = 5;
+ Ca.getSB().c.d.e.num = 5;
+ a.getSCB().c.d.Me.num = 5;
+ Ca.Cb.Cc.Cd.Ce.Snum = 5;
+ // CHECK-NOT: error:
+ // CHECK-NOT: note:
+}
+
+// One note
+void test2(A a, const A Ca) {
+ Ca.b.c.d.e.num = 5;
+ // CHECK-NOT: error:
+ // CHECK: error:{{.*}} 'Ca'
+ // CHECK-NOT: note:
+ // CHECK: note:{{.*}} 'Ca'
+ // CHECK-NOT: note:
+
+ a.Cb.c.d.e.num = 5;
+ // CHECK-NOT: error:
+ // CHECK: error:{{.*}} 'Cb'
+ // CHECK-NOT: note:
+ // CHECK: note:{{.*}} 'Cb'
+ // CHECK-NOT: note:
+
+ a.b.c.Cd.e.num = 5;
+ // CHECK-NOT: error:
+ // CHECK: error:{{.*}} 'Cd'
+ // CHECK-NOT: note:
+ // CHECK: note:{{.*}} 'Cd'
+ // CHECK-NOT: note:
+
+ a.b.c.d.e.CSnum = 5;
+ // CHECK-NOT: error:
+ // CHECK: error:{{.*}} 'CSnum'
+ // CHECK-NOT: note:
+ // CHECK: note:{{.*}} 'CSnum'
+ // CHECK-NOT: note:
+
+ a.b.c.d.e.Cnum = 5;
+ // CHECK-NOT: error:
+ // CHECK: error:{{.*}} 'Cnum'
+ // CHECK-NOT: note:
+ // CHECK: note:{{.*}} 'Cnum'
+ // CHECK-NOT: note:
+
+ a.getCB().c.d.e.num = 5;
+ // CHECK-NOT: error:
+ // CHECK: error:{{.*}} 'getCB'
+ // CHECK-NOT: note:
+ // CHECK: note:{{.*}} 'getCB'
+ // CHECK-NOT: note:
+
+ a.getSCB().c.d.e.num = 5;
+ // CHECK-NOT: error:
+ // CHECK: error:{{.*}} 'getSCB'
+ // CHECK-NOT: note:
+ // CHECK: note:{{.*}} 'getSCB'
+ // CHECK-NOT: note:
+}
+
+// Two notes
+void test3(A a, const A Ca) {
+
+ a.getSCB().Cc.d.e.num = 5;
+ // CHECK-NOT: error:
+ // CHECK: error:{{.*}} 'Cc'
+ // CHECK-NOT: note:
+ // CHECK: note:{{.*}} 'Cc'
+ // CHECK-NOT: note:
+ // CHECK: note:{{.*}} 'getSCB'
+ // CHECK-NOT: note:
+
+ Ca.b.c.Cd.e.num = 5;
+ // CHECK-NOT: error:
+ // CHECK: error:{{.*}} 'Cd'
+ // CHECK-NOT: note:
+ // CHECK: note:{{.*}} 'Cd'
+ // CHECK-NOT: note:
+ // CHECK: note:{{.*}} 'Ca'
+ // CHECK-NOT: note:
+
+ a.getCB().c.Cd.e.num = 5;
+ // CHECK-NOT: error:
+ // CHECK: error:{{.*}} 'Cd'
+ // CHECK-NOT: note:
+ // CHECK: note:{{.*}} 'Cd'
+ // CHECK-NOT: note:
+ // CHECK: note:{{.*}} 'getCB'
+ // CHECK-NOT: note:
+
+ a.b.getCC().d.e.Cnum = 5;
+ // CHECK-NOT: error:
+ // CHECK: error:{{.*}} 'Cnum'
+ // CHECK-NOT: note:
+ // CHECK: note:{{.*}} 'Cnum'
+ // CHECK-NOT: note:
+ // CHECK: note:{{.*}} 'getCC'
+ // CHECK-NOT: note:
+
+ a.b.c.Cd.Ce.num = 5;
+ // CHECK-NOT: error:
+ // CHECK: error:{{.*}} 'Ce'
+ // CHECK-NOT: note:
+ // CHECK: note:{{.*}} 'Ce'
+ // CHECK-NOT: note:
+ // CHECK: note:{{.*}} 'Cd'
+ // CHECK-NOT: note:
+
+ a.b.CSc.Cd.e.num = 5;
+ // CHECK-NOT: error:
+ // CHECK: error:{{.*}} 'Cd'
+ // CHECK-NOT: note:
+ // CHECK: note:{{.*}} 'Cd'
+ // CHECK-NOT: note:
+ // CHECK: note:{{.*}} 'CSc'
+ // CHECK-NOT: note:
+
+ a.CSb.c.Cd.e.num = 5;
+ // CHECK-NOT: error:
+ // CHECK: error:{{.*}} 'Cd'
+ // CHECK-NOT: note:
+ // CHECK: note:{{.*}} 'Cd'
+ // CHECK-NOT: note:
+ // CHECK: note:{{.*}} 'CSb'
+ // CHECK-NOT: note:
+}
+
+// No errors
+void test4(const A Ca) {
+ // Mutable cases
+ Ca.Mb.c.d.e.num = 5;
+ Ca.CSb.Mc.d.e.num = 5;
+ Ca.getCB().Mc.d.e.num = 5;
+ Ca.getSCB().Mc.d.e.num = 5;
+
+ // Returning non-const reference
+ Ca.getB().c.d.e.num = 5;
+ Ca.CSb.getC().d.e.num = 5;
+ Ca.getCB().getC().d.e.num = 5;
+ Ca.getSCB().getC().d.e.num = 5;
+
+ // Returning non-const reference
+ Ca.getSB().c.d.e.num = 5;
+ Ca.CSb.getSC().d.e.num = 5;
+ Ca.getCB().getSC().d.e.num = 5;
+ Ca.getSCB().getSC().d.e.num = 5;
+
+ // Static member
+ Ca.Sb.c.d.e.num = 5;
+ Ca.CSb.Sc.d.e.num = 5;
+ Ca.getCB().Sc.d.e.num = 5;
+ Ca.getSCB().Sc.d.e.num = 5;
+
+ // CHECK-NOT: error:
+ // CHECK-NOT: note:
+}
+
+// Only display notes for relavent cases.
+void test5(const A Ca) {
+ Ca.Mb.c.d.Ce.num = 5;
+ // CHECK-NOT: error:
+ // CHECK: error:{{.*}} 'Ce'
+ // CHECK-NOT: note:
+ // CHECK: note:{{.*}} 'Ce'
+ // CHECK-NOT: note:
+
+ Ca.getB().c.d.Ce.num = 5;
+ // CHECK-NOT: error:
+ // CHECK: error:{{.*}} 'Ce'
+ // CHECK-NOT: note:
+ // CHECK: note:{{.*}} 'Ce'
+ // CHECK-NOT: note:
+
+ Ca.getSB().c.d.Ce.num = 5;
+ // CHECK-NOT: error:
+ // CHECK: error:{{.*}} 'Ce'
+ // CHECK-NOT: note:
+ // CHECK: note:{{.*}} 'Ce'
+ // CHECK-NOT: note:
+
+ Ca.Sb.c.d.Ce.num = 5;
+ // CHECK-NOT: error:
+ // CHECK: error:{{.*}} 'Ce'
+ // CHECK-NOT: note:
+ // CHECK: note:{{.*}} 'Ce'
+ // CHECK-NOT: note:
+}
diff --git a/test/SemaCXX/exceptions.cpp b/test/SemaCXX/exceptions.cpp
index 6ac51b3..9802a1a 100644
--- a/test/SemaCXX/exceptions.cpp
+++ b/test/SemaCXX/exceptions.cpp
@@ -146,6 +146,82 @@
void rval_ref() throw (int &&); // expected-error {{rvalue reference type 'int &&' is not allowed in exception specification}} expected-warning {{C++11}}
+namespace HandlerInversion {
+struct B {};
+struct D : B {};
+struct D2 : D {};
+
+void f1() {
+ try {
+ } catch (B &b) { // expected-note {{for type 'HandlerInversion::B &'}}
+ } catch (D &d) { // expected-warning {{exception of type 'HandlerInversion::D &' will be caught by earlier handler}}
+ }
+}
+
+void f2() {
+ try {
+ } catch (B *b) { // expected-note {{for type 'HandlerInversion::B *'}}
+ } catch (D *d) { // expected-warning {{exception of type 'HandlerInversion::D *' will be caught by earlier handler}}
+ }
+}
+
+void f3() {
+ try {
+ } catch (D &d) { // Ok
+ } catch (B &b) {
+ }
+}
+
+void f4() {
+ try {
+ } catch (B &b) { // Ok
+ }
+}
+
+void f5() {
+ try {
+ } catch (int) {
+ } catch (float) {
+ }
+}
+
+void f6() {
+ try {
+ } catch (B &b) { // expected-note {{for type 'HandlerInversion::B &'}}
+ } catch (D2 &d) { // expected-warning {{exception of type 'HandlerInversion::D2 &' will be caught by earlier handler}}
+ }
+}
+
+void f7() {
+ try {
+ } catch (B *b) { // Ok
+ } catch (D &d) { // Ok
+ }
+
+ try {
+ } catch (B b) { // Ok
+ } catch (D *d) { // Ok
+ }
+}
+
+void f8() {
+ try {
+ } catch (const B &b) { // expected-note {{for type 'const HandlerInversion::B &'}}
+ } catch (D2 &d) { // expected-warning {{exception of type 'HandlerInversion::D2 &' will be caught by earlier handler}}
+ }
+
+ try {
+ } catch (B &b) { // expected-note {{for type 'HandlerInversion::B &'}}
+ } catch (const D2 &d) { // expected-warning {{exception of type 'const HandlerInversion::D2 &' will be caught by earlier handler}}
+ }
+
+ try {
+ } catch (B b) { // expected-note {{for type 'HandlerInversion::B'}}
+ } catch (D &d) { // expected-warning {{exception of type 'HandlerInversion::D &' will be caught by earlier handler}}
+ }
+}
+}
+
namespace ConstVolatileThrow {
struct S {
S() {} // expected-note{{candidate constructor not viable}}
diff --git a/test/SemaCXX/function-type-qual.cpp b/test/SemaCXX/function-type-qual.cpp
index 613ac9b..bb25c17 100644
--- a/test/SemaCXX/function-type-qual.cpp
+++ b/test/SemaCXX/function-type-qual.cpp
@@ -17,8 +17,8 @@
x = 0;
}
- void m2() const {
- x = 0; // expected-error {{read-only variable is not assignable}}
+ void m2() const { // expected-note {{member function 'C::m2' is declared const here}}
+ x = 0; // expected-error {{cannot assign to non-static data member within const member function 'm2'}}
}
int x;
diff --git a/test/SemaCXX/functional-cast.cpp b/test/SemaCXX/functional-cast.cpp
index f5ca76c..9db95e8 100644
--- a/test/SemaCXX/functional-cast.cpp
+++ b/test/SemaCXX/functional-cast.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
// REQUIRES: LP64
// ------------ not interpreted as C-style cast ------------
@@ -11,7 +11,7 @@
InitViaConstructor(int i = 7);
};
-struct NoValueInit { // expected-note 2 {{candidate constructor (the implicit copy constructor)}}
+struct NoValueInit { // expected-note 2 {{candidate constructor (the implicit copy constructor)}} expected-note 2 {{candidate constructor (the implicit move constructor)}}
NoValueInit(int i, int j); // expected-note 2 {{candidate constructor}}
};
@@ -25,6 +25,7 @@
(void)NoValueInit(0, 0);
(void)NoValueInit(0, 0, 0); // expected-error{{no matching constructor for initialization}}
(void)int(1, 2); // expected-error{{excess elements in scalar initializer}}
+ (void)int({}, 2); // expected-error{{excess elements in scalar initializer}}
}
diff --git a/test/SemaCXX/member-expr.cpp b/test/SemaCXX/member-expr.cpp
index e0955ae..5b3393e 100644
--- a/test/SemaCXX/member-expr.cpp
+++ b/test/SemaCXX/member-expr.cpp
@@ -87,7 +87,7 @@
}
void test2(A &x) {
- x->A::foo<int>(); // expected-error {{'test5::A' is not a pointer; maybe you meant to use '.'?}}
+ x->A::foo<int>(); // expected-error {{'test5::A' is not a pointer; did you mean to use '.'?}}
}
}
@@ -181,7 +181,7 @@
int f() {
Cl0 c;
- return c->a; // expected-error {{member reference type 'PR15045::Cl0' is not a pointer; maybe you meant to use '.'?}}
+ return c->a; // expected-error {{member reference type 'PR15045::Cl0' is not a pointer; did you mean to use '.'?}}
}
struct bar {
@@ -202,7 +202,7 @@
foo f;
// Show that recovery has happened by also triggering typo correction
- e->Func(); // expected-error {{member reference type 'PR15045::bar' is not a pointer; maybe you meant to use '.'?}} \
+ e->Func(); // expected-error {{member reference type 'PR15045::bar' is not a pointer; did you mean to use '.'?}} \
// expected-error {{no member named 'Func' in 'PR15045::bar'; did you mean 'func'?}}
// Make sure a fixit isn't given in the case that the '->' isn't actually
@@ -221,6 +221,6 @@
int f(S* s) {
T t;
return t.get_s // expected-error {{reference to non-static member function must be called; did you mean to call it with no arguments?}}
- .i; // expected-error {{member reference type 'pr16676::S *' is a pointer; maybe you meant to use '->'}}
+ .i; // expected-error {{member reference type 'pr16676::S *' is a pointer; did you mean to use '->'}}
}
}
diff --git a/test/SemaCXX/pseudo-destructors.cpp b/test/SemaCXX/pseudo-destructors.cpp
index 3971881..45f1eaf 100644
--- a/test/SemaCXX/pseudo-destructors.cpp
+++ b/test/SemaCXX/pseudo-destructors.cpp
@@ -46,7 +46,7 @@
i->N::~Integer(); // expected-error{{'Integer' does not refer to a type name in pseudo-destructor expression; expected the name of type 'int'}}
i->Integer::~Double(); // expected-error{{the type of object expression ('int') does not match the type being destroyed ('Double' (aka 'double')) in pseudo-destructor expression}}
- ii->~Integer(); // expected-error{{member reference type 'int' is not a pointer; maybe you meant to use '.'?}}
+ ii->~Integer(); // expected-error{{member reference type 'int' is not a pointer; did you mean to use '.'?}}
ii.~Integer();
cv_test(a);
diff --git a/test/SemaCXX/typo-correction-cxx11.cpp b/test/SemaCXX/typo-correction-cxx11.cpp
new file mode 100644
index 0000000..573c6aa
--- /dev/null
+++ b/test/SemaCXX/typo-correction-cxx11.cpp
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+
+namespace PR23186 {
+decltype(ned); // expected-error-re {{use of undeclared identifier 'ned'{{$}}}}
+// The code below was triggering an UNREACHABLE in ASTContext::getTypeInfoImpl
+// once the above code failed to recover properly after making the bogus
+// correction of 'ned' to 'new'.
+template <typename>
+struct S {
+ enum { V };
+ void f() {
+ switch (0)
+ case V:
+ ;
+ }
+};
+}
diff --git a/test/SemaCXX/typo-correction.cpp b/test/SemaCXX/typo-correction.cpp
index 3249001..174b140 100644
--- a/test/SemaCXX/typo-correction.cpp
+++ b/test/SemaCXX/typo-correction.cpp
@@ -634,3 +634,9 @@
}
};
}
+
+namespace crash_has_include {
+int has_include(int); // expected-note {{'has_include' declared here}}
+// expected-error@+1 {{__has_include must be used within a preprocessing directive}}
+int foo = __has_include(42); // expected-error {{use of undeclared identifier '__has_include'; did you mean 'has_include'?}}
+}
diff --git a/test/SemaCXX/unreachable-catch-clauses.cpp b/test/SemaCXX/unreachable-catch-clauses.cpp
index c75067f..8dcb47b 100644
--- a/test/SemaCXX/unreachable-catch-clauses.cpp
+++ b/test/SemaCXX/unreachable-catch-clauses.cpp
@@ -8,7 +8,6 @@
void test()
try {}
-catch (BaseEx &e) { f(); }
-catch (Ex1 &e) { f(); } // expected-note {{for type class Ex1 &}}
-catch (Ex2 &e) { f(); } // expected-warning {{exception of type Ex2 & will be caught by earlier handler}}
-
+catch (BaseEx &e) { f(); } // expected-note 2{{for type 'BaseEx &'}}
+catch (Ex1 &e) { f(); } // expected-warning {{exception of type 'Ex1 &' will be caught by earlier handler}}
+catch (Ex2 &e) { f(); } // expected-warning {{exception of type 'Ex2 &' (aka 'Ex1 &') will be caught by earlier handler}}
diff --git a/test/SemaCXX/vla.cpp b/test/SemaCXX/vla.cpp
index dae6450..6efb648 100644
--- a/test/SemaCXX/vla.cpp
+++ b/test/SemaCXX/vla.cpp
@@ -17,3 +17,6 @@
incomplete c[n]; // expected-error {{incomplete}}
}
}
+
+void pr23151(int (&)[*]) { // expected-error {{variable length array must be bound in function definition}}
+}
diff --git a/test/SemaCXX/warn-consumed-analysis.cpp b/test/SemaCXX/warn-consumed-analysis.cpp
index 977b862..0a6aed6 100644
--- a/test/SemaCXX/warn-consumed-analysis.cpp
+++ b/test/SemaCXX/warn-consumed-analysis.cpp
@@ -638,6 +638,18 @@
*var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}}
}
+// Tests if state information is correctly discarded for certain shapes of CFGs.
+void testSwitchGOTO(void) {
+ int a;
+
+ LABEL0:
+ switch (a)
+ case 0:
+ goto LABEL0;
+
+ goto LABEL0;
+}
+
typedef const int*& IntegerPointerReference;
void testIsRValueRefishAndCanonicalType(IntegerPointerReference a) {}
diff --git a/test/SemaCXX/warn-range-loop-analysis.cpp b/test/SemaCXX/warn-range-loop-analysis.cpp
new file mode 100644
index 0000000..91756b9
--- /dev/null
+++ b/test/SemaCXX/warn-range-loop-analysis.cpp
@@ -0,0 +1,299 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wloop-analysis -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wrange-loop-analysis -verify %s
+
+template <typename return_type>
+struct Iterator {
+ return_type operator*();
+ Iterator operator++();
+ bool operator!=(const Iterator);
+};
+
+template <typename T>
+struct Container {
+ typedef Iterator<T> I;
+
+ I begin();
+ I end();
+};
+
+struct Foo {};
+struct Bar {
+ Bar(Foo);
+ Bar(int);
+ operator int();
+};
+
+// Testing notes:
+// test0 checks that the full text of the warnings and notes is correct. The
+// rest of the tests checks a smaller portion of the text.
+// test1-6 are set in pairs, the odd numbers are the non-reference returning
+// versions of the even numbers.
+// test7-9 use an array instead of a range object
+// tests use all four versions of the loop varaible, const &T, const T, T&, and
+// T. Versions producing errors and are commented out.
+//
+// Conversion chart:
+// double <=> int
+// int <=> Bar
+// double => Bar
+// Foo => Bar
+//
+// Conversions during tests:
+// test1-2
+// int => int
+// int => double
+// int => Bar
+// test3-4
+// Bar => Bar
+// Bar => int
+// test5-6
+// Foo => Bar
+// test7
+// double => double
+// double => int
+// double => Bar
+// test8
+// Foo => Foo
+// Foo => Bar
+// test9
+// Bar => Bar
+// Bar => int
+
+void test0() {
+ Container<int> int_non_ref_container;
+ Container<int&> int_container;
+ Container<Bar&> bar_container;
+
+ for (const int &x : int_non_ref_container) {}
+ // expected-warning@-1 {{loop variable 'x' is always a copy because the range of type 'Container<int>' does not return a reference}}
+ // expected-note@-2 {{use non-reference type 'int'}}
+
+ for (const double &x : int_container) {}
+ // expected-warning@-1 {{loop variable 'x' has type 'const double &' but is initialized with type 'int' resulting in a copy}}
+ // expected-note@-2 {{use non-reference type 'double' to keep the copy or type 'const int &' to prevent copying}}
+
+ for (const Bar x : bar_container) {}
+ // expected-warning@-1 {{loop variable 'x' of type 'const Bar' creates a copy from type 'const Bar'}}
+ // expected-note@-2 {{use reference type 'const Bar &' to prevent copying}}
+}
+
+void test1() {
+ Container<int> A;
+
+ for (const int &x : A) {}
+ // expected-warning@-1 {{always a copy}}
+ // expected-note@-2 {{'int'}}
+ for (const int x : A) {}
+ // No warning, non-reference type indicates copy is made
+ //for (int &x : A) {}
+ // Binding error
+ for (int x : A) {}
+ // No warning, non-reference type indicates copy is made
+
+ for (const double &x : A) {}
+ // expected-warning@-1 {{always a copy}}
+ // expected-note@-2 {{'double'}}
+ for (const double x : A) {}
+ // No warning, non-reference type indicates copy is made
+ //for (double &x : A) {}
+ // Binding error
+ for (double x : A) {}
+ // No warning, non-reference type indicates copy is made
+
+ for (const Bar &x : A) {}
+ // expected-warning@-1 {{always a copy}}
+ // expected-note@-2 {{'Bar'}}
+ for (const Bar x : A) {}
+ // No warning, non-reference type indicates copy is made
+ //for (Bar &x : A) {}
+ // Binding error
+ for (Bar x : A) {}
+ // No warning, non-reference type indicates copy is made
+}
+
+void test2() {
+ Container<int&> B;
+
+ for (const int &x : B) {}
+ // No warning, this reference is not a temporary
+ for (const int x : B) {}
+ // No warning on POD copy
+ for (int &x : B) {}
+ // No warning
+ for (int x : B) {}
+ // No warning
+
+ for (const double &x : B) {}
+ // expected-warning@-1 {{resulting in a copy}}
+ // expected-note-re@-2 {{'double'{{.*}}'const int &'}}
+ for (const double x : B) {}
+ //for (double &x : B) {}
+ // Binding error
+ for (double x : B) {}
+ // No warning
+
+ for (const Bar &x : B) {}
+ // expected-warning@-1 {{resulting in a copy}}
+ // expected-note@-2 {{'Bar'}}
+ for (const Bar x : B) {}
+ //for (Bar &x : B) {}
+ // Binding error
+ for (Bar x : B) {}
+ // No warning
+}
+
+void test3() {
+ Container<Bar> C;
+
+ for (const Bar &x : C) {}
+ // expected-warning@-1 {{always a copy}}
+ // expected-note@-2 {{'Bar'}}
+ for (const Bar x : C) {}
+ // No warning, non-reference type indicates copy is made
+ //for (Bar &x : C) {}
+ // Binding error
+ for (Bar x : C) {}
+ // No warning, non-reference type indicates copy is made
+
+ for (const int &x : C) {}
+ // expected-warning@-1 {{always a copy}}
+ // expected-note@-2 {{'int'}}
+ for (const int x : C) {}
+ // No warning, copy made
+ //for (int &x : C) {}
+ // Binding error
+ for (int x : C) {}
+ // No warning, copy made
+}
+
+void test4() {
+ Container<Bar&> D;
+
+ for (const Bar &x : D) {}
+ // No warning, this reference is not a temporary
+ for (const Bar x : D) {}
+ // expected-warning@-1 {{creates a copy}}
+ // expected-note@-2 {{'const Bar &'}}
+ for (Bar &x : D) {}
+ // No warning
+ for (Bar x : D) {}
+ // No warning
+
+ for (const int &x : D) {}
+ // expected-warning@-1 {{resulting in a copy}}
+ // expected-note-re@-2 {{'int'{{.*}}'const Bar &'}}
+ for (const int x : D) {}
+ // No warning
+ //for (int &x : D) {}
+ // Binding error
+ for (int x : D) {}
+ // No warning
+}
+
+void test5() {
+ Container<Foo> E;
+
+ for (const Bar &x : E) {}
+ // expected-warning@-1 {{always a copy}}
+ // expected-note@-2 {{'Bar'}}
+ for (const Bar x : E) {}
+ // No warning, non-reference type indicates copy is made
+ //for (Bar &x : E) {}
+ // Binding error
+ for (Bar x : E) {}
+ // No warning, non-reference type indicates copy is made
+}
+
+void test6() {
+ Container<Foo&> F;
+
+ for (const Bar &x : F) {}
+ // expected-warning@-1 {{resulting in a copy}}
+ // expected-note-re@-2 {{'Bar'{{.*}}'const Foo &'}}
+ for (const Bar x : F) {}
+ // No warning.
+ //for (Bar &x : F) {}
+ // Binding error
+ for (Bar x : F) {}
+ // No warning
+}
+
+void test7() {
+ double G[2];
+
+ for (const double &x : G) {}
+ // No warning
+ for (const double x : G) {}
+ // No warning on POD copy
+ for (double &x : G) {}
+ // No warning
+ for (double x : G) {}
+ // No warning
+
+ for (const int &x : G) {}
+ // expected-warning@-1 {{resulting in a copy}}
+ // expected-note-re@-2 {{'int'{{.*}}'const double &'}}
+ for (const int x : G) {}
+ // No warning
+ //for (int &x : G) {}
+ // Binding error
+ for (int x : G) {}
+ // No warning
+
+ for (const Bar &x : G) {}
+ // expected-warning@-1 {{resulting in a copy}}
+ // expected-note-re@-2 {{'Bar'{{.*}}'const double &'}}
+ for (const Bar x : G) {}
+ // No warning
+ //for (int &Bar : G) {}
+ // Binding error
+ for (int Bar : G) {}
+ // No warning
+}
+
+void test8() {
+ Foo H[2];
+
+ for (const Foo &x : H) {}
+ // No warning
+ for (const Foo x : H) {}
+ // No warning on POD copy
+ for (Foo &x : H) {}
+ // No warning
+ for (Foo x : H) {}
+ // No warning
+
+ for (const Bar &x : H) {}
+ // expected-warning@-1 {{resulting in a copy}}
+ // expected-note-re@-2 {{'Bar'{{.*}}'const Foo &'}}
+ for (const Bar x : H) {}
+ // No warning
+ //for (Bar &x: H) {}
+ // Binding error
+ for (Bar x: H) {}
+ // No warning
+}
+
+void test9() {
+ Bar I[2] = {1,2};
+
+ for (const Bar &x : I) {}
+ // No warning
+ for (const Bar x : I) {}
+ // expected-warning@-1 {{creates a copy}}
+ // expected-note@-2 {{'const Bar &'}}
+ for (Bar &x : I) {}
+ // No warning
+ for (Bar x : I) {}
+ // No warning
+
+ for (const int &x : I) {}
+ // expected-warning@-1 {{resulting in a copy}}
+ // expected-note-re@-2 {{'int'{{.*}}'const Bar &'}}
+ for (const int x : I) {}
+ // No warning
+ //for (int &x : I) {}
+ // Binding error
+ for (int x : I) {}
+ // No warning
+}
diff --git a/test/SemaCXX/warn-unused-result.cpp b/test/SemaCXX/warn-unused-result.cpp
index 7bdb424..01bc457 100644
--- a/test/SemaCXX/warn-unused-result.cpp
+++ b/test/SemaCXX/warn-unused-result.cpp
@@ -44,6 +44,12 @@
}
namespace warn_unused_CXX11 {
+class Status;
+class Foo {
+ public:
+ Status doStuff();
+};
+
struct [[clang::warn_unused_result]] Status {
bool ok() const;
Status& operator=(const Status& x);
@@ -73,10 +79,23 @@
(void)DoYetAnotherThing();
DoSomething(); // expected-warning {{ignoring return value}}
- DoSomethingElse(); // expected-warning {{ignoring return value}}
- DoAnotherThing(); // expected-warning {{ignoring return value}}
+ DoSomethingElse();
+ DoAnotherThing();
DoYetAnotherThing();
}
+
+template <typename T>
+class [[clang::warn_unused_result]] StatusOr {
+};
+StatusOr<int> doit();
+void test() {
+ Foo f;
+ f.doStuff(); // expected-warning {{ignoring return value}}
+ doit(); // expected-warning {{ignoring return value}}
+
+ auto func = []() { return Status(); };
+ func(); // expected-warning {{ignoring return value}}
+}
}
namespace PR17587 {
diff --git a/test/SemaObjC/arc-bridged-cast.m b/test/SemaObjC/arc-bridged-cast.m
index 9e716f9..0ba7792 100644
--- a/test/SemaObjC/arc-bridged-cast.m
+++ b/test/SemaObjC/arc-bridged-cast.m
@@ -80,3 +80,12 @@
ref = (__bridge_retained CFAnnotatedObjectRef) CreateSomething();
ref = (__bridge_retained CFAnnotatedObjectRef) CreateNSString();
}
+
+// rdar://20113785
+typedef const struct __attribute__((objc_bridge(UIFont))) __CTFont * CTFontRef;
+
+id testObjCBridgeUnknownTypeToId(CTFontRef font) {
+ id x = (__bridge id)font;
+ return x;
+}
+
diff --git a/test/SemaObjC/arc.m b/test/SemaObjC/arc.m
index 54a7db7..60bd673 100644
--- a/test/SemaObjC/arc.m
+++ b/test/SemaObjC/arc.m
@@ -293,8 +293,8 @@
x = 0; // expected-error {{fast enumeration variables can't be modified in ARC by default; declare the variable __strong to allow this}}
}
- for (const id x in collection) {
- x = 0; // expected-error {{read-only variable is not assignable}}
+ for (const id x in collection) { // expected-note {{variable 'x' declared const here}}
+ x = 0; // expected-error {{cannot assign to variable 'x' with const-qualified type 'const __strong id'}}
}
for (__strong id x in collection) {
diff --git a/test/SemaObjC/multiple-property-deprecated-decl.m b/test/SemaObjC/multiple-property-deprecated-decl.m
new file mode 100644
index 0000000..d7dbd45
--- /dev/null
+++ b/test/SemaObjC/multiple-property-deprecated-decl.m
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -fsyntax-only -triple x86_64-apple-macosx10.11 -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -x objective-c++ -fsyntax-only -triple x86_64-apple-macosx10.11 -verify -Wno-objc-root-class %s
+// expected-no-diagnostics
+// rdar://20408445
+
+@protocol NSFileManagerDelegate @end
+
+@interface NSFileManager
+@property (assign) id <NSFileManagerDelegate> delegate;
+@end
+
+@interface NSFontManager
+@property (assign) id delegate __attribute__((availability(macosx,introduced=10.0 ,deprecated=10.11,message="" "NSFontManager doesn't have any delegate method. This property should not be used.")));
+
+@end
+
+id Test20408445(id p) {
+ return [p delegate];
+}
diff --git a/test/SemaObjC/nonnull.m b/test/SemaObjC/nonnull.m
index cacca07..e1f3193 100644
--- a/test/SemaObjC/nonnull.m
+++ b/test/SemaObjC/nonnull.m
@@ -123,3 +123,5 @@
void PR18795_helper() {
PR18795(0); // expected-warning{{null passed to a callee that requires a non-null argument}}
}
+
+void (^PR23117)(int *) = ^(int *p1) __attribute__((nonnull(1))) {};
diff --git a/test/SemaObjC/objc-independent-class-attribute.m b/test/SemaObjC/objc-independent-class-attribute.m
new file mode 100644
index 0000000..2fc13f0
--- /dev/null
+++ b/test/SemaObjC/objc-independent-class-attribute.m
@@ -0,0 +1,36 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
+// rdar://20255473
+
+@interface NSObject @end
+
+typedef NSObject * __attribute__((objc_independent_class))dispatch_queue_t;
+
+typedef struct S {int ii; } * __attribute__((objc_independent_class))dispatch_queue_t_2; // expected-warning {{Objective-C object}}
+
+typedef struct { // expected-warning {{'objc_independent_class' attribute may be put on a typedef only; attribute is ignored}}
+ NSObject *__attribute__((objc_independent_class)) ns; // expected-warning {{'objc_independent_class' attribute may be put on a typedef only; attribute is ignored}}
+} __attribute__((objc_independent_class)) T;
+
+dispatch_queue_t dispatch_queue_create();
+
+@interface DispatchQPointerCastIssue : NSObject {
+ NSObject *__attribute__((objc_independent_class)) Ivar; // expected-warning {{'objc_independent_class' attribute may be put on a typedef only; attribute is ignored}}
+}
+
+@property (copy) NSObject *__attribute__((objc_independent_class)) Prop; // expected-warning {{'objc_independent_class' attribute may be put on a typedef only; attribute is ignored}}
+
+typedef NSObject * __attribute__((objc_independent_class))dispatch_queue_t_1;
+
+@end
+
+@implementation DispatchQPointerCastIssue
++ (dispatch_queue_t) newDispatchQueue {
+ return dispatch_queue_create();
+}
+@end
+
+NSObject *get_nsobject() {
+ typedef NSObject * __attribute__((objc_independent_class))dispatch_queue_t;
+ dispatch_queue_t dt;
+ return dt;
+}
diff --git a/test/SemaObjC/objcbridge-attribute-arc.m b/test/SemaObjC/objcbridge-attribute-arc.m
index e08bd3d..3bcfdf4 100644
--- a/test/SemaObjC/objcbridge-attribute-arc.m
+++ b/test/SemaObjC/objcbridge-attribute-arc.m
@@ -77,7 +77,8 @@
// expected-note {{use __bridge_transfer to transfer ownership of a +1 'CFErrorRef2' (aka 'struct __CFErrorRef *') into ARC}}
(void)(MyError*)cf; // expected-error {{cast of C pointer type 'CFErrorRef2' (aka 'struct __CFErrorRef *') to Objective-C pointer type 'MyError *' requires a bridged cast}} \
// expected-note {{__bridge to convert directly (no change in ownership)}} \
- // expected-note {{use __bridge_transfer to transfer ownership of a +1 'CFErrorRef2' (aka 'struct __CFErrorRef *') into ARC}}
+ // expected-note {{use __bridge_transfer to transfer ownership of a +1 'CFErrorRef2' (aka 'struct __CFErrorRef *') into ARC}} \
+ // expected-warning {{'CFErrorRef2' (aka 'struct __CFErrorRef *') bridges to NSError, not 'MyError'}}
(void)(NSUColor *)cf2; // expected-error {{cast of C pointer type 'CFUColor2Ref' (aka 'union __CFUPrimeColor *') to Objective-C pointer type 'NSUColor *' requires a bridged cast}} \
// expected-note {{use __bridge to convert directly (no change in ownership)}} \
// expected-note {{use __bridge_transfer to transfer ownership of a +1 'CFUColor2Ref' (aka 'union __CFUPrimeColor *') into ARC}}
@@ -216,7 +217,7 @@
void Test9(CFErrorRef2 cf, NSError *ns, NSString *str, Class c, CFUColor2Ref cf2) {
(void)(__bridge NSString *)cf; // expected-warning {{'CFErrorRef2' (aka 'struct __CFErrorRef *') bridges to NSError, not 'NSString'}}
(void)(__bridge NSError *)cf; // okay
- (void)(__bridge MyError*)cf; // okay,
+ (void)(__bridge MyError*)cf; // expected-warning {{'CFErrorRef2' (aka 'struct __CFErrorRef *') bridges to NSError, not 'MyError'}}
(void)(__bridge NSUColor *)cf2; // okay
(void)(__bridge CFErrorRef)ns; // okay
(void)(__bridge CFErrorRef)str; // expected-warning {{'NSString' cannot bridge to 'CFErrorRef' (aka 'struct __CFErrorRef *')}}
diff --git a/test/SemaObjC/objcbridge-attribute.m b/test/SemaObjC/objcbridge-attribute.m
index 2969ebe..9cab64e 100644
--- a/test/SemaObjC/objcbridge-attribute.m
+++ b/test/SemaObjC/objcbridge-attribute.m
@@ -73,7 +73,7 @@
void Test2(CFErrorRef2 cf, NSError *ns, NSString *str, Class c, CFUColor2Ref cf2) {
(void)(NSString *)cf; // expected-warning {{'CFErrorRef2' (aka 'struct __CFErrorRef *') bridges to NSError, not 'NSString'}}
(void)(NSError *)cf; // okay
- (void)(MyError*)cf; // okay,
+ (void)(MyError*)cf; // expected-warning {{'CFErrorRef2' (aka 'struct __CFErrorRef *') bridges to NSError, not 'MyError'}}
(void)(NSUColor *)cf2; // okay
(void)(CFErrorRef)ns; // okay
(void)(CFErrorRef)str; // expected-warning {{'NSString' cannot bridge to 'CFErrorRef' (aka 'struct __CFErrorRef *')}}
@@ -141,3 +141,14 @@
void Test9() {
NSNumber *w2 = (NSNumber*) bar(); // expected-error {{CF object of type 'CFDictionaryRef' (aka 'struct __CFDictionary *') is bridged to 'NSDictionary', which is not an Objective-C class}}
}
+
+// rdar://18311183
+@interface NSObject @end
+
+@interface NSFont : NSObject @end
+
+typedef struct __attribute__ ((objc_bridge(NSFont))) __CFFontRef * CFFontRef;
+
+void Test10(CFFontRef cf) {
+ (void)(__bridge NSObject *)cf;
+}
diff --git a/test/SemaObjC/objcbridgemutable-attribute.m b/test/SemaObjC/objcbridgemutable-attribute.m
index 4ec8de0..524e686 100644
--- a/test/SemaObjC/objcbridgemutable-attribute.m
+++ b/test/SemaObjC/objcbridgemutable-attribute.m
@@ -23,7 +23,8 @@
(void) (CFMutableDictionaryRef)md;
(void) (CFMutableDictionaryRef)nd; // expected-warning {{'NSDictionary' cannot bridge to 'CFMutableDictionaryRef' (aka 'struct __CFDictionary *')}}
- (void) (NSDictionary *)mcf; // expected-warning {{'CFMutableDictionaryRef' (aka 'struct __CFDictionary *') bridges to NSMutableDictionary, not 'NSDictionary'}}
+ (void) (NSDictionary *)mcf; // ok, bridgt_type NSMutableDictionary can be type-cast to its super class.
+ NSDictionary *nsdobj = (NSMutableDictionary*)0;
(void) (NSMutableDictionary *)mcf; // ok;
(void) (NSMutableDictionary *)bmcf; // expected-error {{CF object of type 'CFMutableDictionaryB2Ref' (aka 'struct __CFDictionaryB2 *') is bridged to 'P', which is not an Objective-C class}}
diff --git a/test/SemaObjC/property-9.m b/test/SemaObjC/property-9.m
index 4bed875..623143d 100644
--- a/test/SemaObjC/property-9.m
+++ b/test/SemaObjC/property-9.m
@@ -106,3 +106,18 @@
return d.instance.path; // expected-error {{property 'path' cannot be found in forward class object 'MDAInstance'}}
}
+// rdar://20469452
+@interface UIView @end
+
+@interface FRFakeBannerView : UIView
+@end
+
+@interface FRAdCollectionViewCell
+@property (nonatomic, weak, readonly) UIView *bannerView;
+@end
+
+@interface FRAdCollectionViewCell ()
+
+@property (nonatomic, weak, readwrite) FRFakeBannerView *bannerView;
+
+@end
diff --git a/test/SemaObjC/undef-arg-super-method-call.m b/test/SemaObjC/undef-arg-super-method-call.m
new file mode 100644
index 0000000..6a27acb
--- /dev/null
+++ b/test/SemaObjC/undef-arg-super-method-call.m
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// rdar://20350364
+
+@interface NSObject @end
+
+@interface DBGViewDebuggerSupport : NSObject
++ (void)addViewLayerInfo:(id)view;
+- (void)addInstViewLayerInfo:(id)view;
+@end
+
+@interface DBGViewDebuggerSupport_iOS : DBGViewDebuggerSupport
+@end
+
+@implementation DBGViewDebuggerSupport_iOS
++ (void)addViewLayerInfo:(id)aView; // expected-note {{'aView' declared here}}
+{
+ [super addViewLayerInfo:view]; // expected-error {{use of undeclared identifier 'view'; did you mean 'aView'?}}
+}
+- (void)addInstViewLayerInfo:(id)aView; // expected-note {{'aView' declared here}}
+{
+ [super addInstViewLayerInfo:view]; // expected-error {{use of undeclared identifier 'view'; did you mean 'aView'?}}
+}
+@end
diff --git a/test/SemaObjC/warn-strict-selector-match.m b/test/SemaObjC/warn-strict-selector-match.m
index 9f22e73..13e9bac 100644
--- a/test/SemaObjC/warn-strict-selector-match.m
+++ b/test/SemaObjC/warn-strict-selector-match.m
@@ -13,23 +13,24 @@
@interface Object @end
@interface Class1
-- (void)setWindow:(Object *)wdw; // expected-note {{using}}
+- (void)setWindow:(Object *)wdw; // expected-note 2 {{using}}
@end
@interface Class2
-- (void)setWindow:(Class1 *)window; // expected-note {{also found}}
+- (void)setWindow:(Class1 *)window; // expected-note 2 {{also found}}
@end
id foo(void) {
Object *obj = 0;
id obj2 = obj;
- [obj setWindow:0]; // expected-warning {{Object' may not respond to 'setWindow:'}}
+ [obj setWindow:0]; // expected-warning {{Object' may not respond to 'setWindow:'}} \
+ // expected-warning {{multiple methods named 'setWindow:' found}}
[obj2 setWindow:0]; // expected-warning {{multiple methods named 'setWindow:' found}}
return obj;
}
@protocol MyObject
-- (id)initWithData:(Object *)data; // expected-note {{using}}
+- (id)initWithData:(Object *)data; // expected-note {{also found}}
@end
@protocol SomeOther
@@ -37,7 +38,7 @@
@end
@protocol MyCoding
-- (id)initWithData:(id<MyObject, MyCoding>)data; // expected-note {{also found}}
+- (id)initWithData:(id<MyObject, MyCoding>)data; // expected-note {{using}}
@end
@interface NTGridDataObject: Object <MyCoding>
@@ -71,3 +72,29 @@
[(Class)0 port]; // OK - gcc issues warning but there is only one Class method so no ambiguity to warn
}
+// rdar://19265430
+@interface NSObject
+- (id)class;
+- (id) alloc;
+@end
+
+@class NSString;
+
+@interface A : NSObject
+- (instancetype)initWithType:(NSString *)whatever; // expected-note {{also found}}
+@end
+
+@interface Test : NSObject
+@end
+
+@implementation Test
++ (instancetype)foo
+{
+ return [[[self class] alloc] initWithType:3]; // expected-warning {{multiple methods named 'initWithType:'}}
+}
+
+- (instancetype)initWithType:(unsigned int)whatever // expected-note {{using}}
+{
+ return 0;
+}
+@end
diff --git a/test/SemaObjCXX/objcbridge-attribute-arc.mm b/test/SemaObjCXX/objcbridge-attribute-arc.mm
index 43c8e2b..ccede2a 100644
--- a/test/SemaObjCXX/objcbridge-attribute-arc.mm
+++ b/test/SemaObjCXX/objcbridge-attribute-arc.mm
@@ -62,7 +62,8 @@
// expected-note {{use __bridge_transfer to transfer ownership of a +1 'CFErrorRef2' (aka '__CFErrorRef *') into ARC}}
(void)(MyError*)cf; // expected-error {{cast of C pointer type 'CFErrorRef2' (aka '__CFErrorRef *') to Objective-C pointer type 'MyError *' requires a bridged cast}} \
// expected-note {{__bridge to convert directly (no change in ownership)}} \
- // expected-note {{use __bridge_transfer to transfer ownership of a +1 'CFErrorRef2' (aka '__CFErrorRef *') into ARC}}
+ // expected-note {{use __bridge_transfer to transfer ownership of a +1 'CFErrorRef2' (aka '__CFErrorRef *') into ARC}} \
+ // expected-warning {{'CFErrorRef2' (aka '__CFErrorRef *') bridges to NSError, not 'MyError'}}
(void)(NSUColor *)cf2; // expected-error {{cast of C pointer type 'CFUColor2Ref' (aka '__CFUPrimeColor *') to Objective-C pointer type 'NSUColor *' requires a bridged cast}} \
// expected-note {{use __bridge to convert directly (no change in ownership)}} \
// expected-note {{use __bridge_transfer to transfer ownership of a +1 'CFUColor2Ref' (aka '__CFUPrimeColor *') into ARC}}
@@ -201,7 +202,6 @@
void Test9(CFErrorRef2 cf, NSError *ns, NSString *str, Class c, CFUColor2Ref cf2) {
(void)(__bridge NSString *)cf; // expected-warning {{'CFErrorRef2' (aka '__CFErrorRef *') bridges to NSError, not 'NSString'}}
(void)(__bridge NSError *)cf; // okay
- (void)(__bridge MyError*)cf; // okay,
(void)(__bridge NSUColor *)cf2; // okay
(void)(__bridge CFErrorRef)ns; // okay
(void)(__bridge CFErrorRef)str; // expected-warning {{'NSString' cannot bridge to 'CFErrorRef' (aka '__CFErrorRef *')}}
diff --git a/test/SemaObjCXX/objcbridge-attribute.mm b/test/SemaObjCXX/objcbridge-attribute.mm
index e777774..83a3438 100644
--- a/test/SemaObjCXX/objcbridge-attribute.mm
+++ b/test/SemaObjCXX/objcbridge-attribute.mm
@@ -62,7 +62,8 @@
// expected-note {{use __bridge_transfer to transfer ownership of a +1 'CFErrorRef2' (aka '__CFErrorRef *') into ARC}}
(void)(MyError*)cf; // expected-error {{cast of C pointer type 'CFErrorRef2' (aka '__CFErrorRef *') to Objective-C pointer type 'MyError *' requires a bridged cast}} \
// expected-note {{__bridge to convert directly (no change in ownership)}} \
- // expected-note {{use __bridge_transfer to transfer ownership of a +1 'CFErrorRef2' (aka '__CFErrorRef *') into ARC}}
+ // expected-note {{use __bridge_transfer to transfer ownership of a +1 'CFErrorRef2' (aka '__CFErrorRef *') into ARC}} \
+ // expected-warning {{'CFErrorRef2' (aka '__CFErrorRef *') bridges to NSError, not 'MyError'}}
(void)(NSUColor *)cf2; // expected-error {{cast of C pointer type 'CFUColor2Ref' (aka '__CFUPrimeColor *') to Objective-C pointer type 'NSUColor *' requires a bridged cast}} \
// expected-note {{use __bridge to convert directly (no change in ownership)}} \
// expected-note {{use __bridge_transfer to transfer ownership of a +1 'CFUColor2Ref' (aka '__CFUPrimeColor *') into ARC}}
@@ -201,7 +202,7 @@
void Test9(CFErrorRef2 cf, NSError *ns, NSString *str, Class c, CFUColor2Ref cf2) {
(void)(__bridge NSString *)cf; // expected-warning {{'CFErrorRef2' (aka '__CFErrorRef *') bridges to NSError, not 'NSString'}}
(void)(__bridge NSError *)cf; // okay
- (void)(__bridge MyError*)cf; // okay,
+ (void)(__bridge MyError*)cf; // expected-warning {{'CFErrorRef2' (aka '__CFErrorRef *') bridges to NSError, not 'MyError'}}
(void)(__bridge NSUColor *)cf2; // okay
(void)(__bridge CFErrorRef)ns; // okay
(void)(__bridge CFErrorRef)str; // expected-warning {{'NSString' cannot bridge to 'CFErrorRef' (aka '__CFErrorRef *')}}
diff --git a/test/SemaObjCXX/objcbridge-static-cast.mm b/test/SemaObjCXX/objcbridge-static-cast.mm
index 97cc5c0..03e6145 100644
--- a/test/SemaObjCXX/objcbridge-static-cast.mm
+++ b/test/SemaObjCXX/objcbridge-static-cast.mm
@@ -62,7 +62,8 @@
// expected-note {{use __bridge_transfer with C-style cast to transfer ownership of a +1 'CFErrorRef2' (aka '__CFErrorRef *') into ARC}}
(void)static_cast<MyError*>(cf); // expected-error {{cast of C pointer type 'CFErrorRef2' (aka '__CFErrorRef *') to Objective-C pointer type 'MyError *' requires a bridged cast}} \
// expected-note {{use __bridge with C-style cast to convert directly (no change in ownership)}} \
- // expected-note {{use __bridge_transfer with C-style cast to transfer ownership of a +1 'CFErrorRef2' (aka '__CFErrorRef *') into ARC}}
+ // expected-note {{use __bridge_transfer with C-style cast to transfer ownership of a +1 'CFErrorRef2' (aka '__CFErrorRef *') into ARC}} \
+ // expected-warning {{'CFErrorRef2' (aka '__CFErrorRef *') bridges to NSError, not 'MyError'}}
(void)static_cast<NSUColor *>(cf2); // expected-error {{cast of C pointer type 'CFUColor2Ref' (aka '__CFUPrimeColor *') to Objective-C pointer type 'NSUColor *' requires a bridged cast}} \
// expected-note {{use __bridge with C-style cast to convert directly (no change in ownership)}} \
// expected-note {{use __bridge_transfer with C-style cast to transfer ownership of a +1 'CFUColor2Ref' (aka '__CFUPrimeColor *') into ARC}}
diff --git a/test/SemaTemplate/dependent-type-identity.cpp b/test/SemaTemplate/dependent-type-identity.cpp
index 5b9da5d..6b23a38 100644
--- a/test/SemaTemplate/dependent-type-identity.cpp
+++ b/test/SemaTemplate/dependent-type-identity.cpp
@@ -111,7 +111,9 @@
void A<T>::f(int x) { x = 0; }
template<typename T>
- void A<T>::g(const int x) { x = 0; } // expected-error {{not assignable}}
+ void A<T>::g(const int x) { // expected-note {{declared const here}}
+ x = 0; // expected-error {{cannot assign to variable 'x'}}
+ }
template<typename T>
void A<T>::h(T) {} // FIXME: Should reject this. Type is different from prior decl if T is an array type.
diff --git a/test/SemaTemplate/friend.cpp b/test/SemaTemplate/friend.cpp
index e78a067..ef1aed5 100644
--- a/test/SemaTemplate/friend.cpp
+++ b/test/SemaTemplate/friend.cpp
@@ -31,3 +31,19 @@
friend class f1; // expected-error{{'friend' used outside of class}}
}
}
+
+namespace friend_redecl_inline {
+// We had a bug where instantiating the foo friend declaration would check the
+// defined-ness of the most recent decl while checking if the canonical decl was
+// inlined.
+void foo();
+void bar();
+template <typename T>
+class C {
+ friend void foo();
+ friend inline void bar();
+};
+inline void foo() {}
+inline void bar() {}
+C<int> c;
+}
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
index 90b2225..b2b2f6a 100644
--- a/tools/CMakeLists.txt
+++ b/tools/CMakeLists.txt
@@ -2,6 +2,7 @@
add_subdirectory(driver)
add_subdirectory(clang-format)
add_subdirectory(clang-format-vs)
+add_subdirectory(clang-fuzzer)
add_subdirectory(c-index-test)
add_subdirectory(libclang)
diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c
index 56e4101..56f39c2 100644
--- a/tools/c-index-test/c-index-test.c
+++ b/tools/c-index-test/c-index-test.c
@@ -1250,6 +1250,12 @@
clang_disposeString(TypeKindSpelling);
}
+static enum CXVisitorResult FieldVisitor(CXCursor C,
+ CXClientData client_data) {
+ (*(int *) client_data)+=1;
+ return CXVisit_Continue;
+}
+
static enum CXChildVisitResult PrintType(CXCursor cursor, CXCursor p,
CXClientData d) {
if (!clang_isInvalid(clang_getCursorKind(cursor))) {
@@ -1320,6 +1326,22 @@
PrintTypeAndTypeKind(PT, " [pointeetype=%s] [pointeekind=%s]");
}
}
+ /* Print the number of fields if they exist. */
+ {
+ int numFields = 0;
+ if (clang_Type_visitFields(T, FieldVisitor, &numFields)){
+ if (numFields != 0) {
+ printf(" [nbFields=%d]", numFields);
+ }
+ /* Print if it is an anonymous record. */
+ {
+ unsigned isAnon = clang_Cursor_isAnonymous(cursor);
+ if (isAnon != 0) {
+ printf(" [isAnon=%d]", isAnon);
+ }
+ }
+ }
+ }
printf("\n");
}
@@ -1353,28 +1375,29 @@
{
CXString FieldSpelling = clang_getCursorSpelling(cursor);
const char *FieldName = clang_getCString(FieldSpelling);
- /* recurse to get the root anonymous record parent */
- CXCursor Parent, Root;
+ /* recurse to get the first parent record that is not anonymous. */
+ CXCursor Parent, Record;
+ unsigned RecordIsAnonymous = 0;
if (clang_getCursorKind(cursor) == CXCursor_FieldDecl) {
- CXString RootParentSpelling;
- const char *RootParentName = 0;
- Parent = p;
+ Record = Parent = p;
do {
- if (RootParentName != 0)
- clang_disposeString(RootParentSpelling);
-
- Root = Parent;
- RootParentSpelling = clang_getCursorSpelling(Root);
- RootParentName = clang_getCString(RootParentSpelling);
- Parent = clang_getCursorSemanticParent(Root);
- } while (clang_getCursorType(Parent).kind == CXType_Record &&
- !strcmp(RootParentName, ""));
- clang_disposeString(RootParentSpelling);
- /* if RootParentName is "", record is anonymous. */
+ Record = Parent;
+ Parent = clang_getCursorSemanticParent(Record);
+ RecordIsAnonymous = clang_Cursor_isAnonymous(Record);
+ /* Recurse as long as the parent is a CXType_Record and the Record
+ is anonymous */
+ } while ( clang_getCursorType(Parent).kind == CXType_Record &&
+ RecordIsAnonymous > 0);
{
- long long Offset = clang_Type_getOffsetOf(clang_getCursorType(Root),
+ long long Offset = clang_Type_getOffsetOf(clang_getCursorType(Record),
FieldName);
- printf(" [offsetof=%lld]", Offset);
+ long long Offset2 = clang_Cursor_getOffsetOfField(cursor);
+ if (Offset == Offset2){
+ printf(" [offsetof=%lld]", Offset);
+ } else {
+ /* Offsets will be different in anonymous records. */
+ printf(" [offsetof=%lld/%lld]", Offset, Offset2);
+ }
}
}
clang_disposeString(FieldSpelling);
diff --git a/tools/clang-format/clang-format.py b/tools/clang-format/clang-format.py
index a79205a..b07160e 100644
--- a/tools/clang-format/clang-format.py
+++ b/tools/clang-format/clang-format.py
@@ -34,6 +34,8 @@
# a '.clang-format' or '_clang-format' file to indicate the style that should be
# used.
style = 'file'
+if vim.eval('exists("g:clang_format_fallback_style")') == "1":
+ fallback_style = vim.eval('g:clang_format_fallback_style')
def main():
# Get the current text.
@@ -58,6 +60,8 @@
# Call formatter.
command = [binary, '-lines', lines, '-style', style, '-cursor', str(cursor)]
+ if fallback_style:
+ command.extend(['-fallback-style', fallback_style])
if vim.current.buffer.name:
command.extend(['-assume-filename', vim.current.buffer.name])
p = subprocess.Popen(command,
diff --git a/tools/clang-fuzzer/CMakeLists.txt b/tools/clang-fuzzer/CMakeLists.txt
new file mode 100644
index 0000000..a6c19e1
--- /dev/null
+++ b/tools/clang-fuzzer/CMakeLists.txt
@@ -0,0 +1,20 @@
+if( LLVM_USE_SANITIZE_COVERAGE )
+ set(LLVM_LINK_COMPONENTS support)
+
+ add_clang_executable(clang-fuzzer
+ EXCLUDE_FROM_ALL
+ ClangFuzzer.cpp
+ )
+
+ target_link_libraries(clang-fuzzer
+ ${CLANG_FORMAT_LIB_DEPS}
+ clangAST
+ clangBasic
+ clangDriver
+ clangFrontend
+ clangRewriteFrontend
+ clangStaticAnalyzerFrontend
+ clangTooling
+ LLVMFuzzer
+ )
+endif()
\ No newline at end of file
diff --git a/tools/clang-fuzzer/ClangFuzzer.cpp b/tools/clang-fuzzer/ClangFuzzer.cpp
new file mode 100644
index 0000000..b245319
--- /dev/null
+++ b/tools/clang-fuzzer/ClangFuzzer.cpp
@@ -0,0 +1,43 @@
+//===-- ClangFuzzer.cpp - Fuzz Clang --------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file implements a function that runs Clang on a single
+/// input. This function is then linked into the Fuzzer library.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/Tooling.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "llvm/Option/Option.h"
+
+using namespace clang;
+
+extern "C" void TestOneInput(uint8_t *data, size_t size) {
+ std::string s((const char *)data, size);
+ llvm::opt::ArgStringList CC1Args;
+ CC1Args.push_back("-cc1");
+ CC1Args.push_back("test.cc");
+ llvm::IntrusiveRefCntPtr<FileManager> Files(
+ new FileManager(FileSystemOptions()));
+ IgnoringDiagConsumer Diags;
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+ DiagnosticsEngine Diagnostics(
+ IntrusiveRefCntPtr<clang::DiagnosticIDs>(new DiagnosticIDs()), &*DiagOpts,
+ &Diags, false);
+ std::unique_ptr<clang::CompilerInvocation> Invocation(
+ tooling::newInvocation(&Diagnostics, CC1Args));
+ std::unique_ptr<llvm::MemoryBuffer> Input =
+ llvm::MemoryBuffer::getMemBuffer(s);
+ Invocation->getPreprocessorOpts().addRemappedFile("test.cc", Input.release());
+ std::unique_ptr<tooling::ToolAction> action(
+ tooling::newFrontendActionFactory<clang::SyntaxOnlyAction>());
+ action->runInvocation(Invocation.release(), Files.get(), &Diags);
+}
diff --git a/tools/driver/cc1as_main.cpp b/tools/driver/cc1as_main.cpp
index e528b02..6feffa8 100644
--- a/tools/driver/cc1as_main.cpp
+++ b/tools/driver/cc1as_main.cpp
@@ -19,6 +19,7 @@
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Frontend/Utils.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Triple.h"
#include "llvm/IR/DataLayout.h"
@@ -254,9 +255,9 @@
return Success;
}
-static formatted_raw_ostream *GetOutputStream(AssemblerInvocation &Opts,
- DiagnosticsEngine &Diags,
- bool Binary) {
+static std::unique_ptr<raw_fd_ostream>
+getOutputStream(AssemblerInvocation &Opts, DiagnosticsEngine &Diags,
+ bool Binary) {
if (Opts.OutputPath.empty())
Opts.OutputPath = "-";
@@ -266,16 +267,15 @@
sys::RemoveFileOnSignal(Opts.OutputPath);
std::error_code EC;
- raw_fd_ostream *Out = new raw_fd_ostream(
+ auto Out = llvm::make_unique<raw_fd_ostream>(
Opts.OutputPath, EC, (Binary ? sys::fs::F_None : sys::fs::F_Text));
if (EC) {
Diags.Report(diag::err_fe_unable_to_open_output) << Opts.OutputPath
<< EC.message();
- delete Out;
return nullptr;
}
- return new formatted_raw_ostream(*Out, formatted_raw_ostream::DELETE_STREAM);
+ return Out;
}
static bool ExecuteAssembler(AssemblerInvocation &Opts,
@@ -315,9 +315,8 @@
MAI->setCompressDebugSections(true);
bool IsBinary = Opts.OutputType == AssemblerInvocation::FT_Obj;
- std::unique_ptr<formatted_raw_ostream> Out(
- GetOutputStream(Opts, Diags, IsBinary));
- if (!Out)
+ std::unique_ptr<raw_fd_ostream> FDOS = getOutputStream(Opts, Diags, IsBinary);
+ if (!FDOS)
return true;
// FIXME: This is not pretty. MCContext has a ptr to MCObjectFileInfo and
@@ -356,26 +355,33 @@
std::unique_ptr<MCSubtargetInfo> STI(
TheTarget->createMCSubtargetInfo(Opts.Triple, Opts.CPU, FS));
+ raw_pwrite_stream *Out = FDOS.get();
+ std::unique_ptr<buffer_ostream> BOS;
+
// FIXME: There is a bit of code duplication with addPassesToEmitFile.
if (Opts.OutputType == AssemblerInvocation::FT_Asm) {
- MCInstPrinter *IP =
- TheTarget->createMCInstPrinter(Opts.OutputAsmVariant, *MAI, *MCII, *MRI,
- *STI);
+ MCInstPrinter *IP = TheTarget->createMCInstPrinter(
+ llvm::Triple(Opts.Triple), Opts.OutputAsmVariant, *MAI, *MCII, *MRI);
MCCodeEmitter *CE = nullptr;
MCAsmBackend *MAB = nullptr;
if (Opts.ShowEncoding) {
CE = TheTarget->createMCCodeEmitter(*MCII, *MRI, Ctx);
MAB = TheTarget->createMCAsmBackend(*MRI, Opts.Triple, Opts.CPU);
}
- Str.reset(TheTarget->createAsmStreamer(Ctx, *Out, /*asmverbose*/true,
- /*useDwarfDirectory*/ true,
- IP, CE, MAB,
- Opts.ShowInst));
+ auto FOut = llvm::make_unique<formatted_raw_ostream>(*Out);
+ Str.reset(TheTarget->createAsmStreamer(
+ Ctx, std::move(FOut), /*asmverbose*/ true,
+ /*useDwarfDirectory*/ true, IP, CE, MAB, Opts.ShowInst));
} else if (Opts.OutputType == AssemblerInvocation::FT_Null) {
Str.reset(createNullStreamer(Ctx));
} else {
assert(Opts.OutputType == AssemblerInvocation::FT_Obj &&
"Invalid file type!");
+ if (!FDOS->supportsSeeking()) {
+ BOS = make_unique<buffer_ostream>(*FDOS);
+ Out = BOS.get();
+ }
+
MCCodeEmitter *CE = TheTarget->createMCCodeEmitter(*MCII, *MRI, Ctx);
MCAsmBackend *MAB = TheTarget->createMCAsmBackend(*MRI, Opts.Triple,
Opts.CPU);
@@ -404,7 +410,8 @@
}
// Close the output stream early.
- Out.reset();
+ BOS.reset();
+ FDOS.reset();
// Delete output file if there were errors.
if (Failed && Opts.OutputPath != "-")
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index b98cf5a..5a7a9cf 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -2022,12 +2022,33 @@
void OMPClauseEnqueue::VisitOMPLastprivateClause(
const OMPLastprivateClause *C) {
VisitOMPClauseList(C);
+ for (auto *E : C->private_copies()) {
+ Visitor->AddStmt(E);
+ }
+ for (auto *E : C->source_exprs()) {
+ Visitor->AddStmt(E);
+ }
+ for (auto *E : C->destination_exprs()) {
+ Visitor->AddStmt(E);
+ }
+ for (auto *E : C->assignment_ops()) {
+ Visitor->AddStmt(E);
+ }
}
void OMPClauseEnqueue::VisitOMPSharedClause(const OMPSharedClause *C) {
VisitOMPClauseList(C);
}
void OMPClauseEnqueue::VisitOMPReductionClause(const OMPReductionClause *C) {
VisitOMPClauseList(C);
+ for (auto *E : C->lhs_exprs()) {
+ Visitor->AddStmt(E);
+ }
+ for (auto *E : C->rhs_exprs()) {
+ Visitor->AddStmt(E);
+ }
+ for (auto *E : C->reduction_ops()) {
+ Visitor->AddStmt(E);
+ }
}
void OMPClauseEnqueue::VisitOMPLinearClause(const OMPLinearClause *C) {
VisitOMPClauseList(C);
@@ -2049,6 +2070,15 @@
}
void OMPClauseEnqueue::VisitOMPCopyinClause(const OMPCopyinClause *C) {
VisitOMPClauseList(C);
+ for (auto *E : C->source_exprs()) {
+ Visitor->AddStmt(E);
+ }
+ for (auto *E : C->destination_exprs()) {
+ Visitor->AddStmt(E);
+ }
+ for (auto *E : C->assignment_ops()) {
+ Visitor->AddStmt(E);
+ }
}
void
OMPClauseEnqueue::VisitOMPCopyprivateClause(const OMPCopyprivateClause *C) {
diff --git a/tools/libclang/CIndexCodeCompletion.cpp b/tools/libclang/CIndexCodeCompletion.cpp
index 55f4131..ca167e8 100644
--- a/tools/libclang/CIndexCodeCompletion.cpp
+++ b/tools/libclang/CIndexCodeCompletion.cpp
@@ -533,7 +533,7 @@
: CodeCompleteConsumer(Opts, false),
AllocatedResults(Results), CCTUInfo(Results.CodeCompletionAllocator),
TU(TranslationUnit) { }
- ~CaptureCompletionResults() { Finish(); }
+ ~CaptureCompletionResults() override { Finish(); }
void ProcessCodeCompleteResults(Sema &S,
CodeCompletionContext Context,
diff --git a/tools/libclang/CIndexDiagnostic.cpp b/tools/libclang/CIndexDiagnostic.cpp
index 4d646f0..9ba36a6 100644
--- a/tools/libclang/CIndexDiagnostic.cpp
+++ b/tools/libclang/CIndexDiagnostic.cpp
@@ -48,7 +48,7 @@
: CXDiagnosticImpl(CustomNoteDiagnosticKind),
Message(Msg), Loc(L) {}
- virtual ~CXDiagnosticCustomNoteImpl() {}
+ ~CXDiagnosticCustomNoteImpl() override {}
CXDiagnosticSeverity getSeverity() const override {
return CXDiagnostic_Note;
@@ -91,8 +91,8 @@
CXDiagnosticSetImpl *mainSet)
: DiagnosticNoteRenderer(LangOpts, DiagOpts),
CurrentSet(mainSet), MainSet(mainSet) {}
-
- virtual ~CXDiagnosticRenderer() {}
+
+ ~CXDiagnosticRenderer() override {}
void beginDiagnostic(DiagOrStoredDiag D,
DiagnosticsEngine::Level Level) override {
diff --git a/tools/libclang/CIndexDiagnostic.h b/tools/libclang/CIndexDiagnostic.h
index 4347fb7..9f40698 100644
--- a/tools/libclang/CIndexDiagnostic.h
+++ b/tools/libclang/CIndexDiagnostic.h
@@ -116,9 +116,9 @@
const LangOptions &LangOpts)
: CXDiagnosticImpl(StoredDiagnosticKind),
Diag(Diag), LangOpts(LangOpts) { }
-
- virtual ~CXStoredDiagnostic() {}
-
+
+ ~CXStoredDiagnostic() override {}
+
/// \brief Return the severity of the diagnostic.
CXDiagnosticSeverity getSeverity() const override;
diff --git a/tools/libclang/CXLoadedDiagnostic.cpp b/tools/libclang/CXLoadedDiagnostic.cpp
index 9bc2369..754ad55 100644
--- a/tools/libclang/CXLoadedDiagnostic.cpp
+++ b/tools/libclang/CXLoadedDiagnostic.cpp
@@ -37,7 +37,7 @@
class CXLoadedDiagnosticSetImpl : public CXDiagnosticSetImpl {
public:
CXLoadedDiagnosticSetImpl() : CXDiagnosticSetImpl(true), FakeFiles(FO) {}
- virtual ~CXLoadedDiagnosticSetImpl() {}
+ ~CXLoadedDiagnosticSetImpl() override {}
llvm::BumpPtrAllocator Alloc;
Strings Categories;
diff --git a/tools/libclang/CXLoadedDiagnostic.h b/tools/libclang/CXLoadedDiagnostic.h
index 54261be..d5006a4 100644
--- a/tools/libclang/CXLoadedDiagnostic.h
+++ b/tools/libclang/CXLoadedDiagnostic.h
@@ -26,8 +26,8 @@
CXLoadedDiagnostic() : CXDiagnosticImpl(LoadedDiagnosticKind),
severity(0), category(0) {}
- virtual ~CXLoadedDiagnostic();
-
+ ~CXLoadedDiagnostic() override;
+
/// \brief Return the severity of the diagnostic.
CXDiagnosticSeverity getSeverity() const override;
diff --git a/tools/libclang/CXType.cpp b/tools/libclang/CXType.cpp
index 942dad2..015dd6e 100644
--- a/tools/libclang/CXType.cpp
+++ b/tools/libclang/CXType.cpp
@@ -775,13 +775,12 @@
return 0;
}
-long long clang_Type_getOffsetOf(CXType PT, const char *S) {
- // check that PT is not incomplete/dependent
- CXCursor PC = clang_getTypeDeclaration(PT);
+static long long validateFieldParentType(CXCursor PC, CXType PT){
if (clang_isInvalid(PC.kind))
return CXTypeLayoutError_Invalid;
const RecordDecl *RD =
dyn_cast_or_null<RecordDecl>(cxcursor::getCursorDecl(PC));
+ // validate parent declaration
if (!RD || RD->isInvalidDecl())
return CXTypeLayoutError_Invalid;
RD = RD->getDefinition();
@@ -789,6 +788,7 @@
return CXTypeLayoutError_Incomplete;
if (RD->isInvalidDecl())
return CXTypeLayoutError_Invalid;
+ // validate parent type
QualType RT = GetQualType(PT);
if (RT->isIncompleteType())
return CXTypeLayoutError_Incomplete;
@@ -798,12 +798,25 @@
long long Error = visitRecordForValidation(RD);
if (Error < 0)
return Error;
+ return 0;
+}
+
+long long clang_Type_getOffsetOf(CXType PT, const char *S) {
+ // check that PT is not incomplete/dependent
+ CXCursor PC = clang_getTypeDeclaration(PT);
+ long long Error = validateFieldParentType(PC,PT);
+ if (Error < 0)
+ return Error;
if (!S)
return CXTypeLayoutError_InvalidFieldName;
// lookup field
ASTContext &Ctx = cxtu::getASTUnit(GetTU(PT))->getASTContext();
IdentifierInfo *II = &Ctx.Idents.get(S);
DeclarationName FieldName(II);
+ const RecordDecl *RD =
+ dyn_cast_or_null<RecordDecl>(cxcursor::getCursorDecl(PC));
+ // verified in validateFieldParentType
+ RD = RD->getDefinition();
RecordDecl::lookup_result Res = RD->lookup(FieldName);
// If a field of the parent record is incomplete, lookup will fail.
// and we would return InvalidFieldName instead of Incomplete.
@@ -819,6 +832,25 @@
return CXTypeLayoutError_InvalidFieldName;
}
+long long clang_Cursor_getOffsetOfField(CXCursor C) {
+ if (clang_isDeclaration(C.kind)) {
+ // we need to validate the parent type
+ CXCursor PC = clang_getCursorSemanticParent(C);
+ CXType PT = clang_getCursorType(PC);
+ long long Error = validateFieldParentType(PC,PT);
+ if (Error < 0)
+ return Error;
+ // proceed with the offset calculation
+ const Decl *D = cxcursor::getCursorDecl(C);
+ ASTContext &Ctx = cxcursor::getCursorContext(C);
+ if (const FieldDecl *FD = dyn_cast_or_null<FieldDecl>(D))
+ return Ctx.getFieldOffset(FD);
+ if (const IndirectFieldDecl *IFD = dyn_cast_or_null<IndirectFieldDecl>(D))
+ return Ctx.getFieldOffset(IFD);
+ }
+ return -1;
+}
+
enum CXRefQualifierKind clang_Type_getCXXRefQualifier(CXType T) {
QualType QT = GetQualType(T);
if (QT.isNull())
@@ -908,4 +940,41 @@
return MakeCXType(A.getAsType(), GetTU(CT));
}
+unsigned clang_Type_visitFields(CXType PT,
+ CXFieldVisitor visitor,
+ CXClientData client_data){
+ CXCursor PC = clang_getTypeDeclaration(PT);
+ if (clang_isInvalid(PC.kind))
+ return false;
+ const RecordDecl *RD =
+ dyn_cast_or_null<RecordDecl>(cxcursor::getCursorDecl(PC));
+ if (!RD || RD->isInvalidDecl())
+ return false;
+ RD = RD->getDefinition();
+ if (!RD || RD->isInvalidDecl())
+ return false;
+
+ for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();
+ I != E; ++I){
+ const FieldDecl *FD = dyn_cast_or_null<FieldDecl>((*I));
+ // Callback to the client.
+ switch (visitor(cxcursor::MakeCXCursor(FD, GetTU(PT)), client_data)){
+ case CXVisit_Break:
+ return true;
+ case CXVisit_Continue:
+ break;
+ }
+ }
+ return true;
+}
+
+unsigned clang_Cursor_isAnonymous(CXCursor C){
+ if (!clang_isDeclaration(C.kind))
+ return 0;
+ const Decl *D = cxcursor::getCursorDecl(C);
+ if (const RecordDecl *FD = dyn_cast_or_null<RecordDecl>(D))
+ return FD->isAnonymousStructOrUnion();
+ return 0;
+}
+
} // end: extern "C"
diff --git a/tools/libclang/libclang.exports b/tools/libclang/libclang.exports
index fa2c0e7..f78f998 100644
--- a/tools/libclang/libclang.exports
+++ b/tools/libclang/libclang.exports
@@ -21,9 +21,11 @@
clang_Cursor_getObjCDeclQualifiers
clang_Cursor_getObjCPropertyAttributes
clang_Cursor_getObjCSelectorIndex
+clang_Cursor_getOffsetOfField
clang_Cursor_getSpellingNameRange
clang_Cursor_getTranslationUnit
clang_Cursor_getReceiverType
+clang_Cursor_isAnonymous
clang_Cursor_isBitField
clang_Cursor_isDynamicCall
clang_Cursor_isNull
@@ -77,6 +79,7 @@
clang_Type_getNumTemplateArguments
clang_Type_getTemplateArgumentAsType
clang_Type_getCXXRefQualifier
+clang_Type_visitFields
clang_VerbatimBlockLineComment_getText
clang_VerbatimLineComment_getText
clang_HTMLTagComment_getAsString
diff --git a/tools/scan-build/ccc-analyzer b/tools/scan-build/ccc-analyzer
index aa02653..4549b29 100755
--- a/tools/scan-build/ccc-analyzer
+++ b/tools/scan-build/ccc-analyzer
@@ -492,6 +492,11 @@
my $Arg = $ARGV[$i];
my ($ArgKey) = split /=/,$Arg,2;
+ # Be friendly to "" in the argument list.
+ if (!defined($ArgKey)) {
+ next;
+ }
+
# Modes ccc-analyzer supports
if ($Arg =~ /^-(E|MM?)$/) { $Action = 'preprocess'; }
elsif ($Arg eq '-c') { $Action = 'compile'; }
diff --git a/unittests/AST/DeclPrinterTest.cpp b/unittests/AST/DeclPrinterTest.cpp
index 9f179c4..070b4da 100644
--- a/unittests/AST/DeclPrinterTest.cpp
+++ b/unittests/AST/DeclPrinterTest.cpp
@@ -44,7 +44,7 @@
public:
PrintMatch() : NumFoundDecls(0) {}
- virtual void run(const MatchFinder::MatchResult &Result) {
+ void run(const MatchFinder::MatchResult &Result) override {
const Decl *D = Result.Nodes.getDeclAs<Decl>("id");
if (!D || D->isImplicit())
return;
diff --git a/unittests/AST/ExternalASTSourceTest.cpp b/unittests/AST/ExternalASTSourceTest.cpp
index 0cfde74..4f42dcf 100644
--- a/unittests/AST/ExternalASTSourceTest.cpp
+++ b/unittests/AST/ExternalASTSourceTest.cpp
@@ -28,15 +28,15 @@
TestFrontendAction(ExternalASTSource *Source) : Source(Source) {}
private:
- virtual void ExecuteAction() {
+ void ExecuteAction() override {
getCompilerInstance().getASTContext().setExternalSource(Source);
getCompilerInstance().getASTContext().getTranslationUnitDecl()
->setHasExternalVisibleStorage();
return ASTFrontendAction::ExecuteAction();
}
- virtual std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) {
+ std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) override {
return llvm::make_unique<ASTConsumer>();
}
@@ -67,8 +67,8 @@
struct TestSource : ExternalASTSource {
TestSource(unsigned &Calls) : Calls(Calls) {}
- bool FindExternalVisibleDeclsByName(const DeclContext*,
- DeclarationName Name) {
+ bool FindExternalVisibleDeclsByName(const DeclContext *,
+ DeclarationName Name) override {
if (Name.getAsString() == "j")
++Calls;
return false;
diff --git a/unittests/AST/MatchVerifier.h b/unittests/AST/MatchVerifier.h
index e659391..3193247 100644
--- a/unittests/AST/MatchVerifier.h
+++ b/unittests/AST/MatchVerifier.h
@@ -63,7 +63,7 @@
Language L);
protected:
- virtual void run(const MatchFinder::MatchResult &Result);
+ void run(const MatchFinder::MatchResult &Result) override;
virtual void verify(const MatchFinder::MatchResult &Result,
const NodeType &Node) {}
@@ -166,7 +166,8 @@
}
protected:
- void verify(const MatchFinder::MatchResult &Result, const NodeType &Node) {
+ void verify(const MatchFinder::MatchResult &Result,
+ const NodeType &Node) override {
SourceLocation Loc = getLocation(Node);
unsigned Line = Result.SourceManager->getSpellingLineNumber(Loc);
unsigned Column = Result.SourceManager->getSpellingColumnNumber(Loc);
@@ -205,7 +206,8 @@
}
protected:
- void verify(const MatchFinder::MatchResult &Result, const NodeType &Node) {
+ void verify(const MatchFinder::MatchResult &Result,
+ const NodeType &Node) override {
SourceRange R = getRange(Node);
SourceLocation Begin = R.getBegin();
SourceLocation End = R.getEnd();
@@ -244,7 +246,7 @@
protected:
void verify(const MatchFinder::MatchResult &Result,
- const ast_type_traits::DynTypedNode &Node) {
+ const ast_type_traits::DynTypedNode &Node) override {
std::string DumpStr;
llvm::raw_string_ostream Dump(DumpStr);
Node.dump(Dump, *Result.SourceManager);
@@ -271,7 +273,7 @@
protected:
void verify(const MatchFinder::MatchResult &Result,
- const ast_type_traits::DynTypedNode &Node) {
+ const ast_type_traits::DynTypedNode &Node) override {
std::string PrintStr;
llvm::raw_string_ostream Print(PrintStr);
Node.print(Print, Result.Context->getPrintingPolicy());
diff --git a/unittests/AST/NamedDeclPrinterTest.cpp b/unittests/AST/NamedDeclPrinterTest.cpp
index f8fb984..cf97a0a 100644
--- a/unittests/AST/NamedDeclPrinterTest.cpp
+++ b/unittests/AST/NamedDeclPrinterTest.cpp
@@ -37,7 +37,7 @@
explicit PrintMatch(bool suppressUnwrittenScope)
: NumFoundDecls(0), SuppressUnwrittenScope(suppressUnwrittenScope) {}
- virtual void run(const MatchFinder::MatchResult &Result) {
+ void run(const MatchFinder::MatchResult &Result) override {
const NamedDecl *ND = Result.Nodes.getNodeAs<NamedDecl>("id");
if (!ND)
return;
diff --git a/unittests/AST/SourceLocationTest.cpp b/unittests/AST/SourceLocationTest.cpp
index c1f7b18..a3fc953 100644
--- a/unittests/AST/SourceLocationTest.cpp
+++ b/unittests/AST/SourceLocationTest.cpp
@@ -60,7 +60,7 @@
class LabelDeclRangeVerifier : public RangeVerifier<LabelStmt> {
protected:
- virtual SourceRange getRange(const LabelStmt &Node) {
+ SourceRange getRange(const LabelStmt &Node) override {
return Node.getDecl()->getSourceRange();
}
};
@@ -110,8 +110,8 @@
}
class MemberExprArrowLocVerifier : public RangeVerifier<MemberExpr> {
-protected:
- virtual SourceRange getRange(const MemberExpr &Node) {
+protected:
+ SourceRange getRange(const MemberExpr &Node) override {
return Node.getOperatorLoc();
}
};
@@ -201,7 +201,7 @@
class TemplateAngleBracketLocRangeVerifier : public RangeVerifier<TypeLoc> {
protected:
- virtual SourceRange getRange(const TypeLoc &Node) {
+ SourceRange getRange(const TypeLoc &Node) override {
TemplateSpecializationTypeLoc T =
Node.getUnqualifiedLoc().castAs<TemplateSpecializationTypeLoc>();
assert(!T.isNull());
@@ -226,7 +226,7 @@
class UnaryTransformTypeLocParensRangeVerifier : public RangeVerifier<TypeLoc> {
protected:
- virtual SourceRange getRange(const TypeLoc &Node) {
+ SourceRange getRange(const TypeLoc &Node) override {
UnaryTransformTypeLoc T =
Node.getUnqualifiedLoc().castAs<UnaryTransformTypeLoc>();
assert(!T.isNull());
diff --git a/unittests/AST/StmtPrinterTest.cpp b/unittests/AST/StmtPrinterTest.cpp
index 541fb3d..b1fd2c1 100644
--- a/unittests/AST/StmtPrinterTest.cpp
+++ b/unittests/AST/StmtPrinterTest.cpp
@@ -44,7 +44,7 @@
public:
PrintMatch() : NumFoundStmts(0) {}
- virtual void run(const MatchFinder::MatchResult &Result) {
+ void run(const MatchFinder::MatchResult &Result) override {
const Stmt *S = Result.Nodes.getStmtAs<Stmt>("id");
if (!S)
return;
diff --git a/unittests/ASTMatchers/ASTMatchersTest.cpp b/unittests/ASTMatchers/ASTMatchersTest.cpp
index 7edec96..4b0580a 100644
--- a/unittests/ASTMatchers/ASTMatchersTest.cpp
+++ b/unittests/ASTMatchers/ASTMatchersTest.cpp
@@ -747,12 +747,12 @@
Name.clear();
}
- ~VerifyIdIsBoundTo() {
+ ~VerifyIdIsBoundTo() override {
EXPECT_EQ(0, Count);
EXPECT_EQ("", Name);
}
- virtual bool run(const BoundNodes *Nodes) override {
+ bool run(const BoundNodes *Nodes) override {
const BoundNodes::IDToNodeMap &M = Nodes->getMap();
if (Nodes->getNodeAs<T>(Id)) {
++Count;
@@ -774,7 +774,7 @@
return false;
}
- virtual bool run(const BoundNodes *Nodes, ASTContext *Context) override {
+ bool run(const BoundNodes *Nodes, ASTContext *Context) override {
return run(Nodes);
}
@@ -4379,9 +4379,9 @@
: Id(Id), InnerMatcher(InnerMatcher), InnerId(InnerId) {
}
- virtual bool run(const BoundNodes *Nodes) { return false; }
+ bool run(const BoundNodes *Nodes) override { return false; }
- virtual bool run(const BoundNodes *Nodes, ASTContext *Context) {
+ bool run(const BoundNodes *Nodes, ASTContext *Context) override {
const T *Node = Nodes->getNodeAs<T>(Id);
return selectFirst<T>(InnerId, match(InnerMatcher, *Node, *Context)) !=
nullptr;
@@ -4430,9 +4430,9 @@
template <typename T>
class VerifyAncestorHasChildIsEqual : public BoundNodesCallback {
public:
- virtual bool run(const BoundNodes *Nodes) { return false; }
+ bool run(const BoundNodes *Nodes) override { return false; }
- virtual bool run(const BoundNodes *Nodes, ASTContext *Context) {
+ bool run(const BoundNodes *Nodes, ASTContext *Context) override {
const T *Node = Nodes->getNodeAs<T>("");
return verify(*Nodes, *Context, Node);
}
@@ -4488,12 +4488,10 @@
class VerifyStartOfTranslationUnit : public MatchFinder::MatchCallback {
public:
VerifyStartOfTranslationUnit() : Called(false) {}
- virtual void run(const MatchFinder::MatchResult &Result) {
+ void run(const MatchFinder::MatchResult &Result) override {
EXPECT_TRUE(Called);
}
- virtual void onStartOfTranslationUnit() {
- Called = true;
- }
+ void onStartOfTranslationUnit() override { Called = true; }
bool Called;
};
@@ -4516,12 +4514,10 @@
class VerifyEndOfTranslationUnit : public MatchFinder::MatchCallback {
public:
VerifyEndOfTranslationUnit() : Called(false) {}
- virtual void run(const MatchFinder::MatchResult &Result) {
+ void run(const MatchFinder::MatchResult &Result) override {
EXPECT_FALSE(Called);
}
- virtual void onEndOfTranslationUnit() {
- Called = true;
- }
+ void onEndOfTranslationUnit() override { Called = true; }
bool Called;
};
diff --git a/unittests/ASTMatchers/ASTMatchersTest.h b/unittests/ASTMatchers/ASTMatchersTest.h
index 4befe4a..e555e63 100644
--- a/unittests/ASTMatchers/ASTMatchersTest.h
+++ b/unittests/ASTMatchers/ASTMatchersTest.h
@@ -40,7 +40,7 @@
VerifyMatch(BoundNodesCallback *FindResultVerifier, bool *Verified)
: Verified(Verified), FindResultReviewer(FindResultVerifier) {}
- virtual void run(const MatchFinder::MatchResult &Result) override {
+ void run(const MatchFinder::MatchResult &Result) override {
if (FindResultReviewer != nullptr) {
*Verified |= FindResultReviewer->run(&Result.Nodes, Result.Context);
} else {
diff --git a/unittests/ASTMatchers/Dynamic/ParserTest.cpp b/unittests/ASTMatchers/Dynamic/ParserTest.cpp
index 2a9a61b..5e6cadd 100644
--- a/unittests/ASTMatchers/Dynamic/ParserTest.cpp
+++ b/unittests/ASTMatchers/Dynamic/ParserTest.cpp
@@ -23,7 +23,7 @@
class MockSema : public Parser::Sema {
public:
- virtual ~MockSema() {}
+ ~MockSema() override {}
uint64_t expectMatcher(StringRef MatcherName) {
// Optimizations on the matcher framework make simple matchers like
@@ -42,7 +42,8 @@
Errors.push_back(Error.toStringFull());
}
- llvm::Optional<MatcherCtor> lookupMatcherCtor(StringRef MatcherName) {
+ llvm::Optional<MatcherCtor>
+ lookupMatcherCtor(StringRef MatcherName) override {
const ExpectedMatchersTy::value_type *Matcher =
&*ExpectedMatchers.find(MatcherName);
return reinterpret_cast<MatcherCtor>(Matcher);
@@ -52,7 +53,7 @@
const SourceRange &NameRange,
StringRef BindID,
ArrayRef<ParserValue> Args,
- Diagnostics *Error) {
+ Diagnostics *Error) override {
const ExpectedMatchersTy::value_type *Matcher =
reinterpret_cast<const ExpectedMatchersTy::value_type *>(Ctor);
MatcherInfo ToStore = { Matcher->first, NameRange, Args, BindID };
diff --git a/unittests/Basic/SourceManagerTest.cpp b/unittests/Basic/SourceManagerTest.cpp
index 1dda54d..57b87b7 100644
--- a/unittests/Basic/SourceManagerTest.cpp
+++ b/unittests/Basic/SourceManagerTest.cpp
@@ -257,15 +257,15 @@
public:
explicit MacroTracker(std::vector<MacroAction> &Macros) : Macros(Macros) { }
-
- virtual void MacroDefined(const Token &MacroNameTok,
- const MacroDirective *MD) {
+
+ void MacroDefined(const Token &MacroNameTok,
+ const MacroDirective *MD) override {
Macros.push_back(MacroAction(MD->getLocation(),
MacroNameTok.getIdentifierInfo()->getName(),
true));
}
- virtual void MacroExpands(const Token &MacroNameTok, const MacroDirective *MD,
- SourceRange Range, const MacroArgs *Args) {
+ void MacroExpands(const Token &MacroNameTok, const MacroDirective *MD,
+ SourceRange Range, const MacroArgs *Args) override {
Macros.push_back(MacroAction(MacroNameTok.getLocation(),
MacroNameTok.getIdentifierInfo()->getName(),
false));
diff --git a/unittests/Basic/VirtualFileSystemTest.cpp b/unittests/Basic/VirtualFileSystemTest.cpp
index 67beb92..71d2d2b 100644
--- a/unittests/Basic/VirtualFileSystemTest.cpp
+++ b/unittests/Basic/VirtualFileSystemTest.cpp
@@ -521,9 +521,7 @@
public:
int NumDiagnostics;
- void SetUp() {
- NumDiagnostics = 0;
- }
+ void SetUp() override { NumDiagnostics = 0; }
static void CountingDiagHandler(const SMDiagnostic &, void *Context) {
VFSFromYAMLTest *Test = static_cast<VFSFromYAMLTest *>(Context);
diff --git a/unittests/Format/FormatTest.cpp b/unittests/Format/FormatTest.cpp
index 287ece1..9791e2a 100644
--- a/unittests/Format/FormatTest.cpp
+++ b/unittests/Format/FormatTest.cpp
@@ -812,9 +812,11 @@
" some_more_code();\n"
" }\n"
"}");
- verifyFormat("some_code();\n"
+ verifyFormat("{\n"
+ " some_code();\n"
"test_label:\n"
- "some_other_code();");
+ " some_other_code();\n"
+ "}");
}
//===----------------------------------------------------------------------===//
@@ -1895,6 +1897,8 @@
" void f() {}\n"
"public Q_SLOTS:\n"
" void f() {}\n"
+ "signals:\n"
+ " void g();\n"
"};");
}
@@ -2143,6 +2147,12 @@
" int aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa : 1,\n"
" bbbbbbbbbbbbbbbbbbbbbbbbb;\n"
"};");
+ verifyFormat("struct MyStruct {\n"
+ " uchar data;\n"
+ " uchar : 8;\n"
+ " uchar : 8;\n"
+ " uchar other;\n"
+ "};");
}
TEST_F(FormatTest, FormatsNamespaces) {
@@ -3048,35 +3058,38 @@
}
TEST_F(FormatTest, LayoutBlockInsideParens) {
- EXPECT_EQ("functionCall({ int i; });", format(" functionCall ( {int i;} );"));
- EXPECT_EQ("functionCall({\n"
- " int i;\n"
- " int j;\n"
- "});",
- format(" functionCall ( {int i;int j;} );"));
- EXPECT_EQ("functionCall({\n"
- " int i;\n"
- " int j;\n"
- "}, aaaa, bbbb, cccc);",
- format(" functionCall ( {int i;int j;}, aaaa, bbbb, cccc);"));
- EXPECT_EQ("functionCall(\n"
- " {\n"
- " int i;\n"
- " int j;\n"
- " },\n"
- " aaaa, bbbb, // comment\n"
- " cccc);",
- format(" functionCall ( {int i;int j;}, aaaa, bbbb, // comment\n"
- "cccc);"));
- EXPECT_EQ("functionCall(aaaa, bbbb, { int i; });",
- format(" functionCall (aaaa, bbbb, {int i;});"));
- EXPECT_EQ("functionCall(aaaa, bbbb, {\n"
- " int i;\n"
- " int j;\n"
- "});",
- format(" functionCall (aaaa, bbbb, {int i;int j;});"));
- EXPECT_EQ("functionCall(aaaa, bbbb, { int i; });",
- format(" functionCall (aaaa, bbbb, {int i;});"));
+ verifyFormat("functionCall({ int i; });");
+ verifyFormat("functionCall({\n"
+ " int i;\n"
+ " int j;\n"
+ "});");
+ verifyFormat("functionCall({\n"
+ " int i;\n"
+ " int j;\n"
+ "}, aaaa, bbbb, cccc);");
+ verifyFormat("functionA(functionB({\n"
+ " int i;\n"
+ " int j;\n"
+ " }),\n"
+ " aaaa, bbbb, cccc);");
+ verifyFormat("functionCall(\n"
+ " {\n"
+ " int i;\n"
+ " int j;\n"
+ " },\n"
+ " aaaa, bbbb, // comment\n"
+ " cccc);");
+ verifyFormat("functionA(functionB({\n"
+ " int i;\n"
+ " int j;\n"
+ " }),\n"
+ " aaaa, bbbb, // comment\n"
+ " cccc);");
+ verifyFormat("functionCall(aaaa, bbbb, { int i; });");
+ verifyFormat("functionCall(aaaa, bbbb, {\n"
+ " int i;\n"
+ " int j;\n"
+ "});");
verifyFormat(
"Aaa(\n" // FIXME: There shouldn't be a linebreak here.
" {\n"
@@ -4085,7 +4098,7 @@
" aaaaaaaaaaaaaaa->aaaaa().aaaaaaaaaaaaa().aaaaaa();");
verifyFormat(
"aaaaaaa->aaaaaaa->aaaaaaaaaaaaaaaa(\n"
- " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)\n"
" ->aaaaaaaa(aaaaaaaaaaaaaaa);");
verifyFormat(
"aaaaaaaaaaaaaaaaaaa()->aaaaaa(bbbbb)->aaaaaaaaaaaaaaaaaaa( // break\n"
@@ -4094,7 +4107,7 @@
"aaaaaaaaaaaaaaaaaaaaaaa *aaaaaaaaa =\n"
" aaaaaa->aaaaaaaaaaaa()\n"
" ->aaaaaaaaaaaaaaaa(\n"
- " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)\n"
" ->aaaaaaaaaaaaaaaaa();");
verifyGoogleFormat(
"void f() {\n"
@@ -6738,7 +6751,7 @@
"+ (id)init;\n"
"@end");
- verifyGoogleFormat("@interface Foo (HackStuff) <MyProtocol>\n"
+ verifyGoogleFormat("@interface Foo (HackStuff)<MyProtocol>\n"
"+ (id)init;\n"
"@end");
@@ -6780,7 +6793,7 @@
FormatStyle OnePerLine = getGoogleStyle();
OnePerLine.BinPackParameters = false;
- verifyFormat("@interface aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa () <\n"
+ verifyFormat("@interface aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ()<\n"
" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
@@ -6985,6 +6998,11 @@
verifyFormat("return in[42];");
verifyFormat("for (auto v : in[1]) {\n}");
+ verifyFormat("for (int i = 0; i < in[a]; ++i) {\n}");
+ verifyFormat("for (int i = 0; in[a] < i; ++i) {\n}");
+ verifyFormat("for (int i = 0; i < n; ++i, ++in[a]) {\n}");
+ verifyFormat("for (int i = 0; i < n; ++i, in[a]++) {\n}");
+ verifyFormat("for (int i = 0; i < f(in[a]); ++i, in[a]++) {\n}");
verifyFormat("for (id foo in [self getStuffFor:bla]) {\n"
"}");
verifyFormat("[self aaaaa:MACRO(a, b:, c:)];");
diff --git a/unittests/Format/FormatTestJS.cpp b/unittests/Format/FormatTestJS.cpp
index 5707024..695bad5 100644
--- a/unittests/Format/FormatTestJS.cpp
+++ b/unittests/Format/FormatTestJS.cpp
@@ -144,6 +144,35 @@
verifyFormat("x = foo && {a: 123};");
}
+TEST_F(FormatTestJS, MethodsInObjectLiterals) {
+ verifyFormat("var o = {\n"
+ " value: 'test',\n"
+ " get value() { // getter\n"
+ " return this.value;\n"
+ " }\n"
+ "};");
+ verifyFormat("var o = {\n"
+ " value: 'test',\n"
+ " set value(val) { // setter\n"
+ " this.value = val;\n"
+ " }\n"
+ "};");
+ verifyFormat("var o = {\n"
+ " value: 'test',\n"
+ " someMethod(val) { // method\n"
+ " doSomething(this.value + val);\n"
+ " }\n"
+ "};");
+ verifyFormat("var o = {\n"
+ " someMethod(val) { // method\n"
+ " doSomething(this.value + val);\n"
+ " },\n"
+ " someOtherMethod(val) { // method\n"
+ " doSomething(this.value + val);\n"
+ " }\n"
+ "};");
+}
+
TEST_F(FormatTestJS, SpacesInContainerLiterals) {
verifyFormat("var arr = [1, 2, 3];");
verifyFormat("f({a: 1, b: 2, c: 3});");
@@ -167,6 +196,11 @@
"var x = a.b;\n"
"var y = c.d;\n"
"}); // goog.scope");
+ verifyFormat("goog.scope(function() {\n"
+ "// test\n"
+ "var x = 0;\n"
+ "// test\n"
+ "});");
}
TEST_F(FormatTestJS, GoogModules) {
@@ -374,10 +408,9 @@
" body();\n"
" });");
- // FIXME: This is bad, but it used to be formatted correctly by accident.
- verifyFormat("getSomeLongPromise().then(function(value) {\n"
- " body();\n"
- "}).thenCatch(function(error) { body(); });");
+ verifyFormat("getSomeLongPromise()\n"
+ " .then(function(value) { body(); })\n"
+ " .thenCatch(function(error) { body(); });");
}
TEST_F(FormatTestJS, ReturnStatements) {
@@ -511,6 +544,7 @@
verifyFormat("class C {\n private static x: string = 12;\n}");
verifyFormat("class C {\n static x(): string { return 'asd'; }\n}");
verifyFormat("class C extends P implements I {}");
+ verifyFormat("class C extends p.P implements i.I {}");
}
TEST_F(FormatTestJS, MetadataAnnotations) {
@@ -614,6 +648,33 @@
// Two template strings.
verifyFormat("var x = `hello` == `hello`;");
+
+ // Comments in template strings.
+ EXPECT_EQ("var x = `//a`;\n"
+ "var y;",
+ format("var x =\n `//a`;\n"
+ "var y ;"));
+ EXPECT_EQ("var x = `/*a`;\n"
+ "var y;",
+ format("var x =\n `/*a`;\n"
+ "var y;"));
+ // Backticks in a comment - not a template string.
+ EXPECT_EQ("var x = 1 // `/*a`;\n"
+ " ;",
+ format("var x =\n 1 // `/*a`;\n"
+ " ;"));
+ EXPECT_EQ("/* ` */ var x = 1; /* ` */",
+ format("/* ` */ var x\n= 1; /* ` */"));
+ // Comment spans multiple template strings.
+ EXPECT_EQ("var x = `/*a`;\n"
+ "var y = ` */ `;",
+ format("var x =\n `/*a`;\n"
+ "var y =\n ` */ `;"));
+ // Escaped backtick.
+ EXPECT_EQ("var x = ` \\` a`;\n"
+ "var y;",
+ format("var x = ` \\` a`;\n"
+ "var y;"));
}
TEST_F(FormatTestJS, CastSyntax) {
@@ -628,5 +689,17 @@
verifyFormat("class C extends D<E> implements F<G>, H<I> {}");
}
+TEST_F(FormatTestJS, OptionalTypes) {
+ verifyFormat("function x(a?: b, c?, d?) {\n}");
+ verifyFormat("class X {\n"
+ " y?: z;\n"
+ " z?;\n"
+ "}");
+}
+
+TEST_F(FormatTestJS, IndexSignature) {
+ verifyFormat("var x: {[k: string]: v};");
+}
+
} // end namespace tooling
} // end namespace clang
diff --git a/unittests/Format/FormatTestJava.cpp b/unittests/Format/FormatTestJava.cpp
index 6e3f7ef..631a3dc 100644
--- a/unittests/Format/FormatTestJava.cpp
+++ b/unittests/Format/FormatTestJava.cpp
@@ -433,7 +433,7 @@
getStyleWithColumns(40));
verifyFormat("return aaaaaaaaaaaaaaaaaaa()\n"
" .bbbbbbbbbbbbbbbbbbb(\n"
- " ccccccccccccccc)\n"
+ " ccccccccccccccc)\n"
" .ccccccccccccccccccc();",
getStyleWithColumns(40));
}
diff --git a/unittests/Format/FormatTestProto.cpp b/unittests/Format/FormatTestProto.cpp
index 3a2f97e..d55fe8c 100644
--- a/unittests/Format/FormatTestProto.cpp
+++ b/unittests/Format/FormatTestProto.cpp
@@ -94,6 +94,11 @@
" bbbbbbbbbbbbbbbb: BBBBBBBBBB\n"
"}];");
verifyFormat("repeated double value = 1 [(aaaaaaa.aaaaaaaaa) = {\n"
+ " type: \"AAAAAAAAAA\"\n"
+ " is: \"AAAAAAAAAA\"\n"
+ " or: \"BBBBBBBBBB\"\n"
+ "}];");
+ verifyFormat("repeated double value = 1 [(aaaaaaa.aaaaaaaaa) = {\n"
" aaaaaaaaaaaaaaaa: AAAAAAAAAA,\n"
" bbbbbbb: BBBB,\n"
" bbbb: BBB\n"
diff --git a/unittests/Frontend/FrontendActionTest.cpp b/unittests/Frontend/FrontendActionTest.cpp
index 5581c44..90afd77 100644
--- a/unittests/Frontend/FrontendActionTest.cpp
+++ b/unittests/Frontend/FrontendActionTest.cpp
@@ -35,15 +35,16 @@
bool ActOnEndOfTranslationUnit;
std::vector<std::string> decl_names;
- virtual bool BeginSourceFileAction(CompilerInstance &ci, StringRef filename) {
+ bool BeginSourceFileAction(CompilerInstance &ci,
+ StringRef filename) override {
if (EnableIncrementalProcessing)
ci.getPreprocessor().enableIncrementalProcessing();
return ASTFrontendAction::BeginSourceFileAction(ci, filename);
}
- virtual std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) {
+ std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) override {
return llvm::make_unique<Visitor>(CI, ActOnEndOfTranslationUnit,
decl_names);
}
@@ -56,7 +57,7 @@
CI(CI), ActOnEndOfTranslationUnit(ActOnEndOfTranslationUnit),
decl_names_(decl_names) {}
- virtual void HandleTranslationUnit(ASTContext &context) {
+ void HandleTranslationUnit(ASTContext &context) override {
if (ActOnEndOfTranslationUnit) {
CI.getSema().ActOnEndOfTranslationUnit();
}
diff --git a/unittests/Lex/PPCallbacksTest.cpp b/unittests/Lex/PPCallbacksTest.cpp
index bb27bac..da641a7 100644
--- a/unittests/Lex/PPCallbacksTest.cpp
+++ b/unittests/Lex/PPCallbacksTest.cpp
@@ -54,15 +54,11 @@
// Stub to collect data from InclusionDirective callbacks.
class InclusionDirectiveCallbacks : public PPCallbacks {
public:
- void InclusionDirective(SourceLocation HashLoc,
- const Token &IncludeTok,
- StringRef FileName,
- bool IsAngled,
- CharSourceRange FilenameRange,
- const FileEntry *File,
- StringRef SearchPath,
- StringRef RelativePath,
- const Module *Imported) {
+ void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
+ StringRef FileName, bool IsAngled,
+ CharSourceRange FilenameRange, const FileEntry *File,
+ StringRef SearchPath, StringRef RelativePath,
+ const Module *Imported) override {
this->HashLoc = HashLoc;
this->IncludeTok = IncludeTok;
this->FileName = FileName.str();
@@ -95,9 +91,10 @@
PragmaOpenCLExtensionCallbacks() : Name("Not called."), State(99) {};
- void PragmaOpenCLExtension(
- clang::SourceLocation NameLoc, const clang::IdentifierInfo *Name,
- clang::SourceLocation StateLoc, unsigned State) {
+ void PragmaOpenCLExtension(clang::SourceLocation NameLoc,
+ const clang::IdentifierInfo *Name,
+ clang::SourceLocation StateLoc,
+ unsigned State) override {
this->NameLoc = NameLoc;
this->Name = Name->getName();
this->StateLoc = StateLoc;
diff --git a/unittests/Sema/ExternalSemaSourceTest.cpp b/unittests/Sema/ExternalSemaSourceTest.cpp
index 3a93fc7..703e97b 100644
--- a/unittests/Sema/ExternalSemaSourceTest.cpp
+++ b/unittests/Sema/ExternalSemaSourceTest.cpp
@@ -30,7 +30,7 @@
public:
CompleteTypeDiagnoser(bool MockResult) : CallCount(0), Result(MockResult) {}
- virtual bool MaybeDiagnoseMissingCompleteType(SourceLocation L, QualType T) {
+ bool MaybeDiagnoseMissingCompleteType(SourceLocation L, QualType T) override {
++CallCount;
return Result;
}
@@ -54,8 +54,8 @@
ToNS.append("'");
}
- virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
- const Diagnostic &Info) {
+ void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
+ const Diagnostic &Info) override {
if (Chained)
Chained->HandleDiagnostic(DiagLevel, Info);
if (Info.getID() - 1 == diag::err_using_directive_member_suggest) {
@@ -66,13 +66,13 @@
}
}
- virtual void clear() {
+ void clear() override {
DiagnosticConsumer::clear();
if (Chained)
Chained->clear();
}
- virtual bool IncludeInDiagnosticCounts() const {
+ bool IncludeInDiagnosticCounts() const override {
if (Chained)
return Chained->IncludeInDiagnosticCounts();
return false;
@@ -97,16 +97,15 @@
NamespaceTypoProvider(StringRef From, StringRef To)
: CorrectFrom(From), CorrectTo(To), CurrentSema(nullptr), CallCount(0) {}
- virtual void InitializeSema(Sema &S) { CurrentSema = &S; }
+ void InitializeSema(Sema &S) override { CurrentSema = &S; }
- virtual void ForgetSema() { CurrentSema = nullptr; }
+ void ForgetSema() override { CurrentSema = nullptr; }
- virtual TypoCorrection CorrectTypo(const DeclarationNameInfo &Typo,
- int LookupKind, Scope *S, CXXScopeSpec *SS,
- CorrectionCandidateCallback &CCC,
- DeclContext *MemberContext,
- bool EnteringContext,
- const ObjCObjectPointerType *OPT) {
+ TypoCorrection CorrectTypo(const DeclarationNameInfo &Typo, int LookupKind,
+ Scope *S, CXXScopeSpec *SS,
+ CorrectionCandidateCallback &CCC,
+ DeclContext *MemberContext, bool EnteringContext,
+ const ObjCObjectPointerType *OPT) override {
++CallCount;
if (CurrentSema && Typo.getName().getAsString() == CorrectFrom) {
DeclContext *DestContext = nullptr;
@@ -140,13 +139,13 @@
std::unique_ptr<DiagnosticConsumer> OwnedClient;
protected:
- virtual std::unique_ptr<clang::ASTConsumer>
+ std::unique_ptr<clang::ASTConsumer>
CreateASTConsumer(clang::CompilerInstance &Compiler,
- llvm::StringRef /* dummy */) {
+ llvm::StringRef /* dummy */) override {
return llvm::make_unique<clang::ASTConsumer>();
}
- virtual void ExecuteAction() {
+ void ExecuteAction() override {
CompilerInstance &CI = getCompilerInstance();
ASSERT_FALSE(CI.hasSema());
CI.createSema(getTranslationUnitKind(), nullptr);
diff --git a/unittests/Tooling/CommentHandlerTest.cpp b/unittests/Tooling/CommentHandlerTest.cpp
index 117dfc3..da56045 100644
--- a/unittests/Tooling/CommentHandlerTest.cpp
+++ b/unittests/Tooling/CommentHandlerTest.cpp
@@ -30,11 +30,11 @@
public:
CommentHandlerVisitor() : base(), PP(nullptr), Verified(false) {}
- ~CommentHandlerVisitor() {
+ ~CommentHandlerVisitor() override {
EXPECT_TRUE(Verified) << "CommentVerifier not accessed";
}
- virtual bool HandleComment(Preprocessor &PP, SourceRange Loc) {
+ bool HandleComment(Preprocessor &PP, SourceRange Loc) override {
assert(&PP == this->PP && "Preprocessor changed!");
SourceLocation Start = Loc.getBegin();
@@ -56,7 +56,7 @@
CommentVerifier GetVerifier();
protected:
- virtual ASTFrontendAction* CreateTestAction() {
+ ASTFrontendAction *CreateTestAction() override {
return new CommentHandlerAction(this);
}
@@ -70,8 +70,8 @@
CommentHandlerAction(CommentHandlerVisitor *Visitor)
: TestAction(Visitor) { }
- virtual bool BeginSourceFileAction(CompilerInstance &CI,
- StringRef FileName) {
+ bool BeginSourceFileAction(CompilerInstance &CI,
+ StringRef FileName) override {
CommentHandlerVisitor *V =
static_cast<CommentHandlerVisitor*>(this->Visitor);
V->PP = &CI.getPreprocessor();
@@ -79,7 +79,7 @@
return true;
}
- virtual void EndSourceFileAction() {
+ void EndSourceFileAction() override {
CommentHandlerVisitor *V =
static_cast<CommentHandlerVisitor*>(this->Visitor);
V->PP->removeCommentHandler(V);
diff --git a/unittests/Tooling/CompilationDatabaseTest.cpp b/unittests/Tooling/CompilationDatabaseTest.cpp
index 8866e75..3e5a589 100644
--- a/unittests/Tooling/CompilationDatabaseTest.cpp
+++ b/unittests/Tooling/CompilationDatabaseTest.cpp
@@ -127,8 +127,8 @@
}
struct FakeComparator : public PathComparator {
- virtual ~FakeComparator() {}
- virtual bool equivalent(StringRef FileA, StringRef FileB) const {
+ ~FakeComparator() override {}
+ bool equivalent(StringRef FileA, StringRef FileB) const override {
return FileA.equals_lower(FileB);
}
};
diff --git a/unittests/Tooling/RefactoringTest.cpp b/unittests/Tooling/RefactoringTest.cpp
index a026a94..7e643fa 100644
--- a/unittests/Tooling/RefactoringTest.cpp
+++ b/unittests/Tooling/RefactoringTest.cpp
@@ -213,7 +213,7 @@
public:
FlushRewrittenFilesTest() {}
- ~FlushRewrittenFilesTest() {
+ ~FlushRewrittenFilesTest() override {
for (llvm::StringMap<std::string>::iterator I = TemporaryFiles.begin(),
E = TemporaryFiles.end();
I != E; ++I) {
@@ -287,7 +287,7 @@
public:
FindConsumer(TestVisitor *Visitor) : Visitor(Visitor) {}
- virtual void HandleTranslationUnit(clang::ASTContext &Context) {
+ void HandleTranslationUnit(clang::ASTContext &Context) override {
Visitor->TraverseDecl(Context.getTranslationUnitDecl());
}
@@ -299,9 +299,9 @@
public:
TestAction(TestVisitor *Visitor) : Visitor(Visitor) {}
- virtual std::unique_ptr<clang::ASTConsumer>
+ std::unique_ptr<clang::ASTConsumer>
CreateASTConsumer(clang::CompilerInstance &compiler,
- llvm::StringRef dummy) {
+ llvm::StringRef dummy) override {
Visitor->SM = &compiler.getSourceManager();
/// TestConsumer will be deleted by the framework calling us.
return llvm::make_unique<FindConsumer>(Visitor);
diff --git a/unittests/Tooling/TestVisitor.h b/unittests/Tooling/TestVisitor.h
index d441695..f4a0039 100644
--- a/unittests/Tooling/TestVisitor.h
+++ b/unittests/Tooling/TestVisitor.h
@@ -82,7 +82,7 @@
public:
FindConsumer(TestVisitor *Visitor) : Visitor(Visitor) {}
- virtual void HandleTranslationUnit(clang::ASTContext &Context) {
+ void HandleTranslationUnit(clang::ASTContext &Context) override {
Visitor->Context = &Context;
Visitor->TraverseDecl(Context.getTranslationUnitDecl());
}
@@ -95,8 +95,8 @@
public:
TestAction(TestVisitor *Visitor) : Visitor(Visitor) {}
- virtual std::unique_ptr<clang::ASTConsumer>
- CreateASTConsumer(CompilerInstance &, llvm::StringRef dummy) {
+ std::unique_ptr<clang::ASTConsumer>
+ CreateASTConsumer(CompilerInstance &, llvm::StringRef dummy) override {
/// TestConsumer will be deleted by the framework calling us.
return llvm::make_unique<FindConsumer>(Visitor);
}
@@ -133,7 +133,7 @@
}
/// \brief Checks that all expected matches have been found.
- virtual ~ExpectedLocationVisitor() {
+ ~ExpectedLocationVisitor() override {
for (typename std::vector<ExpectedMatch>::const_iterator
It = ExpectedMatches.begin(), End = ExpectedMatches.end();
It != End; ++It) {
diff --git a/unittests/Tooling/ToolingTest.cpp b/unittests/Tooling/ToolingTest.cpp
index 5a93e38..4b14ebb 100644
--- a/unittests/Tooling/ToolingTest.cpp
+++ b/unittests/Tooling/ToolingTest.cpp
@@ -35,8 +35,9 @@
: TestConsumer(std::move(TestConsumer)) {}
protected:
- virtual std::unique_ptr<clang::ASTConsumer>
- CreateASTConsumer(clang::CompilerInstance &compiler, StringRef dummy) {
+ std::unique_ptr<clang::ASTConsumer>
+ CreateASTConsumer(clang::CompilerInstance &compiler,
+ StringRef dummy) override {
/// TestConsumer will be deleted by the framework calling us.
return std::move(TestConsumer);
}
@@ -49,7 +50,7 @@
public:
explicit FindTopLevelDeclConsumer(bool *FoundTopLevelDecl)
: FoundTopLevelDecl(FoundTopLevelDecl) {}
- virtual bool HandleTopLevelDecl(clang::DeclGroupRef DeclGroup) {
+ bool HandleTopLevelDecl(clang::DeclGroupRef DeclGroup) override {
*FoundTopLevelDecl = true;
return true;
}
@@ -72,7 +73,7 @@
public:
FindClassDeclXConsumer(bool *FoundClassDeclX)
: FoundClassDeclX(FoundClassDeclX) {}
- virtual bool HandleTopLevelDecl(clang::DeclGroupRef GroupRef) {
+ bool HandleTopLevelDecl(clang::DeclGroupRef GroupRef) override {
if (CXXRecordDecl* Record = dyn_cast<clang::CXXRecordDecl>(
*GroupRef.begin())) {
if (Record->getName() == "X") {
@@ -184,14 +185,11 @@
struct VerifyEndCallback : public SourceFileCallbacks {
VerifyEndCallback() : BeginCalled(0), EndCalled(0), Matched(false) {}
- virtual bool handleBeginSource(CompilerInstance &CI,
- StringRef Filename) override {
+ bool handleBeginSource(CompilerInstance &CI, StringRef Filename) override {
++BeginCalled;
return true;
}
- virtual void handleEndSource() override {
- ++EndCalled;
- }
+ void handleEndSource() override { ++EndCalled; }
std::unique_ptr<ASTConsumer> newASTConsumer() {
return llvm::make_unique<FindTopLevelDeclConsumer>(&Matched);
}
@@ -225,15 +223,15 @@
struct SkipBodyConsumer : public clang::ASTConsumer {
/// Skip the 'skipMe' function.
- virtual bool shouldSkipFunctionBody(Decl *D) {
+ bool shouldSkipFunctionBody(Decl *D) override {
FunctionDecl *F = dyn_cast<FunctionDecl>(D);
return F && F->getNameAsString() == "skipMe";
}
};
struct SkipBodyAction : public clang::ASTFrontendAction {
- virtual std::unique_ptr<ASTConsumer>
- CreateASTConsumer(CompilerInstance &Compiler, StringRef) {
+ std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &Compiler,
+ StringRef) override {
Compiler.getFrontendOpts().SkipFunctionBodies = true;
return llvm::make_unique<SkipBodyConsumer>();
}
@@ -312,8 +310,8 @@
struct TestDiagnosticConsumer : public DiagnosticConsumer {
TestDiagnosticConsumer() : NumDiagnosticsSeen(0) {}
- virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
- const Diagnostic &Info) {
+ void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
+ const Diagnostic &Info) override {
++NumDiagnosticsSeen;
}
unsigned NumDiagnosticsSeen;
diff --git a/unittests/libclang/LibclangTest.cpp b/unittests/libclang/LibclangTest.cpp
index a218814..e827ebc 100644
--- a/unittests/libclang/LibclangTest.cpp
+++ b/unittests/libclang/LibclangTest.cpp
@@ -357,7 +357,7 @@
CXTranslationUnit ClangTU;
unsigned TUFlags;
- void SetUp() {
+ void SetUp() override {
llvm::SmallString<256> Dir;
ASSERT_FALSE(llvm::sys::fs::createUniqueDirectory("libclang-test", Dir));
TestDir = Dir.str();
@@ -365,7 +365,7 @@
clang_defaultEditingTranslationUnitOptions();
Index = clang_createIndex(0, 0);
}
- void TearDown() {
+ void TearDown() override {
clang_disposeTranslationUnit(ClangTU);
clang_disposeIndex(Index);
for (const std::string &Path : Files)
diff --git a/utils/TableGen/ClangAttrEmitter.cpp b/utils/TableGen/ClangAttrEmitter.cpp
index c2f9dec..c1d1a1d 100644
--- a/utils/TableGen/ClangAttrEmitter.cpp
+++ b/utils/TableGen/ClangAttrEmitter.cpp
@@ -115,11 +115,7 @@
// This is different from NormalizeAttrName in that it also handles names like
// _pascal and __pascal.
static StringRef NormalizeNameForSpellingComparison(StringRef Name) {
- while (Name.startswith("_"))
- Name = Name.substr(1, Name.size());
- while (Name.endswith("_"))
- Name = Name.substr(0, Name.size() - 1);
- return Name;
+ return Name.trim("_");
}
// Normalize attribute spelling only if the spelling has both leading
@@ -2787,17 +2783,9 @@
// If there is content, print that as well.
std::string ContentStr = DocCategory->getValueAsString("Content");
- if (!ContentStr.empty()) {
- // Trim leading and trailing newlines and spaces.
- StringRef Content(ContentStr);
- while (Content.startswith("\r") || Content.startswith("\n") ||
- Content.startswith(" ") || Content.startswith("\t"))
- Content = Content.substr(1);
- while (Content.endswith("\r") || Content.endswith("\n") ||
- Content.endswith(" ") || Content.endswith("\t"))
- Content = Content.substr(0, Content.size() - 1);
- OS << Content;
- }
+ // Trim leading and trailing newlines and spaces.
+ OS << StringRef(ContentStr).trim();
+
OS << "\n\n";
}
@@ -2919,14 +2907,7 @@
std::string ContentStr = Doc.Documentation->getValueAsString("Content");
// Trim leading and trailing newlines and spaces.
- StringRef Content(ContentStr);
- while (Content.startswith("\r") || Content.startswith("\n") ||
- Content.startswith(" ") || Content.startswith("\t"))
- Content = Content.substr(1);
- while (Content.endswith("\r") || Content.endswith("\n") ||
- Content.endswith(" ") || Content.endswith("\t"))
- Content = Content.substr(0, Content.size() - 1);
- OS << Content;
+ OS << StringRef(ContentStr).trim();
OS << "\n\n\n";
}
diff --git a/utils/TableGen/NeonEmitter.cpp b/utils/TableGen/NeonEmitter.cpp
index d243672..2a857a8 100644
--- a/utils/TableGen/NeonEmitter.cpp
+++ b/utils/TableGen/NeonEmitter.cpp
@@ -1563,10 +1563,8 @@
// See the documentation in arm_neon.td for a description of these operators.
class LowHalf : public SetTheory::Operator {
public:
- virtual void anchor() {}
- virtual ~LowHalf() {}
- virtual void apply(SetTheory &ST, DagInit *Expr, SetTheory::RecSet &Elts,
- ArrayRef<SMLoc> Loc) {
+ void apply(SetTheory &ST, DagInit *Expr, SetTheory::RecSet &Elts,
+ ArrayRef<SMLoc> Loc) override {
SetTheory::RecSet Elts2;
ST.evaluate(Expr->arg_begin(), Expr->arg_end(), Elts2, Loc);
Elts.insert(Elts2.begin(), Elts2.begin() + (Elts2.size() / 2));
@@ -1574,10 +1572,8 @@
};
class HighHalf : public SetTheory::Operator {
public:
- virtual void anchor() {}
- virtual ~HighHalf() {}
- virtual void apply(SetTheory &ST, DagInit *Expr, SetTheory::RecSet &Elts,
- ArrayRef<SMLoc> Loc) {
+ void apply(SetTheory &ST, DagInit *Expr, SetTheory::RecSet &Elts,
+ ArrayRef<SMLoc> Loc) override {
SetTheory::RecSet Elts2;
ST.evaluate(Expr->arg_begin(), Expr->arg_end(), Elts2, Loc);
Elts.insert(Elts2.begin() + (Elts2.size() / 2), Elts2.end());
@@ -1588,10 +1584,8 @@
public:
Rev(unsigned ElementSize) : ElementSize(ElementSize) {}
- virtual void anchor() {}
- virtual ~Rev() {}
- virtual void apply(SetTheory &ST, DagInit *Expr, SetTheory::RecSet &Elts,
- ArrayRef<SMLoc> Loc) {
+ void apply(SetTheory &ST, DagInit *Expr, SetTheory::RecSet &Elts,
+ ArrayRef<SMLoc> Loc) override {
SetTheory::RecSet Elts2;
ST.evaluate(Expr->arg_begin() + 1, Expr->arg_end(), Elts2, Loc);
@@ -1613,9 +1607,7 @@
public:
MaskExpander(unsigned N) : N(N) {}
- virtual void anchor() {}
- virtual ~MaskExpander() {}
- virtual void expand(SetTheory &ST, Record *R, SetTheory::RecSet &Elts) {
+ void expand(SetTheory &ST, Record *R, SetTheory::RecSet &Elts) override {
unsigned Addend = 0;
if (R->getName() == "mask0")
Addend = 0;
@@ -1938,7 +1930,8 @@
}
std::sort(NewTypeSpecs.begin(), NewTypeSpecs.end());
- std::unique(NewTypeSpecs.begin(), NewTypeSpecs.end());
+ NewTypeSpecs.erase(std::unique(NewTypeSpecs.begin(), NewTypeSpecs.end()),
+ NewTypeSpecs.end());
for (auto &I : NewTypeSpecs) {
Intrinsic *IT = new Intrinsic(R, Name, Proto, I.first, I.second, CK, Body,
diff --git a/utils/check_cfc/check_cfc.cfg b/utils/check_cfc/check_cfc.cfg
new file mode 100644
index 0000000..967623e
--- /dev/null
+++ b/utils/check_cfc/check_cfc.cfg
@@ -0,0 +1,3 @@
+[Checks]
+dash_g_no_change = true
+dash_s_no_change = true
diff --git a/utils/check_cfc/check_cfc.py b/utils/check_cfc/check_cfc.py
new file mode 100755
index 0000000..3def36e
--- /dev/null
+++ b/utils/check_cfc/check_cfc.py
@@ -0,0 +1,388 @@
+#!/usr/bin/env python2.7
+
+"""Check CFC - Check Compile Flow Consistency
+
+This is a compiler wrapper for testing that code generation is consistent with
+different compilation processes. It checks that code is not unduly affected by
+compiler options or other changes which should not have side effects.
+
+To use:
+-Ensure that the compiler under test (i.e. clang, clang++) is on the PATH
+-On Linux copy this script to the name of the compiler
+ e.g. cp check_cfc.py clang && cp check_cfc.py clang++
+-On Windows use setup.py to generate check_cfc.exe and copy that to clang.exe
+ and clang++.exe
+-Enable the desired checks in check_cfc.cfg (in the same directory as the
+ wrapper)
+ e.g.
+[Checks]
+dash_g_no_change = true
+dash_s_no_change = false
+
+-The wrapper can be run using its absolute path or added to PATH before the
+ compiler under test
+ e.g. export PATH=<path to check_cfc>:$PATH
+-Compile as normal. The wrapper intercepts normal -c compiles and will return
+ non-zero if the check fails.
+ e.g.
+$ clang -c test.cpp
+Code difference detected with -g
+--- /tmp/tmp5nv893.o
++++ /tmp/tmp6Vwjnc.o
+@@ -1 +1 @@
+- 0: 48 8b 05 51 0b 20 00 mov 0x200b51(%rip),%rax
++ 0: 48 39 3d 51 0b 20 00 cmp %rdi,0x200b51(%rip)
+
+-To run LNT with Check CFC specify the absolute path to the wrapper to the --cc
+ and --cxx options
+ e.g.
+ lnt runtest nt --cc <path to check_cfc>/clang \\
+ --cxx <path to check_cfc>/clang++ ...
+
+To add a new check:
+-Create a new subclass of WrapperCheck
+-Implement the perform_check() method. This should perform the alternate compile
+ and do the comparison.
+-Add the new check to check_cfc.cfg. The check has the same name as the
+ subclass.
+"""
+
+from __future__ import print_function
+
+import imp
+import os
+import platform
+import shutil
+import subprocess
+import sys
+import tempfile
+import ConfigParser
+import io
+
+import obj_diff
+
+def is_windows():
+ """Returns True if running on Windows."""
+ return platform.system() == 'Windows'
+
+class WrapperStepException(Exception):
+ """Exception type to be used when a step other than the original compile
+ fails."""
+ def __init__(self, msg, stdout, stderr):
+ self.msg = msg
+ self.stdout = stdout
+ self.stderr = stderr
+
+class WrapperCheckException(Exception):
+ """Exception type to be used when a comparison check fails."""
+ def __init__(self, msg):
+ self.msg = msg
+
+def main_is_frozen():
+ """Returns True when running as a py2exe executable."""
+ return (hasattr(sys, "frozen") or # new py2exe
+ hasattr(sys, "importers") or # old py2exe
+ imp.is_frozen("__main__")) # tools/freeze
+
+def get_main_dir():
+ """Get the directory that the script or executable is located in."""
+ if main_is_frozen():
+ return os.path.dirname(sys.executable)
+ return os.path.dirname(sys.argv[0])
+
+def remove_dir_from_path(path_var, directory):
+ """Remove the specified directory from path_var, a string representing
+ PATH"""
+ pathlist = path_var.split(os.pathsep)
+ norm_directory = os.path.normpath(os.path.normcase(directory))
+ pathlist = filter(lambda x: os.path.normpath(
+ os.path.normcase(x)) != norm_directory, pathlist)
+ return os.pathsep.join(pathlist)
+
+def path_without_wrapper():
+ """Returns the PATH variable modified to remove the path to this program."""
+ scriptdir = get_main_dir()
+ path = os.environ['PATH']
+ return remove_dir_from_path(path, scriptdir)
+
+def flip_dash_g(args):
+ """Search for -g in args. If it exists then return args without. If not then
+ add it."""
+ if '-g' in args:
+ # Return args without any -g
+ return [x for x in args if x != '-g']
+ else:
+ # No -g, add one
+ return args + ['-g']
+
+def derive_output_file(args):
+ """Derive output file from the input file (if just one) or None
+ otherwise."""
+ infile = get_input_file(args)
+ if infile is None:
+ return None
+ else:
+ return '{}.o'.format(os.path.splitext(infile)[0])
+
+def get_output_file(args):
+ """Return the output file specified by this command or None if not
+ specified."""
+ grabnext = False
+ for arg in args:
+ if grabnext:
+ return arg
+ if arg == '-o':
+ # Specified as a separate arg
+ grabnext = True
+ elif arg.startswith('-o'):
+ # Specified conjoined with -o
+ return arg[2:]
+ assert grabnext == False
+
+ return None
+
+def is_output_specified(args):
+ """Return true is output file is specified in args."""
+ return get_output_file(args) is not None
+
+def replace_output_file(args, new_name):
+ """Replaces the specified name of an output file with the specified name.
+ Assumes that the output file name is specified in the command line args."""
+ replaceidx = None
+ attached = False
+ for idx, val in enumerate(args):
+ if val == '-o':
+ replaceidx = idx + 1
+ attached = False
+ elif val.startswith('-o'):
+ replaceidx = idx
+ attached = True
+
+ if replaceidx is None:
+ raise Exception
+ replacement = new_name
+ if attached == True:
+ replacement = '-o' + new_name
+ args[replaceidx] = replacement
+ return args
+
+def add_output_file(args, output_file):
+ """Append an output file to args, presuming not already specified."""
+ return args + ['-o', output_file]
+
+def set_output_file(args, output_file):
+ """Set the output file within the arguments. Appends or replaces as
+ appropriate."""
+ if is_output_specified(args):
+ args = replace_output_file(args, output_file)
+ else:
+ args = add_output_file(args, output_file)
+ return args
+
+gSrcFileSuffixes = ('.c', '.cpp', '.cxx', '.c++', '.cp', '.cc')
+
+def get_input_file(args):
+ """Return the input file string if it can be found (and there is only
+ one)."""
+ inputFiles = list()
+ for arg in args:
+ testarg = arg
+ quotes = ('"', "'")
+ while testarg.endswith(quotes):
+ testarg = testarg[:-1]
+ testarg = os.path.normcase(testarg)
+
+ # Test if it is a source file
+ if testarg.endswith(gSrcFileSuffixes):
+ inputFiles.append(arg)
+ if len(inputFiles) == 1:
+ return inputFiles[0]
+ else:
+ return None
+
+def set_input_file(args, input_file):
+ """Replaces the input file with that specified."""
+ infile = get_input_file(args)
+ if infile:
+ infile_idx = args.index(infile)
+ args[infile_idx] = input_file
+ return args
+ else:
+ # Could not find input file
+ assert False
+
+def is_normal_compile(args):
+ """Check if this is a normal compile which will output an object file rather
+ than a preprocess or link."""
+ compile_step = '-c' in args
+ # Bitcode cannot be disassembled in the same way
+ bitcode = '-flto' in args or '-emit-llvm' in args
+ # Version and help are queries of the compiler and override -c if specified
+ query = '--version' in args or '--help' in args
+ # Check if the input is recognised as a source file (this may be too
+ # strong a restriction)
+ input_is_valid = bool(get_input_file(args))
+ return compile_step and not bitcode and not query and input_is_valid
+
+def run_step(command, my_env, error_on_failure):
+ """Runs a step of the compilation. Reports failure as exception."""
+ # Need to use shell=True on Windows as Popen won't use PATH otherwise.
+ p = subprocess.Popen(command, stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE, env=my_env, shell=is_windows())
+ (stdout, stderr) = p.communicate()
+ if p.returncode != 0:
+ raise WrapperStepException(error_on_failure, stdout, stderr)
+
+def get_temp_file_name(suffix):
+ """Get a temporary file name with a particular suffix. Let the caller be
+ reponsible for deleting it."""
+ tf = tempfile.NamedTemporaryFile(suffix=suffix, delete=False)
+ tf.close()
+ return tf.name
+
+class WrapperCheck(object):
+ """Base class for a check. Subclass this to add a check."""
+ def __init__(self, output_file_a):
+ """Record the base output file that will be compared against."""
+ self._output_file_a = output_file_a
+
+ def perform_check(self, arguments, my_env):
+ """Override this to perform the modified compilation and required
+ checks."""
+ raise NotImplementedError("Please Implement this method")
+
+class dash_g_no_change(WrapperCheck):
+ def perform_check(self, arguments, my_env):
+ """Check if different code is generated with/without the -g flag."""
+ output_file_b = get_temp_file_name('.o')
+
+ alternate_command = list(arguments)
+ alternate_command = flip_dash_g(alternate_command)
+ alternate_command = set_output_file(alternate_command, output_file_b)
+ run_step(alternate_command, my_env, "Error compiling with -g")
+
+ # Compare disassembly (returns first diff if differs)
+ difference = obj_diff.compare_object_files(self._output_file_a,
+ output_file_b)
+ if difference:
+ raise WrapperCheckException(
+ "Code difference detected with -g\n{}".format(difference))
+
+ # Clean up temp file if comparison okay
+ os.remove(output_file_b)
+
+class dash_s_no_change(WrapperCheck):
+ def perform_check(self, arguments, my_env):
+ """Check if compiling to asm then assembling in separate steps results
+ in different code than compiling to object directly."""
+ output_file_b = get_temp_file_name('.o')
+
+ alternate_command = arguments + ['-via-file-asm']
+ alternate_command = set_output_file(alternate_command, output_file_b)
+ run_step(alternate_command, my_env,
+ "Error compiling with -via-file-asm")
+
+ # Compare disassembly (returns first diff if differs)
+ difference = obj_diff.compare_object_files(self._output_file_a,
+ output_file_b)
+ if difference:
+ raise WrapperCheckException(
+ "Code difference detected with -S\n{}".format(difference))
+
+ # Clean up temp file if comparison okay
+ os.remove(output_file_b)
+
+if __name__ == '__main__':
+ # Create configuration defaults from list of checks
+ default_config = """
+[Checks]
+"""
+
+ # Find all subclasses of WrapperCheck
+ checks = [cls.__name__ for cls in vars()['WrapperCheck'].__subclasses__()]
+
+ for c in checks:
+ default_config += "{} = false\n".format(c)
+
+ config = ConfigParser.RawConfigParser()
+ config.readfp(io.BytesIO(default_config))
+ scriptdir = get_main_dir()
+ config_path = os.path.join(scriptdir, 'check_cfc.cfg')
+ try:
+ config.read(os.path.join(config_path))
+ except:
+ print("Could not read config from {}, "
+ "using defaults.".format(config_path))
+
+ my_env = os.environ.copy()
+ my_env['PATH'] = path_without_wrapper()
+
+ arguments_a = list(sys.argv)
+
+ # Prevent infinite loop if called with absolute path.
+ arguments_a[0] = os.path.basename(arguments_a[0])
+
+ # Sanity check
+ enabled_checks = [check_name
+ for check_name in checks
+ if config.getboolean('Checks', check_name)]
+ checks_comma_separated = ', '.join(enabled_checks)
+ print("Check CFC, checking: {}".format(checks_comma_separated))
+
+ # A - original compilation
+ output_file_orig = get_output_file(arguments_a)
+ if output_file_orig is None:
+ output_file_orig = derive_output_file(arguments_a)
+
+ p = subprocess.Popen(arguments_a, env=my_env, shell=is_windows())
+ p.communicate()
+ if p.returncode != 0:
+ sys.exit(p.returncode)
+
+ if not is_normal_compile(arguments_a) or output_file_orig is None:
+ # Bail out here if we can't apply checks in this case.
+ # Does not indicate an error.
+ # Maybe not straight compilation (e.g. -S or --version or -flto)
+ # or maybe > 1 input files.
+ sys.exit(0)
+
+ # Sometimes we generate files which have very long names which can't be
+ # read/disassembled. This will exit early if we can't find the file we
+ # expected to be output.
+ if not os.path.isfile(output_file_orig):
+ sys.exit(0)
+
+ # Copy output file to a temp file
+ temp_output_file_orig = get_temp_file_name('.o')
+ shutil.copyfile(output_file_orig, temp_output_file_orig)
+
+ # Run checks, if they are enabled in config and if they are appropriate for
+ # this command line.
+ current_module = sys.modules[__name__]
+ for check_name in checks:
+ if config.getboolean('Checks', check_name):
+ class_ = getattr(current_module, check_name)
+ checker = class_(temp_output_file_orig)
+ try:
+ checker.perform_check(arguments_a, my_env)
+ except WrapperCheckException as e:
+ # Check failure
+ print(e.msg, file=sys.stderr)
+
+ # Remove file to comply with build system expectations (no
+ # output file if failed)
+ os.remove(output_file_orig)
+ sys.exit(1)
+
+ except WrapperStepException as e:
+ # Compile step failure
+ print(e.msg, file=sys.stderr)
+ print("*** stdout ***", file=sys.stderr)
+ print(e.stdout, file=sys.stderr)
+ print("*** stderr ***", file=sys.stderr)
+ print(e.stderr, file=sys.stderr)
+
+ # Remove file to comply with build system expectations (no
+ # output file if failed)
+ os.remove(output_file_orig)
+ sys.exit(1)
diff --git a/utils/check_cfc/obj_diff.py b/utils/check_cfc/obj_diff.py
new file mode 100755
index 0000000..6f932b3
--- /dev/null
+++ b/utils/check_cfc/obj_diff.py
@@ -0,0 +1,79 @@
+#!/usr/bin/env python2.7
+
+from __future__ import print_function
+
+import argparse
+import difflib
+import os
+import subprocess
+import sys
+
+disassembler = 'objdump'
+
+def keep_line(line):
+ """Returns true for lines that should be compared in the disassembly
+ output."""
+ return "file format" not in line
+
+def disassemble(objfile):
+ """Disassemble object to a file."""
+ p = subprocess.Popen([disassembler, '-d', objfile],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ (out, err) = p.communicate()
+ if p.returncode or err:
+ print("Disassemble failed: {}".format(objfile))
+ sys.exit(1)
+ return filter(keep_line, out.split(os.linesep))
+
+def first_diff(a, b, fromfile, tofile):
+ """Returns the first few lines of a difference, if there is one. Python
+ diff can be very slow with large objects and the most interesting changes
+ are the first ones. Truncate data before sending to difflib. Returns None
+ is there is no difference."""
+
+ # Find first diff
+ first_diff_idx = None
+ for idx, val in enumerate(a):
+ if val != b[idx]:
+ first_diff_idx = idx
+ break
+
+ if first_diff_idx == None:
+ # No difference
+ return None
+
+ # Diff to first line of diff plus some lines
+ context = 3
+ diff = difflib.unified_diff(a[:first_diff_idx+context],
+ b[:first_diff_idx+context],
+ fromfile,
+ tofile)
+ difference = "\n".join(diff)
+ if first_diff_idx + context < len(a):
+ difference += "\n*** Diff truncated ***"
+ return difference
+
+def compare_object_files(objfilea, objfileb):
+ """Compare disassembly of two different files.
+ Allowing unavoidable differences, such as filenames.
+ Return the first difference if the disassembly differs, or None.
+ """
+ disa = disassemble(objfilea)
+ disb = disassemble(objfileb)
+ return first_diff(disa, disb, objfilea, objfileb)
+
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser()
+ parser.add_argument('objfilea', nargs=1)
+ parser.add_argument('objfileb', nargs=1)
+ parser.add_argument('-v', '--verbose', action='store_true')
+ args = parser.parse_args()
+ diff = compare_object_files(args.objfilea[0], args.objfileb[0])
+ if diff:
+ print("Difference detected")
+ if args.verbose:
+ print(diff)
+ sys.exit(1)
+ else:
+ print("The same")
diff --git a/utils/check_cfc/setup.py b/utils/check_cfc/setup.py
new file mode 100644
index 0000000..b5fc473
--- /dev/null
+++ b/utils/check_cfc/setup.py
@@ -0,0 +1,21 @@
+"""For use on Windows. Run with:
+ python.exe setup.py py2exe
+ """
+from distutils.core import setup
+try:
+ import py2exe
+except ImportError:
+ import platform
+ import sys
+ if platform.system() == 'Windows':
+ print "Could not find py2exe. Please install then run setup.py py2exe."
+ raise
+ else:
+ print "setup.py only required on Windows."
+ sys.exit(1)
+
+setup(
+ console=['check_cfc.py'],
+ name="Check CFC",
+ description='Check Compile Flow Consistency'
+ )
diff --git a/utils/check_cfc/test_check_cfc.py b/utils/check_cfc/test_check_cfc.py
new file mode 100755
index 0000000..0eee5b8
--- /dev/null
+++ b/utils/check_cfc/test_check_cfc.py
@@ -0,0 +1,158 @@
+#!/usr/bin/env python2.7
+
+"""Test internal functions within check_cfc.py."""
+
+import check_cfc
+import os
+import platform
+import unittest
+
+
+class TestCheckCFC(unittest.TestCase):
+
+ def test_flip_dash_g(self):
+ self.assertIn('-g', check_cfc.flip_dash_g(['clang', '-c']))
+ self.assertNotIn('-g', check_cfc.flip_dash_g(['clang', '-c', '-g']))
+ self.assertNotIn(
+ '-g', check_cfc.flip_dash_g(['clang', '-g', '-c', '-g']))
+
+ def test_remove_dir_from_path(self):
+ bin_path = r'/usr/bin'
+ space_path = r'/home/user/space in path'
+ superstring_path = r'/usr/bin/local'
+
+ # Test removing last thing in path
+ self.assertNotIn(
+ bin_path, check_cfc.remove_dir_from_path(bin_path, bin_path))
+
+ # Test removing one entry and leaving others
+ # Also tests removing repeated path
+ path_var = os.pathsep.join(
+ [superstring_path, bin_path, space_path, bin_path])
+ stripped_path_var = check_cfc.remove_dir_from_path(path_var, bin_path)
+ self.assertIn(superstring_path, stripped_path_var)
+ self.assertNotIn(bin_path, stripped_path_var.split(os.pathsep))
+ self.assertIn(space_path, stripped_path_var)
+
+ # Test removing non-canonical path
+ self.assertNotIn(r'/usr//bin',
+ check_cfc.remove_dir_from_path(r'/usr//bin', bin_path))
+
+ if platform == 'Windows':
+ # Windows is case insensitive so should remove a different case
+ # path
+ self.assertNotIn(
+ bin_path, check_cfc.remove_dir_from_path(path_var, r'/USR/BIN'))
+ else:
+ # Case sensitive so will not remove different case path
+ self.assertIn(
+ bin_path, check_cfc.remove_dir_from_path(path_var, r'/USR/BIN'))
+
+ def test_is_output_specified(self):
+ self.assertTrue(
+ check_cfc.is_output_specified(['clang', '-o', 'test.o']))
+ self.assertTrue(check_cfc.is_output_specified(['clang', '-otest.o']))
+ self.assertFalse(
+ check_cfc.is_output_specified(['clang', '-gline-tables-only']))
+ # Not specified for implied output file name
+ self.assertFalse(check_cfc.is_output_specified(['clang', 'test.c']))
+
+ def test_get_output_file(self):
+ self.assertEqual(
+ check_cfc.get_output_file(['clang', '-o', 'test.o']), 'test.o')
+ self.assertEqual(
+ check_cfc.get_output_file(['clang', '-otest.o']), 'test.o')
+ self.assertIsNone(
+ check_cfc.get_output_file(['clang', '-gline-tables-only']))
+ # Can't get output file if more than one input file
+ self.assertIsNone(
+ check_cfc.get_output_file(['clang', '-c', 'test.cpp', 'test2.cpp']))
+ # No output file specified
+ self.assertIsNone(check_cfc.get_output_file(['clang', '-c', 'test.c']))
+
+ def test_derive_output_file(self):
+ # Test getting implicit output file
+ self.assertEqual(
+ check_cfc.derive_output_file(['clang', '-c', 'test.c']), 'test.o')
+ self.assertEqual(
+ check_cfc.derive_output_file(['clang', '-c', 'test.cpp']), 'test.o')
+ self.assertIsNone(check_cfc.derive_output_file(['clang', '--version']))
+
+ def test_is_normal_compile(self):
+ self.assertTrue(check_cfc.is_normal_compile(
+ ['clang', '-c', 'test.cpp', '-o', 'test2.o']))
+ self.assertTrue(
+ check_cfc.is_normal_compile(['clang', '-c', 'test.cpp']))
+ # Outputting bitcode is not a normal compile
+ self.assertFalse(
+ check_cfc.is_normal_compile(['clang', '-c', 'test.cpp', '-flto']))
+ self.assertFalse(
+ check_cfc.is_normal_compile(['clang', '-c', 'test.cpp', '-emit-llvm']))
+ # Outputting preprocessed output or assembly is not a normal compile
+ self.assertFalse(
+ check_cfc.is_normal_compile(['clang', '-E', 'test.cpp', '-o', 'test.ii']))
+ self.assertFalse(
+ check_cfc.is_normal_compile(['clang', '-S', 'test.cpp', '-o', 'test.s']))
+ # Input of preprocessed or assembly is not a "normal compile"
+ self.assertFalse(
+ check_cfc.is_normal_compile(['clang', '-c', 'test.s', '-o', 'test.o']))
+ self.assertFalse(
+ check_cfc.is_normal_compile(['clang', '-c', 'test.ii', '-o', 'test.o']))
+ # Specifying --version and -c is not a normal compile
+ self.assertFalse(
+ check_cfc.is_normal_compile(['clang', '-c', 'test.cpp', '--version']))
+ self.assertFalse(
+ check_cfc.is_normal_compile(['clang', '-c', 'test.cpp', '--help']))
+
+ def test_replace_output_file(self):
+ self.assertEqual(check_cfc.replace_output_file(
+ ['clang', '-o', 'test.o'], 'testg.o'), ['clang', '-o', 'testg.o'])
+ self.assertEqual(check_cfc.replace_output_file(
+ ['clang', '-otest.o'], 'testg.o'), ['clang', '-otestg.o'])
+ with self.assertRaises(Exception):
+ check_cfc.replace_output_file(['clang'], 'testg.o')
+
+ def test_add_output_file(self):
+ self.assertEqual(check_cfc.add_output_file(
+ ['clang'], 'testg.o'), ['clang', '-o', 'testg.o'])
+
+ def test_set_output_file(self):
+ # Test output not specified
+ self.assertEqual(
+ check_cfc.set_output_file(['clang'], 'test.o'), ['clang', '-o', 'test.o'])
+ # Test output is specified
+ self.assertEqual(check_cfc.set_output_file(
+ ['clang', '-o', 'test.o'], 'testb.o'), ['clang', '-o', 'testb.o'])
+
+ def test_get_input_file(self):
+ # No input file
+ self.assertIsNone(check_cfc.get_input_file(['clang']))
+ # Input C file
+ self.assertEqual(
+ check_cfc.get_input_file(['clang', 'test.c']), 'test.c')
+ # Input C++ file
+ self.assertEqual(
+ check_cfc.get_input_file(['clang', 'test.cpp']), 'test.cpp')
+ # Multiple input files
+ self.assertIsNone(
+ check_cfc.get_input_file(['clang', 'test.c', 'test2.cpp']))
+ self.assertIsNone(
+ check_cfc.get_input_file(['clang', 'test.c', 'test2.c']))
+ # Don't handle preprocessed files
+ self.assertIsNone(check_cfc.get_input_file(['clang', 'test.i']))
+ self.assertIsNone(check_cfc.get_input_file(['clang', 'test.ii']))
+ # Test identifying input file with quotes
+ self.assertEqual(
+ check_cfc.get_input_file(['clang', '"test.c"']), '"test.c"')
+ self.assertEqual(
+ check_cfc.get_input_file(['clang', "'test.c'"]), "'test.c'")
+ # Test multiple quotes
+ self.assertEqual(
+ check_cfc.get_input_file(['clang', "\"'test.c'\""]), "\"'test.c'\"")
+
+ def test_set_input_file(self):
+ self.assertEqual(check_cfc.set_input_file(
+ ['clang', 'test.c'], 'test.s'), ['clang', 'test.s'])
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/www/cxx_dr_status.html b/www/cxx_dr_status.html
index e70604f..f4d860f 100644
--- a/www/cxx_dr_status.html
+++ b/www/cxx_dr_status.html
@@ -4681,7 +4681,7 @@
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#777">777</a></td>
<td>CD2</td>
<td>Default arguments and parameter packs</td>
- <td class="none" align="center">Unknown</td>
+ <td class="svn" align="center">SVN</td>
</tr>
<tr id="778">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#778">778</a></td>