aboutsummaryrefslogtreecommitdiff
path: root/clang
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2021-08-21 21:25:07 +0000
committerDimitry Andric <dim@FreeBSD.org>2021-08-21 21:25:07 +0000
commit9cb5bdb8b26e2207293f0fb56701c4a0ff64a47d (patch)
tree8fe8549bfdf28ab5d376f9ae7a956787d6f8b25e /clang
parentfa40418fea35c68de2a358bce3539cdc5cbcd21a (diff)
downloadsrc-9cb5bdb8b26e2207293f0fb56701c4a0ff64a47d.tar.gz
src-9cb5bdb8b26e2207293f0fb56701c4a0ff64a47d.zip
Diffstat (limited to 'clang')
-rw-r--r--clang/include/clang/Basic/DiagnosticDriverKinds.td2
-rw-r--r--clang/include/clang/Basic/DiagnosticLexKinds.td7
-rw-r--r--clang/include/clang/Basic/DiagnosticSemaKinds.td2
-rw-r--r--clang/include/clang/Basic/LangOptions.def2
-rw-r--r--clang/include/clang/Driver/Options.td3
-rw-r--r--clang/include/clang/Driver/Types.h8
-rw-r--r--clang/include/clang/Frontend/PreprocessorOutputOptions.h2
-rw-r--r--clang/include/clang/Lex/HeaderSearch.h17
-rw-r--r--clang/include/clang/Lex/Preprocessor.h5
-rw-r--r--clang/include/clang/Lex/PreprocessorLexer.h20
-rw-r--r--clang/lib/Basic/OpenCLOptions.cpp7
-rw-r--r--clang/lib/Basic/TargetInfo.cpp10
-rw-r--r--clang/lib/Basic/Targets/AArch64.cpp6
-rw-r--r--clang/lib/Basic/Targets/AMDGPU.h5
-rw-r--r--clang/lib/CodeGen/CGStmt.cpp43
-rw-r--r--clang/lib/CodeGen/TargetInfo.cpp14
-rw-r--r--clang/lib/CodeGen/TargetInfo.h7
-rw-r--r--clang/lib/Driver/ToolChains/Clang.cpp15
-rw-r--r--clang/lib/Driver/Types.cpp39
-rw-r--r--clang/lib/Frontend/CompilerInvocation.cpp2
-rw-r--r--clang/lib/Frontend/PrintPreprocessedOutput.cpp349
-rw-r--r--clang/lib/Lex/Lexer.cpp4
-rw-r--r--clang/lib/Lex/PPDirectives.cpp4
-rw-r--r--clang/lib/Lex/PPLexerChange.cpp45
-rw-r--r--clang/lib/Lex/Pragma.cpp92
-rw-r--r--clang/lib/Lex/Preprocessor.cpp6
-rw-r--r--clang/lib/Parse/ParseDecl.cpp16
-rw-r--r--clang/lib/Sema/Sema.cpp3
-rw-r--r--clang/lib/Sema/SemaType.cpp47
29 files changed, 427 insertions, 355 deletions
diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td
index 3b4daa59f66b..fc3704303a95 100644
--- a/clang/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td
@@ -129,8 +129,6 @@ def err_drv_invalid_Xopenmp_target_with_args : Error<
"invalid -Xopenmp-target argument: '%0', options requiring arguments are unsupported">;
def err_drv_argument_only_allowed_with : Error<
"invalid argument '%0' only allowed with '%1'">;
-def err_drv_minws_unsupported_input_type : Error<
- "'-fminimize-whitespace' invalid for input of type %0">;
def err_drv_amdgpu_ieee_without_no_honor_nans : Error<
"invalid argument '-mno-amdgpu-ieee' only allowed with relaxed NaN handling">;
def err_drv_argument_not_allowed_with : Error<
diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td b/clang/include/clang/Basic/DiagnosticLexKinds.td
index ce6d0d0394b4..bdf5d263fa92 100644
--- a/clang/include/clang/Basic/DiagnosticLexKinds.td
+++ b/clang/include/clang/Basic/DiagnosticLexKinds.td
@@ -300,6 +300,13 @@ def pp_pragma_once_in_main_file : Warning<"#pragma once in main file">,
def pp_pragma_sysheader_in_main_file : Warning<
"#pragma system_header ignored in main file">,
InGroup<DiagGroup<"pragma-system-header-outside-header">>;
+
+def err_pragma_include_instead_not_sysheader : Error<
+ "'#pragma clang include_instead' cannot be used outside of system headers">;
+def err_pragma_include_instead_system_reserved : Error<
+ "header '%0' is an implementation detail; #include %select{'%2'|either '%2' "
+ "or '%3'|one of %2}1 instead">;
+
def pp_poisoning_existing_macro : Warning<"poisoning existing macro">;
def pp_out_of_date_dependency : Warning<
"current file is older than dependency %0">;
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 108f1796415c..c57b8eca7deb 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -10100,8 +10100,6 @@ def err_opencl_requires_extension : Error<
def ext_opencl_double_without_pragma : Extension<
"Clang permits use of type 'double' regardless pragma if 'cl_khr_fp64' is"
" supported">;
-def err_opencl_double_requires_extension : Error<
- "use of type 'double' requires %select{cl_khr_fp64|cl_khr_fp64 and __opencl_c_fp64}0 support">;
def warn_opencl_generic_address_space_arg : Warning<
"passing non-generic address space pointer to %0"
" may cause dynamic conversion affecting performance">,
diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def
index 08b8d8851afa..74deba6ef7fb 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -224,7 +224,7 @@ LANGOPT(OpenCLVersion , 32, 0, "OpenCL C version")
LANGOPT(OpenCLCPlusPlus , 1, 0, "C++ for OpenCL")
LANGOPT(OpenCLCPlusPlusVersion , 32, 0, "C++ for OpenCL version")
LANGOPT(OpenCLGenericAddressSpace, 1, 0, "OpenCL generic keyword")
-LANGOPT(OpenCLPipe , 1, 0, "OpenCL pipe keyword")
+LANGOPT(OpenCLPipes , 1, 0, "OpenCL pipes language constructs and built-ins")
LANGOPT(NativeHalfType , 1, 0, "Native half type support")
LANGOPT(NativeHalfArgsAndReturns, 1, 0, "Native half args and returns")
LANGOPT(HalfArgsAndReturns, 1, 0, "half args and returns")
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 5a9fd078390e..ab1a5487d9c0 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -1799,9 +1799,6 @@ def frewrite_map_file_EQ : Joined<["-"], "frewrite-map-file=">,
defm use_line_directives : BoolFOption<"use-line-directives",
PreprocessorOutputOpts<"UseLineDirectives">, DefaultFalse,
PosFlag<SetTrue, [CC1Option], "Use #line in preprocessed output">, NegFlag<SetFalse>>;
-defm minimize_whitespace : BoolFOption<"minimize-whitespace",
- PreprocessorOutputOpts<"MinimizeWhitespace">, DefaultFalse,
- PosFlag<SetTrue, [CC1Option], "Minimize whitespace when emitting preprocessor output">, NegFlag<SetFalse>>;
def ffreestanding : Flag<["-"], "ffreestanding">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Assert that the compilation takes place in a freestanding environment">,
diff --git a/clang/include/clang/Driver/Types.h b/clang/include/clang/Driver/Types.h
index c9d63551090c..6a1f57416ae5 100644
--- a/clang/include/clang/Driver/Types.h
+++ b/clang/include/clang/Driver/Types.h
@@ -66,14 +66,6 @@ namespace types {
/// isAcceptedByClang - Can clang handle this input type.
bool isAcceptedByClang(ID Id);
- /// isDerivedFromC - Is the input derived from C.
- ///
- /// That is, does the lexer follow the rules of
- /// TokenConcatenation::AvoidConcat. If this is the case, the preprocessor may
- /// add and remove whitespace between tokens. Used to determine whether the
- /// input can be processed by -fminimize-whitespace.
- bool isDerivedFromC(ID Id);
-
/// isCXX - Is this a "C++" input (C++ and Obj-C++ sources and headers).
bool isCXX(ID Id);
diff --git a/clang/include/clang/Frontend/PreprocessorOutputOptions.h b/clang/include/clang/Frontend/PreprocessorOutputOptions.h
index 257538ee0606..72e5ad1137fb 100644
--- a/clang/include/clang/Frontend/PreprocessorOutputOptions.h
+++ b/clang/include/clang/Frontend/PreprocessorOutputOptions.h
@@ -24,7 +24,6 @@ public:
unsigned ShowIncludeDirectives : 1; ///< Print includes, imports etc. within preprocessed output.
unsigned RewriteIncludes : 1; ///< Preprocess include directives only.
unsigned RewriteImports : 1; ///< Include contents of transitively-imported modules.
- unsigned MinimizeWhitespace : 1; ///< Ignore whitespace from input.
public:
PreprocessorOutputOptions() {
@@ -37,7 +36,6 @@ public:
ShowIncludeDirectives = 0;
RewriteIncludes = 0;
RewriteImports = 0;
- MinimizeWhitespace = 0;
}
};
diff --git a/clang/include/clang/Lex/HeaderSearch.h b/clang/include/clang/Lex/HeaderSearch.h
index 93d6ea72270a..a35a394f719b 100644
--- a/clang/include/clang/Lex/HeaderSearch.h
+++ b/clang/include/clang/Lex/HeaderSearch.h
@@ -20,9 +20,12 @@
#include "clang/Lex/ModuleMap.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SetVector.h"
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringMap.h"
-#include "llvm/ADT/StringSet.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSet.h"
#include "llvm/Support/Allocator.h"
#include <cassert>
#include <cstddef>
@@ -110,6 +113,14 @@ struct HeaderFileInfo {
/// of the framework.
StringRef Framework;
+ /// List of aliases that this header is known as.
+ /// Most headers should only have at most one alias, but a handful
+ /// have two.
+ llvm::SetVector<llvm::SmallString<32>,
+ llvm::SmallVector<llvm::SmallString<32>, 2>,
+ llvm::SmallSet<llvm::SmallString<32>, 2>>
+ Aliases;
+
HeaderFileInfo()
: isImport(false), isPragmaOnce(false), DirInfo(SrcMgr::C_User),
External(false), isModuleHeader(false), isCompilingModuleHeader(false),
@@ -453,6 +464,10 @@ public:
getFileInfo(File).DirInfo = SrcMgr::C_System;
}
+ void AddFileAlias(const FileEntry *File, StringRef Alias) {
+ getFileInfo(File).Aliases.insert(Alias);
+ }
+
/// Mark the specified file as part of a module.
void MarkFileModuleHeader(const FileEntry *FE,
ModuleMap::ModuleHeaderRole Role,
diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h
index 7ab13640ce2c..fe2327f0a480 100644
--- a/clang/include/clang/Lex/Preprocessor.h
+++ b/clang/include/clang/Lex/Preprocessor.h
@@ -1953,7 +1953,8 @@ public:
/// This either returns the EOF token and returns true, or
/// pops a level off the include stack and returns false, at which point the
/// client should call lex again.
- bool HandleEndOfFile(Token &Result, bool isEndOfMacro = false);
+ bool HandleEndOfFile(Token &Result, SourceLocation Loc,
+ bool isEndOfMacro = false);
/// Callback invoked when the current TokenLexer hits the end of its
/// token stream.
@@ -2363,12 +2364,14 @@ private:
// Pragmas.
void HandlePragmaDirective(PragmaIntroducer Introducer);
+ void ResolvePragmaIncludeInstead(SourceLocation Location) const;
public:
void HandlePragmaOnce(Token &OnceTok);
void HandlePragmaMark(Token &MarkTok);
void HandlePragmaPoison();
void HandlePragmaSystemHeader(Token &SysHeaderTok);
+ void HandlePragmaIncludeInstead(Token &Tok);
void HandlePragmaDependency(Token &DependencyTok);
void HandlePragmaPushMacro(Token &Tok);
void HandlePragmaPopMacro(Token &Tok);
diff --git a/clang/include/clang/Lex/PreprocessorLexer.h b/clang/include/clang/Lex/PreprocessorLexer.h
index 03b1cc2c10e2..b43197a6031c 100644
--- a/clang/include/clang/Lex/PreprocessorLexer.h
+++ b/clang/include/clang/Lex/PreprocessorLexer.h
@@ -14,11 +14,13 @@
#ifndef LLVM_CLANG_LEX_PREPROCESSORLEXER_H
#define LLVM_CLANG_LEX_PREPROCESSORLEXER_H
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/MultipleIncludeOpt.h"
#include "clang/Lex/Token.h"
-#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringMap.h"
#include <cassert>
namespace clang {
@@ -74,6 +76,13 @@ protected:
/// we are currently in.
SmallVector<PPConditionalInfo, 4> ConditionalStack;
+ struct IncludeInfo {
+ const FileEntry *File;
+ SourceLocation Location;
+ };
+ // A complete history of all the files included by the current file.
+ llvm::StringMap<IncludeInfo> IncludeHistory;
+
PreprocessorLexer() : FID() {}
PreprocessorLexer(Preprocessor *pp, FileID fid);
virtual ~PreprocessorLexer() = default;
@@ -175,6 +184,15 @@ public:
ConditionalStack.clear();
ConditionalStack.append(CL.begin(), CL.end());
}
+
+ void addInclude(StringRef Filename, const FileEntry &File,
+ SourceLocation Location) {
+ IncludeHistory.insert({Filename, {&File, Location}});
+ }
+
+ const llvm::StringMap<IncludeInfo> &getIncludeHistory() const {
+ return IncludeHistory;
+ }
};
} // namespace clang
diff --git a/clang/lib/Basic/OpenCLOptions.cpp b/clang/lib/Basic/OpenCLOptions.cpp
index 2e215b185f66..b7408f39bdab 100644
--- a/clang/lib/Basic/OpenCLOptions.cpp
+++ b/clang/lib/Basic/OpenCLOptions.cpp
@@ -111,7 +111,9 @@ bool OpenCLOptions::diagnoseUnsupportedFeatureDependencies(
// Feature pairs. First feature in a pair requires the second one to be
// supported.
static const llvm::StringMap<llvm::StringRef> DependentFeaturesMap = {
- {"__opencl_c_read_write_images", "__opencl_c_images"}};
+ {"__opencl_c_read_write_images", "__opencl_c_images"},
+ {"__opencl_c_3d_image_writes", "__opencl_c_images"},
+ {"__opencl_c_pipes", "__opencl_c_generic_address_space"}};
auto OpenCLFeaturesMap = TI.getSupportedOpenCLOpts();
@@ -130,7 +132,8 @@ bool OpenCLOptions::diagnoseFeatureExtensionDifferences(
const TargetInfo &TI, DiagnosticsEngine &Diags) {
// Extensions and equivalent feature pairs.
static const llvm::StringMap<llvm::StringRef> FeatureExtensionMap = {
- {"cl_khr_fp64", "__opencl_c_fp64"}};
+ {"cl_khr_fp64", "__opencl_c_fp64"},
+ {"cl_khr_3d_image_writes", "__opencl_c_3d_image_writes"}};
auto OpenCLFeaturesMap = TI.getSupportedOpenCLOpts();
diff --git a/clang/lib/Basic/TargetInfo.cpp b/clang/lib/Basic/TargetInfo.cpp
index b647a2fb8a67..5f8e04c2bd6c 100644
--- a/clang/lib/Basic/TargetInfo.cpp
+++ b/clang/lib/Basic/TargetInfo.cpp
@@ -400,14 +400,18 @@ void TargetInfo::adjust(DiagnosticsEngine &Diags, LangOptions &Opts) {
// OpenCL C v3.0 s6.7.5 - The generic address space requires support for
// OpenCL C 2.0 or OpenCL C 3.0 with the __opencl_c_generic_address_space
// feature
- // FIXME: OpenCLGenericAddressSpace is also defined in setLangDefaults()
+ // OpenCL C v3.0 s6.2.1 - OpenCL pipes require support of OpenCL C 2.0
+ // or later and __opencl_c_pipes feature
+ // FIXME: These language options are also defined in setLangDefaults()
// for OpenCL C 2.0 but with no access to target capabilities. Target
- // should be immutable once created and thus this language option needs
+ // should be immutable once created and thus these language options need
// to be defined only once.
- if (Opts.OpenCLVersion >= 300) {
+ if (Opts.OpenCLVersion == 300) {
const auto &OpenCLFeaturesMap = getSupportedOpenCLOpts();
Opts.OpenCLGenericAddressSpace = hasFeatureEnabled(
OpenCLFeaturesMap, "__opencl_c_generic_address_space");
+ Opts.OpenCLPipes =
+ hasFeatureEnabled(OpenCLFeaturesMap, "__opencl_c_pipes");
}
}
diff --git a/clang/lib/Basic/Targets/AArch64.cpp b/clang/lib/Basic/Targets/AArch64.cpp
index 4070ac727d16..e163ebfa2348 100644
--- a/clang/lib/Basic/Targets/AArch64.cpp
+++ b/clang/lib/Basic/Targets/AArch64.cpp
@@ -431,7 +431,8 @@ bool AArch64TargetInfo::hasFeature(StringRef Feature) const {
Feature == "sve2-aes" || Feature == "sve2-sha3" ||
Feature == "sve2-sm4" || Feature == "f64mm" || Feature == "f32mm" ||
Feature == "i8mm" || Feature == "bf16") &&
- (FPU & SveMode));
+ (FPU & SveMode)) ||
+ (Feature == "ls64" && HasLS64);
}
bool AArch64TargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
@@ -752,6 +753,9 @@ bool AArch64TargetInfo::validateConstraintModifier(
if (Size == 64)
return true;
+ if (Size == 512)
+ return HasLS64;
+
SuggestedModifier = "w";
return false;
}
diff --git a/clang/lib/Basic/Targets/AMDGPU.h b/clang/lib/Basic/Targets/AMDGPU.h
index 244a6e044690..2e580ecf2425 100644
--- a/clang/lib/Basic/Targets/AMDGPU.h
+++ b/clang/lib/Basic/Targets/AMDGPU.h
@@ -310,9 +310,12 @@ public:
Opts["cl_khr_mipmap_image"] = true;
Opts["cl_khr_mipmap_image_writes"] = true;
Opts["cl_khr_subgroups"] = true;
- Opts["cl_khr_3d_image_writes"] = true;
Opts["cl_amd_media_ops"] = true;
Opts["cl_amd_media_ops2"] = true;
+
+ Opts["__opencl_c_images"] = true;
+ Opts["__opencl_c_3d_image_writes"] = true;
+ Opts["cl_khr_3d_image_writes"] = true;
}
}
diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp
index aeb319ca1581..0a3a722fa653 100644
--- a/clang/lib/CodeGen/CGStmt.cpp
+++ b/clang/lib/CodeGen/CGStmt.cpp
@@ -2097,7 +2097,8 @@ CodeGenFunction::EmitAsmInputLValue(const TargetInfo::ConstraintInfo &Info,
} else {
llvm::Type *Ty = ConvertType(InputType);
uint64_t Size = CGM.getDataLayout().getTypeSizeInBits(Ty);
- if (Size <= 64 && llvm::isPowerOf2_64(Size)) {
+ if ((Size <= 64 && llvm::isPowerOf2_64(Size)) ||
+ getTargetHooks().isScalarizableAsmOperand(*this, Ty)) {
Ty = llvm::IntegerType::get(getLLVMContext(), Size);
Ty = llvm::PointerType::getUnqual(Ty);
@@ -2320,23 +2321,28 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
// If this is a register output, then make the inline asm return it
// by-value. If this is a memory result, return the value by-reference.
- bool isScalarizableAggregate =
- hasAggregateEvaluationKind(OutExpr->getType());
- if (!Info.allowsMemory() && (hasScalarEvaluationKind(OutExpr->getType()) ||
- isScalarizableAggregate)) {
+ QualType QTy = OutExpr->getType();
+ const bool IsScalarOrAggregate = hasScalarEvaluationKind(QTy) ||
+ hasAggregateEvaluationKind(QTy);
+ if (!Info.allowsMemory() && IsScalarOrAggregate) {
+
Constraints += "=" + OutputConstraint;
- ResultRegQualTys.push_back(OutExpr->getType());
+ ResultRegQualTys.push_back(QTy);
ResultRegDests.push_back(Dest);
- ResultTruncRegTypes.push_back(ConvertTypeForMem(OutExpr->getType()));
- if (Info.allowsRegister() && isScalarizableAggregate) {
- ResultTypeRequiresCast.push_back(true);
- unsigned Size = getContext().getTypeSize(OutExpr->getType());
- llvm::Type *ConvTy = llvm::IntegerType::get(getLLVMContext(), Size);
- ResultRegTypes.push_back(ConvTy);
- } else {
- ResultTypeRequiresCast.push_back(false);
- ResultRegTypes.push_back(ResultTruncRegTypes.back());
+
+ llvm::Type *Ty = ConvertTypeForMem(QTy);
+ const bool RequiresCast = Info.allowsRegister() &&
+ (getTargetHooks().isScalarizableAsmOperand(*this, Ty) ||
+ Ty->isAggregateType());
+
+ ResultTruncRegTypes.push_back(Ty);
+ ResultTypeRequiresCast.push_back(RequiresCast);
+
+ if (RequiresCast) {
+ unsigned Size = getContext().getTypeSize(QTy);
+ Ty = llvm::IntegerType::get(getLLVMContext(), Size);
}
+ ResultRegTypes.push_back(Ty);
// If this output is tied to an input, and if the input is larger, then
// we need to set the actual result type of the inline asm node to be the
// same as the input type.
@@ -2638,11 +2644,11 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
assert(ResultTypeRequiresCast.size() <= ResultRegDests.size());
for (unsigned i = 0, e = RegResults.size(); i != e; ++i) {
llvm::Value *Tmp = RegResults[i];
+ llvm::Type *TruncTy = ResultTruncRegTypes[i];
// If the result type of the LLVM IR asm doesn't match the result type of
// the expression, do the conversion.
if (ResultRegTypes[i] != ResultTruncRegTypes[i]) {
- llvm::Type *TruncTy = ResultTruncRegTypes[i];
// Truncate the integer result to the right size, note that TruncTy can be
// a pointer.
@@ -2672,6 +2678,11 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
unsigned Size = getContext().getTypeSize(ResultRegQualTys[i]);
Address A = Builder.CreateBitCast(Dest.getAddress(*this),
ResultRegTypes[i]->getPointerTo());
+ if (getTargetHooks().isScalarizableAsmOperand(*this, TruncTy)) {
+ Builder.CreateStore(Tmp, A);
+ continue;
+ }
+
QualType Ty = getContext().getIntTypeForBitwidth(Size, /*Signed*/ false);
if (Ty.isNull()) {
const Expr *OutExpr = S.getOutputExpr(i);
diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp
index a2b68a04d351..d2cc0a699f43 100644
--- a/clang/lib/CodeGen/TargetInfo.cpp
+++ b/clang/lib/CodeGen/TargetInfo.cpp
@@ -5526,6 +5526,20 @@ public:
Fn->addFnAttr("branch-target-enforcement",
BPI.BranchTargetEnforcement ? "true" : "false");
}
+
+ bool isScalarizableAsmOperand(CodeGen::CodeGenFunction &CGF,
+ llvm::Type *Ty) const override {
+ if (CGF.getTarget().hasFeature("ls64")) {
+ auto *ST = dyn_cast<llvm::StructType>(Ty);
+ if (ST && ST->getNumElements() == 1) {
+ auto *AT = dyn_cast<llvm::ArrayType>(ST->getElementType(0));
+ if (AT && AT->getNumElements() == 8 &&
+ AT->getElementType()->isIntegerTy(64))
+ return true;
+ }
+ }
+ return TargetCodeGenInfo::isScalarizableAsmOperand(CGF, Ty);
+ }
};
class WindowsAArch64TargetCodeGenInfo : public AArch64TargetCodeGenInfo {
diff --git a/clang/lib/CodeGen/TargetInfo.h b/clang/lib/CodeGen/TargetInfo.h
index e6e474544fc4..aa8bbb60a75f 100644
--- a/clang/lib/CodeGen/TargetInfo.h
+++ b/clang/lib/CodeGen/TargetInfo.h
@@ -148,6 +148,13 @@ public:
return Ty;
}
+ /// Target hook to decide whether an inline asm operand can be passed
+ /// by value.
+ virtual bool isScalarizableAsmOperand(CodeGen::CodeGenFunction &CGF,
+ llvm::Type *Ty) const {
+ return false;
+ }
+
/// Adds constraints and types for result registers.
virtual void addReturnRegisterOutputs(
CodeGen::CodeGenFunction &CGF, CodeGen::LValue ReturnValue,
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index a4b53a640ab5..1870bd81789c 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -52,9 +52,8 @@ using namespace clang;
using namespace llvm::opt;
static void CheckPreprocessingOptions(const Driver &D, const ArgList &Args) {
- if (Arg *A = Args.getLastArg(clang::driver::options::OPT_C, options::OPT_CC,
- options::OPT_fminimize_whitespace,
- options::OPT_fno_minimize_whitespace)) {
+ if (Arg *A =
+ Args.getLastArg(clang::driver::options::OPT_C, options::OPT_CC)) {
if (!Args.hasArg(options::OPT_E) && !Args.hasArg(options::OPT__SLASH_P) &&
!Args.hasArg(options::OPT__SLASH_EP) && !D.CCCIsCPP()) {
D.Diag(clang::diag::err_drv_argument_only_allowed_with)
@@ -6068,16 +6067,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
options::OPT_fno_use_line_directives, false))
CmdArgs.push_back("-fuse-line-directives");
- // -fno-minimize-whitespace is default.
- if (Args.hasFlag(options::OPT_fminimize_whitespace,
- options::OPT_fno_minimize_whitespace, false)) {
- types::ID InputType = Inputs[0].getType();
- if (!isDerivedFromC(InputType))
- D.Diag(diag::err_drv_minws_unsupported_input_type)
- << types::getTypeName(InputType);
- CmdArgs.push_back("-fminimize-whitespace");
- }
-
// -fms-extensions=0 is default.
if (Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions,
IsWindowsMSVC))
diff --git a/clang/lib/Driver/Types.cpp b/clang/lib/Driver/Types.cpp
index 3cb2d6e8f6fd..b7ccdf23cbaa 100644
--- a/clang/lib/Driver/Types.cpp
+++ b/clang/lib/Driver/Types.cpp
@@ -147,45 +147,6 @@ bool types::isAcceptedByClang(ID Id) {
}
}
-bool types::isDerivedFromC(ID Id) {
- switch (Id) {
- default:
- return false;
-
- case TY_PP_C:
- case TY_C:
- case TY_CL:
- case TY_CLCXX:
- case TY_PP_CUDA:
- case TY_CUDA:
- case TY_CUDA_DEVICE:
- case TY_PP_HIP:
- case TY_HIP:
- case TY_HIP_DEVICE:
- case TY_PP_ObjC:
- case TY_PP_ObjC_Alias:
- case TY_ObjC:
- case TY_PP_CXX:
- case TY_CXX:
- case TY_PP_ObjCXX:
- case TY_PP_ObjCXX_Alias:
- case TY_ObjCXX:
- case TY_RenderScript:
- case TY_PP_CHeader:
- case TY_CHeader:
- case TY_CLHeader:
- case TY_PP_ObjCHeader:
- case TY_ObjCHeader:
- case TY_PP_CXXHeader:
- case TY_CXXHeader:
- case TY_PP_ObjCXXHeader:
- case TY_ObjCXXHeader:
- case TY_CXXModule:
- case TY_PP_CXXModule:
- return true;
- }
-}
-
bool types::isObjC(ID Id) {
switch (Id) {
default:
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index d545e9358f04..33e5f3e99c45 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -3173,7 +3173,7 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
Opts.ZVector = 0;
Opts.setDefaultFPContractMode(LangOptions::FPM_On);
Opts.OpenCLCPlusPlus = Opts.CPlusPlus;
- Opts.OpenCLPipe = Opts.OpenCLCPlusPlus || Opts.OpenCLVersion == 200;
+ Opts.OpenCLPipes = Opts.OpenCLCPlusPlus || Opts.OpenCLVersion == 200;
Opts.OpenCLGenericAddressSpace =
Opts.OpenCLCPlusPlus || Opts.OpenCLVersion == 200;
diff --git a/clang/lib/Frontend/PrintPreprocessedOutput.cpp b/clang/lib/Frontend/PrintPreprocessedOutput.cpp
index b7259569595d..24ea1ccba207 100644
--- a/clang/lib/Frontend/PrintPreprocessedOutput.cpp
+++ b/clang/lib/Frontend/PrintPreprocessedOutput.cpp
@@ -95,20 +95,14 @@ private:
bool DumpIncludeDirectives;
bool UseLineDirectives;
bool IsFirstFileEntered;
- bool MinimizeWhitespace;
-
- Token PrevTok;
- Token PrevPrevTok;
-
public:
PrintPPOutputPPCallbacks(Preprocessor &pp, raw_ostream &os, bool lineMarkers,
bool defines, bool DumpIncludeDirectives,
- bool UseLineDirectives, bool MinimizeWhitespace)
+ bool UseLineDirectives)
: PP(pp), SM(PP.getSourceManager()), ConcatInfo(PP), OS(os),
DisableLineMarkers(lineMarkers), DumpDefines(defines),
DumpIncludeDirectives(DumpIncludeDirectives),
- UseLineDirectives(UseLineDirectives),
- MinimizeWhitespace(MinimizeWhitespace) {
+ UseLineDirectives(UseLineDirectives) {
CurLine = 0;
CurFilename += "<uninit>";
EmittedTokensOnThisLine = false;
@@ -116,13 +110,8 @@ public:
FileType = SrcMgr::C_User;
Initialized = false;
IsFirstFileEntered = false;
-
- PrevTok.startToken();
- PrevPrevTok.startToken();
}
- bool isMinimizeWhitespace() const { return MinimizeWhitespace; }
-
void setEmittedTokensOnThisLine() { EmittedTokensOnThisLine = true; }
bool hasEmittedTokensOnThisLine() const { return EmittedTokensOnThisLine; }
@@ -131,12 +120,7 @@ public:
return EmittedDirectiveOnThisLine;
}
- /// Ensure that the output stream position is at the beginning of a new line
- /// and inserts one if it does not. It is intended to ensure that directives
- /// inserted by the directives not from the input source (such as #line) are
- /// in the first column. To insert newlines that represent the input, use
- /// MoveToLine(/*...*/, /*RequireStartOfLine=*/true).
- void startNewLineIfNeeded();
+ bool startNewLineIfNeeded(bool ShouldUpdateCurrentLine = true);
void FileChanged(SourceLocation Loc, FileChangeReason Reason,
SrcMgr::CharacteristicKind FileType,
@@ -164,45 +148,18 @@ public:
void PragmaAssumeNonNullBegin(SourceLocation Loc) override;
void PragmaAssumeNonNullEnd(SourceLocation Loc) override;
- /// Insert whitespace before emitting the next token.
- ///
- /// @param Tok Next token to be emitted.
- /// @param RequireSpace Ensure at least one whitespace is emitted. Useful
- /// if non-tokens have been emitted to the stream.
- /// @param RequireSameLine Never emit newlines. Useful when semantics depend
- /// on being on the same line, such as directives.
- void HandleWhitespaceBeforeTok(const Token &Tok, bool RequireSpace,
- bool RequireSameLine);
+ bool HandleFirstTokOnLine(Token &Tok);
/// Move to the line of the provided source location. This will
- /// return true if a newline was inserted or if
- /// the requested location is the first token on the first line.
- /// In these cases the next output will be the first column on the line and
- /// make it possible to insert indention. The newline was inserted
- /// implicitly when at the beginning of the file.
- ///
- /// @param Tok Token where to move to.
- /// @param RequiresStartOfLine Whether the next line depends on being in the
- /// first column, such as a directive.
- ///
- /// @return Whether column adjustments are necessary.
- bool MoveToLine(const Token &Tok, bool RequireStartOfLine) {
- PresumedLoc PLoc = SM.getPresumedLoc(Tok.getLocation());
- if (PLoc.isInvalid())
- return false;
- bool IsFirstInFile = Tok.isAtStartOfLine() && PLoc.getLine() == 1;
- return MoveToLine(PLoc.getLine(), RequireStartOfLine) || IsFirstInFile;
- }
-
- /// Move to the line of the provided source location. Returns true if a new
- /// line was inserted.
- bool MoveToLine(SourceLocation Loc, bool RequireStartOfLine) {
+ /// return true if the output stream required adjustment or if
+ /// the requested location is on the first line.
+ bool MoveToLine(SourceLocation Loc) {
PresumedLoc PLoc = SM.getPresumedLoc(Loc);
if (PLoc.isInvalid())
return false;
- return MoveToLine(PLoc.getLine(), RequireStartOfLine);
+ return MoveToLine(PLoc.getLine()) || (PLoc.getLine() == 1);
}
- bool MoveToLine(unsigned LineNo, bool RequireStartOfLine);
+ bool MoveToLine(unsigned LineNo);
bool AvoidConcat(const Token &PrevPrevTok, const Token &PrevTok,
const Token &Tok) {
@@ -230,7 +187,7 @@ public:
void PrintPPOutputPPCallbacks::WriteLineInfo(unsigned LineNo,
const char *Extra,
unsigned ExtraLen) {
- startNewLineIfNeeded();
+ startNewLineIfNeeded(/*ShouldUpdateCurrentLine=*/false);
// Emit #line directives or GNU line markers depending on what mode we're in.
if (UseLineDirectives) {
@@ -257,57 +214,43 @@ void PrintPPOutputPPCallbacks::WriteLineInfo(unsigned LineNo,
/// object. We can do this by emitting some number of \n's, or be emitting a
/// #line directive. This returns false if already at the specified line, true
/// if some newlines were emitted.
-bool PrintPPOutputPPCallbacks::MoveToLine(unsigned LineNo,
- bool RequireStartOfLine) {
- // If it is required to start a new line or finish the current, insert
- // vertical whitespace now and take it into account when moving to the
- // expected line.
- bool StartedNewLine = false;
- if ((RequireStartOfLine && EmittedTokensOnThisLine) ||
- EmittedDirectiveOnThisLine) {
- OS << '\n';
- StartedNewLine = true;
- CurLine += 1;
- EmittedTokensOnThisLine = false;
- EmittedDirectiveOnThisLine = false;
- }
-
+bool PrintPPOutputPPCallbacks::MoveToLine(unsigned LineNo) {
// If this line is "close enough" to the original line, just print newlines,
// otherwise print a #line directive.
- if (CurLine == LineNo) {
- // Nothing to do if we are already on the correct line.
- } else if (!StartedNewLine && (!MinimizeWhitespace || !DisableLineMarkers) &&
- LineNo - CurLine == 1) {
- // Printing a single line has priority over printing a #line directive, even
- // when minimizing whitespace which otherwise would print #line directives
- // for every single line.
- OS << '\n';
- StartedNewLine = true;
- } else if (!MinimizeWhitespace && LineNo - CurLine <= 8) {
- const char *NewLines = "\n\n\n\n\n\n\n\n";
- OS.write(NewLines, LineNo - CurLine);
- StartedNewLine = true;
+ if (LineNo-CurLine <= 8) {
+ if (LineNo-CurLine == 1)
+ OS << '\n';
+ else if (LineNo == CurLine)
+ return false; // Spelling line moved, but expansion line didn't.
+ else {
+ const char *NewLines = "\n\n\n\n\n\n\n\n";
+ OS.write(NewLines, LineNo-CurLine);
+ }
} else if (!DisableLineMarkers) {
// Emit a #line or line marker.
WriteLineInfo(LineNo, nullptr, 0);
- StartedNewLine = true;
- }
-
- if (StartedNewLine) {
- EmittedTokensOnThisLine = false;
- EmittedDirectiveOnThisLine = false;
+ } else {
+ // Okay, we're in -P mode, which turns off line markers. However, we still
+ // need to emit a newline between tokens on different lines.
+ startNewLineIfNeeded(/*ShouldUpdateCurrentLine=*/false);
}
CurLine = LineNo;
- return StartedNewLine;
+ return true;
}
-void PrintPPOutputPPCallbacks::startNewLineIfNeeded() {
+bool
+PrintPPOutputPPCallbacks::startNewLineIfNeeded(bool ShouldUpdateCurrentLine) {
if (EmittedTokensOnThisLine || EmittedDirectiveOnThisLine) {
OS << '\n';
EmittedTokensOnThisLine = false;
EmittedDirectiveOnThisLine = false;
+ if (ShouldUpdateCurrentLine)
+ ++CurLine;
+ return true;
}
+
+ return false;
}
/// FileChanged - Whenever the preprocessor enters or exits a #include file
@@ -330,7 +273,7 @@ void PrintPPOutputPPCallbacks::FileChanged(SourceLocation Loc,
if (Reason == PPCallbacks::EnterFile) {
SourceLocation IncludeLoc = UserLoc.getIncludeLoc();
if (IncludeLoc.isValid())
- MoveToLine(IncludeLoc, /*RequireStartOfLine=*/false);
+ MoveToLine(IncludeLoc);
} else if (Reason == PPCallbacks::SystemHeaderPragma) {
// GCC emits the # directive for this directive on the line AFTER the
// directive and emits a bunch of spaces that aren't needed. This is because
@@ -347,8 +290,7 @@ void PrintPPOutputPPCallbacks::FileChanged(SourceLocation Loc,
FileType = NewFileType;
if (DisableLineMarkers) {
- if (!MinimizeWhitespace)
- startNewLineIfNeeded();
+ startNewLineIfNeeded(/*ShouldUpdateCurrentLine=*/false);
return;
}
@@ -394,13 +336,15 @@ void PrintPPOutputPPCallbacks::InclusionDirective(
// In -dI mode, dump #include directives prior to dumping their content or
// interpretation.
if (DumpIncludeDirectives) {
- MoveToLine(HashLoc, /*RequireStartOfLine=*/true);
+ startNewLineIfNeeded();
+ MoveToLine(HashLoc);
const std::string TokenText = PP.getSpelling(IncludeTok);
assert(!TokenText.empty());
OS << "#" << TokenText << " "
<< (IsAngled ? '<' : '"') << FileName << (IsAngled ? '>' : '"')
<< " /* clang -E -dI */";
setEmittedDirectiveOnThisLine();
+ startNewLineIfNeeded();
}
// When preprocessing, turn implicit imports into module import pragmas.
@@ -409,13 +353,17 @@ void PrintPPOutputPPCallbacks::InclusionDirective(
case tok::pp_include:
case tok::pp_import:
case tok::pp_include_next:
- MoveToLine(HashLoc, /*RequireStartOfLine=*/true);
+ startNewLineIfNeeded();
+ MoveToLine(HashLoc);
OS << "#pragma clang module import " << Imported->getFullModuleName(true)
<< " /* clang -E: implicit import for "
<< "#" << PP.getSpelling(IncludeTok) << " "
<< (IsAngled ? '<' : '"') << FileName << (IsAngled ? '>' : '"')
<< " */";
- setEmittedDirectiveOnThisLine();
+ // Since we want a newline after the pragma, but not a #<line>, start a
+ // new line immediately.
+ EmittedTokensOnThisLine = true;
+ startNewLineIfNeeded();
break;
case tok::pp___include_macros:
@@ -450,11 +398,11 @@ void PrintPPOutputPPCallbacks::EndModule(const Module *M) {
/// Ident - Handle #ident directives when read by the preprocessor.
///
void PrintPPOutputPPCallbacks::Ident(SourceLocation Loc, StringRef S) {
- MoveToLine(Loc, /*RequireStartOfLine=*/true);
+ MoveToLine(Loc);
OS.write("#ident ", strlen("#ident "));
OS.write(S.begin(), S.size());
- setEmittedTokensOnThisLine();
+ EmittedTokensOnThisLine = true;
}
/// MacroDefined - This hook is called whenever a macro definition is seen.
@@ -466,7 +414,7 @@ void PrintPPOutputPPCallbacks::MacroDefined(const Token &MacroNameTok,
// Ignore __FILE__ etc.
MI->isBuiltinMacro()) return;
- MoveToLine(MI->getDefinitionLoc(), /*RequireStartOfLine=*/true);
+ MoveToLine(MI->getDefinitionLoc());
PrintMacroDefinition(*MacroNameTok.getIdentifierInfo(), *MI, PP, OS);
setEmittedDirectiveOnThisLine();
}
@@ -477,7 +425,7 @@ void PrintPPOutputPPCallbacks::MacroUndefined(const Token &MacroNameTok,
// Only print out macro definitions in -dD mode.
if (!DumpDefines) return;
- MoveToLine(MacroNameTok.getLocation(), /*RequireStartOfLine=*/true);
+ MoveToLine(MacroNameTok.getLocation());
OS << "#undef " << MacroNameTok.getIdentifierInfo()->getName();
setEmittedDirectiveOnThisLine();
}
@@ -498,7 +446,8 @@ void PrintPPOutputPPCallbacks::PragmaMessage(SourceLocation Loc,
StringRef Namespace,
PragmaMessageKind Kind,
StringRef Str) {
- MoveToLine(Loc, /*RequireStartOfLine=*/true);
+ startNewLineIfNeeded();
+ MoveToLine(Loc);
OS << "#pragma ";
if (!Namespace.empty())
OS << Namespace << ' ';
@@ -523,7 +472,8 @@ void PrintPPOutputPPCallbacks::PragmaMessage(SourceLocation Loc,
void PrintPPOutputPPCallbacks::PragmaDebug(SourceLocation Loc,
StringRef DebugType) {
- MoveToLine(Loc, /*RequireStartOfLine=*/true);
+ startNewLineIfNeeded();
+ MoveToLine(Loc);
OS << "#pragma clang __debug ";
OS << DebugType;
@@ -533,14 +483,16 @@ void PrintPPOutputPPCallbacks::PragmaDebug(SourceLocation Loc,
void PrintPPOutputPPCallbacks::
PragmaDiagnosticPush(SourceLocation Loc, StringRef Namespace) {
- MoveToLine(Loc, /*RequireStartOfLine=*/true);
+ startNewLineIfNeeded();
+ MoveToLine(Loc);
OS << "#pragma " << Namespace << " diagnostic push";
setEmittedDirectiveOnThisLine();
}
void PrintPPOutputPPCallbacks::
PragmaDiagnosticPop(SourceLocation Loc, StringRef Namespace) {
- MoveToLine(Loc, /*RequireStartOfLine=*/true);
+ startNewLineIfNeeded();
+ MoveToLine(Loc);
OS << "#pragma " << Namespace << " diagnostic pop";
setEmittedDirectiveOnThisLine();
}
@@ -549,7 +501,8 @@ void PrintPPOutputPPCallbacks::PragmaDiagnostic(SourceLocation Loc,
StringRef Namespace,
diag::Severity Map,
StringRef Str) {
- MoveToLine(Loc, /*RequireStartOfLine=*/true);
+ startNewLineIfNeeded();
+ MoveToLine(Loc);
OS << "#pragma " << Namespace << " diagnostic ";
switch (Map) {
case diag::Severity::Remark:
@@ -575,7 +528,8 @@ void PrintPPOutputPPCallbacks::PragmaDiagnostic(SourceLocation Loc,
void PrintPPOutputPPCallbacks::PragmaWarning(SourceLocation Loc,
StringRef WarningSpec,
ArrayRef<int> Ids) {
- MoveToLine(Loc, /*RequireStartOfLine=*/true);
+ startNewLineIfNeeded();
+ MoveToLine(Loc);
OS << "#pragma warning(" << WarningSpec << ':';
for (ArrayRef<int>::iterator I = Ids.begin(), E = Ids.end(); I != E; ++I)
OS << ' ' << *I;
@@ -585,7 +539,8 @@ void PrintPPOutputPPCallbacks::PragmaWarning(SourceLocation Loc,
void PrintPPOutputPPCallbacks::PragmaWarningPush(SourceLocation Loc,
int Level) {
- MoveToLine(Loc, /*RequireStartOfLine=*/true);
+ startNewLineIfNeeded();
+ MoveToLine(Loc);
OS << "#pragma warning(push";
if (Level >= 0)
OS << ", " << Level;
@@ -594,14 +549,16 @@ void PrintPPOutputPPCallbacks::PragmaWarningPush(SourceLocation Loc,
}
void PrintPPOutputPPCallbacks::PragmaWarningPop(SourceLocation Loc) {
- MoveToLine(Loc, /*RequireStartOfLine=*/true);
+ startNewLineIfNeeded();
+ MoveToLine(Loc);
OS << "#pragma warning(pop)";
setEmittedDirectiveOnThisLine();
}
void PrintPPOutputPPCallbacks::PragmaExecCharsetPush(SourceLocation Loc,
StringRef Str) {
- MoveToLine(Loc, /*RequireStartOfLine=*/true);
+ startNewLineIfNeeded();
+ MoveToLine(Loc);
OS << "#pragma character_execution_set(push";
if (!Str.empty())
OS << ", " << Str;
@@ -610,80 +567,64 @@ void PrintPPOutputPPCallbacks::PragmaExecCharsetPush(SourceLocation Loc,
}
void PrintPPOutputPPCallbacks::PragmaExecCharsetPop(SourceLocation Loc) {
- MoveToLine(Loc, /*RequireStartOfLine=*/true);
+ startNewLineIfNeeded();
+ MoveToLine(Loc);
OS << "#pragma character_execution_set(pop)";
setEmittedDirectiveOnThisLine();
}
void PrintPPOutputPPCallbacks::
PragmaAssumeNonNullBegin(SourceLocation Loc) {
- MoveToLine(Loc, /*RequireStartOfLine=*/true);
+ startNewLineIfNeeded();
+ MoveToLine(Loc);
OS << "#pragma clang assume_nonnull begin";
setEmittedDirectiveOnThisLine();
}
void PrintPPOutputPPCallbacks::
PragmaAssumeNonNullEnd(SourceLocation Loc) {
- MoveToLine(Loc, /*RequireStartOfLine=*/true);
+ startNewLineIfNeeded();
+ MoveToLine(Loc);
OS << "#pragma clang assume_nonnull end";
setEmittedDirectiveOnThisLine();
}
-void PrintPPOutputPPCallbacks::HandleWhitespaceBeforeTok(const Token &Tok,
- bool RequireSpace,
- bool RequireSameLine) {
- // These tokens are not expanded to anything and don't need whitespace before
- // them.
- if (Tok.is(tok::eof) ||
- (Tok.isAnnotation() && !Tok.is(tok::annot_header_unit) &&
- !Tok.is(tok::annot_module_begin) && !Tok.is(tok::annot_module_end)))
- return;
+/// HandleFirstTokOnLine - When emitting a preprocessed file in -E mode, this
+/// is called for the first token on each new line. If this really is the start
+/// of a new logical line, handle it and return true, otherwise return false.
+/// This may not be the start of a logical line because the "start of line"
+/// marker is set for spelling lines, not expansion ones.
+bool PrintPPOutputPPCallbacks::HandleFirstTokOnLine(Token &Tok) {
+ // Figure out what line we went to and insert the appropriate number of
+ // newline characters.
+ if (!MoveToLine(Tok.getLocation()))
+ return false;
+
+ // Print out space characters so that the first token on a line is
+ // indented for easy reading.
+ unsigned ColNo = SM.getExpansionColumnNumber(Tok.getLocation());
+
+ // The first token on a line can have a column number of 1, yet still expect
+ // leading white space, if a macro expansion in column 1 starts with an empty
+ // macro argument, or an empty nested macro expansion. In this case, move the
+ // token to column 2.
+ if (ColNo == 1 && Tok.hasLeadingSpace())
+ ColNo = 2;
+
+ // This hack prevents stuff like:
+ // #define HASH #
+ // HASH define foo bar
+ // From having the # character end up at column 1, which makes it so it
+ // is not handled as a #define next time through the preprocessor if in
+ // -fpreprocessed mode.
+ if (ColNo <= 1 && Tok.is(tok::hash))
+ OS << ' ';
- if (!RequireSameLine && MoveToLine(Tok, /*RequireStartOfLine=*/false)) {
- if (MinimizeWhitespace) {
- // Avoid interpreting hash as a directive under -fpreprocessed.
- if (Tok.is(tok::hash))
- OS << ' ';
- } else {
- // Print out space characters so that the first token on a line is
- // indented for easy reading.
- unsigned ColNo = SM.getExpansionColumnNumber(Tok.getLocation());
-
- // The first token on a line can have a column number of 1, yet still
- // expect leading white space, if a macro expansion in column 1 starts
- // with an empty macro argument, or an empty nested macro expansion. In
- // this case, move the token to column 2.
- if (ColNo == 1 && Tok.hasLeadingSpace())
- ColNo = 2;
-
- // This hack prevents stuff like:
- // #define HASH #
- // HASH define foo bar
- // From having the # character end up at column 1, which makes it so it
- // is not handled as a #define next time through the preprocessor if in
- // -fpreprocessed mode.
- if (ColNo <= 1 && Tok.is(tok::hash))
- OS << ' ';
-
- // Otherwise, indent the appropriate number of spaces.
- for (; ColNo > 1; --ColNo)
- OS << ' ';
- }
- } else {
- // Insert whitespace between the previous and next token if either
- // - The caller requires it
- // - The input had whitespace between them and we are not in
- // whitespace-minimization mode
- // - The whitespace is necessary to keep the tokens apart and there is not
- // already a newline between them
- if (RequireSpace || (!MinimizeWhitespace && Tok.hasLeadingSpace()) ||
- ((EmittedTokensOnThisLine || EmittedTokensOnThisLine) &&
- AvoidConcat(PrevPrevTok, PrevTok, Tok)))
- OS << ' ';
- }
+ // Otherwise, indent the appropriate number of spaces.
+ for (; ColNo > 1; --ColNo)
+ OS << ' ';
- PrevPrevTok = PrevTok;
- PrevTok = Tok;
+ return true;
}
void PrintPPOutputPPCallbacks::HandleNewlinesInToken(const char *TokStr,
@@ -727,9 +668,9 @@ struct UnknownPragmaHandler : public PragmaHandler {
Token &PragmaTok) override {
// Figure out what line we went to and insert the appropriate number of
// newline characters.
- Callbacks->MoveToLine(PragmaTok.getLocation(), /*RequireStartOfLine=*/true);
+ Callbacks->startNewLineIfNeeded();
+ Callbacks->MoveToLine(PragmaTok.getLocation());
Callbacks->OS.write(Prefix, strlen(Prefix));
- Callbacks->setEmittedTokensOnThisLine();
if (ShouldExpandTokens) {
// The first token does not have expanded macros. Expand them, if
@@ -741,16 +682,21 @@ struct UnknownPragmaHandler : public PragmaHandler {
/*IsReinject=*/false);
PP.Lex(PragmaTok);
}
+ Token PrevToken;
+ Token PrevPrevToken;
+ PrevToken.startToken();
+ PrevPrevToken.startToken();
// Read and print all of the pragma tokens.
- bool IsFirst = true;
while (PragmaTok.isNot(tok::eod)) {
- Callbacks->HandleWhitespaceBeforeTok(PragmaTok, /*RequireSpace=*/IsFirst,
- /*RequireSameLine=*/true);
- IsFirst = false;
+ if (PragmaTok.hasLeadingSpace() ||
+ Callbacks->AvoidConcat(PrevPrevToken, PrevToken, PragmaTok))
+ Callbacks->OS << ' ';
std::string TokSpell = PP.getSpelling(PragmaTok);
Callbacks->OS.write(&TokSpell[0], TokSpell.size());
- Callbacks->setEmittedTokensOnThisLine();
+
+ PrevPrevToken = PrevToken;
+ PrevToken = PragmaTok;
if (ShouldExpandTokens)
PP.Lex(PragmaTok);
@@ -769,41 +715,44 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok,
bool DropComments = PP.getLangOpts().TraditionalCPP &&
!PP.getCommentRetentionState();
- bool IsStartOfLine = false;
char Buffer[256];
+ Token PrevPrevTok, PrevTok;
+ PrevPrevTok.startToken();
+ PrevTok.startToken();
while (1) {
- // Two lines joined with line continuation ('\' as last character on the
- // line) must be emitted as one line even though Tok.getLine() returns two
- // different values. In this situation Tok.isAtStartOfLine() is false even
- // though it may be the first token on the lexical line. When
- // dropping/skipping a token that is at the start of a line, propagate the
- // start-of-line-ness to the next token to not append it to the previous
- // line.
- IsStartOfLine = IsStartOfLine || Tok.isAtStartOfLine();
-
- Callbacks->HandleWhitespaceBeforeTok(Tok, /*RequireSpace=*/false,
- /*RequireSameLine=*/!IsStartOfLine);
+ if (Callbacks->hasEmittedDirectiveOnThisLine()) {
+ Callbacks->startNewLineIfNeeded();
+ Callbacks->MoveToLine(Tok.getLocation());
+ }
+
+ // If this token is at the start of a line, emit newlines if needed.
+ if (Tok.isAtStartOfLine() && Callbacks->HandleFirstTokOnLine(Tok)) {
+ // done.
+ } else if (Tok.hasLeadingSpace() ||
+ // If we haven't emitted a token on this line yet, PrevTok isn't
+ // useful to look at and no concatenation could happen anyway.
+ (Callbacks->hasEmittedTokensOnThisLine() &&
+ // Don't print "-" next to "-", it would form "--".
+ Callbacks->AvoidConcat(PrevPrevTok, PrevTok, Tok))) {
+ OS << ' ';
+ }
if (DropComments && Tok.is(tok::comment)) {
// Skip comments. Normally the preprocessor does not generate
// tok::comment nodes at all when not keeping comments, but under
// -traditional-cpp the lexer keeps /all/ whitespace, including comments.
- PP.Lex(Tok);
- continue;
+ SourceLocation StartLoc = Tok.getLocation();
+ Callbacks->MoveToLine(StartLoc.getLocWithOffset(Tok.getLength()));
} else if (Tok.is(tok::eod)) {
// Don't print end of directive tokens, since they are typically newlines
// that mess up our line tracking. These come from unknown pre-processor
// directives or hash-prefixed comments in standalone assembly files.
PP.Lex(Tok);
- // FIXME: The token on the next line after #include should have
- // Tok.isAtStartOfLine() set.
- IsStartOfLine = true;
continue;
} else if (Tok.is(tok::annot_module_include)) {
// PrintPPOutputPPCallbacks::InclusionDirective handles producing
// appropriate output here. Ignore this token entirely.
PP.Lex(Tok);
- IsStartOfLine = true;
continue;
} else if (Tok.is(tok::annot_module_begin)) {
// FIXME: We retrieve this token after the FileChanged callback, and
@@ -815,13 +764,11 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok,
Callbacks->BeginModule(
reinterpret_cast<Module *>(Tok.getAnnotationValue()));
PP.Lex(Tok);
- IsStartOfLine = true;
continue;
} else if (Tok.is(tok::annot_module_end)) {
Callbacks->EndModule(
reinterpret_cast<Module *>(Tok.getAnnotationValue()));
PP.Lex(Tok);
- IsStartOfLine = true;
continue;
} else if (Tok.is(tok::annot_header_unit)) {
// This is a header-name that has been (effectively) converted into a
@@ -849,17 +796,8 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok,
// Tokens that can contain embedded newlines need to adjust our current
// line number.
- // FIXME: The token may end with a newline in which case
- // setEmittedDirectiveOnThisLine/setEmittedTokensOnThisLine afterwards is
- // wrong.
if (Tok.getKind() == tok::comment || Tok.getKind() == tok::unknown)
Callbacks->HandleNewlinesInToken(TokPtr, Len);
- if (Tok.is(tok::comment) && Len >= 2 && TokPtr[0] == '/' &&
- TokPtr[1] == '/') {
- // It's a line comment;
- // Ensure that we don't concatenate anything behind it.
- Callbacks->setEmittedDirectiveOnThisLine();
- }
} else {
std::string S = PP.getSpelling(Tok);
OS.write(S.data(), S.size());
@@ -868,17 +806,13 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok,
// line number.
if (Tok.getKind() == tok::comment || Tok.getKind() == tok::unknown)
Callbacks->HandleNewlinesInToken(S.data(), S.size());
- if (Tok.is(tok::comment) && S.size() >= 2 && S[0] == '/' && S[1] == '/') {
- // It's a line comment;
- // Ensure that we don't concatenate anything behind it.
- Callbacks->setEmittedDirectiveOnThisLine();
- }
}
Callbacks->setEmittedTokensOnThisLine();
- IsStartOfLine = false;
if (Tok.is(tok::eof)) break;
+ PrevPrevTok = PrevTok;
+ PrevTok = Tok;
PP.Lex(Tok);
}
}
@@ -936,8 +870,7 @@ void clang::DoPrintPreprocessedInput(Preprocessor &PP, raw_ostream *OS,
PrintPPOutputPPCallbacks *Callbacks = new PrintPPOutputPPCallbacks(
PP, *OS, !Opts.ShowLineMarkers, Opts.ShowMacros,
- Opts.ShowIncludeDirectives, Opts.UseLineDirectives,
- Opts.MinimizeWhitespace);
+ Opts.ShowIncludeDirectives, Opts.UseLineDirectives);
// Expand macros in pragmas with -fms-extensions. The assumption is that
// the majority of pragmas in such a file will be Microsoft pragmas.
diff --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp
index 3034af231e0e..64944492eb99 100644
--- a/clang/lib/Lex/Lexer.cpp
+++ b/clang/lib/Lex/Lexer.cpp
@@ -2811,11 +2811,11 @@ bool Lexer::LexEndOfFile(Token &Result, const char *CurPtr) {
ConditionalStack.pop_back();
}
+ SourceLocation EndLoc = getSourceLocation(BufferEnd);
// C99 5.1.1.2p2: If the file is non-empty and didn't end in a newline, issue
// a pedwarn.
if (CurPtr != BufferStart && (CurPtr[-1] != '\n' && CurPtr[-1] != '\r')) {
DiagnosticsEngine &Diags = PP->getDiagnostics();
- SourceLocation EndLoc = getSourceLocation(BufferEnd);
unsigned DiagID;
if (LangOpts.CPlusPlus11) {
@@ -2838,7 +2838,7 @@ bool Lexer::LexEndOfFile(Token &Result, const char *CurPtr) {
BufferPtr = CurPtr;
// Finally, let the preprocessor handle this.
- return PP->HandleEndOfFile(Result, isPragmaLexer());
+ return PP->HandleEndOfFile(Result, EndLoc, isPragmaLexer());
}
/// isNextPPTokenLParen - Return 1 if the next unexpanded token lexed from
diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp
index 556dd8daf652..3fa8746653b0 100644
--- a/clang/lib/Lex/PPDirectives.cpp
+++ b/clang/lib/Lex/PPDirectives.cpp
@@ -2022,6 +2022,10 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(
IsFrameworkFound, IsImportDecl, IsMapped, LookupFrom, LookupFromFile,
LookupFilename, RelativePath, SearchPath, SuggestedModule, isAngled);
+ // Record the header's filename for later use.
+ if (File)
+ CurLexer->addInclude(OriginalFilename, File->getFileEntry(), FilenameLoc);
+
if (usingPCHWithThroughHeader() && SkippingUntilPCHThroughHeader) {
if (File && isPCHThroughHeader(&File->getFileEntry()))
SkippingUntilPCHThroughHeader = false;
diff --git a/clang/lib/Lex/PPLexerChange.cpp b/clang/lib/Lex/PPLexerChange.cpp
index b979b965f46a..16170969a322 100644
--- a/clang/lib/Lex/PPLexerChange.cpp
+++ b/clang/lib/Lex/PPLexerChange.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/LexDiagnostic.h"
@@ -22,6 +23,7 @@
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBufferRef.h"
#include "llvm/Support/Path.h"
+
using namespace clang;
//===----------------------------------------------------------------------===//
@@ -299,10 +301,46 @@ void Preprocessor::diagnoseMissingHeaderInUmbrellaDir(const Module &Mod) {
}
}
+void Preprocessor::ResolvePragmaIncludeInstead(
+ const SourceLocation Location) const {
+ assert(Location.isValid());
+ if (CurLexer == nullptr)
+ return;
+
+ if (SourceMgr.isInSystemHeader(Location))
+ return;
+
+ for (const auto &Include : CurLexer->getIncludeHistory()) {
+ StringRef Filename = Include.getKey();
+ const PreprocessorLexer::IncludeInfo &Info = Include.getValue();
+ ArrayRef<SmallString<32>> Aliases =
+ HeaderInfo.getFileInfo(Info.File).Aliases.getArrayRef();
+
+ if (Aliases.empty())
+ continue;
+
+ switch (Aliases.size()) {
+ case 1:
+ Diag(Info.Location, diag::err_pragma_include_instead_system_reserved)
+ << Filename << 0 << Aliases[0];
+ continue;
+ case 2:
+ Diag(Info.Location, diag::err_pragma_include_instead_system_reserved)
+ << Filename << 1 << Aliases[0] << Aliases[1];
+ continue;
+ default: {
+ Diag(Info.Location, diag::err_pragma_include_instead_system_reserved)
+ << Filename << 2 << ("{'" + llvm::join(Aliases, "', '") + "'}");
+ }
+ }
+ }
+}
+
/// HandleEndOfFile - This callback is invoked when the lexer hits the end of
/// the current file. This either returns the EOF token or pops a level off
/// the include stack and keeps going.
-bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) {
+bool Preprocessor::HandleEndOfFile(Token &Result, SourceLocation EndLoc,
+ bool isEndOfMacro) {
assert(!CurTokenLexer &&
"Ending a file when currently in a macro!");
@@ -372,6 +410,9 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) {
}
}
+ if (EndLoc.isValid())
+ ResolvePragmaIncludeInstead(EndLoc);
+
// Complain about reaching a true EOF within arc_cf_code_audited.
// We don't want to complain about reaching the end of a macro
// instantiation or a _Pragma.
@@ -560,7 +601,7 @@ bool Preprocessor::HandleEndOfTokenLexer(Token &Result) {
TokenLexerCache[NumCachedTokenLexers++] = std::move(CurTokenLexer);
// Handle this like a #include file being popped off the stack.
- return HandleEndOfFile(Result, true);
+ return HandleEndOfFile(Result, {}, true);
}
/// RemoveTopOfLexerStack - Pop the current lexer/macro exp off the top of the
diff --git a/clang/lib/Lex/Pragma.cpp b/clang/lib/Lex/Pragma.cpp
index c89061ba6d02..27765af34fed 100644
--- a/clang/lib/Lex/Pragma.cpp
+++ b/clang/lib/Lex/Pragma.cpp
@@ -13,6 +13,7 @@
#include "clang/Lex/Pragma.h"
#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticLex.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/LLVM.h"
@@ -35,11 +36,12 @@
#include "clang/Lex/TokenLexer.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Timer.h"
@@ -495,43 +497,88 @@ void Preprocessor::HandlePragmaSystemHeader(Token &SysHeaderTok) {
SrcMgr::C_System);
}
-/// HandlePragmaDependency - Handle \#pragma GCC dependency "foo" blah.
-void Preprocessor::HandlePragmaDependency(Token &DependencyTok) {
+static llvm::Optional<Token> LexHeader(Preprocessor &PP,
+ Optional<FileEntryRef> &File,
+ bool SuppressIncludeNotFoundError) {
Token FilenameTok;
- if (LexHeaderName(FilenameTok, /*AllowConcatenation*/false))
- return;
+ if (PP.LexHeaderName(FilenameTok, /*AllowConcatenation*/ false))
+ return llvm::None;
// If the next token wasn't a header-name, diagnose the error.
if (FilenameTok.isNot(tok::header_name)) {
- Diag(FilenameTok.getLocation(), diag::err_pp_expects_filename);
- return;
+ PP.Diag(FilenameTok.getLocation(), diag::err_pp_expects_filename);
+ return llvm::None;
}
// Reserve a buffer to get the spelling.
SmallString<128> FilenameBuffer;
bool Invalid = false;
- StringRef Filename = getSpelling(FilenameTok, FilenameBuffer, &Invalid);
+ StringRef Filename = PP.getSpelling(FilenameTok, FilenameBuffer, &Invalid);
if (Invalid)
- return;
+ return llvm::None;
bool isAngled =
- GetIncludeFilenameSpelling(FilenameTok.getLocation(), Filename);
+ PP.GetIncludeFilenameSpelling(FilenameTok.getLocation(), Filename);
// If GetIncludeFilenameSpelling set the start ptr to null, there was an
// error.
if (Filename.empty())
- return;
+ return llvm::None;
// Search include directories for this file.
const DirectoryLookup *CurDir;
- Optional<FileEntryRef> File =
- LookupFile(FilenameTok.getLocation(), Filename, isAngled, nullptr,
- nullptr, CurDir, nullptr, nullptr, nullptr, nullptr, nullptr);
+ File = PP.LookupFile(FilenameTok.getLocation(), Filename, isAngled, nullptr,
+ nullptr, CurDir, nullptr, nullptr, nullptr, nullptr,
+ nullptr);
if (!File) {
if (!SuppressIncludeNotFoundError)
- Diag(FilenameTok, diag::err_pp_file_not_found) << Filename;
+ PP.Diag(FilenameTok, diag::err_pp_file_not_found) << Filename;
+ return llvm::None;
+ }
+
+ return FilenameTok;
+}
+
+/// HandlePragmaIncludeInstead - Handle \#pragma clang include_instead(header).
+void Preprocessor::HandlePragmaIncludeInstead(Token &Tok) {
+ // Get the current file lexer we're looking at. Ignore _Pragma 'files' etc.
+ PreprocessorLexer *TheLexer = getCurrentFileLexer();
+
+ if (!SourceMgr.isInSystemHeader(Tok.getLocation())) {
+ Diag(Tok, diag::err_pragma_include_instead_not_sysheader);
+ return;
+ }
+
+ Lex(Tok);
+ if (Tok.isNot(tok::l_paren)) {
+ Diag(Tok, diag::err_expected) << "(";
return;
}
+ Optional<FileEntryRef> File;
+ llvm::Optional<Token> FilenameTok =
+ LexHeader(*this, File, SuppressIncludeNotFoundError);
+ if (!FilenameTok)
+ return;
+
+ Lex(Tok);
+ if (Tok.isNot(tok::r_paren)) {
+ Diag(Tok, diag::err_expected) << ")";
+ return;
+ }
+
+ SmallString<128> FilenameBuffer;
+ StringRef Filename = getSpelling(*FilenameTok, FilenameBuffer);
+ HeaderInfo.AddFileAlias(TheLexer->getFileEntry(), Filename);
+}
+
+/// HandlePragmaDependency - Handle \#pragma GCC dependency "foo" blah.
+void Preprocessor::HandlePragmaDependency(Token &DependencyTok) {
+ Optional<FileEntryRef> File;
+ llvm::Optional<Token> FilenameTok =
+ LexHeader(*this, File, SuppressIncludeNotFoundError);
+ if (!FilenameTok)
+ return;
+
const FileEntry *CurFile = getCurrentFileLexer()->getFileEntry();
// If this file is older than the file it depends on, emit a diagnostic.
@@ -547,7 +594,7 @@ void Preprocessor::HandlePragmaDependency(Token &DependencyTok) {
// Remove the trailing ' ' if present.
if (!Message.empty())
Message.erase(Message.end()-1);
- Diag(FilenameTok, diag::pp_out_of_date_dependency) << Message;
+ Diag(*FilenameTok, diag::pp_out_of_date_dependency) << Message;
}
}
@@ -1022,6 +1069,18 @@ struct PragmaSystemHeaderHandler : public PragmaHandler {
}
};
+/// PragmaIncludeInsteadHandler - "\#pragma clang include_instead(header)" marks
+/// the current file as non-includable if the including header is not a system
+/// header.
+struct PragmaIncludeInsteadHandler : public PragmaHandler {
+ PragmaIncludeInsteadHandler() : PragmaHandler("include_instead") {}
+
+ void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
+ Token &IIToken) override {
+ PP.HandlePragmaIncludeInstead(IIToken);
+ }
+};
+
struct PragmaDependencyHandler : public PragmaHandler {
PragmaDependencyHandler() : PragmaHandler("dependency") {}
@@ -1934,6 +1993,7 @@ void Preprocessor::RegisterBuiltinPragmas() {
// #pragma clang ...
AddPragmaHandler("clang", new PragmaPoisonHandler());
AddPragmaHandler("clang", new PragmaSystemHeaderHandler());
+ AddPragmaHandler("clang", new PragmaIncludeInsteadHandler());
AddPragmaHandler("clang", new PragmaDebugHandler());
AddPragmaHandler("clang", new PragmaDependencyHandler());
AddPragmaHandler("clang", new PragmaDiagnosticHandler("clang"));
diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp
index 32ea8791d29a..e376fff90432 100644
--- a/clang/lib/Lex/Preprocessor.cpp
+++ b/clang/lib/Lex/Preprocessor.cpp
@@ -716,12 +716,6 @@ IdentifierInfo *Preprocessor::LookUpIdentifierInfo(Token &Identifier) const {
}
// Update the token info (identifier info and appropriate token kind).
- // FIXME: the raw_identifier may contain leading whitespace which is removed
- // from the cleaned identifier token. The SourceLocation should be updated to
- // refer to the non-whitespace character. For instance, the text "\\\nB" (a
- // line continuation before 'B') is parsed as a single tok::raw_identifier and
- // is cleaned to tok::identifier "B". After cleaning the token's length is
- // still 3 and the SourceLocation refers to the location of the backslash.
Identifier.setIdentifierInfo(II);
if (getLangOpts().MSVCCompat && II->isCPlusPlusOperatorKeyword() &&
getSourceManager().isInSystemHeader(Identifier.getLocation()))
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index f4f5f461e3b6..939323517b4d 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -3952,8 +3952,12 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
Tok.getIdentifierInfo()->revertTokenIDToIdentifier();
Tok.setKind(tok::identifier);
goto DoneWithDeclSpec;
- }
- isInvalid = DS.SetTypePipe(true, Loc, PrevSpec, DiagID, Policy);
+ } else if (!getLangOpts().OpenCLPipes) {
+ DiagID = diag::err_opencl_unknown_type_specifier;
+ PrevSpec = Tok.getIdentifierInfo()->getNameStart();
+ isInvalid = true;
+ } else
+ isInvalid = DS.SetTypePipe(true, Loc, PrevSpec, DiagID, Policy);
break;
// We only need to enumerate each image type once.
#define IMAGE_READ_WRITE_TYPE(Type, Id, Ext)
@@ -5126,8 +5130,10 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
switch (Tok.getKind()) {
default: return false;
+ // OpenCL 2.0 and later define this keyword.
case tok::kw_pipe:
- return getLangOpts().OpenCLPipe;
+ return (getLangOpts().OpenCL && getLangOpts().OpenCLVersion >= 200) ||
+ getLangOpts().OpenCLCPlusPlus;
case tok::identifier: // foo::bar
// Unfortunate hack to support "Class.factoryMethod" notation.
@@ -5656,7 +5662,9 @@ static bool isPtrOperatorToken(tok::TokenKind Kind, const LangOptions &Lang,
if (Kind == tok::star || Kind == tok::caret)
return true;
- if (Kind == tok::kw_pipe && Lang.OpenCLPipe)
+ // OpenCL 2.0 and later define this keyword.
+ if (Kind == tok::kw_pipe &&
+ ((Lang.OpenCL && Lang.OpenCLVersion >= 200) || Lang.OpenCLCPlusPlus))
return true;
if (!Lang.CPlusPlus)
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index 5d3de06e9576..a54bd8719178 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -327,7 +327,8 @@ void Sema::Initialize() {
if (getLangOpts().OpenCLCPlusPlus || getLangOpts().OpenCLVersion >= 200) {
addImplicitTypedef("clk_event_t", Context.OCLClkEventTy);
addImplicitTypedef("queue_t", Context.OCLQueueTy);
- addImplicitTypedef("reserve_id_t", Context.OCLReserveIDTy);
+ if (getLangOpts().OpenCLPipes)
+ addImplicitTypedef("reserve_id_t", Context.OCLReserveIDTy);
addImplicitTypedef("atomic_int", Context.getAtomicType(Context.IntTy));
addImplicitTypedef("atomic_uint",
Context.getAtomicType(Context.UnsignedIntTy));
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index b78331cdfe91..bca21b351c91 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -1525,18 +1525,20 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
break;
case DeclSpec::TST_float: Result = Context.FloatTy; break;
case DeclSpec::TST_double:
+ if (DS.getTypeSpecWidth() == TypeSpecifierWidth::Long)
+ Result = Context.LongDoubleTy;
+ else
+ Result = Context.DoubleTy;
if (S.getLangOpts().OpenCL) {
if (!S.getOpenCLOptions().isSupported("cl_khr_fp64", S.getLangOpts()))
- S.Diag(DS.getTypeSpecTypeLoc(),
- diag::err_opencl_double_requires_extension)
- << (S.getLangOpts().OpenCLVersion >= 300);
+ S.Diag(DS.getTypeSpecTypeLoc(), diag::err_opencl_requires_extension)
+ << 0 << Result
+ << (S.getLangOpts().OpenCLVersion == 300
+ ? "cl_khr_fp64 and __opencl_c_fp64"
+ : "cl_khr_fp64");
else if (!S.getOpenCLOptions().isAvailableOption("cl_khr_fp64", S.getLangOpts()))
S.Diag(DS.getTypeSpecTypeLoc(), diag::ext_opencl_double_without_pragma);
}
- if (DS.getTypeSpecWidth() == TypeSpecifierWidth::Long)
- Result = Context.LongDoubleTy;
- else
- Result = Context.DoubleTy;
break;
case DeclSpec::TST_float128:
if (!S.Context.getTargetInfo().hasFloat128Type() &&
@@ -1724,21 +1726,28 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
if (S.getLangOpts().OpenCL) {
const auto &OpenCLOptions = S.getOpenCLOptions();
- StringRef OptName;
+ bool IsOpenCLC30 = (S.getLangOpts().OpenCLVersion == 300);
// OpenCL C v3.0 s6.3.3 - OpenCL image types require __opencl_c_images
- // support
+ // support.
+ // OpenCL C v3.0 s6.2.1 - OpenCL 3d image write types requires support
+ // for OpenCL C 2.0, or OpenCL C 3.0 or newer and the
+ // __opencl_c_3d_image_writes feature. OpenCL C v3.0 API s4.2 - For devices
+ // that support OpenCL 3.0, cl_khr_3d_image_writes must be returned when and
+ // only when the optional feature is supported
if ((Result->isImageType() || Result->isSamplerT()) &&
- (S.getLangOpts().OpenCLVersion >= 300 &&
- !OpenCLOptions.isSupported("__opencl_c_images", S.getLangOpts())))
- OptName = "__opencl_c_images";
- else if (Result->isOCLImage3dWOType() &&
- !OpenCLOptions.isSupported("cl_khr_3d_image_writes",
- S.getLangOpts()))
- OptName = "cl_khr_3d_image_writes";
-
- if (!OptName.empty()) {
+ (IsOpenCLC30 &&
+ !OpenCLOptions.isSupported("__opencl_c_images", S.getLangOpts()))) {
+ S.Diag(DS.getTypeSpecTypeLoc(), diag::err_opencl_requires_extension)
+ << 0 << Result << "__opencl_c_images";
+ declarator.setInvalidType();
+ } else if (Result->isOCLImage3dWOType() &&
+ !OpenCLOptions.isSupported("cl_khr_3d_image_writes",
+ S.getLangOpts())) {
S.Diag(DS.getTypeSpecTypeLoc(), diag::err_opencl_requires_extension)
- << 0 << Result << OptName;
+ << 0 << Result
+ << (IsOpenCLC30
+ ? "cl_khr_3d_image_writes and __opencl_c_3d_image_writes"
+ : "cl_khr_3d_image_writes");
declarator.setInvalidType();
}
}