Vendor import of clang trunk r304149:
https://llvm.org/svn/llvm-project/cfe/trunk@304149
This commit is contained in:
parent
aa803409c3
commit
b5aee35cc5
@ -359,6 +359,10 @@ if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY)
|
||||
PATTERN "*.inc"
|
||||
PATTERN "*.h"
|
||||
)
|
||||
|
||||
install(PROGRAMS utils/bash-autocomplete.sh
|
||||
DESTINATION share/clang
|
||||
)
|
||||
endif()
|
||||
|
||||
add_definitions( -D_GNU_SOURCE )
|
||||
|
@ -1963,6 +1963,47 @@ TypeKind.DEPENDENTSIZEDARRAY = TypeKind(116)
|
||||
TypeKind.MEMBERPOINTER = TypeKind(117)
|
||||
TypeKind.AUTO = TypeKind(118)
|
||||
TypeKind.ELABORATED = TypeKind(119)
|
||||
TypeKind.PIPE = TypeKind(120)
|
||||
TypeKind.OCLIMAGE1DRO = TypeKind(121)
|
||||
TypeKind.OCLIMAGE1DARRAYRO = TypeKind(122)
|
||||
TypeKind.OCLIMAGE1DBUFFERRO = TypeKind(123)
|
||||
TypeKind.OCLIMAGE2DRO = TypeKind(124)
|
||||
TypeKind.OCLIMAGE2DARRAYRO = TypeKind(125)
|
||||
TypeKind.OCLIMAGE2DDEPTHRO = TypeKind(126)
|
||||
TypeKind.OCLIMAGE2DARRAYDEPTHRO = TypeKind(127)
|
||||
TypeKind.OCLIMAGE2DMSAARO = TypeKind(128)
|
||||
TypeKind.OCLIMAGE2DARRAYMSAARO = TypeKind(129)
|
||||
TypeKind.OCLIMAGE2DMSAADEPTHRO = TypeKind(130)
|
||||
TypeKind.OCLIMAGE2DARRAYMSAADEPTHRO = TypeKind(131)
|
||||
TypeKind.OCLIMAGE3DRO = TypeKind(132)
|
||||
TypeKind.OCLIMAGE1DWO = TypeKind(133)
|
||||
TypeKind.OCLIMAGE1DARRAYWO = TypeKind(134)
|
||||
TypeKind.OCLIMAGE1DBUFFERWO = TypeKind(135)
|
||||
TypeKind.OCLIMAGE2DWO = TypeKind(136)
|
||||
TypeKind.OCLIMAGE2DARRAYWO = TypeKind(137)
|
||||
TypeKind.OCLIMAGE2DDEPTHWO = TypeKind(138)
|
||||
TypeKind.OCLIMAGE2DARRAYDEPTHWO = TypeKind(139)
|
||||
TypeKind.OCLIMAGE2DMSAAWO = TypeKind(140)
|
||||
TypeKind.OCLIMAGE2DARRAYMSAAWO = TypeKind(141)
|
||||
TypeKind.OCLIMAGE2DMSAADEPTHWO = TypeKind(142)
|
||||
TypeKind.OCLIMAGE2DARRAYMSAADEPTHWO = TypeKind(143)
|
||||
TypeKind.OCLIMAGE3DWO = TypeKind(144)
|
||||
TypeKind.OCLIMAGE1DRW = TypeKind(145)
|
||||
TypeKind.OCLIMAGE1DARRAYRW = TypeKind(146)
|
||||
TypeKind.OCLIMAGE1DBUFFERRW = TypeKind(147)
|
||||
TypeKind.OCLIMAGE2DRW = TypeKind(148)
|
||||
TypeKind.OCLIMAGE2DARRAYRW = TypeKind(149)
|
||||
TypeKind.OCLIMAGE2DDEPTHRW = TypeKind(150)
|
||||
TypeKind.OCLIMAGE2DARRAYDEPTHRW = TypeKind(151)
|
||||
TypeKind.OCLIMAGE2DMSAARW = TypeKind(152)
|
||||
TypeKind.OCLIMAGE2DARRAYMSAARW = TypeKind(153)
|
||||
TypeKind.OCLIMAGE2DMSAADEPTHRW = TypeKind(154)
|
||||
TypeKind.OCLIMAGE2DARRAYMSAADEPTHRW = TypeKind(155)
|
||||
TypeKind.OCLIMAGE3DRW = TypeKind(156)
|
||||
TypeKind.OCLSAMPLER = TypeKind(157)
|
||||
TypeKind.OCLEVENT = TypeKind(158)
|
||||
TypeKind.OCLQUEUE = TypeKind(159)
|
||||
TypeKind.OCLRESERVEID = TypeKind(160)
|
||||
|
||||
class RefQualifierKind(BaseEnumeration):
|
||||
"""Describes a specific ref-qualifier of a type."""
|
||||
|
50
cmake/caches/BaremetalARM.cmake
Normal file
50
cmake/caches/BaremetalARM.cmake
Normal file
@ -0,0 +1,50 @@
|
||||
set(LLVM_TARGETS_TO_BUILD ARM;X86 CACHE STRING "")
|
||||
|
||||
# Builtins
|
||||
set(LLVM_BUILTIN_TARGETS "armv7m-none-eabi;armv6m-none-eabi;armv7em-none-eabi" CACHE STRING "Builtin Targets")
|
||||
|
||||
set(BUILTINS_armv6m-none-eabi_CMAKE_SYSROOT ${BAREMETAL_ARMV6M_SYSROOT} CACHE STRING "armv6m-none-eabi Sysroot")
|
||||
set(BUILTINS_armv6m-none-eabi_CMAKE_SYSTEM_NAME Generic CACHE STRING "armv6m-none-eabi System Name")
|
||||
set(BUILTINS_armv6m-none-eabi_COMPILER_RT_BAREMETAL_BUILD ON CACHE BOOL "armv6m-none-eabi Baremetal build")
|
||||
set(BUILTINS_armv6m-none-eabi_COMPILER_RT_OS_DIR "baremetal" CACHE STRING "armv6m-none-eabi os dir")
|
||||
|
||||
set(BUILTINS_armv7m-none-eabi_CMAKE_SYSROOT ${BAREMETAL_ARMV7M_SYSROOT} CACHE STRING "armv7m-none-eabi Sysroot")
|
||||
set(BUILTINS_armv7m-none-eabi_CMAKE_SYSTEM_NAME Generic CACHE STRING "armv7m-none-eabi System Name")
|
||||
set(BUILTINS_armv7m-none-eabi_COMPILER_RT_BAREMETAL_BUILD ON CACHE BOOL "armv7m-none-eabi Baremetal build")
|
||||
set(BUILTINS_armv7m-none-eabi_CMAKE_C_FLAGS "-mfpu=fp-armv8" CACHE STRING "armv7m-none-eabi C Flags")
|
||||
set(BUILTINS_armv7m-none-eabi_CMAKE_ASM_FLAGS "-mfpu=fp-armv8" CACHE STRING "armv7m-none-eabi ASM Flags")
|
||||
set(BUILTINS_armv7m-none-eabi_COMPILER_RT_OS_DIR "baremetal" CACHE STRING "armv7m-none-eabi os dir")
|
||||
|
||||
set(BUILTINS_armv7em-none-eabi_CMAKE_SYSROOT ${BAREMETAL_ARMV7EM_SYSROOT} CACHE STRING "armv7em-none-eabi Sysroot")
|
||||
set(BUILTINS_armv7em-none-eabi_CMAKE_SYSTEM_NAME Generic CACHE STRING "armv7em-none-eabi System Name")
|
||||
set(BUILTINS_armv7em-none-eabi_COMPILER_RT_BAREMETAL_BUILD ON CACHE BOOL "armv7em-none-eabi Baremetal build")
|
||||
set(BUILTINS_armv7em-none-eabi_CMAKE_C_FLAGS "-mfpu=fp-armv8" CACHE STRING "armv7em-none-eabi C Flags")
|
||||
set(BUILTINS_armv7em-none-eabi_CMAKE_ASM_FLAGS "-mfpu=fp-armv8" CACHE STRING "armv7em-none-eabi ASM Flags")
|
||||
set(BUILTINS_armv7em-none-eabi_COMPILER_RT_OS_DIR "baremetal" CACHE STRING "armv7em-none-eabi os dir")
|
||||
|
||||
set(LLVM_INSTALL_TOOLCHAIN_ONLY ON CACHE BOOL "")
|
||||
set(LLVM_TOOLCHAIN_TOOLS
|
||||
llc
|
||||
llvm-ar
|
||||
llvm-cxxfilt
|
||||
llvm-dwarfdump
|
||||
llvm-dsymutil
|
||||
llvm-nm
|
||||
llvm-objdump
|
||||
llvm-ranlib
|
||||
llvm-readobj
|
||||
llvm-size
|
||||
llvm-symbolizer
|
||||
opt
|
||||
CACHE STRING "")
|
||||
|
||||
set(LLVM_DISTRIBUTION_COMPONENTS
|
||||
clang
|
||||
lld
|
||||
clang-headers
|
||||
builtins-armv6m-none-eabi
|
||||
builtins-armv7m-none-eabi
|
||||
builtins-armv7em-none-eabi
|
||||
runtimes
|
||||
${LLVM_TOOLCHAIN_TOOLS}
|
||||
CACHE STRING "")
|
@ -413,6 +413,9 @@ altivec
|
||||
blocks
|
||||
The "blocks" language feature is available.
|
||||
|
||||
coroutines
|
||||
Support for the coroutines TS is available.
|
||||
|
||||
cplusplus
|
||||
C++ support is available.
|
||||
|
||||
|
@ -32,7 +32,7 @@
|
||||
* compatible, thus CINDEX_VERSION_MAJOR is expected to remain stable.
|
||||
*/
|
||||
#define CINDEX_VERSION_MAJOR 0
|
||||
#define CINDEX_VERSION_MINOR 39
|
||||
#define CINDEX_VERSION_MINOR 40
|
||||
|
||||
#define CINDEX_VERSION_ENCODE(major, minor) ( \
|
||||
((major) * 10000) \
|
||||
@ -3076,7 +3076,52 @@ enum CXTypeKind {
|
||||
*
|
||||
* E.g., struct S, or via a qualified name, e.g., N::M::type, or both.
|
||||
*/
|
||||
CXType_Elaborated = 119
|
||||
CXType_Elaborated = 119,
|
||||
|
||||
/* OpenCL PipeType. */
|
||||
CXType_Pipe = 120,
|
||||
|
||||
/* OpenCL builtin types. */
|
||||
CXType_OCLImage1dRO = 121,
|
||||
CXType_OCLImage1dArrayRO = 122,
|
||||
CXType_OCLImage1dBufferRO = 123,
|
||||
CXType_OCLImage2dRO = 124,
|
||||
CXType_OCLImage2dArrayRO = 125,
|
||||
CXType_OCLImage2dDepthRO = 126,
|
||||
CXType_OCLImage2dArrayDepthRO = 127,
|
||||
CXType_OCLImage2dMSAARO = 128,
|
||||
CXType_OCLImage2dArrayMSAARO = 129,
|
||||
CXType_OCLImage2dMSAADepthRO = 130,
|
||||
CXType_OCLImage2dArrayMSAADepthRO = 131,
|
||||
CXType_OCLImage3dRO = 132,
|
||||
CXType_OCLImage1dWO = 133,
|
||||
CXType_OCLImage1dArrayWO = 134,
|
||||
CXType_OCLImage1dBufferWO = 135,
|
||||
CXType_OCLImage2dWO = 136,
|
||||
CXType_OCLImage2dArrayWO = 137,
|
||||
CXType_OCLImage2dDepthWO = 138,
|
||||
CXType_OCLImage2dArrayDepthWO = 139,
|
||||
CXType_OCLImage2dMSAAWO = 140,
|
||||
CXType_OCLImage2dArrayMSAAWO = 141,
|
||||
CXType_OCLImage2dMSAADepthWO = 142,
|
||||
CXType_OCLImage2dArrayMSAADepthWO = 143,
|
||||
CXType_OCLImage3dWO = 144,
|
||||
CXType_OCLImage1dRW = 145,
|
||||
CXType_OCLImage1dArrayRW = 146,
|
||||
CXType_OCLImage1dBufferRW = 147,
|
||||
CXType_OCLImage2dRW = 148,
|
||||
CXType_OCLImage2dArrayRW = 149,
|
||||
CXType_OCLImage2dDepthRW = 150,
|
||||
CXType_OCLImage2dArrayDepthRW = 151,
|
||||
CXType_OCLImage2dMSAARW = 152,
|
||||
CXType_OCLImage2dArrayMSAARW = 153,
|
||||
CXType_OCLImage2dMSAADepthRW = 154,
|
||||
CXType_OCLImage2dArrayMSAADepthRW = 155,
|
||||
CXType_OCLImage3dRW = 156,
|
||||
CXType_OCLSampler = 157,
|
||||
CXType_OCLEvent = 158,
|
||||
CXType_OCLQueue = 159,
|
||||
CXType_OCLReserveID = 160
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -4284,6 +4284,9 @@ public:
|
||||
}
|
||||
|
||||
Designator *getDesignator(unsigned Idx) { return &designators()[Idx]; }
|
||||
const Designator *getDesignator(unsigned Idx) const {
|
||||
return &designators()[Idx];
|
||||
}
|
||||
|
||||
void setDesignators(const ASTContext &C, const Designator *Desigs,
|
||||
unsigned NumDesigs);
|
||||
|
@ -308,7 +308,9 @@ class CoroutineBodyStmt final
|
||||
OnFallthrough, ///< Handler for control flow falling off the body.
|
||||
Allocate, ///< Coroutine frame memory allocation.
|
||||
Deallocate, ///< Coroutine frame memory deallocation.
|
||||
ReturnValue, ///< Return value for thunk function.
|
||||
ReturnValue, ///< Return value for thunk function: p.get_return_object().
|
||||
ResultDecl, ///< Declaration holding the result of get_return_object.
|
||||
ReturnStmt, ///< Return statement for the thunk function.
|
||||
ReturnStmtOnAllocFailure, ///< Return statement if allocation failed.
|
||||
FirstParamMove ///< First offset for move construction of parameter copies.
|
||||
};
|
||||
@ -332,7 +334,9 @@ public:
|
||||
Stmt *OnFallthrough = nullptr;
|
||||
Expr *Allocate = nullptr;
|
||||
Expr *Deallocate = nullptr;
|
||||
Stmt *ReturnValue = nullptr;
|
||||
Expr *ReturnValue = nullptr;
|
||||
Stmt *ResultDecl = nullptr;
|
||||
Stmt *ReturnStmt = nullptr;
|
||||
Stmt *ReturnStmtOnAllocFailure = nullptr;
|
||||
ArrayRef<Stmt *> ParamMoves;
|
||||
};
|
||||
@ -381,10 +385,11 @@ public:
|
||||
Expr *getDeallocate() const {
|
||||
return cast_or_null<Expr>(getStoredStmts()[SubStmt::Deallocate]);
|
||||
}
|
||||
|
||||
Expr *getReturnValueInit() const {
|
||||
return cast_or_null<Expr>(getStoredStmts()[SubStmt::ReturnValue]);
|
||||
return cast<Expr>(getStoredStmts()[SubStmt::ReturnValue]);
|
||||
}
|
||||
Stmt *getResultDecl() const { return getStoredStmts()[SubStmt::ResultDecl]; }
|
||||
Stmt *getReturnStmt() const { return getStoredStmts()[SubStmt::ReturnStmt]; }
|
||||
Stmt *getReturnStmtOnAllocFailure() const {
|
||||
return getStoredStmts()[SubStmt::ReturnStmtOnAllocFailure];
|
||||
}
|
||||
|
@ -149,6 +149,9 @@ class ExprArgument<string name, bit opt = 0> : Argument<name, opt>;
|
||||
class FunctionArgument<string name, bit opt = 0, bit fake = 0> : Argument<name,
|
||||
opt,
|
||||
fake>;
|
||||
class NamedArgument<string name, bit opt = 0, bit fake = 0> : Argument<name,
|
||||
opt,
|
||||
fake>;
|
||||
class TypeArgument<string name, bit opt = 0> : Argument<name, opt>;
|
||||
class UnsignedArgument<string name, bit opt = 0> : Argument<name, opt>;
|
||||
class VariadicUnsignedArgument<string name> : Argument<name, 1>;
|
||||
@ -1819,14 +1822,14 @@ def Unavailable : InheritableAttr {
|
||||
|
||||
def DiagnoseIf : InheritableAttr {
|
||||
let Spellings = [GNU<"diagnose_if">];
|
||||
let Subjects = SubjectList<[Function]>;
|
||||
let Subjects = SubjectList<[Function, ObjCMethod, ObjCProperty]>;
|
||||
let Args = [ExprArgument<"Cond">, StringArgument<"Message">,
|
||||
EnumArgument<"DiagnosticType",
|
||||
"DiagnosticType",
|
||||
["error", "warning"],
|
||||
["DT_Error", "DT_Warning"]>,
|
||||
BoolArgument<"ArgDependent", 0, /*fake*/ 1>,
|
||||
FunctionArgument<"Parent", 0, /*fake*/ 1>];
|
||||
NamedArgument<"Parent", 0, /*fake*/ 1>];
|
||||
let DuplicatesAllowedWhileMerging = 1;
|
||||
let LateParsed = 1;
|
||||
let AdditionalMembers = [{
|
||||
|
@ -36,6 +36,7 @@ BUILTIN(__builtin_amdgcn_workitem_id_z, "Ui", "nc")
|
||||
// Instruction builtins.
|
||||
//===----------------------------------------------------------------------===//
|
||||
BUILTIN(__builtin_amdgcn_s_getreg, "UiIi", "n")
|
||||
BUILTIN(__builtin_amdgcn_s_getpc, "LUi", "n")
|
||||
BUILTIN(__builtin_amdgcn_s_waitcnt, "vIi", "n")
|
||||
BUILTIN(__builtin_amdgcn_s_sendmsg, "vIiUi", "n")
|
||||
BUILTIN(__builtin_amdgcn_s_sendmsghalt, "vIiUi", "n")
|
||||
|
@ -420,6 +420,9 @@ BUILTIN(__builtin_vsx_xvtstdcsp, "V4UiV4fIi", "")
|
||||
BUILTIN(__builtin_vsx_insertword, "V16UcV4UiV16UcIi", "")
|
||||
BUILTIN(__builtin_vsx_extractuword, "V2ULLiV16UcIi", "")
|
||||
|
||||
BUILTIN(__builtin_vsx_xxpermdi, "v.", "t")
|
||||
BUILTIN(__builtin_vsx_xxsldwi, "v.", "t")
|
||||
|
||||
// HTM builtins
|
||||
BUILTIN(__builtin_tbegin, "UiUIi", "")
|
||||
BUILTIN(__builtin_tend, "UiUIi", "")
|
||||
|
@ -1107,6 +1107,9 @@ TARGET_BUILTIN(__builtin_ia32_vpconflictsi_512_mask, "V16iV16iV16iUs", "", "avx5
|
||||
TARGET_BUILTIN(__builtin_ia32_vplzcntd_512_mask, "V16iV16iV16iUs", "", "avx512cd")
|
||||
TARGET_BUILTIN(__builtin_ia32_vplzcntq_512_mask, "V8LLiV8LLiV8LLiUc", "", "avx512cd")
|
||||
|
||||
TARGET_BUILTIN(__builtin_ia32_vpopcntd_512, "V16iV16i", "", "avx512vpopcntdq")
|
||||
TARGET_BUILTIN(__builtin_ia32_vpopcntq_512, "V8LLiV8LLi", "", "avx512vpopcntdq")
|
||||
|
||||
TARGET_BUILTIN(__builtin_ia32_vpermi2varhi128_mask, "V8sV8sV8sV8sUc", "", "avx512vl,avx512bw")
|
||||
TARGET_BUILTIN(__builtin_ia32_vpermi2varhi256_mask, "V16sV16sV16sV16sUs", "", "avx512vl,avx512bw")
|
||||
TARGET_BUILTIN(__builtin_ia32_vpermt2varhi128_mask, "V8sV8sV8sV8sUc", "", "avx512vl,avx512bw")
|
||||
|
@ -87,6 +87,8 @@ VALUE_DIAGOPT(TemplateBacktraceLimit, 32, DefaultTemplateBacktraceLimit)
|
||||
VALUE_DIAGOPT(ConstexprBacktraceLimit, 32, DefaultConstexprBacktraceLimit)
|
||||
/// Limit number of times to perform spell checking.
|
||||
VALUE_DIAGOPT(SpellCheckingLimit, 32, DefaultSpellCheckingLimit)
|
||||
/// Limit number of lines shown in a snippet.
|
||||
VALUE_DIAGOPT(SnippetLineLimit, 32, DefaultSnippetLineLimit)
|
||||
|
||||
VALUE_DIAGOPT(TabStop, 32, DefaultTabStop) /// The distance between tab stops.
|
||||
/// Column limit for formatting message diagnostics, or 0 if unused.
|
||||
|
@ -63,11 +63,15 @@ public:
|
||||
enum TextDiagnosticFormat { Clang, MSVC, Vi };
|
||||
|
||||
// Default values.
|
||||
enum { DefaultTabStop = 8, MaxTabStop = 100,
|
||||
enum {
|
||||
DefaultTabStop = 8,
|
||||
MaxTabStop = 100,
|
||||
DefaultMacroBacktraceLimit = 6,
|
||||
DefaultTemplateBacktraceLimit = 10,
|
||||
DefaultConstexprBacktraceLimit = 10,
|
||||
DefaultSpellCheckingLimit = 50 };
|
||||
DefaultSpellCheckingLimit = 50,
|
||||
DefaultSnippetLineLimit = 1,
|
||||
};
|
||||
|
||||
// Define simple diagnostic options (with no accessors).
|
||||
#define DIAGOPT(Name, Bits, Default) unsigned Name : Bits;
|
||||
|
@ -537,10 +537,10 @@ def err_maybe_falloff_nonvoid_block : Error<
|
||||
def err_falloff_nonvoid_block : Error<
|
||||
"control reaches end of non-void block">;
|
||||
def warn_maybe_falloff_nonvoid_coroutine : Warning<
|
||||
"control may reach end of non-void coroutine">,
|
||||
"control may reach end of coroutine; which is undefined behavior because the promise type %0 does not declare 'return_void()'">,
|
||||
InGroup<ReturnType>;
|
||||
def warn_falloff_nonvoid_coroutine : Warning<
|
||||
"control reaches end of non-void coroutine">,
|
||||
"control reaches end of coroutine; which is undefined behavior because the promise type %0 does not declare 'return_void()'">,
|
||||
InGroup<ReturnType>;
|
||||
def warn_suggest_noreturn_function : Warning<
|
||||
"%select{function|method}0 %1 could be declared with attribute 'noreturn'">,
|
||||
@ -1554,11 +1554,9 @@ def note_ivar_decl : Note<"instance variable is declared here">;
|
||||
def note_bitfield_decl : Note<"bit-field is declared here">;
|
||||
def note_implicit_param_decl : Note<"%0 is an implicit parameter">;
|
||||
def note_member_synthesized_at : Note<
|
||||
"implicit %select{default constructor|copy constructor|move constructor|copy "
|
||||
"assignment operator|move assignment operator|destructor}0 for %1 first "
|
||||
"required here">;
|
||||
def note_inhctor_synthesized_at : Note<
|
||||
"inherited constructor for %0 first required here">;
|
||||
"in implicit %select{default constructor|copy constructor|move constructor|"
|
||||
"copy assignment operator|move assignment operator|destructor}0 for %1 "
|
||||
"first required here">;
|
||||
def err_missing_default_ctor : Error<
|
||||
"%select{constructor for %1 must explicitly initialize the|"
|
||||
"implicit default constructor for %1 must explicitly initialize the|"
|
||||
@ -2769,6 +2767,7 @@ def warn_attribute_wrong_decl_type : Warning<
|
||||
"|types and namespaces"
|
||||
"|Objective-C interfaces"
|
||||
"|methods and properties"
|
||||
"|functions, methods, and properties"
|
||||
"|struct or union"
|
||||
"|struct, union or class"
|
||||
"|types"
|
||||
@ -2883,6 +2882,10 @@ def warn_partial_message : Warning<"%0 is partial: %1">,
|
||||
def warn_partial_fwdclass_message : Warning<
|
||||
"%0 may be partial because the receiver type is unknown">,
|
||||
InGroup<UnguardedAvailability>, DefaultIgnore;
|
||||
def warn_at_available_unchecked_use : Warning<
|
||||
"%select{@available|__builtin_available}0 does not guard availability here; "
|
||||
"use if (%select{@available|__builtin_available}0) instead">,
|
||||
InGroup<DiagGroup<"unsupported-availability-guard">>;
|
||||
|
||||
// Thread Safety Attributes
|
||||
def warn_invalid_capability_name : Warning<
|
||||
@ -6298,6 +6301,8 @@ def warn_ambiguous_suitable_delete_function_found : Warning<
|
||||
InGroup<DiagGroup<"ambiguous-delete">>;
|
||||
def note_member_declared_here : Note<
|
||||
"member %0 declared here">;
|
||||
def note_member_first_declared_here : Note<
|
||||
"member %0 first declared here">;
|
||||
def err_decrement_bool : Error<"cannot decrement expression of type bool">;
|
||||
def warn_increment_bool : Warning<
|
||||
"incrementing expression of type bool is deprecated and "
|
||||
@ -8009,10 +8014,13 @@ def err_block_on_nonlocal : Error<
|
||||
def err_block_on_vm : Error<
|
||||
"__block attribute not allowed on declaration with a variably modified type">;
|
||||
|
||||
def err_shufflevector_non_vector : Error<
|
||||
"first two arguments to __builtin_shufflevector must be vectors">;
|
||||
def err_shufflevector_incompatible_vector : Error<
|
||||
"first two arguments to __builtin_shufflevector must have the same type">;
|
||||
def err_vec_builtin_non_vector : Error<
|
||||
"first two arguments to %0 must be vectors">;
|
||||
def err_vec_builtin_incompatible_vector : Error<
|
||||
"first two arguments to %0 must have the same type">;
|
||||
def err_vsx_builtin_nonconstant_argument : Error<
|
||||
"argument %0 to %1 must be a 2-bit unsigned literal (i.e. 0, 1, 2 or 3)">;
|
||||
|
||||
def err_shufflevector_nonconstant_argument : Error<
|
||||
"index for __builtin_shufflevector must be a constant integer">;
|
||||
def err_shufflevector_argument_too_large : Error<
|
||||
@ -8899,8 +8907,6 @@ def note_equivalent_internal_linkage_decl : Note<
|
||||
|
||||
def note_redefinition_modules_same_file : Note<
|
||||
"'%0' included multiple times, additional include site in header from module '%1'">;
|
||||
def note_redefinition_modules_same_file_modulemap : Note<
|
||||
"consider adding '%0' as part of '%1' definition">;
|
||||
def note_redefinition_include_same_file : Note<
|
||||
"'%0' included multiple times, additional include site here">;
|
||||
}
|
||||
@ -8944,8 +8950,10 @@ def err_coroutine_promise_type_incomplete : Error<
|
||||
def err_coroutine_type_missing_specialization : Error<
|
||||
"this function cannot be a coroutine: missing definition of "
|
||||
"specialization %q0">;
|
||||
def err_coroutine_promise_return_ill_formed : Error<
|
||||
"%0 declares both 'return_value' and 'return_void'">;
|
||||
def err_coroutine_promise_incompatible_return_functions : Error<
|
||||
"the coroutine promise type %0 declares both 'return_value' and 'return_void'">;
|
||||
def err_coroutine_promise_requires_return_function : Error<
|
||||
"the coroutine promise type %0 must declare either 'return_value' or 'return_void'">;
|
||||
def note_coroutine_promise_implicit_await_transform_required_here : Note<
|
||||
"call to 'await_transform' implicitly required by 'co_await' here">;
|
||||
def note_coroutine_promise_suspend_implicitly_required : Note<
|
||||
@ -8958,11 +8966,19 @@ def warn_coroutine_promise_unhandled_exception_required_with_exceptions : Warnin
|
||||
InGroup<CoroutineMissingUnhandledException>;
|
||||
def err_coroutine_promise_get_return_object_on_allocation_failure : Error<
|
||||
"%0: 'get_return_object_on_allocation_failure()' must be a static member function">;
|
||||
def err_seh_in_a_coroutine_with_cxx_exceptions : Error<
|
||||
"cannot use SEH '__try' in a coroutine when C++ exceptions are enabled">;
|
||||
def err_coroutine_promise_new_requires_nothrow : Error<
|
||||
"%0 is required to have a non-throwing noexcept specification when the promise "
|
||||
"type declares 'get_return_object_on_allocation_failure()'">;
|
||||
def note_coroutine_promise_call_implicitly_required : Note<
|
||||
"call to %0 implicitly required by coroutine function here">;
|
||||
def err_await_suspend_invalid_return_type : Error<
|
||||
"the return type of 'await_suspend' is required to be 'void' or 'bool' (have %0)"
|
||||
>;
|
||||
def note_await_ready_no_bool_conversion : Note<
|
||||
"the return type of 'await_ready' is required to be contextually convertible to 'bool'"
|
||||
>;
|
||||
}
|
||||
|
||||
let CategoryName = "Documentation Issue" in {
|
||||
|
@ -1399,10 +1399,9 @@ public:
|
||||
/// specified by Loc.
|
||||
///
|
||||
/// If FilenameID is -1, it is considered to be unspecified.
|
||||
void AddLineNote(SourceLocation Loc, unsigned LineNo, int FilenameID);
|
||||
void AddLineNote(SourceLocation Loc, unsigned LineNo, int FilenameID,
|
||||
bool IsFileEntry, bool IsFileExit,
|
||||
bool IsSystemHeader, bool IsExternCHeader);
|
||||
SrcMgr::CharacteristicKind FileKind);
|
||||
|
||||
/// \brief Determine if the source manager has a line table.
|
||||
bool hasLineTable() const { return LineTable != nullptr; }
|
||||
|
@ -101,8 +101,6 @@ public:
|
||||
}
|
||||
unsigned getNumFilenames() const { return FilenamesByID.size(); }
|
||||
|
||||
void AddLineNote(FileID FID, unsigned Offset,
|
||||
unsigned LineNo, int FilenameID);
|
||||
void AddLineNote(FileID FID, unsigned Offset,
|
||||
unsigned LineNo, int FilenameID,
|
||||
unsigned EntryExit, SrcMgr::CharacteristicKind FileKind);
|
||||
|
@ -26,13 +26,21 @@ enum TemplateNameKind {
|
||||
TNK_Function_template,
|
||||
/// The name refers to a template whose specialization produces a
|
||||
/// type. The template itself could be a class template, template
|
||||
/// template parameter, or C++0x template alias.
|
||||
/// template parameter, or template alias.
|
||||
TNK_Type_template,
|
||||
/// The name refers to a variable template whose specialization produces a
|
||||
/// variable.
|
||||
TNK_Var_template,
|
||||
/// The name refers to a dependent template name. Whether the
|
||||
/// template name is assumed to refer to a type template or a
|
||||
/// The name refers to a dependent template name:
|
||||
/// \code
|
||||
/// template<typename MetaFun, typename T1, typename T2> struct apply2 {
|
||||
/// typedef typename MetaFun::template apply<T1, T2>::type type;
|
||||
/// };
|
||||
/// \endcode
|
||||
///
|
||||
/// Here, "apply" is a dependent template name within the typename
|
||||
/// specifier in the typedef. "apply" is a nested template, and
|
||||
/// whether the template name is assumed to refer to a type template or a
|
||||
/// function template depends on the context in which the template
|
||||
/// name occurs.
|
||||
TNK_Dependent_template_name
|
||||
|
@ -37,6 +37,7 @@ public:
|
||||
NONE,
|
||||
ALWAYS,
|
||||
NEVER,
|
||||
ALWAYS_ARG1,
|
||||
};
|
||||
|
||||
ImbueAttribute shouldImbueFunction(StringRef FunctionName) const;
|
||||
|
@ -172,6 +172,8 @@ def disable_llvm_optzns : Flag<["-"], "disable-llvm-optzns">,
|
||||
def disable_lifetimemarkers : Flag<["-"], "disable-lifetime-markers">,
|
||||
HelpText<"Disable lifetime-markers emission even when optimizations are "
|
||||
"enabled">;
|
||||
def disable_O0_optnone : Flag<["-"], "disable-O0-optnone">,
|
||||
HelpText<"Disable adding the optnone attribute to functions at O0">;
|
||||
def disable_red_zone : Flag<["-"], "disable-red-zone">,
|
||||
HelpText<"Do not emit code that uses the red zone.">;
|
||||
def dwarf_column_info : Flag<["-"], "dwarf-column-info">,
|
||||
@ -359,6 +361,9 @@ def fconstexpr_backtrace_limit : Separate<["-"], "fconstexpr-backtrace-limit">,
|
||||
HelpText<"Set the maximum number of entries to print in a constexpr evaluation backtrace (0 = no limit).">;
|
||||
def fspell_checking_limit : Separate<["-"], "fspell-checking-limit">, MetaVarName<"<N>">,
|
||||
HelpText<"Set the maximum number of times to perform spell checking on unrecognized identifiers (0 = no limit).">;
|
||||
def fcaret_diagnostics_max_lines :
|
||||
Separate<["-"], "fcaret-diagnostics-max-lines">, MetaVarName<"<N>">,
|
||||
HelpText<"Set the maximum number of source lines to show in a caret diagnostic">;
|
||||
def fmessage_length : Separate<["-"], "fmessage-length">, MetaVarName<"<N>">,
|
||||
HelpText<"Format message diagnostics so that they fit within N columns or fewer, when possible.">;
|
||||
def verify : Flag<["-"], "verify">,
|
||||
|
@ -469,6 +469,7 @@ def arch__errors__fatal : Flag<["-"], "arch_errors_fatal">;
|
||||
def arch : Separate<["-"], "arch">, Flags<[DriverOption]>;
|
||||
def arch__only : Separate<["-"], "arch_only">;
|
||||
def a : Joined<["-"], "a">;
|
||||
def autocomplete : Joined<["--"], "autocomplete=">;
|
||||
def bind__at__load : Flag<["-"], "bind_at_load">;
|
||||
def bundle__loader : Separate<["-"], "bundle_loader">;
|
||||
def bundle : Flag<["-"], "bundle">;
|
||||
@ -1740,6 +1741,7 @@ def mno_avx : Flag<["-"], "mno-avx">, Group<m_x86_Features_Group>;
|
||||
def mno_avx2 : Flag<["-"], "mno-avx2">, Group<m_x86_Features_Group>;
|
||||
def mno_avx512f : Flag<["-"], "mno-avx512f">, Group<m_x86_Features_Group>;
|
||||
def mno_avx512cd : Flag<["-"], "mno-avx512cd">, Group<m_x86_Features_Group>;
|
||||
def mno_avx512vpopcntdq : Flag<["-"], "mno-avx512vpopcntdq">, Group<m_x86_Features_Group>;
|
||||
def mno_avx512er : Flag<["-"], "mno-avx512er">, Group<m_x86_Features_Group>;
|
||||
def mno_avx512pf : Flag<["-"], "mno-avx512pf">, Group<m_x86_Features_Group>;
|
||||
def mno_avx512dq : Flag<["-"], "mno-avx512dq">, Group<m_x86_Features_Group>;
|
||||
@ -1940,6 +1942,7 @@ def mavx : Flag<["-"], "mavx">, Group<m_x86_Features_Group>;
|
||||
def mavx2 : Flag<["-"], "mavx2">, Group<m_x86_Features_Group>;
|
||||
def mavx512f : Flag<["-"], "mavx512f">, Group<m_x86_Features_Group>;
|
||||
def mavx512cd : Flag<["-"], "mavx512cd">, Group<m_x86_Features_Group>;
|
||||
def mavx512vpopcntdq : Flag<["-"], "mavx512vpopcntdq">, Group<m_x86_Features_Group>;
|
||||
def mavx512er : Flag<["-"], "mavx512er">, Group<m_x86_Features_Group>;
|
||||
def mavx512pf : Flag<["-"], "mavx512pf">, Group<m_x86_Features_Group>;
|
||||
def mavx512dq : Flag<["-"], "mavx512dq">, Group<m_x86_Features_Group>;
|
||||
|
@ -710,16 +710,35 @@ struct FormatStyle {
|
||||
/// \endcode
|
||||
bool BreakBeforeTernaryOperators;
|
||||
|
||||
/// \brief Always break constructor initializers before commas and align
|
||||
/// the commas with the colon.
|
||||
/// \code
|
||||
/// true: false:
|
||||
/// SomeClass::Constructor() vs. SomeClass::Constructor() : a(a),
|
||||
/// : a(a) b(b),
|
||||
/// , b(b) c(c) {}
|
||||
/// , c(c) {}
|
||||
/// \endcode
|
||||
bool BreakConstructorInitializersBeforeComma;
|
||||
/// \brief Different ways to break initializers.
|
||||
enum BreakConstructorInitializersStyle
|
||||
{
|
||||
/// Break constructor initializers before the colon and after the commas.
|
||||
/// \code
|
||||
/// Constructor()
|
||||
/// : initializer1(),
|
||||
/// initializer2()
|
||||
/// \endcode
|
||||
BCIS_BeforeColon,
|
||||
/// Break constructor initializers before the colon and commas, and align
|
||||
/// the commas with the colon.
|
||||
/// \code
|
||||
/// Constructor()
|
||||
/// : initializer1()
|
||||
/// , initializer2()
|
||||
/// \endcode
|
||||
BCIS_BeforeComma,
|
||||
/// Break constructor initializers after the colon and commas.
|
||||
/// \code
|
||||
/// Constructor() :
|
||||
/// initializer1(),
|
||||
/// initializer2()
|
||||
/// \endcode
|
||||
BCIS_AfterColon
|
||||
};
|
||||
|
||||
/// \brief The constructor initializers style to use..
|
||||
BreakConstructorInitializersStyle BreakConstructorInitializers;
|
||||
|
||||
/// \brief Break after each annotation on a field in Java files.
|
||||
/// \code{.java}
|
||||
@ -1390,8 +1409,7 @@ struct FormatStyle {
|
||||
BreakBeforeBinaryOperators == R.BreakBeforeBinaryOperators &&
|
||||
BreakBeforeBraces == R.BreakBeforeBraces &&
|
||||
BreakBeforeTernaryOperators == R.BreakBeforeTernaryOperators &&
|
||||
BreakConstructorInitializersBeforeComma ==
|
||||
R.BreakConstructorInitializersBeforeComma &&
|
||||
BreakConstructorInitializers == R.BreakConstructorInitializers &&
|
||||
BreakAfterJavaFieldAnnotations == R.BreakAfterJavaFieldAnnotations &&
|
||||
BreakStringLiterals == R.BreakStringLiterals &&
|
||||
ColumnLimit == R.ColumnLimit && CommentPragmas == R.CommentPragmas &&
|
||||
|
@ -59,6 +59,10 @@ class TargetInfo;
|
||||
class FrontendAction;
|
||||
class ASTDeserializationListener;
|
||||
|
||||
namespace vfs {
|
||||
class FileSystem;
|
||||
}
|
||||
|
||||
/// \brief Utility class for loading a ASTContext from an AST file.
|
||||
///
|
||||
class ASTUnit : public ModuleLoader {
|
||||
@ -420,7 +424,8 @@ private:
|
||||
explicit ASTUnit(bool MainFileIsAST);
|
||||
|
||||
bool Parse(std::shared_ptr<PCHContainerOperations> PCHContainerOps,
|
||||
std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer);
|
||||
std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer,
|
||||
IntrusiveRefCntPtr<vfs::FileSystem> VFS);
|
||||
|
||||
struct ComputedPreamble {
|
||||
llvm::MemoryBuffer *Buffer;
|
||||
@ -434,11 +439,13 @@ private:
|
||||
PreambleEndsAtStartOfLine(PreambleEndsAtStartOfLine) {}
|
||||
};
|
||||
ComputedPreamble ComputePreamble(CompilerInvocation &Invocation,
|
||||
unsigned MaxLines);
|
||||
unsigned MaxLines,
|
||||
IntrusiveRefCntPtr<vfs::FileSystem> VFS);
|
||||
|
||||
std::unique_ptr<llvm::MemoryBuffer> getMainBufferWithPrecompiledPreamble(
|
||||
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
|
||||
const CompilerInvocation &PreambleInvocationIn, bool AllowRebuild = true,
|
||||
const CompilerInvocation &PreambleInvocationIn,
|
||||
IntrusiveRefCntPtr<vfs::FileSystem> VFS, bool AllowRebuild = true,
|
||||
unsigned MaxLines = 0);
|
||||
void RealizeTopLevelDeclsFromPreamble();
|
||||
|
||||
@ -731,11 +738,17 @@ private:
|
||||
/// of this translation unit should be precompiled, to improve the performance
|
||||
/// of reparsing. Set to zero to disable preambles.
|
||||
///
|
||||
/// \param VFS - A vfs::FileSystem to be used for all file accesses. Note that
|
||||
/// preamble is saved to a temporary directory on a RealFileSystem, so in order
|
||||
/// for it to be loaded correctly, VFS should have access to it(i.e., be an
|
||||
/// overlay over RealFileSystem).
|
||||
///
|
||||
/// \returns \c true if a catastrophic failure occurred (which means that the
|
||||
/// \c ASTUnit itself is invalid), or \c false otherwise.
|
||||
bool LoadFromCompilerInvocation(
|
||||
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
|
||||
unsigned PrecompilePreambleAfterNParses);
|
||||
unsigned PrecompilePreambleAfterNParses,
|
||||
IntrusiveRefCntPtr<vfs::FileSystem> VFS);
|
||||
|
||||
public:
|
||||
|
||||
@ -826,6 +839,11 @@ public:
|
||||
/// (e.g. because the PCH could not be loaded), this accepts the ASTUnit
|
||||
/// mainly to allow the caller to see the diagnostics.
|
||||
///
|
||||
/// \param VFS - A vfs::FileSystem to be used for all file accesses. Note that
|
||||
/// preamble is saved to a temporary directory on a RealFileSystem, so in order
|
||||
/// for it to be loaded correctly, VFS should have access to it(i.e., be an
|
||||
/// overlay over RealFileSystem). RealFileSystem will be used if \p VFS is nullptr.
|
||||
///
|
||||
// FIXME: Move OnlyLocalDecls, UseBumpAllocator to setters on the ASTUnit, we
|
||||
// shouldn't need to specify them at construction time.
|
||||
static ASTUnit *LoadFromCommandLine(
|
||||
@ -842,15 +860,23 @@ public:
|
||||
bool AllowPCHWithCompilerErrors = false, bool SkipFunctionBodies = false,
|
||||
bool UserFilesAreVolatile = false, bool ForSerialization = false,
|
||||
llvm::Optional<StringRef> ModuleFormat = llvm::None,
|
||||
std::unique_ptr<ASTUnit> *ErrAST = nullptr);
|
||||
std::unique_ptr<ASTUnit> *ErrAST = nullptr,
|
||||
IntrusiveRefCntPtr<vfs::FileSystem> VFS = nullptr);
|
||||
|
||||
/// \brief Reparse the source files using the same command-line options that
|
||||
/// were originally used to produce this translation unit.
|
||||
///
|
||||
/// \param VFS - A vfs::FileSystem to be used for all file accesses. Note that
|
||||
/// preamble is saved to a temporary directory on a RealFileSystem, so in order
|
||||
/// for it to be loaded correctly, VFS should give an access to this(i.e. be an
|
||||
/// overlay over RealFileSystem). FileMgr->getVirtualFileSystem() will be used if
|
||||
/// \p VFS is nullptr.
|
||||
///
|
||||
/// \returns True if a failure occurred that causes the ASTUnit not to
|
||||
/// contain any translation-unit information, false otherwise.
|
||||
bool Reparse(std::shared_ptr<PCHContainerOperations> PCHContainerOps,
|
||||
ArrayRef<RemappedFile> RemappedFiles = None);
|
||||
ArrayRef<RemappedFile> RemappedFiles = None,
|
||||
IntrusiveRefCntPtr<vfs::FileSystem> VFS = nullptr);
|
||||
|
||||
/// \brief Perform code completion at the given file, line, and
|
||||
/// column within this translation unit.
|
||||
|
@ -53,6 +53,7 @@ CODEGENOPT(DisableLLVMPasses , 1, 0) ///< Don't run any LLVM IR passes to get
|
||||
///< the pristine IR generated by the
|
||||
///< frontend.
|
||||
CODEGENOPT(DisableLifetimeMarkers, 1, 0) ///< Don't emit any lifetime markers
|
||||
CODEGENOPT(DisableO0ImplyOptNone , 1, 0) ///< Don't annonate function with optnone at O0
|
||||
CODEGENOPT(ExperimentalNewPassManager, 1, 0) ///< Enables the new, experimental
|
||||
///< pass manager.
|
||||
CODEGENOPT(DisableRedZone , 1, 0) ///< Set when -mno-red-zone is enabled.
|
||||
|
@ -225,6 +225,11 @@ IntrusiveRefCntPtr<vfs::FileSystem>
|
||||
createVFSFromCompilerInvocation(const CompilerInvocation &CI,
|
||||
DiagnosticsEngine &Diags);
|
||||
|
||||
IntrusiveRefCntPtr<vfs::FileSystem>
|
||||
createVFSFromCompilerInvocation(const CompilerInvocation &CI,
|
||||
DiagnosticsEngine &Diags,
|
||||
IntrusiveRefCntPtr<vfs::FileSystem> BaseFS);
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
|
@ -257,6 +257,23 @@ private:
|
||||
/// resolved.
|
||||
Module *resolveModuleId(const ModuleId &Id, Module *Mod, bool Complain) const;
|
||||
|
||||
/// Resolve the given header directive to an actual header file.
|
||||
///
|
||||
/// \param M The module in which we're resolving the header directive.
|
||||
/// \param Header The header directive to resolve.
|
||||
/// \param RelativePathName Filled in with the relative path name from the
|
||||
/// module to the resolved header.
|
||||
/// \return The resolved file, if any.
|
||||
const FileEntry *resolveHeader(Module *M,
|
||||
Module::UnresolvedHeaderDirective Header,
|
||||
SmallVectorImpl<char> &RelativePathName);
|
||||
|
||||
/// Attempt to resolve the specified header directive as naming a builtin
|
||||
/// header.
|
||||
const FileEntry *
|
||||
resolveAsBuiltinHeader(Module *M, Module::UnresolvedHeaderDirective Header,
|
||||
SmallVectorImpl<char> &BuiltinPathName);
|
||||
|
||||
/// \brief Looks up the modules that \p File corresponds to.
|
||||
///
|
||||
/// If \p File represents a builtin header within Clang's builtin include
|
||||
|
@ -915,6 +915,7 @@ enum AttributeDeclKind {
|
||||
ExpectedTypeOrNamespace,
|
||||
ExpectedObjectiveCInterface,
|
||||
ExpectedMethodOrProperty,
|
||||
ExpectedFunctionOrMethodOrProperty,
|
||||
ExpectedStructOrUnion,
|
||||
ExpectedStructOrUnionOrClass,
|
||||
ExpectedType,
|
||||
|
@ -145,12 +145,15 @@ namespace clang {
|
||||
/// expressions, or template names, and the source locations for important
|
||||
/// tokens. All of the information about template arguments is allocated
|
||||
/// directly after this structure.
|
||||
struct TemplateIdAnnotation {
|
||||
struct TemplateIdAnnotation final
|
||||
: private llvm::TrailingObjects<TemplateIdAnnotation,
|
||||
ParsedTemplateArgument> {
|
||||
friend TrailingObjects;
|
||||
/// \brief The nested-name-specifier that precedes the template name.
|
||||
CXXScopeSpec SS;
|
||||
|
||||
/// TemplateKWLoc - The location of the template keyword within the
|
||||
/// source.
|
||||
/// TemplateKWLoc - The location of the template keyword.
|
||||
/// For e.g. typename T::template Y<U>
|
||||
SourceLocation TemplateKWLoc;
|
||||
|
||||
/// TemplateNameLoc - The location of the template name within the
|
||||
@ -183,34 +186,56 @@ namespace clang {
|
||||
|
||||
/// \brief Retrieves a pointer to the template arguments
|
||||
ParsedTemplateArgument *getTemplateArgs() {
|
||||
return reinterpret_cast<ParsedTemplateArgument *>(this + 1);
|
||||
return getTrailingObjects<ParsedTemplateArgument>();
|
||||
}
|
||||
|
||||
/// \brief Creates a new TemplateIdAnnotation with NumArgs arguments and
|
||||
/// appends it to List.
|
||||
static TemplateIdAnnotation *
|
||||
Allocate(unsigned NumArgs, SmallVectorImpl<TemplateIdAnnotation*> &List) {
|
||||
TemplateIdAnnotation *TemplateId
|
||||
= (TemplateIdAnnotation *)std::malloc(sizeof(TemplateIdAnnotation) +
|
||||
sizeof(ParsedTemplateArgument) * NumArgs);
|
||||
TemplateId->NumArgs = NumArgs;
|
||||
|
||||
// Default-construct nested-name-specifier.
|
||||
new (&TemplateId->SS) CXXScopeSpec();
|
||||
|
||||
// Default-construct parsed template arguments.
|
||||
ParsedTemplateArgument *TemplateArgs = TemplateId->getTemplateArgs();
|
||||
for (unsigned I = 0; I != NumArgs; ++I)
|
||||
new (TemplateArgs + I) ParsedTemplateArgument();
|
||||
|
||||
List.push_back(TemplateId);
|
||||
Create(CXXScopeSpec SS, SourceLocation TemplateKWLoc,
|
||||
SourceLocation TemplateNameLoc, IdentifierInfo *Name,
|
||||
OverloadedOperatorKind OperatorKind,
|
||||
ParsedTemplateTy OpaqueTemplateName, TemplateNameKind TemplateKind,
|
||||
SourceLocation LAngleLoc, SourceLocation RAngleLoc,
|
||||
ArrayRef<ParsedTemplateArgument> TemplateArgs,
|
||||
SmallVectorImpl<TemplateIdAnnotation *> &CleanupList) {
|
||||
|
||||
TemplateIdAnnotation *TemplateId = new (std::malloc(
|
||||
totalSizeToAlloc<ParsedTemplateArgument>(TemplateArgs.size())))
|
||||
TemplateIdAnnotation(SS, TemplateKWLoc, TemplateNameLoc, Name,
|
||||
OperatorKind, OpaqueTemplateName, TemplateKind,
|
||||
LAngleLoc, RAngleLoc, TemplateArgs);
|
||||
CleanupList.push_back(TemplateId);
|
||||
return TemplateId;
|
||||
}
|
||||
|
||||
void Destroy() {
|
||||
SS.~CXXScopeSpec();
|
||||
|
||||
void Destroy() {
|
||||
std::for_each(
|
||||
getTemplateArgs(), getTemplateArgs() + NumArgs,
|
||||
[](ParsedTemplateArgument &A) { A.~ParsedTemplateArgument(); });
|
||||
this->~TemplateIdAnnotation();
|
||||
free(this);
|
||||
}
|
||||
private:
|
||||
TemplateIdAnnotation(const TemplateIdAnnotation &) = delete;
|
||||
|
||||
TemplateIdAnnotation(CXXScopeSpec SS, SourceLocation TemplateKWLoc,
|
||||
SourceLocation TemplateNameLoc, IdentifierInfo *Name,
|
||||
OverloadedOperatorKind OperatorKind,
|
||||
ParsedTemplateTy OpaqueTemplateName,
|
||||
TemplateNameKind TemplateKind,
|
||||
SourceLocation LAngleLoc, SourceLocation RAngleLoc,
|
||||
ArrayRef<ParsedTemplateArgument> TemplateArgs) noexcept
|
||||
: SS(SS), TemplateKWLoc(TemplateKWLoc),
|
||||
TemplateNameLoc(TemplateNameLoc), Name(Name), Operator(OperatorKind),
|
||||
Template(OpaqueTemplateName), Kind(TemplateKind),
|
||||
LAngleLoc(LAngleLoc), RAngleLoc(RAngleLoc),
|
||||
NumArgs(TemplateArgs.size()) {
|
||||
|
||||
std::uninitialized_copy(TemplateArgs.begin(), TemplateArgs.end(),
|
||||
getTemplateArgs());
|
||||
}
|
||||
~TemplateIdAnnotation() = default;
|
||||
};
|
||||
|
||||
/// Retrieves the range of the given template parameter lists.
|
||||
|
@ -388,6 +388,8 @@ public:
|
||||
(HasBranchProtectedScope && HasBranchIntoScope));
|
||||
}
|
||||
|
||||
bool isCoroutine() const { return !FirstCoroutineStmtLoc.isInvalid(); }
|
||||
|
||||
void setFirstCoroutineStmt(SourceLocation Loc, StringRef Keyword) {
|
||||
assert(FirstCoroutineStmtLoc.isInvalid() &&
|
||||
"first coroutine statement location already set");
|
||||
|
@ -689,17 +689,37 @@ public:
|
||||
class SynthesizedFunctionScope {
|
||||
Sema &S;
|
||||
Sema::ContextRAII SavedContext;
|
||||
bool PushedCodeSynthesisContext = false;
|
||||
|
||||
public:
|
||||
SynthesizedFunctionScope(Sema &S, DeclContext *DC)
|
||||
: S(S), SavedContext(S, DC)
|
||||
{
|
||||
: S(S), SavedContext(S, DC) {
|
||||
S.PushFunctionScope();
|
||||
S.PushExpressionEvaluationContext(
|
||||
Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
|
||||
if (auto *FD = dyn_cast<FunctionDecl>(DC))
|
||||
FD->setWillHaveBody(true);
|
||||
else
|
||||
assert(isa<ObjCMethodDecl>(DC));
|
||||
}
|
||||
|
||||
void addContextNote(SourceLocation UseLoc) {
|
||||
assert(!PushedCodeSynthesisContext);
|
||||
|
||||
Sema::CodeSynthesisContext Ctx;
|
||||
Ctx.Kind = Sema::CodeSynthesisContext::DefiningSynthesizedFunction;
|
||||
Ctx.PointOfInstantiation = UseLoc;
|
||||
Ctx.Entity = cast<Decl>(S.CurContext);
|
||||
S.pushCodeSynthesisContext(Ctx);
|
||||
|
||||
PushedCodeSynthesisContext = true;
|
||||
}
|
||||
|
||||
~SynthesizedFunctionScope() {
|
||||
if (PushedCodeSynthesisContext)
|
||||
S.popCodeSynthesisContext();
|
||||
if (auto *FD = dyn_cast<FunctionDecl>(S.CurContext))
|
||||
FD->setWillHaveBody(false);
|
||||
S.PopExpressionEvaluationContext();
|
||||
S.PopFunctionScopeInfo();
|
||||
}
|
||||
@ -2727,7 +2747,7 @@ public:
|
||||
/// of a function.
|
||||
///
|
||||
/// Returns true if any errors were emitted.
|
||||
bool diagnoseArgIndependentDiagnoseIfAttrs(const FunctionDecl *Function,
|
||||
bool diagnoseArgIndependentDiagnoseIfAttrs(const NamedDecl *ND,
|
||||
SourceLocation Loc);
|
||||
|
||||
/// Returns whether the given function's address can be taken or not,
|
||||
@ -6974,6 +6994,10 @@ public:
|
||||
|
||||
/// We are declaring an implicit special member function.
|
||||
DeclaringSpecialMember,
|
||||
|
||||
/// We are defining a synthesized function (such as a defaulted special
|
||||
/// member).
|
||||
DefiningSynthesizedFunction,
|
||||
} Kind;
|
||||
|
||||
/// \brief Was the enclosing context a non-instantiation SFINAE context?
|
||||
@ -10121,6 +10145,7 @@ private:
|
||||
bool SemaBuiltinVAStartARM(CallExpr *Call);
|
||||
bool SemaBuiltinUnorderedCompare(CallExpr *TheCall);
|
||||
bool SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs);
|
||||
bool SemaBuiltinVSX(CallExpr *TheCall);
|
||||
bool SemaBuiltinOSLogFormat(CallExpr *TheCall);
|
||||
|
||||
public:
|
||||
|
@ -60,16 +60,6 @@ struct CompileCommand {
|
||||
|
||||
/// The output file associated with the command.
|
||||
std::string Output;
|
||||
|
||||
/// \brief An optional mapping from each file's path to its content for all
|
||||
/// files needed for the compilation that are not available via the file
|
||||
/// system.
|
||||
///
|
||||
/// Note that a tool implementation is required to fall back to the file
|
||||
/// system if a source file is not provided in the mapped sources, as
|
||||
/// compilation databases will usually not provide all files in mapped sources
|
||||
/// for performance reasons.
|
||||
std::vector<std::pair<std::string, std::string> > MappedSources;
|
||||
};
|
||||
|
||||
/// \brief Interface for compilation databases.
|
||||
@ -186,10 +176,11 @@ public:
|
||||
/// the number of arguments before "--", if "--" was found in the argument
|
||||
/// list.
|
||||
/// \param Argv Points to the command line arguments.
|
||||
/// \param ErrorMsg Contains error text if the function returns null pointer.
|
||||
/// \param Directory The base directory used in the FixedCompilationDatabase.
|
||||
static FixedCompilationDatabase *loadFromCommandLine(int &Argc,
|
||||
const char *const *Argv,
|
||||
Twine Directory = ".");
|
||||
static std::unique_ptr<FixedCompilationDatabase> loadFromCommandLine(
|
||||
int &Argc, const char *const *Argv, std::string &ErrorMsg,
|
||||
Twine Directory = ".");
|
||||
|
||||
/// \brief Constructs a compilation data base from a specified directory
|
||||
/// and command line.
|
||||
|
@ -274,9 +274,17 @@ void Decl::setLexicalDeclContext(DeclContext *DC) {
|
||||
} else {
|
||||
getMultipleDC()->LexicalDC = DC;
|
||||
}
|
||||
Hidden = cast<Decl>(DC)->Hidden;
|
||||
if (Hidden && !isFromASTFile() && hasLocalOwningModuleStorage())
|
||||
setLocalOwningModule(cast<Decl>(DC)->getOwningModule());
|
||||
|
||||
// FIXME: We shouldn't be changing the lexical context of declarations
|
||||
// imported from AST files.
|
||||
if (!isFromASTFile()) {
|
||||
Hidden = cast<Decl>(DC)->Hidden && hasLocalOwningModuleStorage();
|
||||
if (Hidden)
|
||||
setLocalOwningModule(cast<Decl>(DC)->getOwningModule());
|
||||
}
|
||||
|
||||
assert((!Hidden || getOwningModule()) &&
|
||||
"hidden declaration has no owning module");
|
||||
}
|
||||
|
||||
void Decl::setDeclContextsImpl(DeclContext *SemaDC, DeclContext *LexicalDC,
|
||||
@ -440,8 +448,8 @@ const Attr *Decl::getDefiningAttr() const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
StringRef getRealizedPlatform(const AvailabilityAttr *A,
|
||||
const ASTContext &Context) {
|
||||
static StringRef getRealizedPlatform(const AvailabilityAttr *A,
|
||||
const ASTContext &Context) {
|
||||
// Check if this is an App Extension "platform", and if so chop off
|
||||
// the suffix for matching with the actual platform.
|
||||
StringRef RealizedPlatform = A->getPlatform()->getName();
|
||||
|
@ -1230,8 +1230,7 @@ namespace {
|
||||
IsNullPtr = V.isNullPointer();
|
||||
}
|
||||
|
||||
void set(APValue::LValueBase B, unsigned I = 0, bool BInvalid = false,
|
||||
bool IsNullPtr_ = false, uint64_t Offset_ = 0) {
|
||||
void set(APValue::LValueBase B, unsigned I = 0, bool BInvalid = false) {
|
||||
#ifndef NDEBUG
|
||||
// We only allow a few types of invalid bases. Enforce that here.
|
||||
if (BInvalid) {
|
||||
@ -1242,11 +1241,20 @@ namespace {
|
||||
#endif
|
||||
|
||||
Base = B;
|
||||
Offset = CharUnits::fromQuantity(Offset_);
|
||||
Offset = CharUnits::fromQuantity(0);
|
||||
InvalidBase = BInvalid;
|
||||
CallIndex = I;
|
||||
Designator = SubobjectDesignator(getType(B));
|
||||
IsNullPtr = IsNullPtr_;
|
||||
IsNullPtr = false;
|
||||
}
|
||||
|
||||
void setNull(QualType PointerTy, uint64_t TargetVal) {
|
||||
Base = (Expr *)nullptr;
|
||||
Offset = CharUnits::fromQuantity(TargetVal);
|
||||
InvalidBase = false;
|
||||
CallIndex = 0;
|
||||
Designator = SubobjectDesignator(PointerTy->getPointeeType());
|
||||
IsNullPtr = true;
|
||||
}
|
||||
|
||||
void setInvalid(APValue::LValueBase B, unsigned I = 0) {
|
||||
@ -5494,8 +5502,8 @@ public:
|
||||
return true;
|
||||
}
|
||||
bool ZeroInitialization(const Expr *E) {
|
||||
auto Offset = Info.Ctx.getTargetNullPointerValue(E->getType());
|
||||
Result.set((Expr*)nullptr, 0, false, true, Offset);
|
||||
auto TargetVal = Info.Ctx.getTargetNullPointerValue(E->getType());
|
||||
Result.setNull(E->getType(), TargetVal);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1689,6 +1689,8 @@ void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T, Qualifiers,
|
||||
// ::= _N # bool
|
||||
// _O # <array in parameter>
|
||||
// ::= _T # __float80 (Intel)
|
||||
// ::= _S # char16_t
|
||||
// ::= _U # char32_t
|
||||
// ::= _W # wchar_t
|
||||
// ::= _Z # __float80 (Digital Mars)
|
||||
switch (T->getKind()) {
|
||||
|
@ -88,7 +88,7 @@ const VarDecl *CXXForRangeStmt::getLoopVariable() const {
|
||||
}
|
||||
|
||||
CoroutineBodyStmt *CoroutineBodyStmt::Create(
|
||||
const ASTContext &C, CoroutineBodyStmt::CtorArgs const& Args) {
|
||||
const ASTContext &C, CoroutineBodyStmt::CtorArgs const &Args) {
|
||||
std::size_t Size = totalSizeToAlloc<Stmt *>(
|
||||
CoroutineBodyStmt::FirstParamMove + Args.ParamMoves.size());
|
||||
|
||||
@ -108,6 +108,8 @@ CoroutineBodyStmt::CoroutineBodyStmt(CoroutineBodyStmt::CtorArgs const &Args)
|
||||
SubStmts[CoroutineBodyStmt::Allocate] = Args.Allocate;
|
||||
SubStmts[CoroutineBodyStmt::Deallocate] = Args.Deallocate;
|
||||
SubStmts[CoroutineBodyStmt::ReturnValue] = Args.ReturnValue;
|
||||
SubStmts[CoroutineBodyStmt::ResultDecl] = Args.ResultDecl;
|
||||
SubStmts[CoroutineBodyStmt::ReturnStmt] = Args.ReturnStmt;
|
||||
SubStmts[CoroutineBodyStmt::ReturnStmtOnAllocFailure] =
|
||||
Args.ReturnStmtOnAllocFailure;
|
||||
std::copy(Args.ParamMoves.begin(), Args.ParamMoves.end(),
|
||||
|
@ -92,6 +92,8 @@ Stmt *AnalysisDeclContext::getBody(bool &IsAutosynthesized) const {
|
||||
IsAutosynthesized = false;
|
||||
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
|
||||
Stmt *Body = FD->getBody();
|
||||
if (auto *CoroBody = dyn_cast_or_null<CoroutineBodyStmt>(Body))
|
||||
Body = CoroBody->getBody();
|
||||
if (Manager && Manager->synthesizeBodies()) {
|
||||
Stmt *SynthesizedBody =
|
||||
getBodyFarm(getASTContext(), Manager->Injector.get()).getBody(FD);
|
||||
|
@ -64,6 +64,7 @@ static bool hasFeature(StringRef Feature, const LangOptions &LangOpts,
|
||||
bool HasFeature = llvm::StringSwitch<bool>(Feature)
|
||||
.Case("altivec", LangOpts.AltiVec)
|
||||
.Case("blocks", LangOpts.Blocks)
|
||||
.Case("coroutines", LangOpts.CoroutinesTS)
|
||||
.Case("cplusplus", LangOpts.CPlusPlus)
|
||||
.Case("cplusplus11", LangOpts.CPlusPlus11)
|
||||
.Case("freestanding", LangOpts.Freestanding)
|
||||
|
@ -183,48 +183,22 @@ unsigned LineTableInfo::getLineTableFilenameID(StringRef Name) {
|
||||
return IterBool.first->second;
|
||||
}
|
||||
|
||||
/// AddLineNote - Add a line note to the line table that indicates that there
|
||||
/// is a \#line at the specified FID/Offset location which changes the presumed
|
||||
/// location to LineNo/FilenameID.
|
||||
void LineTableInfo::AddLineNote(FileID FID, unsigned Offset,
|
||||
unsigned LineNo, int FilenameID) {
|
||||
std::vector<LineEntry> &Entries = LineEntries[FID];
|
||||
|
||||
assert((Entries.empty() || Entries.back().FileOffset < Offset) &&
|
||||
"Adding line entries out of order!");
|
||||
|
||||
SrcMgr::CharacteristicKind Kind = SrcMgr::C_User;
|
||||
unsigned IncludeOffset = 0;
|
||||
|
||||
if (!Entries.empty()) {
|
||||
// If this is a '#line 4' after '#line 42 "foo.h"', make sure to remember
|
||||
// that we are still in "foo.h".
|
||||
if (FilenameID == -1)
|
||||
FilenameID = Entries.back().FilenameID;
|
||||
|
||||
// If we are after a line marker that switched us to system header mode, or
|
||||
// that set #include information, preserve it.
|
||||
Kind = Entries.back().FileKind;
|
||||
IncludeOffset = Entries.back().IncludeOffset;
|
||||
}
|
||||
|
||||
Entries.push_back(LineEntry::get(Offset, LineNo, FilenameID, Kind,
|
||||
IncludeOffset));
|
||||
}
|
||||
|
||||
/// AddLineNote This is the same as the previous version of AddLineNote, but is
|
||||
/// used for GNU line markers. If EntryExit is 0, then this doesn't change the
|
||||
/// presumed \#include stack. If it is 1, this is a file entry, if it is 2 then
|
||||
/// this is a file exit. FileKind specifies whether this is a system header or
|
||||
/// extern C system header.
|
||||
void LineTableInfo::AddLineNote(FileID FID, unsigned Offset,
|
||||
unsigned LineNo, int FilenameID,
|
||||
unsigned EntryExit,
|
||||
/// Add a line note to the line table that indicates that there is a \#line or
|
||||
/// GNU line marker at the specified FID/Offset location which changes the
|
||||
/// presumed location to LineNo/FilenameID. If EntryExit is 0, then this doesn't
|
||||
/// change the presumed \#include stack. If it is 1, this is a file entry, if
|
||||
/// it is 2 then this is a file exit. FileKind specifies whether this is a
|
||||
/// system header or extern C system header.
|
||||
void LineTableInfo::AddLineNote(FileID FID, unsigned Offset, unsigned LineNo,
|
||||
int FilenameID, unsigned EntryExit,
|
||||
SrcMgr::CharacteristicKind FileKind) {
|
||||
assert(FilenameID != -1 && "Unspecified filename should use other accessor");
|
||||
|
||||
std::vector<LineEntry> &Entries = LineEntries[FID];
|
||||
|
||||
// An unspecified FilenameID means use the last filename if available, or the
|
||||
// main source file otherwise.
|
||||
if (FilenameID == -1 && !Entries.empty())
|
||||
FilenameID = Entries.back().FilenameID;
|
||||
|
||||
assert((Entries.empty() || Entries.back().FileOffset < Offset) &&
|
||||
"Adding line entries out of order!");
|
||||
|
||||
@ -281,47 +255,20 @@ unsigned SourceManager::getLineTableFilenameID(StringRef Name) {
|
||||
return getLineTable().getLineTableFilenameID(Name);
|
||||
}
|
||||
|
||||
|
||||
/// AddLineNote - Add a line note to the line table for the FileID and offset
|
||||
/// specified by Loc. If FilenameID is -1, it is considered to be
|
||||
/// unspecified.
|
||||
void SourceManager::AddLineNote(SourceLocation Loc, unsigned LineNo,
|
||||
int FilenameID) {
|
||||
std::pair<FileID, unsigned> LocInfo = getDecomposedExpansionLoc(Loc);
|
||||
|
||||
bool Invalid = false;
|
||||
const SLocEntry &Entry = getSLocEntry(LocInfo.first, &Invalid);
|
||||
if (!Entry.isFile() || Invalid)
|
||||
return;
|
||||
|
||||
const SrcMgr::FileInfo &FileInfo = Entry.getFile();
|
||||
|
||||
// Remember that this file has #line directives now if it doesn't already.
|
||||
const_cast<SrcMgr::FileInfo&>(FileInfo).setHasLineDirectives();
|
||||
|
||||
getLineTable().AddLineNote(LocInfo.first, LocInfo.second, LineNo, FilenameID);
|
||||
}
|
||||
|
||||
/// AddLineNote - Add a GNU line marker to the line table.
|
||||
void SourceManager::AddLineNote(SourceLocation Loc, unsigned LineNo,
|
||||
int FilenameID, bool IsFileEntry,
|
||||
bool IsFileExit, bool IsSystemHeader,
|
||||
bool IsExternCHeader) {
|
||||
// If there is no filename and no flags, this is treated just like a #line,
|
||||
// which does not change the flags of the previous line marker.
|
||||
if (FilenameID == -1) {
|
||||
assert(!IsFileEntry && !IsFileExit && !IsSystemHeader && !IsExternCHeader &&
|
||||
"Can't set flags without setting the filename!");
|
||||
return AddLineNote(Loc, LineNo, FilenameID);
|
||||
}
|
||||
|
||||
bool IsFileExit,
|
||||
SrcMgr::CharacteristicKind FileKind) {
|
||||
std::pair<FileID, unsigned> LocInfo = getDecomposedExpansionLoc(Loc);
|
||||
|
||||
bool Invalid = false;
|
||||
const SLocEntry &Entry = getSLocEntry(LocInfo.first, &Invalid);
|
||||
if (!Entry.isFile() || Invalid)
|
||||
return;
|
||||
|
||||
|
||||
const SrcMgr::FileInfo &FileInfo = Entry.getFile();
|
||||
|
||||
// Remember that this file has #line directives now if it doesn't already.
|
||||
@ -329,14 +276,6 @@ void SourceManager::AddLineNote(SourceLocation Loc, unsigned LineNo,
|
||||
|
||||
(void) getLineTable();
|
||||
|
||||
SrcMgr::CharacteristicKind FileKind;
|
||||
if (IsExternCHeader)
|
||||
FileKind = SrcMgr::C_ExternCSystem;
|
||||
else if (IsSystemHeader)
|
||||
FileKind = SrcMgr::C_System;
|
||||
else
|
||||
FileKind = SrcMgr::C_User;
|
||||
|
||||
unsigned EntryExit = 0;
|
||||
if (IsFileEntry)
|
||||
EntryExit = 1;
|
||||
|
@ -2169,15 +2169,20 @@ public:
|
||||
: DataLayoutStringR600);
|
||||
assert(DataLayout->getAllocaAddrSpace() == AS.Private);
|
||||
|
||||
AddrSpaceMap =
|
||||
llvm::StringSwitch<const LangAS::Map *>(Triple.getEnvironmentName())
|
||||
.Case("opencl", &AMDGPUOpenCLPrivateIsZeroMap)
|
||||
.Case("amdgiz", &AMDGPUNonOpenCLGenericIsZeroMap)
|
||||
.Case("amdgizcl", &AMDGPUOpenCLGenericIsZeroMap)
|
||||
.Default(&AMDGPUNonOpenCLPrivateIsZeroMap);
|
||||
UseAddrSpaceMapMangling = true;
|
||||
}
|
||||
|
||||
void adjust(LangOptions &Opts) override {
|
||||
TargetInfo::adjust(Opts);
|
||||
if (isGenericZero(getTriple())) {
|
||||
AddrSpaceMap = Opts.OpenCL ? &AMDGPUOpenCLGenericIsZeroMap
|
||||
: &AMDGPUNonOpenCLGenericIsZeroMap;
|
||||
} else {
|
||||
AddrSpaceMap = Opts.OpenCL ? &AMDGPUOpenCLPrivateIsZeroMap
|
||||
: &AMDGPUNonOpenCLPrivateIsZeroMap;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t getPointerWidthV(unsigned AddrSpace) const override {
|
||||
if (GPU <= GK_CAYMAN)
|
||||
return 32;
|
||||
@ -2619,6 +2624,7 @@ class X86TargetInfo : public TargetInfo {
|
||||
bool HasFMA = false;
|
||||
bool HasF16C = false;
|
||||
bool HasAVX512CD = false;
|
||||
bool HasAVX512VPOPCNTDQ = false;
|
||||
bool HasAVX512ER = false;
|
||||
bool HasAVX512PF = false;
|
||||
bool HasAVX512DQ = false;
|
||||
@ -3435,23 +3441,32 @@ void X86TargetInfo::setSSELevel(llvm::StringMap<bool> &Features,
|
||||
switch (Level) {
|
||||
case AVX512F:
|
||||
Features["avx512f"] = true;
|
||||
LLVM_FALLTHROUGH;
|
||||
case AVX2:
|
||||
Features["avx2"] = true;
|
||||
LLVM_FALLTHROUGH;
|
||||
case AVX:
|
||||
Features["avx"] = true;
|
||||
Features["xsave"] = true;
|
||||
LLVM_FALLTHROUGH;
|
||||
case SSE42:
|
||||
Features["sse4.2"] = true;
|
||||
LLVM_FALLTHROUGH;
|
||||
case SSE41:
|
||||
Features["sse4.1"] = true;
|
||||
LLVM_FALLTHROUGH;
|
||||
case SSSE3:
|
||||
Features["ssse3"] = true;
|
||||
LLVM_FALLTHROUGH;
|
||||
case SSE3:
|
||||
Features["sse3"] = true;
|
||||
LLVM_FALLTHROUGH;
|
||||
case SSE2:
|
||||
Features["sse2"] = true;
|
||||
LLVM_FALLTHROUGH;
|
||||
case SSE1:
|
||||
Features["sse"] = true;
|
||||
LLVM_FALLTHROUGH;
|
||||
case NoSSE:
|
||||
break;
|
||||
}
|
||||
@ -3462,29 +3477,37 @@ void X86TargetInfo::setSSELevel(llvm::StringMap<bool> &Features,
|
||||
case NoSSE:
|
||||
case SSE1:
|
||||
Features["sse"] = false;
|
||||
LLVM_FALLTHROUGH;
|
||||
case SSE2:
|
||||
Features["sse2"] = Features["pclmul"] = Features["aes"] =
|
||||
Features["sha"] = false;
|
||||
LLVM_FALLTHROUGH;
|
||||
case SSE3:
|
||||
Features["sse3"] = false;
|
||||
setXOPLevel(Features, NoXOP, false);
|
||||
LLVM_FALLTHROUGH;
|
||||
case SSSE3:
|
||||
Features["ssse3"] = false;
|
||||
LLVM_FALLTHROUGH;
|
||||
case SSE41:
|
||||
Features["sse4.1"] = false;
|
||||
LLVM_FALLTHROUGH;
|
||||
case SSE42:
|
||||
Features["sse4.2"] = false;
|
||||
LLVM_FALLTHROUGH;
|
||||
case AVX:
|
||||
Features["fma"] = Features["avx"] = Features["f16c"] = Features["xsave"] =
|
||||
Features["xsaveopt"] = false;
|
||||
setXOPLevel(Features, FMA4, false);
|
||||
LLVM_FALLTHROUGH;
|
||||
case AVX2:
|
||||
Features["avx2"] = false;
|
||||
LLVM_FALLTHROUGH;
|
||||
case AVX512F:
|
||||
Features["avx512f"] = Features["avx512cd"] = Features["avx512er"] =
|
||||
Features["avx512pf"] = Features["avx512dq"] = Features["avx512bw"] =
|
||||
Features["avx512vl"] = Features["avx512vbmi"] =
|
||||
Features["avx512ifma"] = false;
|
||||
Features["avx512pf"] = Features["avx512dq"] = Features["avx512bw"] =
|
||||
Features["avx512vl"] = Features["avx512vbmi"] =
|
||||
Features["avx512ifma"] = Features["avx512vpopcntdq"] = false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -3494,10 +3517,13 @@ void X86TargetInfo::setMMXLevel(llvm::StringMap<bool> &Features,
|
||||
switch (Level) {
|
||||
case AMD3DNowAthlon:
|
||||
Features["3dnowa"] = true;
|
||||
LLVM_FALLTHROUGH;
|
||||
case AMD3DNow:
|
||||
Features["3dnow"] = true;
|
||||
LLVM_FALLTHROUGH;
|
||||
case MMX:
|
||||
Features["mmx"] = true;
|
||||
LLVM_FALLTHROUGH;
|
||||
case NoMMX3DNow:
|
||||
break;
|
||||
}
|
||||
@ -3508,8 +3534,10 @@ void X86TargetInfo::setMMXLevel(llvm::StringMap<bool> &Features,
|
||||
case NoMMX3DNow:
|
||||
case MMX:
|
||||
Features["mmx"] = false;
|
||||
LLVM_FALLTHROUGH;
|
||||
case AMD3DNow:
|
||||
Features["3dnow"] = false;
|
||||
LLVM_FALLTHROUGH;
|
||||
case AMD3DNowAthlon:
|
||||
Features["3dnowa"] = false;
|
||||
}
|
||||
@ -3521,12 +3549,15 @@ void X86TargetInfo::setXOPLevel(llvm::StringMap<bool> &Features, XOPEnum Level,
|
||||
switch (Level) {
|
||||
case XOP:
|
||||
Features["xop"] = true;
|
||||
LLVM_FALLTHROUGH;
|
||||
case FMA4:
|
||||
Features["fma4"] = true;
|
||||
setSSELevel(Features, AVX, true);
|
||||
LLVM_FALLTHROUGH;
|
||||
case SSE4A:
|
||||
Features["sse4a"] = true;
|
||||
setSSELevel(Features, SSE3, true);
|
||||
LLVM_FALLTHROUGH;
|
||||
case NoXOP:
|
||||
break;
|
||||
}
|
||||
@ -3537,8 +3568,10 @@ void X86TargetInfo::setXOPLevel(llvm::StringMap<bool> &Features, XOPEnum Level,
|
||||
case NoXOP:
|
||||
case SSE4A:
|
||||
Features["sse4a"] = false;
|
||||
LLVM_FALLTHROUGH;
|
||||
case FMA4:
|
||||
Features["fma4"] = false;
|
||||
LLVM_FALLTHROUGH;
|
||||
case XOP:
|
||||
Features["xop"] = false;
|
||||
}
|
||||
@ -3584,7 +3617,8 @@ void X86TargetInfo::setFeatureEnabledImpl(llvm::StringMap<bool> &Features,
|
||||
setSSELevel(Features, AVX512F, Enabled);
|
||||
} else if (Name == "avx512cd" || Name == "avx512er" || Name == "avx512pf" ||
|
||||
Name == "avx512dq" || Name == "avx512bw" || Name == "avx512vl" ||
|
||||
Name == "avx512vbmi" || Name == "avx512ifma") {
|
||||
Name == "avx512vbmi" || Name == "avx512ifma" ||
|
||||
Name == "avx512vpopcntdq") {
|
||||
if (Enabled)
|
||||
setSSELevel(Features, AVX512F, Enabled);
|
||||
// Enable BWI instruction if VBMI is being enabled.
|
||||
@ -3668,6 +3702,8 @@ bool X86TargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
|
||||
HasF16C = true;
|
||||
} else if (Feature == "+avx512cd") {
|
||||
HasAVX512CD = true;
|
||||
} else if (Feature == "+avx512vpopcntdq") {
|
||||
HasAVX512VPOPCNTDQ = true;
|
||||
} else if (Feature == "+avx512er") {
|
||||
HasAVX512ER = true;
|
||||
} else if (Feature == "+avx512pf") {
|
||||
@ -3986,10 +4022,13 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
|
||||
switch (XOPLevel) {
|
||||
case XOP:
|
||||
Builder.defineMacro("__XOP__");
|
||||
LLVM_FALLTHROUGH;
|
||||
case FMA4:
|
||||
Builder.defineMacro("__FMA4__");
|
||||
LLVM_FALLTHROUGH;
|
||||
case SSE4A:
|
||||
Builder.defineMacro("__SSE4A__");
|
||||
LLVM_FALLTHROUGH;
|
||||
case NoXOP:
|
||||
break;
|
||||
}
|
||||
@ -4002,6 +4041,8 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
|
||||
|
||||
if (HasAVX512CD)
|
||||
Builder.defineMacro("__AVX512CD__");
|
||||
if (HasAVX512VPOPCNTDQ)
|
||||
Builder.defineMacro("__AVX512VPOPCNTDQ__");
|
||||
if (HasAVX512ER)
|
||||
Builder.defineMacro("__AVX512ER__");
|
||||
if (HasAVX512PF)
|
||||
@ -4051,24 +4092,33 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
|
||||
switch (SSELevel) {
|
||||
case AVX512F:
|
||||
Builder.defineMacro("__AVX512F__");
|
||||
LLVM_FALLTHROUGH;
|
||||
case AVX2:
|
||||
Builder.defineMacro("__AVX2__");
|
||||
LLVM_FALLTHROUGH;
|
||||
case AVX:
|
||||
Builder.defineMacro("__AVX__");
|
||||
LLVM_FALLTHROUGH;
|
||||
case SSE42:
|
||||
Builder.defineMacro("__SSE4_2__");
|
||||
LLVM_FALLTHROUGH;
|
||||
case SSE41:
|
||||
Builder.defineMacro("__SSE4_1__");
|
||||
LLVM_FALLTHROUGH;
|
||||
case SSSE3:
|
||||
Builder.defineMacro("__SSSE3__");
|
||||
LLVM_FALLTHROUGH;
|
||||
case SSE3:
|
||||
Builder.defineMacro("__SSE3__");
|
||||
LLVM_FALLTHROUGH;
|
||||
case SSE2:
|
||||
Builder.defineMacro("__SSE2__");
|
||||
Builder.defineMacro("__SSE2_MATH__"); // -mfp-math=sse always implied.
|
||||
LLVM_FALLTHROUGH;
|
||||
case SSE1:
|
||||
Builder.defineMacro("__SSE__");
|
||||
Builder.defineMacro("__SSE_MATH__"); // -mfp-math=sse always implied.
|
||||
LLVM_FALLTHROUGH;
|
||||
case NoSSE:
|
||||
break;
|
||||
}
|
||||
@ -4097,10 +4147,13 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
|
||||
switch (MMX3DNowLevel) {
|
||||
case AMD3DNowAthlon:
|
||||
Builder.defineMacro("__3dNOW_A__");
|
||||
LLVM_FALLTHROUGH;
|
||||
case AMD3DNow:
|
||||
Builder.defineMacro("__3dNOW__");
|
||||
LLVM_FALLTHROUGH;
|
||||
case MMX:
|
||||
Builder.defineMacro("__MMX__");
|
||||
LLVM_FALLTHROUGH;
|
||||
case NoMMX3DNow:
|
||||
break;
|
||||
}
|
||||
@ -4112,6 +4165,9 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
|
||||
}
|
||||
if (CPU >= CK_i586)
|
||||
Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8");
|
||||
|
||||
if (HasFloat128)
|
||||
Builder.defineMacro("__SIZEOF_FLOAT128__", "16");
|
||||
}
|
||||
|
||||
bool X86TargetInfo::hasFeature(StringRef Feature) const {
|
||||
@ -4121,6 +4177,7 @@ bool X86TargetInfo::hasFeature(StringRef Feature) const {
|
||||
.Case("avx2", SSELevel >= AVX2)
|
||||
.Case("avx512f", SSELevel >= AVX512F)
|
||||
.Case("avx512cd", HasAVX512CD)
|
||||
.Case("avx512vpopcntdq", HasAVX512VPOPCNTDQ)
|
||||
.Case("avx512er", HasAVX512ER)
|
||||
.Case("avx512pf", HasAVX512PF)
|
||||
.Case("avx512dq", HasAVX512DQ)
|
||||
@ -4206,6 +4263,7 @@ bool X86TargetInfo::validateCpuSupports(StringRef FeatureStr) const {
|
||||
.Case("avx512bw", true)
|
||||
.Case("avx512dq", true)
|
||||
.Case("avx512cd", true)
|
||||
.Case("avx512vpopcntdq", true)
|
||||
.Case("avx512er", true)
|
||||
.Case("avx512pf", true)
|
||||
.Case("avx512vbmi", true)
|
||||
@ -4589,7 +4647,9 @@ static void addMinGWDefines(const LangOptions &Opts, MacroBuilder &Builder) {
|
||||
class MinGWX86_32TargetInfo : public WindowsX86_32TargetInfo {
|
||||
public:
|
||||
MinGWX86_32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
|
||||
: WindowsX86_32TargetInfo(Triple, Opts) {}
|
||||
: WindowsX86_32TargetInfo(Triple, Opts) {
|
||||
HasFloat128 = true;
|
||||
}
|
||||
void getTargetDefines(const LangOptions &Opts,
|
||||
MacroBuilder &Builder) const override {
|
||||
WindowsX86_32TargetInfo::getTargetDefines(Opts, Builder);
|
||||
@ -4881,6 +4941,7 @@ public:
|
||||
// with x86 FP ops. Weird.
|
||||
LongDoubleWidth = LongDoubleAlign = 128;
|
||||
LongDoubleFormat = &llvm::APFloat::x87DoubleExtended();
|
||||
HasFloat128 = true;
|
||||
}
|
||||
|
||||
void getTargetDefines(const LangOptions &Opts,
|
||||
|
@ -26,6 +26,8 @@ XRayFunctionFilter::ImbueAttribute
|
||||
XRayFunctionFilter::shouldImbueFunction(StringRef FunctionName) const {
|
||||
// First apply the always instrument list, than if it isn't an "always" see
|
||||
// whether it's treated as a "never" instrument function.
|
||||
if (AlwaysInstrument->inSection("fun", FunctionName, "arg1"))
|
||||
return ImbueAttribute::ALWAYS_ARG1;
|
||||
if (AlwaysInstrument->inSection("fun", FunctionName))
|
||||
return ImbueAttribute::ALWAYS;
|
||||
if (NeverInstrument->inSection("fun", FunctionName))
|
||||
|
@ -7332,39 +7332,42 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
|
||||
AVX512PF,
|
||||
AVX512VBMI,
|
||||
AVX512IFMA,
|
||||
AVX512VPOPCNTDQ,
|
||||
MAX
|
||||
};
|
||||
|
||||
X86Features Feature = StringSwitch<X86Features>(FeatureStr)
|
||||
.Case("cmov", X86Features::CMOV)
|
||||
.Case("mmx", X86Features::MMX)
|
||||
.Case("popcnt", X86Features::POPCNT)
|
||||
.Case("sse", X86Features::SSE)
|
||||
.Case("sse2", X86Features::SSE2)
|
||||
.Case("sse3", X86Features::SSE3)
|
||||
.Case("ssse3", X86Features::SSSE3)
|
||||
.Case("sse4.1", X86Features::SSE4_1)
|
||||
.Case("sse4.2", X86Features::SSE4_2)
|
||||
.Case("avx", X86Features::AVX)
|
||||
.Case("avx2", X86Features::AVX2)
|
||||
.Case("sse4a", X86Features::SSE4_A)
|
||||
.Case("fma4", X86Features::FMA4)
|
||||
.Case("xop", X86Features::XOP)
|
||||
.Case("fma", X86Features::FMA)
|
||||
.Case("avx512f", X86Features::AVX512F)
|
||||
.Case("bmi", X86Features::BMI)
|
||||
.Case("bmi2", X86Features::BMI2)
|
||||
.Case("aes", X86Features::AES)
|
||||
.Case("pclmul", X86Features::PCLMUL)
|
||||
.Case("avx512vl", X86Features::AVX512VL)
|
||||
.Case("avx512bw", X86Features::AVX512BW)
|
||||
.Case("avx512dq", X86Features::AVX512DQ)
|
||||
.Case("avx512cd", X86Features::AVX512CD)
|
||||
.Case("avx512er", X86Features::AVX512ER)
|
||||
.Case("avx512pf", X86Features::AVX512PF)
|
||||
.Case("avx512vbmi", X86Features::AVX512VBMI)
|
||||
.Case("avx512ifma", X86Features::AVX512IFMA)
|
||||
.Default(X86Features::MAX);
|
||||
X86Features Feature =
|
||||
StringSwitch<X86Features>(FeatureStr)
|
||||
.Case("cmov", X86Features::CMOV)
|
||||
.Case("mmx", X86Features::MMX)
|
||||
.Case("popcnt", X86Features::POPCNT)
|
||||
.Case("sse", X86Features::SSE)
|
||||
.Case("sse2", X86Features::SSE2)
|
||||
.Case("sse3", X86Features::SSE3)
|
||||
.Case("ssse3", X86Features::SSSE3)
|
||||
.Case("sse4.1", X86Features::SSE4_1)
|
||||
.Case("sse4.2", X86Features::SSE4_2)
|
||||
.Case("avx", X86Features::AVX)
|
||||
.Case("avx2", X86Features::AVX2)
|
||||
.Case("sse4a", X86Features::SSE4_A)
|
||||
.Case("fma4", X86Features::FMA4)
|
||||
.Case("xop", X86Features::XOP)
|
||||
.Case("fma", X86Features::FMA)
|
||||
.Case("avx512f", X86Features::AVX512F)
|
||||
.Case("bmi", X86Features::BMI)
|
||||
.Case("bmi2", X86Features::BMI2)
|
||||
.Case("aes", X86Features::AES)
|
||||
.Case("pclmul", X86Features::PCLMUL)
|
||||
.Case("avx512vl", X86Features::AVX512VL)
|
||||
.Case("avx512bw", X86Features::AVX512BW)
|
||||
.Case("avx512dq", X86Features::AVX512DQ)
|
||||
.Case("avx512cd", X86Features::AVX512CD)
|
||||
.Case("avx512er", X86Features::AVX512ER)
|
||||
.Case("avx512pf", X86Features::AVX512PF)
|
||||
.Case("avx512vbmi", X86Features::AVX512VBMI)
|
||||
.Case("avx512ifma", X86Features::AVX512IFMA)
|
||||
.Case("avx512vpopcntdq", X86Features::AVX512VPOPCNTDQ)
|
||||
.Default(X86Features::MAX);
|
||||
assert(Feature != X86Features::MAX && "Invalid feature!");
|
||||
|
||||
// Matching the struct layout from the compiler-rt/libgcc structure that is
|
||||
@ -7517,7 +7520,12 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
|
||||
case X86::BI__builtin_ia32_storesd128_mask: {
|
||||
return EmitX86MaskedStore(*this, Ops, 16);
|
||||
}
|
||||
|
||||
case X86::BI__builtin_ia32_vpopcntd_512:
|
||||
case X86::BI__builtin_ia32_vpopcntq_512: {
|
||||
llvm::Type *ResultType = ConvertType(E->getType());
|
||||
llvm::Function *F = CGM.getIntrinsic(Intrinsic::ctpop, ResultType);
|
||||
return Builder.CreateCall(F, Ops);
|
||||
}
|
||||
case X86::BI__builtin_ia32_cvtmask2b128:
|
||||
case X86::BI__builtin_ia32_cvtmask2b256:
|
||||
case X86::BI__builtin_ia32_cvtmask2b512:
|
||||
@ -8442,6 +8450,80 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID,
|
||||
return Builder.CreateCall(F, Ops);
|
||||
}
|
||||
}
|
||||
|
||||
case PPC::BI__builtin_vsx_xxpermdi: {
|
||||
ConstantInt *ArgCI = dyn_cast<ConstantInt>(Ops[2]);
|
||||
assert(ArgCI && "Third arg must be constant integer!");
|
||||
|
||||
unsigned Index = ArgCI->getZExtValue();
|
||||
Ops[0] = Builder.CreateBitCast(Ops[0], llvm::VectorType::get(Int64Ty, 2));
|
||||
Ops[1] = Builder.CreateBitCast(Ops[1], llvm::VectorType::get(Int64Ty, 2));
|
||||
|
||||
// Element zero comes from the first input vector and element one comes from
|
||||
// the second. The element indices within each vector are numbered in big
|
||||
// endian order so the shuffle mask must be adjusted for this on little
|
||||
// endian platforms (i.e. index is complemented and source vector reversed).
|
||||
unsigned ElemIdx0;
|
||||
unsigned ElemIdx1;
|
||||
if (getTarget().isLittleEndian()) {
|
||||
ElemIdx0 = (~Index & 1) + 2;
|
||||
ElemIdx1 = (~Index & 2) >> 1;
|
||||
} else { // BigEndian
|
||||
ElemIdx0 = (Index & 2) >> 1;
|
||||
ElemIdx1 = 2 + (Index & 1);
|
||||
}
|
||||
|
||||
Constant *ShuffleElts[2] = {ConstantInt::get(Int32Ty, ElemIdx0),
|
||||
ConstantInt::get(Int32Ty, ElemIdx1)};
|
||||
Constant *ShuffleMask = llvm::ConstantVector::get(ShuffleElts);
|
||||
|
||||
Value *ShuffleCall =
|
||||
Builder.CreateShuffleVector(Ops[0], Ops[1], ShuffleMask);
|
||||
QualType BIRetType = E->getType();
|
||||
auto RetTy = ConvertType(BIRetType);
|
||||
return Builder.CreateBitCast(ShuffleCall, RetTy);
|
||||
}
|
||||
|
||||
case PPC::BI__builtin_vsx_xxsldwi: {
|
||||
ConstantInt *ArgCI = dyn_cast<ConstantInt>(Ops[2]);
|
||||
assert(ArgCI && "Third argument must be a compile time constant");
|
||||
unsigned Index = ArgCI->getZExtValue() & 0x3;
|
||||
Ops[0] = Builder.CreateBitCast(Ops[0], llvm::VectorType::get(Int32Ty, 4));
|
||||
Ops[1] = Builder.CreateBitCast(Ops[1], llvm::VectorType::get(Int32Ty, 4));
|
||||
|
||||
// Create a shuffle mask
|
||||
unsigned ElemIdx0;
|
||||
unsigned ElemIdx1;
|
||||
unsigned ElemIdx2;
|
||||
unsigned ElemIdx3;
|
||||
if (getTarget().isLittleEndian()) {
|
||||
// Little endian element N comes from element 8+N-Index of the
|
||||
// concatenated wide vector (of course, using modulo arithmetic on
|
||||
// the total number of elements).
|
||||
ElemIdx0 = (8 - Index) % 8;
|
||||
ElemIdx1 = (9 - Index) % 8;
|
||||
ElemIdx2 = (10 - Index) % 8;
|
||||
ElemIdx3 = (11 - Index) % 8;
|
||||
} else {
|
||||
// Big endian ElemIdx<N> = Index + N
|
||||
ElemIdx0 = Index;
|
||||
ElemIdx1 = Index + 1;
|
||||
ElemIdx2 = Index + 2;
|
||||
ElemIdx3 = Index + 3;
|
||||
}
|
||||
|
||||
Constant *ShuffleElts[4] = {ConstantInt::get(Int32Ty, ElemIdx0),
|
||||
ConstantInt::get(Int32Ty, ElemIdx1),
|
||||
ConstantInt::get(Int32Ty, ElemIdx2),
|
||||
ConstantInt::get(Int32Ty, ElemIdx3)};
|
||||
|
||||
Constant *ShuffleMask = llvm::ConstantVector::get(ShuffleElts);
|
||||
Value *ShuffleCall =
|
||||
Builder.CreateShuffleVector(Ops[0], Ops[1], ShuffleMask);
|
||||
QualType BIRetType = E->getType();
|
||||
auto RetTy = ConvertType(BIRetType);
|
||||
return Builder.CreateBitCast(ShuffleCall, RetTy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,9 +11,11 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "CGCleanup.h"
|
||||
#include "CodeGenFunction.h"
|
||||
#include "llvm/ADT/ScopeExit.h"
|
||||
#include "clang/AST/StmtCXX.h"
|
||||
#include "clang/AST/StmtVisitor.h"
|
||||
|
||||
using namespace clang;
|
||||
using namespace CodeGen;
|
||||
@ -57,6 +59,15 @@ struct clang::CodeGen::CGCoroData {
|
||||
// builtin.
|
||||
llvm::CallInst *CoroId = nullptr;
|
||||
|
||||
// Stores the llvm.coro.begin emitted in the function so that we can replace
|
||||
// all coro.frame intrinsics with direct SSA value of coro.begin that returns
|
||||
// the address of the coroutine frame of the current coroutine.
|
||||
llvm::CallInst *CoroBegin = nullptr;
|
||||
|
||||
// Stores the last emitted coro.free for the deallocate expressions, we use it
|
||||
// to wrap dealloc code with if(auto mem = coro.free) dealloc(mem).
|
||||
llvm::CallInst *LastCoroFree = nullptr;
|
||||
|
||||
// If coro.id came from the builtin, remember the expression to give better
|
||||
// diagnostic. If CoroIdExpr is nullptr, the coro.id was created by
|
||||
// EmitCoroutineBody.
|
||||
@ -142,6 +153,20 @@ static RValue emitSuspendExpression(CodeGenFunction &CGF, CGCoroData &Coro,
|
||||
AwaitKind Kind, AggValueSlot aggSlot,
|
||||
bool ignoreResult) {
|
||||
auto *E = S.getCommonExpr();
|
||||
|
||||
// FIXME: rsmith 5/22/2017. Does it still make sense for us to have a
|
||||
// UO_Coawait at all? As I recall, the only purpose it ever had was to
|
||||
// represent a dependent co_await expression that couldn't yet be resolved to
|
||||
// a CoawaitExpr. But now we have (and need!) a separate DependentCoawaitExpr
|
||||
// node to store unqualified lookup results, it seems that the UnaryOperator
|
||||
// portion of the representation serves no purpose (and as seen in this patch,
|
||||
// it's getting in the way). Can we remove it?
|
||||
|
||||
// Skip passthrough operator co_await (present when awaiting on an LValue).
|
||||
if (auto *UO = dyn_cast<UnaryOperator>(E))
|
||||
if (UO->getOpcode() == UO_Coawait)
|
||||
E = UO->getSubExpr();
|
||||
|
||||
auto Binder =
|
||||
CodeGenFunction::OpaqueValueMappingData::bind(CGF, S.getOpaqueValue(), E);
|
||||
auto UnbindOnExit = llvm::make_scope_exit([&] { Binder.unbind(CGF); });
|
||||
@ -215,7 +240,67 @@ void CodeGenFunction::EmitCoreturnStmt(CoreturnStmt const &S) {
|
||||
EmitBranchThroughCleanup(CurCoro.Data->FinalJD);
|
||||
}
|
||||
|
||||
// For WinEH exception representation backend need to know what funclet coro.end
|
||||
// Hunts for the parameter reference in the parameter copy/move declaration.
|
||||
namespace {
|
||||
struct GetParamRef : public StmtVisitor<GetParamRef> {
|
||||
public:
|
||||
DeclRefExpr *Expr = nullptr;
|
||||
GetParamRef() {}
|
||||
void VisitDeclRefExpr(DeclRefExpr *E) {
|
||||
assert(Expr == nullptr && "multilple declref in param move");
|
||||
Expr = E;
|
||||
}
|
||||
void VisitStmt(Stmt *S) {
|
||||
for (auto *C : S->children()) {
|
||||
if (C)
|
||||
Visit(C);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// This class replaces references to parameters to their copies by changing
|
||||
// the addresses in CGF.LocalDeclMap and restoring back the original values in
|
||||
// its destructor.
|
||||
|
||||
namespace {
|
||||
struct ParamReferenceReplacerRAII {
|
||||
CodeGenFunction::DeclMapTy SavedLocals;
|
||||
CodeGenFunction::DeclMapTy& LocalDeclMap;
|
||||
|
||||
ParamReferenceReplacerRAII(CodeGenFunction::DeclMapTy &LocalDeclMap)
|
||||
: LocalDeclMap(LocalDeclMap) {}
|
||||
|
||||
void addCopy(DeclStmt const *PM) {
|
||||
// Figure out what param it refers to.
|
||||
|
||||
assert(PM->isSingleDecl());
|
||||
VarDecl const*VD = static_cast<VarDecl const*>(PM->getSingleDecl());
|
||||
Expr const *InitExpr = VD->getInit();
|
||||
GetParamRef Visitor;
|
||||
Visitor.Visit(const_cast<Expr*>(InitExpr));
|
||||
assert(Visitor.Expr);
|
||||
auto *DREOrig = cast<DeclRefExpr>(Visitor.Expr);
|
||||
auto *PD = DREOrig->getDecl();
|
||||
|
||||
auto it = LocalDeclMap.find(PD);
|
||||
assert(it != LocalDeclMap.end() && "parameter is not found");
|
||||
SavedLocals.insert({ PD, it->second });
|
||||
|
||||
auto copyIt = LocalDeclMap.find(VD);
|
||||
assert(copyIt != LocalDeclMap.end() && "parameter copy is not found");
|
||||
it->second = copyIt->getSecond();
|
||||
}
|
||||
|
||||
~ParamReferenceReplacerRAII() {
|
||||
for (auto&& SavedLocal : SavedLocals) {
|
||||
LocalDeclMap.insert({SavedLocal.first, SavedLocal.second});
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// For WinEH exception representation backend needs to know what funclet coro.end
|
||||
// belongs to. That information is passed in a funclet bundle.
|
||||
static SmallVector<llvm::OperandBundleDef, 1>
|
||||
getBundlesForCoroEnd(CodeGenFunction &CGF) {
|
||||
@ -257,24 +342,135 @@ namespace {
|
||||
struct CallCoroDelete final : public EHScopeStack::Cleanup {
|
||||
Stmt *Deallocate;
|
||||
|
||||
// TODO: Wrap deallocate in if(coro.free(...)) Deallocate.
|
||||
// Emit "if (coro.free(CoroId, CoroBegin)) Deallocate;"
|
||||
|
||||
// Note: That deallocation will be emitted twice: once for a normal exit and
|
||||
// once for exceptional exit. This usage is safe because Deallocate does not
|
||||
// contain any declarations. The SubStmtBuilder::makeNewAndDeleteExpr()
|
||||
// builds a single call to a deallocation function which is safe to emit
|
||||
// multiple times.
|
||||
void Emit(CodeGenFunction &CGF, Flags) override {
|
||||
// Note: That deallocation will be emitted twice: once for a normal exit and
|
||||
// once for exceptional exit. This usage is safe because Deallocate does not
|
||||
// contain any declarations. The SubStmtBuilder::makeNewAndDeleteExpr()
|
||||
// builds a single call to a deallocation function which is safe to emit
|
||||
// multiple times.
|
||||
// Remember the current point, as we are going to emit deallocation code
|
||||
// first to get to coro.free instruction that is an argument to a delete
|
||||
// call.
|
||||
BasicBlock *SaveInsertBlock = CGF.Builder.GetInsertBlock();
|
||||
|
||||
auto *FreeBB = CGF.createBasicBlock("coro.free");
|
||||
CGF.EmitBlock(FreeBB);
|
||||
CGF.EmitStmt(Deallocate);
|
||||
|
||||
auto *AfterFreeBB = CGF.createBasicBlock("after.coro.free");
|
||||
CGF.EmitBlock(AfterFreeBB);
|
||||
|
||||
// We should have captured coro.free from the emission of deallocate.
|
||||
auto *CoroFree = CGF.CurCoro.Data->LastCoroFree;
|
||||
if (!CoroFree) {
|
||||
CGF.CGM.Error(Deallocate->getLocStart(),
|
||||
"Deallocation expressoin does not refer to coro.free");
|
||||
return;
|
||||
}
|
||||
|
||||
// Get back to the block we were originally and move coro.free there.
|
||||
auto *InsertPt = SaveInsertBlock->getTerminator();
|
||||
CoroFree->moveBefore(InsertPt);
|
||||
CGF.Builder.SetInsertPoint(InsertPt);
|
||||
|
||||
// Add if (auto *mem = coro.free) Deallocate;
|
||||
auto *NullPtr = llvm::ConstantPointerNull::get(CGF.Int8PtrTy);
|
||||
auto *Cond = CGF.Builder.CreateICmpNE(CoroFree, NullPtr);
|
||||
CGF.Builder.CreateCondBr(Cond, FreeBB, AfterFreeBB);
|
||||
|
||||
// No longer need old terminator.
|
||||
InsertPt->eraseFromParent();
|
||||
CGF.Builder.SetInsertPoint(AfterFreeBB);
|
||||
}
|
||||
explicit CallCoroDelete(Stmt *DeallocStmt) : Deallocate(DeallocStmt) {}
|
||||
};
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct GetReturnObjectManager {
|
||||
CodeGenFunction &CGF;
|
||||
CGBuilderTy &Builder;
|
||||
const CoroutineBodyStmt &S;
|
||||
|
||||
Address GroActiveFlag;
|
||||
CodeGenFunction::AutoVarEmission GroEmission;
|
||||
|
||||
GetReturnObjectManager(CodeGenFunction &CGF, const CoroutineBodyStmt &S)
|
||||
: CGF(CGF), Builder(CGF.Builder), S(S), GroActiveFlag(Address::invalid()),
|
||||
GroEmission(CodeGenFunction::AutoVarEmission::invalid()) {}
|
||||
|
||||
// The gro variable has to outlive coroutine frame and coroutine promise, but,
|
||||
// it can only be initialized after coroutine promise was created, thus, we
|
||||
// split its emission in two parts. EmitGroAlloca emits an alloca and sets up
|
||||
// cleanups. Later when coroutine promise is available we initialize the gro
|
||||
// and sets the flag that the cleanup is now active.
|
||||
|
||||
void EmitGroAlloca() {
|
||||
auto *GroDeclStmt = dyn_cast<DeclStmt>(S.getResultDecl());
|
||||
if (!GroDeclStmt) {
|
||||
// If get_return_object returns void, no need to do an alloca.
|
||||
return;
|
||||
}
|
||||
|
||||
auto *GroVarDecl = cast<VarDecl>(GroDeclStmt->getSingleDecl());
|
||||
|
||||
// Set GRO flag that it is not initialized yet
|
||||
GroActiveFlag =
|
||||
CGF.CreateTempAlloca(Builder.getInt1Ty(), CharUnits::One(), "gro.active");
|
||||
Builder.CreateStore(Builder.getFalse(), GroActiveFlag);
|
||||
|
||||
GroEmission = CGF.EmitAutoVarAlloca(*GroVarDecl);
|
||||
|
||||
// Remember the top of EHStack before emitting the cleanup.
|
||||
auto old_top = CGF.EHStack.stable_begin();
|
||||
CGF.EmitAutoVarCleanups(GroEmission);
|
||||
auto top = CGF.EHStack.stable_begin();
|
||||
|
||||
// Make the cleanup conditional on gro.active
|
||||
for (auto b = CGF.EHStack.find(top), e = CGF.EHStack.find(old_top);
|
||||
b != e; b++) {
|
||||
if (auto *Cleanup = dyn_cast<EHCleanupScope>(&*b)) {
|
||||
assert(!Cleanup->hasActiveFlag() && "cleanup already has active flag?");
|
||||
Cleanup->setActiveFlag(GroActiveFlag);
|
||||
Cleanup->setTestFlagInEHCleanup();
|
||||
Cleanup->setTestFlagInNormalCleanup();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EmitGroInit() {
|
||||
if (!GroActiveFlag.isValid()) {
|
||||
// No Gro variable was allocated. Simply emit the call to
|
||||
// get_return_object.
|
||||
CGF.EmitStmt(S.getResultDecl());
|
||||
return;
|
||||
}
|
||||
|
||||
CGF.EmitAutoVarInit(GroEmission);
|
||||
Builder.CreateStore(Builder.getTrue(), GroActiveFlag);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static void emitBodyAndFallthrough(CodeGenFunction &CGF,
|
||||
const CoroutineBodyStmt &S, Stmt *Body) {
|
||||
CGF.EmitStmt(Body);
|
||||
const bool CanFallthrough = CGF.Builder.GetInsertBlock();
|
||||
if (CanFallthrough)
|
||||
if (Stmt *OnFallthrough = S.getFallthroughHandler())
|
||||
CGF.EmitStmt(OnFallthrough);
|
||||
}
|
||||
|
||||
void CodeGenFunction::EmitCoroutineBody(const CoroutineBodyStmt &S) {
|
||||
auto *NullPtr = llvm::ConstantPointerNull::get(Builder.getInt8PtrTy());
|
||||
auto &TI = CGM.getContext().getTargetInfo();
|
||||
unsigned NewAlign = TI.getNewAlign() / TI.getCharWidth();
|
||||
|
||||
auto *EntryBB = Builder.GetInsertBlock();
|
||||
auto *AllocBB = createBasicBlock("coro.alloc");
|
||||
auto *InitBB = createBasicBlock("coro.init");
|
||||
auto *FinalBB = createBasicBlock("coro.final");
|
||||
auto *RetBB = createBasicBlock("coro.ret");
|
||||
|
||||
@ -284,12 +480,20 @@ void CodeGenFunction::EmitCoroutineBody(const CoroutineBodyStmt &S) {
|
||||
createCoroData(*this, CurCoro, CoroId);
|
||||
CurCoro.Data->SuspendBB = RetBB;
|
||||
|
||||
// Backend is allowed to elide memory allocations, to help it, emit
|
||||
// auto mem = coro.alloc() ? 0 : ... allocation code ...;
|
||||
auto *CoroAlloc = Builder.CreateCall(
|
||||
CGM.getIntrinsic(llvm::Intrinsic::coro_alloc), {CoroId});
|
||||
|
||||
Builder.CreateCondBr(CoroAlloc, AllocBB, InitBB);
|
||||
|
||||
EmitBlock(AllocBB);
|
||||
auto *AllocateCall = EmitScalarExpr(S.getAllocate());
|
||||
auto *AllocOrInvokeContBB = Builder.GetInsertBlock();
|
||||
|
||||
// Handle allocation failure if 'ReturnStmtOnAllocFailure' was provided.
|
||||
if (auto *RetOnAllocFailure = S.getReturnStmtOnAllocFailure()) {
|
||||
auto *RetOnFailureBB = createBasicBlock("coro.ret.on.failure");
|
||||
auto *InitBB = createBasicBlock("coro.init");
|
||||
|
||||
// See if allocation was successful.
|
||||
auto *NullPtr = llvm::ConstantPointerNull::get(Int8PtrTy);
|
||||
@ -299,40 +503,96 @@ void CodeGenFunction::EmitCoroutineBody(const CoroutineBodyStmt &S) {
|
||||
// If not, return OnAllocFailure object.
|
||||
EmitBlock(RetOnFailureBB);
|
||||
EmitStmt(RetOnAllocFailure);
|
||||
|
||||
EmitBlock(InitBB);
|
||||
}
|
||||
else {
|
||||
Builder.CreateBr(InitBB);
|
||||
}
|
||||
|
||||
EmitBlock(InitBB);
|
||||
|
||||
// Pass the result of the allocation to coro.begin.
|
||||
auto *Phi = Builder.CreatePHI(VoidPtrTy, 2);
|
||||
Phi->addIncoming(NullPtr, EntryBB);
|
||||
Phi->addIncoming(AllocateCall, AllocOrInvokeContBB);
|
||||
auto *CoroBegin = Builder.CreateCall(
|
||||
CGM.getIntrinsic(llvm::Intrinsic::coro_begin), {CoroId, Phi});
|
||||
CurCoro.Data->CoroBegin = CoroBegin;
|
||||
|
||||
GetReturnObjectManager GroManager(*this, S);
|
||||
GroManager.EmitGroAlloca();
|
||||
|
||||
CurCoro.Data->CleanupJD = getJumpDestInCurrentScope(RetBB);
|
||||
{
|
||||
ParamReferenceReplacerRAII ParamReplacer(LocalDeclMap);
|
||||
CodeGenFunction::RunCleanupsScope ResumeScope(*this);
|
||||
EHStack.pushCleanup<CallCoroDelete>(NormalAndEHCleanup, S.getDeallocate());
|
||||
|
||||
// Create parameter copies. We do it before creating a promise, since an
|
||||
// evolution of coroutine TS may allow promise constructor to observe
|
||||
// parameter copies.
|
||||
for (auto *PM : S.getParamMoves()) {
|
||||
EmitStmt(PM);
|
||||
ParamReplacer.addCopy(cast<DeclStmt>(PM));
|
||||
// TODO: if(CoroParam(...)) need to surround ctor and dtor
|
||||
// for the copy, so that llvm can elide it if the copy is
|
||||
// not needed.
|
||||
}
|
||||
|
||||
EmitStmt(S.getPromiseDeclStmt());
|
||||
|
||||
Address PromiseAddr = GetAddrOfLocalVar(S.getPromiseDecl());
|
||||
auto *PromiseAddrVoidPtr =
|
||||
new llvm::BitCastInst(PromiseAddr.getPointer(), VoidPtrTy, "", CoroId);
|
||||
// Update CoroId to refer to the promise. We could not do it earlier because
|
||||
// promise local variable was not emitted yet.
|
||||
CoroId->setArgOperand(1, PromiseAddrVoidPtr);
|
||||
|
||||
// Now we have the promise, initialize the GRO
|
||||
GroManager.EmitGroInit();
|
||||
|
||||
EHStack.pushCleanup<CallCoroEnd>(EHCleanup);
|
||||
|
||||
CurCoro.Data->CurrentAwaitKind = AwaitKind::Init;
|
||||
EmitStmt(S.getInitSuspendStmt());
|
||||
CurCoro.Data->FinalJD = getJumpDestInCurrentScope(FinalBB);
|
||||
|
||||
// FIXME: Emit initial suspend and more before the body.
|
||||
|
||||
CurCoro.Data->CurrentAwaitKind = AwaitKind::Normal;
|
||||
EmitStmt(S.getBody());
|
||||
|
||||
if (auto *OnException = S.getExceptionHandler()) {
|
||||
auto Loc = S.getLocStart();
|
||||
CXXCatchStmt Catch(Loc, /*exDecl=*/nullptr, OnException);
|
||||
auto *TryStmt = CXXTryStmt::Create(getContext(), Loc, S.getBody(), &Catch);
|
||||
|
||||
EnterCXXTryStmt(*TryStmt);
|
||||
emitBodyAndFallthrough(*this, S, TryStmt->getTryBlock());
|
||||
ExitCXXTryStmt(*TryStmt);
|
||||
}
|
||||
else {
|
||||
emitBodyAndFallthrough(*this, S, S.getBody());
|
||||
}
|
||||
|
||||
// See if we need to generate final suspend.
|
||||
const bool CanFallthrough = Builder.GetInsertBlock();
|
||||
const bool HasCoreturns = CurCoro.Data->CoreturnCount > 0;
|
||||
if (CanFallthrough || HasCoreturns) {
|
||||
EmitBlock(FinalBB);
|
||||
// FIXME: Emit final suspend.
|
||||
CurCoro.Data->CurrentAwaitKind = AwaitKind::Final;
|
||||
EmitStmt(S.getFinalSuspendStmt());
|
||||
}
|
||||
else {
|
||||
// We don't need FinalBB. Emit it to make sure the block is deleted.
|
||||
EmitBlock(FinalBB, /*IsFinished=*/true);
|
||||
}
|
||||
}
|
||||
|
||||
EmitBlock(RetBB);
|
||||
// Emit coro.end before getReturnStmt (and parameter destructors), since
|
||||
// resume and destroy parts of the coroutine should not include them.
|
||||
llvm::Function *CoroEnd = CGM.getIntrinsic(llvm::Intrinsic::coro_end);
|
||||
Builder.CreateCall(CoroEnd, {NullPtr, Builder.getFalse()});
|
||||
|
||||
// FIXME: Emit return for the coroutine return object.
|
||||
if (Stmt *Ret = S.getReturnStmt())
|
||||
EmitStmt(Ret);
|
||||
}
|
||||
|
||||
// Emit coroutine intrinsic and patch up arguments of the token type.
|
||||
@ -342,6 +602,17 @@ RValue CodeGenFunction::EmitCoroutineIntrinsic(const CallExpr *E,
|
||||
switch (IID) {
|
||||
default:
|
||||
break;
|
||||
// The coro.frame builtin is replaced with an SSA value of the coro.begin
|
||||
// intrinsic.
|
||||
case llvm::Intrinsic::coro_frame: {
|
||||
if (CurCoro.Data && CurCoro.Data->CoroBegin) {
|
||||
return RValue::get(CurCoro.Data->CoroBegin);
|
||||
}
|
||||
CGM.Error(E->getLocStart(), "this builtin expect that __builtin_coro_begin "
|
||||
"has been used earlier in this function");
|
||||
auto NullPtr = llvm::ConstantPointerNull::get(Builder.getInt8PtrTy());
|
||||
return RValue::get(NullPtr);
|
||||
}
|
||||
// The following three intrinsics take a token parameter referring to a token
|
||||
// returned by earlier call to @llvm.coro.id. Since we cannot represent it in
|
||||
// builtins, we patch it up here.
|
||||
@ -368,10 +639,22 @@ RValue CodeGenFunction::EmitCoroutineIntrinsic(const CallExpr *E,
|
||||
llvm::Value *F = CGM.getIntrinsic(IID);
|
||||
llvm::CallInst *Call = Builder.CreateCall(F, Args);
|
||||
|
||||
// Note: The following code is to enable to emit coro.id and coro.begin by
|
||||
// hand to experiment with coroutines in C.
|
||||
// If we see @llvm.coro.id remember it in the CoroData. We will update
|
||||
// coro.alloc, coro.begin and coro.free intrinsics to refer to it.
|
||||
if (IID == llvm::Intrinsic::coro_id) {
|
||||
createCoroData(*this, CurCoro, Call, E);
|
||||
}
|
||||
else if (IID == llvm::Intrinsic::coro_begin) {
|
||||
if (CurCoro.Data)
|
||||
CurCoro.Data->CoroBegin = Call;
|
||||
}
|
||||
else if (IID == llvm::Intrinsic::coro_free) {
|
||||
// Remember the last coro_free as we need it to build the conditional
|
||||
// deletion of the coroutine frame.
|
||||
if (CurCoro.Data)
|
||||
CurCoro.Data->LastCoroFree = Call;
|
||||
}
|
||||
return RValue::get(Call);
|
||||
}
|
||||
|
@ -1432,11 +1432,12 @@ llvm::Value *CodeGenFunction::EmitLoadOfScalar(Address Addr, bool Volatile,
|
||||
Load->setMetadata(CGM.getModule().getMDKindID("nontemporal"), Node);
|
||||
}
|
||||
if (TBAAInfo) {
|
||||
llvm::MDNode *TBAAPath = CGM.getTBAAStructTagInfo(TBAABaseType, TBAAInfo,
|
||||
TBAAOffset);
|
||||
if (TBAAPath)
|
||||
CGM.DecorateInstructionWithTBAA(Load, TBAAPath,
|
||||
false /*ConvertTypeToTag*/);
|
||||
bool MayAlias = BaseInfo.getMayAlias();
|
||||
llvm::MDNode *TBAA = MayAlias
|
||||
? CGM.getTBAAInfo(getContext().CharTy)
|
||||
: CGM.getTBAAStructTagInfo(TBAABaseType, TBAAInfo, TBAAOffset);
|
||||
if (TBAA)
|
||||
CGM.DecorateInstructionWithTBAA(Load, TBAA, MayAlias);
|
||||
}
|
||||
|
||||
if (EmitScalarRangeCheck(Load, Ty, Loc)) {
|
||||
@ -1522,11 +1523,12 @@ void CodeGenFunction::EmitStoreOfScalar(llvm::Value *Value, Address Addr,
|
||||
Store->setMetadata(CGM.getModule().getMDKindID("nontemporal"), Node);
|
||||
}
|
||||
if (TBAAInfo) {
|
||||
llvm::MDNode *TBAAPath = CGM.getTBAAStructTagInfo(TBAABaseType, TBAAInfo,
|
||||
TBAAOffset);
|
||||
if (TBAAPath)
|
||||
CGM.DecorateInstructionWithTBAA(Store, TBAAPath,
|
||||
false /*ConvertTypeToTag*/);
|
||||
bool MayAlias = BaseInfo.getMayAlias();
|
||||
llvm::MDNode *TBAA = MayAlias
|
||||
? CGM.getTBAAInfo(getContext().CharTy)
|
||||
: CGM.getTBAAStructTagInfo(TBAABaseType, TBAAInfo, TBAAOffset);
|
||||
if (TBAA)
|
||||
CGM.DecorateInstructionWithTBAA(Store, TBAA, MayAlias);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3535,6 +3537,11 @@ LValue CodeGenFunction::EmitLValueForField(LValue base,
|
||||
getFieldAlignmentSource(BaseInfo.getAlignmentSource());
|
||||
LValueBaseInfo FieldBaseInfo(fieldAlignSource, BaseInfo.getMayAlias());
|
||||
|
||||
const RecordDecl *rec = field->getParent();
|
||||
if (rec->isUnion() || rec->hasAttr<MayAliasAttr>())
|
||||
FieldBaseInfo.setMayAlias(true);
|
||||
bool mayAlias = FieldBaseInfo.getMayAlias();
|
||||
|
||||
if (field->isBitField()) {
|
||||
const CGRecordLayout &RL =
|
||||
CGM.getTypes().getCGRecordLayout(field->getParent());
|
||||
@ -3556,11 +3563,7 @@ LValue CodeGenFunction::EmitLValueForField(LValue base,
|
||||
return LValue::MakeBitfield(Addr, Info, fieldType, FieldBaseInfo);
|
||||
}
|
||||
|
||||
const RecordDecl *rec = field->getParent();
|
||||
QualType type = field->getType();
|
||||
|
||||
bool mayAlias = rec->hasAttr<MayAliasAttr>();
|
||||
|
||||
Address addr = base.getAddress();
|
||||
unsigned cvr = base.getVRQualifiers();
|
||||
bool TBAAPath = CGM.getCodeGenOpts().StructPathTBAA;
|
||||
|
@ -760,6 +760,7 @@ emitCombinerOrInitializer(CodeGenModule &CGM, QualType Ty,
|
||||
IsCombiner ? ".omp_combiner." : ".omp_initializer.", &CGM.getModule());
|
||||
CGM.SetInternalFunctionAttributes(/*D=*/nullptr, Fn, FnInfo);
|
||||
Fn->removeFnAttr(llvm::Attribute::NoInline);
|
||||
Fn->removeFnAttr(llvm::Attribute::OptimizeNone);
|
||||
Fn->addFnAttr(llvm::Attribute::AlwaysInline);
|
||||
CodeGenFunction CGF(CGM);
|
||||
// Map "T omp_in;" variable to "*omp_in_parm" value in all expressions.
|
||||
@ -2903,6 +2904,19 @@ CGOpenMPRuntime::createOffloadingBinaryDescriptorRegistration() {
|
||||
Desc);
|
||||
CGM.getCXXABI().registerGlobalDtor(CGF, RegUnregVar, UnRegFn, Desc);
|
||||
});
|
||||
if (CGM.supportsCOMDAT()) {
|
||||
// It is sufficient to call registration function only once, so create a
|
||||
// COMDAT group for registration/unregistration functions and associated
|
||||
// data. That would reduce startup time and code size. Registration
|
||||
// function serves as a COMDAT group key.
|
||||
auto ComdatKey = M.getOrInsertComdat(RegFn->getName());
|
||||
RegFn->setLinkage(llvm::GlobalValue::LinkOnceAnyLinkage);
|
||||
RegFn->setVisibility(llvm::GlobalValue::HiddenVisibility);
|
||||
RegFn->setComdat(ComdatKey);
|
||||
UnRegFn->setComdat(ComdatKey);
|
||||
DeviceImages->setComdat(ComdatKey);
|
||||
Desc->setComdat(ComdatKey);
|
||||
}
|
||||
return RegFn;
|
||||
}
|
||||
|
||||
@ -3502,6 +3516,7 @@ emitTaskPrivateMappingFunction(CodeGenModule &CGM, SourceLocation Loc,
|
||||
CGM.SetInternalFunctionAttributes(/*D=*/nullptr, TaskPrivatesMap,
|
||||
TaskPrivatesMapFnInfo);
|
||||
TaskPrivatesMap->removeFnAttr(llvm::Attribute::NoInline);
|
||||
TaskPrivatesMap->removeFnAttr(llvm::Attribute::OptimizeNone);
|
||||
TaskPrivatesMap->addFnAttr(llvm::Attribute::AlwaysInline);
|
||||
CodeGenFunction CGF(CGM);
|
||||
CGF.disableDebugInfo();
|
||||
|
@ -861,6 +861,7 @@ llvm::Value *CGOpenMPRuntimeNVPTX::emitTeamsOutlinedFunction(
|
||||
D, ThreadIDVar, InnermostKind, CodeGen);
|
||||
llvm::Function *OutlinedFun = cast<llvm::Function>(OutlinedFunVal);
|
||||
OutlinedFun->removeFnAttr(llvm::Attribute::NoInline);
|
||||
OutlinedFun->removeFnAttr(llvm::Attribute::OptimizeNone);
|
||||
OutlinedFun->addFnAttr(llvm::Attribute::AlwaysInline);
|
||||
|
||||
return OutlinedFun;
|
||||
@ -1243,10 +1244,10 @@ static void emitReductionListCopy(
|
||||
/// local = local @ remote
|
||||
/// else
|
||||
/// local = remote
|
||||
llvm::Value *emitReduceScratchpadFunction(CodeGenModule &CGM,
|
||||
ArrayRef<const Expr *> Privates,
|
||||
QualType ReductionArrayTy,
|
||||
llvm::Value *ReduceFn) {
|
||||
static llvm::Value *
|
||||
emitReduceScratchpadFunction(CodeGenModule &CGM,
|
||||
ArrayRef<const Expr *> Privates,
|
||||
QualType ReductionArrayTy, llvm::Value *ReduceFn) {
|
||||
auto &C = CGM.getContext();
|
||||
auto Int32Ty = C.getIntTypeForBitwidth(32, /* Signed */ true);
|
||||
|
||||
@ -1372,9 +1373,9 @@ llvm::Value *emitReduceScratchpadFunction(CodeGenModule &CGM,
|
||||
/// for elem in Reduce List:
|
||||
/// scratchpad[elem_id][index] = elem
|
||||
///
|
||||
llvm::Value *emitCopyToScratchpad(CodeGenModule &CGM,
|
||||
ArrayRef<const Expr *> Privates,
|
||||
QualType ReductionArrayTy) {
|
||||
static llvm::Value *emitCopyToScratchpad(CodeGenModule &CGM,
|
||||
ArrayRef<const Expr *> Privates,
|
||||
QualType ReductionArrayTy) {
|
||||
|
||||
auto &C = CGM.getContext();
|
||||
auto Int32Ty = C.getIntTypeForBitwidth(32, /* Signed */ true);
|
||||
|
@ -400,8 +400,11 @@ void CodeGenModule::Release() {
|
||||
}
|
||||
if (OpenMPRuntime)
|
||||
if (llvm::Function *OpenMPRegistrationFunction =
|
||||
OpenMPRuntime->emitRegistrationFunction())
|
||||
AddGlobalCtor(OpenMPRegistrationFunction, 0);
|
||||
OpenMPRuntime->emitRegistrationFunction()) {
|
||||
auto ComdatKey = OpenMPRegistrationFunction->hasComdat() ?
|
||||
OpenMPRegistrationFunction : nullptr;
|
||||
AddGlobalCtor(OpenMPRegistrationFunction, 0, ComdatKey);
|
||||
}
|
||||
if (PGOReader) {
|
||||
getModule().setProfileSummary(PGOReader->getSummary().getMD(VMContext));
|
||||
if (PGOStats.hasDiagnostics())
|
||||
@ -904,7 +907,16 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
|
||||
return;
|
||||
}
|
||||
|
||||
if (D->hasAttr<OptimizeNoneAttr>()) {
|
||||
// Track whether we need to add the optnone LLVM attribute,
|
||||
// starting with the default for this optimization level.
|
||||
bool ShouldAddOptNone =
|
||||
!CodeGenOpts.DisableO0ImplyOptNone && CodeGenOpts.OptimizationLevel == 0;
|
||||
// We can't add optnone in the following cases, it won't pass the verifier.
|
||||
ShouldAddOptNone &= !D->hasAttr<MinSizeAttr>();
|
||||
ShouldAddOptNone &= !F->hasFnAttribute(llvm::Attribute::AlwaysInline);
|
||||
ShouldAddOptNone &= !D->hasAttr<AlwaysInlineAttr>();
|
||||
|
||||
if (ShouldAddOptNone || D->hasAttr<OptimizeNoneAttr>()) {
|
||||
B.addAttribute(llvm::Attribute::OptimizeNone);
|
||||
|
||||
// OptimizeNone implies noinline; we should not be inlining such functions.
|
||||
@ -958,7 +970,8 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
|
||||
// function.
|
||||
if (!D->hasAttr<OptimizeNoneAttr>()) {
|
||||
if (D->hasAttr<ColdAttr>()) {
|
||||
B.addAttribute(llvm::Attribute::OptimizeForSize);
|
||||
if (!ShouldAddOptNone)
|
||||
B.addAttribute(llvm::Attribute::OptimizeForSize);
|
||||
B.addAttribute(llvm::Attribute::Cold);
|
||||
}
|
||||
|
||||
@ -1508,6 +1521,10 @@ bool CodeGenModule::imbueXRayAttrs(llvm::Function *Fn, SourceLocation Loc,
|
||||
case ImbueAttr::ALWAYS:
|
||||
Fn->addFnAttr("function-instrument", "xray-always");
|
||||
break;
|
||||
case ImbueAttr::ALWAYS_ARG1:
|
||||
Fn->addFnAttr("function-instrument", "xray-always");
|
||||
Fn->addFnAttr("xray-log-args", "1");
|
||||
break;
|
||||
case ImbueAttr::NEVER:
|
||||
Fn->addFnAttr("function-instrument", "xray-never");
|
||||
break;
|
||||
|
@ -4821,6 +4821,9 @@ private:
|
||||
bool isSwiftErrorInRegister() const override {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool isLegalVectorTypeForSwift(CharUnits totalSize, llvm::Type *eltTy,
|
||||
unsigned elts) const override;
|
||||
};
|
||||
|
||||
class AArch64TargetCodeGenInfo : public TargetCodeGenInfo {
|
||||
@ -4994,6 +4997,17 @@ bool AArch64ABIInfo::isIllegalVectorType(QualType Ty) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AArch64ABIInfo::isLegalVectorTypeForSwift(CharUnits totalSize,
|
||||
llvm::Type *eltTy,
|
||||
unsigned elts) const {
|
||||
if (!llvm::isPowerOf2_32(elts))
|
||||
return false;
|
||||
if (totalSize.getQuantity() != 8 &&
|
||||
(totalSize.getQuantity() != 16 || elts == 1))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AArch64ABIInfo::isHomogeneousAggregateBaseType(QualType Ty) const {
|
||||
// Homogeneous aggregates for AAPCS64 must have base types of a floating
|
||||
// point type or a short-vector type. This is the same as the 32-bit ABI,
|
||||
@ -5382,6 +5396,8 @@ private:
|
||||
bool isSwiftErrorInRegister() const override {
|
||||
return true;
|
||||
}
|
||||
bool isLegalVectorTypeForSwift(CharUnits totalSize, llvm::Type *eltTy,
|
||||
unsigned elts) const override;
|
||||
};
|
||||
|
||||
class ARMTargetCodeGenInfo : public TargetCodeGenInfo {
|
||||
@ -5894,6 +5910,20 @@ bool ARMABIInfo::isIllegalVectorType(QualType Ty) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ARMABIInfo::isLegalVectorTypeForSwift(CharUnits vectorSize,
|
||||
llvm::Type *eltTy,
|
||||
unsigned numElts) const {
|
||||
if (!llvm::isPowerOf2_32(numElts))
|
||||
return false;
|
||||
unsigned size = getDataLayout().getTypeStoreSizeInBits(eltTy);
|
||||
if (size > 64)
|
||||
return false;
|
||||
if (vectorSize.getQuantity() != 8 &&
|
||||
(vectorSize.getQuantity() != 16 || numElts == 1))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ARMABIInfo::isHomogeneousAggregateBaseType(QualType Ty) const {
|
||||
// Homogeneous aggregates for AAPCS-VFP must have base types of float,
|
||||
// double, or 64-bit or 128-bit vectors.
|
||||
|
@ -30,6 +30,7 @@ add_clang_library(clangDriver
|
||||
ToolChains/AMDGPU.cpp
|
||||
ToolChains/AVR.cpp
|
||||
ToolChains/Bitrig.cpp
|
||||
ToolChains/BareMetal.cpp
|
||||
ToolChains/Clang.cpp
|
||||
ToolChains/CloudABI.cpp
|
||||
ToolChains/CommonArgs.cpp
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "ToolChains/FreeBSD.h"
|
||||
#include "ToolChains/Fuchsia.h"
|
||||
#include "ToolChains/Gnu.h"
|
||||
#include "ToolChains/BareMetal.h"
|
||||
#include "ToolChains/Haiku.h"
|
||||
#include "ToolChains/Hexagon.h"
|
||||
#include "ToolChains/Lanai.h"
|
||||
@ -598,6 +599,8 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
|
||||
bool CCCPrintPhases;
|
||||
|
||||
InputArgList Args = ParseArgStrings(ArgList.slice(1));
|
||||
if (Diags.hasErrorOccurred())
|
||||
return nullptr;
|
||||
|
||||
// Silence driver warnings if requested
|
||||
Diags.setIgnoreAllWarnings(Args.hasArg(options::OPT_w));
|
||||
@ -1216,6 +1219,13 @@ bool Driver::HandleImmediateArgs(const Compilation &C) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Arg *A = C.getArgs().getLastArg(options::OPT_autocomplete)) {
|
||||
// Print out all options that start with a given argument. This is used for
|
||||
// shell autocompletion.
|
||||
llvm::outs() << llvm::join(Opts->findByPrefix(A->getValue()), " ") << '\n';
|
||||
return false;
|
||||
}
|
||||
|
||||
if (C.getArgs().hasArg(options::OPT_print_libgcc_file_name)) {
|
||||
ToolChain::RuntimeLibType RLT = TC.GetRuntimeLibType(C.getArgs());
|
||||
switch (RLT) {
|
||||
@ -3819,6 +3829,8 @@ const ToolChain &Driver::getToolChain(const ArgList &Args,
|
||||
if (Target.getVendor() == llvm::Triple::Myriad)
|
||||
TC = llvm::make_unique<toolchains::MyriadToolChain>(*this, Target,
|
||||
Args);
|
||||
else if (toolchains::BareMetal::handlesTarget(Target))
|
||||
TC = llvm::make_unique<toolchains::BareMetal>(*this, Target, Args);
|
||||
else if (Target.isOSBinFormatELF())
|
||||
TC = llvm::make_unique<toolchains::Generic_ELF>(*this, Target, Args);
|
||||
else if (Target.isOSBinFormatMachO())
|
||||
|
210
lib/Driver/ToolChains/BareMetal.cpp
Normal file
210
lib/Driver/ToolChains/BareMetal.cpp
Normal file
@ -0,0 +1,210 @@
|
||||
//===--- BaremMetal.cpp - Bare Metal ToolChain ------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "BareMetal.h"
|
||||
|
||||
#include "CommonArgs.h"
|
||||
#include "InputInfo.h"
|
||||
#include "Gnu.h"
|
||||
|
||||
#include "clang/Basic/VirtualFileSystem.h"
|
||||
#include "clang/Driver/Compilation.h"
|
||||
#include "clang/Driver/Driver.h"
|
||||
#include "clang/Driver/DriverDiagnostic.h"
|
||||
#include "clang/Driver/Options.h"
|
||||
#include "llvm/Option/ArgList.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
using namespace llvm::opt;
|
||||
using namespace clang;
|
||||
using namespace clang::driver;
|
||||
using namespace clang::driver::tools;
|
||||
using namespace clang::driver::toolchains;
|
||||
|
||||
BareMetal::BareMetal(const Driver &D, const llvm::Triple &Triple,
|
||||
const ArgList &Args)
|
||||
: ToolChain(D, Triple, Args) {
|
||||
getProgramPaths().push_back(getDriver().getInstalledDir());
|
||||
if (getDriver().getInstalledDir() != getDriver().Dir)
|
||||
getProgramPaths().push_back(getDriver().Dir);
|
||||
}
|
||||
|
||||
BareMetal::~BareMetal() {}
|
||||
|
||||
/// Is the triple {arm,thumb}-none-none-{eabi,eabihf} ?
|
||||
static bool isARMBareMetal(const llvm::Triple &Triple) {
|
||||
if (Triple.getArch() != llvm::Triple::arm &&
|
||||
Triple.getArch() != llvm::Triple::thumb)
|
||||
return false;
|
||||
|
||||
if (Triple.getVendor() != llvm::Triple::UnknownVendor)
|
||||
return false;
|
||||
|
||||
if (Triple.getOS() != llvm::Triple::UnknownOS)
|
||||
return false;
|
||||
|
||||
if (Triple.getEnvironment() != llvm::Triple::EABI &&
|
||||
Triple.getEnvironment() != llvm::Triple::EABIHF)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BareMetal::handlesTarget(const llvm::Triple &Triple) {
|
||||
return isARMBareMetal(Triple);
|
||||
}
|
||||
|
||||
Tool *BareMetal::buildLinker() const {
|
||||
return new tools::baremetal::Linker(*this);
|
||||
}
|
||||
|
||||
std::string BareMetal::getThreadModel() const {
|
||||
return "single";
|
||||
}
|
||||
|
||||
bool BareMetal::isThreadModelSupported(const StringRef Model) const {
|
||||
return Model == "single";
|
||||
}
|
||||
|
||||
std::string BareMetal::getRuntimesDir() const {
|
||||
SmallString<128> Dir(getDriver().ResourceDir);
|
||||
llvm::sys::path::append(Dir, "lib", "baremetal");
|
||||
return Dir.str();
|
||||
}
|
||||
|
||||
void BareMetal::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
|
||||
ArgStringList &CC1Args) const {
|
||||
if (DriverArgs.hasArg(options::OPT_nostdinc))
|
||||
return;
|
||||
|
||||
if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
|
||||
SmallString<128> Dir(getDriver().ResourceDir);
|
||||
llvm::sys::path::append(Dir, "include");
|
||||
addSystemInclude(DriverArgs, CC1Args, Dir.str());
|
||||
}
|
||||
|
||||
if (!DriverArgs.hasArg(options::OPT_nostdlibinc)) {
|
||||
SmallString<128> Dir(getDriver().SysRoot);
|
||||
llvm::sys::path::append(Dir, "include");
|
||||
addSystemInclude(DriverArgs, CC1Args, Dir.str());
|
||||
}
|
||||
}
|
||||
|
||||
void BareMetal::addClangTargetOptions(const ArgList &DriverArgs,
|
||||
ArgStringList &CC1Args) const {
|
||||
CC1Args.push_back("-nostdsysteminc");
|
||||
}
|
||||
|
||||
std::string BareMetal::findLibCxxIncludePath(CXXStdlibType LibType) const {
|
||||
StringRef SysRoot = getDriver().SysRoot;
|
||||
if (SysRoot.empty())
|
||||
return "";
|
||||
|
||||
switch (LibType) {
|
||||
case ToolChain::CST_Libcxx: {
|
||||
SmallString<128> Dir(SysRoot);
|
||||
llvm::sys::path::append(Dir, "include", "c++", "v1");
|
||||
return Dir.str();
|
||||
}
|
||||
case ToolChain::CST_Libstdcxx: {
|
||||
SmallString<128> Dir(SysRoot);
|
||||
llvm::sys::path::append(Dir, "include", "c++");
|
||||
std::error_code EC;
|
||||
Generic_GCC::GCCVersion Version = {"", -1, -1, -1, "", "", ""};
|
||||
// Walk the subdirs, and find the one with the newest gcc version:
|
||||
for (vfs::directory_iterator LI =
|
||||
getDriver().getVFS().dir_begin(Dir.str(), EC), LE;
|
||||
!EC && LI != LE; LI = LI.increment(EC)) {
|
||||
StringRef VersionText = llvm::sys::path::filename(LI->getName());
|
||||
auto CandidateVersion = Generic_GCC::GCCVersion::Parse(VersionText);
|
||||
if (CandidateVersion.Major == -1)
|
||||
continue;
|
||||
if (CandidateVersion <= Version)
|
||||
continue;
|
||||
Version = CandidateVersion;
|
||||
}
|
||||
if (Version.Major == -1)
|
||||
return "";
|
||||
llvm::sys::path::append(Dir, Version.Text);
|
||||
return Dir.str();
|
||||
}
|
||||
}
|
||||
llvm_unreachable("unhandled LibType");
|
||||
}
|
||||
|
||||
void BareMetal::AddClangCXXStdlibIncludeArgs(
|
||||
const ArgList &DriverArgs, ArgStringList &CC1Args) const {
|
||||
if (DriverArgs.hasArg(options::OPT_nostdinc) ||
|
||||
DriverArgs.hasArg(options::OPT_nostdlibinc) ||
|
||||
DriverArgs.hasArg(options::OPT_nostdincxx))
|
||||
return;
|
||||
|
||||
std::string Path = findLibCxxIncludePath(GetCXXStdlibType(DriverArgs));
|
||||
if (!Path.empty())
|
||||
addSystemInclude(DriverArgs, CC1Args, Path);
|
||||
}
|
||||
|
||||
void BareMetal::AddCXXStdlibLibArgs(const ArgList &Args,
|
||||
ArgStringList &CmdArgs) const {
|
||||
switch (GetCXXStdlibType(Args)) {
|
||||
case ToolChain::CST_Libcxx:
|
||||
CmdArgs.push_back("-lc++");
|
||||
CmdArgs.push_back("-lc++abi");
|
||||
break;
|
||||
case ToolChain::CST_Libstdcxx:
|
||||
CmdArgs.push_back("-lstdc++");
|
||||
CmdArgs.push_back("-lsupc++");
|
||||
break;
|
||||
}
|
||||
CmdArgs.push_back("-lunwind");
|
||||
}
|
||||
|
||||
void BareMetal::AddLinkRuntimeLib(const ArgList &Args,
|
||||
ArgStringList &CmdArgs) const {
|
||||
CmdArgs.push_back(Args.MakeArgString("-lclang_rt.builtins-" +
|
||||
getTriple().getArchName() + ".a"));
|
||||
}
|
||||
|
||||
void baremetal::Linker::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
const InputInfo &Output,
|
||||
const InputInfoList &Inputs,
|
||||
const ArgList &Args,
|
||||
const char *LinkingOutput) const {
|
||||
ArgStringList CmdArgs;
|
||||
|
||||
auto &TC = static_cast<const toolchains::BareMetal&>(getToolChain());
|
||||
|
||||
AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA);
|
||||
|
||||
CmdArgs.push_back("-Bstatic");
|
||||
|
||||
CmdArgs.push_back(Args.MakeArgString("-L" + TC.getRuntimesDir()));
|
||||
|
||||
Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group,
|
||||
options::OPT_e, options::OPT_s, options::OPT_t,
|
||||
options::OPT_Z_Flag, options::OPT_r});
|
||||
|
||||
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
|
||||
if (C.getDriver().CCCIsCXX())
|
||||
TC.AddCXXStdlibLibArgs(Args, CmdArgs);
|
||||
|
||||
CmdArgs.push_back("-lc");
|
||||
CmdArgs.push_back("-lm");
|
||||
|
||||
TC.AddLinkRuntimeLib(Args, CmdArgs);
|
||||
}
|
||||
|
||||
CmdArgs.push_back("-o");
|
||||
CmdArgs.push_back(Output.getFilename());
|
||||
|
||||
C.addCommand(llvm::make_unique<Command>(JA, *this,
|
||||
Args.MakeArgString(TC.GetLinkerPath()),
|
||||
CmdArgs, Inputs));
|
||||
}
|
90
lib/Driver/ToolChains/BareMetal.h
Normal file
90
lib/Driver/ToolChains/BareMetal.h
Normal file
@ -0,0 +1,90 @@
|
||||
//===--- BareMetal.h - Bare Metal Tool and ToolChain -------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_BAREMETAL_H
|
||||
#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_BAREMETAL_H
|
||||
|
||||
#include "clang/Driver/Tool.h"
|
||||
#include "clang/Driver/ToolChain.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace clang {
|
||||
namespace driver {
|
||||
|
||||
namespace toolchains {
|
||||
|
||||
class LLVM_LIBRARY_VISIBILITY BareMetal : public ToolChain {
|
||||
public:
|
||||
BareMetal(const Driver &D, const llvm::Triple &Triple,
|
||||
const llvm::opt::ArgList &Args);
|
||||
~BareMetal() override;
|
||||
|
||||
static bool handlesTarget(const llvm::Triple &Triple);
|
||||
protected:
|
||||
Tool *buildLinker() const override;
|
||||
|
||||
public:
|
||||
bool useIntegratedAs() const override { return true; }
|
||||
bool isCrossCompiling() const override { return true; }
|
||||
bool isPICDefault() const override { return false; }
|
||||
bool isPIEDefault() const override { return false; }
|
||||
bool isPICDefaultForced() const override { return false; }
|
||||
bool SupportsProfiling() const override { return false; }
|
||||
bool SupportsObjCGC() const override { return false; }
|
||||
std::string getThreadModel() const override;
|
||||
bool isThreadModelSupported(const StringRef Model) const override;
|
||||
|
||||
RuntimeLibType GetDefaultRuntimeLibType() const override {
|
||||
return ToolChain::RLT_CompilerRT;
|
||||
}
|
||||
CXXStdlibType GetDefaultCXXStdlibType() const override {
|
||||
return ToolChain::CST_Libcxx;
|
||||
}
|
||||
|
||||
const char *getDefaultLinker() const override { return "ld.lld"; }
|
||||
|
||||
std::string getRuntimesDir() const;
|
||||
void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
|
||||
llvm::opt::ArgStringList &CC1Args) const override;
|
||||
void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
|
||||
llvm::opt::ArgStringList &CC1Args) const override;
|
||||
std::string findLibCxxIncludePath(ToolChain::CXXStdlibType LibType) const;
|
||||
void AddClangCXXStdlibIncludeArgs(
|
||||
const llvm::opt::ArgList &DriverArgs,
|
||||
llvm::opt::ArgStringList &CC1Args) const override;
|
||||
void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
|
||||
llvm::opt::ArgStringList &CmdArgs) const override;
|
||||
void AddLinkRuntimeLib(const llvm::opt::ArgList &Args,
|
||||
llvm::opt::ArgStringList &CmdArgs) const;
|
||||
};
|
||||
|
||||
} // namespace toolchains
|
||||
|
||||
namespace tools {
|
||||
namespace baremetal {
|
||||
|
||||
class LLVM_LIBRARY_VISIBILITY Linker : public Tool {
|
||||
public:
|
||||
Linker(const ToolChain &TC) : Tool("baremetal::Linker", "ld.lld", TC) {}
|
||||
bool isLinkJob() const override { return true; }
|
||||
bool hasIntegratedCPP() const override { return false; }
|
||||
void ConstructJob(Compilation &C, const JobAction &JA,
|
||||
const InputInfo &Output, const InputInfoList &Inputs,
|
||||
const llvm::opt::ArgList &TCArgs,
|
||||
const char *LinkingOutput) const override;
|
||||
};
|
||||
|
||||
} // namespace baremetal
|
||||
} // namespace tools
|
||||
|
||||
} // namespace driver
|
||||
} // namespace clang
|
||||
|
||||
#endif
|
@ -1598,6 +1598,49 @@ bool Generic_GCC::GCCVersion::isOlderThan(int RHSMajor, int RHSMinor,
|
||||
return false;
|
||||
}
|
||||
|
||||
/// \brief Parse a GCCVersion object out of a string of text.
|
||||
///
|
||||
/// This is the primary means of forming GCCVersion objects.
|
||||
/*static*/
|
||||
Generic_GCC::GCCVersion Generic_GCC::GCCVersion::Parse(StringRef VersionText) {
|
||||
const GCCVersion BadVersion = {VersionText.str(), -1, -1, -1, "", "", ""};
|
||||
std::pair<StringRef, StringRef> First = VersionText.split('.');
|
||||
std::pair<StringRef, StringRef> Second = First.second.split('.');
|
||||
|
||||
GCCVersion GoodVersion = {VersionText.str(), -1, -1, -1, "", "", ""};
|
||||
if (First.first.getAsInteger(10, GoodVersion.Major) || GoodVersion.Major < 0)
|
||||
return BadVersion;
|
||||
GoodVersion.MajorStr = First.first.str();
|
||||
if (First.second.empty())
|
||||
return GoodVersion;
|
||||
if (Second.first.getAsInteger(10, GoodVersion.Minor) || GoodVersion.Minor < 0)
|
||||
return BadVersion;
|
||||
GoodVersion.MinorStr = Second.first.str();
|
||||
|
||||
// First look for a number prefix and parse that if present. Otherwise just
|
||||
// stash the entire patch string in the suffix, and leave the number
|
||||
// unspecified. This covers versions strings such as:
|
||||
// 5 (handled above)
|
||||
// 4.4
|
||||
// 4.4.0
|
||||
// 4.4.x
|
||||
// 4.4.2-rc4
|
||||
// 4.4.x-patched
|
||||
// And retains any patch number it finds.
|
||||
StringRef PatchText = GoodVersion.PatchSuffix = Second.second.str();
|
||||
if (!PatchText.empty()) {
|
||||
if (size_t EndNumber = PatchText.find_first_not_of("0123456789")) {
|
||||
// Try to parse the number and any suffix.
|
||||
if (PatchText.slice(0, EndNumber).getAsInteger(10, GoodVersion.Patch) ||
|
||||
GoodVersion.Patch < 0)
|
||||
return BadVersion;
|
||||
GoodVersion.PatchSuffix = PatchText.substr(EndNumber);
|
||||
}
|
||||
}
|
||||
|
||||
return GoodVersion;
|
||||
}
|
||||
|
||||
static llvm::StringRef getGCCToolchainDir(const ArgList &Args) {
|
||||
const Arg *A = Args.getLastArg(clang::driver::options::OPT_gcc_toolchain);
|
||||
if (A)
|
||||
|
@ -372,49 +372,6 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
|
||||
addPathIfExists(D, SysRoot + "/usr/lib", Paths);
|
||||
}
|
||||
|
||||
/// \brief Parse a GCCVersion object out of a string of text.
|
||||
///
|
||||
/// This is the primary means of forming GCCVersion objects.
|
||||
/*static*/
|
||||
Generic_GCC::GCCVersion Linux::GCCVersion::Parse(StringRef VersionText) {
|
||||
const GCCVersion BadVersion = {VersionText.str(), -1, -1, -1, "", "", ""};
|
||||
std::pair<StringRef, StringRef> First = VersionText.split('.');
|
||||
std::pair<StringRef, StringRef> Second = First.second.split('.');
|
||||
|
||||
GCCVersion GoodVersion = {VersionText.str(), -1, -1, -1, "", "", ""};
|
||||
if (First.first.getAsInteger(10, GoodVersion.Major) || GoodVersion.Major < 0)
|
||||
return BadVersion;
|
||||
GoodVersion.MajorStr = First.first.str();
|
||||
if (First.second.empty())
|
||||
return GoodVersion;
|
||||
if (Second.first.getAsInteger(10, GoodVersion.Minor) || GoodVersion.Minor < 0)
|
||||
return BadVersion;
|
||||
GoodVersion.MinorStr = Second.first.str();
|
||||
|
||||
// First look for a number prefix and parse that if present. Otherwise just
|
||||
// stash the entire patch string in the suffix, and leave the number
|
||||
// unspecified. This covers versions strings such as:
|
||||
// 5 (handled above)
|
||||
// 4.4
|
||||
// 4.4.0
|
||||
// 4.4.x
|
||||
// 4.4.2-rc4
|
||||
// 4.4.x-patched
|
||||
// And retains any patch number it finds.
|
||||
StringRef PatchText = GoodVersion.PatchSuffix = Second.second.str();
|
||||
if (!PatchText.empty()) {
|
||||
if (size_t EndNumber = PatchText.find_first_not_of("0123456789")) {
|
||||
// Try to parse the number and any suffix.
|
||||
if (PatchText.slice(0, EndNumber).getAsInteger(10, GoodVersion.Patch) ||
|
||||
GoodVersion.Patch < 0)
|
||||
return BadVersion;
|
||||
GoodVersion.PatchSuffix = PatchText.substr(EndNumber);
|
||||
}
|
||||
}
|
||||
|
||||
return GoodVersion;
|
||||
}
|
||||
|
||||
bool Linux::HasNativeLLVMSupport() const { return true; }
|
||||
|
||||
Tool *Linux::buildLinker() const { return new tools::gnutools::Linker(*this); }
|
||||
|
@ -217,6 +217,7 @@ MyriadToolChain::MyriadToolChain(const Driver &D, const llvm::Triple &Triple,
|
||||
default:
|
||||
D.Diag(clang::diag::err_target_unsupported_arch)
|
||||
<< Triple.getArchName() << "myriad";
|
||||
LLVM_FALLTHROUGH;
|
||||
case llvm::Triple::sparc:
|
||||
case llvm::Triple::sparcel:
|
||||
case llvm::Triple::shave:
|
||||
|
@ -54,13 +54,14 @@ static bool startsNextParameter(const FormatToken &Current,
|
||||
const FormatStyle &Style) {
|
||||
const FormatToken &Previous = *Current.Previous;
|
||||
if (Current.is(TT_CtorInitializerComma) &&
|
||||
Style.BreakConstructorInitializersBeforeComma)
|
||||
Style.BreakConstructorInitializers == FormatStyle::BCIS_BeforeComma)
|
||||
return true;
|
||||
return Previous.is(tok::comma) && !Current.isTrailingComment() &&
|
||||
((Previous.isNot(TT_CtorInitializerComma) ||
|
||||
!Style.BreakConstructorInitializersBeforeComma) &&
|
||||
Style.BreakConstructorInitializers !=
|
||||
FormatStyle::BCIS_BeforeComma) &&
|
||||
(Previous.isNot(TT_InheritanceComma) ||
|
||||
!Style.BreakBeforeInheritanceComma));
|
||||
!Style.BreakBeforeInheritanceComma));
|
||||
}
|
||||
|
||||
ContinuationIndenter::ContinuationIndenter(const FormatStyle &Style,
|
||||
@ -178,13 +179,20 @@ bool ContinuationIndenter::mustBreak(const LineState &State) {
|
||||
getLengthToMatchingParen(Previous) + State.Column - 1 >
|
||||
getColumnLimit(State))
|
||||
return true;
|
||||
if (Current.is(TT_CtorInitializerColon) &&
|
||||
(State.Column + State.Line->Last->TotalLength - Current.TotalLength + 2 >
|
||||
|
||||
const FormatToken &BreakConstructorInitializersToken =
|
||||
Style.BreakConstructorInitializers == FormatStyle::BCIS_AfterColon
|
||||
? Previous
|
||||
: Current;
|
||||
if (BreakConstructorInitializersToken.is(TT_CtorInitializerColon) &&
|
||||
(State.Column + State.Line->Last->TotalLength - Previous.TotalLength >
|
||||
getColumnLimit(State) ||
|
||||
State.Stack.back().BreakBeforeParameter) &&
|
||||
((Style.AllowShortFunctionsOnASingleLine != FormatStyle::SFS_All) ||
|
||||
Style.BreakConstructorInitializersBeforeComma || Style.ColumnLimit != 0))
|
||||
(Style.AllowShortFunctionsOnASingleLine != FormatStyle::SFS_All ||
|
||||
Style.BreakConstructorInitializers != FormatStyle::BCIS_BeforeColon ||
|
||||
Style.ColumnLimit != 0))
|
||||
return true;
|
||||
|
||||
if (Current.is(TT_ObjCMethodExpr) && !Previous.is(TT_SelectorName) &&
|
||||
State.Line->startsWith(TT_ObjCMethodSpecifier))
|
||||
return true;
|
||||
@ -207,7 +215,7 @@ bool ContinuationIndenter::mustBreak(const LineState &State) {
|
||||
// ...
|
||||
// }.bind(...));
|
||||
// FIXME: We should find a more generic solution to this problem.
|
||||
!(State.Column <= NewLineColumn && Previous.isNot(tok::r_paren) &&
|
||||
!(State.Column <= NewLineColumn &&
|
||||
Style.Language == FormatStyle::LK_JavaScript))
|
||||
return true;
|
||||
|
||||
@ -455,6 +463,11 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
|
||||
!Previous.is(TT_OverloadedOperator)) ||
|
||||
(Previous.is(tok::colon) && Previous.is(TT_ObjCMethodExpr)))) {
|
||||
State.Stack.back().LastSpace = State.Column;
|
||||
} else if (Previous.is(TT_CtorInitializerColon) &&
|
||||
Style.BreakConstructorInitializers ==
|
||||
FormatStyle::BCIS_AfterColon) {
|
||||
State.Stack.back().Indent = State.Column;
|
||||
State.Stack.back().LastSpace = State.Column;
|
||||
} else if ((Previous.isOneOf(TT_BinaryOperator, TT_ConditionalExpr,
|
||||
TT_CtorInitializerColon)) &&
|
||||
((Previous.getPrecedence() != prec::Assignment &&
|
||||
@ -614,7 +627,7 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State,
|
||||
State.Stack[i].BreakBeforeParameter = true;
|
||||
|
||||
if (PreviousNonComment &&
|
||||
!PreviousNonComment->isOneOf(tok::comma, tok::semi) &&
|
||||
!PreviousNonComment->isOneOf(tok::comma, tok::colon, tok::semi) &&
|
||||
(PreviousNonComment->isNot(TT_TemplateCloser) ||
|
||||
Current.NestingLevel != 0) &&
|
||||
!PreviousNonComment->isOneOf(
|
||||
@ -676,7 +689,18 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) {
|
||||
return State.Stack[State.Stack.size() - 2].LastSpace;
|
||||
return State.FirstIndent;
|
||||
}
|
||||
if (Current.is(tok::r_paren) && State.Stack.size() > 1)
|
||||
// Indent a closing parenthesis at the previous level if followed by a semi or
|
||||
// opening brace. This allows indentations such as:
|
||||
// foo(
|
||||
// a,
|
||||
// );
|
||||
// function foo(
|
||||
// a,
|
||||
// ) {
|
||||
// code(); //
|
||||
// }
|
||||
if (Current.is(tok::r_paren) && State.Stack.size() > 1 &&
|
||||
(!Current.Next || Current.Next->isOneOf(tok::semi, tok::l_brace)))
|
||||
return State.Stack[State.Stack.size() - 2].LastSpace;
|
||||
if (NextNonComment->is(TT_TemplateString) && NextNonComment->closesScope())
|
||||
return State.Stack[State.Stack.size() - 2].LastSpace;
|
||||
@ -750,6 +774,9 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) {
|
||||
return ContinuationIndent;
|
||||
if (NextNonComment->is(TT_CtorInitializerComma))
|
||||
return State.Stack.back().Indent;
|
||||
if (PreviousNonComment && PreviousNonComment->is(TT_CtorInitializerColon) &&
|
||||
Style.BreakConstructorInitializers == FormatStyle::BCIS_AfterColon)
|
||||
return State.Stack.back().Indent;
|
||||
if (NextNonComment->isOneOf(TT_CtorInitializerColon, TT_InheritanceColon,
|
||||
TT_InheritanceComma))
|
||||
return State.FirstIndent + Style.ConstructorInitializerIndentWidth;
|
||||
@ -810,19 +837,29 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State,
|
||||
State.FirstIndent + Style.ContinuationIndentWidth;
|
||||
}
|
||||
}
|
||||
if (Current.is(TT_CtorInitializerColon)) {
|
||||
if (Current.is(TT_CtorInitializerColon) &&
|
||||
Style.BreakConstructorInitializers != FormatStyle::BCIS_AfterColon) {
|
||||
// Indent 2 from the column, so:
|
||||
// SomeClass::SomeClass()
|
||||
// : First(...), ...
|
||||
// Next(...)
|
||||
// ^ line up here.
|
||||
State.Stack.back().Indent =
|
||||
State.Column + (Style.BreakConstructorInitializersBeforeComma ? 0 : 2);
|
||||
State.Column + (Style.BreakConstructorInitializers ==
|
||||
FormatStyle::BCIS_BeforeComma ? 0 : 2);
|
||||
State.Stack.back().NestedBlockIndent = State.Stack.back().Indent;
|
||||
if (Style.ConstructorInitializerAllOnOneLineOrOnePerLine)
|
||||
State.Stack.back().AvoidBinPacking = true;
|
||||
State.Stack.back().BreakBeforeParameter = false;
|
||||
}
|
||||
if (Current.is(TT_CtorInitializerColon) &&
|
||||
Style.BreakConstructorInitializers == FormatStyle::BCIS_AfterColon) {
|
||||
State.Stack.back().Indent =
|
||||
State.FirstIndent + Style.ConstructorInitializerIndentWidth;
|
||||
State.Stack.back().NestedBlockIndent = State.Stack.back().Indent;
|
||||
if (Style.ConstructorInitializerAllOnOneLineOrOnePerLine)
|
||||
State.Stack.back().AvoidBinPacking = true;
|
||||
}
|
||||
if (Current.is(TT_InheritanceColon))
|
||||
State.Stack.back().Indent =
|
||||
State.FirstIndent + Style.ContinuationIndentWidth;
|
||||
|
@ -123,6 +123,14 @@ template <> struct ScalarEnumerationTraits<FormatStyle::BraceBreakingStyle> {
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct ScalarEnumerationTraits<FormatStyle::BreakConstructorInitializersStyle> {
|
||||
static void enumeration(IO &IO, FormatStyle::BreakConstructorInitializersStyle &Value) {
|
||||
IO.enumCase(Value, "BeforeColon", FormatStyle::BCIS_BeforeColon);
|
||||
IO.enumCase(Value, "BeforeComma", FormatStyle::BCIS_BeforeComma);
|
||||
IO.enumCase(Value, "AfterColon", FormatStyle::BCIS_AfterColon);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ScalarEnumerationTraits<FormatStyle::ReturnTypeBreakingStyle> {
|
||||
static void enumeration(IO &IO, FormatStyle::ReturnTypeBreakingStyle &Value) {
|
||||
@ -304,8 +312,19 @@ template <> struct MappingTraits<FormatStyle> {
|
||||
IO.mapOptional("BreakBeforeBraces", Style.BreakBeforeBraces);
|
||||
IO.mapOptional("BreakBeforeTernaryOperators",
|
||||
Style.BreakBeforeTernaryOperators);
|
||||
|
||||
bool BreakConstructorInitializersBeforeComma = false;
|
||||
IO.mapOptional("BreakConstructorInitializersBeforeComma",
|
||||
Style.BreakConstructorInitializersBeforeComma);
|
||||
BreakConstructorInitializersBeforeComma);
|
||||
IO.mapOptional("BreakConstructorInitializers",
|
||||
Style.BreakConstructorInitializers);
|
||||
// If BreakConstructorInitializersBeforeComma was specified but
|
||||
// BreakConstructorInitializers was not, initialize the latter from the
|
||||
// former for backwards compatibility.
|
||||
if (BreakConstructorInitializersBeforeComma &&
|
||||
Style.BreakConstructorInitializers == FormatStyle::BCIS_BeforeColon)
|
||||
Style.BreakConstructorInitializers = FormatStyle::BCIS_BeforeComma;
|
||||
|
||||
IO.mapOptional("BreakAfterJavaFieldAnnotations",
|
||||
Style.BreakAfterJavaFieldAnnotations);
|
||||
IO.mapOptional("BreakStringLiterals", Style.BreakStringLiterals);
|
||||
@ -537,7 +556,7 @@ FormatStyle getLLVMStyle() {
|
||||
LLVMStyle.BraceWrapping = {false, false, false, false, false, false,
|
||||
false, false, false, false, false};
|
||||
LLVMStyle.BreakAfterJavaFieldAnnotations = false;
|
||||
LLVMStyle.BreakConstructorInitializersBeforeComma = false;
|
||||
LLVMStyle.BreakConstructorInitializers = FormatStyle::BCIS_BeforeColon;
|
||||
LLVMStyle.BreakBeforeInheritanceComma = false;
|
||||
LLVMStyle.BreakStringLiterals = true;
|
||||
LLVMStyle.ColumnLimit = 80;
|
||||
@ -694,7 +713,7 @@ FormatStyle getMozillaStyle() {
|
||||
MozillaStyle.BinPackParameters = false;
|
||||
MozillaStyle.BinPackArguments = false;
|
||||
MozillaStyle.BreakBeforeBraces = FormatStyle::BS_Mozilla;
|
||||
MozillaStyle.BreakConstructorInitializersBeforeComma = true;
|
||||
MozillaStyle.BreakConstructorInitializers = FormatStyle::BCIS_BeforeComma;
|
||||
MozillaStyle.BreakBeforeInheritanceComma = true;
|
||||
MozillaStyle.ConstructorInitializerIndentWidth = 2;
|
||||
MozillaStyle.ContinuationIndentWidth = 2;
|
||||
@ -717,7 +736,7 @@ FormatStyle getWebKitStyle() {
|
||||
Style.AlignTrailingComments = false;
|
||||
Style.BreakBeforeBinaryOperators = FormatStyle::BOS_All;
|
||||
Style.BreakBeforeBraces = FormatStyle::BS_WebKit;
|
||||
Style.BreakConstructorInitializersBeforeComma = true;
|
||||
Style.BreakConstructorInitializers = FormatStyle::BCIS_BeforeComma;
|
||||
Style.Cpp11BracedListStyle = false;
|
||||
Style.ColumnLimit = 0;
|
||||
Style.FixNamespaceComments = false;
|
||||
@ -1891,6 +1910,9 @@ tooling::Replacements reformat(const FormatStyle &Style, StringRef Code,
|
||||
tooling::Replacements cleanup(const FormatStyle &Style, StringRef Code,
|
||||
ArrayRef<tooling::Range> Ranges,
|
||||
StringRef FileName) {
|
||||
// cleanups only apply to C++ (they mostly concern ctor commas etc.)
|
||||
if (Style.Language != FormatStyle::LK_Cpp)
|
||||
return tooling::Replacements();
|
||||
std::unique_ptr<Environment> Env =
|
||||
Environment::CreateVirtualEnvironment(Code, FileName, Ranges);
|
||||
Cleaner Clean(*Env, Style);
|
||||
|
@ -1996,7 +1996,7 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line,
|
||||
if (Left.is(tok::comment))
|
||||
return 1000;
|
||||
|
||||
if (Left.isOneOf(TT_RangeBasedForLoopColon, TT_InheritanceColon))
|
||||
if (Left.isOneOf(TT_RangeBasedForLoopColon, TT_InheritanceColon, TT_CtorInitializerColon))
|
||||
return 2;
|
||||
|
||||
if (Right.isMemberAccess()) {
|
||||
@ -2514,8 +2514,12 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
|
||||
Right.Previous->MatchingParen->NestingLevel == 0 &&
|
||||
Style.AlwaysBreakTemplateDeclarations)
|
||||
return true;
|
||||
if ((Right.isOneOf(TT_CtorInitializerComma, TT_CtorInitializerColon)) &&
|
||||
Style.BreakConstructorInitializersBeforeComma &&
|
||||
if (Right.is(TT_CtorInitializerComma) &&
|
||||
Style.BreakConstructorInitializers == FormatStyle::BCIS_BeforeComma &&
|
||||
!Style.ConstructorInitializerAllOnOneLineOrOnePerLine)
|
||||
return true;
|
||||
if (Right.is(TT_CtorInitializerColon) &&
|
||||
Style.BreakConstructorInitializers == FormatStyle::BCIS_BeforeComma &&
|
||||
!Style.ConstructorInitializerAllOnOneLineOrOnePerLine)
|
||||
return true;
|
||||
// Break only if we have multiple inheritance.
|
||||
@ -2625,7 +2629,10 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
|
||||
// The first comment in a braced lists is always interpreted as belonging to
|
||||
// the first list element. Otherwise, it should be placed outside of the
|
||||
// list.
|
||||
return Left.BlockKind == BK_BracedInit;
|
||||
return Left.BlockKind == BK_BracedInit ||
|
||||
(Left.is(TT_CtorInitializerColon) &&
|
||||
Style.BreakConstructorInitializers ==
|
||||
FormatStyle::BCIS_AfterColon);
|
||||
if (Left.is(tok::question) && Right.is(tok::colon))
|
||||
return false;
|
||||
if (Right.is(TT_ConditionalExpr) || Right.is(tok::question))
|
||||
@ -2698,11 +2705,15 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
|
||||
if (Right.is(tok::identifier) && Right.Next && Right.Next->is(TT_DictLiteral))
|
||||
return true;
|
||||
|
||||
if (Left.is(TT_CtorInitializerColon))
|
||||
return Style.BreakConstructorInitializers == FormatStyle::BCIS_AfterColon;
|
||||
if (Right.is(TT_CtorInitializerColon))
|
||||
return Style.BreakConstructorInitializers != FormatStyle::BCIS_AfterColon;
|
||||
if (Left.is(TT_CtorInitializerComma) &&
|
||||
Style.BreakConstructorInitializersBeforeComma)
|
||||
Style.BreakConstructorInitializers == FormatStyle::BCIS_BeforeComma)
|
||||
return false;
|
||||
if (Right.is(TT_CtorInitializerComma) &&
|
||||
Style.BreakConstructorInitializersBeforeComma)
|
||||
Style.BreakConstructorInitializers == FormatStyle::BCIS_BeforeComma)
|
||||
return true;
|
||||
if (Left.is(TT_InheritanceComma) && Style.BreakBeforeInheritanceComma)
|
||||
return false;
|
||||
|
@ -90,6 +90,21 @@ namespace {
|
||||
/// \brief Erase temporary files and the preamble file.
|
||||
void Cleanup();
|
||||
};
|
||||
|
||||
template <class T>
|
||||
std::unique_ptr<T> valueOrNull(llvm::ErrorOr<std::unique_ptr<T>> Val) {
|
||||
if (!Val)
|
||||
return nullptr;
|
||||
return std::move(*Val);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool moveOnNoError(llvm::ErrorOr<T> Val, T &Output) {
|
||||
if (!Val)
|
||||
return false;
|
||||
Output = std::move(*Val);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static llvm::sys::SmartMutex<false> &getOnDiskMutex() {
|
||||
@ -1019,7 +1034,8 @@ static void checkAndSanitizeDiags(SmallVectorImpl<StoredDiagnostic> &
|
||||
/// \returns True if a failure occurred that causes the ASTUnit not to
|
||||
/// contain any translation-unit information, false otherwise.
|
||||
bool ASTUnit::Parse(std::shared_ptr<PCHContainerOperations> PCHContainerOps,
|
||||
std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer) {
|
||||
std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer,
|
||||
IntrusiveRefCntPtr<vfs::FileSystem> VFS) {
|
||||
SavedMainFileBuffer.reset();
|
||||
|
||||
if (!Invocation)
|
||||
@ -1028,6 +1044,12 @@ bool ASTUnit::Parse(std::shared_ptr<PCHContainerOperations> PCHContainerOps,
|
||||
// Create the compiler instance to use for building the AST.
|
||||
std::unique_ptr<CompilerInstance> Clang(
|
||||
new CompilerInstance(std::move(PCHContainerOps)));
|
||||
if (FileMgr && VFS) {
|
||||
assert(VFS == FileMgr->getVirtualFileSystem() &&
|
||||
"VFS passed to Parse and VFS in FileMgr are different");
|
||||
} else if (VFS) {
|
||||
Clang->setVirtualFileSystem(VFS);
|
||||
}
|
||||
|
||||
// Recover resources if we crash before exiting this method.
|
||||
llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance>
|
||||
@ -1170,7 +1192,8 @@ static std::string GetPreamblePCHPath() {
|
||||
/// that corresponds to the main file along with a pair (bytes, start-of-line)
|
||||
/// that describes the preamble.
|
||||
ASTUnit::ComputedPreamble
|
||||
ASTUnit::ComputePreamble(CompilerInvocation &Invocation, unsigned MaxLines) {
|
||||
ASTUnit::ComputePreamble(CompilerInvocation &Invocation, unsigned MaxLines,
|
||||
IntrusiveRefCntPtr<vfs::FileSystem> VFS) {
|
||||
FrontendOptions &FrontendOpts = Invocation.getFrontendOpts();
|
||||
PreprocessorOptions &PreprocessorOpts = Invocation.getPreprocessorOpts();
|
||||
|
||||
@ -1180,28 +1203,32 @@ ASTUnit::ComputePreamble(CompilerInvocation &Invocation, unsigned MaxLines) {
|
||||
llvm::MemoryBuffer *Buffer = nullptr;
|
||||
std::unique_ptr<llvm::MemoryBuffer> BufferOwner;
|
||||
std::string MainFilePath(FrontendOpts.Inputs[0].getFile());
|
||||
llvm::sys::fs::UniqueID MainFileID;
|
||||
if (!llvm::sys::fs::getUniqueID(MainFilePath, MainFileID)) {
|
||||
auto MainFileStatus = VFS->status(MainFilePath);
|
||||
if (MainFileStatus) {
|
||||
llvm::sys::fs::UniqueID MainFileID = MainFileStatus->getUniqueID();
|
||||
|
||||
// Check whether there is a file-file remapping of the main file
|
||||
for (const auto &RF : PreprocessorOpts.RemappedFiles) {
|
||||
std::string MPath(RF.first);
|
||||
llvm::sys::fs::UniqueID MID;
|
||||
if (!llvm::sys::fs::getUniqueID(MPath, MID)) {
|
||||
auto MPathStatus = VFS->status(MPath);
|
||||
if (MPathStatus) {
|
||||
llvm::sys::fs::UniqueID MID = MPathStatus->getUniqueID();
|
||||
if (MainFileID == MID) {
|
||||
// We found a remapping. Try to load the resulting, remapped source.
|
||||
BufferOwner = getBufferForFile(RF.second);
|
||||
BufferOwner = valueOrNull(VFS->getBufferForFile(RF.second));
|
||||
if (!BufferOwner)
|
||||
return ComputedPreamble(nullptr, nullptr, 0, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Check whether there is a file-buffer remapping. It supercedes the
|
||||
// file-file remapping.
|
||||
for (const auto &RB : PreprocessorOpts.RemappedFileBuffers) {
|
||||
std::string MPath(RB.first);
|
||||
llvm::sys::fs::UniqueID MID;
|
||||
if (!llvm::sys::fs::getUniqueID(MPath, MID)) {
|
||||
auto MPathStatus = VFS->status(MPath);
|
||||
if (MPathStatus) {
|
||||
llvm::sys::fs::UniqueID MID = MPathStatus->getUniqueID();
|
||||
if (MainFileID == MID) {
|
||||
// We found a remapping.
|
||||
BufferOwner.reset();
|
||||
@ -1213,7 +1240,7 @@ ASTUnit::ComputePreamble(CompilerInvocation &Invocation, unsigned MaxLines) {
|
||||
|
||||
// If the main source file was not remapped, load it now.
|
||||
if (!Buffer && !BufferOwner) {
|
||||
BufferOwner = getBufferForFile(FrontendOpts.Inputs[0].getFile());
|
||||
BufferOwner = valueOrNull(VFS->getBufferForFile(FrontendOpts.Inputs[0].getFile()));
|
||||
if (!BufferOwner)
|
||||
return ComputedPreamble(nullptr, nullptr, 0, true);
|
||||
}
|
||||
@ -1324,8 +1351,10 @@ makeStandaloneDiagnostic(const LangOptions &LangOpts,
|
||||
std::unique_ptr<llvm::MemoryBuffer>
|
||||
ASTUnit::getMainBufferWithPrecompiledPreamble(
|
||||
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
|
||||
const CompilerInvocation &PreambleInvocationIn, bool AllowRebuild,
|
||||
const CompilerInvocation &PreambleInvocationIn,
|
||||
IntrusiveRefCntPtr<vfs::FileSystem> VFS, bool AllowRebuild,
|
||||
unsigned MaxLines) {
|
||||
assert(VFS && "VFS is null");
|
||||
|
||||
auto PreambleInvocation =
|
||||
std::make_shared<CompilerInvocation>(PreambleInvocationIn);
|
||||
@ -1333,7 +1362,8 @@ ASTUnit::getMainBufferWithPrecompiledPreamble(
|
||||
PreprocessorOptions &PreprocessorOpts
|
||||
= PreambleInvocation->getPreprocessorOpts();
|
||||
|
||||
ComputedPreamble NewPreamble = ComputePreamble(*PreambleInvocation, MaxLines);
|
||||
ComputedPreamble NewPreamble =
|
||||
ComputePreamble(*PreambleInvocation, MaxLines, VFS);
|
||||
|
||||
if (!NewPreamble.Size) {
|
||||
// We couldn't find a preamble in the main source. Clear out the current
|
||||
@ -1369,7 +1399,7 @@ ASTUnit::getMainBufferWithPrecompiledPreamble(
|
||||
break;
|
||||
|
||||
vfs::Status Status;
|
||||
if (FileMgr->getNoncachedStatValue(R.second, Status)) {
|
||||
if (!moveOnNoError(VFS->status(R.second), Status)) {
|
||||
// If we can't stat the file we're remapping to, assume that something
|
||||
// horrible happened.
|
||||
AnyFileChanged = true;
|
||||
@ -1386,7 +1416,7 @@ ASTUnit::getMainBufferWithPrecompiledPreamble(
|
||||
break;
|
||||
|
||||
vfs::Status Status;
|
||||
if (FileMgr->getNoncachedStatValue(RB.first, Status)) {
|
||||
if (!moveOnNoError(VFS->status(RB.first), Status)) {
|
||||
AnyFileChanged = true;
|
||||
break;
|
||||
}
|
||||
@ -1401,7 +1431,7 @@ ASTUnit::getMainBufferWithPrecompiledPreamble(
|
||||
!AnyFileChanged && F != FEnd;
|
||||
++F) {
|
||||
vfs::Status Status;
|
||||
if (FileMgr->getNoncachedStatValue(F->first(), Status)) {
|
||||
if (!moveOnNoError(VFS->status(F->first()), Status)) {
|
||||
// If we can't stat the file, assume that something horrible happened.
|
||||
AnyFileChanged = true;
|
||||
break;
|
||||
@ -1546,14 +1576,14 @@ ASTUnit::getMainBufferWithPrecompiledPreamble(
|
||||
TopLevelDeclsInPreamble.clear();
|
||||
PreambleDiagnostics.clear();
|
||||
|
||||
IntrusiveRefCntPtr<vfs::FileSystem> VFS =
|
||||
createVFSFromCompilerInvocation(Clang->getInvocation(), getDiagnostics());
|
||||
VFS = createVFSFromCompilerInvocation(Clang->getInvocation(),
|
||||
getDiagnostics(), VFS);
|
||||
if (!VFS)
|
||||
return nullptr;
|
||||
|
||||
// Create a file manager object to provide access to and cache the filesystem.
|
||||
Clang->setFileManager(new FileManager(Clang->getFileSystemOpts(), VFS));
|
||||
|
||||
|
||||
// Create the source manager.
|
||||
Clang->setSourceManager(new SourceManager(getDiagnostics(),
|
||||
Clang->getFileManager()));
|
||||
@ -1863,10 +1893,13 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(
|
||||
|
||||
bool ASTUnit::LoadFromCompilerInvocation(
|
||||
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
|
||||
unsigned PrecompilePreambleAfterNParses) {
|
||||
unsigned PrecompilePreambleAfterNParses,
|
||||
IntrusiveRefCntPtr<vfs::FileSystem> VFS) {
|
||||
if (!Invocation)
|
||||
return true;
|
||||
|
||||
|
||||
assert(VFS && "VFS is null");
|
||||
|
||||
// We'll manage file buffers ourselves.
|
||||
Invocation->getPreprocessorOpts().RetainRemappedFileBuffers = true;
|
||||
Invocation->getFrontendOpts().DisableFree = false;
|
||||
@ -1877,19 +1910,19 @@ bool ASTUnit::LoadFromCompilerInvocation(
|
||||
if (PrecompilePreambleAfterNParses > 0) {
|
||||
PreambleRebuildCounter = PrecompilePreambleAfterNParses;
|
||||
OverrideMainBuffer =
|
||||
getMainBufferWithPrecompiledPreamble(PCHContainerOps, *Invocation);
|
||||
getMainBufferWithPrecompiledPreamble(PCHContainerOps, *Invocation, VFS);
|
||||
getDiagnostics().Reset();
|
||||
ProcessWarningOptions(getDiagnostics(), Invocation->getDiagnosticOpts());
|
||||
}
|
||||
|
||||
|
||||
SimpleTimer ParsingTimer(WantTiming);
|
||||
ParsingTimer.setOutput("Parsing " + getMainFileName());
|
||||
|
||||
|
||||
// Recover resources if we crash before exiting this method.
|
||||
llvm::CrashRecoveryContextCleanupRegistrar<llvm::MemoryBuffer>
|
||||
MemBufferCleanup(OverrideMainBuffer.get());
|
||||
|
||||
return Parse(std::move(PCHContainerOps), std::move(OverrideMainBuffer));
|
||||
return Parse(std::move(PCHContainerOps), std::move(OverrideMainBuffer), VFS);
|
||||
}
|
||||
|
||||
std::unique_ptr<ASTUnit> ASTUnit::LoadFromCompilerInvocation(
|
||||
@ -1923,7 +1956,8 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromCompilerInvocation(
|
||||
DiagCleanup(Diags.get());
|
||||
|
||||
if (AST->LoadFromCompilerInvocation(std::move(PCHContainerOps),
|
||||
PrecompilePreambleAfterNParses))
|
||||
PrecompilePreambleAfterNParses,
|
||||
AST->FileMgr->getVirtualFileSystem()))
|
||||
return nullptr;
|
||||
return AST;
|
||||
}
|
||||
@ -1938,7 +1972,8 @@ ASTUnit *ASTUnit::LoadFromCommandLine(
|
||||
bool CacheCodeCompletionResults, bool IncludeBriefCommentsInCodeCompletion,
|
||||
bool AllowPCHWithCompilerErrors, bool SkipFunctionBodies,
|
||||
bool UserFilesAreVolatile, bool ForSerialization,
|
||||
llvm::Optional<StringRef> ModuleFormat, std::unique_ptr<ASTUnit> *ErrAST) {
|
||||
llvm::Optional<StringRef> ModuleFormat, std::unique_ptr<ASTUnit> *ErrAST,
|
||||
IntrusiveRefCntPtr<vfs::FileSystem> VFS) {
|
||||
assert(Diags.get() && "no DiagnosticsEngine was provided");
|
||||
|
||||
SmallVector<StoredDiagnostic, 4> StoredDiagnostics;
|
||||
@ -1979,8 +2014,9 @@ ASTUnit *ASTUnit::LoadFromCommandLine(
|
||||
ConfigureDiags(Diags, *AST, CaptureDiagnostics);
|
||||
AST->Diagnostics = Diags;
|
||||
AST->FileSystemOpts = CI->getFileSystemOpts();
|
||||
IntrusiveRefCntPtr<vfs::FileSystem> VFS =
|
||||
createVFSFromCompilerInvocation(*CI, *Diags);
|
||||
if (!VFS)
|
||||
VFS = vfs::getRealFileSystem();
|
||||
VFS = createVFSFromCompilerInvocation(*CI, *Diags, VFS);
|
||||
if (!VFS)
|
||||
return nullptr;
|
||||
AST->FileMgr = new FileManager(AST->FileSystemOpts, VFS);
|
||||
@ -2006,7 +2042,8 @@ ASTUnit *ASTUnit::LoadFromCommandLine(
|
||||
ASTUnitCleanup(AST.get());
|
||||
|
||||
if (AST->LoadFromCompilerInvocation(std::move(PCHContainerOps),
|
||||
PrecompilePreambleAfterNParses)) {
|
||||
PrecompilePreambleAfterNParses,
|
||||
VFS)) {
|
||||
// Some error occurred, if caller wants to examine diagnostics, pass it the
|
||||
// ASTUnit.
|
||||
if (ErrAST) {
|
||||
@ -2020,10 +2057,16 @@ ASTUnit *ASTUnit::LoadFromCommandLine(
|
||||
}
|
||||
|
||||
bool ASTUnit::Reparse(std::shared_ptr<PCHContainerOperations> PCHContainerOps,
|
||||
ArrayRef<RemappedFile> RemappedFiles) {
|
||||
ArrayRef<RemappedFile> RemappedFiles,
|
||||
IntrusiveRefCntPtr<vfs::FileSystem> VFS) {
|
||||
if (!Invocation)
|
||||
return true;
|
||||
|
||||
if (!VFS) {
|
||||
assert(FileMgr && "FileMgr is null on Reparse call");
|
||||
VFS = FileMgr->getVirtualFileSystem();
|
||||
}
|
||||
|
||||
clearFileLevelDecls();
|
||||
|
||||
SimpleTimer ParsingTimer(WantTiming);
|
||||
@ -2045,7 +2088,8 @@ bool ASTUnit::Reparse(std::shared_ptr<PCHContainerOperations> PCHContainerOps,
|
||||
std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer;
|
||||
if (!getPreambleFile(this).empty() || PreambleRebuildCounter > 0)
|
||||
OverrideMainBuffer =
|
||||
getMainBufferWithPrecompiledPreamble(PCHContainerOps, *Invocation);
|
||||
getMainBufferWithPrecompiledPreamble(PCHContainerOps, *Invocation, VFS);
|
||||
|
||||
|
||||
// Clear out the diagnostics state.
|
||||
FileMgr.reset();
|
||||
@ -2056,7 +2100,7 @@ bool ASTUnit::Reparse(std::shared_ptr<PCHContainerOperations> PCHContainerOps,
|
||||
|
||||
// Parse the sources
|
||||
bool Result =
|
||||
Parse(std::move(PCHContainerOps), std::move(OverrideMainBuffer));
|
||||
Parse(std::move(PCHContainerOps), std::move(OverrideMainBuffer), VFS);
|
||||
|
||||
// If we're caching global code-completion results, and the top-level
|
||||
// declarations have changed, clear out the code-completion cache.
|
||||
@ -2414,15 +2458,19 @@ void ASTUnit::CodeComplete(
|
||||
std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer;
|
||||
if (!getPreambleFile(this).empty()) {
|
||||
std::string CompleteFilePath(File);
|
||||
llvm::sys::fs::UniqueID CompleteFileID;
|
||||
|
||||
if (!llvm::sys::fs::getUniqueID(CompleteFilePath, CompleteFileID)) {
|
||||
auto VFS = FileMgr.getVirtualFileSystem();
|
||||
auto CompleteFileStatus = VFS->status(CompleteFilePath);
|
||||
if (CompleteFileStatus) {
|
||||
llvm::sys::fs::UniqueID CompleteFileID = CompleteFileStatus->getUniqueID();
|
||||
|
||||
std::string MainPath(OriginalSourceFile);
|
||||
llvm::sys::fs::UniqueID MainID;
|
||||
if (!llvm::sys::fs::getUniqueID(MainPath, MainID)) {
|
||||
auto MainStatus = VFS->status(MainPath);
|
||||
if (MainStatus) {
|
||||
llvm::sys::fs::UniqueID MainID = MainStatus->getUniqueID();
|
||||
if (CompleteFileID == MainID && Line > 1)
|
||||
OverrideMainBuffer = getMainBufferWithPrecompiledPreamble(
|
||||
PCHContainerOps, Inv, false, Line - 1);
|
||||
PCHContainerOps, Inv, VFS, false, Line - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -534,6 +534,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
|
||||
|
||||
Opts.DisableLLVMPasses = Args.hasArg(OPT_disable_llvm_passes);
|
||||
Opts.DisableLifetimeMarkers = Args.hasArg(OPT_disable_lifetimemarkers);
|
||||
Opts.DisableO0ImplyOptNone = Args.hasArg(OPT_disable_O0_optnone);
|
||||
Opts.DisableRedZone = Args.hasArg(OPT_disable_red_zone);
|
||||
Opts.ForbidGuardVariables = Args.hasArg(OPT_fforbid_guard_variables);
|
||||
Opts.UseRegisterSizedBitfieldAccess = Args.hasArg(
|
||||
@ -1087,6 +1088,9 @@ bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
|
||||
Opts.SpellCheckingLimit = getLastArgIntValue(
|
||||
Args, OPT_fspell_checking_limit,
|
||||
DiagnosticOptions::DefaultSpellCheckingLimit, Diags);
|
||||
Opts.SnippetLineLimit = getLastArgIntValue(
|
||||
Args, OPT_fcaret_diagnostics_max_lines,
|
||||
DiagnosticOptions::DefaultSnippetLineLimit, Diags);
|
||||
Opts.TabStop = getLastArgIntValue(Args, OPT_ftabstop,
|
||||
DiagnosticOptions::DefaultTabStop, Diags);
|
||||
if (Opts.TabStop == 0 || Opts.TabStop > DiagnosticOptions::MaxTabStop) {
|
||||
@ -2747,15 +2751,22 @@ void BuryPointer(const void *Ptr) {
|
||||
IntrusiveRefCntPtr<vfs::FileSystem>
|
||||
createVFSFromCompilerInvocation(const CompilerInvocation &CI,
|
||||
DiagnosticsEngine &Diags) {
|
||||
if (CI.getHeaderSearchOpts().VFSOverlayFiles.empty())
|
||||
return vfs::getRealFileSystem();
|
||||
return createVFSFromCompilerInvocation(CI, Diags, vfs::getRealFileSystem());
|
||||
}
|
||||
|
||||
IntrusiveRefCntPtr<vfs::OverlayFileSystem>
|
||||
Overlay(new vfs::OverlayFileSystem(vfs::getRealFileSystem()));
|
||||
IntrusiveRefCntPtr<vfs::FileSystem>
|
||||
createVFSFromCompilerInvocation(const CompilerInvocation &CI,
|
||||
DiagnosticsEngine &Diags,
|
||||
IntrusiveRefCntPtr<vfs::FileSystem> BaseFS) {
|
||||
if (CI.getHeaderSearchOpts().VFSOverlayFiles.empty())
|
||||
return BaseFS;
|
||||
|
||||
IntrusiveRefCntPtr<vfs::OverlayFileSystem> Overlay(
|
||||
new vfs::OverlayFileSystem(BaseFS));
|
||||
// earlier vfs files are on the bottom
|
||||
for (const std::string &File : CI.getHeaderSearchOpts().VFSOverlayFiles) {
|
||||
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Buffer =
|
||||
llvm::MemoryBuffer::getFile(File);
|
||||
BaseFS->getBufferForFile(File);
|
||||
if (!Buffer) {
|
||||
Diags.Report(diag::err_missing_vfs_overlay_file) << File;
|
||||
return IntrusiveRefCntPtr<vfs::FileSystem>();
|
||||
|
@ -52,6 +52,8 @@ std::unique_ptr<CompilerInvocation> clang::createInvocationFromCommandLine(
|
||||
TheDriver.setCheckInputsExist(false);
|
||||
|
||||
std::unique_ptr<driver::Compilation> C(TheDriver.BuildCompilation(Args));
|
||||
if (!C)
|
||||
return nullptr;
|
||||
|
||||
// Just print the cc1 options if -### was present.
|
||||
if (C->getArgs().hasArg(driver::options::OPT__HASH_HASH_HASH)) {
|
||||
|
@ -252,7 +252,8 @@ static SourceLocation ReadOriginalFileName(CompilerInstance &CI,
|
||||
|
||||
if (AddLineNote)
|
||||
CI.getSourceManager().AddLineNote(
|
||||
LineNoLoc, LineNo, SourceMgr.getLineTableFilenameID(InputFile));
|
||||
LineNoLoc, LineNo, SourceMgr.getLineTableFilenameID(InputFile), false,
|
||||
false, SrcMgr::C_User);
|
||||
|
||||
return T.getLocation();
|
||||
}
|
||||
|
@ -535,7 +535,7 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts,
|
||||
if (LangOpts.ConceptsTS)
|
||||
Builder.defineMacro("__cpp_experimental_concepts", "1");
|
||||
if (LangOpts.CoroutinesTS)
|
||||
Builder.defineMacro("__cpp_coroutines", "1");
|
||||
Builder.defineMacro("__cpp_coroutines", "201703L");
|
||||
}
|
||||
|
||||
static void InitializePredefinedMacros(const TargetInfo &TI,
|
||||
|
@ -928,6 +928,56 @@ void TextDiagnostic::emitBuildingModuleLocation(SourceLocation Loc,
|
||||
OS << "While building module '" << ModuleName << "':\n";
|
||||
}
|
||||
|
||||
/// \brief Find the suitable set of lines to show to include a set of ranges.
|
||||
static llvm::Optional<std::pair<unsigned, unsigned>>
|
||||
findLinesForRange(const CharSourceRange &R, FileID FID,
|
||||
const SourceManager &SM) {
|
||||
if (!R.isValid()) return None;
|
||||
|
||||
SourceLocation Begin = R.getBegin();
|
||||
SourceLocation End = R.getEnd();
|
||||
if (SM.getFileID(Begin) != FID || SM.getFileID(End) != FID)
|
||||
return None;
|
||||
|
||||
return std::make_pair(SM.getExpansionLineNumber(Begin),
|
||||
SM.getExpansionLineNumber(End));
|
||||
}
|
||||
|
||||
/// Add as much of range B into range A as possible without exceeding a maximum
|
||||
/// size of MaxRange. Ranges are inclusive.
|
||||
static std::pair<unsigned, unsigned>
|
||||
maybeAddRange(std::pair<unsigned, unsigned> A, std::pair<unsigned, unsigned> B,
|
||||
unsigned MaxRange) {
|
||||
// If A is already the maximum size, we're done.
|
||||
unsigned Slack = MaxRange - (A.second - A.first + 1);
|
||||
if (Slack == 0)
|
||||
return A;
|
||||
|
||||
// Easy case: merge succeeds within MaxRange.
|
||||
unsigned Min = std::min(A.first, B.first);
|
||||
unsigned Max = std::max(A.second, B.second);
|
||||
if (Max - Min + 1 <= MaxRange)
|
||||
return {Min, Max};
|
||||
|
||||
// If we can't reach B from A within MaxRange, there's nothing to do.
|
||||
// Don't add lines to the range that contain nothing interesting.
|
||||
if ((B.first > A.first && B.first - A.first + 1 > MaxRange) ||
|
||||
(B.second < A.second && A.second - B.second + 1 > MaxRange))
|
||||
return A;
|
||||
|
||||
// Otherwise, expand A towards B to produce a range of size MaxRange. We
|
||||
// attempt to expand by the same amount in both directions if B strictly
|
||||
// contains A.
|
||||
|
||||
// Expand downwards by up to half the available amount, then upwards as
|
||||
// much as possible, then downwards as much as possible.
|
||||
A.second = std::min(A.second + (Slack + 1) / 2, Max);
|
||||
Slack = MaxRange - (A.second - A.first + 1);
|
||||
A.first = std::max(Min + Slack, A.first) - Slack;
|
||||
A.second = std::min(A.first + MaxRange - 1, Max);
|
||||
return A;
|
||||
}
|
||||
|
||||
/// \brief Highlight a SourceRange (with ~'s) for any characters on LineNo.
|
||||
static void highlightRange(const CharSourceRange &R,
|
||||
unsigned LineNo, FileID FID,
|
||||
@ -990,9 +1040,12 @@ static void highlightRange(const CharSourceRange &R,
|
||||
EndColNo = map.startOfPreviousColumn(EndColNo);
|
||||
|
||||
// If the start/end passed each other, then we are trying to highlight a
|
||||
// range that just exists in whitespace, which must be some sort of other
|
||||
// bug.
|
||||
assert(StartColNo <= EndColNo && "Trying to highlight whitespace??");
|
||||
// range that just exists in whitespace. That most likely means we have
|
||||
// a multi-line highlighting range that covers a blank line.
|
||||
if (StartColNo > EndColNo) {
|
||||
assert(StartLineNo != EndLineNo && "trying to highlight whitespace");
|
||||
StartColNo = EndColNo;
|
||||
}
|
||||
}
|
||||
|
||||
assert(StartColNo <= map.getSourceLine().size() && "Invalid range!");
|
||||
@ -1103,7 +1156,7 @@ void TextDiagnostic::emitSnippetAndCaret(
|
||||
// Decompose the location into a FID/Offset pair.
|
||||
std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
|
||||
FileID FID = LocInfo.first;
|
||||
unsigned FileOffset = LocInfo.second;
|
||||
unsigned CaretFileOffset = LocInfo.second;
|
||||
|
||||
// Get information about the buffer it points into.
|
||||
bool Invalid = false;
|
||||
@ -1111,101 +1164,118 @@ void TextDiagnostic::emitSnippetAndCaret(
|
||||
if (Invalid)
|
||||
return;
|
||||
|
||||
const char *BufStart = BufData.data();
|
||||
const char *BufEnd = BufStart + BufData.size();
|
||||
unsigned CaretLineNo = SM.getLineNumber(FID, CaretFileOffset);
|
||||
unsigned CaretColNo = SM.getColumnNumber(FID, CaretFileOffset);
|
||||
|
||||
unsigned LineNo = SM.getLineNumber(FID, FileOffset);
|
||||
unsigned ColNo = SM.getColumnNumber(FID, FileOffset);
|
||||
|
||||
// Arbitrarily stop showing snippets when the line is too long.
|
||||
static const size_t MaxLineLengthToPrint = 4096;
|
||||
if (ColNo > MaxLineLengthToPrint)
|
||||
if (CaretColNo > MaxLineLengthToPrint)
|
||||
return;
|
||||
|
||||
// Rewind from the current position to the start of the line.
|
||||
const char *TokPtr = BufStart+FileOffset;
|
||||
const char *LineStart = TokPtr-ColNo+1; // Column # is 1-based.
|
||||
|
||||
// Compute the line end. Scan forward from the error position to the end of
|
||||
// the line.
|
||||
const char *LineEnd = TokPtr;
|
||||
while (*LineEnd != '\n' && *LineEnd != '\r' && LineEnd != BufEnd)
|
||||
++LineEnd;
|
||||
|
||||
// Arbitrarily stop showing snippets when the line is too long.
|
||||
if (size_t(LineEnd - LineStart) > MaxLineLengthToPrint)
|
||||
return;
|
||||
|
||||
// Trim trailing null-bytes.
|
||||
StringRef Line(LineStart, LineEnd - LineStart);
|
||||
while (Line.size() > ColNo && Line.back() == '\0')
|
||||
Line = Line.drop_back();
|
||||
|
||||
// Copy the line of code into an std::string for ease of manipulation.
|
||||
std::string SourceLine(Line.begin(), Line.end());
|
||||
|
||||
// Build the byte to column map.
|
||||
const SourceColumnMap sourceColMap(SourceLine, DiagOpts->TabStop);
|
||||
|
||||
// Create a line for the caret that is filled with spaces that is the same
|
||||
// number of columns as the line of source code.
|
||||
std::string CaretLine(sourceColMap.columns(), ' ');
|
||||
|
||||
// Highlight all of the characters covered by Ranges with ~ characters.
|
||||
// Find the set of lines to include.
|
||||
const unsigned MaxLines = DiagOpts->SnippetLineLimit;
|
||||
std::pair<unsigned, unsigned> Lines = {CaretLineNo, CaretLineNo};
|
||||
for (SmallVectorImpl<CharSourceRange>::iterator I = Ranges.begin(),
|
||||
E = Ranges.end();
|
||||
I != E; ++I)
|
||||
highlightRange(*I, LineNo, FID, sourceColMap, CaretLine, SM, LangOpts);
|
||||
if (auto OptionalRange = findLinesForRange(*I, FID, SM))
|
||||
Lines = maybeAddRange(Lines, *OptionalRange, MaxLines);
|
||||
|
||||
// Next, insert the caret itself.
|
||||
ColNo = sourceColMap.byteToContainingColumn(ColNo-1);
|
||||
if (CaretLine.size()<ColNo+1)
|
||||
CaretLine.resize(ColNo+1, ' ');
|
||||
CaretLine[ColNo] = '^';
|
||||
for (unsigned LineNo = Lines.first; LineNo != Lines.second + 1; ++LineNo) {
|
||||
const char *BufStart = BufData.data();
|
||||
const char *BufEnd = BufStart + BufData.size();
|
||||
|
||||
std::string FixItInsertionLine = buildFixItInsertionLine(LineNo,
|
||||
sourceColMap,
|
||||
Hints, SM,
|
||||
DiagOpts.get());
|
||||
// Rewind from the current position to the start of the line.
|
||||
const char *LineStart =
|
||||
BufStart +
|
||||
SM.getDecomposedLoc(SM.translateLineCol(FID, LineNo, 1)).second;
|
||||
if (LineStart == BufEnd)
|
||||
break;
|
||||
|
||||
// If the source line is too long for our terminal, select only the
|
||||
// "interesting" source region within that line.
|
||||
unsigned Columns = DiagOpts->MessageLength;
|
||||
if (Columns)
|
||||
selectInterestingSourceRegion(SourceLine, CaretLine, FixItInsertionLine,
|
||||
Columns, sourceColMap);
|
||||
// Compute the line end.
|
||||
const char *LineEnd = LineStart;
|
||||
while (*LineEnd != '\n' && *LineEnd != '\r' && LineEnd != BufEnd)
|
||||
++LineEnd;
|
||||
|
||||
// If we are in -fdiagnostics-print-source-range-info mode, we are trying
|
||||
// to produce easily machine parsable output. Add a space before the
|
||||
// source line and the caret to make it trivial to tell the main diagnostic
|
||||
// line from what the user is intended to see.
|
||||
if (DiagOpts->ShowSourceRanges) {
|
||||
SourceLine = ' ' + SourceLine;
|
||||
CaretLine = ' ' + CaretLine;
|
||||
}
|
||||
// Arbitrarily stop showing snippets when the line is too long.
|
||||
// FIXME: Don't print any lines in this case.
|
||||
if (size_t(LineEnd - LineStart) > MaxLineLengthToPrint)
|
||||
return;
|
||||
|
||||
// Finally, remove any blank spaces from the end of CaretLine.
|
||||
while (CaretLine[CaretLine.size()-1] == ' ')
|
||||
CaretLine.erase(CaretLine.end()-1);
|
||||
// Trim trailing null-bytes.
|
||||
StringRef Line(LineStart, LineEnd - LineStart);
|
||||
while (!Line.empty() && Line.back() == '\0' &&
|
||||
(LineNo != CaretLineNo || Line.size() > CaretColNo))
|
||||
Line = Line.drop_back();
|
||||
|
||||
// Emit what we have computed.
|
||||
emitSnippet(SourceLine);
|
||||
// Copy the line of code into an std::string for ease of manipulation.
|
||||
std::string SourceLine(Line.begin(), Line.end());
|
||||
|
||||
if (DiagOpts->ShowColors)
|
||||
OS.changeColor(caretColor, true);
|
||||
OS << CaretLine << '\n';
|
||||
if (DiagOpts->ShowColors)
|
||||
OS.resetColor();
|
||||
// Build the byte to column map.
|
||||
const SourceColumnMap sourceColMap(SourceLine, DiagOpts->TabStop);
|
||||
|
||||
if (!FixItInsertionLine.empty()) {
|
||||
if (DiagOpts->ShowColors)
|
||||
// Print fixit line in color
|
||||
OS.changeColor(fixitColor, false);
|
||||
if (DiagOpts->ShowSourceRanges)
|
||||
OS << ' ';
|
||||
OS << FixItInsertionLine << '\n';
|
||||
if (DiagOpts->ShowColors)
|
||||
OS.resetColor();
|
||||
// Create a line for the caret that is filled with spaces that is the same
|
||||
// number of columns as the line of source code.
|
||||
std::string CaretLine(sourceColMap.columns(), ' ');
|
||||
|
||||
// Highlight all of the characters covered by Ranges with ~ characters.
|
||||
for (SmallVectorImpl<CharSourceRange>::iterator I = Ranges.begin(),
|
||||
E = Ranges.end();
|
||||
I != E; ++I)
|
||||
highlightRange(*I, LineNo, FID, sourceColMap, CaretLine, SM, LangOpts);
|
||||
|
||||
// Next, insert the caret itself.
|
||||
if (CaretLineNo == LineNo) {
|
||||
CaretColNo = sourceColMap.byteToContainingColumn(CaretColNo - 1);
|
||||
if (CaretLine.size() < CaretColNo + 1)
|
||||
CaretLine.resize(CaretColNo + 1, ' ');
|
||||
CaretLine[CaretColNo] = '^';
|
||||
}
|
||||
|
||||
std::string FixItInsertionLine = buildFixItInsertionLine(
|
||||
LineNo, sourceColMap, Hints, SM, DiagOpts.get());
|
||||
|
||||
// If the source line is too long for our terminal, select only the
|
||||
// "interesting" source region within that line.
|
||||
unsigned Columns = DiagOpts->MessageLength;
|
||||
if (Columns)
|
||||
selectInterestingSourceRegion(SourceLine, CaretLine, FixItInsertionLine,
|
||||
Columns, sourceColMap);
|
||||
|
||||
// If we are in -fdiagnostics-print-source-range-info mode, we are trying
|
||||
// to produce easily machine parsable output. Add a space before the
|
||||
// source line and the caret to make it trivial to tell the main diagnostic
|
||||
// line from what the user is intended to see.
|
||||
if (DiagOpts->ShowSourceRanges) {
|
||||
SourceLine = ' ' + SourceLine;
|
||||
CaretLine = ' ' + CaretLine;
|
||||
}
|
||||
|
||||
// Finally, remove any blank spaces from the end of CaretLine.
|
||||
while (!CaretLine.empty() && CaretLine[CaretLine.size() - 1] == ' ')
|
||||
CaretLine.erase(CaretLine.end() - 1);
|
||||
|
||||
// Emit what we have computed.
|
||||
emitSnippet(SourceLine);
|
||||
|
||||
if (!CaretLine.empty()) {
|
||||
if (DiagOpts->ShowColors)
|
||||
OS.changeColor(caretColor, true);
|
||||
OS << CaretLine << '\n';
|
||||
if (DiagOpts->ShowColors)
|
||||
OS.resetColor();
|
||||
}
|
||||
|
||||
if (!FixItInsertionLine.empty()) {
|
||||
if (DiagOpts->ShowColors)
|
||||
// Print fixit line in color
|
||||
OS.changeColor(fixitColor, false);
|
||||
if (DiagOpts->ShowSourceRanges)
|
||||
OS << ' ';
|
||||
OS << FixItInsertionLine << '\n';
|
||||
if (DiagOpts->ShowColors)
|
||||
OS.resetColor();
|
||||
}
|
||||
}
|
||||
|
||||
// Print out any parseable fixit information requested by the options.
|
||||
|
@ -7,6 +7,7 @@ set(files
|
||||
avx2intrin.h
|
||||
avx512bwintrin.h
|
||||
avx512cdintrin.h
|
||||
avx512vpopcntdqintrin.h
|
||||
avx512dqintrin.h
|
||||
avx512erintrin.h
|
||||
avx512fintrin.h
|
||||
|
@ -12156,6 +12156,11 @@ static __inline__ void __ATTRS_o_ai vec_vsx_st(vector unsigned char __a,
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __VSX__
|
||||
#define vec_xxpermdi __builtin_vsx_xxpermdi
|
||||
#define vec_xxsldwi __builtin_vsx_xxsldwi
|
||||
#endif
|
||||
|
||||
/* vec_xor */
|
||||
|
||||
#define __builtin_altivec_vxor vec_xor
|
||||
|
70
lib/Headers/avx512vpopcntdqintrin.h
Normal file
70
lib/Headers/avx512vpopcntdqintrin.h
Normal file
@ -0,0 +1,70 @@
|
||||
/*===------------- avx512vpopcntdqintrin.h - AVX512VPOPCNTDQ 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 __IMMINTRIN_H
|
||||
#error \
|
||||
"Never use <avx512vpopcntdqintrin.h> directly; include <immintrin.h> instead."
|
||||
#endif
|
||||
|
||||
#ifndef __AVX512VPOPCNTDQINTRIN_H
|
||||
#define __AVX512VPOPCNTDQINTRIN_H
|
||||
|
||||
/* Define the default attributes for the functions in this file. */
|
||||
#define __DEFAULT_FN_ATTRS \
|
||||
__attribute__((__always_inline__, __nodebug__, __target__("avx512vpopcntd" \
|
||||
"q")))
|
||||
|
||||
static __inline__ __m512i __DEFAULT_FN_ATTRS _mm512_popcnt_epi64(__m512i __A) {
|
||||
return (__m512i)__builtin_ia32_vpopcntq_512((__v8di)__A);
|
||||
}
|
||||
|
||||
static __inline__ __m512i __DEFAULT_FN_ATTRS
|
||||
_mm512_mask_popcnt_epi64(__m512i __W, __mmask8 __U, __m512i __A) {
|
||||
return (__m512i)__builtin_ia32_selectq_512(
|
||||
(__mmask8)__U, (__v8di)_mm512_popcnt_epi64(__A), (__v8di)__W);
|
||||
}
|
||||
|
||||
static __inline__ __m512i __DEFAULT_FN_ATTRS
|
||||
_mm512_maskz_popcnt_epi64(__mmask8 __U, __m512i __A) {
|
||||
return _mm512_mask_popcnt_epi64((__m512i)_mm512_setzero_si512(), __U, __A);
|
||||
}
|
||||
|
||||
static __inline__ __m512i __DEFAULT_FN_ATTRS _mm512_popcnt_epi32(__m512i __A) {
|
||||
return (__m512i)__builtin_ia32_vpopcntd_512((__v16si)__A);
|
||||
}
|
||||
|
||||
static __inline__ __m512i __DEFAULT_FN_ATTRS
|
||||
_mm512_mask_popcnt_epi32(__m512i __W, __mmask16 __U, __m512i __A) {
|
||||
return (__m512i)__builtin_ia32_selectd_512(
|
||||
(__mmask16)__U, (__v16si)_mm512_popcnt_epi32(__A), (__v16si)__W);
|
||||
}
|
||||
|
||||
static __inline__ __m512i __DEFAULT_FN_ATTRS
|
||||
_mm512_maskz_popcnt_epi32(__mmask16 __U, __m512i __A) {
|
||||
return _mm512_mask_popcnt_epi32((__m512i)_mm512_setzero_si512(), __U, __A);
|
||||
}
|
||||
|
||||
#undef __DEFAULT_FN_ATTRS
|
||||
|
||||
#endif
|
@ -146,6 +146,10 @@ _mm256_cvtph_ps(__m128i __a)
|
||||
#include <avx512cdintrin.h>
|
||||
#endif
|
||||
|
||||
#if !defined(_MSC_VER) || __has_feature(modules) || defined(__AVX512VPOPCNTDQ__)
|
||||
#include <avx512vpopcntdqintrin.h>
|
||||
#endif
|
||||
|
||||
#if !defined(_MSC_VER) || __has_feature(modules) || defined(__AVX512DQ__)
|
||||
#include <avx512dqintrin.h>
|
||||
#endif
|
||||
|
@ -254,6 +254,18 @@ public:
|
||||
SymbolRoleSet Roles = getRolesForRef(E, Relations);
|
||||
return IndexCtx.handleReference(E->getExplicitProperty(), E->getLocation(),
|
||||
Parent, ParentDC, Roles, Relations, E);
|
||||
} else if (const ObjCMethodDecl *Getter = E->getImplicitPropertyGetter()) {
|
||||
// Class properties that are explicitly defined using @property
|
||||
// declarations are represented implicitly as there is no ivar for class
|
||||
// properties.
|
||||
if (Getter->isClassMethod()) {
|
||||
if (const auto *PD = Getter->getCanonicalDecl()->findPropertyDecl()) {
|
||||
SmallVector<SymbolRelation, 2> Relations;
|
||||
SymbolRoleSet Roles = getRolesForRef(E, Relations);
|
||||
return IndexCtx.handleReference(PD, E->getLocation(), Parent,
|
||||
ParentDC, Roles, Relations, E);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No need to do a handleReference for the objc method, because there will
|
||||
|
@ -124,10 +124,16 @@ bool IndexingContext::isTemplateImplicitInstantiation(const Decl *D) {
|
||||
TKind = FD->getTemplateSpecializationKind();
|
||||
} else if (auto *VD = dyn_cast<VarDecl>(D)) {
|
||||
TKind = VD->getTemplateSpecializationKind();
|
||||
} else if (isa<FieldDecl>(D)) {
|
||||
if (const auto *Parent =
|
||||
dyn_cast<ClassTemplateSpecializationDecl>(D->getDeclContext()))
|
||||
TKind = Parent->getSpecializationKind();
|
||||
} else if (const auto *RD = dyn_cast<CXXRecordDecl>(D)) {
|
||||
if (RD->getInstantiatedFromMemberClass())
|
||||
TKind = RD->getTemplateSpecializationKind();
|
||||
} else if (const auto *ED = dyn_cast<EnumDecl>(D)) {
|
||||
if (ED->getInstantiatedFromMemberEnum())
|
||||
TKind = ED->getTemplateSpecializationKind();
|
||||
} else if (isa<FieldDecl>(D) || isa<TypedefNameDecl>(D) ||
|
||||
isa<EnumConstantDecl>(D)) {
|
||||
if (const auto *Parent = dyn_cast<Decl>(D->getDeclContext()))
|
||||
return isTemplateImplicitInstantiation(Parent);
|
||||
}
|
||||
switch (TKind) {
|
||||
case TSK_Undeclared:
|
||||
@ -155,6 +161,16 @@ bool IndexingContext::shouldIgnoreIfImplicit(const Decl *D) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static const CXXRecordDecl *
|
||||
getDeclContextForTemplateInstationPattern(const Decl *D) {
|
||||
if (const auto *CTSD =
|
||||
dyn_cast<ClassTemplateSpecializationDecl>(D->getDeclContext()))
|
||||
return CTSD->getTemplateInstantiationPattern();
|
||||
else if (const auto *RD = dyn_cast<CXXRecordDecl>(D->getDeclContext()))
|
||||
return RD->getInstantiatedFromMemberClass();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static const Decl *adjustTemplateImplicitInstantiation(const Decl *D) {
|
||||
if (const ClassTemplateSpecializationDecl *
|
||||
SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
|
||||
@ -163,15 +179,26 @@ static const Decl *adjustTemplateImplicitInstantiation(const Decl *D) {
|
||||
return FD->getTemplateInstantiationPattern();
|
||||
} else if (auto *VD = dyn_cast<VarDecl>(D)) {
|
||||
return VD->getTemplateInstantiationPattern();
|
||||
} else if (const auto *FD = dyn_cast<FieldDecl>(D)) {
|
||||
if (const auto *Parent =
|
||||
dyn_cast<ClassTemplateSpecializationDecl>(D->getDeclContext())) {
|
||||
const CXXRecordDecl *Pattern = Parent->getTemplateInstantiationPattern();
|
||||
for (const NamedDecl *ND : Pattern->lookup(FD->getDeclName())) {
|
||||
if (ND->isImplicit())
|
||||
} else if (const auto *RD = dyn_cast<CXXRecordDecl>(D)) {
|
||||
return RD->getInstantiatedFromMemberClass();
|
||||
} else if (const auto *ED = dyn_cast<EnumDecl>(D)) {
|
||||
return ED->getInstantiatedFromMemberEnum();
|
||||
} else if (isa<FieldDecl>(D) || isa<TypedefNameDecl>(D)) {
|
||||
const auto *ND = cast<NamedDecl>(D);
|
||||
if (const CXXRecordDecl *Pattern =
|
||||
getDeclContextForTemplateInstationPattern(ND)) {
|
||||
for (const NamedDecl *BaseND : Pattern->lookup(ND->getDeclName())) {
|
||||
if (BaseND->isImplicit())
|
||||
continue;
|
||||
if (isa<FieldDecl>(ND))
|
||||
return ND;
|
||||
if (BaseND->getKind() == ND->getKind())
|
||||
return BaseND;
|
||||
}
|
||||
}
|
||||
} else if (const auto *ECD = dyn_cast<EnumConstantDecl>(D)) {
|
||||
if (const auto *ED = dyn_cast<EnumDecl>(ECD->getDeclContext())) {
|
||||
if (const EnumDecl *Pattern = ED->getInstantiatedFromMemberEnum()) {
|
||||
for (const NamedDecl *BaseECD : Pattern->lookup(ECD->getDeclName()))
|
||||
return BaseECD;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -563,7 +563,6 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
|
||||
// Parse the suffix. At this point we can classify whether we have an FP or
|
||||
// integer constant.
|
||||
bool isFPConstant = isFloatingLiteral();
|
||||
const char *ImaginarySuffixLoc = nullptr;
|
||||
|
||||
// Loop over all of the characters of the suffix. If we see something bad,
|
||||
// we break out of the loop.
|
||||
@ -660,7 +659,6 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
|
||||
case 'J':
|
||||
if (isImaginary) break; // Cannot be repeated.
|
||||
isImaginary = true;
|
||||
ImaginarySuffixLoc = s;
|
||||
continue; // Success.
|
||||
}
|
||||
// If we reached here, there was an error or a ud-suffix.
|
||||
@ -694,8 +692,7 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
|
||||
}
|
||||
|
||||
if (isImaginary) {
|
||||
PP.Diag(PP.AdvanceToTokenCharacter(TokLoc,
|
||||
ImaginarySuffixLoc - ThisTokBegin),
|
||||
PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, SuffixBegin - ThisTokBegin),
|
||||
diag::ext_imaginary_constant);
|
||||
}
|
||||
}
|
||||
|
@ -84,6 +84,90 @@ Module *ModuleMap::resolveModuleId(const ModuleId &Id, Module *Mod,
|
||||
return Context;
|
||||
}
|
||||
|
||||
/// \brief Append to \p Paths the set of paths needed to get to the
|
||||
/// subframework in which the given module lives.
|
||||
static void appendSubframeworkPaths(Module *Mod,
|
||||
SmallVectorImpl<char> &Path) {
|
||||
// Collect the framework names from the given module to the top-level module.
|
||||
SmallVector<StringRef, 2> Paths;
|
||||
for (; Mod; Mod = Mod->Parent) {
|
||||
if (Mod->IsFramework)
|
||||
Paths.push_back(Mod->Name);
|
||||
}
|
||||
|
||||
if (Paths.empty())
|
||||
return;
|
||||
|
||||
// Add Frameworks/Name.framework for each subframework.
|
||||
for (unsigned I = Paths.size() - 1; I != 0; --I)
|
||||
llvm::sys::path::append(Path, "Frameworks", Paths[I-1] + ".framework");
|
||||
}
|
||||
|
||||
const FileEntry *
|
||||
ModuleMap::resolveHeader(Module *M, Module::UnresolvedHeaderDirective Header,
|
||||
SmallVectorImpl<char> &RelativePathName) {
|
||||
if (llvm::sys::path::is_absolute(Header.FileName)) {
|
||||
RelativePathName.clear();
|
||||
RelativePathName.append(Header.FileName.begin(), Header.FileName.end());
|
||||
return SourceMgr.getFileManager().getFile(Header.FileName);
|
||||
}
|
||||
|
||||
// Search for the header file within the module's home directory.
|
||||
auto *Directory = M->Directory;
|
||||
SmallString<128> FullPathName(Directory->getName());
|
||||
unsigned FullPathLength = FullPathName.size();
|
||||
|
||||
if (M->isPartOfFramework()) {
|
||||
appendSubframeworkPaths(M, RelativePathName);
|
||||
unsigned RelativePathLength = RelativePathName.size();
|
||||
|
||||
// Check whether this file is in the public headers.
|
||||
llvm::sys::path::append(RelativePathName, "Headers", Header.FileName);
|
||||
llvm::sys::path::append(FullPathName, RelativePathName);
|
||||
if (auto *File = SourceMgr.getFileManager().getFile(FullPathName))
|
||||
return File;
|
||||
|
||||
// Check whether this file is in the private headers.
|
||||
// Ideally, private modules in the form 'FrameworkName.Private' should
|
||||
// be defined as 'module FrameworkName.Private', and not as
|
||||
// 'framework module FrameworkName.Private', since a 'Private.Framework'
|
||||
// does not usually exist. However, since both are currently widely used
|
||||
// for private modules, make sure we find the right path in both cases.
|
||||
if (M->IsFramework && M->Name == "Private")
|
||||
RelativePathName.clear();
|
||||
else
|
||||
RelativePathName.resize(RelativePathLength);
|
||||
FullPathName.resize(FullPathLength);
|
||||
llvm::sys::path::append(RelativePathName, "PrivateHeaders",
|
||||
Header.FileName);
|
||||
llvm::sys::path::append(FullPathName, RelativePathName);
|
||||
return SourceMgr.getFileManager().getFile(FullPathName);
|
||||
}
|
||||
|
||||
// Lookup for normal headers.
|
||||
llvm::sys::path::append(RelativePathName, Header.FileName);
|
||||
llvm::sys::path::append(FullPathName, RelativePathName);
|
||||
return SourceMgr.getFileManager().getFile(FullPathName);
|
||||
}
|
||||
|
||||
const FileEntry *
|
||||
ModuleMap::resolveAsBuiltinHeader(Module *M,
|
||||
Module::UnresolvedHeaderDirective Header,
|
||||
SmallVectorImpl<char> &BuiltinPathName) {
|
||||
if (llvm::sys::path::is_absolute(Header.FileName) || M->isPartOfFramework() ||
|
||||
!M->IsSystem || Header.IsUmbrella || !BuiltinIncludeDir ||
|
||||
BuiltinIncludeDir == M->Directory || !isBuiltinHeader(Header.FileName))
|
||||
return nullptr;
|
||||
|
||||
// This is a system module with a top-level header. This header
|
||||
// may have a counterpart (or replacement) in the set of headers
|
||||
// supplied by Clang. Find that builtin header.
|
||||
llvm::sys::path::append(BuiltinPathName, BuiltinIncludeDir->getName(),
|
||||
Header.FileName);
|
||||
return SourceMgr.getFileManager().getFile(
|
||||
StringRef(BuiltinPathName.data(), BuiltinPathName.size()));
|
||||
}
|
||||
|
||||
ModuleMap::ModuleMap(SourceManager &SourceMgr, DiagnosticsEngine &Diags,
|
||||
const LangOptions &LangOpts, const TargetInfo *Target,
|
||||
HeaderSearch &HeaderInfo)
|
||||
@ -1026,9 +1110,6 @@ namespace clang {
|
||||
/// be resolved relative to.
|
||||
const DirectoryEntry *Directory;
|
||||
|
||||
/// \brief The directory containing Clang-supplied headers.
|
||||
const DirectoryEntry *BuiltinIncludeDir;
|
||||
|
||||
/// \brief Whether this module map is in a system header directory.
|
||||
bool IsSystem;
|
||||
|
||||
@ -1087,12 +1168,10 @@ namespace clang {
|
||||
ModuleMap &Map,
|
||||
const FileEntry *ModuleMapFile,
|
||||
const DirectoryEntry *Directory,
|
||||
const DirectoryEntry *BuiltinIncludeDir,
|
||||
bool IsSystem)
|
||||
: L(L), SourceMgr(SourceMgr), Target(Target), Diags(Diags), Map(Map),
|
||||
ModuleMapFile(ModuleMapFile), Directory(Directory),
|
||||
BuiltinIncludeDir(BuiltinIncludeDir), IsSystem(IsSystem),
|
||||
HadError(false), ActiveModule(nullptr)
|
||||
IsSystem(IsSystem), HadError(false), ActiveModule(nullptr)
|
||||
{
|
||||
Tok.clear();
|
||||
consumeToken();
|
||||
@ -1772,25 +1851,6 @@ void ModuleMapParser::parseRequiresDecl() {
|
||||
} while (true);
|
||||
}
|
||||
|
||||
/// \brief Append to \p Paths the set of paths needed to get to the
|
||||
/// subframework in which the given module lives.
|
||||
static void appendSubframeworkPaths(Module *Mod,
|
||||
SmallVectorImpl<char> &Path) {
|
||||
// Collect the framework names from the given module to the top-level module.
|
||||
SmallVector<StringRef, 2> Paths;
|
||||
for (; Mod; Mod = Mod->Parent) {
|
||||
if (Mod->IsFramework)
|
||||
Paths.push_back(Mod->Name);
|
||||
}
|
||||
|
||||
if (Paths.empty())
|
||||
return;
|
||||
|
||||
// Add Frameworks/Name.framework for each subframework.
|
||||
for (unsigned I = Paths.size() - 1; I != 0; --I)
|
||||
llvm::sys::path::append(Path, "Frameworks", Paths[I-1] + ".framework");
|
||||
}
|
||||
|
||||
/// \brief Parse a header declaration.
|
||||
///
|
||||
/// header-declaration:
|
||||
@ -1843,85 +1903,36 @@ void ModuleMapParser::parseHeaderDecl(MMToken::TokenKind LeadingToken,
|
||||
Module::UnresolvedHeaderDirective Header;
|
||||
Header.FileName = Tok.getString();
|
||||
Header.FileNameLoc = consumeToken();
|
||||
Header.IsUmbrella = LeadingToken == MMToken::UmbrellaKeyword;
|
||||
|
||||
// Check whether we already have an umbrella.
|
||||
if (LeadingToken == MMToken::UmbrellaKeyword && ActiveModule->Umbrella) {
|
||||
if (Header.IsUmbrella && ActiveModule->Umbrella) {
|
||||
Diags.Report(Header.FileNameLoc, diag::err_mmap_umbrella_clash)
|
||||
<< ActiveModule->getFullModuleName();
|
||||
HadError = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Look for this file.
|
||||
const FileEntry *File = nullptr;
|
||||
const FileEntry *BuiltinFile = nullptr;
|
||||
SmallString<128> RelativePathName;
|
||||
if (llvm::sys::path::is_absolute(Header.FileName)) {
|
||||
RelativePathName = Header.FileName;
|
||||
File = SourceMgr.getFileManager().getFile(RelativePathName);
|
||||
} else {
|
||||
// Search for the header file within the search directory.
|
||||
SmallString<128> FullPathName(Directory->getName());
|
||||
unsigned FullPathLength = FullPathName.size();
|
||||
// Look for this file by name if we don't have any stat information.
|
||||
SmallString<128> RelativePathName, BuiltinPathName;
|
||||
const FileEntry *File =
|
||||
Map.resolveHeader(ActiveModule, Header, RelativePathName);
|
||||
const FileEntry *BuiltinFile =
|
||||
Map.resolveAsBuiltinHeader(ActiveModule, Header, BuiltinPathName);
|
||||
|
||||
if (ActiveModule->isPartOfFramework()) {
|
||||
appendSubframeworkPaths(ActiveModule, RelativePathName);
|
||||
unsigned RelativePathLength = RelativePathName.size();
|
||||
|
||||
// Check whether this file is in the public headers.
|
||||
llvm::sys::path::append(RelativePathName, "Headers", Header.FileName);
|
||||
llvm::sys::path::append(FullPathName, RelativePathName);
|
||||
File = SourceMgr.getFileManager().getFile(FullPathName);
|
||||
|
||||
// Check whether this file is in the private headers.
|
||||
if (!File) {
|
||||
// Ideally, private modules in the form 'FrameworkName.Private' should
|
||||
// be defined as 'module FrameworkName.Private', and not as
|
||||
// 'framework module FrameworkName.Private', since a 'Private.Framework'
|
||||
// does not usually exist. However, since both are currently widely used
|
||||
// for private modules, make sure we find the right path in both cases.
|
||||
if (ActiveModule->IsFramework && ActiveModule->Name == "Private")
|
||||
RelativePathName.clear();
|
||||
else
|
||||
RelativePathName.resize(RelativePathLength);
|
||||
FullPathName.resize(FullPathLength);
|
||||
llvm::sys::path::append(RelativePathName, "PrivateHeaders",
|
||||
Header.FileName);
|
||||
llvm::sys::path::append(FullPathName, RelativePathName);
|
||||
File = SourceMgr.getFileManager().getFile(FullPathName);
|
||||
}
|
||||
} else {
|
||||
// Lookup for normal headers.
|
||||
llvm::sys::path::append(RelativePathName, Header.FileName);
|
||||
llvm::sys::path::append(FullPathName, RelativePathName);
|
||||
File = SourceMgr.getFileManager().getFile(FullPathName);
|
||||
|
||||
// If this is a system module with a top-level header, this header
|
||||
// may have a counterpart (or replacement) in the set of headers
|
||||
// supplied by Clang. Find that builtin header.
|
||||
if (ActiveModule->IsSystem && LeadingToken != MMToken::UmbrellaKeyword &&
|
||||
BuiltinIncludeDir && BuiltinIncludeDir != Directory &&
|
||||
ModuleMap::isBuiltinHeader(Header.FileName)) {
|
||||
SmallString<128> BuiltinPathName(BuiltinIncludeDir->getName());
|
||||
llvm::sys::path::append(BuiltinPathName, Header.FileName);
|
||||
BuiltinFile = SourceMgr.getFileManager().getFile(BuiltinPathName);
|
||||
|
||||
// If Clang supplies this header but the underlying system does not,
|
||||
// just silently swap in our builtin version. Otherwise, we'll end
|
||||
// up adding both (later).
|
||||
if (BuiltinFile && !File) {
|
||||
File = BuiltinFile;
|
||||
RelativePathName = BuiltinPathName;
|
||||
BuiltinFile = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
// If Clang supplies this header but the underlying system does not,
|
||||
// just silently swap in our builtin version. Otherwise, we'll end
|
||||
// up adding both (later).
|
||||
if (BuiltinFile && !File) {
|
||||
RelativePathName = BuiltinPathName;
|
||||
File = BuiltinFile;
|
||||
BuiltinFile = nullptr;
|
||||
}
|
||||
|
||||
// FIXME: We shouldn't be eagerly stat'ing every file named in a module map.
|
||||
// Come up with a lazy way to do this.
|
||||
if (File) {
|
||||
if (LeadingToken == MMToken::UmbrellaKeyword) {
|
||||
if (Header.IsUmbrella) {
|
||||
const DirectoryEntry *UmbrellaDir = File->getDir();
|
||||
if (Module *UmbrellaModule = Map.UmbrellaDirs[UmbrellaDir]) {
|
||||
Diags.Report(LeadingLoc, diag::err_mmap_umbrella_clash)
|
||||
@ -1938,10 +1949,7 @@ void ModuleMapParser::parseHeaderDecl(MMToken::TokenKind LeadingToken,
|
||||
// If there is a builtin counterpart to this file, add it now so it can
|
||||
// wrap the system header.
|
||||
if (BuiltinFile) {
|
||||
// FIXME: Taking the name from the FileEntry is unstable and can give
|
||||
// different results depending on how we've previously named that file
|
||||
// in this build.
|
||||
Module::Header H = { BuiltinFile->getName(), BuiltinFile };
|
||||
Module::Header H = { BuiltinPathName.str(), BuiltinFile };
|
||||
Map.addHeader(ActiveModule, H, Role);
|
||||
|
||||
// If we have both a builtin and system version of the file, the
|
||||
@ -1960,7 +1968,6 @@ void ModuleMapParser::parseHeaderDecl(MMToken::TokenKind LeadingToken,
|
||||
|
||||
// If we find a module that has a missing header, we mark this module as
|
||||
// unavailable and store the header directive for displaying diagnostics.
|
||||
Header.IsUmbrella = LeadingToken == MMToken::UmbrellaKeyword;
|
||||
ActiveModule->markUnavailable();
|
||||
ActiveModule->MissingHeaders.push_back(Header);
|
||||
}
|
||||
@ -2555,7 +2562,7 @@ bool ModuleMap::parseModuleMapFile(const FileEntry *File, bool IsSystem,
|
||||
Buffer->getBufferEnd());
|
||||
SourceLocation Start = L.getSourceLocation();
|
||||
ModuleMapParser Parser(L, SourceMgr, Target, Diags, *this, File, Dir,
|
||||
BuiltinIncludeDir, IsSystem);
|
||||
IsSystem);
|
||||
bool Result = Parser.parseModuleMapFile();
|
||||
ParsedModuleMap[File] = Result;
|
||||
|
||||
|
@ -1171,18 +1171,26 @@ void Preprocessor::HandleLineDirective() {
|
||||
CheckEndOfDirective("line", true);
|
||||
}
|
||||
|
||||
SourceMgr.AddLineNote(DigitTok.getLocation(), LineNo, FilenameID);
|
||||
// Take the file kind of the file containing the #line directive. #line
|
||||
// directives are often used for generated sources from the same codebase, so
|
||||
// the new file should generally be classified the same way as the current
|
||||
// file. This is visible in GCC's pre-processed output, which rewrites #line
|
||||
// to GNU line markers.
|
||||
SrcMgr::CharacteristicKind FileKind =
|
||||
SourceMgr.getFileCharacteristic(DigitTok.getLocation());
|
||||
|
||||
SourceMgr.AddLineNote(DigitTok.getLocation(), LineNo, FilenameID, false,
|
||||
false, FileKind);
|
||||
|
||||
if (Callbacks)
|
||||
Callbacks->FileChanged(CurPPLexer->getSourceLocation(),
|
||||
PPCallbacks::RenameFile,
|
||||
SrcMgr::C_User);
|
||||
PPCallbacks::RenameFile, FileKind);
|
||||
}
|
||||
|
||||
/// ReadLineMarkerFlags - Parse and validate any flags at the end of a GNU line
|
||||
/// marker directive.
|
||||
static bool ReadLineMarkerFlags(bool &IsFileEntry, bool &IsFileExit,
|
||||
bool &IsSystemHeader, bool &IsExternCHeader,
|
||||
SrcMgr::CharacteristicKind &FileKind,
|
||||
Preprocessor &PP) {
|
||||
unsigned FlagVal;
|
||||
Token FlagTok;
|
||||
@ -1233,7 +1241,7 @@ static bool ReadLineMarkerFlags(bool &IsFileEntry, bool &IsFileExit,
|
||||
return true;
|
||||
}
|
||||
|
||||
IsSystemHeader = true;
|
||||
FileKind = SrcMgr::C_System;
|
||||
|
||||
PP.Lex(FlagTok);
|
||||
if (FlagTok.is(tok::eod)) return false;
|
||||
@ -1247,7 +1255,7 @@ static bool ReadLineMarkerFlags(bool &IsFileEntry, bool &IsFileExit,
|
||||
return true;
|
||||
}
|
||||
|
||||
IsExternCHeader = true;
|
||||
FileKind = SrcMgr::C_ExternCSystem;
|
||||
|
||||
PP.Lex(FlagTok);
|
||||
if (FlagTok.is(tok::eod)) return false;
|
||||
@ -1277,14 +1285,15 @@ void Preprocessor::HandleDigitDirective(Token &DigitTok) {
|
||||
Lex(StrTok);
|
||||
|
||||
bool IsFileEntry = false, IsFileExit = false;
|
||||
bool IsSystemHeader = false, IsExternCHeader = false;
|
||||
int FilenameID = -1;
|
||||
SrcMgr::CharacteristicKind FileKind = SrcMgr::C_User;
|
||||
|
||||
// If the StrTok is "eod", then it wasn't present. Otherwise, it must be a
|
||||
// string followed by eod.
|
||||
if (StrTok.is(tok::eod))
|
||||
; // ok
|
||||
else if (StrTok.isNot(tok::string_literal)) {
|
||||
if (StrTok.is(tok::eod)) {
|
||||
// Treat this like "#line NN", which doesn't change file characteristics.
|
||||
FileKind = SourceMgr.getFileCharacteristic(DigitTok.getLocation());
|
||||
} else if (StrTok.isNot(tok::string_literal)) {
|
||||
Diag(StrTok, diag::err_pp_linemarker_invalid_filename);
|
||||
return DiscardUntilEndOfDirective();
|
||||
} else if (StrTok.hasUDSuffix()) {
|
||||
@ -1303,15 +1312,13 @@ void Preprocessor::HandleDigitDirective(Token &DigitTok) {
|
||||
FilenameID = SourceMgr.getLineTableFilenameID(Literal.GetString());
|
||||
|
||||
// If a filename was present, read any flags that are present.
|
||||
if (ReadLineMarkerFlags(IsFileEntry, IsFileExit,
|
||||
IsSystemHeader, IsExternCHeader, *this))
|
||||
if (ReadLineMarkerFlags(IsFileEntry, IsFileExit, FileKind, *this))
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a line note with this information.
|
||||
SourceMgr.AddLineNote(DigitTok.getLocation(), LineNo, FilenameID,
|
||||
IsFileEntry, IsFileExit,
|
||||
IsSystemHeader, IsExternCHeader);
|
||||
SourceMgr.AddLineNote(DigitTok.getLocation(), LineNo, FilenameID, IsFileEntry,
|
||||
IsFileExit, FileKind);
|
||||
|
||||
// If the preprocessor has callbacks installed, notify them of the #line
|
||||
// change. This is used so that the line marker comes out in -E mode for
|
||||
@ -1322,11 +1329,6 @@ void Preprocessor::HandleDigitDirective(Token &DigitTok) {
|
||||
Reason = PPCallbacks::EnterFile;
|
||||
else if (IsFileExit)
|
||||
Reason = PPCallbacks::ExitFile;
|
||||
SrcMgr::CharacteristicKind FileKind = SrcMgr::C_User;
|
||||
if (IsExternCHeader)
|
||||
FileKind = SrcMgr::C_ExternCSystem;
|
||||
else if (IsSystemHeader)
|
||||
FileKind = SrcMgr::C_System;
|
||||
|
||||
Callbacks->FileChanged(CurPPLexer->getSourceLocation(), Reason, FileKind);
|
||||
}
|
||||
|
@ -1125,6 +1125,7 @@ static bool HasFeature(const Preprocessor &PP, StringRef Feature) {
|
||||
.Case("attribute_overloadable", true)
|
||||
.Case("attribute_unavailable_with_message", true)
|
||||
.Case("attribute_unused_on_fields", true)
|
||||
.Case("attribute_diagnose_if_objc", true)
|
||||
.Case("blocks", LangOpts.Blocks)
|
||||
.Case("c_thread_safety_attributes", true)
|
||||
.Case("cxx_exceptions", LangOpts.CXXExceptions)
|
||||
|
@ -475,9 +475,9 @@ void Preprocessor::HandlePragmaSystemHeader(Token &SysHeaderTok) {
|
||||
// Emit a line marker. This will change any source locations from this point
|
||||
// forward to realize they are in a system header.
|
||||
// Create a line note with this information.
|
||||
SourceMgr.AddLineNote(SysHeaderTok.getLocation(), PLoc.getLine()+1,
|
||||
SourceMgr.AddLineNote(SysHeaderTok.getLocation(), PLoc.getLine() + 1,
|
||||
FilenameID, /*IsEntry=*/false, /*IsExit=*/false,
|
||||
/*IsSystem=*/true, /*IsExternC=*/false);
|
||||
SrcMgr::C_System);
|
||||
}
|
||||
|
||||
/// HandlePragmaDependency - Handle \#pragma GCC dependency "foo" blah.
|
||||
|
@ -2120,31 +2120,18 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
|
||||
Id.getKind() == UnqualifiedId::IK_LiteralOperatorId) {
|
||||
// Form a parsed representation of the template-id to be stored in the
|
||||
// UnqualifiedId.
|
||||
TemplateIdAnnotation *TemplateId
|
||||
= TemplateIdAnnotation::Allocate(TemplateArgs.size(), TemplateIds);
|
||||
|
||||
// FIXME: Store name for literal operator too.
|
||||
if (Id.getKind() == UnqualifiedId::IK_Identifier) {
|
||||
TemplateId->Name = Id.Identifier;
|
||||
TemplateId->Operator = OO_None;
|
||||
TemplateId->TemplateNameLoc = Id.StartLocation;
|
||||
} else {
|
||||
TemplateId->Name = nullptr;
|
||||
TemplateId->Operator = Id.OperatorFunctionId.Operator;
|
||||
TemplateId->TemplateNameLoc = Id.StartLocation;
|
||||
}
|
||||
IdentifierInfo *TemplateII =
|
||||
Id.getKind() == UnqualifiedId::IK_Identifier ? Id.Identifier : nullptr;
|
||||
OverloadedOperatorKind OpKind = Id.getKind() == UnqualifiedId::IK_Identifier
|
||||
? OO_None
|
||||
: Id.OperatorFunctionId.Operator;
|
||||
|
||||
TemplateIdAnnotation *TemplateId = TemplateIdAnnotation::Create(
|
||||
SS, TemplateKWLoc, Id.StartLocation, TemplateII, OpKind, Template, TNK,
|
||||
LAngleLoc, RAngleLoc, TemplateArgs, TemplateIds);
|
||||
|
||||
TemplateId->SS = SS;
|
||||
TemplateId->TemplateKWLoc = TemplateKWLoc;
|
||||
TemplateId->Template = Template;
|
||||
TemplateId->Kind = TNK;
|
||||
TemplateId->LAngleLoc = LAngleLoc;
|
||||
TemplateId->RAngleLoc = RAngleLoc;
|
||||
ParsedTemplateArgument *Args = TemplateId->getTemplateArgs();
|
||||
for (unsigned Arg = 0, ArgEnd = TemplateArgs.size();
|
||||
Arg != ArgEnd; ++Arg)
|
||||
Args[Arg] = TemplateArgs[Arg];
|
||||
|
||||
Id.setTemplateId(TemplateId);
|
||||
return false;
|
||||
}
|
||||
|
@ -1011,25 +1011,21 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
|
||||
// Build a template-id annotation token that can be processed
|
||||
// later.
|
||||
Tok.setKind(tok::annot_template_id);
|
||||
TemplateIdAnnotation *TemplateId
|
||||
= TemplateIdAnnotation::Allocate(TemplateArgs.size(), TemplateIds);
|
||||
TemplateId->TemplateNameLoc = TemplateNameLoc;
|
||||
if (TemplateName.getKind() == UnqualifiedId::IK_Identifier) {
|
||||
TemplateId->Name = TemplateName.Identifier;
|
||||
TemplateId->Operator = OO_None;
|
||||
} else {
|
||||
TemplateId->Name = nullptr;
|
||||
TemplateId->Operator = TemplateName.OperatorFunctionId.Operator;
|
||||
}
|
||||
TemplateId->SS = SS;
|
||||
TemplateId->TemplateKWLoc = TemplateKWLoc;
|
||||
TemplateId->Template = Template;
|
||||
TemplateId->Kind = TNK;
|
||||
TemplateId->LAngleLoc = LAngleLoc;
|
||||
TemplateId->RAngleLoc = RAngleLoc;
|
||||
ParsedTemplateArgument *Args = TemplateId->getTemplateArgs();
|
||||
for (unsigned Arg = 0, ArgEnd = TemplateArgs.size(); Arg != ArgEnd; ++Arg)
|
||||
Args[Arg] = ParsedTemplateArgument(TemplateArgs[Arg]);
|
||||
|
||||
IdentifierInfo *TemplateII =
|
||||
TemplateName.getKind() == UnqualifiedId::IK_Identifier
|
||||
? TemplateName.Identifier
|
||||
: nullptr;
|
||||
|
||||
OverloadedOperatorKind OpKind =
|
||||
TemplateName.getKind() == UnqualifiedId::IK_Identifier
|
||||
? OO_None
|
||||
: TemplateName.OperatorFunctionId.Operator;
|
||||
|
||||
TemplateIdAnnotation *TemplateId = TemplateIdAnnotation::Create(
|
||||
SS, TemplateKWLoc, TemplateNameLoc, TemplateII, OpKind, Template, TNK,
|
||||
LAngleLoc, RAngleLoc, TemplateArgs, TemplateIds);
|
||||
|
||||
Tok.setAnnotationValue(TemplateId);
|
||||
if (TemplateKWLoc.isValid())
|
||||
Tok.setLocation(TemplateKWLoc);
|
||||
|
@ -542,6 +542,7 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body,
|
||||
|
||||
bool ReturnsVoid = false;
|
||||
bool HasNoReturn = false;
|
||||
bool IsCoroutine = S.getCurFunction() && S.getCurFunction()->isCoroutine();
|
||||
|
||||
if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
|
||||
if (const auto *CBody = dyn_cast<CoroutineBodyStmt>(Body))
|
||||
@ -570,8 +571,13 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body,
|
||||
// Short circuit for compilation speed.
|
||||
if (CD.checkDiagnostics(Diags, ReturnsVoid, HasNoReturn))
|
||||
return;
|
||||
|
||||
SourceLocation LBrace = Body->getLocStart(), RBrace = Body->getLocEnd();
|
||||
auto EmitDiag = [&](SourceLocation Loc, unsigned DiagID) {
|
||||
if (IsCoroutine)
|
||||
S.Diag(Loc, DiagID) << S.getCurFunction()->CoroutinePromise->getType();
|
||||
else
|
||||
S.Diag(Loc, DiagID);
|
||||
};
|
||||
// Either in a function body compound statement, or a function-try-block.
|
||||
switch (CheckFallThrough(AC)) {
|
||||
case UnknownFallThrough:
|
||||
@ -579,15 +585,15 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body,
|
||||
|
||||
case MaybeFallThrough:
|
||||
if (HasNoReturn)
|
||||
S.Diag(RBrace, CD.diag_MaybeFallThrough_HasNoReturn);
|
||||
EmitDiag(RBrace, CD.diag_MaybeFallThrough_HasNoReturn);
|
||||
else if (!ReturnsVoid)
|
||||
S.Diag(RBrace, CD.diag_MaybeFallThrough_ReturnsNonVoid);
|
||||
EmitDiag(RBrace, CD.diag_MaybeFallThrough_ReturnsNonVoid);
|
||||
break;
|
||||
case AlwaysFallThrough:
|
||||
if (HasNoReturn)
|
||||
S.Diag(RBrace, CD.diag_AlwaysFallThrough_HasNoReturn);
|
||||
EmitDiag(RBrace, CD.diag_AlwaysFallThrough_HasNoReturn);
|
||||
else if (!ReturnsVoid)
|
||||
S.Diag(RBrace, CD.diag_AlwaysFallThrough_ReturnsNonVoid);
|
||||
EmitDiag(RBrace, CD.diag_AlwaysFallThrough_ReturnsNonVoid);
|
||||
break;
|
||||
case NeverFallThroughOrReturn:
|
||||
if (ReturnsVoid && !HasNoReturn && CD.diag_NeverFallThroughOrReturn) {
|
||||
@ -2027,12 +2033,6 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
|
||||
|
||||
// Warning: check missing 'return'
|
||||
if (P.enableCheckFallThrough) {
|
||||
auto IsCoro = [&]() {
|
||||
if (auto *FD = dyn_cast<FunctionDecl>(D))
|
||||
if (FD->getBody() && isa<CoroutineBodyStmt>(FD->getBody()))
|
||||
return true;
|
||||
return false;
|
||||
};
|
||||
const CheckFallThroughDiagnostics &CD =
|
||||
(isa<BlockDecl>(D)
|
||||
? CheckFallThroughDiagnostics::MakeForBlock()
|
||||
@ -2040,7 +2040,7 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
|
||||
cast<CXXMethodDecl>(D)->getOverloadedOperator() == OO_Call &&
|
||||
cast<CXXMethodDecl>(D)->getParent()->isLambda())
|
||||
? CheckFallThroughDiagnostics::MakeForLambda()
|
||||
: (IsCoro()
|
||||
: (fscope->isCoroutine()
|
||||
? CheckFallThroughDiagnostics::MakeForCoroutine(D)
|
||||
: CheckFallThroughDiagnostics::MakeForFunction(D)));
|
||||
CheckFallThroughForBody(S, D, Body, blkExpr, CD, AC);
|
||||
|
@ -28,7 +28,6 @@ class CoroutineStmtBuilder : public CoroutineBodyStmt::CtorArgs {
|
||||
sema::FunctionScopeInfo &Fn;
|
||||
bool IsValid = true;
|
||||
SourceLocation Loc;
|
||||
QualType RetType;
|
||||
SmallVector<Stmt *, 4> ParamMovesVector;
|
||||
const bool IsPromiseDependentType;
|
||||
CXXRecordDecl *PromiseRecordDecl = nullptr;
|
||||
@ -61,6 +60,7 @@ private:
|
||||
bool makeOnFallthrough();
|
||||
bool makeOnException();
|
||||
bool makeReturnObject();
|
||||
bool makeGroDeclAndReturnStmt();
|
||||
bool makeReturnOnAllocFailure();
|
||||
bool makeParamMoves();
|
||||
};
|
||||
|
@ -1696,6 +1696,9 @@ bool Sema::CheckPPCBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
|
||||
case PPC::BI__builtin_tabortdci:
|
||||
return SemaBuiltinConstantArgRange(TheCall, 0, 0, 31) ||
|
||||
SemaBuiltinConstantArgRange(TheCall, 2, 0, 31);
|
||||
case PPC::BI__builtin_vsx_xxpermdi:
|
||||
case PPC::BI__builtin_vsx_xxsldwi:
|
||||
return SemaBuiltinVSX(TheCall);
|
||||
}
|
||||
return SemaBuiltinConstantArgRange(TheCall, i, l, u);
|
||||
}
|
||||
@ -3892,6 +3895,65 @@ bool Sema::SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Customized Sema Checking for VSX builtins that have the following signature:
|
||||
// vector [...] builtinName(vector [...], vector [...], const int);
|
||||
// Which takes the same type of vectors (any legal vector type) for the first
|
||||
// two arguments and takes compile time constant for the third argument.
|
||||
// Example builtins are :
|
||||
// vector double vec_xxpermdi(vector double, vector double, int);
|
||||
// vector short vec_xxsldwi(vector short, vector short, int);
|
||||
bool Sema::SemaBuiltinVSX(CallExpr *TheCall) {
|
||||
unsigned ExpectedNumArgs = 3;
|
||||
if (TheCall->getNumArgs() < ExpectedNumArgs)
|
||||
return Diag(TheCall->getLocEnd(),
|
||||
diag::err_typecheck_call_too_few_args_at_least)
|
||||
<< 0 /*function call*/ << ExpectedNumArgs << TheCall->getNumArgs()
|
||||
<< TheCall->getSourceRange();
|
||||
|
||||
if (TheCall->getNumArgs() > ExpectedNumArgs)
|
||||
return Diag(TheCall->getLocEnd(),
|
||||
diag::err_typecheck_call_too_many_args_at_most)
|
||||
<< 0 /*function call*/ << ExpectedNumArgs << TheCall->getNumArgs()
|
||||
<< TheCall->getSourceRange();
|
||||
|
||||
// Check the third argument is a compile time constant
|
||||
llvm::APSInt Value;
|
||||
if(!TheCall->getArg(2)->isIntegerConstantExpr(Value, Context))
|
||||
return Diag(TheCall->getLocStart(),
|
||||
diag::err_vsx_builtin_nonconstant_argument)
|
||||
<< 3 /* argument index */ << TheCall->getDirectCallee()
|
||||
<< SourceRange(TheCall->getArg(2)->getLocStart(),
|
||||
TheCall->getArg(2)->getLocEnd());
|
||||
|
||||
QualType Arg1Ty = TheCall->getArg(0)->getType();
|
||||
QualType Arg2Ty = TheCall->getArg(1)->getType();
|
||||
|
||||
// Check the type of argument 1 and argument 2 are vectors.
|
||||
SourceLocation BuiltinLoc = TheCall->getLocStart();
|
||||
if ((!Arg1Ty->isVectorType() && !Arg1Ty->isDependentType()) ||
|
||||
(!Arg2Ty->isVectorType() && !Arg2Ty->isDependentType())) {
|
||||
return Diag(BuiltinLoc, diag::err_vec_builtin_non_vector)
|
||||
<< TheCall->getDirectCallee()
|
||||
<< SourceRange(TheCall->getArg(0)->getLocStart(),
|
||||
TheCall->getArg(1)->getLocEnd());
|
||||
}
|
||||
|
||||
// Check the first two arguments are the same type.
|
||||
if (!Context.hasSameUnqualifiedType(Arg1Ty, Arg2Ty)) {
|
||||
return Diag(BuiltinLoc, diag::err_vec_builtin_incompatible_vector)
|
||||
<< TheCall->getDirectCallee()
|
||||
<< SourceRange(TheCall->getArg(0)->getLocStart(),
|
||||
TheCall->getArg(1)->getLocEnd());
|
||||
}
|
||||
|
||||
// When default clang type checking is turned off and the customized type
|
||||
// checking is used, the returning type of the function must be explicitly
|
||||
// set. Otherwise it is _Bool by default.
|
||||
TheCall->setType(Arg1Ty);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// SemaBuiltinShuffleVector - Handle __builtin_shufflevector.
|
||||
// This is declared to take (...), so we have to check everything.
|
||||
ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) {
|
||||
@ -3914,7 +3976,8 @@ ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) {
|
||||
|
||||
if (!LHSType->isVectorType() || !RHSType->isVectorType())
|
||||
return ExprError(Diag(TheCall->getLocStart(),
|
||||
diag::err_shufflevector_non_vector)
|
||||
diag::err_vec_builtin_non_vector)
|
||||
<< TheCall->getDirectCallee()
|
||||
<< SourceRange(TheCall->getArg(0)->getLocStart(),
|
||||
TheCall->getArg(1)->getLocEnd()));
|
||||
|
||||
@ -3928,12 +3991,14 @@ ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) {
|
||||
if (!RHSType->hasIntegerRepresentation() ||
|
||||
RHSType->getAs<VectorType>()->getNumElements() != numElements)
|
||||
return ExprError(Diag(TheCall->getLocStart(),
|
||||
diag::err_shufflevector_incompatible_vector)
|
||||
diag::err_vec_builtin_incompatible_vector)
|
||||
<< TheCall->getDirectCallee()
|
||||
<< SourceRange(TheCall->getArg(1)->getLocStart(),
|
||||
TheCall->getArg(1)->getLocEnd()));
|
||||
} else if (!Context.hasSameUnqualifiedType(LHSType, RHSType)) {
|
||||
return ExprError(Diag(TheCall->getLocStart(),
|
||||
diag::err_shufflevector_incompatible_vector)
|
||||
diag::err_vec_builtin_incompatible_vector)
|
||||
<< TheCall->getDirectCallee()
|
||||
<< SourceRange(TheCall->getArg(0)->getLocStart(),
|
||||
TheCall->getArg(1)->getLocEnd()));
|
||||
} else if (numElements != numResElements) {
|
||||
|
@ -23,14 +23,22 @@
|
||||
using namespace clang;
|
||||
using namespace sema;
|
||||
|
||||
static bool lookupMember(Sema &S, const char *Name, CXXRecordDecl *RD,
|
||||
SourceLocation Loc) {
|
||||
static LookupResult lookupMember(Sema &S, const char *Name, CXXRecordDecl *RD,
|
||||
SourceLocation Loc, bool &Res) {
|
||||
DeclarationName DN = S.PP.getIdentifierInfo(Name);
|
||||
LookupResult LR(S, DN, Loc, Sema::LookupMemberName);
|
||||
// Suppress diagnostics when a private member is selected. The same warnings
|
||||
// will be produced again when building the call.
|
||||
LR.suppressDiagnostics();
|
||||
return S.LookupQualifiedName(LR, RD);
|
||||
Res = S.LookupQualifiedName(LR, RD);
|
||||
return LR;
|
||||
}
|
||||
|
||||
static bool lookupMember(Sema &S, const char *Name, CXXRecordDecl *RD,
|
||||
SourceLocation Loc) {
|
||||
bool Res;
|
||||
lookupMember(S, Name, RD, Loc, Res);
|
||||
return Res;
|
||||
}
|
||||
|
||||
/// Look up the std::coroutine_traits<...>::promise_type for the given
|
||||
@ -120,8 +128,7 @@ static QualType lookupPromiseType(Sema &S, const FunctionProtoType *FnType,
|
||||
return PromiseType;
|
||||
}
|
||||
|
||||
/// Look up the std::coroutine_traits<...>::promise_type for the given
|
||||
/// function type.
|
||||
/// Look up the std::experimental::coroutine_handle<PromiseType>.
|
||||
static QualType lookupCoroutineHandleType(Sema &S, QualType PromiseType,
|
||||
SourceLocation Loc) {
|
||||
if (PromiseType.isNull())
|
||||
@ -314,6 +321,7 @@ static ExprResult buildCoroutineHandle(Sema &S, QualType PromiseType,
|
||||
}
|
||||
|
||||
struct ReadySuspendResumeResult {
|
||||
enum AwaitCallType { ACT_Ready, ACT_Suspend, ACT_Resume };
|
||||
Expr *Results[3];
|
||||
OpaqueValueExpr *OpaqueValue;
|
||||
bool IsInvalid;
|
||||
@ -359,7 +367,41 @@ static ReadySuspendResumeResult buildCoawaitCalls(Sema &S, VarDecl *CoroPromise,
|
||||
Calls.Results[I] = Result.get();
|
||||
}
|
||||
|
||||
// Assume the calls are valid; all further checking should make them invalid.
|
||||
Calls.IsInvalid = false;
|
||||
|
||||
using ACT = ReadySuspendResumeResult::AwaitCallType;
|
||||
CallExpr *AwaitReady = cast<CallExpr>(Calls.Results[ACT::ACT_Ready]);
|
||||
if (!AwaitReady->getType()->isDependentType()) {
|
||||
// [expr.await]p3 [...]
|
||||
// — await-ready is the expression e.await_ready(), contextually converted
|
||||
// to bool.
|
||||
ExprResult Conv = S.PerformContextuallyConvertToBool(AwaitReady);
|
||||
if (Conv.isInvalid()) {
|
||||
S.Diag(AwaitReady->getDirectCallee()->getLocStart(),
|
||||
diag::note_await_ready_no_bool_conversion);
|
||||
S.Diag(Loc, diag::note_coroutine_promise_call_implicitly_required)
|
||||
<< AwaitReady->getDirectCallee() << E->getSourceRange();
|
||||
Calls.IsInvalid = true;
|
||||
}
|
||||
Calls.Results[ACT::ACT_Ready] = Conv.get();
|
||||
}
|
||||
CallExpr *AwaitSuspend = cast<CallExpr>(Calls.Results[ACT::ACT_Suspend]);
|
||||
if (!AwaitSuspend->getType()->isDependentType()) {
|
||||
// [expr.await]p3 [...]
|
||||
// - await-suspend is the expression e.await_suspend(h), which shall be
|
||||
// a prvalue of type void or bool.
|
||||
QualType RetType = AwaitSuspend->getType();
|
||||
if (RetType != S.Context.BoolTy && RetType != S.Context.VoidTy) {
|
||||
S.Diag(AwaitSuspend->getCalleeDecl()->getLocation(),
|
||||
diag::err_await_suspend_invalid_return_type)
|
||||
<< RetType;
|
||||
S.Diag(Loc, diag::note_coroutine_promise_call_implicitly_required)
|
||||
<< AwaitSuspend->getDirectCallee();
|
||||
Calls.IsInvalid = true;
|
||||
}
|
||||
}
|
||||
|
||||
return Calls;
|
||||
}
|
||||
|
||||
@ -373,7 +415,6 @@ static ExprResult buildPromiseCall(Sema &S, VarDecl *Promise,
|
||||
if (PromiseRef.isInvalid())
|
||||
return ExprError();
|
||||
|
||||
// Call 'yield_value', passing in E.
|
||||
return buildMemberCall(S, PromiseRef.get(), Loc, Name, Args);
|
||||
}
|
||||
|
||||
@ -721,17 +762,19 @@ static FunctionDecl *findDeleteForPromise(Sema &S, SourceLocation Loc,
|
||||
|
||||
void Sema::CheckCompletedCoroutineBody(FunctionDecl *FD, Stmt *&Body) {
|
||||
FunctionScopeInfo *Fn = getCurFunction();
|
||||
assert(Fn && Fn->CoroutinePromise && "not a coroutine");
|
||||
|
||||
assert(Fn && Fn->isCoroutine() && "not a coroutine");
|
||||
if (!Body) {
|
||||
assert(FD->isInvalidDecl() &&
|
||||
"a null body is only allowed for invalid declarations");
|
||||
return;
|
||||
}
|
||||
// We have a function that uses coroutine keywords, but we failed to build
|
||||
// the promise type.
|
||||
if (!Fn->CoroutinePromise)
|
||||
return FD->setInvalidDecl();
|
||||
|
||||
if (isa<CoroutineBodyStmt>(Body)) {
|
||||
// FIXME(EricWF): Nothing todo. the body is already a transformed coroutine
|
||||
// body statement.
|
||||
// Nothing todo. the body is already a transformed coroutine body statement.
|
||||
return;
|
||||
}
|
||||
|
||||
@ -780,7 +823,8 @@ bool CoroutineStmtBuilder::buildDependentStatements() {
|
||||
assert(!this->IsPromiseDependentType &&
|
||||
"coroutine cannot have a dependent promise type");
|
||||
this->IsValid = makeOnException() && makeOnFallthrough() &&
|
||||
makeReturnOnAllocFailure() && makeNewAndDeleteExpr();
|
||||
makeGroDeclAndReturnStmt() && makeReturnOnAllocFailure() &&
|
||||
makeNewAndDeleteExpr();
|
||||
return this->IsValid;
|
||||
}
|
||||
|
||||
@ -857,15 +901,15 @@ bool CoroutineStmtBuilder::makeReturnOnAllocFailure() {
|
||||
if (ReturnObjectOnAllocationFailure.isInvalid())
|
||||
return false;
|
||||
|
||||
// FIXME: ActOnReturnStmt expects a scope that is inside of the function, due
|
||||
// to CheckJumpOutOfSEHFinally(*this, ReturnLoc, *CurScope->getFnParent());
|
||||
// S.getCurScope()->getFnParent() == nullptr at ActOnFinishFunctionBody when
|
||||
// CoroutineBodyStmt is built. Figure it out and fix it.
|
||||
// Use BuildReturnStmt here to unbreak sanitized tests. (Gor:3/27/2017)
|
||||
StmtResult ReturnStmt =
|
||||
S.BuildReturnStmt(Loc, ReturnObjectOnAllocationFailure.get());
|
||||
if (ReturnStmt.isInvalid())
|
||||
if (ReturnStmt.isInvalid()) {
|
||||
S.Diag(Found.getFoundDecl()->getLocation(), diag::note_member_declared_here)
|
||||
<< DN;
|
||||
S.Diag(Fn.FirstCoroutineStmtLoc, diag::note_declared_coroutine_here)
|
||||
<< Fn.getFirstCoroutineStmtKeyword();
|
||||
return false;
|
||||
}
|
||||
|
||||
this->ReturnStmtOnAllocFailure = ReturnStmt.get();
|
||||
return true;
|
||||
@ -991,13 +1035,32 @@ bool CoroutineStmtBuilder::makeOnFallthrough() {
|
||||
// [dcl.fct.def.coroutine]/4
|
||||
// The unqualified-ids 'return_void' and 'return_value' are looked up in
|
||||
// the scope of class P. If both are found, the program is ill-formed.
|
||||
const bool HasRVoid = lookupMember(S, "return_void", PromiseRecordDecl, Loc);
|
||||
const bool HasRValue = lookupMember(S, "return_value", PromiseRecordDecl, Loc);
|
||||
bool HasRVoid, HasRValue;
|
||||
LookupResult LRVoid =
|
||||
lookupMember(S, "return_void", PromiseRecordDecl, Loc, HasRVoid);
|
||||
LookupResult LRValue =
|
||||
lookupMember(S, "return_value", PromiseRecordDecl, Loc, HasRValue);
|
||||
|
||||
StmtResult Fallthrough;
|
||||
if (HasRVoid && HasRValue) {
|
||||
// FIXME Improve this diagnostic
|
||||
S.Diag(FD.getLocation(), diag::err_coroutine_promise_return_ill_formed)
|
||||
S.Diag(FD.getLocation(),
|
||||
diag::err_coroutine_promise_incompatible_return_functions)
|
||||
<< PromiseRecordDecl;
|
||||
S.Diag(LRVoid.getRepresentativeDecl()->getLocation(),
|
||||
diag::note_member_first_declared_here)
|
||||
<< LRVoid.getLookupName();
|
||||
S.Diag(LRValue.getRepresentativeDecl()->getLocation(),
|
||||
diag::note_member_first_declared_here)
|
||||
<< LRValue.getLookupName();
|
||||
return false;
|
||||
} else if (!HasRVoid && !HasRValue) {
|
||||
// FIXME: The PDTS currently specifies this case as UB, not ill-formed.
|
||||
// However we still diagnose this as an error since until the PDTS is fixed.
|
||||
S.Diag(FD.getLocation(),
|
||||
diag::err_coroutine_promise_requires_return_function)
|
||||
<< PromiseRecordDecl;
|
||||
S.Diag(PromiseRecordDecl->getLocation(), diag::note_defined_here)
|
||||
<< PromiseRecordDecl;
|
||||
return false;
|
||||
} else if (HasRVoid) {
|
||||
@ -1029,6 +1092,8 @@ bool CoroutineStmtBuilder::makeOnException() {
|
||||
: diag::
|
||||
warn_coroutine_promise_unhandled_exception_required_with_exceptions;
|
||||
S.Diag(Loc, DiagID) << PromiseRecordDecl;
|
||||
S.Diag(PromiseRecordDecl->getLocation(), diag::note_defined_here)
|
||||
<< PromiseRecordDecl;
|
||||
return !RequireUnhandledException;
|
||||
}
|
||||
|
||||
@ -1042,37 +1107,185 @@ bool CoroutineStmtBuilder::makeOnException() {
|
||||
if (UnhandledException.isInvalid())
|
||||
return false;
|
||||
|
||||
// Since the body of the coroutine will be wrapped in try-catch, it will
|
||||
// be incompatible with SEH __try if present in a function.
|
||||
if (!S.getLangOpts().Borland && Fn.FirstSEHTryLoc.isValid()) {
|
||||
S.Diag(Fn.FirstSEHTryLoc, diag::err_seh_in_a_coroutine_with_cxx_exceptions);
|
||||
S.Diag(Fn.FirstCoroutineStmtLoc, diag::note_declared_coroutine_here)
|
||||
<< Fn.getFirstCoroutineStmtKeyword();
|
||||
return false;
|
||||
}
|
||||
|
||||
this->OnException = UnhandledException.get();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CoroutineStmtBuilder::makeReturnObject() {
|
||||
|
||||
// Build implicit 'p.get_return_object()' expression and form initialization
|
||||
// of return type from it.
|
||||
ExprResult ReturnObject =
|
||||
buildPromiseCall(S, Fn.CoroutinePromise, Loc, "get_return_object", None);
|
||||
if (ReturnObject.isInvalid())
|
||||
return false;
|
||||
QualType RetType = FD.getReturnType();
|
||||
if (!RetType->isDependentType()) {
|
||||
InitializedEntity Entity =
|
||||
InitializedEntity::InitializeResult(Loc, RetType, false);
|
||||
ReturnObject = S.PerformMoveOrCopyInitialization(Entity, nullptr, RetType,
|
||||
ReturnObject.get());
|
||||
if (ReturnObject.isInvalid())
|
||||
return false;
|
||||
}
|
||||
ReturnObject = S.ActOnFinishFullExpr(ReturnObject.get(), Loc);
|
||||
if (ReturnObject.isInvalid())
|
||||
return false;
|
||||
|
||||
this->ReturnValue = ReturnObject.get();
|
||||
return true;
|
||||
}
|
||||
|
||||
static void noteMemberDeclaredHere(Sema &S, Expr *E, FunctionScopeInfo &Fn) {
|
||||
if (auto *MbrRef = dyn_cast<CXXMemberCallExpr>(E)) {
|
||||
auto *MethodDecl = MbrRef->getMethodDecl();
|
||||
S.Diag(MethodDecl->getLocation(), diag::note_member_declared_here)
|
||||
<< MethodDecl;
|
||||
}
|
||||
S.Diag(Fn.FirstCoroutineStmtLoc, diag::note_declared_coroutine_here)
|
||||
<< Fn.getFirstCoroutineStmtKeyword();
|
||||
}
|
||||
|
||||
bool CoroutineStmtBuilder::makeGroDeclAndReturnStmt() {
|
||||
assert(!IsPromiseDependentType &&
|
||||
"cannot make statement while the promise type is dependent");
|
||||
assert(this->ReturnValue && "ReturnValue must be already formed");
|
||||
|
||||
QualType const GroType = this->ReturnValue->getType();
|
||||
assert(!GroType->isDependentType() &&
|
||||
"get_return_object type must no longer be dependent");
|
||||
|
||||
QualType const FnRetType = FD.getReturnType();
|
||||
assert(!FnRetType->isDependentType() &&
|
||||
"get_return_object type must no longer be dependent");
|
||||
|
||||
if (FnRetType->isVoidType()) {
|
||||
ExprResult Res = S.ActOnFinishFullExpr(this->ReturnValue, Loc);
|
||||
if (Res.isInvalid())
|
||||
return false;
|
||||
|
||||
this->ResultDecl = Res.get();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (GroType->isVoidType()) {
|
||||
// Trigger a nice error message.
|
||||
InitializedEntity Entity =
|
||||
InitializedEntity::InitializeResult(Loc, FnRetType, false);
|
||||
S.PerformMoveOrCopyInitialization(Entity, nullptr, FnRetType, ReturnValue);
|
||||
noteMemberDeclaredHere(S, ReturnValue, Fn);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto *GroDecl = VarDecl::Create(
|
||||
S.Context, &FD, FD.getLocation(), FD.getLocation(),
|
||||
&S.PP.getIdentifierTable().get("__coro_gro"), GroType,
|
||||
S.Context.getTrivialTypeSourceInfo(GroType, Loc), SC_None);
|
||||
|
||||
S.CheckVariableDeclarationType(GroDecl);
|
||||
if (GroDecl->isInvalidDecl())
|
||||
return false;
|
||||
|
||||
InitializedEntity Entity = InitializedEntity::InitializeVariable(GroDecl);
|
||||
ExprResult Res = S.PerformMoveOrCopyInitialization(Entity, nullptr, GroType,
|
||||
this->ReturnValue);
|
||||
if (Res.isInvalid())
|
||||
return false;
|
||||
|
||||
Res = S.ActOnFinishFullExpr(Res.get());
|
||||
if (Res.isInvalid())
|
||||
return false;
|
||||
|
||||
if (GroType == FnRetType) {
|
||||
GroDecl->setNRVOVariable(true);
|
||||
}
|
||||
|
||||
S.AddInitializerToDecl(GroDecl, Res.get(),
|
||||
/*DirectInit=*/false);
|
||||
|
||||
S.FinalizeDeclaration(GroDecl);
|
||||
|
||||
// Form a declaration statement for the return declaration, so that AST
|
||||
// visitors can more easily find it.
|
||||
StmtResult GroDeclStmt =
|
||||
S.ActOnDeclStmt(S.ConvertDeclToDeclGroup(GroDecl), Loc, Loc);
|
||||
if (GroDeclStmt.isInvalid())
|
||||
return false;
|
||||
|
||||
this->ResultDecl = GroDeclStmt.get();
|
||||
|
||||
ExprResult declRef = S.BuildDeclRefExpr(GroDecl, GroType, VK_LValue, Loc);
|
||||
if (declRef.isInvalid())
|
||||
return false;
|
||||
|
||||
StmtResult ReturnStmt = S.BuildReturnStmt(Loc, declRef.get());
|
||||
if (ReturnStmt.isInvalid()) {
|
||||
noteMemberDeclaredHere(S, ReturnValue, Fn);
|
||||
return false;
|
||||
}
|
||||
|
||||
this->ReturnStmt = ReturnStmt.get();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Create a static_cast\<T&&>(expr).
|
||||
static Expr *castForMoving(Sema &S, Expr *E, QualType T = QualType()) {
|
||||
if (T.isNull())
|
||||
T = E->getType();
|
||||
QualType TargetType = S.BuildReferenceType(
|
||||
T, /*SpelledAsLValue*/ false, SourceLocation(), DeclarationName());
|
||||
SourceLocation ExprLoc = E->getLocStart();
|
||||
TypeSourceInfo *TargetLoc =
|
||||
S.Context.getTrivialTypeSourceInfo(TargetType, ExprLoc);
|
||||
|
||||
return S
|
||||
.BuildCXXNamedCast(ExprLoc, tok::kw_static_cast, TargetLoc, E,
|
||||
SourceRange(ExprLoc, ExprLoc), E->getSourceRange())
|
||||
.get();
|
||||
}
|
||||
|
||||
/// \brief Build a variable declaration for move parameter.
|
||||
static VarDecl *buildVarDecl(Sema &S, SourceLocation Loc, QualType Type,
|
||||
StringRef Name) {
|
||||
DeclContext *DC = S.CurContext;
|
||||
IdentifierInfo *II = &S.PP.getIdentifierTable().get(Name);
|
||||
TypeSourceInfo *TInfo = S.Context.getTrivialTypeSourceInfo(Type, Loc);
|
||||
VarDecl *Decl =
|
||||
VarDecl::Create(S.Context, DC, Loc, Loc, II, Type, TInfo, SC_None);
|
||||
Decl->setImplicit();
|
||||
return Decl;
|
||||
}
|
||||
|
||||
bool CoroutineStmtBuilder::makeParamMoves() {
|
||||
// FIXME: Perform move-initialization of parameters into frame-local copies.
|
||||
for (auto *paramDecl : FD.parameters()) {
|
||||
auto Ty = paramDecl->getType();
|
||||
if (Ty->isDependentType())
|
||||
continue;
|
||||
|
||||
// No need to copy scalars, llvm will take care of them.
|
||||
if (Ty->getAsCXXRecordDecl()) {
|
||||
if (!paramDecl->getIdentifier())
|
||||
continue;
|
||||
|
||||
ExprResult ParamRef =
|
||||
S.BuildDeclRefExpr(paramDecl, paramDecl->getType(),
|
||||
ExprValueKind::VK_LValue, Loc); // FIXME: scope?
|
||||
if (ParamRef.isInvalid())
|
||||
return false;
|
||||
|
||||
Expr *RCast = castForMoving(S, ParamRef.get());
|
||||
|
||||
auto D = buildVarDecl(S, Loc, Ty, paramDecl->getIdentifier()->getName());
|
||||
|
||||
S.AddInitializerToDecl(D, RCast, /*DirectInit=*/true);
|
||||
|
||||
// Convert decl to a statement.
|
||||
StmtResult Stmt = S.ActOnDeclStmt(S.ConvertDeclToDeclGroup(D), Loc, Loc);
|
||||
if (Stmt.isInvalid())
|
||||
return false;
|
||||
|
||||
ParamMovesVector.push_back(Stmt.get());
|
||||
}
|
||||
}
|
||||
|
||||
// Convert to ArrayRef in CtorArgs structure that builder inherits from.
|
||||
ParamMoves = ParamMovesVector;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -6516,7 +6516,7 @@ NamedDecl *Sema::ActOnVariableDeclarator(
|
||||
diag::err_thread_non_global)
|
||||
<< DeclSpec::getSpecifierName(TSCS);
|
||||
else if (!Context.getTargetInfo().isTLSSupported()) {
|
||||
if (getLangOpts().CUDA) {
|
||||
if (getLangOpts().CUDA || getLangOpts().OpenMPIsDevice) {
|
||||
// Postpone error emission until we've collected attributes required to
|
||||
// figure out whether it's a host or device variable and whether the
|
||||
// error should be ignored.
|
||||
@ -6578,8 +6578,11 @@ NamedDecl *Sema::ActOnVariableDeclarator(
|
||||
// Handle attributes prior to checking for duplicates in MergeVarDecl
|
||||
ProcessDeclAttributes(S, NewVD, D);
|
||||
|
||||
if (getLangOpts().CUDA) {
|
||||
if (EmitTLSUnsupportedError && DeclAttrsMatchCUDAMode(getLangOpts(), NewVD))
|
||||
if (getLangOpts().CUDA || getLangOpts().OpenMPIsDevice) {
|
||||
if (EmitTLSUnsupportedError &&
|
||||
((getLangOpts().CUDA && DeclAttrsMatchCUDAMode(getLangOpts(), NewVD)) ||
|
||||
(getLangOpts().OpenMPIsDevice &&
|
||||
NewVD->hasAttr<OMPDeclareTargetDeclAttr>())))
|
||||
Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(),
|
||||
diag::err_thread_unsupported);
|
||||
// CUDA B.2.5: "__shared__ and __constant__ variables have implied static
|
||||
@ -7917,10 +7920,7 @@ static OpenCLParamType getOpenCLKernelParameterType(Sema &S, QualType PT) {
|
||||
if (PT->isImageType())
|
||||
return PtrKernelParam;
|
||||
|
||||
if (PT->isBooleanType())
|
||||
return InvalidKernelParam;
|
||||
|
||||
if (PT->isEventT())
|
||||
if (PT->isBooleanType() || PT->isEventT() || PT->isReserveIDT())
|
||||
return InvalidKernelParam;
|
||||
|
||||
// OpenCL extension spec v1.2 s9.5:
|
||||
@ -12176,7 +12176,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
|
||||
sema::AnalysisBasedWarnings::Policy WP = AnalysisWarnings.getDefaultPolicy();
|
||||
sema::AnalysisBasedWarnings::Policy *ActivePolicy = nullptr;
|
||||
|
||||
if (getLangOpts().CoroutinesTS && getCurFunction()->CoroutinePromise)
|
||||
if (getLangOpts().CoroutinesTS && getCurFunction()->isCoroutine())
|
||||
CheckCompletedCoroutineBody(FD, Body);
|
||||
|
||||
if (FD) {
|
||||
@ -16097,7 +16097,8 @@ void Sema::ActOnModuleEnd(SourceLocation EomLoc, Module *Mod) {
|
||||
void Sema::createImplicitModuleImportForErrorRecovery(SourceLocation Loc,
|
||||
Module *Mod) {
|
||||
// Bail if we're not allowed to implicitly import a module here.
|
||||
if (isSFINAEContext() || !getLangOpts().ModulesErrorRecovery)
|
||||
if (isSFINAEContext() || !getLangOpts().ModulesErrorRecovery ||
|
||||
VisibleModules.isVisible(Mod))
|
||||
return;
|
||||
|
||||
// Create the implicit import declaration.
|
||||
|
@ -238,7 +238,7 @@ static typename std::enable_if<std::is_base_of<clang::Attr, AttrInfo>::value,
|
||||
getAttrName(const AttrInfo &Attr) {
|
||||
return &Attr;
|
||||
}
|
||||
const IdentifierInfo *getAttrName(const clang::AttributeList &Attr) {
|
||||
static const IdentifierInfo *getAttrName(const clang::AttributeList &Attr) {
|
||||
return Attr.getName();
|
||||
}
|
||||
|
||||
@ -949,7 +949,7 @@ static bool checkFunctionConditionAttr(Sema &S, Decl *D,
|
||||
Msg = "<no message provided>";
|
||||
|
||||
SmallVector<PartialDiagnosticAt, 8> Diags;
|
||||
if (!Cond->isValueDependent() &&
|
||||
if (isa<FunctionDecl>(D) && !Cond->isValueDependent() &&
|
||||
!Expr::isPotentialConstantExprUnevaluated(Cond, cast<FunctionDecl>(D),
|
||||
Diags)) {
|
||||
S.Diag(Attr.getLoc(), diag::err_attr_cond_never_constant_expr)
|
||||
@ -1037,10 +1037,11 @@ static void handleDiagnoseIfAttr(Sema &S, Decl *D, const AttributeList &Attr) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto *FD = cast<FunctionDecl>(D);
|
||||
bool ArgDependent = ArgumentDependenceChecker(FD).referencesArgs(Cond);
|
||||
bool ArgDependent = false;
|
||||
if (const auto *FD = dyn_cast<FunctionDecl>(D))
|
||||
ArgDependent = ArgumentDependenceChecker(FD).referencesArgs(Cond);
|
||||
D->addAttr(::new (S.Context) DiagnoseIfAttr(
|
||||
Attr.getRange(), S.Context, Cond, Msg, DiagType, ArgDependent, FD,
|
||||
Attr.getRange(), S.Context, Cond, Msg, DiagType, ArgDependent, cast<NamedDecl>(D),
|
||||
Attr.getAttributeSpellingListIndex()));
|
||||
}
|
||||
|
||||
@ -7283,6 +7284,12 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VisitObjCAvailabilityCheckExpr(ObjCAvailabilityCheckExpr *E) {
|
||||
SemaRef.Diag(E->getLocStart(), diag::warn_at_available_unchecked_use)
|
||||
<< (!SemaRef.getLangOpts().ObjC1);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VisitTypeLoc(TypeLoc Ty);
|
||||
};
|
||||
|
||||
|
@ -10348,32 +10348,33 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
|
||||
!Constructor->doesThisDeclarationHaveABody() &&
|
||||
!Constructor->isDeleted()) &&
|
||||
"DefineImplicitDefaultConstructor - call it for implicit default ctor");
|
||||
if (Constructor->willHaveBody() || Constructor->isInvalidDecl())
|
||||
return;
|
||||
|
||||
CXXRecordDecl *ClassDecl = Constructor->getParent();
|
||||
assert(ClassDecl && "DefineImplicitDefaultConstructor - invalid constructor");
|
||||
|
||||
SynthesizedFunctionScope Scope(*this, Constructor);
|
||||
DiagnosticErrorTrap Trap(Diags);
|
||||
if (SetCtorInitializers(Constructor, /*AnyErrors=*/false) ||
|
||||
Trap.hasErrorOccurred()) {
|
||||
Diag(CurrentLocation, diag::note_member_synthesized_at)
|
||||
<< CXXDefaultConstructor << Context.getTagDeclType(ClassDecl);
|
||||
Constructor->setInvalidDecl();
|
||||
return;
|
||||
}
|
||||
|
||||
// The exception specification is needed because we are defining the
|
||||
// function.
|
||||
ResolveExceptionSpec(CurrentLocation,
|
||||
Constructor->getType()->castAs<FunctionProtoType>());
|
||||
MarkVTableUsed(CurrentLocation, ClassDecl);
|
||||
|
||||
// Add a context note for diagnostics produced after this point.
|
||||
Scope.addContextNote(CurrentLocation);
|
||||
|
||||
if (SetCtorInitializers(Constructor, /*AnyErrors=*/false)) {
|
||||
Constructor->setInvalidDecl();
|
||||
return;
|
||||
}
|
||||
|
||||
SourceLocation Loc = Constructor->getLocEnd().isValid()
|
||||
? Constructor->getLocEnd()
|
||||
: Constructor->getLocation();
|
||||
Constructor->setBody(new (Context) CompoundStmt(Loc));
|
||||
|
||||
Constructor->markUsed(Context);
|
||||
MarkVTableUsed(CurrentLocation, ClassDecl);
|
||||
|
||||
if (ASTMutationListener *L = getASTMutationListener()) {
|
||||
L->CompletedImplicitDefinition(Constructor);
|
||||
@ -10483,9 +10484,22 @@ void Sema::DefineInheritingConstructor(SourceLocation CurrentLocation,
|
||||
assert(Constructor->getInheritedConstructor() &&
|
||||
!Constructor->doesThisDeclarationHaveABody() &&
|
||||
!Constructor->isDeleted());
|
||||
if (Constructor->isInvalidDecl())
|
||||
if (Constructor->willHaveBody() || Constructor->isInvalidDecl())
|
||||
return;
|
||||
|
||||
// Initializations are performed "as if by a defaulted default constructor",
|
||||
// so enter the appropriate scope.
|
||||
SynthesizedFunctionScope Scope(*this, Constructor);
|
||||
|
||||
// The exception specification is needed because we are defining the
|
||||
// function.
|
||||
ResolveExceptionSpec(CurrentLocation,
|
||||
Constructor->getType()->castAs<FunctionProtoType>());
|
||||
MarkVTableUsed(CurrentLocation, ClassDecl);
|
||||
|
||||
// Add a context note for diagnostics produced after this point.
|
||||
Scope.addContextNote(CurrentLocation);
|
||||
|
||||
ConstructorUsingShadowDecl *Shadow =
|
||||
Constructor->getInheritedConstructor().getShadowDecl();
|
||||
CXXConstructorDecl *InheritedCtor =
|
||||
@ -10500,11 +10514,6 @@ void Sema::DefineInheritingConstructor(SourceLocation CurrentLocation,
|
||||
CXXRecordDecl *RD = Shadow->getParent();
|
||||
SourceLocation InitLoc = Shadow->getLocation();
|
||||
|
||||
// Initializations are performed "as if by a defaulted default constructor",
|
||||
// so enter the appropriate scope.
|
||||
SynthesizedFunctionScope Scope(*this, Constructor);
|
||||
DiagnosticErrorTrap Trap(Diags);
|
||||
|
||||
// Build explicit initializers for all base classes from which the
|
||||
// constructor was inherited.
|
||||
SmallVector<CXXCtorInitializer*, 8> Inits;
|
||||
@ -10535,22 +10544,13 @@ void Sema::DefineInheritingConstructor(SourceLocation CurrentLocation,
|
||||
// We now proceed as if for a defaulted default constructor, with the relevant
|
||||
// initializers replaced.
|
||||
|
||||
bool HadError = SetCtorInitializers(Constructor, /*AnyErrors*/false, Inits);
|
||||
if (HadError || Trap.hasErrorOccurred()) {
|
||||
Diag(CurrentLocation, diag::note_inhctor_synthesized_at) << RD;
|
||||
if (SetCtorInitializers(Constructor, /*AnyErrors*/false, Inits)) {
|
||||
Constructor->setInvalidDecl();
|
||||
return;
|
||||
}
|
||||
|
||||
// The exception specification is needed because we are defining the
|
||||
// function.
|
||||
ResolveExceptionSpec(CurrentLocation,
|
||||
Constructor->getType()->castAs<FunctionProtoType>());
|
||||
|
||||
Constructor->setBody(new (Context) CompoundStmt(InitLoc));
|
||||
|
||||
Constructor->markUsed(Context);
|
||||
MarkVTableUsed(CurrentLocation, ClassDecl);
|
||||
|
||||
if (ASTMutationListener *L = getASTMutationListener()) {
|
||||
L->CompletedImplicitDefinition(Constructor);
|
||||
@ -10626,37 +10626,36 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
|
||||
!Destructor->doesThisDeclarationHaveABody() &&
|
||||
!Destructor->isDeleted()) &&
|
||||
"DefineImplicitDestructor - call it for implicit default dtor");
|
||||
if (Destructor->willHaveBody() || Destructor->isInvalidDecl())
|
||||
return;
|
||||
|
||||
CXXRecordDecl *ClassDecl = Destructor->getParent();
|
||||
assert(ClassDecl && "DefineImplicitDestructor - invalid destructor");
|
||||
|
||||
if (Destructor->isInvalidDecl())
|
||||
return;
|
||||
|
||||
SynthesizedFunctionScope Scope(*this, Destructor);
|
||||
|
||||
DiagnosticErrorTrap Trap(Diags);
|
||||
MarkBaseAndMemberDestructorsReferenced(Destructor->getLocation(),
|
||||
Destructor->getParent());
|
||||
|
||||
if (CheckDestructor(Destructor) || Trap.hasErrorOccurred()) {
|
||||
Diag(CurrentLocation, diag::note_member_synthesized_at)
|
||||
<< CXXDestructor << Context.getTagDeclType(ClassDecl);
|
||||
|
||||
Destructor->setInvalidDecl();
|
||||
return;
|
||||
}
|
||||
|
||||
// The exception specification is needed because we are defining the
|
||||
// function.
|
||||
ResolveExceptionSpec(CurrentLocation,
|
||||
Destructor->getType()->castAs<FunctionProtoType>());
|
||||
MarkVTableUsed(CurrentLocation, ClassDecl);
|
||||
|
||||
// Add a context note for diagnostics produced after this point.
|
||||
Scope.addContextNote(CurrentLocation);
|
||||
|
||||
MarkBaseAndMemberDestructorsReferenced(Destructor->getLocation(),
|
||||
Destructor->getParent());
|
||||
|
||||
if (CheckDestructor(Destructor)) {
|
||||
Destructor->setInvalidDecl();
|
||||
return;
|
||||
}
|
||||
|
||||
SourceLocation Loc = Destructor->getLocEnd().isValid()
|
||||
? Destructor->getLocEnd()
|
||||
: Destructor->getLocation();
|
||||
Destructor->setBody(new (Context) CompoundStmt(Loc));
|
||||
Destructor->markUsed(Context);
|
||||
MarkVTableUsed(CurrentLocation, ClassDecl);
|
||||
|
||||
if (ASTMutationListener *L = getASTMutationListener()) {
|
||||
L->CompletedImplicitDefinition(Destructor);
|
||||
@ -11224,8 +11223,7 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
|
||||
/// Diagnose an implicit copy operation for a class which is odr-used, but
|
||||
/// which is deprecated because the class has a user-declared copy constructor,
|
||||
/// copy assignment operator, or destructor.
|
||||
static void diagnoseDeprecatedCopyOperation(Sema &S, CXXMethodDecl *CopyOp,
|
||||
SourceLocation UseLoc) {
|
||||
static void diagnoseDeprecatedCopyOperation(Sema &S, CXXMethodDecl *CopyOp) {
|
||||
assert(CopyOp->isImplicit());
|
||||
|
||||
CXXRecordDecl *RD = CopyOp->getParent();
|
||||
@ -11264,10 +11262,6 @@ static void diagnoseDeprecatedCopyOperation(Sema &S, CXXMethodDecl *CopyOp,
|
||||
diag::warn_deprecated_copy_operation)
|
||||
<< RD << /*copy assignment*/!isa<CXXConstructorDecl>(CopyOp)
|
||||
<< /*destructor*/isa<CXXDestructorDecl>(UserDeclaredOperation);
|
||||
S.Diag(UseLoc, diag::note_member_synthesized_at)
|
||||
<< (isa<CXXConstructorDecl>(CopyOp) ? Sema::CXXCopyConstructor
|
||||
: Sema::CXXCopyAssignment)
|
||||
<< RD;
|
||||
}
|
||||
}
|
||||
|
||||
@ -11279,25 +11273,31 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
|
||||
!CopyAssignOperator->doesThisDeclarationHaveABody() &&
|
||||
!CopyAssignOperator->isDeleted()) &&
|
||||
"DefineImplicitCopyAssignment called for wrong function");
|
||||
if (CopyAssignOperator->willHaveBody() || CopyAssignOperator->isInvalidDecl())
|
||||
return;
|
||||
|
||||
CXXRecordDecl *ClassDecl = CopyAssignOperator->getParent();
|
||||
|
||||
if (ClassDecl->isInvalidDecl() || CopyAssignOperator->isInvalidDecl()) {
|
||||
if (ClassDecl->isInvalidDecl()) {
|
||||
CopyAssignOperator->setInvalidDecl();
|
||||
return;
|
||||
}
|
||||
|
||||
SynthesizedFunctionScope Scope(*this, CopyAssignOperator);
|
||||
|
||||
// The exception specification is needed because we are defining the
|
||||
// function.
|
||||
ResolveExceptionSpec(CurrentLocation,
|
||||
CopyAssignOperator->getType()->castAs<FunctionProtoType>());
|
||||
|
||||
// Add a context note for diagnostics produced after this point.
|
||||
Scope.addContextNote(CurrentLocation);
|
||||
|
||||
// C++11 [class.copy]p18:
|
||||
// The [definition of an implicitly declared copy assignment operator] is
|
||||
// deprecated if the class has a user-declared copy constructor or a
|
||||
// user-declared destructor.
|
||||
if (getLangOpts().CPlusPlus11 && CopyAssignOperator->isImplicit())
|
||||
diagnoseDeprecatedCopyOperation(*this, CopyAssignOperator, CurrentLocation);
|
||||
|
||||
CopyAssignOperator->markUsed(Context);
|
||||
|
||||
SynthesizedFunctionScope Scope(*this, CopyAssignOperator);
|
||||
DiagnosticErrorTrap Trap(Diags);
|
||||
diagnoseDeprecatedCopyOperation(*this, CopyAssignOperator);
|
||||
|
||||
// C++0x [class.copy]p30:
|
||||
// The implicitly-defined or explicitly-defaulted copy assignment operator
|
||||
@ -11363,8 +11363,6 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
|
||||
/*CopyingBaseSubobject=*/true,
|
||||
/*Copying=*/true);
|
||||
if (Copy.isInvalid()) {
|
||||
Diag(CurrentLocation, diag::note_member_synthesized_at)
|
||||
<< CXXCopyAssignment << Context.getTagDeclType(ClassDecl);
|
||||
CopyAssignOperator->setInvalidDecl();
|
||||
return;
|
||||
}
|
||||
@ -11390,8 +11388,6 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
|
||||
Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign)
|
||||
<< Context.getTagDeclType(ClassDecl) << 0 << Field->getDeclName();
|
||||
Diag(Field->getLocation(), diag::note_declared_at);
|
||||
Diag(CurrentLocation, diag::note_member_synthesized_at)
|
||||
<< CXXCopyAssignment << Context.getTagDeclType(ClassDecl);
|
||||
Invalid = true;
|
||||
continue;
|
||||
}
|
||||
@ -11402,8 +11398,6 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
|
||||
Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign)
|
||||
<< Context.getTagDeclType(ClassDecl) << 1 << Field->getDeclName();
|
||||
Diag(Field->getLocation(), diag::note_declared_at);
|
||||
Diag(CurrentLocation, diag::note_member_synthesized_at)
|
||||
<< CXXCopyAssignment << Context.getTagDeclType(ClassDecl);
|
||||
Invalid = true;
|
||||
continue;
|
||||
}
|
||||
@ -11436,8 +11430,6 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
|
||||
/*CopyingBaseSubobject=*/false,
|
||||
/*Copying=*/true);
|
||||
if (Copy.isInvalid()) {
|
||||
Diag(CurrentLocation, diag::note_member_synthesized_at)
|
||||
<< CXXCopyAssignment << Context.getTagDeclType(ClassDecl);
|
||||
CopyAssignOperator->setInvalidDecl();
|
||||
return;
|
||||
}
|
||||
@ -11453,22 +11445,10 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
|
||||
StmtResult Return = BuildReturnStmt(Loc, ThisObj.get());
|
||||
if (Return.isInvalid())
|
||||
Invalid = true;
|
||||
else {
|
||||
else
|
||||
Statements.push_back(Return.getAs<Stmt>());
|
||||
|
||||
if (Trap.hasErrorOccurred()) {
|
||||
Diag(CurrentLocation, diag::note_member_synthesized_at)
|
||||
<< CXXCopyAssignment << Context.getTagDeclType(ClassDecl);
|
||||
Invalid = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The exception specification is needed because we are defining the
|
||||
// function.
|
||||
ResolveExceptionSpec(CurrentLocation,
|
||||
CopyAssignOperator->getType()->castAs<FunctionProtoType>());
|
||||
|
||||
if (Invalid) {
|
||||
CopyAssignOperator->setInvalidDecl();
|
||||
return;
|
||||
@ -11482,6 +11462,7 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
|
||||
assert(!Body.isInvalid() && "Compound statement creation cannot fail");
|
||||
}
|
||||
CopyAssignOperator->setBody(Body.getAs<Stmt>());
|
||||
CopyAssignOperator->markUsed(Context);
|
||||
|
||||
if (ASTMutationListener *L = getASTMutationListener()) {
|
||||
L->CompletedImplicitDefinition(CopyAssignOperator);
|
||||
@ -11654,19 +11635,15 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
|
||||
!MoveAssignOperator->doesThisDeclarationHaveABody() &&
|
||||
!MoveAssignOperator->isDeleted()) &&
|
||||
"DefineImplicitMoveAssignment called for wrong function");
|
||||
if (MoveAssignOperator->willHaveBody() || MoveAssignOperator->isInvalidDecl())
|
||||
return;
|
||||
|
||||
CXXRecordDecl *ClassDecl = MoveAssignOperator->getParent();
|
||||
|
||||
if (ClassDecl->isInvalidDecl() || MoveAssignOperator->isInvalidDecl()) {
|
||||
if (ClassDecl->isInvalidDecl()) {
|
||||
MoveAssignOperator->setInvalidDecl();
|
||||
return;
|
||||
}
|
||||
|
||||
MoveAssignOperator->markUsed(Context);
|
||||
|
||||
SynthesizedFunctionScope Scope(*this, MoveAssignOperator);
|
||||
DiagnosticErrorTrap Trap(Diags);
|
||||
|
||||
// C++0x [class.copy]p28:
|
||||
// The implicitly-defined or move assignment operator for a non-union class
|
||||
// X performs memberwise move assignment of its subobjects. The direct base
|
||||
@ -11679,6 +11656,16 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
|
||||
// from a virtual base more than once.
|
||||
checkMoveAssignmentForRepeatedMove(*this, ClassDecl, CurrentLocation);
|
||||
|
||||
SynthesizedFunctionScope Scope(*this, MoveAssignOperator);
|
||||
|
||||
// The exception specification is needed because we are defining the
|
||||
// function.
|
||||
ResolveExceptionSpec(CurrentLocation,
|
||||
MoveAssignOperator->getType()->castAs<FunctionProtoType>());
|
||||
|
||||
// Add a context note for diagnostics produced after this point.
|
||||
Scope.addContextNote(CurrentLocation);
|
||||
|
||||
// The statements that form the synthesized function body.
|
||||
SmallVector<Stmt*, 8> Statements;
|
||||
|
||||
@ -11743,8 +11730,6 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
|
||||
/*CopyingBaseSubobject=*/true,
|
||||
/*Copying=*/false);
|
||||
if (Move.isInvalid()) {
|
||||
Diag(CurrentLocation, diag::note_member_synthesized_at)
|
||||
<< CXXMoveAssignment << Context.getTagDeclType(ClassDecl);
|
||||
MoveAssignOperator->setInvalidDecl();
|
||||
return;
|
||||
}
|
||||
@ -11770,8 +11755,6 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
|
||||
Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign)
|
||||
<< Context.getTagDeclType(ClassDecl) << 0 << Field->getDeclName();
|
||||
Diag(Field->getLocation(), diag::note_declared_at);
|
||||
Diag(CurrentLocation, diag::note_member_synthesized_at)
|
||||
<< CXXMoveAssignment << Context.getTagDeclType(ClassDecl);
|
||||
Invalid = true;
|
||||
continue;
|
||||
}
|
||||
@ -11782,8 +11765,6 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
|
||||
Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign)
|
||||
<< Context.getTagDeclType(ClassDecl) << 1 << Field->getDeclName();
|
||||
Diag(Field->getLocation(), diag::note_declared_at);
|
||||
Diag(CurrentLocation, diag::note_member_synthesized_at)
|
||||
<< CXXMoveAssignment << Context.getTagDeclType(ClassDecl);
|
||||
Invalid = true;
|
||||
continue;
|
||||
}
|
||||
@ -11819,8 +11800,6 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
|
||||
/*CopyingBaseSubobject=*/false,
|
||||
/*Copying=*/false);
|
||||
if (Move.isInvalid()) {
|
||||
Diag(CurrentLocation, diag::note_member_synthesized_at)
|
||||
<< CXXMoveAssignment << Context.getTagDeclType(ClassDecl);
|
||||
MoveAssignOperator->setInvalidDecl();
|
||||
return;
|
||||
}
|
||||
@ -11837,22 +11816,10 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
|
||||
StmtResult Return = BuildReturnStmt(Loc, ThisObj.get());
|
||||
if (Return.isInvalid())
|
||||
Invalid = true;
|
||||
else {
|
||||
else
|
||||
Statements.push_back(Return.getAs<Stmt>());
|
||||
|
||||
if (Trap.hasErrorOccurred()) {
|
||||
Diag(CurrentLocation, diag::note_member_synthesized_at)
|
||||
<< CXXMoveAssignment << Context.getTagDeclType(ClassDecl);
|
||||
Invalid = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The exception specification is needed because we are defining the
|
||||
// function.
|
||||
ResolveExceptionSpec(CurrentLocation,
|
||||
MoveAssignOperator->getType()->castAs<FunctionProtoType>());
|
||||
|
||||
if (Invalid) {
|
||||
MoveAssignOperator->setInvalidDecl();
|
||||
return;
|
||||
@ -11866,6 +11833,7 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
|
||||
assert(!Body.isInvalid() && "Compound statement creation cannot fail");
|
||||
}
|
||||
MoveAssignOperator->setBody(Body.getAs<Stmt>());
|
||||
MoveAssignOperator->markUsed(Context);
|
||||
|
||||
if (ASTMutationListener *L = getASTMutationListener()) {
|
||||
L->CompletedImplicitDefinition(MoveAssignOperator);
|
||||
@ -11952,30 +11920,37 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
|
||||
}
|
||||
|
||||
void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
|
||||
CXXConstructorDecl *CopyConstructor) {
|
||||
CXXConstructorDecl *CopyConstructor) {
|
||||
assert((CopyConstructor->isDefaulted() &&
|
||||
CopyConstructor->isCopyConstructor() &&
|
||||
!CopyConstructor->doesThisDeclarationHaveABody() &&
|
||||
!CopyConstructor->isDeleted()) &&
|
||||
"DefineImplicitCopyConstructor - call it for implicit copy ctor");
|
||||
if (CopyConstructor->willHaveBody() || CopyConstructor->isInvalidDecl())
|
||||
return;
|
||||
|
||||
CXXRecordDecl *ClassDecl = CopyConstructor->getParent();
|
||||
assert(ClassDecl && "DefineImplicitCopyConstructor - invalid constructor");
|
||||
|
||||
SynthesizedFunctionScope Scope(*this, CopyConstructor);
|
||||
|
||||
// The exception specification is needed because we are defining the
|
||||
// function.
|
||||
ResolveExceptionSpec(CurrentLocation,
|
||||
CopyConstructor->getType()->castAs<FunctionProtoType>());
|
||||
MarkVTableUsed(CurrentLocation, ClassDecl);
|
||||
|
||||
// Add a context note for diagnostics produced after this point.
|
||||
Scope.addContextNote(CurrentLocation);
|
||||
|
||||
// C++11 [class.copy]p7:
|
||||
// The [definition of an implicitly declared copy constructor] is
|
||||
// deprecated if the class has a user-declared copy assignment operator
|
||||
// or a user-declared destructor.
|
||||
if (getLangOpts().CPlusPlus11 && CopyConstructor->isImplicit())
|
||||
diagnoseDeprecatedCopyOperation(*this, CopyConstructor, CurrentLocation);
|
||||
diagnoseDeprecatedCopyOperation(*this, CopyConstructor);
|
||||
|
||||
SynthesizedFunctionScope Scope(*this, CopyConstructor);
|
||||
DiagnosticErrorTrap Trap(Diags);
|
||||
|
||||
if (SetCtorInitializers(CopyConstructor, /*AnyErrors=*/false) ||
|
||||
Trap.hasErrorOccurred()) {
|
||||
Diag(CurrentLocation, diag::note_member_synthesized_at)
|
||||
<< CXXCopyConstructor << Context.getTagDeclType(ClassDecl);
|
||||
if (SetCtorInitializers(CopyConstructor, /*AnyErrors=*/false)) {
|
||||
CopyConstructor->setInvalidDecl();
|
||||
} else {
|
||||
SourceLocation Loc = CopyConstructor->getLocEnd().isValid()
|
||||
@ -11984,16 +11959,9 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
|
||||
Sema::CompoundScopeRAII CompoundScope(*this);
|
||||
CopyConstructor->setBody(
|
||||
ActOnCompoundStmt(Loc, Loc, None, /*isStmtExpr=*/false).getAs<Stmt>());
|
||||
CopyConstructor->markUsed(Context);
|
||||
}
|
||||
|
||||
// The exception specification is needed because we are defining the
|
||||
// function.
|
||||
ResolveExceptionSpec(CurrentLocation,
|
||||
CopyConstructor->getType()->castAs<FunctionProtoType>());
|
||||
|
||||
CopyConstructor->markUsed(Context);
|
||||
MarkVTableUsed(CurrentLocation, ClassDecl);
|
||||
|
||||
if (ASTMutationListener *L = getASTMutationListener()) {
|
||||
L->CompletedImplicitDefinition(CopyConstructor);
|
||||
}
|
||||
@ -12075,41 +12043,41 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor(
|
||||
}
|
||||
|
||||
void Sema::DefineImplicitMoveConstructor(SourceLocation CurrentLocation,
|
||||
CXXConstructorDecl *MoveConstructor) {
|
||||
CXXConstructorDecl *MoveConstructor) {
|
||||
assert((MoveConstructor->isDefaulted() &&
|
||||
MoveConstructor->isMoveConstructor() &&
|
||||
!MoveConstructor->doesThisDeclarationHaveABody() &&
|
||||
!MoveConstructor->isDeleted()) &&
|
||||
"DefineImplicitMoveConstructor - call it for implicit move ctor");
|
||||
if (MoveConstructor->willHaveBody() || MoveConstructor->isInvalidDecl())
|
||||
return;
|
||||
|
||||
CXXRecordDecl *ClassDecl = MoveConstructor->getParent();
|
||||
assert(ClassDecl && "DefineImplicitMoveConstructor - invalid constructor");
|
||||
|
||||
SynthesizedFunctionScope Scope(*this, MoveConstructor);
|
||||
DiagnosticErrorTrap Trap(Diags);
|
||||
|
||||
if (SetCtorInitializers(MoveConstructor, /*AnyErrors=*/false) ||
|
||||
Trap.hasErrorOccurred()) {
|
||||
Diag(CurrentLocation, diag::note_member_synthesized_at)
|
||||
<< CXXMoveConstructor << Context.getTagDeclType(ClassDecl);
|
||||
// The exception specification is needed because we are defining the
|
||||
// function.
|
||||
ResolveExceptionSpec(CurrentLocation,
|
||||
MoveConstructor->getType()->castAs<FunctionProtoType>());
|
||||
MarkVTableUsed(CurrentLocation, ClassDecl);
|
||||
|
||||
// Add a context note for diagnostics produced after this point.
|
||||
Scope.addContextNote(CurrentLocation);
|
||||
|
||||
if (SetCtorInitializers(MoveConstructor, /*AnyErrors=*/false)) {
|
||||
MoveConstructor->setInvalidDecl();
|
||||
} else {
|
||||
} else {
|
||||
SourceLocation Loc = MoveConstructor->getLocEnd().isValid()
|
||||
? MoveConstructor->getLocEnd()
|
||||
: MoveConstructor->getLocation();
|
||||
Sema::CompoundScopeRAII CompoundScope(*this);
|
||||
MoveConstructor->setBody(ActOnCompoundStmt(
|
||||
Loc, Loc, None, /*isStmtExpr=*/ false).getAs<Stmt>());
|
||||
MoveConstructor->markUsed(Context);
|
||||
}
|
||||
|
||||
// The exception specification is needed because we are defining the
|
||||
// function.
|
||||
ResolveExceptionSpec(CurrentLocation,
|
||||
MoveConstructor->getType()->castAs<FunctionProtoType>());
|
||||
|
||||
MoveConstructor->markUsed(Context);
|
||||
MarkVTableUsed(CurrentLocation, ClassDecl);
|
||||
|
||||
if (ASTMutationListener *L = getASTMutationListener()) {
|
||||
L->CompletedImplicitDefinition(MoveConstructor);
|
||||
}
|
||||
@ -12122,6 +12090,8 @@ bool Sema::isImplicitlyDeleted(FunctionDecl *FD) {
|
||||
void Sema::DefineImplicitLambdaToFunctionPointerConversion(
|
||||
SourceLocation CurrentLocation,
|
||||
CXXConversionDecl *Conv) {
|
||||
SynthesizedFunctionScope Scope(*this, Conv);
|
||||
|
||||
CXXRecordDecl *Lambda = Conv->getParent();
|
||||
CXXMethodDecl *CallOp = Lambda->getLambdaCallOperator();
|
||||
// If we are defining a specialization of a conversion to function-ptr
|
||||
@ -12144,6 +12114,7 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion(
|
||||
"Conversion operator must have a corresponding call operator");
|
||||
CallOp = cast<CXXMethodDecl>(CallOpSpec);
|
||||
}
|
||||
|
||||
// Mark the call operator referenced (and add to pending instantiations
|
||||
// if necessary).
|
||||
// For both the conversion and static-invoker template specializations
|
||||
@ -12151,9 +12122,6 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion(
|
||||
// to the PendingInstantiations.
|
||||
MarkFunctionReferenced(CurrentLocation, CallOp);
|
||||
|
||||
SynthesizedFunctionScope Scope(*this, Conv);
|
||||
DiagnosticErrorTrap Trap(Diags);
|
||||
|
||||
// Retrieve the static invoker...
|
||||
CXXMethodDecl *Invoker = Lambda->getLambdaStaticInvoker();
|
||||
// ... and get the corresponding specialization for a generic lambda.
|
||||
@ -12191,7 +12159,7 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion(
|
||||
if (ASTMutationListener *L = getASTMutationListener()) {
|
||||
L->CompletedImplicitDefinition(Conv);
|
||||
L->CompletedImplicitDefinition(Invoker);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -12202,10 +12170,7 @@ void Sema::DefineImplicitLambdaToBlockPointerConversion(
|
||||
{
|
||||
assert(!Conv->getParent()->isGenericLambda());
|
||||
|
||||
Conv->markUsed(Context);
|
||||
|
||||
SynthesizedFunctionScope Scope(*this, Conv);
|
||||
DiagnosticErrorTrap Trap(Diags);
|
||||
|
||||
// Copy-initialize the lambda object as needed to capture it.
|
||||
Expr *This = ActOnCXXThis(CurrentLocation).get();
|
||||
@ -12244,6 +12209,7 @@ void Sema::DefineImplicitLambdaToBlockPointerConversion(
|
||||
Conv->setBody(new (Context) CompoundStmt(Context, ReturnS,
|
||||
Conv->getLocation(),
|
||||
Conv->getLocation()));
|
||||
Conv->markUsed(Context);
|
||||
|
||||
// We're done; notify the mutation listener, if any.
|
||||
if (ASTMutationListener *L = getASTMutationListener()) {
|
||||
@ -13971,6 +13937,11 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) {
|
||||
MD->setDefaulted();
|
||||
MD->setExplicitlyDefaulted();
|
||||
|
||||
// Unset that we will have a body for this function. We might not,
|
||||
// if it turns out to be trivial, and we don't need this marking now
|
||||
// that we've marked it as defaulted.
|
||||
MD->setWillHaveBody(false);
|
||||
|
||||
// If this definition appears within the record, do the checking when
|
||||
// the record is complete.
|
||||
const FunctionDecl *Primary = MD;
|
||||
|
@ -366,8 +366,18 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
|
||||
|
||||
if (getLangOpts().CUDA && !CheckCUDACall(Loc, FD))
|
||||
return true;
|
||||
}
|
||||
|
||||
if (diagnoseArgIndependentDiagnoseIfAttrs(FD, Loc))
|
||||
auto getReferencedObjCProp = [](const NamedDecl *D) ->
|
||||
const ObjCPropertyDecl * {
|
||||
if (const auto *MD = dyn_cast<ObjCMethodDecl>(D))
|
||||
return MD->findPropertyDecl();
|
||||
return nullptr;
|
||||
};
|
||||
if (const ObjCPropertyDecl *ObjCPDecl = getReferencedObjCProp(D)) {
|
||||
if (diagnoseArgIndependentDiagnoseIfAttrs(ObjCPDecl, Loc))
|
||||
return true;
|
||||
} else if (diagnoseArgIndependentDiagnoseIfAttrs(D, Loc)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -15742,6 +15752,13 @@ ExprResult Sema::ActOnObjCAvailabilityCheckExpr(
|
||||
if (Spec != AvailSpecs.end())
|
||||
Version = Spec->getVersion();
|
||||
|
||||
// The use of `@available` in the enclosing function should be analyzed to
|
||||
// warn when it's used inappropriately (i.e. not if(@available)).
|
||||
if (getCurFunctionOrMethodDecl())
|
||||
getEnclosingFunction()->HasPotentialAvailabilityViolations = true;
|
||||
else if (getCurBlock() || getCurLambda())
|
||||
getCurFunction()->HasPotentialAvailabilityViolations = true;
|
||||
|
||||
return new (Context)
|
||||
ObjCAvailabilityCheckExpr(Version, AtLoc, RParen, Context.BoolTy);
|
||||
}
|
||||
|
@ -1591,6 +1591,7 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
|
||||
// its constexpr-ness, supressing diagnostics while doing so.
|
||||
if (getLangOpts().CPlusPlus1z && !CallOperator->isInvalidDecl() &&
|
||||
!CallOperator->isConstexpr() &&
|
||||
!isa<CoroutineBodyStmt>(CallOperator->getBody()) &&
|
||||
!Class->getDeclContext()->isDependentContext()) {
|
||||
TentativeAnalysisScope DiagnosticScopeGuard(*this);
|
||||
CallOperator->setConstexpr(
|
||||
|
@ -4929,8 +4929,6 @@ static NamedDecl *getDefinitionToImport(NamedDecl *D) {
|
||||
|
||||
void Sema::diagnoseMissingImport(SourceLocation Loc, NamedDecl *Decl,
|
||||
MissingImportKind MIK, bool Recover) {
|
||||
assert(!isVisible(Decl) && "missing import for non-hidden decl?");
|
||||
|
||||
// Suggest importing a module providing the definition of this entity, if
|
||||
// possible.
|
||||
NamedDecl *Def = getDefinitionToImport(Decl);
|
||||
|
@ -6242,11 +6242,11 @@ EnableIfAttr *Sema::CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> Args,
|
||||
}
|
||||
|
||||
template <typename CheckFn>
|
||||
static bool diagnoseDiagnoseIfAttrsWith(Sema &S, const FunctionDecl *FD,
|
||||
static bool diagnoseDiagnoseIfAttrsWith(Sema &S, const NamedDecl *ND,
|
||||
bool ArgDependent, SourceLocation Loc,
|
||||
CheckFn &&IsSuccessful) {
|
||||
SmallVector<const DiagnoseIfAttr *, 8> Attrs;
|
||||
for (const auto *DIA : FD->specific_attrs<DiagnoseIfAttr>()) {
|
||||
for (const auto *DIA : ND->specific_attrs<DiagnoseIfAttr>()) {
|
||||
if (ArgDependent == DIA->getArgDependent())
|
||||
Attrs.push_back(DIA);
|
||||
}
|
||||
@ -6293,16 +6293,16 @@ bool Sema::diagnoseArgDependentDiagnoseIfAttrs(const FunctionDecl *Function,
|
||||
// EvaluateWithSubstitution only cares about the position of each
|
||||
// argument in the arg list, not the ParmVarDecl* it maps to.
|
||||
if (!DIA->getCond()->EvaluateWithSubstitution(
|
||||
Result, Context, DIA->getParent(), Args, ThisArg))
|
||||
Result, Context, cast<FunctionDecl>(DIA->getParent()), Args, ThisArg))
|
||||
return false;
|
||||
return Result.isInt() && Result.getInt().getBoolValue();
|
||||
});
|
||||
}
|
||||
|
||||
bool Sema::diagnoseArgIndependentDiagnoseIfAttrs(const FunctionDecl *Function,
|
||||
bool Sema::diagnoseArgIndependentDiagnoseIfAttrs(const NamedDecl *ND,
|
||||
SourceLocation Loc) {
|
||||
return diagnoseDiagnoseIfAttrsWith(
|
||||
*this, Function, /*ArgDependent=*/false, Loc,
|
||||
*this, ND, /*ArgDependent=*/false, Loc,
|
||||
[&](const DiagnoseIfAttr *DIA) {
|
||||
bool Result;
|
||||
return DIA->getCond()->EvaluateAsBooleanCondition(Result, Context) &&
|
||||
|
@ -197,6 +197,7 @@ bool Sema::CodeSynthesisContext::isInstantiationRecord() const {
|
||||
|
||||
case DefaultTemplateArgumentChecking:
|
||||
case DeclaringSpecialMember:
|
||||
case DefiningSynthesizedFunction:
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -624,6 +625,17 @@ void Sema::PrintInstantiationStack() {
|
||||
diag::note_in_declaration_of_implicit_special_member)
|
||||
<< cast<CXXRecordDecl>(Active->Entity) << Active->SpecialMember;
|
||||
break;
|
||||
|
||||
case CodeSynthesisContext::DefiningSynthesizedFunction:
|
||||
// FIXME: For synthesized members other than special members, produce a note.
|
||||
auto *MD = dyn_cast<CXXMethodDecl>(Active->Entity);
|
||||
auto CSM = MD ? getSpecialMember(MD) : CXXInvalid;
|
||||
if (CSM != CXXInvalid) {
|
||||
Diags.Report(Active->PointOfInstantiation,
|
||||
diag::note_member_synthesized_at)
|
||||
<< CSM << Context.getTagDeclType(MD->getParent());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -666,6 +678,7 @@ Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {
|
||||
return Active->DeductionInfo;
|
||||
|
||||
case CodeSynthesisContext::DeclaringSpecialMember:
|
||||
case CodeSynthesisContext::DefiningSynthesizedFunction:
|
||||
// This happens in a context unrelated to template instantiation, so
|
||||
// there is no SFINAE.
|
||||
return None;
|
||||
|
@ -6945,6 +6945,19 @@ TreeTransform<Derived>::TransformCoroutineBodyStmt(CoroutineBodyStmt *S) {
|
||||
if (DeallocRes.isInvalid())
|
||||
return StmtError();
|
||||
Builder.Deallocate = DeallocRes.get();
|
||||
|
||||
assert(S->getResultDecl() && "ResultDecl must already be built");
|
||||
StmtResult ResultDecl = getDerived().TransformStmt(S->getResultDecl());
|
||||
if (ResultDecl.isInvalid())
|
||||
return StmtError();
|
||||
Builder.ResultDecl = ResultDecl.get();
|
||||
|
||||
if (auto *ReturnStmt = S->getReturnStmt()) {
|
||||
StmtResult Res = getDerived().TransformStmt(ReturnStmt);
|
||||
if (Res.isInvalid())
|
||||
return StmtError();
|
||||
Builder.ReturnStmt = Res.get();
|
||||
}
|
||||
}
|
||||
|
||||
return getDerived().RebuildCoroutineBodyStmt(Builder);
|
||||
|
@ -116,7 +116,11 @@ CommonOptionsParser::CommonOptionsParser(
|
||||
|
||||
cl::HideUnrelatedOptions(Category);
|
||||
|
||||
Compilations.reset(FixedCompilationDatabase::loadFromCommandLine(argc, argv));
|
||||
std::string ErrorMessage;
|
||||
Compilations =
|
||||
FixedCompilationDatabase::loadFromCommandLine(argc, argv, ErrorMessage);
|
||||
if (!Compilations && !ErrorMessage.empty())
|
||||
llvm::errs() << ErrorMessage;
|
||||
cl::ParseCommandLineOptions(argc, argv, Overview);
|
||||
cl::PrintOptionValues();
|
||||
|
||||
@ -125,7 +129,6 @@ CommonOptionsParser::CommonOptionsParser(
|
||||
SourcePathList.empty())
|
||||
return;
|
||||
if (!Compilations) {
|
||||
std::string ErrorMessage;
|
||||
if (!BuildPath.empty()) {
|
||||
Compilations =
|
||||
CompilationDatabase::autoDetectFromDirectory(BuildPath, ErrorMessage);
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "llvm/Option/Arg.h"
|
||||
#include "llvm/Support/Host.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <sstream>
|
||||
#include <system_error>
|
||||
using namespace clang;
|
||||
@ -150,23 +151,21 @@ private:
|
||||
// options.
|
||||
class UnusedInputDiagConsumer : public DiagnosticConsumer {
|
||||
public:
|
||||
UnusedInputDiagConsumer() : Other(nullptr) {}
|
||||
|
||||
// Useful for debugging, chain diagnostics to another consumer after
|
||||
// recording for our own purposes.
|
||||
UnusedInputDiagConsumer(DiagnosticConsumer *Other) : Other(Other) {}
|
||||
UnusedInputDiagConsumer(DiagnosticConsumer &Other) : Other(Other) {}
|
||||
|
||||
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));
|
||||
} else if (DiagLevel >= DiagnosticsEngine::Error) {
|
||||
// If driver failed to create compilation object, show the diagnostics
|
||||
// to user.
|
||||
Other.HandleDiagnostic(DiagLevel, Info);
|
||||
}
|
||||
if (Other)
|
||||
Other->HandleDiagnostic(DiagLevel, Info);
|
||||
}
|
||||
|
||||
DiagnosticConsumer *Other;
|
||||
DiagnosticConsumer &Other;
|
||||
SmallVector<std::string, 2> UnusedInputs;
|
||||
};
|
||||
|
||||
@ -205,9 +204,12 @@ private:
|
||||
/// \li false if \c Args cannot be used for compilation jobs (e.g.
|
||||
/// contains an option like -E or -version).
|
||||
static bool stripPositionalArgs(std::vector<const char *> Args,
|
||||
std::vector<std::string> &Result) {
|
||||
std::vector<std::string> &Result,
|
||||
std::string &ErrorMsg) {
|
||||
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
|
||||
UnusedInputDiagConsumer DiagClient;
|
||||
llvm::raw_string_ostream Output(ErrorMsg);
|
||||
TextDiagnosticPrinter DiagnosticPrinter(Output, &*DiagOpts);
|
||||
UnusedInputDiagConsumer DiagClient(DiagnosticPrinter);
|
||||
DiagnosticsEngine Diagnostics(
|
||||
IntrusiveRefCntPtr<clang::DiagnosticIDs>(new DiagnosticIDs()),
|
||||
&*DiagOpts, &DiagClient, false);
|
||||
@ -245,6 +247,8 @@ static bool stripPositionalArgs(std::vector<const char *> Args,
|
||||
|
||||
const std::unique_ptr<driver::Compilation> Compilation(
|
||||
NewDriver->BuildCompilation(Args));
|
||||
if (!Compilation)
|
||||
return false;
|
||||
|
||||
const driver::JobList &Jobs = Compilation->getJobs();
|
||||
|
||||
@ -258,8 +262,7 @@ static bool stripPositionalArgs(std::vector<const char *> Args,
|
||||
}
|
||||
|
||||
if (CompileAnalyzer.Inputs.empty()) {
|
||||
// No compile jobs found.
|
||||
// FIXME: Emit a warning of some kind?
|
||||
ErrorMsg = "warning: no compile jobs found\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -280,8 +283,14 @@ static bool stripPositionalArgs(std::vector<const char *> Args,
|
||||
return true;
|
||||
}
|
||||
|
||||
FixedCompilationDatabase *FixedCompilationDatabase::loadFromCommandLine(
|
||||
int &Argc, const char *const *Argv, Twine Directory) {
|
||||
std::unique_ptr<FixedCompilationDatabase>
|
||||
FixedCompilationDatabase::loadFromCommandLine(int &Argc,
|
||||
const char *const *Argv,
|
||||
std::string &ErrorMsg,
|
||||
Twine Directory) {
|
||||
ErrorMsg.clear();
|
||||
if (Argc == 0)
|
||||
return nullptr;
|
||||
const char *const *DoubleDash = std::find(Argv, Argv + Argc, StringRef("--"));
|
||||
if (DoubleDash == Argv + Argc)
|
||||
return nullptr;
|
||||
@ -289,9 +298,10 @@ FixedCompilationDatabase *FixedCompilationDatabase::loadFromCommandLine(
|
||||
Argc = DoubleDash - Argv;
|
||||
|
||||
std::vector<std::string> StrippedArgs;
|
||||
if (!stripPositionalArgs(CommandLine, StrippedArgs))
|
||||
if (!stripPositionalArgs(CommandLine, StrippedArgs, ErrorMsg))
|
||||
return nullptr;
|
||||
return new FixedCompilationDatabase(Directory, StrippedArgs);
|
||||
return std::unique_ptr<FixedCompilationDatabase>(
|
||||
new FixedCompilationDatabase(Directory, StrippedArgs));
|
||||
}
|
||||
|
||||
FixedCompilationDatabase::
|
||||
|
@ -260,6 +260,8 @@ bool ToolInvocation::run() {
|
||||
Driver->setCheckInputsExist(false);
|
||||
const std::unique_ptr<clang::driver::Compilation> Compilation(
|
||||
Driver->BuildCompilation(llvm::makeArrayRef(Argv)));
|
||||
if (!Compilation)
|
||||
return false;
|
||||
const llvm::opt::ArgStringList *const CC1Args = getCC1Arguments(
|
||||
&Diagnostics, Compilation.get());
|
||||
if (!CC1Args) {
|
||||
|
@ -167,7 +167,7 @@ namespace test3 {
|
||||
Base2, // expected-error 2 {{base class 'test3::Base2' has private destructor}}
|
||||
virtual Base3
|
||||
{};
|
||||
Derived3 d3; // expected-note {{implicit default constructor}}\
|
||||
Derived3 d3; // expected-note 3{{implicit default constructor}}\
|
||||
// expected-note{{implicit destructor}}}
|
||||
#else
|
||||
template <unsigned N> class Base { ~Base(); }; // expected-note 4{{declared private here}}
|
||||
|
@ -1,5 +1,6 @@
|
||||
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -target-cpu core2 -emit-llvm -o - %s | FileCheck %s
|
||||
// RUN: %clang_cc1 -triple arm64-apple-ios9 -target-cpu cyclone -emit-llvm -o - %s | FileCheck %s
|
||||
// RUN: %clang_cc1 -triple arm64-apple-ios9 -target-cpu cyclone -emit-llvm -o - %s | FileCheck %s --check-prefix=ARM64
|
||||
|
||||
// REQUIRES: aarch64-registered-target,x86-registered-target
|
||||
|
||||
@ -60,6 +61,7 @@ SWIFTCALL void context_error_2(short s, CONTEXT int *self, ERROR float **error)
|
||||
/********************************** LOWERING *********************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef float float3 __attribute__((ext_vector_type(3)));
|
||||
typedef float float4 __attribute__((ext_vector_type(4)));
|
||||
typedef float float8 __attribute__((ext_vector_type(8)));
|
||||
typedef double double2 __attribute__((ext_vector_type(2)));
|
||||
@ -1005,3 +1007,10 @@ struct {
|
||||
TEST(union_het_vecint)
|
||||
// CHECK: define swiftcc void @return_union_het_vecint([[UNION:%.*]]* noalias sret
|
||||
// CHECK: define swiftcc void @take_union_het_vecint([[UNION]]*
|
||||
|
||||
typedef struct {
|
||||
float3 f3;
|
||||
} struct_v1f3;
|
||||
TEST(struct_v1f3)
|
||||
// ARM64-LABEL: define swiftcc { <2 x float>, float } @return_struct_v1f3()
|
||||
// ARM64-LABEL: define swiftcc void @take_struct_v1f3(<2 x float>, float)
|
||||
|
@ -1,4 +1,4 @@
|
||||
// RUN: %clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon -emit-llvm -o - %s | opt -S -mem2reg | FileCheck %s
|
||||
// RUN: %clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon -disable-O0-optnone -emit-llvm -o - %s | opt -S -mem2reg | FileCheck %s
|
||||
|
||||
// Test new aarch64 intrinsics and types
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
// RUN: %clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon -emit-llvm -o - %s | opt -S -mem2reg | FileCheck %s
|
||||
// RUN: %clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon -disable-O0-optnone -emit-llvm -o - %s | opt -S -mem2reg | FileCheck %s
|
||||
|
||||
// Test new aarch64 intrinsics and types
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
// RUN: %clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon \
|
||||
// RUN: -emit-llvm -o - %s | opt -S -mem2reg | FileCheck %s
|
||||
// RUN: -disable-O0-optnone -emit-llvm -o - %s | opt -S -mem2reg | FileCheck %s
|
||||
|
||||
// Test new aarch64 intrinsics and types
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
// REQUIRES: aarch64-registered-target
|
||||
// RUN: %clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon \
|
||||
// RUN: -emit-llvm -o - %s | opt -S -mem2reg | FileCheck %s
|
||||
// RUN: -disable-O0-optnone -emit-llvm -o - %s | opt -S -mem2reg | FileCheck %s
|
||||
|
||||
// Test new aarch64 intrinsics and types
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
// RUN: %clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon \
|
||||
// RUN: -emit-llvm -o - %s | opt -S -mem2reg | FileCheck %s
|
||||
// RUN: -disable-O0-optnone -emit-llvm -o - %s | opt -S -mem2reg | FileCheck %s
|
||||
|
||||
// Test new aarch64 intrinsics and types
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
// RUN: %clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon -S -emit-llvm -o - %s | opt -S -mem2reg | FileCheck %s
|
||||
// RUN: %clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon -S -disable-O0-optnone -emit-llvm -o - %s | opt -S -mem2reg | FileCheck %s
|
||||
|
||||
// Test new aarch64 intrinsics and types
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
// RUN: %clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon \
|
||||
// RUN: -fallow-half-arguments-and-returns -S -emit-llvm -o - %s \
|
||||
// RUN: -fallow-half-arguments-and-returns -S -disable-O0-optnone -emit-llvm -o - %s \
|
||||
// RUN: | opt -S -mem2reg \
|
||||
// RUN: | FileCheck %s
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user