aboutsummaryrefslogtreecommitdiff
path: root/clang
diff options
context:
space:
mode:
Diffstat (limited to 'clang')
-rw-r--r--clang/include/clang/APINotes/Types.h2
-rw-r--r--clang/include/clang/AST/ASTContext.h42
-rw-r--r--clang/include/clang/AST/ASTImportError.h1
-rw-r--r--clang/include/clang/AST/DeclTemplate.h13
-rw-r--r--clang/include/clang/AST/PropertiesBase.td10
-rw-r--r--clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h28
-rw-r--r--clang/include/clang/Analysis/FlowSensitive/DebugSupport.h63
-rw-r--r--clang/include/clang/Analysis/FlowSensitive/Solver.h62
-rw-r--r--clang/include/clang/Analysis/SelectorExtras.h2
-rw-r--r--clang/include/clang/Basic/AlignedAllocation.h4
-rw-r--r--clang/include/clang/Basic/Attr.td11
-rw-r--r--clang/include/clang/Basic/AttrDocs.td47
-rw-r--r--clang/include/clang/Basic/BuiltinsX86.def1
-rw-r--r--clang/include/clang/Basic/CodeGenOptions.def1
-rw-r--r--clang/include/clang/Basic/CodeGenOptions.h3
-rw-r--r--clang/include/clang/Basic/DiagnosticDriverKinds.td2
-rw-r--r--clang/include/clang/Basic/DiagnosticGroups.td4
-rw-r--r--clang/include/clang/Basic/DiagnosticLexKinds.td11
-rw-r--r--clang/include/clang/Basic/DiagnosticSemaKinds.td34
-rw-r--r--clang/include/clang/Basic/MakeSupport.h23
-rw-r--r--clang/include/clang/Basic/TargetInfo.h6
-rw-r--r--clang/include/clang/Basic/riscv_vector.td99
-rw-r--r--clang/include/clang/Driver/Options.td27
-rw-r--r--clang/include/clang/Frontend/FrontendActions.h4
-rw-r--r--clang/include/clang/Lex/Preprocessor.h63
-rw-r--r--clang/include/clang/Sema/HLSLExternalSemaSource.h41
-rw-r--r--clang/include/clang/Sema/Sema.h45
-rw-r--r--clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h5
-rw-r--r--clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h12
-rw-r--r--clang/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConstraintManager.h2
-rw-r--r--clang/include/clang/Support/RISCVVIntrinsicUtils.h6
-rw-r--r--clang/include/clang/Tooling/DependencyScanning/DependencyScanningFilesystem.h4
-rw-r--r--clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h12
-rw-r--r--clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h31
-rw-r--r--clang/lib/AST/ASTContext.cpp169
-rw-r--r--clang/lib/AST/ASTImporter.cpp10
-rw-r--r--clang/lib/AST/AttrImpl.cpp6
-rw-r--r--clang/lib/AST/DeclPrinter.cpp6
-rw-r--r--clang/lib/AST/FormatString.cpp6
-rw-r--r--clang/lib/AST/Interp/ByteCodeExprGen.cpp2
-rw-r--r--clang/lib/Analysis/BodyFarm.cpp4
-rw-r--r--clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp2
-rw-r--r--clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp8
-rw-r--r--clang/lib/Analysis/FlowSensitive/DebugSupport.cpp197
-rw-r--r--clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp6
-rw-r--r--clang/lib/Analysis/FlowSensitive/WatchedLiteralsSolver.cpp66
-rw-r--r--clang/lib/Analysis/PathDiagnostic.cpp4
-rw-r--r--clang/lib/Analysis/UninitializedValues.cpp4
-rw-r--r--clang/lib/Basic/LangStandards.cpp4
-rw-r--r--clang/lib/Basic/MakeSupport.cpp35
-rw-r--r--clang/lib/Basic/TargetInfo.cpp2
-rw-r--r--clang/lib/Basic/Targets/RISCV.cpp2
-rw-r--r--clang/lib/Basic/Targets/SystemZ.h8
-rw-r--r--clang/lib/Basic/Targets/X86.cpp6
-rw-r--r--clang/lib/Basic/Targets/X86.h7
-rw-r--r--clang/lib/CodeGen/BackendUtil.cpp12
-rw-r--r--clang/lib/CodeGen/CGCUDANV.cpp11
-rw-r--r--clang/lib/CodeGen/CGCall.cpp3
-rw-r--r--clang/lib/CodeGen/CGClass.cpp4
-rw-r--r--clang/lib/CodeGen/CGOpenMPRuntime.cpp140
-rw-r--r--clang/lib/CodeGen/CGOpenMPRuntime.h10
-rw-r--r--clang/lib/CodeGen/CGStmtOpenMP.cpp48
-rw-r--r--clang/lib/CodeGen/CodeGenFunction.cpp14
-rw-r--r--clang/lib/CodeGen/CodeGenModule.cpp10
-rw-r--r--clang/lib/CodeGen/CodeGenModule.h19
-rw-r--r--clang/lib/CodeGen/CodeGenTBAA.cpp37
-rw-r--r--clang/lib/CodeGen/SanitizerMetadata.cpp18
-rw-r--r--clang/lib/Driver/Driver.cpp39
-rw-r--r--clang/lib/Driver/ToolChains/AVR.cpp8
-rw-r--r--clang/lib/Driver/ToolChains/Clang.cpp234
-rw-r--r--clang/lib/Driver/ToolChains/CommonArgs.cpp3
-rw-r--r--clang/lib/Driver/ToolChains/Darwin.cpp14
-rw-r--r--clang/lib/Driver/ToolChains/Gnu.cpp2
-rw-r--r--clang/lib/Driver/ToolChains/Hexagon.cpp4
-rw-r--r--clang/lib/Driver/ToolChains/MinGW.cpp28
-rw-r--r--clang/lib/Driver/ToolChains/MinGW.h1
-rw-r--r--clang/lib/Driver/ToolChains/RISCVToolchain.cpp7
-rw-r--r--clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp4
-rw-r--r--clang/lib/Format/ContinuationIndenter.cpp6
-rw-r--r--clang/lib/Format/ContinuationIndenter.h2
-rw-r--r--clang/lib/Format/Format.cpp31
-rw-r--r--clang/lib/Format/FormatToken.cpp2
-rw-r--r--clang/lib/Format/FormatToken.h9
-rw-r--r--clang/lib/Format/MacroCallReconstructor.cpp573
-rw-r--r--clang/lib/Format/Macros.h279
-rw-r--r--clang/lib/Format/TokenAnnotator.cpp8
-rw-r--r--clang/lib/Format/UnwrappedLineFormatter.cpp15
-rw-r--r--clang/lib/Format/UnwrappedLineParser.cpp16
-rw-r--r--clang/lib/Format/UnwrappedLineParser.h3
-rw-r--r--clang/lib/Frontend/CompilerInstance.cpp21
-rw-r--r--clang/lib/Frontend/CompilerInvocation.cpp28
-rw-r--r--clang/lib/Frontend/FrontendAction.cpp9
-rw-r--r--clang/lib/Frontend/FrontendActions.cpp3
-rw-r--r--clang/lib/Frontend/InitPreprocessor.cpp4
-rw-r--r--clang/lib/Headers/hlsl/hlsl_basic_types.h54
-rw-r--r--clang/lib/Headers/opencl-c.h18
-rw-r--r--clang/lib/Headers/rdpruintrin.h57
-rw-r--r--clang/lib/Headers/stdatomic.h4
-rw-r--r--clang/lib/Headers/x86intrin.h4
-rw-r--r--clang/lib/Lex/DependencyDirectivesScanner.cpp2
-rw-r--r--clang/lib/Lex/Lexer.cpp117
-rw-r--r--clang/lib/Lex/LiteralSupport.cpp10
-rw-r--r--clang/lib/Lex/MacroInfo.cpp2
-rw-r--r--clang/lib/Lex/ModuleMap.cpp4
-rw-r--r--clang/lib/Lex/PPDirectives.cpp90
-rw-r--r--clang/lib/Lex/PPMacroExpansion.cpp4
-rw-r--r--clang/lib/Lex/PreprocessingRecord.cpp2
-rw-r--r--clang/lib/Lex/Preprocessor.cpp14
-rw-r--r--clang/lib/Parse/ParseOpenMP.cpp18
-rw-r--r--clang/lib/Parse/Parser.cpp18
-rw-r--r--clang/lib/Sema/HLSLExternalSemaSource.cpp96
-rw-r--r--clang/lib/Sema/SemaCUDA.cpp13
-rw-r--r--clang/lib/Sema/SemaChecking.cpp403
-rw-r--r--clang/lib/Sema/SemaCodeComplete.cpp4
-rw-r--r--clang/lib/Sema/SemaDecl.cpp72
-rw-r--r--clang/lib/Sema/SemaDeclAttr.cpp46
-rw-r--r--clang/lib/Sema/SemaExpr.cpp48
-rw-r--r--clang/lib/Sema/SemaExprCXX.cpp35
-rw-r--r--clang/lib/Sema/SemaModule.cpp13
-rw-r--r--clang/lib/Sema/SemaOpenMP.cpp79
-rw-r--r--clang/lib/Sema/SemaTemplate.cpp65
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiateDecl.cpp9
-rw-r--r--clang/lib/Serialization/ASTReader.cpp16
-rw-r--r--clang/lib/Serialization/ASTWriter.cpp13
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp4
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp9
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp4
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp3
-rw-r--r--clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp6
-rw-r--r--clang/lib/StaticAnalyzer/Core/BugReporter.cpp6
-rw-r--r--clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp8
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp4
-rw-r--r--clang/lib/StaticAnalyzer/Core/SValBuilder.cpp6
-rw-r--r--clang/lib/Support/RISCVVIntrinsicUtils.cpp4
-rw-r--r--clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp19
-rw-r--r--clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp45
-rw-r--r--clang/tools/clang-format/ClangFormat.cpp16
-rw-r--r--clang/tools/driver/driver.cpp4
-rw-r--r--clang/utils/TableGen/RISCVVEmitter.cpp22
141 files changed, 3406 insertions, 1042 deletions
diff --git a/clang/include/clang/APINotes/Types.h b/clang/include/clang/APINotes/Types.h
index d79586931995..0e5b43080e4b 100644
--- a/clang/include/clang/APINotes/Types.h
+++ b/clang/include/clang/APINotes/Types.h
@@ -76,7 +76,7 @@ public:
}
void setSwiftPrivate(llvm::Optional<bool> Private) {
- SwiftPrivateSpecified = Private.hasValue();
+ SwiftPrivateSpecified = Private.has_value();
SwiftPrivate = Private ? *Private : 0;
}
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index 7db6af9cb87d..85eba45e4de6 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -130,6 +130,7 @@ class TemplateDecl;
class TemplateParameterList;
class TemplateTemplateParmDecl;
class TemplateTypeParmDecl;
+class TypeConstraint;
class UnresolvedSetIterator;
class UsingShadowDecl;
class VarTemplateDecl;
@@ -260,7 +261,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
mutable llvm::FoldingSet<DeducedTemplateSpecializationType>
DeducedTemplateSpecializationTypes;
mutable llvm::FoldingSet<AtomicType> AtomicTypes;
- llvm::FoldingSet<AttributedType> AttributedTypes;
+ mutable llvm::FoldingSet<AttributedType> AttributedTypes;
mutable llvm::FoldingSet<PipeType> PipeTypes;
mutable llvm::FoldingSet<BitIntType> BitIntTypes;
mutable llvm::FoldingSet<DependentBitIntType> DependentBitIntTypes;
@@ -1306,11 +1307,11 @@ public:
/// declaration of a function with an exception specification is permitted
/// and preserved. Other type sugar (for instance, typedefs) is not.
QualType getFunctionTypeWithExceptionSpec(
- QualType Orig, const FunctionProtoType::ExceptionSpecInfo &ESI);
+ QualType Orig, const FunctionProtoType::ExceptionSpecInfo &ESI) const;
/// Determine whether two function types are the same, ignoring
/// exception specifications in cases where they're part of the type.
- bool hasSameFunctionTypeIgnoringExceptionSpec(QualType T, QualType U);
+ bool hasSameFunctionTypeIgnoringExceptionSpec(QualType T, QualType U) const;
/// Change the exception specification on a function once it is
/// delay-parsed, instantiated, or computed.
@@ -1597,9 +1598,8 @@ public:
QualType getInjectedClassNameType(CXXRecordDecl *Decl, QualType TST) const;
- QualType getAttributedType(attr::Kind attrKind,
- QualType modifiedType,
- QualType equivalentType);
+ QualType getAttributedType(attr::Kind attrKind, QualType modifiedType,
+ QualType equivalentType) const;
QualType getBTFTagAttributedType(const BTFTypeTagAttr *BTFAttr,
QualType Wrapped);
@@ -2654,25 +2654,33 @@ public:
bool hasSameTemplateName(const TemplateName &X, const TemplateName &Y) const;
/// Determine whether the two declarations refer to the same entity.
- ///
- /// FIXME: isSameEntity is not const due to its implementation calls
- /// hasSameFunctionTypeIgnoringExceptionSpec which may alter this.
- bool isSameEntity(const NamedDecl *X, const NamedDecl *Y);
+ bool isSameEntity(const NamedDecl *X, const NamedDecl *Y) const;
/// Determine whether two template parameter lists are similar enough
/// that they may be used in declarations of the same template.
- ///
- /// FIXME: isSameTemplateParameterList is not const since it calls
- /// isSameTemplateParameter.
bool isSameTemplateParameterList(const TemplateParameterList *X,
- const TemplateParameterList *Y);
+ const TemplateParameterList *Y) const;
/// Determine whether two template parameters are similar enough
/// that they may be used in declarations of the same template.
+ bool isSameTemplateParameter(const NamedDecl *X, const NamedDecl *Y) const;
+
+ /// Determine whether two 'requires' expressions are similar enough that they
+ /// may be used in re-declarations.
///
- /// FIXME: isSameTemplateParameterList is not const since it calls
- /// isSameEntity.
- bool isSameTemplateParameter(const NamedDecl *X, const NamedDecl *Y);
+ /// Use of 'requires' isn't mandatory, works with constraints expressed in
+ /// other ways too.
+ bool isSameConstraintExpr(const Expr *XCE, const Expr *YCE) const;
+
+ /// Determine whether two type contraint are similar enough that they could
+ /// used in declarations of the same template.
+ bool isSameTypeConstraint(const TypeConstraint *XTC,
+ const TypeConstraint *YTC) const;
+
+ /// Determine whether two default template arguments are similar enough
+ /// that they may be used in declarations of the same template.
+ bool isSameDefaultTemplateArgument(const NamedDecl *X,
+ const NamedDecl *Y) const;
/// Retrieve the "canonical" template argument.
///
diff --git a/clang/include/clang/AST/ASTImportError.h b/clang/include/clang/AST/ASTImportError.h
index 405790b6ded3..728314ca0936 100644
--- a/clang/include/clang/AST/ASTImportError.h
+++ b/clang/include/clang/AST/ASTImportError.h
@@ -19,7 +19,6 @@
namespace clang {
class ASTImportError : public llvm::ErrorInfo<ASTImportError> {
-
public:
/// \brief Kind of error when importing an AST component.
enum ErrorKind {
diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h
index 3e4ccda73111..725bb0bced9c 100644
--- a/clang/include/clang/AST/DeclTemplate.h
+++ b/clang/include/clang/AST/DeclTemplate.h
@@ -15,6 +15,7 @@
#define LLVM_CLANG_AST_DECLTEMPLATE_H
#include "clang/AST/ASTConcept.h"
+#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclCXX.h"
@@ -373,11 +374,19 @@ public:
/// Set that the default argument was inherited from another parameter.
void setInherited(const ASTContext &C, ParmDecl *InheritedFrom) {
- assert(!isInherited() && "default argument already inherited");
InheritedFrom = getParmOwningDefaultArg(InheritedFrom);
if (!isSet())
ValueOrInherited = InheritedFrom;
- else
+ else if (auto *D = ValueOrInherited.template dyn_cast<ParmDecl *>()) {
+ assert(C.isSameDefaultTemplateArgument(D, InheritedFrom));
+ ValueOrInherited =
+ new (allocateDefaultArgStorageChain(C)) Chain{InheritedFrom, get()};
+ } else if (auto *Inherited =
+ ValueOrInherited.template dyn_cast<Chain *>()) {
+ assert(C.isSameDefaultTemplateArgument(Inherited->PrevDeclWithDefaultArg,
+ InheritedFrom));
+ Inherited->PrevDeclWithDefaultArg = InheritedFrom;
+ } else
ValueOrInherited = new (allocateDefaultArgStorageChain(C))
Chain{InheritedFrom, ValueOrInherited.template get<ArgType>()};
}
diff --git a/clang/include/clang/AST/PropertiesBase.td b/clang/include/clang/AST/PropertiesBase.td
index 559f29edcf0f..ec310a459927 100644
--- a/clang/include/clang/AST/PropertiesBase.td
+++ b/clang/include/clang/AST/PropertiesBase.td
@@ -520,15 +520,15 @@ let Class = PropertyTypeCase<APValue, "LValue"> in {
if (hasBase) {
if (isTypeInfo) {
base = APValue::LValueBase::getTypeInfo(
- TypeInfoLValue(typeInfo.getValue().getTypePtr()), type.getValue());
+ TypeInfoLValue(typeInfo.value().getTypePtr()), type.value());
elemTy = base.getTypeInfoType();
} else if (isExpr) {
- base = APValue::LValueBase(cast<Expr>(stmt.getValue()),
- callIndex.getValue(), version.getValue());
+ base = APValue::LValueBase(cast<Expr>(stmt.value()),
+ callIndex.value(), version.value());
elemTy = base.get<const Expr *>()->getType();
} else {
- base = APValue::LValueBase(cast<ValueDecl>(decl.getValue()),
- callIndex.getValue(), version.getValue());
+ base = APValue::LValueBase(cast<ValueDecl>(decl.value()),
+ callIndex.value(), version.value());
elemTy = base.get<const ValueDecl *>()->getType();
}
}
diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h
index c1100d8474aa..358ace0430f6 100644
--- a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h
+++ b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h
@@ -155,6 +155,7 @@ public:
/// Returns a pointer value that represents a null pointer. Calls with
/// `PointeeType` that are canonically equivalent will return the same result.
+ /// A null `PointeeType` can be used for the pointee of `std::nullptr_t`.
PointerValue &getOrCreateNullPointerValue(QualType PointeeType);
/// Returns a symbolic boolean value that models a boolean literal equal to
@@ -251,6 +252,17 @@ public:
bool equivalentBoolValues(BoolValue &Val1, BoolValue &Val2);
private:
+ struct NullableQualTypeDenseMapInfo : private llvm::DenseMapInfo<QualType> {
+ static QualType getEmptyKey() {
+ // Allow a NULL `QualType` by using a different value as the empty key.
+ return QualType::getFromOpaquePtr(reinterpret_cast<Type *>(1));
+ }
+
+ using DenseMapInfo::getHashValue;
+ using DenseMapInfo::getTombstoneKey;
+ using DenseMapInfo::isEqual;
+ };
+
/// Adds all constraints of the flow condition identified by `Token` and all
/// of its transitive dependencies to `Constraints`. `VisitedTokens` is used
/// to track tokens of flow conditions that were already visited by recursive
@@ -259,17 +271,18 @@ private:
AtomicBoolValue &Token, llvm::DenseSet<BoolValue *> &Constraints,
llvm::DenseSet<AtomicBoolValue *> &VisitedTokens);
- /// Returns the result of satisfiability checking on `Constraints`.
- /// Possible return values are:
- /// - `Satisfiable`: There exists a satisfying assignment for `Constraints`.
- /// - `Unsatisfiable`: There is no satisfying assignment for `Constraints`.
- /// - `TimedOut`: The solver gives up on finding a satisfying assignment.
+ /// Returns the outcome of satisfiability checking on `Constraints`.
+ /// Possible outcomes are:
+ /// - `Satisfiable`: A satisfying assignment exists and is returned.
+ /// - `Unsatisfiable`: A satisfying assignment does not exist.
+ /// - `TimedOut`: The search for a satisfying assignment was not completed.
Solver::Result querySolver(llvm::DenseSet<BoolValue *> Constraints);
/// Returns true if the solver is able to prove that there is no satisfying
/// assignment for `Constraints`
bool isUnsatisfiable(llvm::DenseSet<BoolValue *> Constraints) {
- return querySolver(std::move(Constraints)) == Solver::Result::Unsatisfiable;
+ return querySolver(std::move(Constraints)).getStatus() ==
+ Solver::Result::Status::Unsatisfiable;
}
/// Returns a boolean value as a result of substituting `Val` and its sub
@@ -311,7 +324,8 @@ private:
// required to initialize the `PointeeLoc` field in `PointerValue`. Consider
// creating a type-independent `NullPointerValue` without a `PointeeLoc`
// field.
- llvm::DenseMap<QualType, PointerValue *> NullPointerVals;
+ llvm::DenseMap<QualType, PointerValue *, NullableQualTypeDenseMapInfo>
+ NullPointerVals;
AtomicBoolValue &TrueVal;
AtomicBoolValue &FalseVal;
diff --git a/clang/include/clang/Analysis/FlowSensitive/DebugSupport.h b/clang/include/clang/Analysis/FlowSensitive/DebugSupport.h
new file mode 100644
index 000000000000..ef903d807e12
--- /dev/null
+++ b/clang/include/clang/Analysis/FlowSensitive/DebugSupport.h
@@ -0,0 +1,63 @@
+//===-- DebugSupport.h ------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines functions which generate more readable forms of data
+// structures used in the dataflow analyses, for debugging purposes.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DEBUGSUPPORT_H_
+#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DEBUGSUPPORT_H_
+
+#include <string>
+#include <vector>
+
+#include "clang/Analysis/FlowSensitive/Solver.h"
+#include "clang/Analysis/FlowSensitive/Value.h"
+#include "llvm/ADT/DenseMap.h"
+
+namespace clang {
+namespace dataflow {
+/// Returns a string representation for the boolean value `B`.
+///
+/// Atomic booleans appearing in the boolean value `B` are assigned to labels
+/// either specified in `AtomNames` or created by default rules as B0, B1, ...
+///
+/// Requirements:
+///
+/// Names assigned to atoms should not be repeated in `AtomNames`.
+std::string debugString(
+ const BoolValue &B,
+ llvm::DenseMap<const AtomicBoolValue *, std::string> AtomNames = {{}});
+
+/// Returns a string representation for `Constraints` - a collection of boolean
+/// formulas and the `Result` of satisfiability checking.
+///
+/// Atomic booleans appearing in `Constraints` and `Result` are assigned to
+/// labels either specified in `AtomNames` or created by default rules as B0,
+/// B1, ...
+///
+/// Requirements:
+///
+/// Names assigned to atoms should not be repeated in `AtomNames`.
+std::string debugString(
+ const std::vector<BoolValue *> &Constraints, const Solver::Result &Result,
+ llvm::DenseMap<const AtomicBoolValue *, std::string> AtomNames = {{}});
+inline std::string debugString(
+ const llvm::DenseSet<BoolValue *> &Constraints,
+ const Solver::Result &Result,
+ llvm::DenseMap<const AtomicBoolValue *, std::string> AtomNames = {{}}) {
+ std::vector<BoolValue *> ConstraintsVec(Constraints.begin(),
+ Constraints.end());
+ return debugString(ConstraintsVec, Result, std::move(AtomNames));
+}
+
+} // namespace dataflow
+} // namespace clang
+
+#endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DEBUGSUPPORT_H_
diff --git a/clang/include/clang/Analysis/FlowSensitive/Solver.h b/clang/include/clang/Analysis/FlowSensitive/Solver.h
index 6b685b9b3c9a..93568b119793 100644
--- a/clang/include/clang/Analysis/FlowSensitive/Solver.h
+++ b/clang/include/clang/Analysis/FlowSensitive/Solver.h
@@ -15,7 +15,9 @@
#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_SOLVER_H
#include "clang/Analysis/FlowSensitive/Value.h"
+#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/Optional.h"
namespace clang {
namespace dataflow {
@@ -23,17 +25,58 @@ namespace dataflow {
/// An interface for a SAT solver that can be used by dataflow analyses.
class Solver {
public:
- enum class Result {
- /// Indicates that there exists a satisfying assignment for a boolean
+ struct Result {
+ enum class Status {
+ /// Indicates that there exists a satisfying assignment for a boolean
+ /// formula.
+ Satisfiable,
+
+ /// Indicates that there is no satisfying assignment for a boolean
+ /// formula.
+ Unsatisfiable,
+
+ /// Indicates that the solver gave up trying to find a satisfying
+ /// assignment for a boolean formula.
+ TimedOut,
+ };
+
+ /// A boolean value is set to true or false in a truth assignment.
+ enum class Assignment : uint8_t { AssignedFalse = 0, AssignedTrue = 1 };
+
+ /// Constructs a result indicating that the queried boolean formula is
+ /// satisfiable. The result will hold a solution found by the solver.
+ static Result
+ Satisfiable(llvm::DenseMap<AtomicBoolValue *, Assignment> Solution) {
+ return Result(Status::Satisfiable, std::move(Solution));
+ }
+
+ /// Constructs a result indicating that the queried boolean formula is
+ /// unsatisfiable.
+ static Result Unsatisfiable() { return Result(Status::Unsatisfiable, {}); }
+
+ /// Constructs a result indicating that satisfiability checking on the
+ /// queried boolean formula was not completed.
+ static Result TimedOut() { return Result(Status::TimedOut, {}); }
+
+ /// Returns the status of satisfiability checking on the queried boolean
/// formula.
- Satisfiable,
+ Status getStatus() const { return SATCheckStatus; }
- /// Indicates that there is no satisfying assignment for a boolean formula.
- Unsatisfiable,
+ /// Returns a truth assignment to boolean values that satisfies the queried
+ /// boolean formula if available. Otherwise, an empty optional is returned.
+ llvm::Optional<llvm::DenseMap<AtomicBoolValue *, Assignment>>
+ getSolution() const {
+ return Solution;
+ }
- /// Indicates that the solver gave up trying to find a satisfying assignment
- /// for a boolean formula.
- TimedOut,
+ private:
+ Result(
+ enum Status SATCheckStatus,
+ llvm::Optional<llvm::DenseMap<AtomicBoolValue *, Assignment>> Solution)
+ : SATCheckStatus(SATCheckStatus), Solution(std::move(Solution)) {}
+
+ Status SATCheckStatus;
+ llvm::Optional<llvm::DenseMap<AtomicBoolValue *, Assignment>> Solution;
};
virtual ~Solver() = default;
@@ -44,9 +87,6 @@ public:
/// Requirements:
///
/// All elements in `Vals` must not be null.
- ///
- /// FIXME: Consider returning a model in case the conjunction of `Vals` is
- /// satisfiable so that it can be used to generate warning messages.
virtual Result solve(llvm::DenseSet<BoolValue *> Vals) = 0;
};
diff --git a/clang/include/clang/Analysis/SelectorExtras.h b/clang/include/clang/Analysis/SelectorExtras.h
index 278f20e87cc6..1e1daf5706bb 100644
--- a/clang/include/clang/Analysis/SelectorExtras.h
+++ b/clang/include/clang/Analysis/SelectorExtras.h
@@ -16,7 +16,7 @@ namespace clang {
template <typename... IdentifierInfos>
static inline Selector getKeywordSelector(ASTContext &Ctx,
IdentifierInfos *... IIs) {
- static_assert(sizeof...(IdentifierInfos),
+ static_assert(sizeof...(IdentifierInfos) > 0,
"keyword selectors must have at least one argument");
SmallVector<IdentifierInfo *, 10> II({&Ctx.Idents.get(IIs)...});
diff --git a/clang/include/clang/Basic/AlignedAllocation.h b/clang/include/clang/Basic/AlignedAllocation.h
index c1187b81420b..949e54c8c030 100644
--- a/clang/include/clang/Basic/AlignedAllocation.h
+++ b/clang/include/clang/Basic/AlignedAllocation.h
@@ -26,8 +26,8 @@ inline llvm::VersionTuple alignedAllocMinVersion(llvm::Triple::OSType OS) {
default:
break;
case llvm::Triple::Darwin:
- case llvm::Triple::MacOSX: // Earliest supporting version is 10.14.
- return llvm::VersionTuple(10U, 14U);
+ case llvm::Triple::MacOSX: // Earliest supporting version is 10.13.
+ return llvm::VersionTuple(10U, 13U);
case llvm::Triple::IOS:
case llvm::Triple::TvOS: // Earliest supporting version is 11.0.0.
return llvm::VersionTuple(11U);
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index cb47215f7e1d..78e0fce917a0 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -4036,3 +4036,14 @@ def NoRandomizeLayout : InheritableAttr {
let LangOpts = [COnly];
}
def : MutualExclusions<[RandomizeLayout, NoRandomizeLayout]>;
+
+def FunctionReturnThunks : InheritableAttr,
+ TargetSpecificAttr<TargetAnyX86> {
+ let Spellings = [GCC<"function_return">];
+ let Args = [EnumArgument<"ThunkType", "Kind",
+ ["keep", "thunk-extern"],
+ ["Keep", "Extern"]
+ >];
+ let Subjects = SubjectList<[Function]>;
+ let Documentation = [FunctionReturnThunksDocs];
+}
diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td
index 4e4d871a58a7..aff0dbbdd94d 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -3088,8 +3088,8 @@ def FormatDocs : Documentation {
let Content = [{
Clang supports the ``format`` attribute, which indicates that the function
-accepts a ``printf`` or ``scanf``-like format string and corresponding
-arguments or a ``va_list`` that contains these arguments.
+accepts (among other possibilities) a ``printf`` or ``scanf``-like format string
+and corresponding arguments or a ``va_list`` that contains these arguments.
Please see `GCC documentation about format attribute
<http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html>`_ to find details
@@ -3143,6 +3143,27 @@ Clang implements two kinds of checks with this attribute.
In this case Clang does not warn because the format string ``s`` and
the corresponding arguments are annotated. If the arguments are
incorrect, the caller of ``foo`` will receive a warning.
+
+As an extension to GCC's behavior, Clang accepts the ``format`` attribute on
+non-variadic functions. Clang checks non-variadic format functions for the same
+classes of issues that can be found on variadic functions, as controlled by the
+same warning flags, except that the types of formatted arguments is forced by
+the function signature. For example:
+
+.. code-block:: c
+
+ __attribute__((__format__(__printf__, 1, 2)))
+ void fmt(const char *s, const char *a, int b);
+
+ void bar(void) {
+ fmt("%s %i", "hello", 123); // OK
+ fmt("%i %g", "hello", 123); // warning: arguments don't match format
+ extern const char *fmt;
+ fmt(fmt, "hello", 123); // warning: format string is not a string literal
+ }
+
+Using the ``format`` attribute on a non-variadic function emits a GCC
+compatibility diagnostic.
}];
}
@@ -6585,6 +6606,28 @@ evaluate to NULL.
}
return 0;
}
+ }];
+}
+
+def FunctionReturnThunksDocs : Documentation {
+ let Category = DocCatFunction;
+ let Content = [{
+The attribute ``function_return`` can replace return instructions with jumps to
+target-specific symbols. This attribute supports 2 possible values,
+corresponding to the values supported by the ``-mfunction-return=`` command
+line flag:
+
+* ``__attribute__((function_return("keep")))`` to disable related transforms.
+ This is useful for undoing global setting from ``-mfunction-return=`` locally
+ for individual functions.
+* ``__attribute__((function_return("thunk-extern")))`` to replace returns with
+ jumps, while NOT emitting the thunk.
+
+The values ``thunk`` and ``thunk-inline`` from GCC are not supported.
+
+The symbol used for ``thunk-extern`` is target specific:
+* X86: ``__x86_return_thunk``
+As such, this function attribute is currently only supported on X86 targets.
}];
}
diff --git a/clang/include/clang/Basic/BuiltinsX86.def b/clang/include/clang/Basic/BuiltinsX86.def
index 3e5c376f9bc1..6bf35c340c2d 100644
--- a/clang/include/clang/Basic/BuiltinsX86.def
+++ b/clang/include/clang/Basic/BuiltinsX86.def
@@ -825,6 +825,7 @@ BUILTIN(__rdtsc, "UOi", "")
BUILTIN(__builtin_ia32_rdtscp, "UOiUi*", "")
TARGET_BUILTIN(__builtin_ia32_rdpid, "Ui", "n", "rdpid")
+TARGET_BUILTIN(__builtin_ia32_rdpru, "ULLii", "n", "rdpru")
// PKU
TARGET_BUILTIN(__builtin_ia32_rdpkru, "Ui", "n", "pku")
diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def
index 72b0e5d8eb41..b1d394edd04a 100644
--- a/clang/include/clang/Basic/CodeGenOptions.def
+++ b/clang/include/clang/Basic/CodeGenOptions.def
@@ -107,6 +107,7 @@ CODEGENOPT(CFProtectionReturn , 1, 0) ///< if -fcf-protection is
CODEGENOPT(CFProtectionBranch , 1, 0) ///< if -fcf-protection is
///< set to full or branch.
CODEGENOPT(IBTSeal, 1, 0) ///< set to optimize CFProtectionBranch.
+CODEGENOPT(FunctionReturnThunks, 1, 0) ///< -mfunction-return={keep|thunk-extern}
CODEGENOPT(XRayInstrumentFunctions , 1, 0) ///< Set when -fxray-instrument is
///< enabled.
diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h
index 23d76c308d84..cd204e5d7c15 100644
--- a/clang/include/clang/Basic/CodeGenOptions.h
+++ b/clang/include/clang/Basic/CodeGenOptions.h
@@ -389,6 +389,9 @@ public:
/// On AArch64 this can only be "sp_el0".
std::string StackProtectorGuardReg;
+ /// Specify a symbol to be the guard value.
+ std::string StackProtectorGuardSymbol;
+
/// Path to ignorelist file specifying which objects
/// (files, functions) listed for instrumentation by sanitizer
/// coverage pass should actually not be instrumented.
diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td
index 96219f83b0a5..68685baf7633 100644
--- a/clang/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td
@@ -60,8 +60,6 @@ def err_drv_no_cuda_libdevice : Error<
"cannot find libdevice for %0; provide path to different CUDA installation "
"via '--cuda-path', or pass '-nocudalib' to build without linking with "
"libdevice">;
-def err_drv_no_rdc_new_driver : Error<
- "Using '--offload-new-driver' requires '-fgpu-rdc'">;
def err_drv_no_rocm_device_lib : Error<
"cannot find ROCm device library%select{| for %1|for ABI version %1}0; provide its path via "
diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td
index 10da02ecbf7e..53e246a39ed8 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -31,6 +31,7 @@ def GNUAnonymousStruct : DiagGroup<"gnu-anonymous-struct">;
def GNUAutoType : DiagGroup<"gnu-auto-type">;
def ArrayBounds : DiagGroup<"array-bounds">;
def ArrayBoundsPointerArithmetic : DiagGroup<"array-bounds-pointer-arithmetic">;
+def ArrayParameter : DiagGroup<"array-parameter">;
def AutoDisableVptrSanitizer : DiagGroup<"auto-disable-vptr-sanitizer">;
def Availability : DiagGroup<"availability">;
def Section : DiagGroup<"section">;
@@ -187,6 +188,7 @@ def UnguardedAvailability : DiagGroup<"unguarded-availability",
def : DiagGroup<"partial-availability", [UnguardedAvailability]>;
def DeprecatedDynamicExceptionSpec
: DiagGroup<"deprecated-dynamic-exception-spec">;
+def DeprecatedBuiltins : DiagGroup<"deprecated-builtins">;
def DeprecatedImplementations :DiagGroup<"deprecated-implementations">;
def DeprecatedIncrementBool : DiagGroup<"deprecated-increment-bool">;
def DeprecatedRegister : DiagGroup<"deprecated-register">;
@@ -209,6 +211,7 @@ def Deprecated : DiagGroup<"deprecated", [DeprecatedAnonEnumEnumConversion,
DeprecatedEnumCompareConditional,
DeprecatedEnumEnumConversion,
DeprecatedEnumFloatConversion,
+ DeprecatedBuiltins,
DeprecatedIncrementBool,
DeprecatedPragma,
DeprecatedRegister,
@@ -978,6 +981,7 @@ def Extra : DiagGroup<"extra", [
]>;
def Most : DiagGroup<"most", [
+ ArrayParameter,
BoolOperation,
CharSubscript,
Comment,
diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td b/clang/include/clang/Basic/DiagnosticLexKinds.td
index ac86076140c5..dd0909704492 100644
--- a/clang/include/clang/Basic/DiagnosticLexKinds.td
+++ b/clang/include/clang/Basic/DiagnosticLexKinds.td
@@ -113,6 +113,8 @@ def warn_four_char_character_literal : Warning<
// Unicode and UCNs
def err_invalid_utf8 : Error<
"source file is not valid UTF-8">;
+def warn_invalid_utf8_in_comment : Extension<
+ "invalid UTF-8 in comment">, InGroup<DiagGroup<"invalid-utf8">>;
def err_character_not_allowed : Error<
"unexpected character <U+%0>">;
def err_character_not_allowed_identifier : Error<
@@ -128,8 +130,15 @@ def warn_utf8_symbol_zero_width : Warning<
"some environments">, InGroup<DiagGroup<"unicode-zero-width">>;
def ext_delimited_escape_sequence : Extension<
- "%select{delimited|named}0 escape sequences are a Clang extension">,
+ "%select{delimited|named}0 escape sequences are a "
+ "%select{Clang|C++2b}1 extension">,
InGroup<DiagGroup<"delimited-escape-sequence-extension">>;
+
+def warn_cxx2b_delimited_escape_sequence : Warning<
+ "%select{delimited|named}0 escape sequences are "
+ "incompatible with C++ standards before C++2b">,
+ InGroup<CXXPre2bCompat>, DefaultIgnore;
+
def err_delimited_escape_empty : Error<
"delimited escape sequence cannot be empty">;
def err_delimited_escape_missing_brace: Error<
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index bc7aec3803e8..550029f58b54 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3115,8 +3115,6 @@ def note_ownership_returns_index_mismatch : Note<
"declared with index %0 here">;
def err_format_strftime_third_parameter : Error<
"strftime format attribute requires 3rd parameter to be 0">;
-def err_format_attribute_requires_variadic : Error<
- "format attribute requires variadic function">;
def err_format_attribute_not : Error<"format argument not a string type">;
def err_format_attribute_result_not : Error<"function does not return %0">;
def err_format_attribute_implicit_this_format_string : Error<
@@ -3343,10 +3341,11 @@ def warn_assume_aligned_too_great
"alignment assumed">,
InGroup<DiagGroup<"builtin-assume-aligned-alignment">>;
def warn_not_xl_compatible
- : Warning<"requesting an alignment of 16 bytes or greater for struct"
- " members is not binary compatible with IBM XL C/C++ for AIX"
- " 16.1.0 and older">,
+ : Warning<"alignment of 16 bytes for a struct member is not binary "
+ "compatible with IBM XL C/C++ for AIX 16.1.0 or older">,
InGroup<AIXCompat>;
+def note_misaligned_member_used_here : Note<
+ "passing byval argument %0 with potentially incompatible alignment here">;
def warn_redeclaration_without_attribute_prev_attribute_ignored : Warning<
"%q0 redeclared without %1 attribute: previous %1 ignored">,
InGroup<MicrosoftInconsistentDllImport>;
@@ -4127,6 +4126,9 @@ def err_attribute_not_supported_on_arch
def warn_gcc_ignores_type_attr : Warning<
"GCC does not allow the %0 attribute to be written on a type">,
InGroup<GccCompat>;
+def warn_gcc_requires_variadic_function : Warning<
+ "GCC requires a function with the %0 attribute to be variadic">,
+ InGroup<GccCompat>;
// Clang-Specific Attributes
def warn_attribute_iboutlet : Warning<
@@ -4829,8 +4831,12 @@ def warn_cxx14_compat_template_nontype_parm_auto_type : Warning<
DefaultIgnore, InGroup<CXXPre17Compat>;
def err_template_param_default_arg_redefinition : Error<
"template parameter redefines default argument">;
+def err_template_param_default_arg_inconsistent_redefinition : Error<
+ "template parameter default argument is inconsistent with previous definition">;
def note_template_param_prev_default_arg : Note<
"previous default template argument defined here">;
+def note_template_param_prev_default_arg_in_other_module : Note<
+ "previous default template argument defined in module %0">;
def err_template_param_default_arg_missing : Error<
"template parameter missing a default argument">;
def ext_template_parameter_default_in_function_template : ExtWarn<
@@ -5557,6 +5563,9 @@ def warn_deprecated_def : Warning<
def warn_unavailable_def : Warning<
"implementing unavailable method">,
InGroup<DeprecatedImplementations>, DefaultIgnore;
+def warn_deprecated_builtin : Warning<
+ "builtin %0 is deprecated; use %1 instead">,
+ InGroup<DeprecatedBuiltins>;
def err_unavailable : Error<"%0 is unavailable">;
def err_property_method_unavailable :
Error<"property access is using %0 method which is unavailable">;
@@ -6605,13 +6614,16 @@ def warn_addition_in_bitshift : Warning<
"'%1' will be evaluated first">, InGroup<ShiftOpParentheses>;
def warn_self_assignment_builtin : Warning<
- "explicitly assigning value of variable of type %0 to itself">,
+ "explicitly assigning value of variable of type %0 to itself%select{|; did "
+ "you mean to assign to member %2?}1">,
InGroup<SelfAssignment>, DefaultIgnore;
def warn_self_assignment_overloaded : Warning<
- "explicitly assigning value of variable of type %0 to itself">,
+ "explicitly assigning value of variable of type %0 to itself%select{|; did "
+ "you mean to assign to member %2?}1">,
InGroup<SelfAssignmentOverloaded>, DefaultIgnore;
def warn_self_move : Warning<
- "explicitly moving variable of type %0 to itself">,
+ "explicitly moving variable of type %0 to itself%select{|; did you mean to "
+ "move to member %2?}1">,
InGroup<SelfMove>, DefaultIgnore;
def err_builtin_move_forward_unsupported : Error<
@@ -9395,6 +9407,12 @@ def warn_array_index_exceeds_max_addressable_bounds : Warning<
def note_array_declared_here : Note<
"array %0 declared here">;
+def warn_inconsistent_array_form : Warning<
+ "argument %0 of type %1 with mismatched bound">,
+ InGroup<ArrayParameter>, DefaultIgnore;
+def note_previous_declaration_as : Note<
+ "previously declared as %0 here">;
+
def warn_printf_insufficient_data_args : Warning<
"more '%%' conversions than data arguments">, InGroup<FormatInsufficientArgs>;
def warn_printf_data_arg_not_used : Warning<
diff --git a/clang/include/clang/Basic/MakeSupport.h b/clang/include/clang/Basic/MakeSupport.h
new file mode 100644
index 000000000000..c663014ba7bc
--- /dev/null
+++ b/clang/include/clang/Basic/MakeSupport.h
@@ -0,0 +1,23 @@
+//===- MakeSupport.h - Make Utilities ---------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_BASIC_MAKESUPPORT_H
+#define LLVM_CLANG_BASIC_MAKESUPPORT_H
+
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/StringRef.h"
+
+namespace clang {
+
+/// Quote target names for inclusion in GNU Make dependency files.
+/// Only the characters '$', '#', ' ', '\t' are quoted.
+void quoteMakeTarget(StringRef Target, SmallVectorImpl<char> &Res);
+
+} // namespace clang
+
+#endif // LLVM_CLANG_BASIC_MAKESUPPORT_H
diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h
index 0ab3e9b67dfe..b4f3a69259fa 100644
--- a/clang/include/clang/Basic/TargetInfo.h
+++ b/clang/include/clang/Basic/TargetInfo.h
@@ -222,9 +222,7 @@ protected:
mutable VersionTuple PlatformMinVersion;
unsigned HasAlignMac68kSupport : 1;
- unsigned RealTypeUsesObjCFPRetMask
- : llvm::BitmaskEnumDetail::bitWidth(
- (int)FloatModeKind::LLVM_BITMASK_LARGEST_ENUMERATOR);
+ unsigned RealTypeUsesObjCFPRetMask : llvm::BitWidth<FloatModeKind>;
unsigned ComplexLongDoubleUsesFP2Ret : 1;
unsigned HasBuiltinMSVaList : 1;
@@ -893,7 +891,7 @@ public:
/// Check whether the given real type should use the "fpret" flavor of
/// Objective-C message passing on this target.
bool useObjCFPRetForRealType(FloatModeKind T) const {
- return RealTypeUsesObjCFPRetMask & llvm::BitmaskEnumDetail::Underlying(T);
+ return (int)((FloatModeKind)RealTypeUsesObjCFPRetMask & T);
}
/// Check whether _Complex long double should use the "fp2ret" flavor
diff --git a/clang/include/clang/Basic/riscv_vector.td b/clang/include/clang/Basic/riscv_vector.td
index b11b780ec1f7..d96020ee40d0 100644
--- a/clang/include/clang/Basic/riscv_vector.td
+++ b/clang/include/clang/Basic/riscv_vector.td
@@ -582,18 +582,8 @@ class IsFloat<string type> {
}
let HasUnMaskedOverloaded = false,
- MaskedPolicy = NonePolicy,
- ManualCodegen = [{
- IntrinsicTypes = {ResultType, Ops[1]->getType()};
- Ops[0] = Builder.CreateBitCast(Ops[0], ResultType->getPointerTo());
- }],
- MaskedManualCodegen= [{
- // Move mask to right before vl.
- std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);
- IntrinsicTypes = {ResultType, Ops[3]->getType()};
- Ops[1] = Builder.CreateBitCast(Ops[1], ResultType->getPointerTo());
- }] in {
- class RVVVLEMaskBuiltin : RVVBuiltin<"m", "mPCUe", "c"> {
+ MaskedPolicy = NonePolicy in {
+ class RVVVLEMaskBuiltin : RVVOutBuiltin<"m", "mPCUe", "c"> {
let Name = "vlm_v";
let IRName = "vlm";
let HasMasked = false;
@@ -601,26 +591,15 @@ let HasUnMaskedOverloaded = false,
}
let HasUnMaskedOverloaded = false,
- ManualCodegen = [{
- IntrinsicTypes = {ResultType, Ops[1]->getType()};
- Ops[0] = Builder.CreateBitCast(Ops[0], ResultType->getPointerTo());
- Ops.insert(Ops.begin(), llvm::UndefValue::get(ResultType));
- }],
- MaskedManualCodegen= [{
- // Move mask to right before vl.
- std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);
- Ops.push_back(ConstantInt::get(Ops.back()->getType(), TAIL_UNDISTURBED));
- IntrinsicTypes = {ResultType, Ops[3]->getType()};
- Ops[1] = Builder.CreateBitCast(Ops[1], ResultType->getPointerTo());
- }] in {
+ UnMaskedPolicy = HasPassthruOperand in {
multiclass RVVVLEBuiltin<list<string> types> {
let Name = NAME # "_v",
IRName = "vle",
MaskedIRName ="vle_mask" in {
foreach type = types in {
- def : RVVBuiltin<"v", "vPCe", type>;
+ def : RVVOutBuiltin<"v", "vPCe", type>;
if !not(IsFloat<type>.val) then {
- def : RVVBuiltin<"Uv", "UvPCUe", type>;
+ def : RVVOutBuiltin<"Uv", "UvPCUe", type>;
}
}
}
@@ -685,61 +664,39 @@ multiclass RVVVLSEBuiltin<list<string> types> {
IRName = "vlse",
MaskedIRName ="vlse_mask",
HasUnMaskedOverloaded = false,
- ManualCodegen = [{
- IntrinsicTypes = {ResultType, Ops[2]->getType()};
- Ops[0] = Builder.CreateBitCast(Ops[0], ResultType->getPointerTo());
- Ops.insert(Ops.begin(), llvm::UndefValue::get(ResultType));
- }],
- MaskedManualCodegen= [{
- // Move mask to right before vl.
- std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);
- Ops.push_back(ConstantInt::get(Ops.back()->getType(), TAIL_UNDISTURBED));
- IntrinsicTypes = {ResultType, Ops[4]->getType()};
- Ops[1] = Builder.CreateBitCast(Ops[1], ResultType->getPointerTo());
- }] in {
+ UnMaskedPolicy = HasPassthruOperand in {
foreach type = types in {
- def : RVVBuiltin<"v", "vPCet", type>;
+ def : RVVOutBuiltin<"v", "vPCet", type>;
if !not(IsFloat<type>.val) then {
- def : RVVBuiltin<"Uv", "UvPCUet", type>;
+ def : RVVOutBuiltin<"Uv", "UvPCUet", type>;
}
}
}
}
multiclass RVVIndexedLoad<string op> {
- let ManualCodegen = [{
- IntrinsicTypes = {ResultType, Ops[1]->getType(), Ops[2]->getType()};
- Ops[0] = Builder.CreateBitCast(Ops[0], ResultType->getPointerTo());
- Ops.insert(Ops.begin(), llvm::UndefValue::get(ResultType));
- }],
- MaskedManualCodegen = [{
- // Move mask to right before vl.
- std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);
- Ops.push_back(ConstantInt::get(Ops.back()->getType(), TAIL_UNDISTURBED));
- IntrinsicTypes = {ResultType, Ops[2]->getType(), Ops[4]->getType()};
- Ops[1] = Builder.CreateBitCast(Ops[1], ResultType->getPointerTo());
- }] in {
- foreach type = TypeList in {
- foreach eew_list = EEWList[0-2] in {
- defvar eew = eew_list[0];
- defvar eew_type = eew_list[1];
- let Name = op # eew # "_v", IRName = op, MaskedIRName = op # "_mask" in {
- def: RVVBuiltin<"v", "vPCe" # eew_type # "Uv", type>;
- if !not(IsFloat<type>.val) then {
- def: RVVBuiltin<"Uv", "UvPCUe" # eew_type # "Uv", type>;
- }
- }
+ let UnMaskedPolicy = HasPassthruOperand in {
+ foreach type = TypeList in {
+ foreach eew_list = EEWList[0-2] in {
+ defvar eew = eew_list[0];
+ defvar eew_type = eew_list[1];
+ let Name = op # eew # "_v", IRName = op, MaskedIRName = op # "_mask" in {
+ def: RVVOutOp1Builtin<"v", "vPCe" # eew_type # "Uv", type>;
+ if !not(IsFloat<type>.val) then {
+ def: RVVOutOp1Builtin<"Uv", "UvPCUe" # eew_type # "Uv", type>;
+ }
}
- defvar eew64 = "64";
- defvar eew64_type = "(Log2EEW:6)";
- let Name = op # eew64 # "_v", IRName = op, MaskedIRName = op # "_mask",
- RequiredFeatures = ["RV64"] in {
- def: RVVBuiltin<"v", "vPCe" # eew64_type # "Uv", type>;
- if !not(IsFloat<type>.val) then {
- def: RVVBuiltin<"Uv", "UvPCUe" # eew64_type # "Uv", type>;
- }
- }
}
+ defvar eew64 = "64";
+ defvar eew64_type = "(Log2EEW:6)";
+ let Name = op # eew64 # "_v", IRName = op, MaskedIRName = op # "_mask",
+ RequiredFeatures = ["RV64"] in {
+ def: RVVOutOp1Builtin<"v", "vPCe" # eew64_type # "Uv", type>;
+ if !not(IsFloat<type>.val) then {
+ def: RVVOutOp1Builtin<"Uv", "UvPCUe" # eew64_type # "Uv", type>;
+ }
+ }
+ }
}
}
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index f4fe08aa1a5b..532d7780c529 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -1998,6 +1998,13 @@ def fcf_protection : Flag<["-"], "fcf-protection">, Group<f_Group>, Flags<[CoreO
HelpText<"Enable cf-protection in 'full' mode">;
def mibt_seal : Flag<["-"], "mibt-seal">, Group<m_Group>, Flags<[CoreOption, CC1Option]>,
HelpText<"Optimize fcf-protection=branch/full (requires LTO).">;
+def mfunction_return_EQ : Joined<["-"], "mfunction-return=">,
+ Group<m_Group>, Flags<[CoreOption, CC1Option]>,
+ HelpText<"Replace returns with jumps to ``__x86_return_thunk`` (x86 only, error otherwise)">,
+ Values<"keep,thunk-extern">,
+ NormalizedValues<["Keep", "Extern"]>,
+ NormalizedValuesScope<"llvm::FunctionReturnThunksKind">,
+ MarshallingInfoEnum<CodeGenOpts<"FunctionReturnThunks">, "Keep">;
defm xray_instrument : BoolFOption<"xray-instrument",
LangOpts<"XRayInstrument">, DefaultFalse,
@@ -3338,11 +3345,12 @@ def mhwmult_EQ : Joined<["-"], "mhwmult=">, Group<m_Group>;
def mglobal_merge : Flag<["-"], "mglobal-merge">, Group<m_Group>, Flags<[CC1Option]>,
HelpText<"Enable merging of globals">;
def mhard_float : Flag<["-"], "mhard-float">, Group<m_Group>;
-def miphoneos_version_min_EQ : Joined<["-"], "miphoneos-version-min=">, Group<m_Group>;
def mios_version_min_EQ : Joined<["-"], "mios-version-min=">,
- Alias<miphoneos_version_min_EQ>, HelpText<"Set iOS deployment target">;
+ Group<m_Group>, HelpText<"Set iOS deployment target">;
+def : Joined<["-"], "miphoneos-version-min=">,
+ Group<m_Group>, Alias<mios_version_min_EQ>;
def mios_simulator_version_min_EQ : Joined<["-"], "mios-simulator-version-min=">;
-def miphonesimulator_version_min_EQ : Joined<["-"], "miphonesimulator-version-min=">, Alias<mios_simulator_version_min_EQ>;
+def : Joined<["-"], "miphonesimulator-version-min=">, Alias<mios_simulator_version_min_EQ>;
def mkernel : Flag<["-"], "mkernel">, Group<m_Group>;
def mlinker_version_EQ : Joined<["-"], "mlinker-version=">,
Flags<[NoXarchOption]>;
@@ -3354,10 +3362,10 @@ def mmlir : Separate<["-"], "mmlir">, Flags<[CoreOption,FC1Option,FlangOption]>,
def ffuchsia_api_level_EQ : Joined<["-"], "ffuchsia-api-level=">,
Group<m_Group>, Flags<[CC1Option]>, HelpText<"Set Fuchsia API level">,
MarshallingInfoInt<LangOpts<"FuchsiaAPILevel">>;
-def mmacosx_version_min_EQ : Joined<["-"], "mmacosx-version-min=">,
- Group<m_Group>, HelpText<"Set Mac OS X deployment target">;
def mmacos_version_min_EQ : Joined<["-"], "mmacos-version-min=">,
- Group<m_Group>, Alias<mmacosx_version_min_EQ>;
+ Group<m_Group>, HelpText<"Set macOS deployment target">;
+def : Joined<["-"], "mmacosx-version-min=">,
+ Group<m_Group>, Alias<mmacos_version_min_EQ>;
def mms_bitfields : Flag<["-"], "mms-bitfields">, Group<m_Group>, Flags<[CC1Option]>,
HelpText<"Set the default structure layout to be compatible with the Microsoft compiler standard">,
MarshallingInfoFlag<LangOpts<"MSBitfields">>;
@@ -3771,6 +3779,9 @@ def mstack_protector_guard_EQ : Joined<["-"], "mstack-protector-guard=">, Group<
def mstack_protector_guard_offset_EQ : Joined<["-"], "mstack-protector-guard-offset=">, Group<m_Group>, Flags<[CC1Option]>,
HelpText<"Use the given offset for addressing the stack-protector guard">,
MarshallingInfoInt<CodeGenOpts<"StackProtectorGuardOffset">, "INT_MAX", "int">;
+def mstack_protector_guard_symbol_EQ : Joined<["-"], "mstack-protector-guard-symbol=">, Group<m_Group>, Flags<[CC1Option]>,
+ HelpText<"Use the given symbol for addressing the stack-protector guard">,
+ MarshallingInfoString<CodeGenOpts<"StackProtectorGuardSymbol">>;
def mstack_protector_guard_reg_EQ : Joined<["-"], "mstack-protector-guard-reg=">, Group<m_Group>, Flags<[CC1Option]>,
HelpText<"Use the given reg for addressing the stack-protector guard">,
MarshallingInfoString<CodeGenOpts<"StackProtectorGuardReg">>;
@@ -3939,7 +3950,7 @@ def module_file_info : Flag<["-"], "module-file-info">, Flags<[NoXarchOption,CC1
HelpText<"Provide information about a particular module file">;
def mthumb : Flag<["-"], "mthumb">, Group<m_Group>;
def mtune_EQ : Joined<["-"], "mtune=">, Group<m_Group>,
- HelpText<"Only supported on X86 and RISC-V. Otherwise accepted for compatibility with GCC.">;
+ HelpText<"Only supported on X86, RISC-V and SystemZ. Otherwise accepted for compatibility with GCC.">;
def multi__module : Flag<["-"], "multi_module">;
def multiply__defined__unused : Separate<["-"], "multiply_defined_unused">;
def multiply__defined : Separate<["-"], "multiply_defined">;
@@ -4570,6 +4581,8 @@ def mptwrite : Flag<["-"], "mptwrite">, Group<m_x86_Features_Group>;
def mno_ptwrite : Flag<["-"], "mno-ptwrite">, Group<m_x86_Features_Group>;
def mrdpid : Flag<["-"], "mrdpid">, Group<m_x86_Features_Group>;
def mno_rdpid : Flag<["-"], "mno-rdpid">, Group<m_x86_Features_Group>;
+def mrdpru : Flag<["-"], "mrdpru">, Group<m_x86_Features_Group>;
+def mno_rdpru : Flag<["-"], "mno-rdpru">, Group<m_x86_Features_Group>;
def mrdrnd : Flag<["-"], "mrdrnd">, Group<m_x86_Features_Group>;
def mno_rdrnd : Flag<["-"], "mno-rdrnd">, Group<m_x86_Features_Group>;
def mrtm : Flag<["-"], "mrtm">, Group<m_x86_Features_Group>;
diff --git a/clang/include/clang/Frontend/FrontendActions.h b/clang/include/clang/Frontend/FrontendActions.h
index ae829d741152..fe399850bd44 100644
--- a/clang/include/clang/Frontend/FrontendActions.h
+++ b/clang/include/clang/Frontend/FrontendActions.h
@@ -190,6 +190,10 @@ public:
/// Dump information about the given module file, to be used for
/// basic debugging and discovery.
class DumpModuleInfoAction : public ASTFrontendAction {
+public:
+ // Allow other tools (ex lldb) to direct output for their use.
+ llvm::raw_ostream *OutputStream = nullptr;
+
protected:
std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) override;
diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h
index d130aba3ee3a..8fc24c731035 100644
--- a/clang/include/clang/Lex/Preprocessor.h
+++ b/clang/include/clang/Lex/Preprocessor.h
@@ -385,6 +385,7 @@ private:
bool atTopLevel() { return S <= 0; }
bool afterImportSeq() { return S == AfterImportSeq; }
+ bool afterTopLevelSeq() { return S == AfterTopLevelTokenSeq; }
private:
State S;
@@ -397,6 +398,67 @@ private:
/// Our current position within a C++20 import-seq.
ImportSeq ImportSeqState = ImportSeq::AfterTopLevelTokenSeq;
+ /// Track whether we are in a Global Module Fragment
+ class TrackGMF {
+ public:
+ enum GMFState : int {
+ GMFActive = 1,
+ MaybeGMF = 0,
+ BeforeGMFIntroducer = -1,
+ GMFAbsentOrEnded = -2,
+ };
+
+ TrackGMF(GMFState S) : S(S) {}
+
+ /// Saw a semicolon.
+ void handleSemi() {
+ // If it is immediately after the first instance of the module keyword,
+ // then that introduces the GMF.
+ if (S == MaybeGMF)
+ S = GMFActive;
+ }
+
+ /// Saw an 'export' identifier.
+ void handleExport() {
+ // The presence of an 'export' keyword always ends or excludes a GMF.
+ S = GMFAbsentOrEnded;
+ }
+
+ /// Saw an 'import' identifier.
+ void handleImport(bool AfterTopLevelTokenSeq) {
+ // If we see this before any 'module' kw, then we have no GMF.
+ if (AfterTopLevelTokenSeq && S == BeforeGMFIntroducer)
+ S = GMFAbsentOrEnded;
+ }
+
+ /// Saw a 'module' identifier.
+ void handleModule(bool AfterTopLevelTokenSeq) {
+ // This was the first module identifier and not preceded by any token
+ // that would exclude a GMF. It could begin a GMF, but only if directly
+ // followed by a semicolon.
+ if (AfterTopLevelTokenSeq && S == BeforeGMFIntroducer)
+ S = MaybeGMF;
+ else
+ S = GMFAbsentOrEnded;
+ }
+
+ /// Saw any other token.
+ void handleMisc() {
+ // We saw something other than ; after the 'module' kw, so not a GMF.
+ if (S == MaybeGMF)
+ S = GMFAbsentOrEnded;
+ }
+
+ bool inGMF() { return S == GMFActive; }
+
+ private:
+ /// Track the transitions into and out of a Global Module Fragment,
+ /// if one is present.
+ GMFState S;
+ };
+
+ TrackGMF TrackGMFState = TrackGMF::BeforeGMFIntroducer;
+
/// Whether the module import expects an identifier next. Otherwise,
/// it expects a '.' or ';'.
bool ModuleImportExpectsIdentifier = false;
@@ -2414,6 +2476,7 @@ private:
None,
ModuleBegin,
ModuleImport,
+ HeaderUnitImport,
SkippedModuleImport,
Failure,
} Kind;
diff --git a/clang/include/clang/Sema/HLSLExternalSemaSource.h b/clang/include/clang/Sema/HLSLExternalSemaSource.h
new file mode 100644
index 000000000000..439fc3d10f33
--- /dev/null
+++ b/clang/include/clang/Sema/HLSLExternalSemaSource.h
@@ -0,0 +1,41 @@
+//===--- HLSLExternalSemaSource.h - HLSL Sema Source ------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the HLSLExternalSemaSource interface.
+//
+//===----------------------------------------------------------------------===//
+#ifndef CLANG_SEMA_HLSLEXTERNALSEMASOURCE_H
+#define CLANG_SEMA_HLSLEXTERNALSEMASOURCE_H
+
+#include "clang/Sema/ExternalSemaSource.h"
+
+namespace clang {
+class NamespaceDecl;
+class Sema;
+
+class HLSLExternalSemaSource : public ExternalSemaSource {
+ Sema *SemaPtr = nullptr;
+ NamespaceDecl *HLSLNamespace;
+
+ void defineHLSLVectorAlias();
+
+public:
+ ~HLSLExternalSemaSource() override;
+
+ /// Initialize the semantic source with the Sema instance
+ /// being used to perform semantic analysis on the abstract syntax
+ /// tree.
+ void InitializeSema(Sema &S) override;
+
+ /// Inform the semantic consumer that Sema is no longer available.
+ void ForgetSema() override { SemaPtr = nullptr; }
+};
+
+} // namespace clang
+
+#endif // CLANG_SEMA_HLSLEXTERNALSEMASOURCE_H
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index ac241cf0515d..e51b9daef7d3 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -2272,6 +2272,9 @@ private:
bool isAcceptableSlow(const NamedDecl *D, AcceptableKind Kind);
+ // Determine whether the module M belongs to the current TU.
+ bool isModuleUnitOfCurrentTU(const Module *M) const;
+
public:
/// Get the module unit whose scope we are currently within.
Module *getCurrentModule() const {
@@ -5167,6 +5170,11 @@ public:
void DiagnoseSelfMove(const Expr *LHSExpr, const Expr *RHSExpr,
SourceLocation OpLoc);
+ /// Returns a field in a CXXRecordDecl that has the same name as the decl \p
+ /// SelfAssigned when inside a CXXMethodDecl.
+ const FieldDecl *
+ getSelfAssignmentClassMemberCandidate(const ValueDecl *SelfAssigned);
+
/// Warn if we're implicitly casting from a _Nullable pointer type to a
/// _Nonnull one.
void diagnoseNullableToNonnullConversion(QualType DstType, QualType SrcType,
@@ -12997,21 +13005,29 @@ public:
SourceLocation getLocationOfStringLiteralByte(const StringLiteral *SL,
unsigned ByteNo) const;
-private:
- void CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr,
- const ArraySubscriptExpr *ASE=nullptr,
- bool AllowOnePastEnd=true, bool IndexNegated=false);
- void CheckArrayAccess(const Expr *E);
+ enum FormatArgumentPassingKind {
+ FAPK_Fixed, // values to format are fixed (no C-style variadic arguments)
+ FAPK_Variadic, // values to format are passed as variadic arguments
+ FAPK_VAList, // values to format are passed in a va_list
+ };
+
// Used to grab the relevant information from a FormatAttr and a
// FunctionDeclaration.
struct FormatStringInfo {
unsigned FormatIdx;
unsigned FirstDataArg;
- bool HasVAListArg;
+ FormatArgumentPassingKind ArgPassingKind;
};
static bool getFormatStringInfo(const FormatAttr *Format, bool IsCXXMember,
- FormatStringInfo *FSI);
+ bool IsVariadic, FormatStringInfo *FSI);
+
+private:
+ void CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr,
+ const ArraySubscriptExpr *ASE = nullptr,
+ bool AllowOnePastEnd = true, bool IndexNegated = false);
+ void CheckArrayAccess(const Expr *E);
+
bool CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall,
const FunctionProtoType *Proto);
bool CheckObjCMethodCall(ObjCMethodDecl *Method, SourceLocation loc,
@@ -13023,6 +13039,8 @@ private:
ArrayRef<const Expr *> Args,
const FunctionProtoType *Proto, SourceLocation Loc);
+ void checkAIXMemberAlignment(SourceLocation Loc, const Expr *Arg);
+
void CheckArgAlignment(SourceLocation Loc, NamedDecl *FDecl,
StringRef ParamName, QualType ArgTy, QualType ParamTy);
@@ -13166,16 +13184,15 @@ public:
private:
bool CheckFormatArguments(const FormatAttr *Format,
- ArrayRef<const Expr *> Args,
- bool IsCXXMember,
- VariadicCallType CallType,
- SourceLocation Loc, SourceRange Range,
+ ArrayRef<const Expr *> Args, bool IsCXXMember,
+ VariadicCallType CallType, SourceLocation Loc,
+ SourceRange Range,
llvm::SmallBitVector &CheckedVarArgs);
bool CheckFormatArguments(ArrayRef<const Expr *> Args,
- bool HasVAListArg, unsigned format_idx,
+ FormatArgumentPassingKind FAPK, unsigned format_idx,
unsigned firstDataArg, FormatStringType Type,
- VariadicCallType CallType,
- SourceLocation Loc, SourceRange range,
+ VariadicCallType CallType, SourceLocation Loc,
+ SourceRange range,
llvm::SmallBitVector &CheckedVarArgs);
void CheckAbsoluteValueFunction(const CallExpr *Call,
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
index a01b32669ce3..50a27a211ef0 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
@@ -414,7 +414,8 @@ public:
bool isArgumentConstructedDirectly(unsigned Index) const {
// This assumes that the object was not yet removed from the state.
return ExprEngine::getObjectUnderConstruction(
- getState(), {getOriginExpr(), Index}, getLocationContext()).hasValue();
+ getState(), {getOriginExpr(), Index}, getLocationContext())
+ .has_value();
}
/// Some calls have parameter numbering mismatched from argument numbering.
@@ -1018,7 +1019,7 @@ public:
SVal getObjectUnderConstruction() const {
return ExprEngine::getObjectUnderConstruction(getState(), getOriginExpr(),
getLocationContext())
- .getValue();
+ .value();
}
/// Number of non-placement arguments to the call. It is equal to 2 for
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h
index 4b6cbd516628..22b405919bc1 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h
@@ -53,21 +53,17 @@ public:
}
/// Return true if the constraint is perfectly constrained to 'true'.
- bool isConstrainedTrue() const { return Val && Val.getValue(); }
+ bool isConstrainedTrue() const { return Val && Val.value(); }
/// Return true if the constraint is perfectly constrained to 'false'.
- bool isConstrainedFalse() const { return Val && !Val.getValue(); }
+ bool isConstrainedFalse() const { return Val && !Val.value(); }
/// Return true if the constrained is perfectly constrained.
- bool isConstrained() const {
- return Val.hasValue();
- }
+ bool isConstrained() const { return Val.has_value(); }
/// Return true if the constrained is underconstrained and we do not know
/// if the constraint is true of value.
- bool isUnderconstrained() const {
- return !Val.hasValue();
- }
+ bool isUnderconstrained() const { return !Val.has_value(); }
};
class ConstraintManager {
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConstraintManager.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConstraintManager.h
index 61cab28918db..cf515c5a809a 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConstraintManager.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConstraintManager.h
@@ -344,7 +344,7 @@ protected:
if (!res)
Cached[hash] = ConditionTruthVal();
else
- Cached[hash] = ConditionTruthVal(res.getValue());
+ Cached[hash] = ConditionTruthVal(res.value());
return Cached[hash];
}
diff --git a/clang/include/clang/Support/RISCVVIntrinsicUtils.h b/clang/include/clang/Support/RISCVVIntrinsicUtils.h
index 3b6f205f9f22..a5e7e6d35cc8 100644
--- a/clang/include/clang/Support/RISCVVIntrinsicUtils.h
+++ b/clang/include/clang/Support/RISCVVIntrinsicUtils.h
@@ -209,8 +209,8 @@ public:
}
bool isValid() const { return Valid; }
- bool isScalar() const { return Scale && Scale.getValue() == 0; }
- bool isVector() const { return Scale && Scale.getValue() != 0; }
+ bool isScalar() const { return Scale && Scale.value() == 0; }
+ bool isVector() const { return Scale && Scale.value() != 0; }
bool isVector(unsigned Width) const {
return isVector() && ElementBitwidth == Width;
}
@@ -225,6 +225,8 @@ public:
return isFloat() && ElementBitwidth == Width;
}
+ bool isPointer() const { return IsPointer; }
+
private:
// Verify RVV vector type and set Valid.
bool verifyType() const;
diff --git a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningFilesystem.h b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningFilesystem.h
index e0d16df92e1a..b3882c227eaf 100644
--- a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningFilesystem.h
+++ b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningFilesystem.h
@@ -94,9 +94,9 @@ public:
assert(!isDirectory() && "not a file");
assert(Contents && "contents not initialized");
if (auto *Directives = Contents->DepDirectives.load()) {
- if (Directives->hasValue())
+ if (Directives->has_value())
return ArrayRef<dependency_directives_scan::Directive>(
- Directives->getValue());
+ Directives->value());
}
return None;
}
diff --git a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h
index 3bb44e44187b..a85d333ba6b1 100644
--- a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h
+++ b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h
@@ -47,12 +47,12 @@ struct FullDependencies {
/// Get the full command line.
///
- /// \param LookupPCMPath This function is called to fill in "-fmodule-file="
- /// arguments and the "-o" argument. It needs to return
- /// a path for where the PCM for the given module is to
- /// be located.
- std::vector<std::string>
- getCommandLine(std::function<StringRef(ModuleID)> LookupPCMPath) const;
+ /// \param LookupModuleOutput This function is called to fill in
+ /// "-fmodule-file=", "-o" and other output
+ /// arguments for dependencies.
+ std::vector<std::string> getCommandLine(
+ llvm::function_ref<std::string(const ModuleID &, ModuleOutputKind)>
+ LookupOutput) const;
/// Get the full command line, excluding -fmodule-file=" arguments.
std::vector<std::string> getCommandLineWithoutModulePaths() const;
diff --git a/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h b/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h
index e0a4d6a554eb..05c9f56b4cf6 100644
--- a/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h
+++ b/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h
@@ -65,6 +65,19 @@ struct ModuleIDHasher {
}
};
+/// An output from a module compilation, such as the path of the module file.
+enum class ModuleOutputKind {
+ /// The module file (.pcm). Required.
+ ModuleFile,
+ /// The path of the dependency file (.d), if any.
+ DependencyFile,
+ /// The null-separated list of names to use as the targets in the dependency
+ /// file, if any. Defaults to the value of \c ModuleFile, as in the driver.
+ DependencyTargets,
+ /// The path of the serialized diagnostic file (.dia), if any.
+ DiagnosticSerializationFile,
+};
+
struct ModuleDeps {
/// The identifier of the module.
ModuleID ID;
@@ -104,17 +117,25 @@ struct ModuleDeps {
// the primary TU.
bool ImportedByMainFile = false;
+ /// Whether the TU had a dependency file. The path in \c BuildInvocation is
+ /// cleared to avoid leaking the specific path from the TU into the module.
+ bool HadDependencyFile = false;
+
+ /// Whether the TU had serialized diagnostics. The path in \c BuildInvocation
+ /// is cleared to avoid leaking the specific path from the TU into the module.
+ bool HadSerializedDiagnostics = false;
+
/// Compiler invocation that can be used to build this module (without paths).
CompilerInvocation BuildInvocation;
/// Gets the canonical command line suitable for passing to clang.
///
- /// \param LookupPCMPath This function is called to fill in "-fmodule-file="
- /// arguments and the "-o" argument. It needs to return
- /// a path for where the PCM for the given module is to
- /// be located.
+ /// \param LookupModuleOutput This function is called to fill in
+ /// "-fmodule-file=", "-o" and other output
+ /// arguments.
std::vector<std::string> getCanonicalCommandLine(
- std::function<StringRef(ModuleID)> LookupPCMPath) const;
+ llvm::function_ref<std::string(const ModuleID &, ModuleOutputKind)>
+ LookupModuleOutput) const;
/// Gets the canonical command line suitable for passing to clang, excluding
/// "-fmodule-file=" and "-o" arguments.
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 682b71a3d686..cfd7bf604542 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -3166,7 +3166,7 @@ void ASTContext::adjustDeducedFunctionResultType(FunctionDecl *FD,
/// declaration of a function with an exception specification is permitted
/// and preserved. Other type sugar (for instance, typedefs) is not.
QualType ASTContext::getFunctionTypeWithExceptionSpec(
- QualType Orig, const FunctionProtoType::ExceptionSpecInfo &ESI) {
+ QualType Orig, const FunctionProtoType::ExceptionSpecInfo &ESI) const {
// Might have some parens.
if (const auto *PT = dyn_cast<ParenType>(Orig))
return getParenType(
@@ -3194,7 +3194,7 @@ QualType ASTContext::getFunctionTypeWithExceptionSpec(
}
bool ASTContext::hasSameFunctionTypeIgnoringExceptionSpec(QualType T,
- QualType U) {
+ QualType U) const {
return hasSameType(T, U) ||
(getLangOpts().CPlusPlus17 &&
hasSameType(getFunctionTypeWithExceptionSpec(T, EST_None),
@@ -4703,7 +4703,7 @@ QualType ASTContext::getUnresolvedUsingType(
QualType ASTContext::getAttributedType(attr::Kind attrKind,
QualType modifiedType,
- QualType equivalentType) {
+ QualType equivalentType) const {
llvm::FoldingSetNodeID id;
AttributedType::Profile(id, attrKind, modifiedType, equivalentType);
@@ -5707,6 +5707,9 @@ QualType ASTContext::getAutoTypeInternal(
!TypeConstraintConcept && !IsDependent)
return getAutoDeductType();
+ if (TypeConstraintConcept)
+ TypeConstraintConcept = TypeConstraintConcept->getCanonicalDecl();
+
// Look in the folding set for an existing type.
void *InsertPos = nullptr;
llvm::FoldingSetNodeID ID;
@@ -6215,8 +6218,59 @@ bool ASTContext::hasSameTemplateName(const TemplateName &X,
getCanonicalTemplateName(Y).getAsVoidPointer();
}
+bool ASTContext::isSameConstraintExpr(const Expr *XCE, const Expr *YCE) const {
+ if (!XCE != !YCE)
+ return false;
+
+ if (!XCE)
+ return true;
+
+ llvm::FoldingSetNodeID XCEID, YCEID;
+ XCE->Profile(XCEID, *this, /*Canonical=*/true);
+ YCE->Profile(YCEID, *this, /*Canonical=*/true);
+ return XCEID == YCEID;
+}
+
+bool ASTContext::isSameTypeConstraint(const TypeConstraint *XTC,
+ const TypeConstraint *YTC) const {
+ if (!XTC != !YTC)
+ return false;
+
+ if (!XTC)
+ return true;
+
+ auto *NCX = XTC->getNamedConcept();
+ auto *NCY = YTC->getNamedConcept();
+ if (!NCX || !NCY || !isSameEntity(NCX, NCY))
+ return false;
+ if (XTC->hasExplicitTemplateArgs() != YTC->hasExplicitTemplateArgs())
+ return false;
+ if (XTC->hasExplicitTemplateArgs())
+ if (XTC->getTemplateArgsAsWritten()->NumTemplateArgs !=
+ YTC->getTemplateArgsAsWritten()->NumTemplateArgs)
+ return false;
+
+ // Compare slowly by profiling.
+ //
+ // We couldn't compare the profiling result for the template
+ // args here. Consider the following example in different modules:
+ //
+ // template <__integer_like _Tp, C<_Tp> Sentinel>
+ // constexpr _Tp operator()(_Tp &&__t, Sentinel &&last) const {
+ // return __t;
+ // }
+ //
+ // When we compare the profiling result for `C<_Tp>` in different
+ // modules, it will compare the type of `_Tp` in different modules.
+ // However, the type of `_Tp` in different modules refer to different
+ // types here naturally. So we couldn't compare the profiling result
+ // for the template args directly.
+ return isSameConstraintExpr(XTC->getImmediatelyDeclaredConstraint(),
+ YTC->getImmediatelyDeclaredConstraint());
+}
+
bool ASTContext::isSameTemplateParameter(const NamedDecl *X,
- const NamedDecl *Y) {
+ const NamedDecl *Y) const {
if (X->getKind() != Y->getKind())
return false;
@@ -6226,32 +6280,8 @@ bool ASTContext::isSameTemplateParameter(const NamedDecl *X,
return false;
if (TX->hasTypeConstraint() != TY->hasTypeConstraint())
return false;
- const TypeConstraint *TXTC = TX->getTypeConstraint();
- const TypeConstraint *TYTC = TY->getTypeConstraint();
- if (!TXTC != !TYTC)
- return false;
- if (TXTC && TYTC) {
- auto *NCX = TXTC->getNamedConcept();
- auto *NCY = TYTC->getNamedConcept();
- if (!NCX || !NCY || !isSameEntity(NCX, NCY))
- return false;
- if (TXTC->hasExplicitTemplateArgs() != TYTC->hasExplicitTemplateArgs())
- return false;
- if (TXTC->hasExplicitTemplateArgs()) {
- auto *TXTCArgs = TXTC->getTemplateArgsAsWritten();
- auto *TYTCArgs = TYTC->getTemplateArgsAsWritten();
- if (TXTCArgs->NumTemplateArgs != TYTCArgs->NumTemplateArgs)
- return false;
- llvm::FoldingSetNodeID XID, YID;
- for (auto &ArgLoc : TXTCArgs->arguments())
- ArgLoc.getArgument().Profile(XID, X->getASTContext());
- for (auto &ArgLoc : TYTCArgs->arguments())
- ArgLoc.getArgument().Profile(YID, Y->getASTContext());
- if (XID != YID)
- return false;
- }
- }
- return true;
+ return isSameTypeConstraint(TX->getTypeConstraint(),
+ TY->getTypeConstraint());
}
if (auto *TX = dyn_cast<NonTypeTemplateParmDecl>(X)) {
@@ -6267,8 +6297,8 @@ bool ASTContext::isSameTemplateParameter(const NamedDecl *X,
TY->getTemplateParameters());
}
-bool ASTContext::isSameTemplateParameterList(const TemplateParameterList *X,
- const TemplateParameterList *Y) {
+bool ASTContext::isSameTemplateParameterList(
+ const TemplateParameterList *X, const TemplateParameterList *Y) const {
if (X->size() != Y->size())
return false;
@@ -6276,19 +6306,46 @@ bool ASTContext::isSameTemplateParameterList(const TemplateParameterList *X,
if (!isSameTemplateParameter(X->getParam(I), Y->getParam(I)))
return false;
- const Expr *XRC = X->getRequiresClause();
- const Expr *YRC = Y->getRequiresClause();
- if (!XRC != !YRC)
+ return isSameConstraintExpr(X->getRequiresClause(), Y->getRequiresClause());
+}
+
+bool ASTContext::isSameDefaultTemplateArgument(const NamedDecl *X,
+ const NamedDecl *Y) const {
+ // If the type parameter isn't the same already, we don't need to check the
+ // default argument further.
+ if (!isSameTemplateParameter(X, Y))
return false;
- if (XRC) {
- llvm::FoldingSetNodeID XRCID, YRCID;
- XRC->Profile(XRCID, *this, /*Canonical=*/true);
- YRC->Profile(YRCID, *this, /*Canonical=*/true);
- if (XRCID != YRCID)
+
+ if (auto *TTPX = dyn_cast<TemplateTypeParmDecl>(X)) {
+ auto *TTPY = cast<TemplateTypeParmDecl>(Y);
+ if (!TTPX->hasDefaultArgument() || !TTPY->hasDefaultArgument())
return false;
+
+ return hasSameType(TTPX->getDefaultArgument(), TTPY->getDefaultArgument());
}
- return true;
+ if (auto *NTTPX = dyn_cast<NonTypeTemplateParmDecl>(X)) {
+ auto *NTTPY = cast<NonTypeTemplateParmDecl>(Y);
+ if (!NTTPX->hasDefaultArgument() || !NTTPY->hasDefaultArgument())
+ return false;
+
+ Expr *DefaultArgumentX = NTTPX->getDefaultArgument()->IgnoreImpCasts();
+ Expr *DefaultArgumentY = NTTPY->getDefaultArgument()->IgnoreImpCasts();
+ llvm::FoldingSetNodeID XID, YID;
+ DefaultArgumentX->Profile(XID, *this, /*Canonical=*/true);
+ DefaultArgumentY->Profile(YID, *this, /*Canonical=*/true);
+ return XID == YID;
+ }
+
+ auto *TTPX = cast<TemplateTemplateParmDecl>(X);
+ auto *TTPY = cast<TemplateTemplateParmDecl>(Y);
+
+ if (!TTPX->hasDefaultArgument() || !TTPY->hasDefaultArgument())
+ return false;
+
+ const TemplateArgument &TAX = TTPX->getDefaultArgument().getArgument();
+ const TemplateArgument &TAY = TTPY->getDefaultArgument().getArgument();
+ return hasSameTemplateName(TAX.getAsTemplate(), TAY.getAsTemplate());
}
static NamespaceDecl *getNamespace(const NestedNameSpecifier *X) {
@@ -6371,7 +6428,7 @@ static bool hasSameOverloadableAttrs(const FunctionDecl *A,
return true;
}
-bool ASTContext::isSameEntity(const NamedDecl *X, const NamedDecl *Y) {
+bool ASTContext::isSameEntity(const NamedDecl *X, const NamedDecl *Y) const {
if (X == Y)
return true;
@@ -6447,17 +6504,9 @@ bool ASTContext::isSameEntity(const NamedDecl *X, const NamedDecl *Y) {
return false;
}
- const Expr *XRC = FuncX->getTrailingRequiresClause();
- const Expr *YRC = FuncY->getTrailingRequiresClause();
- if (!XRC != !YRC)
+ if (!isSameConstraintExpr(FuncX->getTrailingRequiresClause(),
+ FuncY->getTrailingRequiresClause()))
return false;
- if (XRC) {
- llvm::FoldingSetNodeID XRCID, YRCID;
- XRC->Profile(XRCID, *this, /*Canonical=*/true);
- YRC->Profile(YRCID, *this, /*Canonical=*/true);
- if (XRCID != YRCID)
- return false;
- }
auto GetTypeAsWritten = [](const FunctionDecl *FD) {
// Map to the first declaration that we've already merged into this one.
@@ -6478,8 +6527,6 @@ bool ASTContext::isSameEntity(const NamedDecl *X, const NamedDecl *Y) {
if (getLangOpts().CPlusPlus17 && XFPT && YFPT &&
(isUnresolvedExceptionSpec(XFPT->getExceptionSpecType()) ||
isUnresolvedExceptionSpec(YFPT->getExceptionSpecType())) &&
- // FIXME: We could make isSameEntity const after we make
- // hasSameFunctionTypeIgnoringExceptionSpec const.
hasSameFunctionTypeIgnoringExceptionSpec(XT, YT))
return true;
return false;
@@ -6521,6 +6568,20 @@ bool ASTContext::isSameEntity(const NamedDecl *X, const NamedDecl *Y) {
// and patterns match.
if (const auto *TemplateX = dyn_cast<TemplateDecl>(X)) {
const auto *TemplateY = cast<TemplateDecl>(Y);
+
+ // ConceptDecl wouldn't be the same if their constraint expression differs.
+ if (const auto *ConceptX = dyn_cast<ConceptDecl>(X)) {
+ const auto *ConceptY = cast<ConceptDecl>(Y);
+ const Expr *XCE = ConceptX->getConstraintExpr();
+ const Expr *YCE = ConceptY->getConstraintExpr();
+ assert(XCE && YCE && "ConceptDecl without constraint expression?");
+ llvm::FoldingSetNodeID XID, YID;
+ XCE->Profile(XID, *this, /*Canonical=*/true);
+ YCE->Profile(YID, *this, /*Canonical=*/true);
+ if (XID != YID)
+ return false;
+ }
+
return isSameEntity(TemplateX->getTemplatedDecl(),
TemplateY->getTemplatedDecl()) &&
isSameTemplateParameterList(TemplateX->getTemplateParameters(),
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index e9730112eaa3..73c3f02e67a8 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -5667,11 +5667,6 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
D2->setPreviousDecl(Recent);
}
- if (FromTemplated->isCompleteDefinition() &&
- !ToTemplated->isCompleteDefinition()) {
- // FIXME: Import definition!
- }
-
return D2;
}
@@ -5950,11 +5945,6 @@ ExpectedDecl ASTNodeImporter::VisitVarTemplateDecl(VarTemplateDecl *D) {
ToVarTD->setPreviousDecl(Recent);
}
- if (DTemplated->isThisDeclarationADefinition() &&
- !ToTemplated->isThisDeclarationADefinition()) {
- // FIXME: Import definition!
- }
-
return ToVarTD;
}
diff --git a/clang/lib/AST/AttrImpl.cpp b/clang/lib/AST/AttrImpl.cpp
index c1e7435b22da..deb28bee5ed8 100644
--- a/clang/lib/AST/AttrImpl.cpp
+++ b/clang/lib/AST/AttrImpl.cpp
@@ -169,7 +169,7 @@ llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy>
OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(const ValueDecl *VD) {
llvm::Optional<OMPDeclareTargetDeclAttr *> ActiveAttr = getActiveAttr(VD);
if (ActiveAttr)
- return ActiveAttr.getValue()->getMapType();
+ return ActiveAttr.value()->getMapType();
return llvm::None;
}
@@ -177,7 +177,7 @@ llvm::Optional<OMPDeclareTargetDeclAttr::DevTypeTy>
OMPDeclareTargetDeclAttr::getDeviceType(const ValueDecl *VD) {
llvm::Optional<OMPDeclareTargetDeclAttr *> ActiveAttr = getActiveAttr(VD);
if (ActiveAttr)
- return ActiveAttr.getValue()->getDevType();
+ return ActiveAttr.value()->getDevType();
return llvm::None;
}
@@ -185,7 +185,7 @@ llvm::Optional<SourceLocation>
OMPDeclareTargetDeclAttr::getLocation(const ValueDecl *VD) {
llvm::Optional<OMPDeclareTargetDeclAttr *> ActiveAttr = getActiveAttr(VD);
if (ActiveAttr)
- return ActiveAttr.getValue()->getRange().getBegin();
+ return ActiveAttr.value()->getRange().getBegin();
return llvm::None;
}
diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp
index c6a392c9c01b..3f04d9b4073e 100644
--- a/clang/lib/AST/DeclPrinter.cpp
+++ b/clang/lib/AST/DeclPrinter.cpp
@@ -1007,6 +1007,12 @@ void DeclPrinter::VisitCXXRecordDecl(CXXRecordDecl *D) {
}
}
+ if (auto *Def = D->getDefinition()) {
+ if (D->hasAttr<FinalAttr>()) {
+ Out << " final";
+ }
+ }
+
if (D->isCompleteDefinition()) {
// Print the base classes
if (D->getNumBases()) {
diff --git a/clang/lib/AST/FormatString.cpp b/clang/lib/AST/FormatString.cpp
index 4977aaa51319..c0879704de4d 100644
--- a/clang/lib/AST/FormatString.cpp
+++ b/clang/lib/AST/FormatString.cpp
@@ -321,6 +321,12 @@ bool clang::analyze_format_string::ParseUTF8InvalidSpecifier(
clang::analyze_format_string::ArgType::MatchKind
ArgType::matchesType(ASTContext &C, QualType argTy) const {
+ // When using the format attribute in C++, you can receive a function or an
+ // array that will necessarily decay to a pointer when passed to the final
+ // format consumer. Apply decay before type comparison.
+ if (argTy->canDecayToPointerType())
+ argTy = C.getDecayedType(argTy);
+
if (Ptr) {
// It has to be a pointer.
const PointerType *PT = argTy->getAs<PointerType>();
diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
index da538aa332ff..9b729e347a24 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -496,7 +496,7 @@ ByteCodeExprGen<Emitter>::getGlobalIdx(const VarDecl *VD) {
template <class Emitter>
const RecordType *ByteCodeExprGen<Emitter>::getRecordTy(QualType Ty) {
- if (auto *PT = dyn_cast<PointerType>(Ty))
+ if (const PointerType *PT = dyn_cast<PointerType>(Ty))
return PT->getPointeeType()->getAs<RecordType>();
else
return Ty->getAs<RecordType>();
diff --git a/clang/lib/Analysis/BodyFarm.cpp b/clang/lib/Analysis/BodyFarm.cpp
index 23d37b881069..38f100ae0a4f 100644
--- a/clang/lib/Analysis/BodyFarm.cpp
+++ b/clang/lib/Analysis/BodyFarm.cpp
@@ -699,7 +699,7 @@ static Stmt *create_OSAtomicCompareAndSwap(ASTContext &C, const FunctionDecl *D)
Stmt *BodyFarm::getBody(const FunctionDecl *D) {
Optional<Stmt *> &Val = Bodies[D];
if (Val)
- return Val.getValue();
+ return Val.value();
Val = nullptr;
@@ -874,7 +874,7 @@ Stmt *BodyFarm::getBody(const ObjCMethodDecl *D) {
Optional<Stmt *> &Val = Bodies[D];
if (Val)
- return Val.getValue();
+ return Val.value();
Val = nullptr;
// For now, we only synthesize getters.
diff --git a/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp b/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp
index fe9907a7c99b..58708b5b5efb 100644
--- a/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp
+++ b/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp
@@ -36,7 +36,7 @@ buildStmtToBasicBlockMap(const CFG &Cfg) {
if (!Stmt)
continue;
- StmtToBlock[Stmt.getValue().getStmt()] = Block;
+ StmtToBlock[Stmt.value().getStmt()] = Block;
}
if (const Stmt *TerminatorStmt = Block->getTerminatorStmt())
StmtToBlock[TerminatorStmt] = Block;
diff --git a/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp b/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp
index e08fc71c51dc..cd87e87a6aca 100644
--- a/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp
+++ b/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp
@@ -24,8 +24,8 @@ namespace dataflow {
StorageLocation &
DataflowAnalysisContext::getStableStorageLocation(QualType Type) {
- assert(!Type.isNull());
- if (Type->isStructureOrClassType() || Type->isUnionType()) {
+ if (!Type.isNull() &&
+ (Type->isStructureOrClassType() || Type->isUnionType())) {
// FIXME: Explore options to avoid eager initialization of fields as some of
// them might not be needed for a particular analysis.
llvm::DenseMap<const ValueDecl *, StorageLocation *> FieldLocs;
@@ -57,8 +57,8 @@ DataflowAnalysisContext::getStableStorageLocation(const Expr &E) {
PointerValue &
DataflowAnalysisContext::getOrCreateNullPointerValue(QualType PointeeType) {
- assert(!PointeeType.isNull());
- auto CanonicalPointeeType = PointeeType.getCanonicalType();
+ auto CanonicalPointeeType =
+ PointeeType.isNull() ? PointeeType : PointeeType.getCanonicalType();
auto Res = NullPointerVals.try_emplace(CanonicalPointeeType, nullptr);
if (Res.second) {
auto &PointeeLoc = getStableStorageLocation(CanonicalPointeeType);
diff --git a/clang/lib/Analysis/FlowSensitive/DebugSupport.cpp b/clang/lib/Analysis/FlowSensitive/DebugSupport.cpp
new file mode 100644
index 000000000000..305d9d346089
--- /dev/null
+++ b/clang/lib/Analysis/FlowSensitive/DebugSupport.cpp
@@ -0,0 +1,197 @@
+//===- DebugSupport.cpp -----------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines functions which generate more readable forms of data
+// structures used in the dataflow analyses, for debugging purposes.
+//
+//===----------------------------------------------------------------------===//
+
+#include <utility>
+
+#include "clang/Analysis/FlowSensitive/DebugSupport.h"
+#include "clang/Analysis/FlowSensitive/Solver.h"
+#include "clang/Analysis/FlowSensitive/Value.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FormatAdapters.h"
+#include "llvm/Support/FormatCommon.h"
+#include "llvm/Support/FormatVariadic.h"
+
+namespace clang {
+namespace dataflow {
+
+using llvm::AlignStyle;
+using llvm::fmt_pad;
+using llvm::formatv;
+
+namespace {
+
+class DebugStringGenerator {
+public:
+ explicit DebugStringGenerator(
+ llvm::DenseMap<const AtomicBoolValue *, std::string> AtomNamesArg)
+ : Counter(0), AtomNames(std::move(AtomNamesArg)) {
+#ifndef NDEBUG
+ llvm::StringSet<> Names;
+ for (auto &N : AtomNames) {
+ assert(Names.insert(N.second).second &&
+ "The same name must not assigned to different atoms");
+ }
+#endif
+ }
+
+ /// Returns a string representation of a boolean value `B`.
+ std::string debugString(const BoolValue &B, size_t Depth = 0) {
+ std::string S;
+ switch (B.getKind()) {
+ case Value::Kind::AtomicBool: {
+ S = getAtomName(&cast<AtomicBoolValue>(B));
+ break;
+ }
+ case Value::Kind::Conjunction: {
+ auto &C = cast<ConjunctionValue>(B);
+ auto L = debugString(C.getLeftSubValue(), Depth + 1);
+ auto R = debugString(C.getRightSubValue(), Depth + 1);
+ S = formatv("(and\n{0}\n{1})", L, R);
+ break;
+ }
+ case Value::Kind::Disjunction: {
+ auto &D = cast<DisjunctionValue>(B);
+ auto L = debugString(D.getLeftSubValue(), Depth + 1);
+ auto R = debugString(D.getRightSubValue(), Depth + 1);
+ S = formatv("(or\n{0}\n{1})", L, R);
+ break;
+ }
+ case Value::Kind::Negation: {
+ auto &N = cast<NegationValue>(B);
+ S = formatv("(not\n{0})", debugString(N.getSubVal(), Depth + 1));
+ break;
+ }
+ default:
+ llvm_unreachable("Unhandled value kind");
+ }
+ auto Indent = Depth * 4;
+ return formatv("{0}", fmt_pad(S, Indent, 0));
+ }
+
+ /// Returns a string representation of a set of boolean `Constraints` and the
+ /// `Result` of satisfiability checking on the `Constraints`.
+ std::string debugString(const std::vector<BoolValue *> &Constraints,
+ const Solver::Result &Result) {
+ auto Template = R"(
+Constraints
+------------
+{0:$[
+
+]}
+------------
+{1}.
+{2}
+)";
+
+ std::vector<std::string> ConstraintsStrings;
+ ConstraintsStrings.reserve(Constraints.size());
+ for (auto &Constraint : Constraints) {
+ ConstraintsStrings.push_back(debugString(*Constraint));
+ }
+
+ auto StatusString = debugString(Result.getStatus());
+ auto Solution = Result.getSolution();
+ auto SolutionString =
+ Solution.hasValue() ? "\n" + debugString(Solution.value()) : "";
+
+ return formatv(
+ Template,
+ llvm::make_range(ConstraintsStrings.begin(), ConstraintsStrings.end()),
+ StatusString, SolutionString);
+ }
+
+private:
+ /// Returns a string representation of a truth assignment to atom booleans.
+ std::string debugString(
+ const llvm::DenseMap<AtomicBoolValue *, Solver::Result::Assignment>
+ &AtomAssignments) {
+ size_t MaxNameLength = 0;
+ for (auto &AtomName : AtomNames) {
+ MaxNameLength = std::max(MaxNameLength, AtomName.second.size());
+ }
+
+ std::vector<std::string> Lines;
+ for (auto &AtomAssignment : AtomAssignments) {
+ auto Line = formatv("{0} = {1}",
+ fmt_align(getAtomName(AtomAssignment.first),
+ AlignStyle::Left, MaxNameLength),
+ debugString(AtomAssignment.second));
+ Lines.push_back(Line);
+ }
+ llvm::sort(Lines.begin(), Lines.end());
+
+ return formatv("{0:$[\n]}", llvm::make_range(Lines.begin(), Lines.end()));
+ }
+
+ /// Returns a string representation of a boolean assignment to true or false.
+ std::string debugString(Solver::Result::Assignment Assignment) {
+ switch (Assignment) {
+ case Solver::Result::Assignment::AssignedFalse:
+ return "False";
+ case Solver::Result::Assignment::AssignedTrue:
+ return "True";
+ }
+ llvm_unreachable("Booleans can only be assigned true/false");
+ }
+
+ /// Returns a string representation of the result status of a SAT check.
+ std::string debugString(Solver::Result::Status Status) {
+ switch (Status) {
+ case Solver::Result::Status::Satisfiable:
+ return "Satisfiable";
+ case Solver::Result::Status::Unsatisfiable:
+ return "Unsatisfiable";
+ case Solver::Result::Status::TimedOut:
+ return "TimedOut";
+ }
+ llvm_unreachable("Unhandled SAT check result status");
+ }
+
+ /// Returns the name assigned to `Atom`, either user-specified or created by
+ /// default rules (B0, B1, ...).
+ std::string getAtomName(const AtomicBoolValue *Atom) {
+ auto Entry = AtomNames.try_emplace(Atom, formatv("B{0}", Counter));
+ if (Entry.second) {
+ Counter++;
+ }
+ return Entry.first->second;
+ }
+
+ // Keep track of number of atoms without a user-specified name, used to assign
+ // non-repeating default names to such atoms.
+ size_t Counter;
+
+ // Keep track of names assigned to atoms.
+ llvm::DenseMap<const AtomicBoolValue *, std::string> AtomNames;
+};
+
+} // namespace
+
+std::string
+debugString(const BoolValue &B,
+ llvm::DenseMap<const AtomicBoolValue *, std::string> AtomNames) {
+ return DebugStringGenerator(std::move(AtomNames)).debugString(B);
+}
+
+std::string
+debugString(const std::vector<BoolValue *> &Constraints,
+ const Solver::Result &Result,
+ llvm::DenseMap<const AtomicBoolValue *, std::string> AtomNames) {
+ return DebugStringGenerator(std::move(AtomNames))
+ .debugString(Constraints, Result);
+}
+
+} // namespace dataflow
+} // namespace clang
diff --git a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp
index 6443fc1b6422..6ce9dd55914d 100644
--- a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp
+++ b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp
@@ -51,7 +51,7 @@ public:
assert(BlockIT != CFCtx.getStmtToBlock().end());
const auto &State = BlockToState[BlockIT->getSecond()->getBlockID()];
assert(State);
- return &State.getValue().Env;
+ return &State.value().Env;
}
private:
@@ -212,7 +212,7 @@ static TypeErasedDataflowAnalysisState computeBlockInputState(
if (!MaybePredState)
continue;
- TypeErasedDataflowAnalysisState PredState = MaybePredState.getValue();
+ TypeErasedDataflowAnalysisState PredState = MaybePredState.value();
if (ApplyBuiltinTransfer) {
if (const Stmt *PredTerminatorStmt = Pred->getTerminatorStmt()) {
const StmtToEnvMapImpl StmtToEnv(CFCtx, BlockStates);
@@ -370,7 +370,7 @@ runTypeErasedDataflowAnalysis(
transferBlock(CFCtx, BlockStates, *Block, InitEnv, Analysis);
if (OldBlockState &&
- Analysis.isEqualTypeErased(OldBlockState.getValue().Lattice,
+ Analysis.isEqualTypeErased(OldBlockState.value().Lattice,
NewBlockState.Lattice) &&
OldBlockState->Env.equivalentTo(NewBlockState.Env, Analysis)) {
// The state of `Block` didn't change after transfer so there's no need to
diff --git a/clang/lib/Analysis/FlowSensitive/WatchedLiteralsSolver.cpp b/clang/lib/Analysis/FlowSensitive/WatchedLiteralsSolver.cpp
index 0e6e70d6d5d4..6a3948bd1fea 100644
--- a/clang/lib/Analysis/FlowSensitive/WatchedLiteralsSolver.cpp
+++ b/clang/lib/Analysis/FlowSensitive/WatchedLiteralsSolver.cpp
@@ -120,7 +120,13 @@ struct BooleanFormula {
/// clauses in the formula start from the element at index 1.
std::vector<ClauseID> NextWatched;
- explicit BooleanFormula(Variable LargestVar) : LargestVar(LargestVar) {
+ /// Stores the variable identifier and value location for atomic booleans in
+ /// the formula.
+ llvm::DenseMap<Variable, AtomicBoolValue *> Atomics;
+
+ explicit BooleanFormula(Variable LargestVar,
+ llvm::DenseMap<Variable, AtomicBoolValue *> Atomics)
+ : LargestVar(LargestVar), Atomics(std::move(Atomics)) {
Clauses.push_back(0);
ClauseStarts.push_back(0);
NextWatched.push_back(0);
@@ -180,28 +186,47 @@ BooleanFormula buildBooleanFormula(const llvm::DenseSet<BoolValue *> &Vals) {
// Map each sub-value in `Vals` to a unique variable.
llvm::DenseMap<BoolValue *, Variable> SubValsToVar;
+ // Store variable identifiers and value location of atomic booleans.
+ llvm::DenseMap<Variable, AtomicBoolValue *> Atomics;
Variable NextVar = 1;
{
std::queue<BoolValue *> UnprocessedSubVals;
for (BoolValue *Val : Vals)
UnprocessedSubVals.push(Val);
while (!UnprocessedSubVals.empty()) {
+ Variable Var = NextVar;
BoolValue *Val = UnprocessedSubVals.front();
UnprocessedSubVals.pop();
- if (!SubValsToVar.try_emplace(Val, NextVar).second)
+ if (!SubValsToVar.try_emplace(Val, Var).second)
continue;
++NextVar;
// Visit the sub-values of `Val`.
- if (auto *C = dyn_cast<ConjunctionValue>(Val)) {
+ switch (Val->getKind()) {
+ case Value::Kind::Conjunction: {
+ auto *C = cast<ConjunctionValue>(Val);
UnprocessedSubVals.push(&C->getLeftSubValue());
UnprocessedSubVals.push(&C->getRightSubValue());
- } else if (auto *D = dyn_cast<DisjunctionValue>(Val)) {
+ break;
+ }
+ case Value::Kind::Disjunction: {
+ auto *D = cast<DisjunctionValue>(Val);
UnprocessedSubVals.push(&D->getLeftSubValue());
UnprocessedSubVals.push(&D->getRightSubValue());
- } else if (auto *N = dyn_cast<NegationValue>(Val)) {
+ break;
+ }
+ case Value::Kind::Negation: {
+ auto *N = cast<NegationValue>(Val);
UnprocessedSubVals.push(&N->getSubVal());
+ break;
+ }
+ case Value::Kind::AtomicBool: {
+ Atomics[Var] = cast<AtomicBoolValue>(Val);
+ break;
+ }
+ default:
+ llvm_unreachable("buildBooleanFormula: unhandled value kind");
}
}
}
@@ -212,7 +237,7 @@ BooleanFormula buildBooleanFormula(const llvm::DenseSet<BoolValue *> &Vals) {
return ValIt->second;
};
- BooleanFormula Formula(NextVar - 1);
+ BooleanFormula Formula(NextVar - 1, std::move(Atomics));
std::vector<bool> ProcessedSubVals(NextVar, false);
// Add a conjunct for each variable that represents a top-level conjunction
@@ -383,7 +408,7 @@ public:
// If the root level is reached, then all possible assignments lead to
// a conflict.
if (Level == 0)
- return WatchedLiteralsSolver::Result::Unsatisfiable;
+ return Solver::Result::Unsatisfiable();
// Otherwise, take the other branch at the most recent level where a
// decision was made.
@@ -440,12 +465,29 @@ public:
++I;
}
}
- return WatchedLiteralsSolver::Result::Satisfiable;
+ return Solver::Result::Satisfiable(buildSolution());
}
private:
- // Reverses forced moves until the most recent level where a decision was made
- // on the assignment of a variable.
+ /// Returns a satisfying truth assignment to the atomic values in the boolean
+ /// formula.
+ llvm::DenseMap<AtomicBoolValue *, Solver::Result::Assignment>
+ buildSolution() {
+ llvm::DenseMap<AtomicBoolValue *, Solver::Result::Assignment> Solution;
+ for (auto &Atomic : Formula.Atomics) {
+ // A variable may have a definite true/false assignment, or it may be
+ // unassigned indicating its truth value does not affect the result of
+ // the formula. Unassigned variables are assigned to true as a default.
+ Solution[Atomic.second] =
+ VarAssignments[Atomic.first] == Assignment::AssignedFalse
+ ? Solver::Result::Assignment::AssignedFalse
+ : Solver::Result::Assignment::AssignedTrue;
+ }
+ return Solution;
+ }
+
+ /// Reverses forced moves until the most recent level where a decision was
+ /// made on the assignment of a variable.
void reverseForcedMoves() {
for (; LevelStates[Level] == State::Forced; --Level) {
const Variable Var = LevelVars[Level];
@@ -459,7 +501,7 @@ private:
}
}
- // Updates watched literals that are affected by a variable assignment.
+ /// Updates watched literals that are affected by a variable assignment.
void updateWatchedLiterals() {
const Variable Var = LevelVars[Level];
@@ -592,7 +634,7 @@ private:
};
Solver::Result WatchedLiteralsSolver::solve(llvm::DenseSet<BoolValue *> Vals) {
- return Vals.empty() ? WatchedLiteralsSolver::Result::Satisfiable
+ return Vals.empty() ? Solver::Result::Satisfiable({{}})
: WatchedLiteralsSolverImpl(Vals).solve();
}
diff --git a/clang/lib/Analysis/PathDiagnostic.cpp b/clang/lib/Analysis/PathDiagnostic.cpp
index 8a7305000746..bb5f116d6940 100644
--- a/clang/lib/Analysis/PathDiagnostic.cpp
+++ b/clang/lib/Analysis/PathDiagnostic.cpp
@@ -320,7 +320,7 @@ static Optional<bool> comparePath(const PathPieces &X, const PathPieces &Y) {
for ( ; X_I != X_end && Y_I != Y_end; ++X_I, ++Y_I) {
Optional<bool> b = comparePiece(**X_I, **Y_I);
if (b)
- return b.getValue();
+ return b.value();
}
return None;
@@ -397,7 +397,7 @@ static bool compare(const PathDiagnostic &X, const PathDiagnostic &Y) {
}
Optional<bool> b = comparePath(X.path, Y.path);
assert(b);
- return b.getValue();
+ return b.value();
}
void PathDiagnosticConsumer::FlushDiagnostics(
diff --git a/clang/lib/Analysis/UninitializedValues.cpp b/clang/lib/Analysis/UninitializedValues.cpp
index 800943a99d87..7f44685355e0 100644
--- a/clang/lib/Analysis/UninitializedValues.cpp
+++ b/clang/lib/Analysis/UninitializedValues.cpp
@@ -149,7 +149,7 @@ public:
const VarDecl *vd) {
const Optional<unsigned> &idx = declToIndex.getValueIndex(vd);
assert(idx);
- return getValueVector(block)[idx.getValue()];
+ return getValueVector(block)[idx.value()];
}
};
@@ -210,7 +210,7 @@ void CFGBlockValues::resetScratch() {
ValueVector::reference CFGBlockValues::operator[](const VarDecl *vd) {
const Optional<unsigned> &idx = declToIndex.getValueIndex(vd);
assert(idx);
- return scratch[idx.getValue()];
+ return scratch[idx.value()];
}
//------------------------------------------------------------------------====//
diff --git a/clang/lib/Basic/LangStandards.cpp b/clang/lib/Basic/LangStandards.cpp
index 5bacc3b16496..a21898dd3c62 100644
--- a/clang/lib/Basic/LangStandards.cpp
+++ b/clang/lib/Basic/LangStandards.cpp
@@ -61,8 +61,8 @@ LangStandard::Kind clang::getDefaultLanguageStandard(clang::Language Lang,
if (CLANG_DEFAULT_STD_C != LangStandard::lang_unspecified)
return CLANG_DEFAULT_STD_C;
- // The PS4 and PS5 use C99 as the default C standard.
- if (T.isPS())
+ // The PS4 uses C99 as the default C standard.
+ if (T.isPS4())
return LangStandard::lang_gnu99;
return LangStandard::lang_gnu17;
case Language::ObjC:
diff --git a/clang/lib/Basic/MakeSupport.cpp b/clang/lib/Basic/MakeSupport.cpp
new file mode 100644
index 000000000000..37838f7bbc7b
--- /dev/null
+++ b/clang/lib/Basic/MakeSupport.cpp
@@ -0,0 +1,35 @@
+//===-- MakeSuport.cpp --------------------------------------------------*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/MakeSupport.h"
+
+void clang::quoteMakeTarget(StringRef Target, SmallVectorImpl<char> &Res) {
+ for (unsigned i = 0, e = Target.size(); i != e; ++i) {
+ switch (Target[i]) {
+ case ' ':
+ case '\t':
+ // Escape the preceding backslashes
+ for (int j = i - 1; j >= 0 && Target[j] == '\\'; --j)
+ Res.push_back('\\');
+
+ // Escape the space/tab
+ Res.push_back('\\');
+ break;
+ case '$':
+ Res.push_back('$');
+ break;
+ case '#':
+ Res.push_back('\\');
+ break;
+ default:
+ break;
+ }
+
+ Res.push_back(Target[i]);
+ }
+} \ No newline at end of file
diff --git a/clang/lib/Basic/TargetInfo.cpp b/clang/lib/Basic/TargetInfo.cpp
index e22ed34e7da4..6685145ea6d2 100644
--- a/clang/lib/Basic/TargetInfo.cpp
+++ b/clang/lib/Basic/TargetInfo.cpp
@@ -503,7 +503,7 @@ bool TargetInfo::initFeatureMap(
TargetInfo::CallingConvKind
TargetInfo::getCallingConvKind(bool ClangABICompat4) const {
if (getCXXABI() != TargetCXXABI::Microsoft &&
- (ClangABICompat4 || getTriple().getOS() == llvm::Triple::PS4))
+ (ClangABICompat4 || getTriple().isPS4()))
return CCK_ClangABI4OrPS4;
return CCK_Default;
}
diff --git a/clang/lib/Basic/Targets/RISCV.cpp b/clang/lib/Basic/Targets/RISCV.cpp
index 32dd2bad2c5c..cb2cdb50e18e 100644
--- a/clang/lib/Basic/Targets/RISCV.cpp
+++ b/clang/lib/Basic/Targets/RISCV.cpp
@@ -252,7 +252,7 @@ bool RISCVTargetInfo::hasFeature(StringRef Feature) const {
.Case("64bit", Is64Bit)
.Default(None);
if (Result)
- return Result.getValue();
+ return Result.value();
if (ISAInfo->isSupportedExtensionFeature(Feature))
return ISAInfo->hasExtension(Feature);
diff --git a/clang/lib/Basic/Targets/SystemZ.h b/clang/lib/Basic/Targets/SystemZ.h
index d12045c756c1..e4f242e624cb 100644
--- a/clang/lib/Basic/Targets/SystemZ.h
+++ b/clang/lib/Basic/Targets/SystemZ.h
@@ -123,6 +123,14 @@ public:
void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override;
+ bool isValidTuneCPUName(StringRef Name) const override {
+ return isValidCPUName(Name);
+ }
+
+ void fillValidTuneCPUList(SmallVectorImpl<StringRef> &Values) const override {
+ fillValidCPUList(Values);
+ }
+
bool setCPU(const std::string &Name) override {
CPU = Name;
ISARevision = getISARevision(CPU);
diff --git a/clang/lib/Basic/Targets/X86.cpp b/clang/lib/Basic/Targets/X86.cpp
index 06988830eaed..69afdf8a3584 100644
--- a/clang/lib/Basic/Targets/X86.cpp
+++ b/clang/lib/Basic/Targets/X86.cpp
@@ -297,6 +297,8 @@ bool X86TargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
HasCLDEMOTE = true;
} else if (Feature == "+rdpid") {
HasRDPID = true;
+ } else if (Feature == "+rdpru") {
+ HasRDPRU = true;
} else if (Feature == "+kl") {
HasKL = true;
} else if (Feature == "+widekl") {
@@ -743,6 +745,8 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
Builder.defineMacro("__WIDEKL__");
if (HasRDPID)
Builder.defineMacro("__RDPID__");
+ if (HasRDPRU)
+ Builder.defineMacro("__RDPRU__");
if (HasCLDEMOTE)
Builder.defineMacro("__CLDEMOTE__");
if (HasWAITPKG)
@@ -926,6 +930,7 @@ bool X86TargetInfo::isValidFeatureName(StringRef Name) const {
.Case("prfchw", true)
.Case("ptwrite", true)
.Case("rdpid", true)
+ .Case("rdpru", true)
.Case("rdrnd", true)
.Case("rdseed", true)
.Case("rtm", true)
@@ -1021,6 +1026,7 @@ bool X86TargetInfo::hasFeature(StringRef Feature) const {
.Case("prfchw", HasPRFCHW)
.Case("ptwrite", HasPTWRITE)
.Case("rdpid", HasRDPID)
+ .Case("rdpru", HasRDPRU)
.Case("rdrnd", HasRDRND)
.Case("rdseed", HasRDSEED)
.Case("retpoline-external-thunk", HasRetpolineExternalThunk)
diff --git a/clang/lib/Basic/Targets/X86.h b/clang/lib/Basic/Targets/X86.h
index 78e444f4e4eb..ea98dcf42de6 100644
--- a/clang/lib/Basic/Targets/X86.h
+++ b/clang/lib/Basic/Targets/X86.h
@@ -125,6 +125,7 @@ class LLVM_LIBRARY_VISIBILITY X86TargetInfo : public TargetInfo {
bool HasMOVBE = false;
bool HasPREFETCHWT1 = false;
bool HasRDPID = false;
+ bool HasRDPRU = false;
bool HasRetpolineExternalThunk = false;
bool HasLAHFSAHF = false;
bool HasWBNOINVD = false;
@@ -420,8 +421,8 @@ public:
// Use fpret for all types.
RealTypeUsesObjCFPRetMask =
- (int)(FloatModeKind::Float | FloatModeKind::Double |
- FloatModeKind::LongDouble);
+ (unsigned)(FloatModeKind::Float | FloatModeKind::Double |
+ FloatModeKind::LongDouble);
// x86-32 has atomics up to 8 bytes
MaxAtomicPromoteWidth = 64;
@@ -700,7 +701,7 @@ public:
"64-i64:64-f80:128-n8:16:32:64-S128");
// Use fpret only for long double.
- RealTypeUsesObjCFPRetMask = (int)FloatModeKind::LongDouble;
+ RealTypeUsesObjCFPRetMask = (unsigned)FloatModeKind::LongDouble;
// Use fp2ret for _Complex long double.
ComplexLongDoubleUsesFP2Ret = true;
diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp
index eb40e446057f..7c4e35634e5d 100644
--- a/clang/lib/CodeGen/BackendUtil.cpp
+++ b/clang/lib/CodeGen/BackendUtil.cpp
@@ -788,6 +788,18 @@ void EmitAssemblyHelper::RunOptimizationPipeline(
SI.registerCallbacks(PIC, &FAM);
PassBuilder PB(TM.get(), PTO, PGOOpt, &PIC);
+ // Enable verify-debuginfo-preserve-each for new PM.
+ DebugifyEachInstrumentation Debugify;
+ DebugInfoPerPass DebugInfoBeforePass;
+ if (CodeGenOpts.EnableDIPreservationVerify) {
+ Debugify.setDebugifyMode(DebugifyMode::OriginalDebugInfo);
+ Debugify.setDebugInfoBeforePass(DebugInfoBeforePass);
+
+ if (!CodeGenOpts.DIBugsReportFilePath.empty())
+ Debugify.setOrigDIVerifyBugsReportFilePath(
+ CodeGenOpts.DIBugsReportFilePath);
+ Debugify.registerCallbacks(PIC);
+ }
// Attempt to load pass plugins and register their callbacks with PB.
for (auto &PluginFN : CodeGenOpts.PassPlugins) {
auto PassPlugin = PassPlugin::Load(PluginFN);
diff --git a/clang/lib/CodeGen/CGCUDANV.cpp b/clang/lib/CodeGen/CGCUDANV.cpp
index 6f2679cb15e4..a8bb0dd65d1a 100644
--- a/clang/lib/CodeGen/CGCUDANV.cpp
+++ b/clang/lib/CodeGen/CGCUDANV.cpp
@@ -212,8 +212,7 @@ static std::unique_ptr<MangleContext> InitDeviceMC(CodeGenModule &CGM) {
CGNVCUDARuntime::CGNVCUDARuntime(CodeGenModule &CGM)
: CGCUDARuntime(CGM), Context(CGM.getLLVMContext()),
TheModule(CGM.getModule()),
- RelocatableDeviceCode(CGM.getLangOpts().GPURelocatableDeviceCode ||
- CGM.getLangOpts().OffloadingNewDriver),
+ RelocatableDeviceCode(CGM.getLangOpts().GPURelocatableDeviceCode),
DeviceMC(InitDeviceMC(CGM)) {
CodeGen::CodeGenTypes &Types = CGM.getTypes();
ASTContext &Ctx = CGM.getContext();
@@ -1116,7 +1115,8 @@ void CGNVCUDARuntime::createOffloadingEntries() {
llvm::OpenMPIRBuilder OMPBuilder(CGM.getModule());
OMPBuilder.initialize();
- StringRef Section = "cuda_offloading_entries";
+ StringRef Section = CGM.getLangOpts().HIP ? "hip_offloading_entries"
+ : "cuda_offloading_entries";
for (KernelInfo &I : EmittedKernels)
OMPBuilder.emitOffloadingEntry(KernelHandles[I.Kernel],
getDeviceSideName(cast<NamedDecl>(I.D)), 0,
@@ -1171,10 +1171,11 @@ llvm::Function *CGNVCUDARuntime::finalizeModule() {
}
return nullptr;
}
- if (!(CGM.getLangOpts().OffloadingNewDriver && RelocatableDeviceCode))
+ if (CGM.getLangOpts().OffloadingNewDriver && RelocatableDeviceCode)
+ createOffloadingEntries();
+ else
return makeModuleCtorFunction();
- createOffloadingEntries();
return nullptr;
}
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index 4e26c35c6342..104a30dd6b25 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -1931,6 +1931,9 @@ void CodeGenModule::getDefaultFunctionAttributes(StringRef Name,
FuncAttrs.addAttribute(llvm::Attribute::Convergent);
}
+ // TODO: NoUnwind attribute should be added for other GPU modes OpenCL, HIP,
+ // SYCL, OpenMP offload. AFAIK, none of them support exceptions in device
+ // code.
if (getLangOpts().CUDA && getLangOpts().CUDAIsDevice) {
// Exceptions aren't supported in CUDA device code.
FuncAttrs.addAttribute(llvm::Attribute::NoUnwind);
diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp
index 153f299a1c4b..cde31711a7db 100644
--- a/clang/lib/CodeGen/CGClass.cpp
+++ b/clang/lib/CodeGen/CGClass.cpp
@@ -1783,14 +1783,14 @@ namespace {
StartIndex = FieldIndex;
} else if (StartIndex) {
EHStack.pushCleanup<SanitizeDtorFieldRange>(
- NormalAndEHCleanup, DD, StartIndex.getValue(), FieldIndex);
+ NormalAndEHCleanup, DD, StartIndex.value(), FieldIndex);
StartIndex = None;
}
}
void End() {
if (StartIndex)
EHStack.pushCleanup<SanitizeDtorFieldRange>(NormalAndEHCleanup, DD,
- StartIndex.getValue(), -1);
+ StartIndex.value(), -1);
}
};
} // end anonymous namespace
diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp
index 305040b01c08..091eb9da5af4 100644
--- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp
+++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp
@@ -6717,11 +6717,9 @@ llvm::Value *CGOpenMPRuntime::emitNumTeamsForTargetDirective(
default:
break;
}
- } else if (DefaultNT == -1) {
- return nullptr;
}
- return Bld.getInt32(DefaultNT);
+ return llvm::ConstantInt::get(CGF.Int32Ty, DefaultNT);
}
static llvm::Value *getNumThreads(CodeGenFunction &CGF, const CapturedStmt *CS,
@@ -10189,9 +10187,8 @@ llvm::Function *CGOpenMPRuntime::getOrCreateUserDefinedMapperFunc(
return UDMMap.lookup(D);
}
-void CGOpenMPRuntime::emitTargetNumIterationsCall(
+llvm::Value *CGOpenMPRuntime::emitTargetNumIterationsCall(
CodeGenFunction &CGF, const OMPExecutableDirective &D,
- llvm::Value *DeviceID,
llvm::function_ref<llvm::Value *(CodeGenFunction &CGF,
const OMPLoopDirective &D)>
SizeEmitter) {
@@ -10201,20 +10198,12 @@ void CGOpenMPRuntime::emitTargetNumIterationsCall(
if (!isOpenMPDistributeDirective(Kind) || !isOpenMPTeamsDirective(Kind))
TD = getNestedDistributeDirective(CGM.getContext(), D);
if (!TD)
- return;
+ return llvm::ConstantInt::get(CGF.Int64Ty, 0);
+
const auto *LD = cast<OMPLoopDirective>(TD);
- auto &&CodeGen = [LD, DeviceID, SizeEmitter, &D, this](CodeGenFunction &CGF,
- PrePostActionTy &) {
- if (llvm::Value *NumIterations = SizeEmitter(CGF, *LD)) {
- llvm::Value *RTLoc = emitUpdateLocation(CGF, D.getBeginLoc());
- llvm::Value *Args[] = {RTLoc, DeviceID, NumIterations};
- CGF.EmitRuntimeCall(
- OMPBuilder.getOrCreateRuntimeFunction(
- CGM.getModule(), OMPRTL___kmpc_push_target_tripcount_mapper),
- Args);
- }
- };
- emitInlinedDirective(CGF, OMPD_unknown, CodeGen);
+ if (llvm::Value *NumIterations = SizeEmitter(CGF, *LD))
+ return NumIterations;
+ return llvm::ConstantInt::get(CGF.Int64Ty, 0);
}
void CGOpenMPRuntime::emitTargetCall(
@@ -10308,26 +10297,34 @@ void CGOpenMPRuntime::emitTargetCall(
// Source location for the ident struct
llvm::Value *RTLoc = emitUpdateLocation(CGF, D.getBeginLoc());
- // Emit tripcount for the target loop-based directive.
- emitTargetNumIterationsCall(CGF, D, DeviceID, SizeEmitter);
+ // Get tripcount for the target loop-based directive.
+ llvm::Value *NumIterations =
+ emitTargetNumIterationsCall(CGF, D, SizeEmitter);
+
+ // Arguments for the target kernel.
+ SmallVector<llvm::Value *> KernelArgs{
+ CGF.Builder.getInt32(/* Version */ 1),
+ PointerNum,
+ InputInfo.BasePointersArray.getPointer(),
+ InputInfo.PointersArray.getPointer(),
+ InputInfo.SizesArray.getPointer(),
+ MapTypesArray,
+ MapNamesArray,
+ InputInfo.MappersArray.getPointer(),
+ NumIterations};
+
+ // Arguments passed to the 'nowait' variant.
+ SmallVector<llvm::Value *> NoWaitKernelArgs{
+ CGF.Builder.getInt32(0),
+ llvm::ConstantPointerNull::get(CGM.VoidPtrTy),
+ CGF.Builder.getInt32(0),
+ llvm::ConstantPointerNull::get(CGM.VoidPtrTy),
+ };
+
+ bool HasNoWait = D.hasClausesOfKind<OMPNowaitClause>();
- bool HasNowait = D.hasClausesOfKind<OMPNowaitClause>();
// The target region is an outlined function launched by the runtime
- // via calls __tgt_target() or __tgt_target_teams().
- //
- // __tgt_target() launches a target region with one team and one thread,
- // executing a serial region. This master thread may in turn launch
- // more threads within its team upon encountering a parallel region,
- // however, no additional teams can be launched on the device.
- //
- // __tgt_target_teams() launches a target region with one or more teams,
- // each with one or more threads. This call is required for target
- // constructs such as:
- // 'target teams'
- // 'target' / 'teams'
- // 'target teams distribute parallel for'
- // 'target parallel'
- // and so on.
+ // via calls to __tgt_target_kernel().
//
// Note that on the host and CPU targets, the runtime implementation of
// these calls simply call the outlined function without forking threads.
@@ -10338,70 +10335,15 @@ void CGOpenMPRuntime::emitTargetCall(
// In contrast, on the NVPTX target, the implementation of
// __tgt_target_teams() launches a GPU kernel with the requested number
// of teams and threads so no additional calls to the runtime are required.
- if (NumTeams) {
- // If we have NumTeams defined this means that we have an enclosed teams
- // region. Therefore we also expect to have NumThreads defined. These two
- // values should be defined in the presence of a teams directive,
- // regardless of having any clauses associated. If the user is using teams
- // but no clauses, these two values will be the default that should be
- // passed to the runtime library - a 32-bit integer with the value zero.
- assert(NumThreads && "Thread limit expression should be available along "
- "with number of teams.");
- SmallVector<llvm::Value *> OffloadingArgs = {
- RTLoc,
- DeviceID,
- OutlinedFnID,
- PointerNum,
- InputInfo.BasePointersArray.getPointer(),
- InputInfo.PointersArray.getPointer(),
- InputInfo.SizesArray.getPointer(),
- MapTypesArray,
- MapNamesArray,
- InputInfo.MappersArray.getPointer(),
- NumTeams,
- NumThreads};
- if (HasNowait) {
- // Add int32_t depNum = 0, void *depList = nullptr, int32_t
- // noAliasDepNum = 0, void *noAliasDepList = nullptr.
- OffloadingArgs.push_back(CGF.Builder.getInt32(0));
- OffloadingArgs.push_back(llvm::ConstantPointerNull::get(CGM.VoidPtrTy));
- OffloadingArgs.push_back(CGF.Builder.getInt32(0));
- OffloadingArgs.push_back(llvm::ConstantPointerNull::get(CGM.VoidPtrTy));
- }
- Return = CGF.EmitRuntimeCall(
- OMPBuilder.getOrCreateRuntimeFunction(
- CGM.getModule(), HasNowait
- ? OMPRTL___tgt_target_teams_nowait_mapper
- : OMPRTL___tgt_target_teams_mapper),
- OffloadingArgs);
- } else {
- SmallVector<llvm::Value *> OffloadingArgs = {
- RTLoc,
- DeviceID,
- OutlinedFnID,
- PointerNum,
- InputInfo.BasePointersArray.getPointer(),
- InputInfo.PointersArray.getPointer(),
- InputInfo.SizesArray.getPointer(),
- MapTypesArray,
- MapNamesArray,
- InputInfo.MappersArray.getPointer()};
- if (HasNowait) {
- // Add int32_t depNum = 0, void *depList = nullptr, int32_t
- // noAliasDepNum = 0, void *noAliasDepList = nullptr.
- OffloadingArgs.push_back(CGF.Builder.getInt32(0));
- OffloadingArgs.push_back(llvm::ConstantPointerNull::get(CGM.VoidPtrTy));
- OffloadingArgs.push_back(CGF.Builder.getInt32(0));
- OffloadingArgs.push_back(llvm::ConstantPointerNull::get(CGM.VoidPtrTy));
- }
- Return = CGF.EmitRuntimeCall(
- OMPBuilder.getOrCreateRuntimeFunction(
- CGM.getModule(), HasNowait ? OMPRTL___tgt_target_nowait_mapper
- : OMPRTL___tgt_target_mapper),
- OffloadingArgs);
- }
-
// Check the error code and execute the host version if required.
+ CGF.Builder.restoreIP(
+ HasNoWait ? OMPBuilder.emitTargetKernel(
+ CGF.Builder, Return, RTLoc, DeviceID, NumTeams,
+ NumThreads, OutlinedFnID, KernelArgs, NoWaitKernelArgs)
+ : OMPBuilder.emitTargetKernel(CGF.Builder, Return, RTLoc,
+ DeviceID, NumTeams, NumThreads,
+ OutlinedFnID, KernelArgs));
+
llvm::BasicBlock *OffloadFailedBlock =
CGF.createBasicBlock("omp_offload.failed");
llvm::BasicBlock *OffloadContBlock =
diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.h b/clang/lib/CodeGen/CGOpenMPRuntime.h
index 7fc6a7e278e5..b95aef68335e 100644
--- a/clang/lib/CodeGen/CGOpenMPRuntime.h
+++ b/clang/lib/CodeGen/CGOpenMPRuntime.h
@@ -884,13 +884,11 @@ private:
llvm::Function *TaskFunction, QualType SharedsTy,
Address Shareds, const OMPTaskDataTy &Data);
- /// Emit code that pushes the trip count of loops associated with constructs
- /// 'target teams distribute' and 'teams distribute parallel for'.
- /// \param SizeEmitter Emits the int64 value for the number of iterations of
- /// the associated loop.
- void emitTargetNumIterationsCall(
+ /// Return the trip count of loops associated with constructs / 'target teams
+ /// distribute' and 'teams distribute parallel for'. \param SizeEmitter Emits
+ /// the int64 value for the number of iterations of the associated loop.
+ llvm::Value *emitTargetNumIterationsCall(
CodeGenFunction &CGF, const OMPExecutableDirective &D,
- llvm::Value *DeviceID,
llvm::function_ref<llvm::Value *(CodeGenFunction &CGF,
const OMPLoopDirective &D)>
SizeEmitter);
diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp
index 301f5278df69..db0b2ffd3a4f 100644
--- a/clang/lib/CodeGen/CGStmtOpenMP.cpp
+++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp
@@ -2591,11 +2591,12 @@ static void emitOMPSimdRegion(CodeGenFunction &CGF, const OMPLoopDirective &S,
}
}
-static bool isSupportedByOpenMPIRBuilder(const OMPExecutableDirective &S) {
+static bool isSupportedByOpenMPIRBuilder(const OMPSimdDirective &S) {
// Check for unsupported clauses
- if (!S.clauses().empty()) {
- // Currently no clause is supported
- return false;
+ for (OMPClause *C : S.clauses()) {
+ // Currently only simdlen clause is supported
+ if (!isa<OMPSimdlenClause>(C))
+ return false;
}
// Check if we have a statement with the ordered directive.
@@ -2630,7 +2631,6 @@ void CodeGenFunction::EmitOMPSimdDirective(const OMPSimdDirective &S) {
// Use the OpenMPIRBuilder if enabled.
if (UseOMPIRBuilder) {
// Emit the associated statement and get its loop representation.
- llvm::DebugLoc DL = SourceLocToDebugLoc(S.getBeginLoc());
const Stmt *Inner = S.getRawStmt();
llvm::CanonicalLoopInfo *CLI =
EmitOMPCollapsedCanonicalLoopNest(Inner, 1);
@@ -2638,7 +2638,15 @@ void CodeGenFunction::EmitOMPSimdDirective(const OMPSimdDirective &S) {
llvm::OpenMPIRBuilder &OMPBuilder =
CGM.getOpenMPRuntime().getOMPBuilder();
// Add SIMD specific metadata
- OMPBuilder.applySimd(DL, CLI);
+ llvm::ConstantInt *Simdlen = nullptr;
+ if (const auto *C = S.getSingleClause<OMPSimdlenClause>()) {
+ RValue Len =
+ this->EmitAnyExpr(C->getSimdlen(), AggValueSlot::ignored(),
+ /*ignoreResult=*/true);
+ auto *Val = cast<llvm::ConstantInt>(Len.getScalarVal());
+ Simdlen = Val;
+ }
+ OMPBuilder.applySimd(CLI, Simdlen);
return;
}
};
@@ -5998,18 +6006,26 @@ static std::pair<bool, RValue> emitOMPAtomicRMW(CodeGenFunction &CGF, LValue X,
RMWOp = llvm::AtomicRMWInst::Xor;
break;
case BO_LT:
- RMWOp = X.getType()->hasSignedIntegerRepresentation()
- ? (IsXLHSInRHSPart ? llvm::AtomicRMWInst::Min
- : llvm::AtomicRMWInst::Max)
- : (IsXLHSInRHSPart ? llvm::AtomicRMWInst::UMin
- : llvm::AtomicRMWInst::UMax);
+ if (IsInteger)
+ RMWOp = X.getType()->hasSignedIntegerRepresentation()
+ ? (IsXLHSInRHSPart ? llvm::AtomicRMWInst::Min
+ : llvm::AtomicRMWInst::Max)
+ : (IsXLHSInRHSPart ? llvm::AtomicRMWInst::UMin
+ : llvm::AtomicRMWInst::UMax);
+ else
+ RMWOp = IsXLHSInRHSPart ? llvm::AtomicRMWInst::FMin
+ : llvm::AtomicRMWInst::FMax;
break;
case BO_GT:
- RMWOp = X.getType()->hasSignedIntegerRepresentation()
- ? (IsXLHSInRHSPart ? llvm::AtomicRMWInst::Max
- : llvm::AtomicRMWInst::Min)
- : (IsXLHSInRHSPart ? llvm::AtomicRMWInst::UMax
- : llvm::AtomicRMWInst::UMin);
+ if (IsInteger)
+ RMWOp = X.getType()->hasSignedIntegerRepresentation()
+ ? (IsXLHSInRHSPart ? llvm::AtomicRMWInst::Max
+ : llvm::AtomicRMWInst::Min)
+ : (IsXLHSInRHSPart ? llvm::AtomicRMWInst::UMax
+ : llvm::AtomicRMWInst::UMin);
+ else
+ RMWOp = IsXLHSInRHSPart ? llvm::AtomicRMWInst::FMax
+ : llvm::AtomicRMWInst::FMin;
break;
case BO_Assign:
RMWOp = llvm::AtomicRMWInst::Xchg;
diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp
index 05942f462dd1..17c1c91c7e8f 100644
--- a/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -898,6 +898,20 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
if (D && D->hasAttr<NoProfileFunctionAttr>())
Fn->addFnAttr(llvm::Attribute::NoProfile);
+ if (D) {
+ // Function attributes take precedence over command line flags.
+ if (auto *A = D->getAttr<FunctionReturnThunksAttr>()) {
+ switch (A->getThunkType()) {
+ case FunctionReturnThunksAttr::Kind::Keep:
+ break;
+ case FunctionReturnThunksAttr::Kind::Extern:
+ Fn->addFnAttr(llvm::Attribute::FnRetThunkExtern);
+ break;
+ }
+ } else if (CGM.getCodeGenOpts().FunctionReturnThunks)
+ Fn->addFnAttr(llvm::Attribute::FnRetThunkExtern);
+ }
+
if (FD && (getLangOpts().OpenCL ||
(getLangOpts().HIP && getLangOpts().CUDAIsDevice))) {
// Add metadata for a kernel function.
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 56ed59d1e3f1..c372bab1eccb 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -445,6 +445,7 @@ void CodeGenModule::checkAliases() {
void CodeGenModule::clear() {
DeferredDeclsToEmit.clear();
+ EmittedDeferredDecls.clear();
if (OpenMPRuntime)
OpenMPRuntime->clear();
}
@@ -510,6 +511,9 @@ static void setVisibilityFromDLLStorageClass(const clang::LangOptions &LO,
void CodeGenModule::Release() {
EmitDeferred();
+ DeferredDecls.insert(EmittedDeferredDecls.begin(),
+ EmittedDeferredDecls.end());
+ EmittedDeferredDecls.clear();
EmitVTablesOpportunistically();
applyGlobalValReplacements();
applyReplacements();
@@ -900,6 +904,9 @@ void CodeGenModule::Release() {
if (!getCodeGenOpts().StackProtectorGuardReg.empty())
getModule().setStackProtectorGuardReg(
getCodeGenOpts().StackProtectorGuardReg);
+ if (!getCodeGenOpts().StackProtectorGuardSymbol.empty())
+ getModule().setStackProtectorGuardSymbol(
+ getCodeGenOpts().StackProtectorGuardSymbol);
if (getCodeGenOpts().StackProtectorGuardOffset != INT_MAX)
getModule().setStackProtectorGuardOffset(
getCodeGenOpts().StackProtectorGuardOffset);
@@ -4286,6 +4293,9 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName, llvm::Type *Ty,
getCUDARuntime().handleVarRegistration(D, *GV);
}
+ if (D)
+ SanitizerMD->reportGlobal(GV, *D);
+
LangAS ExpectedAS =
D ? D->getType().getAddressSpace()
: (LangOpts.OpenCL ? LangAS::opencl_global : LangAS::Default);
diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h
index da43b9616c88..10b49da27dab 100644
--- a/clang/lib/CodeGen/CodeGenModule.h
+++ b/clang/lib/CodeGen/CodeGenModule.h
@@ -344,6 +344,20 @@ private:
std::vector<GlobalDecl> DeferredDeclsToEmit;
void addDeferredDeclToEmit(GlobalDecl GD) {
DeferredDeclsToEmit.emplace_back(GD);
+ addEmittedDeferredDecl(GD);
+ }
+
+ /// Decls that were DeferredDecls and have now been emitted.
+ llvm::DenseMap<llvm::StringRef, GlobalDecl> EmittedDeferredDecls;
+
+ void addEmittedDeferredDecl(GlobalDecl GD) {
+ if (!llvm::isa<FunctionDecl>(GD.getDecl()))
+ return;
+ llvm::GlobalVariable::LinkageTypes L = getFunctionLinkage(GD);
+ if (llvm::GlobalValue::isLinkOnceLinkage(L) ||
+ llvm::GlobalValue::isWeakLinkage(L)) {
+ EmittedDeferredDecls[getMangledName(GD)] = GD;
+ }
}
/// List of alias we have emitted. Used to make sure that what they point to
@@ -1516,6 +1530,11 @@ public:
NewBuilder->WeakRefReferences = std::move(WeakRefReferences);
NewBuilder->TBAA = std::move(TBAA);
+
+ assert(NewBuilder->EmittedDeferredDecls.empty() &&
+ "Still have (unmerged) EmittedDeferredDecls deferred decls");
+
+ NewBuilder->EmittedDeferredDecls = std::move(EmittedDeferredDecls);
}
private:
diff --git a/clang/lib/CodeGen/CodeGenTBAA.cpp b/clang/lib/CodeGen/CodeGenTBAA.cpp
index 95763d8e18b7..0cb63fbbe9e5 100644
--- a/clang/lib/CodeGen/CodeGenTBAA.cpp
+++ b/clang/lib/CodeGen/CodeGenTBAA.cpp
@@ -335,7 +335,42 @@ llvm::MDNode *CodeGenTBAA::getBaseTypeInfoHelper(const Type *Ty) {
if (auto *TTy = dyn_cast<RecordType>(Ty)) {
const RecordDecl *RD = TTy->getDecl()->getDefinition();
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
- SmallVector<llvm::MDBuilder::TBAAStructField, 4> Fields;
+ using TBAAStructField = llvm::MDBuilder::TBAAStructField;
+ SmallVector<TBAAStructField, 4> Fields;
+ if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
+ // Handle C++ base classes. Non-virtual bases can treated a a kind of
+ // field. Virtual bases are more complex and omitted, but avoid an
+ // incomplete view for NewStructPathTBAA.
+ if (CodeGenOpts.NewStructPathTBAA && CXXRD->getNumVBases() != 0)
+ return BaseTypeMetadataCache[Ty] = nullptr;
+ for (const CXXBaseSpecifier &B : CXXRD->bases()) {
+ if (B.isVirtual())
+ continue;
+ QualType BaseQTy = B.getType();
+ const CXXRecordDecl *BaseRD = BaseQTy->getAsCXXRecordDecl();
+ if (BaseRD->isEmpty())
+ continue;
+ llvm::MDNode *TypeNode = isValidBaseType(BaseQTy)
+ ? getBaseTypeInfo(BaseQTy)
+ : getTypeInfo(BaseQTy);
+ if (!TypeNode)
+ return BaseTypeMetadataCache[Ty] = nullptr;
+ uint64_t Offset = Layout.getBaseClassOffset(BaseRD).getQuantity();
+ uint64_t Size =
+ Context.getASTRecordLayout(BaseRD).getDataSize().getQuantity();
+ Fields.push_back(
+ llvm::MDBuilder::TBAAStructField(Offset, Size, TypeNode));
+ }
+ // The order in which base class subobjects are allocated is unspecified,
+ // so may differ from declaration order. In particular, Itanium ABI will
+ // allocate a primary base first.
+ // Since we exclude empty subobjects, the objects are not overlapping and
+ // their offsets are unique.
+ llvm::sort(Fields,
+ [](const TBAAStructField &A, const TBAAStructField &B) {
+ return A.Offset < B.Offset;
+ });
+ }
for (FieldDecl *Field : RD->fields()) {
if (Field->isZeroSize(Context) || Field->isUnnamedBitfield())
continue;
diff --git a/clang/lib/CodeGen/SanitizerMetadata.cpp b/clang/lib/CodeGen/SanitizerMetadata.cpp
index 5f4eb9be981f..7848cf012633 100644
--- a/clang/lib/CodeGen/SanitizerMetadata.cpp
+++ b/clang/lib/CodeGen/SanitizerMetadata.cpp
@@ -60,17 +60,17 @@ void SanitizerMetadata::reportGlobal(llvm::GlobalVariable *GV,
Meta.NoHWAddress |= CGM.isInNoSanitizeList(
FsanitizeArgument.Mask & SanitizerKind::HWAddress, GV, Loc, Ty);
- Meta.NoMemtag |= NoSanitizeAttrSet.hasOneOf(SanitizerKind::MemTag);
- Meta.NoMemtag |= CGM.isInNoSanitizeList(
+ Meta.Memtag |=
+ static_cast<bool>(FsanitizeArgument.Mask & SanitizerKind::MemtagGlobals);
+ Meta.Memtag &= !NoSanitizeAttrSet.hasOneOf(SanitizerKind::MemTag);
+ Meta.Memtag &= !CGM.isInNoSanitizeList(
FsanitizeArgument.Mask & SanitizerKind::MemTag, GV, Loc, Ty);
- if (FsanitizeArgument.has(SanitizerKind::Address)) {
- // TODO(hctim): Make this conditional when we migrate off llvm.asan.globals.
- IsDynInit &= !CGM.isInNoSanitizeList(SanitizerKind::Address |
- SanitizerKind::KernelAddress,
- GV, Loc, Ty, "init");
- Meta.IsDynInit = IsDynInit;
- }
+ Meta.IsDynInit = IsDynInit && !Meta.NoAddress &&
+ FsanitizeArgument.has(SanitizerKind::Address) &&
+ !CGM.isInNoSanitizeList(SanitizerKind::Address |
+ SanitizerKind::KernelAddress,
+ GV, Loc, Ty, "init");
GV->setSanitizerMetadata(Meta);
}
diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp
index 0da32dae2ef6..3a8400a55741 100644
--- a/clang/lib/Driver/Driver.cpp
+++ b/clang/lib/Driver/Driver.cpp
@@ -2930,7 +2930,7 @@ class OffloadingActionBuilder final {
return false;
Relocatable = Args.hasFlag(options::OPT_fgpu_rdc,
- options::OPT_fno_gpu_rdc, /*Default=*/false);
+ options::OPT_fno_gpu_rdc, /*Default=*/false);
const ToolChain *HostTC = C.getSingleOffloadToolChain<Action::OFK_Host>();
assert(HostTC && "No toolchain for host compilation.");
@@ -3326,7 +3326,7 @@ class OffloadingActionBuilder final {
AssociatedOffloadKind);
if (CompileDeviceOnly && CurPhase == FinalPhase && BundleOutput &&
- BundleOutput.getValue()) {
+ BundleOutput.value()) {
for (unsigned I = 0, E = GpuArchList.size(); I != E; ++I) {
OffloadAction::DeviceDependences DDep;
DDep.add(*CudaDeviceActions[I], *ToolChains.front(), GpuArchList[I],
@@ -4355,7 +4355,17 @@ Driver::getOffloadArchs(Compilation &C, const llvm::opt::DerivedArgList &Args,
return KnownArchs.lookup(TC);
llvm::DenseSet<StringRef> Archs;
- for (auto &Arg : Args) {
+ for (auto *Arg : Args) {
+ // Extract any '--[no-]offload-arch' arguments intended for this toolchain.
+ std::unique_ptr<llvm::opt::Arg> ExtractedArg = nullptr;
+ if (Arg->getOption().matches(options::OPT_Xopenmp_target_EQ) &&
+ ToolChain::getOpenMPTriple(Arg->getValue(0)) == TC->getTriple()) {
+ Arg->claim();
+ unsigned Index = Args.getBaseArgs().MakeIndex(Arg->getValue(1));
+ ExtractedArg = getOpts().ParseOneArg(Args, Index);
+ Arg = ExtractedArg.get();
+ }
+
if (Arg->getOption().matches(options::OPT_offload_arch_EQ)) {
for (StringRef Arch : llvm::split(Arg->getValue(), ","))
Archs.insert(getCanonicalArchString(C, Args, Arch, TC->getTriple()));
@@ -4425,8 +4435,7 @@ Action *Driver::BuildOffloadingActions(Compilation &C,
// Get the product of all bound architectures and toolchains.
SmallVector<std::pair<const ToolChain *, StringRef>> TCAndArchs;
for (const ToolChain *TC : ToolChains)
- for (StringRef Arch : getOffloadArchs(
- C, C.getArgsForToolChain(TC, "generic", Kind), Kind, TC))
+ for (StringRef Arch : getOffloadArchs(C, Args, Kind, TC))
TCAndArchs.push_back(std::make_pair(TC, Arch));
for (unsigned I = 0, E = TCAndArchs.size(); I != E; ++I)
@@ -4477,11 +4486,23 @@ Action *Driver::BuildOffloadingActions(Compilation &C,
if (offloadDeviceOnly())
return C.MakeAction<OffloadAction>(DDeps, types::TY_Nothing);
- Action *OffloadPackager =
- C.MakeAction<OffloadPackagerJobAction>(OffloadActions, types::TY_Image);
OffloadAction::DeviceDependences DDep;
- DDep.add(*OffloadPackager, *C.getSingleOffloadToolChain<Action::OFK_Host>(),
- nullptr, Action::OFK_None);
+ if (C.isOffloadingHostKind(Action::OFK_Cuda) &&
+ !Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, false)) {
+ // If we are not in RDC-mode we just emit the final CUDA fatbinary for each
+ // translation unit without requiring any linking.
+ Action *FatbinAction =
+ C.MakeAction<LinkJobAction>(OffloadActions, types::TY_CUDA_FATBIN);
+ DDep.add(*FatbinAction, *C.getSingleOffloadToolChain<Action::OFK_Cuda>(),
+ nullptr, Action::OFK_Cuda);
+ } else {
+ // Package all the offloading actions into a single output that can be
+ // embedded in the host and linked.
+ Action *PackagerAction =
+ C.MakeAction<OffloadPackagerJobAction>(OffloadActions, types::TY_Image);
+ DDep.add(*PackagerAction, *C.getSingleOffloadToolChain<Action::OFK_Host>(),
+ nullptr, Action::OFK_None);
+ }
OffloadAction::HostDependence HDep(
*HostAction, *C.getSingleOffloadToolChain<Action::OFK_Host>(),
/*BoundArch=*/nullptr, isa<CompileJobAction>(HostAction) ? DDep : DDeps);
diff --git a/clang/lib/Driver/ToolChains/AVR.cpp b/clang/lib/Driver/ToolChains/AVR.cpp
index 1e866553d826..89d408823270 100644
--- a/clang/lib/Driver/ToolChains/AVR.cpp
+++ b/clang/lib/Driver/ToolChains/AVR.cpp
@@ -437,7 +437,6 @@ void AVR::Linker::ConstructJob(Compilation &C, const JobAction &JA,
: getToolChain().GetProgramPath(getShortName());
ArgStringList CmdArgs;
- AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
@@ -476,8 +475,8 @@ void AVR::Linker::ConstructJob(Compilation &C, const JobAction &JA,
}
if (SectionAddressData) {
- std::string DataSectionArg = std::string("-Tdata=0x") +
- llvm::utohexstr(SectionAddressData.getValue());
+ std::string DataSectionArg =
+ std::string("-Tdata=0x") + llvm::utohexstr(SectionAddressData.value());
CmdArgs.push_back(Args.MakeArgString(DataSectionArg));
} else {
// We do not have an entry for this CPU in the address mapping table yet.
@@ -503,6 +502,7 @@ void AVR::Linker::ConstructJob(Compilation &C, const JobAction &JA,
// Add the link library specific to the MCU.
CmdArgs.push_back(Args.MakeArgString(std::string("-l") + CPU));
+ AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);
CmdArgs.push_back("--end-group");
// Add user specified linker script.
@@ -514,6 +514,8 @@ void AVR::Linker::ConstructJob(Compilation &C, const JobAction &JA,
// than the bare minimum supports.
if (Linker.find("avr-ld") != std::string::npos)
CmdArgs.push_back(Args.MakeArgString(std::string("-m") + *FamilyName));
+ } else {
+ AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);
}
C.addCommand(std::make_unique<Command>(
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index c9bbdb2ac72e..97435f1a73de 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -27,6 +27,7 @@
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/CodeGenOptions.h"
#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/MakeSupport.h"
#include "clang/Basic/ObjCRuntime.h"
#include "clang/Basic/Version.h"
#include "clang/Config/config.h"
@@ -51,6 +52,7 @@
#include "llvm/Support/Process.h"
#include "llvm/Support/TargetParser.h"
#include "llvm/Support/YAMLParser.h"
+#include <cctype>
using namespace clang::driver;
using namespace clang::driver::tools;
@@ -97,34 +99,6 @@ static void EscapeSpacesAndBackslashes(const char *Arg,
}
}
-// Quote target names for inclusion in GNU Make dependency files.
-// Only the characters '$', '#', ' ', '\t' are quoted.
-static void QuoteTarget(StringRef Target, SmallVectorImpl<char> &Res) {
- for (unsigned i = 0, e = Target.size(); i != e; ++i) {
- switch (Target[i]) {
- case ' ':
- case '\t':
- // Escape the preceding backslashes
- for (int j = i - 1; j >= 0 && Target[j] == '\\'; --j)
- Res.push_back('\\');
-
- // Escape the space/tab
- Res.push_back('\\');
- break;
- case '$':
- Res.push_back('$');
- break;
- case '#':
- Res.push_back('\\');
- break;
- default:
- break;
- }
-
- Res.push_back(Target[i]);
- }
-}
-
/// Apply \a Work on the current tool chain \a RegularToolChain and any other
/// offloading tool chain that is associated with the current action \a JA.
static void
@@ -567,7 +541,7 @@ static bool useFramePointerForTargetByDefault(const ArgList &Args,
break;
}
- if (Triple.isOSNetBSD()) {
+ if (Triple.isOSFuchsia() || Triple.isOSNetBSD()) {
return !areOptimizationsEnabled(Args);
}
@@ -1144,7 +1118,7 @@ static void RenderDebugInfoCompressionArgs(const ArgList &Args,
if (Value == "none") {
CmdArgs.push_back("--compress-debug-sections=none");
} else if (Value == "zlib") {
- if (llvm::zlib::isAvailable()) {
+ if (llvm::compression::zlib::isAvailable()) {
CmdArgs.push_back(
Args.MakeArgString("--compress-debug-sections=" + Twine(Value)));
} else {
@@ -1249,7 +1223,7 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA,
} else {
CmdArgs.push_back("-MT");
SmallString<128> Quoted;
- QuoteTarget(A->getValue(), Quoted);
+ quoteMakeTarget(A->getValue(), Quoted);
CmdArgs.push_back(Args.MakeArgString(Quoted));
}
}
@@ -1274,7 +1248,7 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-MT");
SmallString<128> Quoted;
- QuoteTarget(DepTarget, Quoted);
+ quoteMakeTarget(DepTarget, Quoted);
CmdArgs.push_back(Args.MakeArgString(Quoted));
}
@@ -2228,8 +2202,23 @@ void Clang::AddSparcTargetArgs(const ArgList &Args,
void Clang::AddSystemZTargetArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
- bool HasBackchain = Args.hasFlag(options::OPT_mbackchain,
- options::OPT_mno_backchain, false);
+ if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_mtune_EQ)) {
+ StringRef Name = A->getValue();
+
+ std::string TuneCPU;
+ if (Name == "native")
+ TuneCPU = std::string(llvm::sys::getHostCPUName());
+ else
+ TuneCPU = std::string(Name);
+
+ if (!TuneCPU.empty()) {
+ CmdArgs.push_back("-tune-cpu");
+ CmdArgs.push_back(Args.MakeArgString(TuneCPU));
+ }
+ }
+
+ bool HasBackchain =
+ Args.hasFlag(options::OPT_mbackchain, options::OPT_mno_backchain, false);
bool HasPackedStack = Args.hasFlag(options::OPT_mpacked_stack,
options::OPT_mno_packed_stack, false);
systemz::FloatABI FloatABI =
@@ -2341,7 +2330,7 @@ void Clang::AddHexagonTargetArgs(const ArgList &Args,
if (auto G = toolchains::HexagonToolChain::getSmallDataThreshold(Args)) {
CmdArgs.push_back("-mllvm");
CmdArgs.push_back(Args.MakeArgString("-hexagon-small-data-threshold=" +
- Twine(G.getValue())));
+ Twine(G.value())));
}
if (!Args.hasArg(options::OPT_fno_short_enums))
@@ -3231,6 +3220,16 @@ static void RenderAnalyzerOptions(const ArgList &Args, ArgStringList &CmdArgs,
Args.AddAllArgValues(CmdArgs, options::OPT_Xanalyzer);
}
+static bool isValidSymbolName(StringRef S) {
+ if (S.empty())
+ return false;
+
+ if (std::isdigit(S[0]))
+ return false;
+
+ return llvm::all_of(S, [](char C) { return std::isalnum(C) || C == '_'; });
+}
+
static void RenderSSPOptions(const Driver &D, const ToolChain &TC,
const ArgList &Args, ArgStringList &CmdArgs,
bool KernelOrKext) {
@@ -3362,6 +3361,16 @@ static void RenderSSPOptions(const Driver &D, const ToolChain &TC,
}
A->render(Args, CmdArgs);
}
+
+ if (Arg *A = Args.getLastArg(options::OPT_mstack_protector_guard_symbol_EQ)) {
+ StringRef Value = A->getValue();
+ if (!isValidSymbolName(Value)) {
+ D.Diag(diag::err_drv_argument_only_allowed_with)
+ << A->getOption().getName() << "legal symbol name";
+ return;
+ }
+ A->render(Args, CmdArgs);
+ }
}
static void RenderSCPOptions(const ToolChain &TC, const ArgList &Args,
@@ -3750,38 +3759,49 @@ static void RenderModulesOptions(Compilation &C, const Driver &D,
Args.AddLastArg(CmdArgs, options::OPT_fmodules_prune_interval);
Args.AddLastArg(CmdArgs, options::OPT_fmodules_prune_after);
- Args.AddLastArg(CmdArgs, options::OPT_fbuild_session_timestamp);
+ if (HaveClangModules) {
+ Args.AddLastArg(CmdArgs, options::OPT_fbuild_session_timestamp);
- if (Arg *A = Args.getLastArg(options::OPT_fbuild_session_file)) {
- if (Args.hasArg(options::OPT_fbuild_session_timestamp))
- D.Diag(diag::err_drv_argument_not_allowed_with)
- << A->getAsString(Args) << "-fbuild-session-timestamp";
+ if (Arg *A = Args.getLastArg(options::OPT_fbuild_session_file)) {
+ if (Args.hasArg(options::OPT_fbuild_session_timestamp))
+ D.Diag(diag::err_drv_argument_not_allowed_with)
+ << A->getAsString(Args) << "-fbuild-session-timestamp";
- llvm::sys::fs::file_status Status;
- if (llvm::sys::fs::status(A->getValue(), Status))
- D.Diag(diag::err_drv_no_such_file) << A->getValue();
- CmdArgs.push_back(Args.MakeArgString(
- "-fbuild-session-timestamp=" +
- Twine((uint64_t)std::chrono::duration_cast<std::chrono::seconds>(
- Status.getLastModificationTime().time_since_epoch())
- .count())));
- }
+ llvm::sys::fs::file_status Status;
+ if (llvm::sys::fs::status(A->getValue(), Status))
+ D.Diag(diag::err_drv_no_such_file) << A->getValue();
+ CmdArgs.push_back(Args.MakeArgString(
+ "-fbuild-session-timestamp=" +
+ Twine((uint64_t)std::chrono::duration_cast<std::chrono::seconds>(
+ Status.getLastModificationTime().time_since_epoch())
+ .count())));
+ }
- if (Args.getLastArg(options::OPT_fmodules_validate_once_per_build_session)) {
- if (!Args.getLastArg(options::OPT_fbuild_session_timestamp,
- options::OPT_fbuild_session_file))
- D.Diag(diag::err_drv_modules_validate_once_requires_timestamp);
+ if (Args.getLastArg(
+ options::OPT_fmodules_validate_once_per_build_session)) {
+ if (!Args.getLastArg(options::OPT_fbuild_session_timestamp,
+ options::OPT_fbuild_session_file))
+ D.Diag(diag::err_drv_modules_validate_once_requires_timestamp);
- Args.AddLastArg(CmdArgs,
- options::OPT_fmodules_validate_once_per_build_session);
- }
+ Args.AddLastArg(CmdArgs,
+ options::OPT_fmodules_validate_once_per_build_session);
+ }
- if (Args.hasFlag(options::OPT_fmodules_validate_system_headers,
- options::OPT_fno_modules_validate_system_headers,
- ImplicitModules))
- CmdArgs.push_back("-fmodules-validate-system-headers");
+ if (Args.hasFlag(options::OPT_fmodules_validate_system_headers,
+ options::OPT_fno_modules_validate_system_headers,
+ ImplicitModules))
+ CmdArgs.push_back("-fmodules-validate-system-headers");
- Args.AddLastArg(CmdArgs, options::OPT_fmodules_disable_diagnostic_validation);
+ Args.AddLastArg(CmdArgs,
+ options::OPT_fmodules_disable_diagnostic_validation);
+ } else {
+ Args.ClaimAllArgs(options::OPT_fbuild_session_timestamp);
+ Args.ClaimAllArgs(options::OPT_fbuild_session_file);
+ Args.ClaimAllArgs(options::OPT_fmodules_validate_once_per_build_session);
+ Args.ClaimAllArgs(options::OPT_fmodules_validate_system_headers);
+ Args.ClaimAllArgs(options::OPT_fno_modules_validate_system_headers);
+ Args.ClaimAllArgs(options::OPT_fmodules_disable_diagnostic_validation);
+ }
}
static void RenderCharacterOptions(const ArgList &Args, const llvm::Triple &T,
@@ -4422,12 +4442,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.hasFlag(options::OPT_offload_new_driver,
options::OPT_no_offload_new_driver, false));
+ bool IsRDCMode =
+ Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, false);
bool IsUsingLTO = D.isUsingLTO(IsDeviceOffloadAction);
auto LTOMode = D.getLTOMode(IsDeviceOffloadAction);
// A header module compilation doesn't have a main input file, so invent a
// fake one as a placeholder.
- const char *ModuleName = [&]{
+ const char *ModuleName = [&] {
auto *ModuleNameArg = Args.getLastArg(options::OPT_fmodule_name_EQ);
return ModuleNameArg ? ModuleNameArg->getValue() : "";
}();
@@ -6285,10 +6307,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
}
if (IsCuda || IsHIP) {
- if (!Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, false) &&
- Args.hasArg(options::OPT_offload_new_driver))
- D.Diag(diag::err_drv_no_rdc_new_driver);
- if (Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, false))
+ if (IsRDCMode)
CmdArgs.push_back("-fgpu-rdc");
if (Args.hasFlag(options::OPT_fgpu_defer_diag,
options::OPT_fno_gpu_defer_diag, false))
@@ -6313,6 +6332,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (IsUsingLTO)
Args.AddLastArg(CmdArgs, options::OPT_mibt_seal);
+ if (Arg *A = Args.getLastArg(options::OPT_mfunction_return_EQ))
+ CmdArgs.push_back(
+ Args.MakeArgString(Twine("-mfunction-return=") + A->getValue()));
+
// Forward -f options with positive and negative forms; we translate these by
// hand. Do not propagate PGO options to the GPU-side compilations as the
// profile info is for the host-side compilation only.
@@ -6956,13 +6979,22 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
}
}
- // Host-side cuda compilation receives all device-side outputs in a single
- // fatbin as Inputs[1]. Include the binary with -fcuda-include-gpubinary.
+ // Host-side offloading compilation receives all device-side outputs. Include
+ // them in the host compilation depending on the target. If the host inputs
+ // are not empty we use the new-driver scheme, otherwise use the old scheme.
if ((IsCuda || IsHIP) && CudaDeviceInput) {
+ CmdArgs.push_back("-fcuda-include-gpubinary");
+ CmdArgs.push_back(CudaDeviceInput->getFilename());
+ } else if (!HostOffloadingInputs.empty()) {
+ if (IsCuda && !IsRDCMode) {
+ assert(HostOffloadingInputs.size() == 1 && "Only one input expected");
CmdArgs.push_back("-fcuda-include-gpubinary");
- CmdArgs.push_back(CudaDeviceInput->getFilename());
- if (Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, false))
- CmdArgs.push_back("-fgpu-rdc");
+ CmdArgs.push_back(HostOffloadingInputs.front().getFilename());
+ } else {
+ for (const InputInfo Input : HostOffloadingInputs)
+ CmdArgs.push_back(Args.MakeArgString("-fembed-offload-object=" +
+ TC.getInputFilename(Input)));
+ }
}
if (IsCuda) {
@@ -7011,12 +7043,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
}
}
- // Host-side offloading recieves the device object files and embeds it in a
- // named section including the associated target triple and architecture.
- for (const InputInfo Input : HostOffloadingInputs)
- CmdArgs.push_back(Args.MakeArgString("-fembed-offload-object=" +
- TC.getInputFilename(Input)));
-
if (Triple.isAMDGPU()) {
handleAMDGPUCodeObjectVersionOptions(D, Args, CmdArgs);
@@ -8314,7 +8340,8 @@ void OffloadPackager::ConstructJob(Compilation &C, const JobAction &JA,
ArgStringList Features;
SmallVector<StringRef> FeatureArgs;
- getTargetFeatures(TC->getDriver(), TC->getTriple(), Args, Features, false);
+ getTargetFeatures(TC->getDriver(), TC->getTriple(), TCArgs, Features,
+ false);
llvm::copy_if(Features, std::back_inserter(FeatureArgs),
[](StringRef Arg) { return !Arg.startswith("-target"); });
@@ -8382,7 +8409,7 @@ void LinkerWrapper::ConstructJob(Compilation &C, const JobAction &JA,
for (StringRef LibName : BCLibs)
CmdArgs.push_back(Args.MakeArgString(
- "-target-library=" + Action::GetOffloadKindName(Action::OFK_OpenMP) +
+ "--bitcode-library=" + Action::GetOffloadKindName(Action::OFK_OpenMP) +
"-" + TC->getTripleString() + "-" + Arch + "=" + LibName));
}
@@ -8402,63 +8429,64 @@ void LinkerWrapper::ConstructJob(Compilation &C, const JobAction &JA,
} else if (A->getOption().matches(options::OPT_O0))
OOpt = "0";
if (!OOpt.empty())
- CmdArgs.push_back(Args.MakeArgString(Twine("-opt-level=O") + OOpt));
+ CmdArgs.push_back(Args.MakeArgString(Twine("--opt-level=O") + OOpt));
}
}
- CmdArgs.push_back("-host-triple");
- CmdArgs.push_back(Args.MakeArgString(TheTriple.getTriple()));
+ CmdArgs.push_back(
+ Args.MakeArgString("--host-triple=" + TheTriple.getTriple()));
if (Args.hasArg(options::OPT_v))
- CmdArgs.push_back("-v");
+ CmdArgs.push_back("--verbose");
- // Add debug information if present.
if (const Arg *A = Args.getLastArg(options::OPT_g_Group)) {
- const Option &Opt = A->getOption();
- if (Opt.matches(options::OPT_gN_Group)) {
- if (Opt.matches(options::OPT_gline_directives_only) ||
- Opt.matches(options::OPT_gline_tables_only))
- CmdArgs.push_back("-gline-directives-only");
- } else
- CmdArgs.push_back("-g");
+ if (!A->getOption().matches(options::OPT_g0))
+ CmdArgs.push_back("--device-debug");
}
for (const auto &A : Args.getAllArgValues(options::OPT_Xcuda_ptxas))
- CmdArgs.push_back(Args.MakeArgString("-ptxas-args=" + A));
+ CmdArgs.push_back(Args.MakeArgString("--ptxas-args=" + A));
// Forward remarks passes to the LLVM backend in the wrapper.
if (const Arg *A = Args.getLastArg(options::OPT_Rpass_EQ))
CmdArgs.push_back(
- Args.MakeArgString(Twine("-pass-remarks=") + A->getValue()));
+ Args.MakeArgString(Twine("--pass-remarks=") + A->getValue()));
if (const Arg *A = Args.getLastArg(options::OPT_Rpass_missed_EQ))
CmdArgs.push_back(
- Args.MakeArgString(Twine("-pass-remarks-missed=") + A->getValue()));
+ Args.MakeArgString(Twine("--pass-remarks-missed=") + A->getValue()));
if (const Arg *A = Args.getLastArg(options::OPT_Rpass_analysis_EQ))
CmdArgs.push_back(
- Args.MakeArgString(Twine("-pass-remarks-analysis=") + A->getValue()));
+ Args.MakeArgString(Twine("--pass-remarks-analysis=") + A->getValue()));
if (Args.getLastArg(options::OPT_save_temps_EQ))
- CmdArgs.push_back("-save-temps");
+ CmdArgs.push_back("--save-temps");
// Construct the link job so we can wrap around it.
Linker->ConstructJob(C, JA, Output, Inputs, Args, LinkingOutput);
const auto &LinkCommand = C.getJobs().getJobs().back();
// Forward -Xoffload-linker<-triple> arguments to the device link job.
- for (auto *Arg : Args.filtered(options::OPT_Xoffload_linker)) {
- StringRef Val = Arg->getValue(0);
+ for (Arg *A : Args.filtered(options::OPT_Xoffload_linker)) {
+ StringRef Val = A->getValue(0);
if (Val.empty())
CmdArgs.push_back(
- Args.MakeArgString(Twine("-device-linker=") + Arg->getValue(1)));
+ Args.MakeArgString(Twine("--device-linker=") + A->getValue(1)));
else
CmdArgs.push_back(Args.MakeArgString(
- "-device-linker=" +
+ "--device-linker=" +
ToolChain::getOpenMPTriple(Val.drop_front()).getTriple() + "=" +
- Arg->getValue(1)));
+ A->getValue(1)));
}
Args.ClaimAllArgs(options::OPT_Xoffload_linker);
+ // Forward `-mllvm` arguments to the LLVM invocations if present.
+ for (Arg *A : Args.filtered(options::OPT_mllvm)) {
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back(A->getValue());
+ A->claim();
+ }
+
// Add the linker arguments to be forwarded by the wrapper.
- CmdArgs.push_back("-linker-path");
- CmdArgs.push_back(LinkCommand->getExecutable());
+ CmdArgs.push_back(Args.MakeArgString(Twine("--linker-path=") +
+ LinkCommand->getExecutable()));
CmdArgs.push_back("--");
for (const char *LinkArg : LinkCommand->getArguments())
CmdArgs.push_back(LinkArg);
diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp
index 2d53b829b01c..1d2c085d683e 100644
--- a/clang/lib/Driver/ToolChains/CommonArgs.cpp
+++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp
@@ -727,7 +727,8 @@ bool tools::addOpenMPRuntime(ArgStringList &CmdArgs, const ToolChain &TC,
if (IsOffloadingHost)
CmdArgs.push_back("-lomptarget");
- if (IsOffloadingHost && TC.getDriver().isUsingLTO(/* IsOffload */ true))
+ if (IsOffloadingHost && TC.getDriver().isUsingLTO(/* IsOffload */ true) &&
+ !Args.hasArg(options::OPT_nogpulib))
CmdArgs.push_back("-lomptarget.devicertl");
addArchSpecificRPath(TC, Args, CmdArgs);
diff --git a/clang/lib/Driver/ToolChains/Darwin.cpp b/clang/lib/Driver/ToolChains/Darwin.cpp
index 0a8a9c6eb6ff..c9e773701ac3 100644
--- a/clang/lib/Driver/ToolChains/Darwin.cpp
+++ b/clang/lib/Driver/ToolChains/Darwin.cpp
@@ -1551,10 +1551,10 @@ struct DarwinPlatform {
options::ID Opt;
switch (Platform) {
case DarwinPlatformKind::MacOS:
- Opt = options::OPT_mmacosx_version_min_EQ;
+ Opt = options::OPT_mmacos_version_min_EQ;
break;
case DarwinPlatformKind::IPhoneOS:
- Opt = options::OPT_miphoneos_version_min_EQ;
+ Opt = options::OPT_mios_version_min_EQ;
break;
case DarwinPlatformKind::TvOS:
Opt = options::OPT_mtvos_version_min_EQ;
@@ -1727,8 +1727,8 @@ private:
Optional<DarwinPlatform>
getDeploymentTargetFromOSVersionArg(DerivedArgList &Args,
const Driver &TheDriver) {
- Arg *OSXVersion = Args.getLastArg(options::OPT_mmacosx_version_min_EQ);
- Arg *iOSVersion = Args.getLastArg(options::OPT_miphoneos_version_min_EQ,
+ Arg *macOSVersion = Args.getLastArg(options::OPT_mmacos_version_min_EQ);
+ Arg *iOSVersion = Args.getLastArg(options::OPT_mios_version_min_EQ,
options::OPT_mios_simulator_version_min_EQ);
Arg *TvOSVersion =
Args.getLastArg(options::OPT_mtvos_version_min_EQ,
@@ -1736,15 +1736,15 @@ getDeploymentTargetFromOSVersionArg(DerivedArgList &Args,
Arg *WatchOSVersion =
Args.getLastArg(options::OPT_mwatchos_version_min_EQ,
options::OPT_mwatchos_simulator_version_min_EQ);
- if (OSXVersion) {
+ if (macOSVersion) {
if (iOSVersion || TvOSVersion || WatchOSVersion) {
TheDriver.Diag(diag::err_drv_argument_not_allowed_with)
- << OSXVersion->getAsString(Args)
+ << macOSVersion->getAsString(Args)
<< (iOSVersion ? iOSVersion
: TvOSVersion ? TvOSVersion : WatchOSVersion)
->getAsString(Args);
}
- return DarwinPlatform::createOSVersionArg(Darwin::MacOS, OSXVersion);
+ return DarwinPlatform::createOSVersionArg(Darwin::MacOS, macOSVersion);
} else if (iOSVersion) {
if (TvOSVersion || WatchOSVersion) {
TheDriver.Diag(diag::err_drv_argument_not_allowed_with)
diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp
index f52bb8af5ec9..34396b0b59c2 100644
--- a/clang/lib/Driver/ToolChains/Gnu.cpp
+++ b/clang/lib/Driver/ToolChains/Gnu.cpp
@@ -2087,7 +2087,7 @@ void Generic_GCC::GCCInstallationDetector::print(raw_ostream &OS) const {
bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const {
if (BiarchSibling) {
- M = BiarchSibling.getValue();
+ M = BiarchSibling.value();
return true;
}
return false;
diff --git a/clang/lib/Driver/ToolChains/Hexagon.cpp b/clang/lib/Driver/ToolChains/Hexagon.cpp
index 9142dba81d54..ed07e710fc49 100644
--- a/clang/lib/Driver/ToolChains/Hexagon.cpp
+++ b/clang/lib/Driver/ToolChains/Hexagon.cpp
@@ -340,8 +340,8 @@ constructHexagonLinkArgs(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-pie");
if (auto G = toolchains::HexagonToolChain::getSmallDataThreshold(Args)) {
- CmdArgs.push_back(Args.MakeArgString("-G" + Twine(G.getValue())));
- UseG0 = G.getValue() == 0;
+ CmdArgs.push_back(Args.MakeArgString("-G" + Twine(G.value())));
+ UseG0 = G.value() == 0;
}
CmdArgs.push_back("-o");
diff --git a/clang/lib/Driver/ToolChains/MinGW.cpp b/clang/lib/Driver/ToolChains/MinGW.cpp
index c4b4f8e9b89b..ae7c4c56bf9e 100644
--- a/clang/lib/Driver/ToolChains/MinGW.cpp
+++ b/clang/lib/Driver/ToolChains/MinGW.cpp
@@ -339,8 +339,9 @@ void tools::MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA,
// Simplified from Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple.
static bool findGccVersion(StringRef LibDir, std::string &GccLibDir,
- std::string &Ver) {
- auto Version = toolchains::Generic_GCC::GCCVersion::Parse("0.0.0");
+ std::string &Ver,
+ toolchains::Generic_GCC::GCCVersion &Version) {
+ Version = toolchains::Generic_GCC::GCCVersion::Parse("0.0.0");
std::error_code EC;
for (llvm::sys::fs::directory_iterator LI(LibDir, EC), LE; !EC && LI != LE;
LI = LI.increment(EC)) {
@@ -371,7 +372,7 @@ void toolchains::MinGW::findGccLibDir() {
for (StringRef CandidateSysroot : SubdirNames) {
llvm::SmallString<1024> LibDir(Base);
llvm::sys::path::append(LibDir, CandidateLib, "gcc", CandidateSysroot);
- if (findGccVersion(LibDir, GccLibDir, Ver)) {
+ if (findGccVersion(LibDir, GccLibDir, Ver, GccVer)) {
SubdirName = std::string(CandidateSysroot);
return;
}
@@ -438,6 +439,11 @@ toolchains::MinGW::MinGW(const Driver &D, const llvm::Triple &Triple,
getFilePaths().push_back(GccLibDir);
getFilePaths().push_back(
(Base + SubdirName + llvm::sys::path::get_separator() + "lib").str());
+
+ // Gentoo
+ getFilePaths().push_back(
+ (Base + SubdirName + llvm::sys::path::get_separator() + "mingw/lib").str());
+
getFilePaths().push_back(Base + "lib");
// openSUSE
getFilePaths().push_back(Base + SubdirName + "/sys-root/mingw/lib");
@@ -593,6 +599,11 @@ void toolchains::MinGW::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
addSystemInclude(DriverArgs, CC1Args,
Base + SubdirName + llvm::sys::path::get_separator() +
"include");
+
+ // Gentoo
+ addSystemInclude(DriverArgs, CC1Args,
+ Base + SubdirName + llvm::sys::path::get_separator() + "usr/include");
+
addSystemInclude(DriverArgs, CC1Args, Base + "include");
}
@@ -620,7 +631,7 @@ void toolchains::MinGW::AddClangCXXStdlibIncludeArgs(
}
case ToolChain::CST_Libstdcxx:
- llvm::SmallVector<llvm::SmallString<1024>, 4> CppIncludeBases;
+ llvm::SmallVector<llvm::SmallString<1024>, 7> CppIncludeBases;
CppIncludeBases.emplace_back(Base);
llvm::sys::path::append(CppIncludeBases[0], SubdirName, "include", "c++");
CppIncludeBases.emplace_back(Base);
@@ -630,6 +641,15 @@ void toolchains::MinGW::AddClangCXXStdlibIncludeArgs(
llvm::sys::path::append(CppIncludeBases[2], "include", "c++", Ver);
CppIncludeBases.emplace_back(GccLibDir);
llvm::sys::path::append(CppIncludeBases[3], "include", "c++");
+ CppIncludeBases.emplace_back(GccLibDir);
+ llvm::sys::path::append(CppIncludeBases[4], "include",
+ "g++-v" + GccVer.Text);
+ CppIncludeBases.emplace_back(GccLibDir);
+ llvm::sys::path::append(CppIncludeBases[5], "include",
+ "g++-v" + GccVer.MajorStr + "." + GccVer.MinorStr);
+ CppIncludeBases.emplace_back(GccLibDir);
+ llvm::sys::path::append(CppIncludeBases[6], "include",
+ "g++-v" + GccVer.MajorStr);
for (auto &CppIncludeBase : CppIncludeBases) {
addSystemInclude(DriverArgs, CC1Args, CppIncludeBase);
CppIncludeBase += Slash;
diff --git a/clang/lib/Driver/ToolChains/MinGW.h b/clang/lib/Driver/ToolChains/MinGW.h
index c9553b4f4652..f15f99dc8a8c 100644
--- a/clang/lib/Driver/ToolChains/MinGW.h
+++ b/clang/lib/Driver/ToolChains/MinGW.h
@@ -103,6 +103,7 @@ private:
std::string Base;
std::string GccLibDir;
+ clang::driver::toolchains::Generic_GCC::GCCVersion GccVer;
std::string Ver;
std::string SubdirName;
mutable std::unique_ptr<tools::gcc::Preprocessor> Preprocessor;
diff --git a/clang/lib/Driver/ToolChains/RISCVToolchain.cpp b/clang/lib/Driver/ToolChains/RISCVToolchain.cpp
index a048765bc6d3..3491de22d371 100644
--- a/clang/lib/Driver/ToolChains/RISCVToolchain.cpp
+++ b/clang/lib/Driver/ToolChains/RISCVToolchain.cpp
@@ -201,8 +201,11 @@ void RISCV::Linker::ConstructJob(Compilation &C, const JobAction &JA,
if (!Args.hasArg(options::OPT_nostdlib) &&
!Args.hasArg(options::OPT_nodefaultlibs)) {
- if (ToolChain.ShouldLinkCXXStdlib(Args))
- ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
+ if (D.CCCIsCXX()) {
+ if (ToolChain.ShouldLinkCXXStdlib(Args))
+ ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
+ CmdArgs.push_back("-lm");
+ }
CmdArgs.push_back("--start-group");
CmdArgs.push_back("-lc");
CmdArgs.push_back("-lgloss");
diff --git a/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp b/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
index c4797cea333f..709b781968bf 100644
--- a/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
+++ b/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
@@ -31,14 +31,14 @@ namespace {
/// at position \p Key.
void serializeObject(Object &Paren, StringRef Key, Optional<Object> Obj) {
if (Obj)
- Paren[Key] = std::move(Obj.getValue());
+ Paren[Key] = std::move(Obj.value());
}
/// Helper function to inject a JSON array \p Array into object \p Paren at
/// position \p Key.
void serializeArray(Object &Paren, StringRef Key, Optional<Array> Array) {
if (Array)
- Paren[Key] = std::move(Array.getValue());
+ Paren[Key] = std::move(Array.value());
}
/// Serialize a \c VersionTuple \p V with the Symbol Graph semantic version
diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp
index 2cb985cdc4e5..1cd28ab073da 100644
--- a/clang/lib/Format/ContinuationIndenter.cpp
+++ b/clang/lib/Format/ContinuationIndenter.cpp
@@ -37,7 +37,7 @@ static bool shouldIndentWrappedSelectorName(const FormatStyle &Style,
// Returns the length of everything up to the first possible line break after
// the ), ], } or > matching \c Tok.
static unsigned getLengthToMatchingParen(const FormatToken &Tok,
- const std::vector<ParenState> &Stack) {
+ const SmallVector<ParenState> &Stack) {
// Normally whether or not a break before T is possible is calculated and
// stored in T.CanBreakBefore. Braces, array initializers and text proto
// messages like `key: < ... >` are an exception: a break is possible
@@ -404,6 +404,7 @@ bool ContinuationIndenter::mustBreak(const LineState &State) {
(State.Column + State.Line->Last->TotalLength - Previous.TotalLength >
getColumnLimit(State) ||
CurrentState.BreakBeforeParameter) &&
+ (!Current.isTrailingComment() || Current.NewlinesBefore > 0) &&
(Style.AllowShortFunctionsOnASingleLine != FormatStyle::SFS_All ||
Style.BreakConstructorInitializers != FormatStyle::BCIS_BeforeColon ||
Style.ColumnLimit != 0)) {
@@ -793,6 +794,7 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
(Previous.is(tok::colon) && Previous.is(TT_ObjCMethodExpr)))) {
CurrentState.LastSpace = State.Column;
} else if (Previous.is(TT_CtorInitializerColon) &&
+ (!Current.isTrailingComment() || Current.NewlinesBefore > 0) &&
Style.BreakConstructorInitializers ==
FormatStyle::BCIS_AfterColon) {
CurrentState.Indent = State.Column;
@@ -1032,7 +1034,7 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State,
// be considered bin packing unless the relevant AllowAll option is false or
// this is a dict/object literal.
bool PreviousIsBreakingCtorInitializerColon =
- Previous.is(TT_CtorInitializerColon) &&
+ PreviousNonComment && PreviousNonComment->is(TT_CtorInitializerColon) &&
Style.BreakConstructorInitializers == FormatStyle::BCIS_AfterColon;
if (!(Previous.isOneOf(tok::l_paren, tok::l_brace, TT_BinaryOperator) ||
PreviousIsBreakingCtorInitializerColon) ||
diff --git a/clang/lib/Format/ContinuationIndenter.h b/clang/lib/Format/ContinuationIndenter.h
index 494a9727d5ed..620060e68861 100644
--- a/clang/lib/Format/ContinuationIndenter.h
+++ b/clang/lib/Format/ContinuationIndenter.h
@@ -434,7 +434,7 @@ struct LineState {
/// A stack keeping track of properties applying to parenthesis
/// levels.
- std::vector<ParenState> Stack;
+ SmallVector<ParenState> Stack;
/// Ignore the stack of \c ParenStates for state comparison.
///
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index 51526dc2a681..d13907faca43 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -2386,7 +2386,7 @@ private:
tooling::Replacements generateFixes() {
tooling::Replacements Fixes;
- std::vector<FormatToken *> Tokens;
+ SmallVector<FormatToken *> Tokens;
std::copy(DeletedTokens.begin(), DeletedTokens.end(),
std::back_inserter(Tokens));
@@ -2580,7 +2580,7 @@ struct JavaImportDirective {
StringRef Identifier;
StringRef Text;
unsigned Offset;
- std::vector<StringRef> AssociatedCommentLines;
+ SmallVector<StringRef> AssociatedCommentLines;
bool IsStatic;
};
@@ -2983,7 +2983,7 @@ tooling::Replacements sortJavaImports(const FormatStyle &Style, StringRef Code,
llvm::Regex ImportRegex(JavaImportRegexPattern);
SmallVector<StringRef, 4> Matches;
SmallVector<JavaImportDirective, 16> ImportsInBlock;
- std::vector<StringRef> AssociatedCommentLines;
+ SmallVector<StringRef> AssociatedCommentLines;
bool FormattingOff = false;
@@ -3433,17 +3433,19 @@ LangOptions getFormattingLangOpts(const FormatStyle &Style) {
}
const char *StyleOptionHelpDescription =
- "Coding style, currently supports:\n"
- " LLVM, GNU, Google, Chromium, Microsoft, Mozilla, WebKit.\n"
- "Use -style=file to load style configuration from\n"
- ".clang-format file located in one of the parent\n"
- "directories of the source file (or current\n"
- "directory for stdin).\n"
- "Use -style=file:<format_file_path> to explicitly specify\n"
- "the configuration file.\n"
- "Use -style=\"{key: value, ...}\" to set specific\n"
- "parameters, e.g.:\n"
- " -style=\"{BasedOnStyle: llvm, IndentWidth: 8}\"";
+ "Set coding style. <string> can be:\n"
+ "1. A preset: LLVM, GNU, Google, Chromium, Microsoft,\n"
+ " Mozilla, WebKit.\n"
+ "2. 'file' to load style configuration from a\n"
+ " .clang-format file in one of the parent directories\n"
+ " of the source file (for stdin, see --assume-filename).\n"
+ " If no .clang-format file is found, falls back to\n"
+ " --fallback-style.\n"
+ " --style=file is the default.\n"
+ "3. 'file:<format_file_path>' to explicitly specify\n"
+ " the configuration file.\n"
+ "4. \"{key: value, ...}\" to set specific parameters, e.g.:\n"
+ " --style=\"{BasedOnStyle: llvm, IndentWidth: 8}\"";
static FormatStyle::LanguageKind getLanguageByFileName(StringRef FileName) {
if (FileName.endswith(".java"))
@@ -3498,6 +3500,7 @@ FormatStyle::LanguageKind guessLanguage(StringRef FileName, StringRef Code) {
return GuessedLanguage;
}
+// Update StyleOptionHelpDescription above when changing this.
const char *DefaultFormatStyle = "file";
const char *DefaultFallbackStyle = "LLVM";
diff --git a/clang/lib/Format/FormatToken.cpp b/clang/lib/Format/FormatToken.cpp
index 2c0fee6975c2..832af463206c 100644
--- a/clang/lib/Format/FormatToken.cpp
+++ b/clang/lib/Format/FormatToken.cpp
@@ -264,7 +264,7 @@ void CommaSeparatedList::precomputeFormattingInfos(const FormatToken *Token) {
// We can never place more than ColumnLimit / 3 items in a row (because of the
// spaces and the comma).
unsigned MaxItems = Style.ColumnLimit / 3;
- std::vector<unsigned> MinSizeInColumn;
+ SmallVector<unsigned> MinSizeInColumn;
MinSizeInColumn.reserve(MaxItems);
for (unsigned Columns = 1; Columns <= MaxItems; ++Columns) {
ColumnFormat Format;
diff --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h
index b6cc021affae..73e32979853f 100644
--- a/clang/lib/Format/FormatToken.h
+++ b/clang/lib/Format/FormatToken.h
@@ -497,6 +497,15 @@ public:
// in a configured macro expansion.
llvm::Optional<MacroExpansion> MacroCtx;
+ /// When macro expansion introduces nodes with children, those are marked as
+ /// \c MacroParent.
+ /// FIXME: The formatting code currently hard-codes the assumption that
+ /// child nodes are introduced by blocks following an opening brace.
+ /// This is deeply baked into the code and disentangling this will require
+ /// signficant refactorings. \c MacroParent allows us to special-case the
+ /// cases in which we treat parents as block-openers for now.
+ bool MacroParent = false;
+
bool is(tok::TokenKind Kind) const { return Tok.is(Kind); }
bool is(TokenType TT) const { return getType() == TT; }
bool is(const IdentifierInfo *II) const {
diff --git a/clang/lib/Format/MacroCallReconstructor.cpp b/clang/lib/Format/MacroCallReconstructor.cpp
new file mode 100644
index 000000000000..ccff183cf0da
--- /dev/null
+++ b/clang/lib/Format/MacroCallReconstructor.cpp
@@ -0,0 +1,573 @@
+//===--- MacroCallReconstructor.cpp - Format C++ code -----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file contains the implementation of MacroCallReconstructor, which fits
+/// an reconstructed macro call to a parsed set of UnwrappedLines.
+///
+//===----------------------------------------------------------------------===//
+
+#include "Macros.h"
+
+#include "UnwrappedLineParser.h"
+#include "clang/Basic/TokenKinds.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/Support/Debug.h"
+#include <cassert>
+
+#define DEBUG_TYPE "format-reconstruct"
+
+namespace clang {
+namespace format {
+
+// Call \p Call for each token in the unwrapped line given, passing
+// the token, its parent and whether it is the first token in the line.
+template <typename T>
+void forEachToken(const UnwrappedLine &Line, const T &Call,
+ FormatToken *Parent = nullptr) {
+ bool First = true;
+ for (const auto &N : Line.Tokens) {
+ Call(N.Tok, Parent, First);
+ First = false;
+ for (const auto &Child : N.Children) {
+ forEachToken(Child, Call, N.Tok);
+ }
+ }
+}
+
+MacroCallReconstructor::MacroCallReconstructor(
+ unsigned Level,
+ const llvm::DenseMap<FormatToken *, std::unique_ptr<UnwrappedLine>>
+ &ActiveExpansions)
+ : Level(Level), IdToReconstructed(ActiveExpansions) {
+ Result.Tokens.push_back(std::make_unique<LineNode>());
+ ActiveReconstructedLines.push_back(&Result);
+}
+
+void MacroCallReconstructor::addLine(const UnwrappedLine &Line) {
+ assert(State != Finalized);
+ LLVM_DEBUG(llvm::dbgs() << "MCR: new line...\n");
+ forEachToken(Line, [&](FormatToken *Token, FormatToken *Parent, bool First) {
+ add(Token, Parent, First);
+ });
+ assert(InProgress || finished());
+}
+
+UnwrappedLine MacroCallReconstructor::takeResult() && {
+ finalize();
+ assert(Result.Tokens.size() == 1 && Result.Tokens.front()->Children.size() == 1);
+ UnwrappedLine Final =
+ createUnwrappedLine(*Result.Tokens.front()->Children.front(), Level);
+ assert(!Final.Tokens.empty());
+ return Final;
+}
+
+// Reconstruct the position of the next \p Token, given its parent \p
+// ExpandedParent in the incoming unwrapped line. \p First specifies whether it
+// is the first token in a given unwrapped line.
+void MacroCallReconstructor::add(FormatToken *Token,
+ FormatToken *ExpandedParent, bool First) {
+ LLVM_DEBUG(
+ llvm::dbgs() << "MCR: Token: " << Token->TokenText << ", Parent: "
+ << (ExpandedParent ? ExpandedParent->TokenText : "<null>")
+ << ", First: " << First << "\n");
+ // In order to be able to find the correct parent in the reconstructed token
+ // stream, we need to continue the last open reconstruction until we find the
+ // given token if it is part of the reconstructed token stream.
+ //
+ // Note that hidden tokens can be part of the reconstructed stream in nested
+ // macro calls.
+ // For example, given
+ // #define C(x, y) x y
+ // #define B(x) {x}
+ // And the call:
+ // C(a, B(b))
+ // The outer macro call will be C(a, {b}), and the hidden token '}' can be
+ // found in the reconstructed token stream of that expansion level.
+ // In the expanded token stream
+ // a {b}
+ // 'b' is a child of '{'. We need to continue the open expansion of the ','
+ // in the call of 'C' in order to correctly set the ',' as the parent of '{',
+ // so we later set the spelled token 'b' as a child of the ','.
+ if (!ActiveExpansions.empty() && Token->MacroCtx &&
+ (Token->MacroCtx->Role != MR_Hidden ||
+ ActiveExpansions.size() != Token->MacroCtx->ExpandedFrom.size())) {
+ if (/*PassedMacroComma = */ reconstructActiveCallUntil(Token))
+ First = true;
+ }
+
+ prepareParent(ExpandedParent, First);
+
+ if (Token->MacroCtx) {
+ // If this token was generated by a macro call, add the reconstructed
+ // equivalent of the token.
+ reconstruct(Token);
+ } else {
+ // Otherwise, we add it to the current line.
+ appendToken(Token);
+ }
+}
+
+// Adjusts the stack of active reconstructed lines so we're ready to push
+// tokens. The tokens to be pushed are children of ExpandedParent in the
+// expanded code.
+//
+// This may entail:
+// - creating a new line, if the parent is on the active line
+// - popping active lines, if the parent is further up the stack
+//
+// Postcondition:
+// ActiveReconstructedLines.back() is the line that has \p ExpandedParent or its
+// reconstructed replacement token as a parent (when possible) - that is, the
+// last token in \c ActiveReconstructedLines[ActiveReconstructedLines.size()-2]
+// is the parent of ActiveReconstructedLines.back() in the reconstructed
+// unwrapped line.
+void MacroCallReconstructor::prepareParent(FormatToken *ExpandedParent,
+ bool NewLine) {
+ LLVM_DEBUG({
+ llvm::dbgs() << "ParentMap:\n";
+ debugParentMap();
+ });
+ // We want to find the parent in the new unwrapped line, where the expanded
+ // parent might have been replaced during reconstruction.
+ FormatToken *Parent = getParentInResult(ExpandedParent);
+ LLVM_DEBUG(llvm::dbgs() << "MCR: New parent: "
+ << (Parent ? Parent->TokenText : "<null>") << "\n");
+
+ FormatToken *OpenMacroParent = nullptr;
+ if (!MacroCallStructure.empty()) {
+ // Inside a macro expansion, it is possible to lose track of the correct
+ // parent - either because it is already popped, for example because it was
+ // in a different macro argument (e.g. M({, })), or when we work on invalid
+ // code.
+ // Thus, we use the innermost macro call's parent as the parent at which
+ // we stop; this allows us to stay within the macro expansion and keeps
+ // any problems confined to the extent of the macro call.
+ OpenMacroParent =
+ getParentInResult(MacroCallStructure.back().MacroCallLParen);
+ LLVM_DEBUG(llvm::dbgs()
+ << "MacroCallLParen: "
+ << MacroCallStructure.back().MacroCallLParen->TokenText
+ << ", OpenMacroParent: "
+ << (OpenMacroParent ? OpenMacroParent->TokenText : "<null>")
+ << "\n");
+ }
+ if (NewLine ||
+ (!ActiveReconstructedLines.back()->Tokens.empty() &&
+ Parent == ActiveReconstructedLines.back()->Tokens.back()->Tok)) {
+ // If we are at the first token in a new line, we want to also
+ // create a new line in the resulting reconstructed unwrapped line.
+ while (ActiveReconstructedLines.back()->Tokens.empty() ||
+ (Parent != ActiveReconstructedLines.back()->Tokens.back()->Tok &&
+ ActiveReconstructedLines.back()->Tokens.back()->Tok !=
+ OpenMacroParent)) {
+ ActiveReconstructedLines.pop_back();
+ assert(!ActiveReconstructedLines.empty());
+ }
+ assert(!ActiveReconstructedLines.empty());
+ ActiveReconstructedLines.back()->Tokens.back()->Children.push_back(
+ std::make_unique<ReconstructedLine>());
+ ActiveReconstructedLines.push_back(
+ &*ActiveReconstructedLines.back()->Tokens.back()->Children.back());
+ } else if (parentLine().Tokens.back()->Tok != Parent) {
+ // If we're not the first token in a new line, pop lines until we find
+ // the child of \c Parent in the stack.
+ while (Parent != parentLine().Tokens.back()->Tok &&
+ parentLine().Tokens.back()->Tok &&
+ parentLine().Tokens.back()->Tok != OpenMacroParent) {
+ ActiveReconstructedLines.pop_back();
+ assert(!ActiveReconstructedLines.empty());
+ }
+ }
+ assert(!ActiveReconstructedLines.empty());
+}
+
+// For a given \p Parent in the incoming expanded token stream, find the
+// corresponding parent in the output.
+FormatToken *MacroCallReconstructor::getParentInResult(FormatToken *Parent) {
+ FormatToken *Mapped = SpelledParentToReconstructedParent.lookup(Parent);
+ if (!Mapped)
+ return Parent;
+ for (; Mapped; Mapped = SpelledParentToReconstructedParent.lookup(Parent)) {
+ Parent = Mapped;
+ }
+ // If we use a different token than the parent in the expanded token stream
+ // as parent, mark it as a special parent, so the formatting code knows it
+ // needs to have its children formatted.
+ Parent->MacroParent = true;
+ return Parent;
+}
+
+// Reconstruct a \p Token that was expanded from a macro call.
+void MacroCallReconstructor::reconstruct(FormatToken *Token) {
+ assert(Token->MacroCtx);
+ // A single token can be the only result of a macro call:
+ // Given: #define ID(x, y) ;
+ // And the call: ID(<some>, <tokens>)
+ // ';' in the expanded stream will reconstruct all of ID(<some>, <tokens>).
+ if (Token->MacroCtx->StartOfExpansion) {
+ startReconstruction(Token);
+ // If the order of tokens in the expanded token stream is not the
+ // same as the order of tokens in the reconstructed stream, we need
+ // to reconstruct tokens that arrive later in the stream.
+ if (Token->MacroCtx->Role != MR_Hidden) {
+ reconstructActiveCallUntil(Token);
+ }
+ }
+ assert(!ActiveExpansions.empty());
+ if (ActiveExpansions.back().SpelledI != ActiveExpansions.back().SpelledE) {
+ assert(ActiveExpansions.size() == Token->MacroCtx->ExpandedFrom.size());
+ if (Token->MacroCtx->Role != MR_Hidden) {
+ // The current token in the reconstructed token stream must be the token
+ // we're looking for - we either arrive here after startReconstruction,
+ // which initiates the stream to the first token, or after
+ // continueReconstructionUntil skipped until the expected token in the
+ // reconstructed stream at the start of add(...).
+ assert(ActiveExpansions.back().SpelledI->Tok == Token);
+ processNextReconstructed();
+ } else if (!currentLine()->Tokens.empty()) {
+ // Map all hidden tokens to the last visible token in the output.
+ // If the hidden token is a parent, we'll use the last visible
+ // token as the parent of the hidden token's children.
+ SpelledParentToReconstructedParent[Token] =
+ currentLine()->Tokens.back()->Tok;
+ } else {
+ for (auto I = ActiveReconstructedLines.rbegin(),
+ E = ActiveReconstructedLines.rend();
+ I != E; ++I) {
+ if (!(*I)->Tokens.empty()) {
+ SpelledParentToReconstructedParent[Token] = (*I)->Tokens.back()->Tok;
+ break;
+ }
+ }
+ }
+ }
+ if (Token->MacroCtx->EndOfExpansion)
+ endReconstruction(Token);
+}
+
+// Given a \p Token that starts an expansion, reconstruct the beginning of the
+// macro call.
+// For example, given: #define ID(x) x
+// And the call: ID(int a)
+// Reconstructs: ID(
+void MacroCallReconstructor::startReconstruction(FormatToken *Token) {
+ assert(Token->MacroCtx);
+ assert(!Token->MacroCtx->ExpandedFrom.empty());
+ assert(ActiveExpansions.size() <= Token->MacroCtx->ExpandedFrom.size());
+#ifndef NDEBUG
+ // Check that the token's reconstruction stack matches our current
+ // reconstruction stack.
+ for (size_t I = 0; I < ActiveExpansions.size(); ++I) {
+ assert(ActiveExpansions[I].ID ==
+ Token->MacroCtx
+ ->ExpandedFrom[Token->MacroCtx->ExpandedFrom.size() - 1 - I]);
+ }
+#endif
+ // Start reconstruction for all calls for which this token is the first token
+ // generated by the call.
+ // Note that the token's expanded from stack is inside-to-outside, and the
+ // expansions for which this token is not the first are the outermost ones.
+ ArrayRef<FormatToken *> StartedMacros =
+ makeArrayRef(Token->MacroCtx->ExpandedFrom)
+ .drop_back(ActiveExpansions.size());
+ assert(StartedMacros.size() == Token->MacroCtx->StartOfExpansion);
+ // We reconstruct macro calls outside-to-inside.
+ for (FormatToken *ID : llvm::reverse(StartedMacros)) {
+ // We found a macro call to be reconstructed; the next time our
+ // reconstruction stack is empty we know we finished an reconstruction.
+#ifndef NDEBUG
+ State = InProgress;
+#endif
+ // Put the reconstructed macro call's token into our reconstruction stack.
+ auto IU = IdToReconstructed.find(ID);
+ assert(IU != IdToReconstructed.end());
+ ActiveExpansions.push_back(
+ {ID, IU->second->Tokens.begin(), IU->second->Tokens.end()});
+ // Process the macro call's identifier.
+ processNextReconstructed();
+ if (ActiveExpansions.back().SpelledI == ActiveExpansions.back().SpelledE)
+ continue;
+ if (ActiveExpansions.back().SpelledI->Tok->is(tok::l_paren)) {
+ // Process the optional opening parenthesis.
+ processNextReconstructed();
+ }
+ }
+}
+
+// Add all tokens in the reconstruction stream to the output until we find the
+// given \p Token.
+bool MacroCallReconstructor::reconstructActiveCallUntil(FormatToken *Token) {
+ assert(!ActiveExpansions.empty());
+ bool PassedMacroComma = false;
+ // FIXME: If Token was already expanded earlier, due to
+ // a change in order, we will not find it, but need to
+ // skip it.
+ while (ActiveExpansions.back().SpelledI != ActiveExpansions.back().SpelledE &&
+ ActiveExpansions.back().SpelledI->Tok != Token) {
+ PassedMacroComma = processNextReconstructed() || PassedMacroComma;
+ }
+ return PassedMacroComma;
+}
+
+// End all reconstructions for which \p Token is the final token.
+void MacroCallReconstructor::endReconstruction(FormatToken *Token) {
+ assert(Token->MacroCtx &&
+ (ActiveExpansions.size() >= Token->MacroCtx->EndOfExpansion));
+ for (size_t I = 0; I < Token->MacroCtx->EndOfExpansion; ++I) {
+#ifndef NDEBUG
+ // Check all remaining tokens but the final closing parenthesis and optional
+ // trailing comment were already reconstructed at an inner expansion level.
+ for (auto T = ActiveExpansions.back().SpelledI;
+ T != ActiveExpansions.back().SpelledE; ++T) {
+ FormatToken *Token = T->Tok;
+ bool ClosingParen = (std::next(T) == ActiveExpansions.back().SpelledE ||
+ std::next(T)->Tok->isTrailingComment()) &&
+ !Token->MacroCtx && Token->is(tok::r_paren);
+ bool TrailingComment = Token->isTrailingComment();
+ bool PreviousLevel =
+ Token->MacroCtx &&
+ (ActiveExpansions.size() < Token->MacroCtx->ExpandedFrom.size());
+ if (!ClosingParen && !TrailingComment && !PreviousLevel) {
+ llvm::dbgs() << "At token: " << Token->TokenText << "\n";
+ }
+ // In addition to the following cases, we can also run into this
+ // when a macro call had more arguments than expected; in that case,
+ // the comma and the remaining tokens in the macro call will potentially
+ // end up in the line when we finish the expansion.
+ // FIXME: Add the information which arguments are unused, and assert
+ // one of the cases below plus reconstructed macro argument tokens.
+ // assert(ClosingParen || TrailingComment || PreviousLevel);
+ }
+#endif
+ // Handle the remaining open tokens:
+ // - expand the closing parenthesis, if it exists, including an optional
+ // trailing comment
+ // - handle tokens that were already reconstructed at an inner expansion
+ // level
+ // - handle tokens when a macro call had more than the expected number of
+ // arguments, i.e. when #define M(x) is called as M(a, b, c) we'll end
+ // up with the sequence ", b, c)" being open at the end of the
+ // reconstruction; we want to gracefully handle that case
+ //
+ // FIXME: See the above debug-check for what we will need to do to be
+ // able to assert this.
+ for (auto T = ActiveExpansions.back().SpelledI;
+ T != ActiveExpansions.back().SpelledE; ++T) {
+ processNextReconstructed();
+ }
+ ActiveExpansions.pop_back();
+ }
+}
+
+void MacroCallReconstructor::debugParentMap() const {
+ llvm::DenseSet<FormatToken *> Values;
+ for (const auto &P : SpelledParentToReconstructedParent)
+ Values.insert(P.second);
+
+ for (const auto &P : SpelledParentToReconstructedParent) {
+ if (Values.contains(P.first))
+ continue;
+ llvm::dbgs() << (P.first ? P.first->TokenText : "<null>");
+ for (auto I = SpelledParentToReconstructedParent.find(P.first),
+ E = SpelledParentToReconstructedParent.end();
+ I != E; I = SpelledParentToReconstructedParent.find(I->second)) {
+ llvm::dbgs() << " -> " << (I->second ? I->second->TokenText : "<null>");
+ }
+ llvm::dbgs() << "\n";
+ }
+}
+
+// If visible, add the next token of the reconstructed token sequence to the
+// output. Returns whether reconstruction passed a comma that is part of a
+// macro call.
+bool MacroCallReconstructor::processNextReconstructed() {
+ FormatToken *Token = ActiveExpansions.back().SpelledI->Tok;
+ ++ActiveExpansions.back().SpelledI;
+ if (Token->MacroCtx) {
+ // Skip tokens that are not part of the macro call.
+ if (Token->MacroCtx->Role == MR_Hidden) {
+ return false;
+ }
+ // Skip tokens we already expanded during an inner reconstruction.
+ // For example, given: #define ID(x) {x}
+ // And the call: ID(ID(f))
+ // We get two reconstructions:
+ // ID(f) -> {f}
+ // ID({f}) -> {{f}}
+ // We reconstruct f during the first reconstruction, and skip it during the
+ // second reconstruction.
+ if (ActiveExpansions.size() < Token->MacroCtx->ExpandedFrom.size()) {
+ return false;
+ }
+ }
+ // Tokens that do not have a macro context are tokens in that are part of the
+ // macro call that have not taken part in expansion.
+ if (!Token->MacroCtx) {
+ // Put the parentheses and commas of a macro call into the same line;
+ // if the arguments produce new unwrapped lines, they will become children
+ // of the corresponding opening parenthesis or comma tokens in the
+ // reconstructed call.
+ if (Token->is(tok::l_paren)) {
+ MacroCallStructure.push_back(MacroCallState(
+ currentLine(), parentLine().Tokens.back()->Tok, Token));
+ // All tokens that are children of the previous line's last token in the
+ // reconstructed token stream will now be children of the l_paren token.
+ // For example, for the line containing the macro calls:
+ // auto x = ID({ID(2)});
+ // We will build up a map <null> -> ( -> ( with the first and second
+ // l_paren of the macro call respectively. New lines that come in with a
+ // <null> parent will then become children of the l_paren token of the
+ // currently innermost macro call.
+ SpelledParentToReconstructedParent[MacroCallStructure.back()
+ .ParentLastToken] = Token;
+ appendToken(Token);
+ prepareParent(Token, /*NewLine=*/true);
+ Token->MacroParent = true;
+ return false;
+ }
+ if (!MacroCallStructure.empty()) {
+ if (Token->is(tok::comma)) {
+ // Make new lines inside the next argument children of the comma token.
+ SpelledParentToReconstructedParent
+ [MacroCallStructure.back().Line->Tokens.back()->Tok] = Token;
+ Token->MacroParent = true;
+ appendToken(Token, MacroCallStructure.back().Line);
+ prepareParent(Token, /*NewLine=*/true);
+ return true;
+ }
+ if (Token->is(tok::r_paren)) {
+ appendToken(Token, MacroCallStructure.back().Line);
+ SpelledParentToReconstructedParent.erase(
+ MacroCallStructure.back().ParentLastToken);
+ MacroCallStructure.pop_back();
+ return false;
+ }
+ }
+ }
+ // Note that any tokens that are tagged with MR_None have been passed as
+ // arguments to the macro that have not been expanded, for example:
+ // Given: #define ID(X) x
+ // When calling: ID(a, b)
+ // 'b' will be part of the reconstructed token stream, but tagged MR_None.
+ // Given that erroring out in this case would be disruptive, we continue
+ // pushing the (unformatted) token.
+ // FIXME: This can lead to unfortunate formatting decisions - give the user
+ // a hint that their macro definition is broken.
+ appendToken(Token);
+ return false;
+}
+
+void MacroCallReconstructor::finalize() {
+#ifndef NDEBUG
+ assert(State != Finalized && finished());
+ State = Finalized;
+#endif
+
+ // We created corresponding unwrapped lines for each incoming line as children
+ // the the toplevel null token.
+ assert(Result.Tokens.size() == 1 && !Result.Tokens.front()->Children.empty());
+ LLVM_DEBUG({
+ llvm::dbgs() << "Finalizing reconstructed lines:\n";
+ debug(Result, 0);
+ });
+
+ // The first line becomes the top level line in the resulting unwrapped line.
+ LineNode &Top = *Result.Tokens.front();
+ auto *I = Top.Children.begin();
+ // Every subsequent line will become a child of the last token in the previous
+ // line, which is the token prior to the first token in the line.
+ LineNode *Last = (*I)->Tokens.back().get();
+ ++I;
+ for (auto *E = Top.Children.end(); I != E; ++I) {
+ assert(Last->Children.empty());
+ Last->Children.push_back(std::move(*I));
+
+ // Mark the previous line's last token as generated by a macro expansion
+ // so the formatting algorithm can take that into account.
+ Last->Tok->MacroParent = true;
+
+ Last = Last->Children.back()->Tokens.back().get();
+ }
+ Top.Children.resize(1);
+}
+
+void MacroCallReconstructor::appendToken(FormatToken *Token,
+ ReconstructedLine *L) {
+ L = L ? L : currentLine();
+ LLVM_DEBUG(llvm::dbgs() << "-> " << Token->TokenText << "\n");
+ L->Tokens.push_back(std::make_unique<LineNode>(Token));
+}
+
+UnwrappedLine
+MacroCallReconstructor::createUnwrappedLine(const ReconstructedLine &Line,
+ int Level) {
+ UnwrappedLine Result;
+ Result.Level = Level;
+ for (const auto &N : Line.Tokens) {
+ Result.Tokens.push_back(N->Tok);
+ UnwrappedLineNode &Current = Result.Tokens.back();
+ for (const auto &Child : N->Children) {
+ if (Child->Tokens.empty())
+ continue;
+ Current.Children.push_back(createUnwrappedLine(*Child, Level + 1));
+ }
+ if (Current.Children.size() == 1 &&
+ Current.Tok->isOneOf(tok::l_paren, tok::comma)) {
+ Result.Tokens.splice(Result.Tokens.end(),
+ Current.Children.front().Tokens);
+ Current.Children.clear();
+ }
+ }
+ return Result;
+}
+
+void MacroCallReconstructor::debug(const ReconstructedLine &Line, int Level) {
+ for (int i = 0; i < Level; ++i)
+ llvm::dbgs() << " ";
+ for (const auto &N : Line.Tokens) {
+ if (!N)
+ continue;
+ if (N->Tok)
+ llvm::dbgs() << N->Tok->TokenText << " ";
+ for (const auto &Child : N->Children) {
+ llvm::dbgs() << "\n";
+ debug(*Child, Level + 1);
+ for (int i = 0; i < Level; ++i)
+ llvm::dbgs() << " ";
+ }
+ }
+ llvm::dbgs() << "\n";
+}
+
+MacroCallReconstructor::ReconstructedLine &
+MacroCallReconstructor::parentLine() {
+ return **std::prev(std::prev(ActiveReconstructedLines.end()));
+}
+
+MacroCallReconstructor::ReconstructedLine *
+MacroCallReconstructor::currentLine() {
+ return ActiveReconstructedLines.back();
+}
+
+MacroCallReconstructor::MacroCallState::MacroCallState(
+ MacroCallReconstructor::ReconstructedLine *Line,
+ FormatToken *ParentLastToken, FormatToken *MacroCallLParen)
+ : Line(Line), ParentLastToken(ParentLastToken),
+ MacroCallLParen(MacroCallLParen) {
+ LLVM_DEBUG(
+ llvm::dbgs() << "ParentLastToken: "
+ << (ParentLastToken ? ParentLastToken->TokenText : "<null>")
+ << "\n");
+
+ assert(MacroCallLParen->is(tok::l_paren));
+}
+
+} // namespace format
+} // namespace clang
diff --git a/clang/lib/Format/Macros.h b/clang/lib/Format/Macros.h
index da03beb09145..b26799c20f8c 100644
--- a/clang/lib/Format/Macros.h
+++ b/clang/lib/Format/Macros.h
@@ -1,4 +1,4 @@
-//===--- MacroExpander.h - Format C++ code ----------------------*- C++ -*-===//
+//===--- Macros.h - Format C++ code -----------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -22,40 +22,38 @@
/// spelled token streams into expanded token streams when it encounters a
/// macro call. The UnwrappedLineParser continues to parse UnwrappedLines
/// from the expanded token stream.
-/// After the expanded unwrapped lines are parsed, the MacroUnexpander matches
-/// the spelled token stream into unwrapped lines that best resemble the
-/// structure of the expanded unwrapped lines.
+/// After the expanded unwrapped lines are parsed, the MacroCallReconstructor
+/// matches the spelled token stream into unwrapped lines that best resemble the
+/// structure of the expanded unwrapped lines. These reconstructed unwrapped
+/// lines are aliasing the tokens in the expanded token stream, so that token
+/// annotations will be reused when formatting the spelled macro calls.
///
-/// When formatting, clang-format formats the expanded unwrapped lines first,
-/// determining the token types. Next, it formats the spelled unwrapped lines,
-/// keeping the token types fixed, while allowing other formatting decisions
-/// to change.
+/// When formatting, clang-format annotates and formats the expanded unwrapped
+/// lines first, determining the token types. Next, it formats the spelled
+/// unwrapped lines, keeping the token types fixed, while allowing other
+/// formatting decisions to change.
///
//===----------------------------------------------------------------------===//
#ifndef CLANG_LIB_FORMAT_MACROS_H
#define CLANG_LIB_FORMAT_MACROS_H
+#include <list>
+#include <map>
#include <string>
-#include <unordered_map>
#include <vector>
-#include "Encoding.h"
#include "FormatToken.h"
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
-namespace llvm {
-class MemoryBuffer;
-} // namespace llvm
-
namespace clang {
-class IdentifierTable;
-class SourceManager;
-
namespace format {
-struct FormatStyle;
+
+struct UnwrappedLine;
+struct UnwrappedLineNode;
/// Takes a set of macro definitions as strings and allows expanding calls to
/// those macros.
@@ -130,10 +128,253 @@ private:
const FormatStyle &Style;
llvm::SpecificBumpPtrAllocator<FormatToken> &Allocator;
IdentifierTable &IdentTable;
- std::vector<std::unique_ptr<llvm::MemoryBuffer>> Buffers;
+ SmallVector<std::unique_ptr<llvm::MemoryBuffer>> Buffers;
llvm::StringMap<Definition> Definitions;
};
+/// Converts a sequence of UnwrappedLines containing expanded macros into a
+/// single UnwrappedLine containing the macro calls. This UnwrappedLine may be
+/// broken into child lines, in a way that best conveys the structure of the
+/// expanded code.
+///
+/// In the simplest case, a spelled UnwrappedLine contains one macro, and after
+/// expanding it we have one expanded UnwrappedLine. In general, macro
+/// expansions can span UnwrappedLines, and multiple macros can contribute
+/// tokens to the same line. We keep consuming expanded lines until:
+/// * all expansions that started have finished (we're not chopping any macros
+/// in half)
+/// * *and* we've reached the end of a *spelled* unwrapped line.
+///
+/// A single UnwrappedLine represents this chunk of code.
+///
+/// After this point, the state of the spelled/expanded stream is "in sync"
+/// (both at the start of an UnwrappedLine, with no macros open), so the
+/// Unexpander can be thrown away and parsing can continue.
+///
+/// Given a mapping from the macro name identifier token in the macro call
+/// to the tokens of the macro call, for example:
+/// CLASSA -> CLASSA({public: void x();})
+///
+/// When getting the formatted lines of the expansion via the \c addLine method
+/// (each '->' specifies a call to \c addLine ):
+/// -> class A {
+/// -> public:
+/// -> void x();
+/// -> };
+///
+/// Creates the tree of unwrapped lines containing the macro call tokens so that
+/// the macro call tokens fit the semantic structure of the expanded formatted
+/// lines:
+/// -> CLASSA({
+/// -> public:
+/// -> void x();
+/// -> })
+class MacroCallReconstructor {
+public:
+ /// Create an Reconstructor whose resulting \p UnwrappedLine will start at
+ /// \p Level, using the map from name identifier token to the corresponding
+ /// tokens of the spelled macro call.
+ MacroCallReconstructor(
+ unsigned Level,
+ const llvm::DenseMap<FormatToken *, std::unique_ptr<UnwrappedLine>>
+ &ActiveExpansions);
+
+ /// For the given \p Line, match all occurences of tokens expanded from a
+ /// macro to unwrapped lines in the spelled macro call so that the resulting
+ /// tree of unwrapped lines best resembles the structure of unwrapped lines
+ /// passed in via \c addLine.
+ void addLine(const UnwrappedLine &Line);
+
+ /// Check whether at the current state there is no open macro expansion
+ /// that needs to be processed to finish an macro call.
+ /// Only when \c finished() is true, \c takeResult() can be called to retrieve
+ /// the resulting \c UnwrappedLine.
+ /// If there are multiple subsequent macro calls within an unwrapped line in
+ /// the spelled token stream, the calling code may also continue to call
+ /// \c addLine() when \c finished() is true.
+ bool finished() const { return ActiveExpansions.empty(); }
+
+ /// Retrieve the formatted \c UnwrappedLine containing the orginal
+ /// macro calls, formatted according to the expanded token stream received
+ /// via \c addLine().
+ /// Generally, this line tries to have the same structure as the expanded,
+ /// formatted unwrapped lines handed in via \c addLine(), with the exception
+ /// that for multiple top-level lines, each subsequent line will be the
+ /// child of the last token in its predecessor. This representation is chosen
+ /// because it is a precondition to the formatter that we get what looks like
+ /// a single statement in a single \c UnwrappedLine (i.e. matching parens).
+ ///
+ /// If a token in a macro argument is a child of a token in the expansion,
+ /// the parent will be the corresponding token in the macro call.
+ /// For example:
+ /// #define C(a, b) class C { a b
+ /// C(int x;, int y;)
+ /// would expand to
+ /// class C { int x; int y;
+ /// where in a formatted line "int x;" and "int y;" would both be new separate
+ /// lines.
+ ///
+ /// In the result, "int x;" will be a child of the opening parenthesis in "C("
+ /// and "int y;" will be a child of the "," token:
+ /// C (
+ /// \- int x;
+ /// ,
+ /// \- int y;
+ /// )
+ UnwrappedLine takeResult() &&;
+
+private:
+ void add(FormatToken *Token, FormatToken *ExpandedParent, bool First);
+ void prepareParent(FormatToken *ExpandedParent, bool First);
+ FormatToken *getParentInResult(FormatToken *Parent);
+ void reconstruct(FormatToken *Token);
+ void startReconstruction(FormatToken *Token);
+ bool reconstructActiveCallUntil(FormatToken *Token);
+ void endReconstruction(FormatToken *Token);
+ bool processNextReconstructed();
+ void finalize();
+
+ struct ReconstructedLine;
+
+ void appendToken(FormatToken *Token, ReconstructedLine *L = nullptr);
+ UnwrappedLine createUnwrappedLine(const ReconstructedLine &Line, int Level);
+ void debug(const ReconstructedLine &Line, int Level);
+ ReconstructedLine &parentLine();
+ ReconstructedLine *currentLine();
+ void debugParentMap() const;
+
+#ifndef NDEBUG
+ enum ReconstructorState {
+ Start, // No macro expansion was found in the input yet.
+ InProgress, // During a macro reconstruction.
+ Finalized, // Past macro reconstruction, the result is finalized.
+ };
+ ReconstructorState State = Start;
+#endif
+
+ // Node in which we build up the resulting unwrapped line; this type is
+ // analogous to UnwrappedLineNode.
+ struct LineNode {
+ LineNode() = default;
+ LineNode(FormatToken *Tok) : Tok(Tok) {}
+ FormatToken *Tok = nullptr;
+ llvm::SmallVector<std::unique_ptr<ReconstructedLine>> Children;
+ };
+
+ // Line in which we build up the resulting unwrapped line.
+ // FIXME: Investigate changing UnwrappedLine to a pointer type and using it
+ // instead of rolling our own type.
+ struct ReconstructedLine {
+ llvm::SmallVector<std::unique_ptr<LineNode>> Tokens;
+ };
+
+ // The line in which we collect the resulting reconstructed output.
+ // To reduce special cases in the algorithm, the first level of the line
+ // contains a single null token that has the reconstructed incoming
+ // lines as children.
+ // In the end, we stich the lines together so that each subsequent line
+ // is a child of the last token of the previous line. This is necessary
+ // in order to format the overall expression as a single logical line -
+ // if we created separate lines, we'd format them with their own top-level
+ // indent depending on the semantic structure, which is not desired.
+ ReconstructedLine Result;
+
+ // Stack of currently "open" lines, where each line's predecessor's last
+ // token is the parent token for that line.
+ llvm::SmallVector<ReconstructedLine *> ActiveReconstructedLines;
+
+ // Maps from the expanded token to the token that takes its place in the
+ // reconstructed token stream in terms of parent-child relationships.
+ // Note that it might take multiple steps to arrive at the correct
+ // parent in the output.
+ // Given: #define C(a, b) []() { a; b; }
+ // And a call: C(f(), g())
+ // The structure in the incoming formatted unwrapped line will be:
+ // []() {
+ // |- f();
+ // \- g();
+ // }
+ // with f and g being children of the opening brace.
+ // In the reconstructed call:
+ // C(f(), g())
+ // \- f()
+ // \- g()
+ // We want f to be a child of the opening parenthesis and g to be a child
+ // of the comma token in the macro call.
+ // Thus, we map
+ // { -> (
+ // and add
+ // ( -> ,
+ // once we're past the comma in the reconstruction.
+ llvm::DenseMap<FormatToken *, FormatToken *>
+ SpelledParentToReconstructedParent;
+
+ // Keeps track of a single expansion while we're reconstructing tokens it
+ // generated.
+ struct Expansion {
+ // The identifier token of the macro call.
+ FormatToken *ID;
+ // Our current position in the reconstruction.
+ std::list<UnwrappedLineNode>::iterator SpelledI;
+ // The end of the reconstructed token sequence.
+ std::list<UnwrappedLineNode>::iterator SpelledE;
+ };
+
+ // Stack of macro calls for which we're in the middle of an expansion.
+ llvm::SmallVector<Expansion> ActiveExpansions;
+
+ struct MacroCallState {
+ MacroCallState(ReconstructedLine *Line, FormatToken *ParentLastToken,
+ FormatToken *MacroCallLParen);
+
+ ReconstructedLine *Line;
+
+ // The last token in the parent line or expansion, or nullptr if the macro
+ // expansion is on a top-level line.
+ //
+ // For example, in the macro call:
+ // auto f = []() { ID(1); };
+ // The MacroCallState for ID will have '{' as ParentLastToken.
+ //
+ // In the macro call:
+ // ID(ID(void f()));
+ // The MacroCallState of the outer ID will have nullptr as ParentLastToken,
+ // while the MacroCallState for the inner ID will have the '(' of the outer
+ // ID as ParentLastToken.
+ //
+ // In the macro call:
+ // ID2(a, ID(b));
+ // The MacroCallState of ID will have ',' as ParentLastToken.
+ FormatToken *ParentLastToken;
+
+ // The l_paren of this MacroCallState's macro call.
+ FormatToken *MacroCallLParen;
+ };
+
+ // Keeps track of the lines into which the opening brace/parenthesis &
+ // argument separating commas for each level in the macro call go in order to
+ // put the corresponding closing brace/parenthesis into the same line in the
+ // output and keep track of which parents in the expanded token stream map to
+ // which tokens in the reconstructed stream.
+ // When an opening brace/parenthesis has children, we want the structure of
+ // the output line to be:
+ // |- MACRO
+ // |- (
+ // | \- <argument>
+ // |- ,
+ // | \- <argument>
+ // \- )
+ llvm::SmallVector<MacroCallState> MacroCallStructure;
+
+ // Level the generated UnwrappedLine will be at.
+ const unsigned Level;
+
+ // Maps from identifier of the macro call to an unwrapped line containing
+ // all tokens of the macro call.
+ const llvm::DenseMap<FormatToken *, std::unique_ptr<UnwrappedLine>>
+ &IdToReconstructed;
+};
+
} // namespace format
} // namespace clang
diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp
index 029cb9097871..98c012994f45 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -4734,7 +4734,7 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
// the first list element. Otherwise, it should be placed outside of the
// list.
return Left.is(BK_BracedInit) ||
- (Left.is(TT_CtorInitializerColon) &&
+ (Left.is(TT_CtorInitializerColon) && Right.NewlinesBefore > 0 &&
Style.BreakConstructorInitializers == FormatStyle::BCIS_AfterColon);
}
if (Left.is(tok::question) && Right.is(tok::colon))
@@ -4894,8 +4894,10 @@ 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 (Left.is(TT_CtorInitializerColon)) {
+ return Style.BreakConstructorInitializers == FormatStyle::BCIS_AfterColon &&
+ (!Right.isTrailingComment() || Right.NewlinesBefore > 0);
+ }
if (Right.is(TT_CtorInitializerColon))
return Style.BreakConstructorInitializers != FormatStyle::BCIS_AfterColon;
if (Left.is(TT_CtorInitializerComma) &&
diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp b/clang/lib/Format/UnwrappedLineFormatter.cpp
index 22509a504246..abeb93d23776 100644
--- a/clang/lib/Format/UnwrappedLineFormatter.cpp
+++ b/clang/lib/Format/UnwrappedLineFormatter.cpp
@@ -59,14 +59,12 @@ public:
Offset = getIndentOffset(*Line.First);
// Update the indent level cache size so that we can rely on it
// having the right size in adjustToUnmodifiedline.
- while (IndentForLevel.size() <= Line.Level)
- IndentForLevel.push_back(-1);
+ skipLine(Line, /*UnknownIndent=*/true);
if (Line.InPPDirective) {
unsigned IndentWidth =
(Style.PPIndentWidth >= 0) ? Style.PPIndentWidth : Style.IndentWidth;
Indent = Line.Level * IndentWidth + AdditionalIndent;
} else {
- IndentForLevel.resize(Line.Level + 1);
Indent = getIndent(Line.Level);
}
if (static_cast<int>(Indent) + Offset >= 0)
@@ -77,9 +75,9 @@ public:
/// Update the indent state given that \p Line indent should be
/// skipped.
- void skipLine(const AnnotatedLine &Line) {
- while (IndentForLevel.size() <= Line.Level)
- IndentForLevel.push_back(Indent);
+ void skipLine(const AnnotatedLine &Line, bool UnknownIndent = false) {
+ if (Line.Level >= IndentForLevel.size())
+ IndentForLevel.resize(Line.Level + 1, UnknownIndent ? -1 : Indent);
}
/// Update the level indent to adapt to the given \p Line.
@@ -91,6 +89,7 @@ public:
unsigned LevelIndent = Line.First->OriginalColumn;
if (static_cast<int>(LevelIndent) - Offset >= 0)
LevelIndent -= Offset;
+ assert(Line.Level < IndentForLevel.size());
if ((!Line.First->is(tok::comment) || IndentForLevel[Line.Level] == -1) &&
!Line.InPPDirective) {
IndentForLevel[Line.Level] = LevelIndent;
@@ -159,7 +158,7 @@ private:
const unsigned AdditionalIndent;
/// The indent in characters for each level.
- std::vector<int> IndentForLevel;
+ SmallVector<int> IndentForLevel;
/// Offset of the current line relative to the indent level.
///
@@ -1133,7 +1132,7 @@ private:
typedef std::pair<OrderedPenalty, StateNode *> QueueItem;
/// The BFS queue type.
- typedef std::priority_queue<QueueItem, std::vector<QueueItem>,
+ typedef std::priority_queue<QueueItem, SmallVector<QueueItem>,
std::greater<QueueItem>>
QueueType;
diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp
index d3383292f7a3..97c3d86282a0 100644
--- a/clang/lib/Format/UnwrappedLineParser.cpp
+++ b/clang/lib/Format/UnwrappedLineParser.cpp
@@ -15,6 +15,7 @@
#include "UnwrappedLineParser.h"
#include "FormatToken.h"
#include "TokenAnnotator.h"
+#include "clang/Basic/TokenKinds.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
@@ -1910,15 +1911,12 @@ void UnwrappedLineParser::parseStructuralElement(
break;
auto OneTokenSoFar = [&]() {
- const UnwrappedLineNode *Tok = &Line->Tokens.front(),
- *End = Tok + Line->Tokens.size();
- while (Tok != End && Tok->Tok->is(tok::comment))
- ++Tok;
- // In Verilog, macro invocations start with a backtick which the code
- // treats as a hash. Skip it.
- if (Style.isVerilog() && Tok != End && Tok->Tok->is(tok::hash))
- ++Tok;
- return End - Tok == 1;
+ auto I = Line->Tokens.begin(), E = Line->Tokens.end();
+ while (I != E && I->Tok->is(tok::comment))
+ ++I;
+ while (I != E && Style.isVerilog() && I->Tok->is(tok::hash))
+ ++I;
+ return I != E && (++I == E);
};
if (OneTokenSoFar()) {
if (FormatTok->is(tok::colon) && !Line->MustBeDeclaration) {
diff --git a/clang/lib/Format/UnwrappedLineParser.h b/clang/lib/Format/UnwrappedLineParser.h
index 8f63870412d0..3394bfab8b8e 100644
--- a/clang/lib/Format/UnwrappedLineParser.h
+++ b/clang/lib/Format/UnwrappedLineParser.h
@@ -20,6 +20,7 @@
#include "clang/Format/Format.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/Support/Regex.h"
+#include <list>
#include <stack>
#include <vector>
@@ -38,7 +39,7 @@ struct UnwrappedLine {
UnwrappedLine();
/// The \c Tokens comprising this \c UnwrappedLine.
- std::vector<UnwrappedLineNode> Tokens;
+ std::list<UnwrappedLineNode> Tokens;
/// The indent level of the \c UnwrappedLine.
unsigned Level;
diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp
index b982ca72c78c..2cd7efd862ec 100644
--- a/clang/lib/Frontend/CompilerInstance.cpp
+++ b/clang/lib/Frontend/CompilerInstance.cpp
@@ -115,9 +115,9 @@ bool CompilerInstance::createTarget() {
auto TO = std::make_shared<TargetOptions>();
TO->Triple = llvm::Triple::normalize(getFrontendOpts().AuxTriple);
if (getFrontendOpts().AuxTargetCPU)
- TO->CPU = getFrontendOpts().AuxTargetCPU.getValue();
+ TO->CPU = getFrontendOpts().AuxTargetCPU.value();
if (getFrontendOpts().AuxTargetFeatures)
- TO->FeaturesAsWritten = getFrontendOpts().AuxTargetFeatures.getValue();
+ TO->FeaturesAsWritten = getFrontendOpts().AuxTargetFeatures.value();
TO->HostTriple = getTarget().getTriple().str();
setAuxTarget(TargetInfo::CreateTargetInfo(getDiagnostics(), TO));
}
@@ -757,6 +757,8 @@ void CompilerInstance::createSema(TranslationUnitKind TUKind,
// Output Files
void CompilerInstance::clearOutputFiles(bool EraseFiles) {
+ // The ASTConsumer can own streams that write to the output files.
+ assert(!hasASTConsumer() && "ASTConsumer should be reset");
// Ignore errors that occur when trying to discard the temp file.
for (OutputFile &OF : OutputFiles) {
if (EraseFiles) {
@@ -1235,8 +1237,7 @@ compileModuleImpl(CompilerInstance &ImportingInstance, SourceLocation ImportLoc,
// Execute the action to actually build the module in-place. Use a separate
// thread so that we get a stack large enough.
- llvm::CrashRecoveryContext CRC;
- CRC.RunSafelyOnThread(
+ bool Crashed = !llvm::CrashRecoveryContext().RunSafelyOnThread(
[&]() {
GenerateModuleFromModuleMapAction Action;
Instance.ExecuteAction(Action);
@@ -1249,9 +1250,15 @@ compileModuleImpl(CompilerInstance &ImportingInstance, SourceLocation ImportLoc,
diag::remark_module_build_done)
<< ModuleName;
- // Delete any remaining temporary files related to Instance, in case the
- // module generation thread crashed.
- Instance.clearOutputFiles(/*EraseFiles=*/true);
+ if (Crashed) {
+ // Clear the ASTConsumer if it hasn't been already, in case it owns streams
+ // that must be closed before clearing output files.
+ Instance.setSema(nullptr);
+ Instance.setASTConsumer(nullptr);
+
+ // Delete any remaining temporary files related to Instance.
+ Instance.clearOutputFiles(/*EraseFiles=*/true);
+ }
// If \p AllowPCMWithCompilerErrors is set return 'success' even if errors
// occurred.
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index abef4cf65496..48cd6a394107 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -1485,6 +1485,9 @@ void CompilerInvocation::GenerateCodeGenArgs(
if (Opts.IBTSeal)
GenerateArg(Args, OPT_mibt_seal, SA);
+ if (Opts.FunctionReturnThunks)
+ GenerateArg(Args, OPT_mfunction_return_EQ, "thunk-extern", SA);
+
for (const auto &F : Opts.LinkBitcodeFiles) {
bool Builtint = F.LinkFlags == llvm::Linker::Flags::LinkOnlyNeeded &&
F.PropagateAttrs && F.Internalize;
@@ -1825,6 +1828,27 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Name;
}
+ if (const Arg *A = Args.getLastArg(OPT_mfunction_return_EQ)) {
+ auto Val = llvm::StringSwitch<llvm::FunctionReturnThunksKind>(A->getValue())
+ .Case("keep", llvm::FunctionReturnThunksKind::Keep)
+ .Case("thunk-extern", llvm::FunctionReturnThunksKind::Extern)
+ .Default(llvm::FunctionReturnThunksKind::Invalid);
+ // SystemZ might want to add support for "expolines."
+ if (!T.isX86())
+ Diags.Report(diag::err_drv_argument_not_allowed_with)
+ << A->getSpelling() << T.getTriple();
+ else if (Val == llvm::FunctionReturnThunksKind::Invalid)
+ Diags.Report(diag::err_drv_invalid_value)
+ << A->getAsString(Args) << A->getValue();
+ else if (Val == llvm::FunctionReturnThunksKind::Extern &&
+ Args.getLastArgValue(OPT_mcmodel_EQ).equals("large"))
+ Diags.Report(diag::err_drv_argument_not_allowed_with)
+ << A->getAsString(Args)
+ << Args.getLastArg(OPT_mcmodel_EQ)->getAsString(Args);
+ else
+ Opts.FunctionReturnThunks = static_cast<unsigned>(Val);
+ }
+
if (Opts.PrepareForLTO && Args.hasArg(OPT_mibt_seal))
Opts.IBTSeal = 1;
@@ -1952,7 +1976,7 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
} else {
Opts.DiagnosticsHotnessThreshold = *ResultOrErr;
if ((!Opts.DiagnosticsHotnessThreshold ||
- Opts.DiagnosticsHotnessThreshold.getValue() > 0) &&
+ Opts.DiagnosticsHotnessThreshold.value() > 0) &&
!UsingProfile)
Diags.Report(diag::warn_drv_diagnostics_hotness_requires_pgo)
<< "-fdiagnostics-hotness-threshold=";
@@ -1969,7 +1993,7 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
} else {
Opts.DiagnosticsMisExpectTolerance = *ResultOrErr;
if ((!Opts.DiagnosticsMisExpectTolerance ||
- Opts.DiagnosticsMisExpectTolerance.getValue() > 0) &&
+ Opts.DiagnosticsMisExpectTolerance.value() > 0) &&
!UsingProfile)
Diags.Report(diag::warn_drv_diagnostics_misexpect_requires_pgo)
<< "-fdiagnostics-misexpect-tolerance=";
diff --git a/clang/lib/Frontend/FrontendAction.cpp b/clang/lib/Frontend/FrontendAction.cpp
index 65160dd7e0b1..ed3e314cc73b 100644
--- a/clang/lib/Frontend/FrontendAction.cpp
+++ b/clang/lib/Frontend/FrontendAction.cpp
@@ -24,6 +24,7 @@
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/PreprocessorOptions.h"
#include "clang/Parse/ParseAST.h"
+#include "clang/Sema/HLSLExternalSemaSource.h"
#include "clang/Serialization/ASTDeserializationListener.h"
#include "clang/Serialization/ASTReader.h"
#include "clang/Serialization/GlobalModuleIndex.h"
@@ -580,6 +581,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
auto FailureCleanup = llvm::make_scope_exit([&]() {
if (HasBegunSourceFile)
CI.getDiagnosticClient().EndSourceFile();
+ CI.setASTConsumer(nullptr);
CI.clearOutputFiles(/*EraseFiles=*/true);
CI.getLangOpts().setCompilingModule(LangOptions::CMK_None);
setCurrentInput(FrontendInputFile());
@@ -1014,6 +1016,13 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
CI.getASTContext().setExternalSource(Override);
}
+ // Setup HLSL External Sema Source
+ if (CI.getLangOpts().HLSL && CI.hasASTContext()) {
+ IntrusiveRefCntPtr<ExternalASTSource> HLSLSema(
+ new HLSLExternalSemaSource());
+ CI.getASTContext().setExternalSource(HLSLSema);
+ }
+
FailureCleanup.release();
return true;
}
diff --git a/clang/lib/Frontend/FrontendActions.cpp b/clang/lib/Frontend/FrontendActions.cpp
index f61c83a2a465..f833541caa25 100644
--- a/clang/lib/Frontend/FrontendActions.cpp
+++ b/clang/lib/Frontend/FrontendActions.cpp
@@ -854,8 +854,9 @@ void DumpModuleInfoAction::ExecuteAction() {
std::error_code EC;
OutFile.reset(new llvm::raw_fd_ostream(OutputFileName.str(), EC,
llvm::sys::fs::OF_TextWithCRLF));
+ OutputStream = OutFile.get();
}
- llvm::raw_ostream &Out = OutFile.get()? *OutFile.get() : llvm::outs();
+ llvm::raw_ostream &Out = OutputStream ? *OutputStream : llvm::outs();
Out << "Information for module file '" << getCurrentFile() << "':\n";
auto &FileMgr = getCompilerInstance().getFileManager();
diff --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp
index fe3736c07c3c..d0360696ff9c 100644
--- a/clang/lib/Frontend/InitPreprocessor.cpp
+++ b/clang/lib/Frontend/InitPreprocessor.cpp
@@ -832,11 +832,11 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
unsigned minor = 0;
if (tuple.getMinor())
- minor = tuple.getMinor().getValue();
+ minor = tuple.getMinor().value();
unsigned subminor = 0;
if (tuple.getSubminor())
- subminor = tuple.getSubminor().getValue();
+ subminor = tuple.getSubminor().value();
Builder.defineMacro("__OBJFW_RUNTIME_ABI__",
Twine(tuple.getMajor() * 10000 + minor * 100 +
diff --git a/clang/lib/Headers/hlsl/hlsl_basic_types.h b/clang/lib/Headers/hlsl/hlsl_basic_types.h
index 2069990f5c06..e68715f1a6a4 100644
--- a/clang/lib/Headers/hlsl/hlsl_basic_types.h
+++ b/clang/lib/Headers/hlsl/hlsl_basic_types.h
@@ -27,38 +27,38 @@ typedef long int64_t;
// built-in vector data types:
#ifdef __HLSL_ENABLE_16_BIT
-typedef int16_t int16_t2 __attribute__((ext_vector_type(2)));
-typedef int16_t int16_t3 __attribute__((ext_vector_type(3)));
-typedef int16_t int16_t4 __attribute__((ext_vector_type(4)));
-typedef uint16_t uint16_t2 __attribute__((ext_vector_type(2)));
-typedef uint16_t uint16_t3 __attribute__((ext_vector_type(3)));
-typedef uint16_t uint16_t4 __attribute__((ext_vector_type(4)));
+typedef vector<int16_t, 2> int16_t2;
+typedef vector<int16_t, 3> int16_t3;
+typedef vector<int16_t, 4> int16_t4;
+typedef vector<uint16_t, 2> uint16_t2;
+typedef vector<uint16_t, 3> uint16_t3;
+typedef vector<uint16_t, 4> uint16_t4;
#endif
-typedef int int2 __attribute__((ext_vector_type(2)));
-typedef int int3 __attribute__((ext_vector_type(3)));
-typedef int int4 __attribute__((ext_vector_type(4)));
-typedef uint uint2 __attribute__((ext_vector_type(2)));
-typedef uint uint3 __attribute__((ext_vector_type(3)));
-typedef uint uint4 __attribute__((ext_vector_type(4)));
-typedef int64_t int64_t2 __attribute__((ext_vector_type(2)));
-typedef int64_t int64_t3 __attribute__((ext_vector_type(3)));
-typedef int64_t int64_t4 __attribute__((ext_vector_type(4)));
-typedef uint64_t uint64_t2 __attribute__((ext_vector_type(2)));
-typedef uint64_t uint64_t3 __attribute__((ext_vector_type(3)));
-typedef uint64_t uint64_t4 __attribute__((ext_vector_type(4)));
+typedef vector<int, 2> int2;
+typedef vector<int, 3> int3;
+typedef vector<int, 4> int4;
+typedef vector<uint, 2> uint2;
+typedef vector<uint, 3> uint3;
+typedef vector<uint, 4> uint4;
+typedef vector<int64_t, 2> int64_t2;
+typedef vector<int64_t, 3> int64_t3;
+typedef vector<int64_t, 4> int64_t4;
+typedef vector<uint64_t, 2> uint64_t2;
+typedef vector<uint64_t, 3> uint64_t3;
+typedef vector<uint64_t, 4> uint64_t4;
#ifdef __HLSL_ENABLE_16_BIT
-typedef half half2 __attribute__((ext_vector_type(2)));
-typedef half half3 __attribute__((ext_vector_type(3)));
-typedef half half4 __attribute__((ext_vector_type(4)));
+typedef vector<half, 2> half2;
+typedef vector<half, 3> half3;
+typedef vector<half, 4> half4;
#endif
-typedef float float2 __attribute__((ext_vector_type(2)));
-typedef float float3 __attribute__((ext_vector_type(3)));
-typedef float float4 __attribute__((ext_vector_type(4)));
-typedef double double2 __attribute__((ext_vector_type(2)));
-typedef double double3 __attribute__((ext_vector_type(3)));
-typedef double double4 __attribute__((ext_vector_type(4)));
+typedef vector<float, 2> float2;
+typedef vector<float, 3> float3;
+typedef vector<float, 4> float4;
+typedef vector<double, 2> double2;
+typedef vector<double, 3> double3;
+typedef vector<double, 4> double4;
#endif //_HLSL_HLSL_BASIC_TYPES_H_
diff --git a/clang/lib/Headers/opencl-c.h b/clang/lib/Headers/opencl-c.h
index ed647d9e9c06..72a6bfeafd6a 100644
--- a/clang/lib/Headers/opencl-c.h
+++ b/clang/lib/Headers/opencl-c.h
@@ -10467,12 +10467,6 @@ float __ovld __cnfn fast_distance(float, float);
float __ovld __cnfn fast_distance(float2, float2);
float __ovld __cnfn fast_distance(float3, float3);
float __ovld __cnfn fast_distance(float4, float4);
-#ifdef cl_khr_fp16
-half __ovld __cnfn fast_distance(half, half);
-half __ovld __cnfn fast_distance(half2, half2);
-half __ovld __cnfn fast_distance(half3, half3);
-half __ovld __cnfn fast_distance(half4, half4);
-#endif //cl_khr_fp16
/**
* Returns the length of vector p computed as:
@@ -10482,12 +10476,6 @@ float __ovld __cnfn fast_length(float);
float __ovld __cnfn fast_length(float2);
float __ovld __cnfn fast_length(float3);
float __ovld __cnfn fast_length(float4);
-#ifdef cl_khr_fp16
-half __ovld __cnfn fast_length(half);
-half __ovld __cnfn fast_length(half2);
-half __ovld __cnfn fast_length(half3);
-half __ovld __cnfn fast_length(half4);
-#endif //cl_khr_fp16
/**
* Returns a vector in the same direction as p but with a
@@ -10514,12 +10502,6 @@ float __ovld __cnfn fast_normalize(float);
float2 __ovld __cnfn fast_normalize(float2);
float3 __ovld __cnfn fast_normalize(float3);
float4 __ovld __cnfn fast_normalize(float4);
-#ifdef cl_khr_fp16
-half __ovld __cnfn fast_normalize(half);
-half2 __ovld __cnfn fast_normalize(half2);
-half3 __ovld __cnfn fast_normalize(half3);
-half4 __ovld __cnfn fast_normalize(half4);
-#endif //cl_khr_fp16
// OpenCL v1.1 s6.11.6, v1.2 s6.12.6, v2.0 s6.13.6 - Relational Functions
diff --git a/clang/lib/Headers/rdpruintrin.h b/clang/lib/Headers/rdpruintrin.h
new file mode 100644
index 000000000000..89732bb8b3cf
--- /dev/null
+++ b/clang/lib/Headers/rdpruintrin.h
@@ -0,0 +1,57 @@
+/*===---- rdpruintrin.h - RDPRU intrinsics ---------------------------------===
+ *
+ * Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+ * See https://llvm.org/LICENSE.txt for license information.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ *
+ *===-----------------------------------------------------------------------===
+ */
+
+#if !defined __X86INTRIN_H
+#error "Never use <rdpruintrin.h> directly; include <x86intrin.h> instead."
+#endif
+
+#ifndef __RDPRUINTRIN_H
+#define __RDPRUINTRIN_H
+
+/* Define the default attributes for the functions in this file. */
+#define __DEFAULT_FN_ATTRS \
+ __attribute__((__always_inline__, __nodebug__, __target__("rdpru")))
+
+
+/// Reads the content of a processor register.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the <c> RDPRU </c> instruction.
+///
+/// \param reg_id
+/// A processor register identifier.
+static __inline__ unsigned long long __DEFAULT_FN_ATTRS
+__rdpru (int reg_id)
+{
+ return __builtin_ia32_rdpru(reg_id);
+}
+
+#define __RDPRU_MPERF 0
+#define __RDPRU_APERF 1
+
+/// Reads the content of processor register MPERF.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic generates instruction <c> RDPRU </c> to read the value of
+/// register MPERF.
+#define __mperf() __builtin_ia32_rdpru(__RDPRU_MPERF)
+
+/// Reads the content of processor register APERF.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic generates instruction <c> RDPRU </c> to read the value of
+/// register APERF.
+#define __aperf() __builtin_ia32_rdpru(__RDPRU_APERF)
+
+#undef __DEFAULT_FN_ATTRS
+
+#endif /* __RDPRUINTRIN_H */
diff --git a/clang/lib/Headers/stdatomic.h b/clang/lib/Headers/stdatomic.h
index 780bcc2dfea1..3a0b9cc056be 100644
--- a/clang/lib/Headers/stdatomic.h
+++ b/clang/lib/Headers/stdatomic.h
@@ -158,10 +158,6 @@ typedef _Atomic(uintmax_t) atomic_uintmax_t;
typedef struct atomic_flag { atomic_bool _Value; } atomic_flag;
#define ATOMIC_FLAG_INIT { 0 }
-#if __cplusplus >= 202002L && !defined(_CLANG_DISABLE_CRT_DEPRECATION_WARNINGS)
-/* ATOMIC_FLAG_INIT was deprecated in C++20 but is not deprecated in C. */
-#pragma clang deprecated(ATOMIC_FLAG_INIT)
-#endif
/* These should be provided by the libc implementation. */
#ifdef __cplusplus
diff --git a/clang/lib/Headers/x86intrin.h b/clang/lib/Headers/x86intrin.h
index 768d0e56ab05..450fd008dab9 100644
--- a/clang/lib/Headers/x86intrin.h
+++ b/clang/lib/Headers/x86intrin.h
@@ -59,5 +59,9 @@
#include <clzerointrin.h>
#endif
+#if !(defined(_MSC_VER) || defined(__SCE__)) || __has_feature(modules) || \
+ defined(__RDPRU__)
+#include <rdpruintrin.h>
+#endif
#endif /* __X86INTRIN_H */
diff --git a/clang/lib/Lex/DependencyDirectivesScanner.cpp b/clang/lib/Lex/DependencyDirectivesScanner.cpp
index be7b7d6e17b2..567ca81f6ac2 100644
--- a/clang/lib/Lex/DependencyDirectivesScanner.cpp
+++ b/clang/lib/Lex/DependencyDirectivesScanner.cpp
@@ -550,7 +550,7 @@ Scanner::tryLexIdentifierOrSkipLine(const char *&First, const char *const End) {
StringRef Scanner::lexIdentifier(const char *&First, const char *const End) {
Optional<StringRef> Id = tryLexIdentifierOrSkipLine(First, End);
assert(Id && "expected identifier token");
- return Id.getValue();
+ return Id.value();
}
bool Scanner::isNextIdentifierOrSkipLine(StringRef Id, const char *&First,
diff --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp
index 6820057642be..b3aac9df6546 100644
--- a/clang/lib/Lex/Lexer.cpp
+++ b/clang/lib/Lex/Lexer.cpp
@@ -2392,13 +2392,37 @@ bool Lexer::SkipLineComment(Token &Result, const char *CurPtr,
//
// This loop terminates with CurPtr pointing at the newline (or end of buffer)
// character that ends the line comment.
+
+ // C++23 [lex.phases] p1
+ // Diagnose invalid UTF-8 if the corresponding warning is enabled, emitting a
+ // diagnostic only once per entire ill-formed subsequence to avoid
+ // emiting to many diagnostics (see http://unicode.org/review/pr-121.html).
+ bool UnicodeDecodingAlreadyDiagnosed = false;
+
char C;
while (true) {
C = *CurPtr;
// Skip over characters in the fast loop.
- while (C != 0 && // Potentially EOF.
- C != '\n' && C != '\r') // Newline or DOS-style newline.
+ while (isASCII(C) && C != 0 && // Potentially EOF.
+ C != '\n' && C != '\r') { // Newline or DOS-style newline.
C = *++CurPtr;
+ UnicodeDecodingAlreadyDiagnosed = false;
+ }
+
+ if (!isASCII(C)) {
+ unsigned Length = llvm::getUTF8SequenceSize(
+ (const llvm::UTF8 *)CurPtr, (const llvm::UTF8 *)BufferEnd);
+ if (Length == 0) {
+ if (!UnicodeDecodingAlreadyDiagnosed && !isLexingRawMode())
+ Diag(CurPtr, diag::warn_invalid_utf8_in_comment);
+ UnicodeDecodingAlreadyDiagnosed = true;
+ ++CurPtr;
+ } else {
+ UnicodeDecodingAlreadyDiagnosed = false;
+ CurPtr += Length;
+ }
+ continue;
+ }
const char *NextLine = CurPtr;
if (C != 0) {
@@ -2665,6 +2689,12 @@ bool Lexer::SkipBlockComment(Token &Result, const char *CurPtr,
if (C == '/')
C = *CurPtr++;
+ // C++23 [lex.phases] p1
+ // Diagnose invalid UTF-8 if the corresponding warning is enabled, emitting a
+ // diagnostic only once per entire ill-formed subsequence to avoid
+ // emiting to many diagnostics (see http://unicode.org/review/pr-121.html).
+ bool UnicodeDecodingAlreadyDiagnosed = false;
+
while (true) {
// Skip over all non-interesting characters until we find end of buffer or a
// (probably ending) '/' character.
@@ -2673,14 +2703,21 @@ bool Lexer::SkipBlockComment(Token &Result, const char *CurPtr,
// doesn't check for '\0'.
!(PP && PP->getCodeCompletionFileLoc() == FileLoc)) {
// While not aligned to a 16-byte boundary.
- while (C != '/' && ((intptr_t)CurPtr & 0x0F) != 0)
+ while (C != '/' && (intptr_t)CurPtr % 16 != 0) {
+ if (!isASCII(C))
+ goto MultiByteUTF8;
C = *CurPtr++;
-
+ }
if (C == '/') goto FoundSlash;
#ifdef __SSE2__
__m128i Slashes = _mm_set1_epi8('/');
- while (CurPtr+16 <= BufferEnd) {
+ while (CurPtr + 16 < BufferEnd) {
+ int Mask = _mm_movemask_epi8(*(const __m128i *)CurPtr);
+ if (LLVM_UNLIKELY(Mask != 0)) {
+ goto MultiByteUTF8;
+ }
+ // look for slashes
int cmp = _mm_movemask_epi8(_mm_cmpeq_epi8(*(const __m128i*)CurPtr,
Slashes));
if (cmp != 0) {
@@ -2693,21 +2730,38 @@ bool Lexer::SkipBlockComment(Token &Result, const char *CurPtr,
CurPtr += 16;
}
#elif __ALTIVEC__
+ __vector unsigned char LongUTF = {0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80};
__vector unsigned char Slashes = {
'/', '/', '/', '/', '/', '/', '/', '/',
'/', '/', '/', '/', '/', '/', '/', '/'
};
- while (CurPtr + 16 <= BufferEnd &&
- !vec_any_eq(*(const __vector unsigned char *)CurPtr, Slashes))
+ while (CurPtr + 16 < BufferEnd) {
+ if (LLVM_UNLIKELY(
+ vec_any_ge(*(const __vector unsigned char *)CurPtr, LongUTF)))
+ goto MultiByteUTF8;
+ if (vec_any_eq(*(const __vector unsigned char *)CurPtr, Slashes)) {
+ break;
+ }
CurPtr += 16;
+ }
+
#else
- // Scan for '/' quickly. Many block comments are very large.
- while (CurPtr[0] != '/' &&
- CurPtr[1] != '/' &&
- CurPtr[2] != '/' &&
- CurPtr[3] != '/' &&
- CurPtr+4 < BufferEnd) {
- CurPtr += 4;
+ while (CurPtr + 16 < BufferEnd) {
+ bool HasNonASCII = false;
+ for (unsigned I = 0; I < 16; ++I)
+ HasNonASCII |= !isASCII(CurPtr[I]);
+
+ if (LLVM_UNLIKELY(HasNonASCII))
+ goto MultiByteUTF8;
+
+ bool HasSlash = false;
+ for (unsigned I = 0; I < 16; ++I)
+ HasSlash |= CurPtr[I] == '/';
+ if (HasSlash)
+ break;
+ CurPtr += 16;
}
#endif
@@ -2715,9 +2769,30 @@ bool Lexer::SkipBlockComment(Token &Result, const char *CurPtr,
C = *CurPtr++;
}
- // Loop to scan the remainder.
- while (C != '/' && C != '\0')
+ // Loop to scan the remainder, warning on invalid UTF-8
+ // if the corresponding warning is enabled, emitting a diagnostic only once
+ // per sequence that cannot be decoded.
+ while (C != '/' && C != '\0') {
+ if (isASCII(C)) {
+ UnicodeDecodingAlreadyDiagnosed = false;
+ C = *CurPtr++;
+ continue;
+ }
+ MultiByteUTF8:
+ // CurPtr is 1 code unit past C, so to decode
+ // the codepoint, we need to read from the previous position.
+ unsigned Length = llvm::getUTF8SequenceSize(
+ (const llvm::UTF8 *)CurPtr - 1, (const llvm::UTF8 *)BufferEnd);
+ if (Length == 0) {
+ if (!UnicodeDecodingAlreadyDiagnosed && !isLexingRawMode())
+ Diag(CurPtr - 1, diag::warn_invalid_utf8_in_comment);
+ UnicodeDecodingAlreadyDiagnosed = true;
+ } else {
+ UnicodeDecodingAlreadyDiagnosed = false;
+ CurPtr += Length - 1;
+ }
C = *CurPtr++;
+ }
if (C == '/') {
FoundSlash:
@@ -3212,7 +3287,10 @@ llvm::Optional<uint32_t> Lexer::tryReadNumericUCN(const char *&StartPtr,
}
if (Delimited && PP) {
- Diag(BufferPtr, diag::ext_delimited_escape_sequence) << /*delimited*/ 0;
+ Diag(BufferPtr, PP->getLangOpts().CPlusPlus2b
+ ? diag::warn_cxx2b_delimited_escape_sequence
+ : diag::ext_delimited_escape_sequence)
+ << /*delimited*/ 0 << (PP->getLangOpts().CPlusPlus ? 1 : 0);
}
if (Result) {
@@ -3296,7 +3374,10 @@ llvm::Optional<uint32_t> Lexer::tryReadNamedUCN(const char *&StartPtr,
}
if (Diagnose && PP && !LooseMatch)
- Diag(BufferPtr, diag::ext_delimited_escape_sequence) << /*named*/ 1;
+ Diag(BufferPtr, PP->getLangOpts().CPlusPlus2b
+ ? diag::warn_cxx2b_delimited_escape_sequence
+ : diag::ext_delimited_escape_sequence)
+ << /*named*/ 1 << (PP->getLangOpts().CPlusPlus ? 1 : 0);
if (LooseMatch)
Res = LooseMatch->CodePoint;
diff --git a/clang/lib/Lex/LiteralSupport.cpp b/clang/lib/Lex/LiteralSupport.cpp
index ebf30c9f01a9..53635a7385ec 100644
--- a/clang/lib/Lex/LiteralSupport.cpp
+++ b/clang/lib/Lex/LiteralSupport.cpp
@@ -311,8 +311,9 @@ static unsigned ProcessCharEscape(const char *ThisTokBegin,
<< tok::r_brace;
else if (!HadError) {
Diag(Diags, Features, Loc, ThisTokBegin, EscapeBegin, ThisTokBuf,
- diag::ext_delimited_escape_sequence)
- << /*delimited*/ 0;
+ Features.CPlusPlus2b ? diag::warn_cxx2b_delimited_escape_sequence
+ : diag::ext_delimited_escape_sequence)
+ << /*delimited*/ 0 << (Features.CPlusPlus ? 1 : 0);
}
}
@@ -641,8 +642,9 @@ static bool ProcessUCNEscape(const char *ThisTokBegin, const char *&ThisTokBuf,
if ((IsDelimitedEscapeSequence || IsNamedEscapeSequence) && Diags)
Diag(Diags, Features, Loc, ThisTokBegin, UcnBegin, ThisTokBuf,
- diag::ext_delimited_escape_sequence)
- << (IsNamedEscapeSequence ? 1 : 0);
+ Features.CPlusPlus2b ? diag::warn_cxx2b_delimited_escape_sequence
+ : diag::ext_delimited_escape_sequence)
+ << (IsNamedEscapeSequence ? 1 : 0) << (Features.CPlusPlus ? 1 : 0);
return true;
}
diff --git a/clang/lib/Lex/MacroInfo.cpp b/clang/lib/Lex/MacroInfo.cpp
index 310b95f36771..eae12beb6244 100644
--- a/clang/lib/Lex/MacroInfo.cpp
+++ b/clang/lib/Lex/MacroInfo.cpp
@@ -213,7 +213,7 @@ MacroDirective::DefInfo MacroDirective::getDefinition() {
isPublic = VisMD->isPublic();
}
- return DefInfo(nullptr, UndefLoc, !isPublic || isPublic.getValue());
+ return DefInfo(nullptr, UndefLoc, !isPublic || isPublic.value());
}
const MacroDirective::DefInfo
diff --git a/clang/lib/Lex/ModuleMap.cpp b/clang/lib/Lex/ModuleMap.cpp
index c791e3e4e5ca..57e344622f25 100644
--- a/clang/lib/Lex/ModuleMap.cpp
+++ b/clang/lib/Lex/ModuleMap.cpp
@@ -1219,8 +1219,8 @@ void ModuleMap::resolveHeaderDirectives(
Module *Mod, llvm::Optional<const FileEntry *> File) const {
bool NeedsFramework = false;
SmallVector<Module::UnresolvedHeaderDirective, 1> NewHeaders;
- const auto Size = File ? File.getValue()->getSize() : 0;
- const auto ModTime = File ? File.getValue()->getModificationTime() : 0;
+ const auto Size = File ? File.value()->getSize() : 0;
+ const auto ModTime = File ? File.value()->getModificationTime() : 0;
for (auto &Header : Mod->UnresolvedHeaders) {
if (File && ((Header.ModTime && Header.ModTime != ModTime) ||
diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp
index 4dcef01e3e4c..352e1f217819 100644
--- a/clang/lib/Lex/PPDirectives.cpp
+++ b/clang/lib/Lex/PPDirectives.cpp
@@ -1983,6 +1983,10 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
EnterAnnotationToken(SourceRange(HashLoc, EndLoc),
tok::annot_module_begin, Action.ModuleForHeader);
break;
+ case ImportAction::HeaderUnitImport:
+ EnterAnnotationToken(SourceRange(HashLoc, EndLoc), tok::annot_header_unit,
+ Action.ModuleForHeader);
+ break;
case ImportAction::ModuleImport:
EnterAnnotationToken(SourceRange(HashLoc, EndLoc),
tok::annot_module_include, Action.ModuleForHeader);
@@ -2191,6 +2195,17 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(
// known to have no effect beyond its effect on module visibility -- that is,
// if it's got an include guard that is already defined, set to Import if it
// is a modular header we've already built and should import.
+
+ // For C++20 Modules
+ // [cpp.include]/7 If the header identified by the header-name denotes an
+ // importable header, it is implementation-defined whether the #include
+ // preprocessing directive is instead replaced by an import directive.
+ // For this implementation, the translation is permitted when we are parsing
+ // the Global Module Fragment, and not otherwise (the cases where it would be
+ // valid to replace an include with an import are highly constrained once in
+ // named module purview; this choice avoids considerable complexity in
+ // determining valid cases).
+
enum { Enter, Import, Skip, IncludeLimitReached } Action = Enter;
if (PPOpts->SingleFileParseMode)
@@ -2203,13 +2218,34 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(
alreadyIncluded(*File))
Action = IncludeLimitReached;
+ bool MaybeTranslateInclude = Action == Enter && File && SuggestedModule &&
+ !isForModuleBuilding(SuggestedModule.getModule(),
+ getLangOpts().CurrentModule,
+ getLangOpts().ModuleName);
+
+ // FIXME: We do not have a good way to disambiguate C++ clang modules from
+ // C++ standard modules (other than use/non-use of Header Units).
+ Module *SM = SuggestedModule.getModule();
+ // Maybe a usable Header Unit
+ bool UsableHeaderUnit = false;
+ if (getLangOpts().CPlusPlusModules && SM && SM->isHeaderUnit()) {
+ if (TrackGMFState.inGMF() || IsImportDecl)
+ UsableHeaderUnit = true;
+ else if (!IsImportDecl) {
+ // This is a Header Unit that we do not include-translate
+ SuggestedModule = ModuleMap::KnownHeader();
+ SM = nullptr;
+ }
+ }
+ // Maybe a usable clang header module.
+ bool UsableHeaderModule =
+ (getLangOpts().CPlusPlusModules || getLangOpts().Modules) && SM &&
+ !SM->isHeaderUnit();
+
// Determine whether we should try to import the module for this #include, if
// there is one. Don't do so if precompiled module support is disabled or we
// are processing this module textually (because we're building the module).
- if (Action == Enter && File && SuggestedModule && getLangOpts().Modules &&
- !isForModuleBuilding(SuggestedModule.getModule(),
- getLangOpts().CurrentModule,
- getLangOpts().ModuleName)) {
+ if (MaybeTranslateInclude && (UsableHeaderUnit || UsableHeaderModule)) {
// If this include corresponds to a module but that module is
// unavailable, diagnose the situation and bail out.
// FIXME: Remove this; loadModule does the same check (but produces
@@ -2226,7 +2262,7 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(
// FIXME: Should we have a second loadModule() overload to avoid this
// extra lookup step?
SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> Path;
- for (Module *Mod = SuggestedModule.getModule(); Mod; Mod = Mod->Parent)
+ for (Module *Mod = SM; Mod; Mod = Mod->Parent)
Path.push_back(std::make_pair(getIdentifierInfo(Mod->Name),
FilenameTok.getLocation()));
std::reverse(Path.begin(), Path.end());
@@ -2293,9 +2329,12 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(
// Ask HeaderInfo if we should enter this #include file. If not, #including
// this file will have no effect.
if (Action == Enter && File &&
- !HeaderInfo.ShouldEnterIncludeFile(
- *this, &File->getFileEntry(), EnterOnce, getLangOpts().Modules,
- SuggestedModule.getModule(), IsFirstIncludeOfFile)) {
+ !HeaderInfo.ShouldEnterIncludeFile(*this, &File->getFileEntry(),
+ EnterOnce, getLangOpts().Modules, SM,
+ IsFirstIncludeOfFile)) {
+ // C++ standard modules:
+ // If we are not in the GMF, then we textually include only
+ // clang modules:
// Even if we've already preprocessed this header once and know that we
// don't need to see its contents again, we still need to import it if it's
// modular because we might not have imported it from this submodule before.
@@ -2303,7 +2342,10 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(
// FIXME: We don't do this when compiling a PCH because the AST
// serialization layer can't cope with it. This means we get local
// submodule visibility semantics wrong in that case.
- Action = (SuggestedModule && !getLangOpts().CompilingPCH) ? Import : Skip;
+ if (UsableHeaderUnit && !getLangOpts().CompilingPCH)
+ Action = TrackGMFState.inGMF() ? Import : Skip;
+ else
+ Action = (SuggestedModule && !getLangOpts().CompilingPCH) ? Import : Skip;
}
// Check for circular inclusion of the main file.
@@ -2440,8 +2482,8 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(
switch (Action) {
case Skip:
// If we don't need to enter the file, stop now.
- if (Module *M = SuggestedModule.getModule())
- return {ImportAction::SkippedModuleImport, M};
+ if (SM)
+ return {ImportAction::SkippedModuleImport, SM};
return {ImportAction::None};
case IncludeLimitReached:
@@ -2451,16 +2493,15 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(
case Import: {
// If this is a module import, make it visible if needed.
- Module *M = SuggestedModule.getModule();
- assert(M && "no module to import");
+ assert(SM && "no module to import");
- makeModuleVisible(M, EndLoc);
+ makeModuleVisible(SM, EndLoc);
if (IncludeTok.getIdentifierInfo()->getPPKeywordID() ==
tok::pp___include_macros)
return {ImportAction::None};
- return {ImportAction::ModuleImport, M};
+ return {ImportAction::ModuleImport, SM};
}
case Enter:
@@ -2492,13 +2533,14 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(
return {ImportAction::None};
// Determine if we're switching to building a new submodule, and which one.
- if (auto *M = SuggestedModule.getModule()) {
- if (M->getTopLevelModule()->ShadowingModule) {
+ // This does not apply for C++20 modules header units.
+ if (SM && !SM->isHeaderUnit()) {
+ if (SM->getTopLevelModule()->ShadowingModule) {
// We are building a submodule that belongs to a shadowed module. This
// means we find header files in the shadowed module.
- Diag(M->DefinitionLoc, diag::err_module_build_shadowed_submodule)
- << M->getFullModuleName();
- Diag(M->getTopLevelModule()->ShadowingModule->DefinitionLoc,
+ Diag(SM->DefinitionLoc, diag::err_module_build_shadowed_submodule)
+ << SM->getFullModuleName();
+ Diag(SM->getTopLevelModule()->ShadowingModule->DefinitionLoc,
diag::note_previous_definition);
return {ImportAction::None};
}
@@ -2511,22 +2553,22 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(
// that PCH, which means we should enter the submodule. We need to teach
// the AST serialization layer to deal with the resulting AST.
if (getLangOpts().CompilingPCH &&
- isForModuleBuilding(M, getLangOpts().CurrentModule,
+ isForModuleBuilding(SM, getLangOpts().CurrentModule,
getLangOpts().ModuleName))
return {ImportAction::None};
assert(!CurLexerSubmodule && "should not have marked this as a module yet");
- CurLexerSubmodule = M;
+ CurLexerSubmodule = SM;
// Let the macro handling code know that any future macros are within
// the new submodule.
- EnterSubmodule(M, EndLoc, /*ForPragma*/false);
+ EnterSubmodule(SM, EndLoc, /*ForPragma*/ false);
// Let the parser know that any future declarations are within the new
// submodule.
// FIXME: There's no point doing this if we're handling a #__include_macros
// directive.
- return {ImportAction::ModuleBegin, M};
+ return {ImportAction::ModuleBegin, SM};
}
assert(!IsImportDecl && "failed to diagnose missing module for import decl");
diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp
index bf46e5422bc8..f3be2107f985 100644
--- a/clang/lib/Lex/PPMacroExpansion.cpp
+++ b/clang/lib/Lex/PPMacroExpansion.cpp
@@ -1326,10 +1326,10 @@ already_lexed:
// The last ')' has been reached; return the value if one found or
// a diagnostic and a dummy value.
if (Result) {
- OS << Result.getValue();
+ OS << Result.value();
// For strict conformance to __has_cpp_attribute rules, use 'L'
// suffix for dated literals.
- if (Result.getValue() > 1)
+ if (Result.value() > 1)
OS << 'L';
} else {
OS << 0;
diff --git a/clang/lib/Lex/PreprocessingRecord.cpp b/clang/lib/Lex/PreprocessingRecord.cpp
index 673ef637e396..2146a7c04217 100644
--- a/clang/lib/Lex/PreprocessingRecord.cpp
+++ b/clang/lib/Lex/PreprocessingRecord.cpp
@@ -115,7 +115,7 @@ bool PreprocessingRecord::isEntityInFileID(iterator PPEI, FileID FID) {
Optional<bool> IsInFile =
ExternalSource->isPreprocessedEntityInFileID(LoadedIndex, FID);
if (IsInFile)
- return IsInFile.getValue();
+ return IsInFile.value();
// The external source did not provide a definite answer, go and deserialize
// the entity to check it.
diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp
index 281f01fb28a4..5310db3c882b 100644
--- a/clang/lib/Lex/Preprocessor.cpp
+++ b/clang/lib/Lex/Preprocessor.cpp
@@ -941,6 +941,9 @@ void Preprocessor::Lex(Token &Result) {
// Update ImportSeqState to track our position within a C++20 import-seq
// if this token is being produced as a result of phase 4 of translation.
+ // Update TrackGMFState to decide if we are currently in a Global Module
+ // Fragment. GMF state updates should precede ImportSeq ones, since GMF state
+ // depends on the prevailing ImportSeq state in two cases.
if (getLangOpts().CPlusPlusModules && LexLevel == 1 &&
!Result.getFlag(Token::IsReinjected)) {
switch (Result.getKind()) {
@@ -953,7 +956,11 @@ void Preprocessor::Lex(Token &Result) {
case tok::r_brace:
ImportSeqState.handleCloseBrace();
break;
+ // This token is injected to represent the translation of '#include "a.h"'
+ // into "import a.h;". Mimic the notional ';'.
+ case tok::annot_module_include:
case tok::semi:
+ TrackGMFState.handleSemi();
ImportSeqState.handleSemi();
break;
case tok::header_name:
@@ -961,10 +968,12 @@ void Preprocessor::Lex(Token &Result) {
ImportSeqState.handleHeaderName();
break;
case tok::kw_export:
+ TrackGMFState.handleExport();
ImportSeqState.handleExport();
break;
case tok::identifier:
if (Result.getIdentifierInfo()->isModulesImport()) {
+ TrackGMFState.handleImport(ImportSeqState.afterTopLevelSeq());
ImportSeqState.handleImport();
if (ImportSeqState.afterImportSeq()) {
ModuleImportLoc = Result.getLocation();
@@ -973,9 +982,13 @@ void Preprocessor::Lex(Token &Result) {
CurLexerKind = CLK_LexAfterModuleImport;
}
break;
+ } else if (Result.getIdentifierInfo() == getIdentifierInfo("module")) {
+ TrackGMFState.handleModule(ImportSeqState.afterTopLevelSeq());
+ break;
}
LLVM_FALLTHROUGH;
default:
+ TrackGMFState.handleMisc();
ImportSeqState.handleMisc();
break;
}
@@ -1222,6 +1235,7 @@ bool Preprocessor::LexAfterModuleImport(Token &Result) {
LLVM_FALLTHROUGH;
case ImportAction::ModuleImport:
+ case ImportAction::HeaderUnitImport:
case ImportAction::SkippedModuleImport:
// We chose to import (or textually enter) the file. Convert the
// header-name token into a header unit annotation token.
diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp
index 08dccf9e43f7..5f53f9d684e7 100644
--- a/clang/lib/Parse/ParseOpenMP.cpp
+++ b/clang/lib/Parse/ParseOpenMP.cpp
@@ -1884,11 +1884,11 @@ void Parser::ParseOMPDeclareTargetClauses(
if (DevTypeData) {
if (DeviceTypeLoc.isValid()) {
// We already saw another device_type clause, diagnose it.
- Diag(DevTypeData.getValue().Loc,
+ Diag(DevTypeData.value().Loc,
diag::warn_omp_more_one_device_type_clause);
break;
}
- switch (static_cast<OpenMPDeviceType>(DevTypeData.getValue().Type)) {
+ switch (static_cast<OpenMPDeviceType>(DevTypeData.value().Type)) {
case OMPC_DEVICE_TYPE_any:
DTCI.DT = OMPDeclareTargetDeclAttr::DT_Any;
break;
@@ -3634,20 +3634,20 @@ OMPClause *Parser::ParseOpenMPSimpleClause(OpenMPClauseKind Kind,
if (!Val || ParseOnly)
return nullptr;
if (getLangOpts().OpenMP < 51 && Kind == OMPC_default &&
- (static_cast<DefaultKind>(Val.getValue().Type) == OMP_DEFAULT_private ||
- static_cast<DefaultKind>(Val.getValue().Type) ==
+ (static_cast<DefaultKind>(Val.value().Type) == OMP_DEFAULT_private ||
+ static_cast<DefaultKind>(Val.value().Type) ==
OMP_DEFAULT_firstprivate)) {
- Diag(Val.getValue().LOpen, diag::err_omp_invalid_dsa)
- << getOpenMPClauseName(static_cast<DefaultKind>(Val.getValue().Type) ==
+ Diag(Val.value().LOpen, diag::err_omp_invalid_dsa)
+ << getOpenMPClauseName(static_cast<DefaultKind>(Val.value().Type) ==
OMP_DEFAULT_private
? OMPC_private
: OMPC_firstprivate)
<< getOpenMPClauseName(OMPC_default) << "5.1";
return nullptr;
}
- return Actions.ActOnOpenMPSimpleClause(
- Kind, Val.getValue().Type, Val.getValue().TypeLoc, Val.getValue().LOpen,
- Val.getValue().Loc, Val.getValue().RLoc);
+ return Actions.ActOnOpenMPSimpleClause(Kind, Val.value().Type,
+ Val.value().TypeLoc, Val.value().LOpen,
+ Val.value().Loc, Val.value().RLoc);
}
/// Parsing of OpenMP clauses like 'ordered'.
diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp
index 6f63d01bc8ad..ab8748c2c63d 100644
--- a/clang/lib/Parse/Parser.cpp
+++ b/clang/lib/Parse/Parser.cpp
@@ -663,12 +663,22 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result,
return false;
}
- case tok::annot_module_include:
- Actions.ActOnModuleInclude(Tok.getLocation(),
- reinterpret_cast<Module *>(
- Tok.getAnnotationValue()));
+ case tok::annot_module_include: {
+ auto Loc = Tok.getLocation();
+ Module *Mod = reinterpret_cast<Module *>(Tok.getAnnotationValue());
+ // FIXME: We need a better way to disambiguate C++ clang modules and
+ // standard C++ modules.
+ if (!getLangOpts().CPlusPlusModules || !Mod->isHeaderUnit())
+ Actions.ActOnModuleInclude(Loc, Mod);
+ else {
+ DeclResult Import =
+ Actions.ActOnModuleImport(Loc, SourceLocation(), Loc, Mod);
+ Decl *ImportDecl = Import.isInvalid() ? nullptr : Import.get();
+ Result = Actions.ConvertDeclToDeclGroup(ImportDecl);
+ }
ConsumeAnnotationToken();
return false;
+ }
case tok::annot_module_begin:
Actions.ActOnModuleBegin(Tok.getLocation(), reinterpret_cast<Module *>(
diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp
new file mode 100644
index 000000000000..56c2dd40bd9a
--- /dev/null
+++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp
@@ -0,0 +1,96 @@
+//===--- HLSLExternalSemaSource.cpp - HLSL Sema Source --------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Sema/HLSLExternalSemaSource.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/Basic/AttrKinds.h"
+#include "clang/Sema/Sema.h"
+
+using namespace clang;
+
+HLSLExternalSemaSource::~HLSLExternalSemaSource() {}
+
+void HLSLExternalSemaSource::InitializeSema(Sema &S) {
+ SemaPtr = &S;
+ ASTContext &AST = SemaPtr->getASTContext();
+ IdentifierInfo &HLSL = AST.Idents.get("hlsl", tok::TokenKind::identifier);
+ HLSLNamespace =
+ NamespaceDecl::Create(AST, AST.getTranslationUnitDecl(), false,
+ SourceLocation(), SourceLocation(), &HLSL, nullptr);
+ HLSLNamespace->setImplicit(true);
+ AST.getTranslationUnitDecl()->addDecl(HLSLNamespace);
+ defineHLSLVectorAlias();
+
+ // This adds a `using namespace hlsl` directive. In DXC, we don't put HLSL's
+ // built in types inside a namespace, but we are planning to change that in
+ // the near future. In order to be source compatible older versions of HLSL
+ // will need to implicitly use the hlsl namespace. For now in clang everything
+ // will get added to the namespace, and we can remove the using directive for
+ // future language versions to match HLSL's evolution.
+ auto *UsingDecl = UsingDirectiveDecl::Create(
+ AST, AST.getTranslationUnitDecl(), SourceLocation(), SourceLocation(),
+ NestedNameSpecifierLoc(), SourceLocation(), HLSLNamespace,
+ AST.getTranslationUnitDecl());
+
+ AST.getTranslationUnitDecl()->addDecl(UsingDecl);
+}
+
+void HLSLExternalSemaSource::defineHLSLVectorAlias() {
+ ASTContext &AST = SemaPtr->getASTContext();
+
+ llvm::SmallVector<NamedDecl *> TemplateParams;
+
+ auto *TypeParam = TemplateTypeParmDecl::Create(
+ AST, HLSLNamespace, SourceLocation(), SourceLocation(), 0, 0,
+ &AST.Idents.get("element", tok::TokenKind::identifier), false, false);
+ TypeParam->setDefaultArgument(AST.getTrivialTypeSourceInfo(AST.FloatTy));
+
+ TemplateParams.emplace_back(TypeParam);
+
+ auto *SizeParam = NonTypeTemplateParmDecl::Create(
+ AST, HLSLNamespace, SourceLocation(), SourceLocation(), 0, 1,
+ &AST.Idents.get("element_count", tok::TokenKind::identifier), AST.IntTy,
+ false, AST.getTrivialTypeSourceInfo(AST.IntTy));
+ Expr *LiteralExpr =
+ IntegerLiteral::Create(AST, llvm::APInt(AST.getIntWidth(AST.IntTy), 4),
+ AST.IntTy, SourceLocation());
+ SizeParam->setDefaultArgument(LiteralExpr);
+ TemplateParams.emplace_back(SizeParam);
+
+ auto *ParamList =
+ TemplateParameterList::Create(AST, SourceLocation(), SourceLocation(),
+ TemplateParams, SourceLocation(), nullptr);
+
+ IdentifierInfo &II = AST.Idents.get("vector", tok::TokenKind::identifier);
+
+ QualType AliasType = AST.getDependentSizedExtVectorType(
+ AST.getTemplateTypeParmType(0, 0, false, TypeParam),
+ DeclRefExpr::Create(
+ AST, NestedNameSpecifierLoc(), SourceLocation(), SizeParam, false,
+ DeclarationNameInfo(SizeParam->getDeclName(), SourceLocation()),
+ AST.IntTy, VK_LValue),
+ SourceLocation());
+
+ auto *Record = TypeAliasDecl::Create(AST, HLSLNamespace, SourceLocation(),
+ SourceLocation(), &II,
+ AST.getTrivialTypeSourceInfo(AliasType));
+ Record->setImplicit(true);
+
+ auto *Template =
+ TypeAliasTemplateDecl::Create(AST, HLSLNamespace, SourceLocation(),
+ Record->getIdentifier(), ParamList, Record);
+
+ Record->setDescribedAliasTemplate(Template);
+ Template->setImplicit(true);
+ Template->setLexicalDeclContext(Record->getDeclContext());
+ HLSLNamespace->addDecl(Template);
+}
diff --git a/clang/lib/Sema/SemaCUDA.cpp b/clang/lib/Sema/SemaCUDA.cpp
index 8f8144d658d8..185ccebe2717 100644
--- a/clang/lib/Sema/SemaCUDA.cpp
+++ b/clang/lib/Sema/SemaCUDA.cpp
@@ -381,13 +381,13 @@ bool Sema::inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl,
InferredTarget = BaseMethodTarget;
} else {
bool ResolutionError = resolveCalleeCUDATargetConflict(
- InferredTarget.getValue(), BaseMethodTarget,
+ InferredTarget.value(), BaseMethodTarget,
InferredTarget.getPointer());
if (ResolutionError) {
if (Diagnose) {
Diag(ClassDecl->getLocation(),
diag::note_implicit_member_target_infer_collision)
- << (unsigned)CSM << InferredTarget.getValue() << BaseMethodTarget;
+ << (unsigned)CSM << InferredTarget.value() << BaseMethodTarget;
}
MemberDecl->addAttr(CUDAInvalidTargetAttr::CreateImplicit(Context));
return true;
@@ -425,14 +425,13 @@ bool Sema::inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl,
InferredTarget = FieldMethodTarget;
} else {
bool ResolutionError = resolveCalleeCUDATargetConflict(
- InferredTarget.getValue(), FieldMethodTarget,
+ InferredTarget.value(), FieldMethodTarget,
InferredTarget.getPointer());
if (ResolutionError) {
if (Diagnose) {
Diag(ClassDecl->getLocation(),
diag::note_implicit_member_target_infer_collision)
- << (unsigned)CSM << InferredTarget.getValue()
- << FieldMethodTarget;
+ << (unsigned)CSM << InferredTarget.value() << FieldMethodTarget;
}
MemberDecl->addAttr(CUDAInvalidTargetAttr::CreateImplicit(Context));
return true;
@@ -445,9 +444,9 @@ bool Sema::inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl,
// it's the least restrictive option that can be invoked from any target.
bool NeedsH = true, NeedsD = true;
if (InferredTarget) {
- if (InferredTarget.getValue() == CFT_Device)
+ if (InferredTarget.value() == CFT_Device)
NeedsH = false;
- else if (InferredTarget.getValue() == CFT_Host)
+ else if (InferredTarget.value() == CFT_Host)
NeedsD = false;
}
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 79420cc27699..aed1d9befe2b 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -109,6 +109,11 @@ SourceLocation Sema::getLocationOfStringLiteralByte(const StringLiteral *SL,
Context.getTargetInfo());
}
+static constexpr unsigned short combineFAPK(Sema::FormatArgumentPassingKind A,
+ Sema::FormatArgumentPassingKind B) {
+ return (A << 8) | B;
+}
+
/// Checks that a call expression's argument count is at least the desired
/// number. This is useful when doing custom type-checking on a variadic
/// function. Returns true on error.
@@ -1875,7 +1880,7 @@ static ExprResult SemaBuiltinLaunder(Sema &S, CallExpr *TheCall) {
}();
if (DiagSelect) {
S.Diag(TheCall->getBeginLoc(), diag::err_builtin_launder_invalid_arg)
- << DiagSelect.getValue() << TheCall->getSourceRange();
+ << DiagSelect.value() << TheCall->getSourceRange();
return ExprError();
}
@@ -2408,7 +2413,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
bool ReturnsPointer = BuiltinID == Builtin::BIaddressof ||
BuiltinID == Builtin::BI__addressof;
if (!(Param->isReferenceType() &&
- (ReturnsPointer ? Result->isPointerType()
+ (ReturnsPointer ? Result->isAnyPointerType()
: Result->isReferenceType()) &&
Context.hasSameUnqualifiedType(Param->getPointeeType(),
Result->getPointeeType()))) {
@@ -5403,10 +5408,16 @@ bool Sema::CheckX86BuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID,
/// Returns true when the format fits the function and the FormatStringInfo has
/// been populated.
bool Sema::getFormatStringInfo(const FormatAttr *Format, bool IsCXXMember,
- FormatStringInfo *FSI) {
- FSI->HasVAListArg = Format->getFirstArg() == 0;
+ bool IsVariadic, FormatStringInfo *FSI) {
+ if (Format->getFirstArg() == 0)
+ FSI->ArgPassingKind = FAPK_VAList;
+ else if (IsVariadic)
+ FSI->ArgPassingKind = FAPK_Variadic;
+ else
+ FSI->ArgPassingKind = FAPK_Fixed;
FSI->FormatIdx = Format->getFormatIdx() - 1;
- FSI->FirstDataArg = FSI->HasVAListArg ? 0 : Format->getFirstArg() - 1;
+ FSI->FirstDataArg =
+ FSI->ArgPassingKind == FAPK_VAList ? 0 : Format->getFirstArg() - 1;
// The way the format attribute works in GCC, the implicit this argument
// of member functions is counted. However, it doesn't appear in our own
@@ -5461,7 +5472,7 @@ static void CheckNonNullArgument(Sema &S,
bool Sema::GetFormatNSStringIdx(const FormatAttr *Format, unsigned &Idx) {
FormatStringInfo FSI;
if ((GetFormatStringType(Format) == FST_NSString) &&
- getFormatStringInfo(Format, false, &FSI)) {
+ getFormatStringInfo(Format, false, true, &FSI)) {
Idx = FSI.FormatIdx;
return true;
}
@@ -5615,6 +5626,40 @@ static void CheckNonNullArguments(Sema &S,
}
}
+// 16 byte ByVal alignment not due to a vector member is not honoured by XL
+// on AIX. Emit a warning here that users are generating binary incompatible
+// code to be safe.
+// Here we try to get information about the alignment of the struct member
+// from the struct passed to the caller function. We only warn when the struct
+// is passed byval, hence the series of checks and early returns if we are a not
+// passing a struct byval.
+void Sema::checkAIXMemberAlignment(SourceLocation Loc, const Expr *Arg) {
+ const auto *ICE = dyn_cast<ImplicitCastExpr>(Arg->IgnoreParens());
+ if (!ICE)
+ return;
+
+ const auto *DR = dyn_cast<DeclRefExpr>(ICE->getSubExpr());
+ if (!DR)
+ return;
+
+ const auto *PD = dyn_cast<ParmVarDecl>(DR->getDecl());
+ if (!PD || !PD->getType()->isRecordType())
+ return;
+
+ QualType ArgType = Arg->getType();
+ for (const FieldDecl *FD :
+ ArgType->castAs<RecordType>()->getDecl()->fields()) {
+ if (const auto *AA = FD->getAttr<AlignedAttr>()) {
+ CharUnits Alignment =
+ Context.toCharUnitsFromBits(AA->getAlignment(Context));
+ if (Alignment.getQuantity() == 16) {
+ Diag(FD->getLocation(), diag::warn_not_xl_compatible) << FD;
+ Diag(Loc, diag::note_misaligned_member_used_here) << PD;
+ }
+ }
+ }
+}
+
/// Warn if a pointer or reference argument passed to a function points to an
/// object that is less aligned than the parameter. This can happen when
/// creating a typedef with a lower alignment than the original type and then
@@ -5725,6 +5770,12 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto,
if (Arg->containsErrors())
continue;
+ if (Context.getTargetInfo().getTriple().isOSAIX() && FDecl && Arg &&
+ FDecl->hasLinkage() &&
+ FDecl->getFormalLinkage() != InternalLinkage &&
+ CallType == VariadicDoesNotApply)
+ checkAIXMemberAlignment((Arg->getExprLoc()), Arg);
+
QualType ParamTy = Proto->getParamType(ArgIdx);
QualType ArgTy = Arg->getType();
CheckArgAlignment(Arg->getExprLoc(), FDecl, std::to_string(ArgIdx + 1),
@@ -7695,7 +7746,7 @@ bool Sema::SemaBuiltinOSLogFormat(CallExpr *TheCall) {
llvm::SmallBitVector CheckedVarArgs(NumArgs, false);
ArrayRef<const Expr *> Args(TheCall->getArgs(), TheCall->getNumArgs());
bool Success = CheckFormatArguments(
- Args, /*HasVAListArg*/ false, FormatIdx, FirstDataArg, FST_OSLog,
+ Args, FAPK_Variadic, FormatIdx, FirstDataArg, FST_OSLog,
VariadicFunction, TheCall->getBeginLoc(), SourceRange(),
CheckedVarArgs);
if (!Success)
@@ -8412,19 +8463,15 @@ class FormatStringLiteral {
SourceLocation getEndLoc() const LLVM_READONLY { return FExpr->getEndLoc(); }
};
-} // namespace
+} // namespace
-static void CheckFormatString(Sema &S, const FormatStringLiteral *FExpr,
- const Expr *OrigFormatExpr,
- ArrayRef<const Expr *> Args,
- bool HasVAListArg, unsigned format_idx,
- unsigned firstDataArg,
- Sema::FormatStringType Type,
- bool inFunctionCall,
- Sema::VariadicCallType CallType,
- llvm::SmallBitVector &CheckedVarArgs,
- UncoveredArgHandler &UncoveredArg,
- bool IgnoreStringsWithoutSpecifiers);
+static void CheckFormatString(
+ Sema &S, const FormatStringLiteral *FExpr, const Expr *OrigFormatExpr,
+ ArrayRef<const Expr *> Args, Sema::FormatArgumentPassingKind APK,
+ unsigned format_idx, unsigned firstDataArg, Sema::FormatStringType Type,
+ bool inFunctionCall, Sema::VariadicCallType CallType,
+ llvm::SmallBitVector &CheckedVarArgs, UncoveredArgHandler &UncoveredArg,
+ bool IgnoreStringsWithoutSpecifiers);
// Determine if an expression is a string literal or constant string.
// If this function returns false on the arguments to a function expecting a
@@ -8432,16 +8479,15 @@ static void CheckFormatString(Sema &S, const FormatStringLiteral *FExpr,
// True string literals are then checked by CheckFormatString.
static StringLiteralCheckType
checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args,
- bool HasVAListArg, unsigned format_idx,
+ Sema::FormatArgumentPassingKind APK, unsigned format_idx,
unsigned firstDataArg, Sema::FormatStringType Type,
Sema::VariadicCallType CallType, bool InFunctionCall,
llvm::SmallBitVector &CheckedVarArgs,
- UncoveredArgHandler &UncoveredArg,
- llvm::APSInt Offset,
+ UncoveredArgHandler &UncoveredArg, llvm::APSInt Offset,
bool IgnoreStringsWithoutSpecifiers = false) {
if (S.isConstantEvaluated())
return SLCT_NotALiteral;
- tryAgain:
+tryAgain:
assert(Offset.isSigned() && "invalid offset");
if (E->isTypeDependent() || E->isValueDependent())
@@ -8486,9 +8532,8 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args,
if (!CheckLeft)
Left = SLCT_UncheckedLiteral;
else {
- Left = checkFormatStringExpr(S, C->getTrueExpr(), Args,
- HasVAListArg, format_idx, firstDataArg,
- Type, CallType, InFunctionCall,
+ Left = checkFormatStringExpr(S, C->getTrueExpr(), Args, APK, format_idx,
+ firstDataArg, Type, CallType, InFunctionCall,
CheckedVarArgs, UncoveredArg, Offset,
IgnoreStringsWithoutSpecifiers);
if (Left == SLCT_NotALiteral || !CheckRight) {
@@ -8497,8 +8542,8 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args,
}
StringLiteralCheckType Right = checkFormatStringExpr(
- S, C->getFalseExpr(), Args, HasVAListArg, format_idx, firstDataArg,
- Type, CallType, InFunctionCall, CheckedVarArgs, UncoveredArg, Offset,
+ S, C->getFalseExpr(), Args, APK, format_idx, firstDataArg, Type,
+ CallType, InFunctionCall, CheckedVarArgs, UncoveredArg, Offset,
IgnoreStringsWithoutSpecifiers);
return (CheckLeft && Left < Right) ? Left : Right;
@@ -8548,42 +8593,85 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args,
if (InitList->isStringLiteralInit())
Init = InitList->getInit(0)->IgnoreParenImpCasts();
}
- return checkFormatStringExpr(S, Init, Args,
- HasVAListArg, format_idx,
- firstDataArg, Type, CallType,
- /*InFunctionCall*/ false, CheckedVarArgs,
- UncoveredArg, Offset);
+ return checkFormatStringExpr(
+ S, Init, Args, APK, format_idx, firstDataArg, Type, CallType,
+ /*InFunctionCall*/ false, CheckedVarArgs, UncoveredArg, Offset);
}
}
- // For vprintf* functions (i.e., HasVAListArg==true), we add a
- // special check to see if the format string is a function parameter
- // of the function calling the printf function. If the function
- // has an attribute indicating it is a printf-like function, then we
- // should suppress warnings concerning non-literals being used in a call
- // to a vprintf function. For example:
+ // When the format argument is an argument of this function, and this
+ // function also has the format attribute, there are several interactions
+ // for which there shouldn't be a warning. For instance, when calling
+ // v*printf from a function that has the printf format attribute, we
+ // should not emit a warning about using `fmt`, even though it's not
+ // constant, because the arguments have already been checked for the
+ // caller of `logmessage`:
//
- // void
- // logmessage(char const *fmt __attribute__ (format (printf, 1, 2)), ...){
- // va_list ap;
- // va_start(ap, fmt);
- // vprintf(fmt, ap); // Do NOT emit a warning about "fmt".
- // ...
+ // __attribute__((format(printf, 1, 2)))
+ // void logmessage(char const *fmt, ...) {
+ // va_list ap;
+ // va_start(ap, fmt);
+ // vprintf(fmt, ap); /* do not emit a warning about "fmt" */
+ // ...
// }
- if (HasVAListArg) {
- if (const ParmVarDecl *PV = dyn_cast<ParmVarDecl>(VD)) {
- if (const Decl *D = dyn_cast<Decl>(PV->getDeclContext())) {
- int PVIndex = PV->getFunctionScopeIndex() + 1;
- for (const auto *PVFormat : D->specific_attrs<FormatAttr>()) {
- // adjust for implicit parameter
- if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D))
- if (MD->isInstance())
- ++PVIndex;
+ //
+ // Another interaction that we need to support is calling a variadic
+ // format function from a format function that has fixed arguments. For
+ // instance:
+ //
+ // __attribute__((format(printf, 1, 2)))
+ // void logstring(char const *fmt, char const *str) {
+ // printf(fmt, str); /* do not emit a warning about "fmt" */
+ // }
+ //
+ // Same (and perhaps more relatably) for the variadic template case:
+ //
+ // template<typename... Args>
+ // __attribute__((format(printf, 1, 2)))
+ // void log(const char *fmt, Args&&... args) {
+ // printf(fmt, forward<Args>(args)...);
+ // /* do not emit a warning about "fmt" */
+ // }
+ //
+ // Due to implementation difficulty, we only check the format, not the
+ // format arguments, in all cases.
+ //
+ if (const auto *PV = dyn_cast<ParmVarDecl>(VD)) {
+ if (const auto *D = dyn_cast<Decl>(PV->getDeclContext())) {
+ for (const auto *PVFormat : D->specific_attrs<FormatAttr>()) {
+ bool IsCXXMember = false;
+ if (const auto *MD = dyn_cast<CXXMethodDecl>(D))
+ IsCXXMember = MD->isInstance();
+
+ bool IsVariadic = false;
+ if (const FunctionType *FnTy = D->getFunctionType())
+ IsVariadic = cast<FunctionProtoType>(FnTy)->isVariadic();
+ else if (const auto *BD = dyn_cast<BlockDecl>(D))
+ IsVariadic = BD->isVariadic();
+ else if (const auto *OMD = dyn_cast<ObjCMethodDecl>(D))
+ IsVariadic = OMD->isVariadic();
+
+ Sema::FormatStringInfo CallerFSI;
+ if (Sema::getFormatStringInfo(PVFormat, IsCXXMember, IsVariadic,
+ &CallerFSI)) {
// We also check if the formats are compatible.
// We can't pass a 'scanf' string to a 'printf' function.
- if (PVIndex == PVFormat->getFormatIdx() &&
- Type == S.GetFormatStringType(PVFormat))
- return SLCT_UncheckedLiteral;
+ if (PV->getFunctionScopeIndex() == CallerFSI.FormatIdx &&
+ Type == S.GetFormatStringType(PVFormat)) {
+ // Lastly, check that argument passing kinds transition in a
+ // way that makes sense:
+ // from a caller with FAPK_VAList, allow FAPK_VAList
+ // from a caller with FAPK_Fixed, allow FAPK_Fixed
+ // from a caller with FAPK_Fixed, allow FAPK_Variadic
+ // from a caller with FAPK_Variadic, allow FAPK_VAList
+ switch (combineFAPK(CallerFSI.ArgPassingKind, APK)) {
+ case combineFAPK(Sema::FAPK_VAList, Sema::FAPK_VAList):
+ case combineFAPK(Sema::FAPK_Fixed, Sema::FAPK_Fixed):
+ case combineFAPK(Sema::FAPK_Fixed, Sema::FAPK_Variadic):
+ case combineFAPK(Sema::FAPK_Variadic, Sema::FAPK_VAList):
+ return SLCT_UncheckedLiteral;
+ }
+ }
}
}
}
@@ -8602,8 +8690,8 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args,
for (const auto *FA : ND->specific_attrs<FormatArgAttr>()) {
const Expr *Arg = CE->getArg(FA->getFormatIdx().getASTIndex());
StringLiteralCheckType Result = checkFormatStringExpr(
- S, Arg, Args, HasVAListArg, format_idx, firstDataArg, Type,
- CallType, InFunctionCall, CheckedVarArgs, UncoveredArg, Offset,
+ S, Arg, Args, APK, format_idx, firstDataArg, Type, CallType,
+ InFunctionCall, CheckedVarArgs, UncoveredArg, Offset,
IgnoreStringsWithoutSpecifiers);
if (IsFirst) {
CommonResult = Result;
@@ -8618,12 +8706,10 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args,
if (BuiltinID == Builtin::BI__builtin___CFStringMakeConstantString ||
BuiltinID == Builtin::BI__builtin___NSStringMakeConstantString) {
const Expr *Arg = CE->getArg(0);
- return checkFormatStringExpr(S, Arg, Args,
- HasVAListArg, format_idx,
- firstDataArg, Type, CallType,
- InFunctionCall, CheckedVarArgs,
- UncoveredArg, Offset,
- IgnoreStringsWithoutSpecifiers);
+ return checkFormatStringExpr(
+ S, Arg, Args, APK, format_idx, firstDataArg, Type, CallType,
+ InFunctionCall, CheckedVarArgs, UncoveredArg, Offset,
+ IgnoreStringsWithoutSpecifiers);
}
}
}
@@ -8651,8 +8737,8 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args,
const Expr *Arg = ME->getArg(FA->getFormatIdx().getASTIndex());
return checkFormatStringExpr(
- S, Arg, Args, HasVAListArg, format_idx, firstDataArg, Type,
- CallType, InFunctionCall, CheckedVarArgs, UncoveredArg, Offset,
+ S, Arg, Args, APK, format_idx, firstDataArg, Type, CallType,
+ InFunctionCall, CheckedVarArgs, UncoveredArg, Offset,
IgnoreStringsWithoutSpecifiers);
}
}
@@ -8675,9 +8761,8 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args,
return SLCT_NotALiteral;
}
FormatStringLiteral FStr(StrE, Offset.sextOrTrunc(64).getSExtValue());
- CheckFormatString(S, &FStr, E, Args, HasVAListArg, format_idx,
- firstDataArg, Type, InFunctionCall, CallType,
- CheckedVarArgs, UncoveredArg,
+ CheckFormatString(S, &FStr, E, Args, APK, format_idx, firstDataArg, Type,
+ InFunctionCall, CallType, CheckedVarArgs, UncoveredArg,
IgnoreStringsWithoutSpecifiers);
return SLCT_CheckedLiteral;
}
@@ -8756,24 +8841,25 @@ Sema::FormatStringType Sema::GetFormatStringType(const FormatAttr *Format) {
/// functions) for correct use of format strings.
/// Returns true if a format string has been fully checked.
bool Sema::CheckFormatArguments(const FormatAttr *Format,
- ArrayRef<const Expr *> Args,
- bool IsCXXMember,
- VariadicCallType CallType,
- SourceLocation Loc, SourceRange Range,
+ ArrayRef<const Expr *> Args, bool IsCXXMember,
+ VariadicCallType CallType, SourceLocation Loc,
+ SourceRange Range,
llvm::SmallBitVector &CheckedVarArgs) {
FormatStringInfo FSI;
- if (getFormatStringInfo(Format, IsCXXMember, &FSI))
- return CheckFormatArguments(Args, FSI.HasVAListArg, FSI.FormatIdx,
+ if (getFormatStringInfo(Format, IsCXXMember, CallType != VariadicDoesNotApply,
+ &FSI))
+ return CheckFormatArguments(Args, FSI.ArgPassingKind, FSI.FormatIdx,
FSI.FirstDataArg, GetFormatStringType(Format),
CallType, Loc, Range, CheckedVarArgs);
return false;
}
bool Sema::CheckFormatArguments(ArrayRef<const Expr *> Args,
- bool HasVAListArg, unsigned format_idx,
- unsigned firstDataArg, FormatStringType Type,
- VariadicCallType CallType,
- SourceLocation Loc, SourceRange Range,
+ Sema::FormatArgumentPassingKind APK,
+ unsigned format_idx, unsigned firstDataArg,
+ FormatStringType Type,
+ VariadicCallType CallType, SourceLocation Loc,
+ SourceRange Range,
llvm::SmallBitVector &CheckedVarArgs) {
// CHECK: printf/scanf-like function is called with no format string.
if (format_idx >= Args.size()) {
@@ -8796,12 +8882,11 @@ bool Sema::CheckFormatArguments(ArrayRef<const Expr *> Args,
// ObjC string uses the same format specifiers as C string, so we can use
// the same format string checking logic for both ObjC and C strings.
UncoveredArgHandler UncoveredArg;
- StringLiteralCheckType CT =
- checkFormatStringExpr(*this, OrigFormatExpr, Args, HasVAListArg,
- format_idx, firstDataArg, Type, CallType,
- /*IsFunctionCall*/ true, CheckedVarArgs,
- UncoveredArg,
- /*no string offset*/ llvm::APSInt(64, false) = 0);
+ StringLiteralCheckType CT = checkFormatStringExpr(
+ *this, OrigFormatExpr, Args, APK, format_idx, firstDataArg, Type,
+ CallType,
+ /*IsFunctionCall*/ true, CheckedVarArgs, UncoveredArg,
+ /*no string offset*/ llvm::APSInt(64, false) = 0);
// Generate a diagnostic where an uncovered argument is detected.
if (UncoveredArg.hasUncoveredArg()) {
@@ -8864,7 +8949,7 @@ protected:
const unsigned FirstDataArg;
const unsigned NumDataArgs;
const char *Beg; // Start of format string.
- const bool HasVAListArg;
+ const Sema::FormatArgumentPassingKind ArgPassingKind;
ArrayRef<const Expr *> Args;
unsigned FormatIdx;
llvm::SmallBitVector CoveredArgs;
@@ -8879,14 +8964,15 @@ public:
CheckFormatHandler(Sema &s, const FormatStringLiteral *fexpr,
const Expr *origFormatExpr,
const Sema::FormatStringType type, unsigned firstDataArg,
- unsigned numDataArgs, const char *beg, bool hasVAListArg,
+ unsigned numDataArgs, const char *beg,
+ Sema::FormatArgumentPassingKind APK,
ArrayRef<const Expr *> Args, unsigned formatIdx,
bool inFunctionCall, Sema::VariadicCallType callType,
llvm::SmallBitVector &CheckedVarArgs,
UncoveredArgHandler &UncoveredArg)
: S(s), FExpr(fexpr), OrigFormatExpr(origFormatExpr), FSType(type),
FirstDataArg(firstDataArg), NumDataArgs(numDataArgs), Beg(beg),
- HasVAListArg(hasVAListArg), Args(Args), FormatIdx(formatIdx),
+ ArgPassingKind(APK), Args(Args), FormatIdx(formatIdx),
inFunctionCall(inFunctionCall), CallType(callType),
CheckedVarArgs(CheckedVarArgs), UncoveredArg(UncoveredArg) {
CoveredArgs.resize(numDataArgs);
@@ -9122,8 +9208,8 @@ const Expr *CheckFormatHandler::getDataArg(unsigned i) const {
void CheckFormatHandler::DoneProcessing() {
// Does the number of data arguments exceed the number of
// format conversions in the format string?
- if (!HasVAListArg) {
- // Find any arguments that weren't covered.
+ if (ArgPassingKind != Sema::FAPK_VAList) {
+ // Find any arguments that weren't covered.
CoveredArgs.flip();
signed notCoveredArg = CoveredArgs.find_first();
if (notCoveredArg >= 0) {
@@ -9318,13 +9404,13 @@ public:
const Expr *origFormatExpr,
const Sema::FormatStringType type, unsigned firstDataArg,
unsigned numDataArgs, bool isObjC, const char *beg,
- bool hasVAListArg, ArrayRef<const Expr *> Args,
- unsigned formatIdx, bool inFunctionCall,
- Sema::VariadicCallType CallType,
+ Sema::FormatArgumentPassingKind APK,
+ ArrayRef<const Expr *> Args, unsigned formatIdx,
+ bool inFunctionCall, Sema::VariadicCallType CallType,
llvm::SmallBitVector &CheckedVarArgs,
UncoveredArgHandler &UncoveredArg)
: CheckFormatHandler(s, fexpr, origFormatExpr, type, firstDataArg,
- numDataArgs, beg, hasVAListArg, Args, formatIdx,
+ numDataArgs, beg, APK, Args, formatIdx,
inFunctionCall, CallType, CheckedVarArgs,
UncoveredArg) {}
@@ -9399,17 +9485,16 @@ void CheckPrintfHandler::handleInvalidMaskType(StringRef MaskType) {
}
bool CheckPrintfHandler::HandleAmount(
- const analyze_format_string::OptionalAmount &Amt,
- unsigned k, const char *startSpecifier,
- unsigned specifierLen) {
+ const analyze_format_string::OptionalAmount &Amt, unsigned k,
+ const char *startSpecifier, unsigned specifierLen) {
if (Amt.hasDataArgument()) {
- if (!HasVAListArg) {
+ if (ArgPassingKind != Sema::FAPK_VAList) {
unsigned argIndex = Amt.getArgIndex();
if (argIndex >= NumDataArgs) {
EmitFormatDiagnostic(S.PDiag(diag::warn_printf_asterisk_missing_arg)
- << k,
+ << k,
getLocationOfByte(Amt.getStart()),
- /*IsStringLocation*/true,
+ /*IsStringLocation*/ true,
getSpecifierRange(startSpecifier, specifierLen));
// Don't do any more checking. We will just emit
// spurious errors.
@@ -9805,7 +9890,7 @@ bool CheckPrintfHandler::HandlePrintfSpecifier(
HandleNonStandardConversionSpecifier(CS, startSpecifier, specifierLen);
// The remaining checks depend on the data arguments.
- if (HasVAListArg)
+ if (ArgPassingKind == Sema::FAPK_VAList)
return true;
if (!CheckNumArgs(FS, CS, startSpecifier, specifierLen, argIndex))
@@ -9953,6 +10038,12 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
ExprTy = TET->getUnderlyingExpr()->getType();
}
+ // When using the format attribute in C++, you can receive a function or an
+ // array that will necessarily decay to a pointer when passed to the final
+ // format consumer. Apply decay before type comparison.
+ if (ExprTy->canDecayToPointerType())
+ ExprTy = S.Context.getDecayedType(ExprTy);
+
// Diagnose attempts to print a boolean value as a character. Unlike other
// -Wformat diagnostics, this is fine from a type perspective, but it still
// doesn't make sense.
@@ -10173,6 +10264,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
// Since the warning for passing non-POD types to variadic functions
// was deferred until now, we emit a warning for non-POD
// arguments here.
+ bool EmitTypeMismatch = false;
switch (S.isValidVarArgType(ExprTy)) {
case Sema::VAK_Valid:
case Sema::VAK_ValidInCXX11: {
@@ -10198,17 +10290,23 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
}
case Sema::VAK_Undefined:
case Sema::VAK_MSVCUndefined:
- EmitFormatDiagnostic(S.PDiag(diag::warn_non_pod_vararg_with_format_string)
- << S.getLangOpts().CPlusPlus11 << ExprTy
- << CallType
- << AT.getRepresentativeTypeName(S.Context) << CSR
- << E->getSourceRange(),
- E->getBeginLoc(), /*IsStringLocation*/ false, CSR);
- checkForCStrMembers(AT, E);
+ if (CallType == Sema::VariadicDoesNotApply) {
+ EmitTypeMismatch = true;
+ } else {
+ EmitFormatDiagnostic(
+ S.PDiag(diag::warn_non_pod_vararg_with_format_string)
+ << S.getLangOpts().CPlusPlus11 << ExprTy << CallType
+ << AT.getRepresentativeTypeName(S.Context) << CSR
+ << E->getSourceRange(),
+ E->getBeginLoc(), /*IsStringLocation*/ false, CSR);
+ checkForCStrMembers(AT, E);
+ }
break;
case Sema::VAK_Invalid:
- if (ExprTy->isObjCObjectType())
+ if (CallType == Sema::VariadicDoesNotApply)
+ EmitTypeMismatch = true;
+ else if (ExprTy->isObjCObjectType())
EmitFormatDiagnostic(
S.PDiag(diag::err_cannot_pass_objc_interface_to_vararg_format)
<< S.getLangOpts().CPlusPlus11 << ExprTy << CallType
@@ -10224,6 +10322,19 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
break;
}
+ if (EmitTypeMismatch) {
+ // The function is not variadic, so we do not generate warnings about
+ // being allowed to pass that object as a variadic argument. Instead,
+ // since there are inherently no printf specifiers for types which cannot
+ // be passed as variadic arguments, emit a plain old specifier mismatch
+ // argument.
+ EmitFormatDiagnostic(
+ S.PDiag(diag::warn_format_conversion_argument_type_mismatch)
+ << AT.getRepresentativeTypeName(S.Context) << ExprTy << false
+ << E->getSourceRange(),
+ E->getBeginLoc(), false, CSR);
+ }
+
assert(FirstDataArg + FS.getArgIndex() < CheckedVarArgs.size() &&
"format string specifier index out of range");
CheckedVarArgs[FirstDataArg + FS.getArgIndex()] = true;
@@ -10241,13 +10352,13 @@ public:
CheckScanfHandler(Sema &s, const FormatStringLiteral *fexpr,
const Expr *origFormatExpr, Sema::FormatStringType type,
unsigned firstDataArg, unsigned numDataArgs,
- const char *beg, bool hasVAListArg,
+ const char *beg, Sema::FormatArgumentPassingKind APK,
ArrayRef<const Expr *> Args, unsigned formatIdx,
bool inFunctionCall, Sema::VariadicCallType CallType,
llvm::SmallBitVector &CheckedVarArgs,
UncoveredArgHandler &UncoveredArg)
: CheckFormatHandler(s, fexpr, origFormatExpr, type, firstDataArg,
- numDataArgs, beg, hasVAListArg, Args, formatIdx,
+ numDataArgs, beg, APK, Args, formatIdx,
inFunctionCall, CallType, CheckedVarArgs,
UncoveredArg) {}
@@ -10351,7 +10462,7 @@ bool CheckScanfHandler::HandleScanfSpecifier(
HandleNonStandardConversionSpecifier(CS, startSpecifier, specifierLen);
// The remaining checks depend on the data arguments.
- if (HasVAListArg)
+ if (ArgPassingKind == Sema::FAPK_VAList)
return true;
if (!CheckNumArgs(FS, CS, startSpecifier, specifierLen, argIndex))
@@ -10408,17 +10519,13 @@ bool CheckScanfHandler::HandleScanfSpecifier(
return true;
}
-static void CheckFormatString(Sema &S, const FormatStringLiteral *FExpr,
- const Expr *OrigFormatExpr,
- ArrayRef<const Expr *> Args,
- bool HasVAListArg, unsigned format_idx,
- unsigned firstDataArg,
- Sema::FormatStringType Type,
- bool inFunctionCall,
- Sema::VariadicCallType CallType,
- llvm::SmallBitVector &CheckedVarArgs,
- UncoveredArgHandler &UncoveredArg,
- bool IgnoreStringsWithoutSpecifiers) {
+static void CheckFormatString(
+ Sema &S, const FormatStringLiteral *FExpr, const Expr *OrigFormatExpr,
+ ArrayRef<const Expr *> Args, Sema::FormatArgumentPassingKind APK,
+ unsigned format_idx, unsigned firstDataArg, Sema::FormatStringType Type,
+ bool inFunctionCall, Sema::VariadicCallType CallType,
+ llvm::SmallBitVector &CheckedVarArgs, UncoveredArgHandler &UncoveredArg,
+ bool IgnoreStringsWithoutSpecifiers) {
// CHECK: is the format string a wide literal?
if (!FExpr->isAscii() && !FExpr->isUTF8()) {
CheckFormatHandler::EmitFormatDiagnostic(
@@ -10469,23 +10576,21 @@ static void CheckFormatString(Sema &S, const FormatStringLiteral *FExpr,
Type == Sema::FST_OSTrace) {
CheckPrintfHandler H(
S, FExpr, OrigFormatExpr, Type, firstDataArg, numDataArgs,
- (Type == Sema::FST_NSString || Type == Sema::FST_OSTrace), Str,
- HasVAListArg, Args, format_idx, inFunctionCall, CallType,
- CheckedVarArgs, UncoveredArg);
-
- if (!analyze_format_string::ParsePrintfString(H, Str, Str + StrLen,
- S.getLangOpts(),
- S.Context.getTargetInfo(),
- Type == Sema::FST_FreeBSDKPrintf))
+ (Type == Sema::FST_NSString || Type == Sema::FST_OSTrace), Str, APK,
+ Args, format_idx, inFunctionCall, CallType, CheckedVarArgs,
+ UncoveredArg);
+
+ if (!analyze_format_string::ParsePrintfString(
+ H, Str, Str + StrLen, S.getLangOpts(), S.Context.getTargetInfo(),
+ Type == Sema::FST_FreeBSDKPrintf))
H.DoneProcessing();
} else if (Type == Sema::FST_Scanf) {
CheckScanfHandler H(S, FExpr, OrigFormatExpr, Type, firstDataArg,
- numDataArgs, Str, HasVAListArg, Args, format_idx,
- inFunctionCall, CallType, CheckedVarArgs, UncoveredArg);
+ numDataArgs, Str, APK, Args, format_idx, inFunctionCall,
+ CallType, CheckedVarArgs, UncoveredArg);
- if (!analyze_format_string::ParseScanfString(H, Str, Str + StrLen,
- S.getLangOpts(),
- S.Context.getTargetInfo()))
+ if (!analyze_format_string::ParseScanfString(
+ H, Str, Str + StrLen, S.getLangOpts(), S.Context.getTargetInfo()))
H.DoneProcessing();
} // TODO: handle other formats
}
@@ -16765,9 +16870,15 @@ void Sema::DiagnoseSelfMove(const Expr *LHSExpr, const Expr *RHSExpr,
RHSDeclRef->getDecl()->getCanonicalDecl())
return;
- Diag(OpLoc, diag::warn_self_move) << LHSExpr->getType()
- << LHSExpr->getSourceRange()
- << RHSExpr->getSourceRange();
+ auto D = Diag(OpLoc, diag::warn_self_move)
+ << LHSExpr->getType() << LHSExpr->getSourceRange()
+ << RHSExpr->getSourceRange();
+ if (const FieldDecl *F =
+ getSelfAssignmentClassMemberCandidate(RHSDeclRef->getDecl()))
+ D << 1 << F
+ << FixItHint::CreateInsertion(LHSDeclRef->getBeginLoc(), "this->");
+ else
+ D << 0;
return;
}
@@ -16802,16 +16913,16 @@ void Sema::DiagnoseSelfMove(const Expr *LHSExpr, const Expr *RHSExpr,
RHSDeclRef->getDecl()->getCanonicalDecl())
return;
- Diag(OpLoc, diag::warn_self_move) << LHSExpr->getType()
- << LHSExpr->getSourceRange()
- << RHSExpr->getSourceRange();
+ Diag(OpLoc, diag::warn_self_move)
+ << LHSExpr->getType() << 0 << LHSExpr->getSourceRange()
+ << RHSExpr->getSourceRange();
return;
}
if (isa<CXXThisExpr>(LHSBase) && isa<CXXThisExpr>(RHSBase))
- Diag(OpLoc, diag::warn_self_move) << LHSExpr->getType()
- << LHSExpr->getSourceRange()
- << RHSExpr->getSourceRange();
+ Diag(OpLoc, diag::warn_self_move)
+ << LHSExpr->getType() << 0 << LHSExpr->getSourceRange()
+ << RHSExpr->getSourceRange();
}
//===--- Layout compatibility ----------------------------------------------//
diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp
index 8c9ed5389488..86bad736227d 100644
--- a/clang/lib/Sema/SemaCodeComplete.cpp
+++ b/clang/lib/Sema/SemaCodeComplete.cpp
@@ -5362,8 +5362,8 @@ private:
// Overwrite existing if the new member has more info.
// The preference of . vs :: vs -> is fairly arbitrary.
if (/*Inserted*/ R.second ||
- std::make_tuple(M.ArgTypes.hasValue(), M.ResultType != nullptr,
- M.Operator) > std::make_tuple(O.ArgTypes.hasValue(),
+ std::make_tuple(M.ArgTypes.has_value(), M.ResultType != nullptr,
+ M.Operator) > std::make_tuple(O.ArgTypes.has_value(),
O.ResultType != nullptr,
O.Operator))
O = std::move(M);
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 1139088ecde2..5a546503cced 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -1625,22 +1625,20 @@ bool Sema::CheckRedeclarationModuleOwnership(NamedDecl *New, NamedDecl *Old) {
Module *NewM = New->getOwningModule();
Module *OldM = Old->getOwningModule();
- if (NewM && NewM->Kind == Module::PrivateModuleFragment)
+ if (NewM && NewM->isPrivateModule())
NewM = NewM->Parent;
- if (OldM && OldM->Kind == Module::PrivateModuleFragment)
+ if (OldM && OldM->isPrivateModule())
OldM = OldM->Parent;
- // If we have a decl in a module partition, it is part of the containing
- // module (which is the only thing that can be importing it).
- if (NewM && OldM &&
- (OldM->Kind == Module::ModulePartitionInterface ||
- OldM->Kind == Module::ModulePartitionImplementation)) {
- return false;
- }
-
if (NewM == OldM)
return false;
+ // Partitions are part of the module, but a partition could import another
+ // module, so verify that the PMIs agree.
+ if (NewM && OldM && (NewM->isModulePartition() || OldM->isModulePartition()))
+ return NewM->getPrimaryModuleInterfaceName() ==
+ OldM->getPrimaryModuleInterfaceName();
+
bool NewIsModuleInterface = NewM && NewM->isModulePurview();
bool OldIsModuleInterface = OldM && OldM->isModulePurview();
if (NewIsModuleInterface || OldIsModuleInterface) {
@@ -3209,6 +3207,45 @@ static void mergeParamDeclAttributes(ParmVarDecl *newDecl,
if (!foundAny) newDecl->dropAttrs();
}
+static bool EquivalentArrayTypes(QualType Old, QualType New,
+ const ASTContext &Ctx) {
+
+ auto NoSizeInfo = [&Ctx](QualType Ty) {
+ if (Ty->isIncompleteArrayType() || Ty->isPointerType())
+ return true;
+ if (const auto *VAT = Ctx.getAsVariableArrayType(Ty))
+ return VAT->getSizeModifier() == ArrayType::ArraySizeModifier::Star;
+ return false;
+ };
+
+ // `type[]` is equivalent to `type *` and `type[*]`.
+ if (NoSizeInfo(Old) && NoSizeInfo(New))
+ return true;
+
+ // Don't try to compare VLA sizes, unless one of them has the star modifier.
+ if (Old->isVariableArrayType() && New->isVariableArrayType()) {
+ const auto *OldVAT = Ctx.getAsVariableArrayType(Old);
+ const auto *NewVAT = Ctx.getAsVariableArrayType(New);
+ if ((OldVAT->getSizeModifier() == ArrayType::ArraySizeModifier::Star) ^
+ (NewVAT->getSizeModifier() == ArrayType::ArraySizeModifier::Star))
+ return false;
+ return true;
+ }
+
+ // Only compare size, ignore Size modifiers and CVR.
+ if (Old->isConstantArrayType() && New->isConstantArrayType()) {
+ return Ctx.getAsConstantArrayType(Old)->getSize() ==
+ Ctx.getAsConstantArrayType(New)->getSize();
+ }
+
+ // Don't try to compare dependent sized array
+ if (Old->isDependentSizedArrayType() && New->isDependentSizedArrayType()) {
+ return true;
+ }
+
+ return Old == New;
+}
+
static void mergeParamDeclTypes(ParmVarDecl *NewParam,
const ParmVarDecl *OldParam,
Sema &S) {
@@ -3234,6 +3271,19 @@ static void mergeParamDeclTypes(ParmVarDecl *NewParam,
NewParam->setType(NewT);
}
}
+ const auto *OldParamDT = dyn_cast<DecayedType>(OldParam->getType());
+ const auto *NewParamDT = dyn_cast<DecayedType>(NewParam->getType());
+ if (OldParamDT && NewParamDT &&
+ OldParamDT->getPointeeType() == NewParamDT->getPointeeType()) {
+ QualType OldParamOT = OldParamDT->getOriginalType();
+ QualType NewParamOT = NewParamDT->getOriginalType();
+ if (!EquivalentArrayTypes(OldParamOT, NewParamOT, S.getASTContext())) {
+ S.Diag(NewParam->getLocation(), diag::warn_inconsistent_array_form)
+ << NewParam << NewParamOT;
+ S.Diag(OldParam->getLocation(), diag::note_previous_declaration_as)
+ << OldParamOT;
+ }
+ }
}
namespace {
@@ -15464,7 +15514,7 @@ void Sema::AddKnownFunctionAttributesForReplaceableGlobalAllocationFunction(
// specified by the value of this argument.
if (AlignmentParam && !FD->hasAttr<AllocAlignAttr>()) {
FD->addAttr(AllocAlignAttr::CreateImplicit(
- Context, ParamIdx(AlignmentParam.getValue(), FD), FD->getLocation()));
+ Context, ParamIdx(AlignmentParam.value(), FD), FD->getLocation()));
}
// FIXME:
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index f79523983ed8..838fd48357fb 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -2673,7 +2673,7 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (IOSToWatchOSMapping) {
if (auto MappedVersion = IOSToWatchOSMapping->map(
Version, MinimumWatchOSVersion, None)) {
- return MappedVersion.getValue();
+ return MappedVersion.value();
}
}
@@ -2682,10 +2682,10 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (NewMajor >= 2) {
if (Version.getMinor()) {
if (Version.getSubminor())
- return VersionTuple(NewMajor, Version.getMinor().getValue(),
- Version.getSubminor().getValue());
+ return VersionTuple(NewMajor, Version.getMinor().value(),
+ Version.getSubminor().value());
else
- return VersionTuple(NewMajor, Version.getMinor().getValue());
+ return VersionTuple(NewMajor, Version.getMinor().value());
}
return VersionTuple(NewMajor);
}
@@ -3886,12 +3886,10 @@ static void handleFormatAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
// check if the function is variadic if the 3rd argument non-zero
if (FirstArg != 0) {
- if (isFunctionOrMethodVariadic(D)) {
+ if (isFunctionOrMethodVariadic(D))
++NumArgs; // +1 for ...
- } else {
- S.Diag(D->getLocation(), diag::err_format_attribute_requires_variadic);
- return;
- }
+ else
+ S.Diag(D->getLocation(), diag::warn_gcc_requires_variadic_function) << AL;
}
// strftime requires FirstArg to be 0 because it doesn't read from any
@@ -4314,13 +4312,6 @@ void Sema::AddAlignedAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E,
return;
uint64_t AlignVal = Alignment.getZExtValue();
- // 16 byte ByVal alignment not due to a vector member is not honoured by XL
- // on AIX. Emit a warning here that users are generating binary incompatible
- // code to be safe.
- if (AlignVal >= 16 && isa<FieldDecl>(D) &&
- Context.getTargetInfo().getTriple().isOSAIX())
- Diag(AttrLoc, diag::warn_not_xl_compatible) << E->getSourceRange();
-
// C++11 [dcl.align]p2:
// -- if the constant expression evaluates to zero, the alignment
// specifier shall have no effect
@@ -8002,6 +7993,26 @@ static void handleZeroCallUsedRegsAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
D->addAttr(ZeroCallUsedRegsAttr::Create(S.Context, Kind, AL));
}
+static void handleFunctionReturnThunksAttr(Sema &S, Decl *D,
+ const ParsedAttr &AL) {
+ StringRef KindStr;
+ SourceLocation LiteralLoc;
+ if (!S.checkStringLiteralArgumentAttr(AL, 0, KindStr, &LiteralLoc))
+ return;
+
+ FunctionReturnThunksAttr::Kind Kind;
+ if (!FunctionReturnThunksAttr::ConvertStrToKind(KindStr, Kind)) {
+ S.Diag(LiteralLoc, diag::warn_attribute_type_not_supported)
+ << AL << KindStr;
+ return;
+ }
+ // FIXME: it would be good to better handle attribute merging rather than
+ // silently replacing the existing attribute, so long as it does not break
+ // the expected codegen tests.
+ D->dropAttr<FunctionReturnThunksAttr>();
+ D->addAttr(FunctionReturnThunksAttr::Create(S.Context, Kind, AL));
+}
+
static void handleSYCLKernelAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
// The 'sycl_kernel' attribute applies only to function templates.
const auto *FD = cast<FunctionDecl>(D);
@@ -8868,6 +8879,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
case ParsedAttr::AT_ZeroCallUsedRegs:
handleZeroCallUsedRegsAttr(S, D, AL);
break;
+ case ParsedAttr::AT_FunctionReturnThunks:
+ handleFunctionReturnThunksAttr(S, D, AL);
+ break;
// Microsoft attributes:
case ParsedAttr::AT_LayoutVersion:
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index b9ecde6f20a0..742c4828b8dc 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -14600,6 +14600,40 @@ static inline UnaryOperatorKind ConvertTokenKindToUnaryOpcode(
return Opc;
}
+const FieldDecl *
+Sema::getSelfAssignmentClassMemberCandidate(const ValueDecl *SelfAssigned) {
+ // Explore the case for adding 'this->' to the LHS of a self assignment, very
+ // common for setters.
+ // struct A {
+ // int X;
+ // -void setX(int X) { X = X; }
+ // +void setX(int X) { this->X = X; }
+ // };
+
+ // Only consider parameters for self assignment fixes.
+ if (!isa<ParmVarDecl>(SelfAssigned))
+ return nullptr;
+ const auto *Method =
+ dyn_cast_or_null<CXXMethodDecl>(getCurFunctionDecl(true));
+ if (!Method)
+ return nullptr;
+
+ const CXXRecordDecl *Parent = Method->getParent();
+ // In theory this is fixable if the lambda explicitly captures this, but
+ // that's added complexity that's rarely going to be used.
+ if (Parent->isLambda())
+ return nullptr;
+
+ // FIXME: Use an actual Lookup operation instead of just traversing fields
+ // in order to get base class fields.
+ auto Field =
+ llvm::find_if(Parent->fields(),
+ [Name(SelfAssigned->getDeclName())](const FieldDecl *F) {
+ return F->getDeclName() == Name;
+ });
+ return (Field != Parent->field_end()) ? *Field : nullptr;
+}
+
/// DiagnoseSelfAssignment - Emits a warning if a value is assigned to itself.
/// This warning suppressed in the event of macro expansions.
static void DiagnoseSelfAssignment(Sema &S, Expr *LHSExpr, Expr *RHSExpr,
@@ -14630,10 +14664,16 @@ static void DiagnoseSelfAssignment(Sema &S, Expr *LHSExpr, Expr *RHSExpr,
if (RefTy->getPointeeType().isVolatileQualified())
return;
- S.Diag(OpLoc, IsBuiltin ? diag::warn_self_assignment_builtin
- : diag::warn_self_assignment_overloaded)
- << LHSDeclRef->getType() << LHSExpr->getSourceRange()
- << RHSExpr->getSourceRange();
+ auto Diag = S.Diag(OpLoc, IsBuiltin ? diag::warn_self_assignment_builtin
+ : diag::warn_self_assignment_overloaded)
+ << LHSDeclRef->getType() << LHSExpr->getSourceRange()
+ << RHSExpr->getSourceRange();
+ if (const FieldDecl *SelfAssignField =
+ S.getSelfAssignmentClassMemberCandidate(RHSDecl))
+ Diag << 1 << SelfAssignField
+ << FixItHint::CreateInsertion(LHSDeclRef->getBeginLoc(), "this->");
+ else
+ Diag << 0;
}
/// Check if a bitwise-& is performed on an Objective-C pointer. This
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 0d73fcf8bf4e..11f33c7c6363 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -5394,6 +5394,39 @@ static bool evaluateTypeTrait(Sema &S, TypeTrait Kind, SourceLocation KWLoc,
return false;
}
+namespace {
+void DiagnoseBuiltinDeprecation(Sema& S, TypeTrait Kind,
+ SourceLocation KWLoc) {
+ TypeTrait Replacement;
+ switch (Kind) {
+ case UTT_HasNothrowAssign:
+ case UTT_HasNothrowMoveAssign:
+ Replacement = BTT_IsNothrowAssignable;
+ break;
+ case UTT_HasNothrowCopy:
+ case UTT_HasNothrowConstructor:
+ Replacement = TT_IsNothrowConstructible;
+ break;
+ case UTT_HasTrivialAssign:
+ case UTT_HasTrivialMoveAssign:
+ Replacement = BTT_IsTriviallyAssignable;
+ break;
+ case UTT_HasTrivialCopy:
+ case UTT_HasTrivialDefaultConstructor:
+ case UTT_HasTrivialMoveConstructor:
+ Replacement = TT_IsTriviallyConstructible;
+ break;
+ case UTT_HasTrivialDestructor:
+ Replacement = UTT_IsTriviallyDestructible;
+ break;
+ default:
+ return;
+ }
+ S.Diag(KWLoc, diag::warn_deprecated_builtin)
+ << getTraitSpelling(Kind) << getTraitSpelling(Replacement);
+}
+}
+
ExprResult Sema::BuildTypeTrait(TypeTrait Kind, SourceLocation KWLoc,
ArrayRef<TypeSourceInfo *> Args,
SourceLocation RParenLoc) {
@@ -5403,6 +5436,8 @@ ExprResult Sema::BuildTypeTrait(TypeTrait Kind, SourceLocation KWLoc,
*this, Kind, KWLoc, Args[0]->getType()))
return ExprError();
+ DiagnoseBuiltinDeprecation(*this, Kind, KWLoc);
+
bool Dependent = false;
for (unsigned I = 0, N = Args.size(); I != N; ++I) {
if (Args[I]->getType()->isDependentType()) {
diff --git a/clang/lib/Sema/SemaModule.cpp b/clang/lib/Sema/SemaModule.cpp
index 3aa124d457b0..e9a1ac17ce86 100644
--- a/clang/lib/Sema/SemaModule.cpp
+++ b/clang/lib/Sema/SemaModule.cpp
@@ -935,3 +935,16 @@ void Sema::PopGlobalModuleFragment() {
"left the wrong module scope, which is not global module fragment");
ModuleScopes.pop_back();
}
+
+bool Sema::isModuleUnitOfCurrentTU(const Module *M) const {
+ assert(M);
+
+ Module *CurrentModuleUnit = getCurrentModule();
+
+ // If we are not in a module currently, M must not be the module unit of
+ // current TU.
+ if (!CurrentModuleUnit)
+ return false;
+
+ return M->isSubModuleOf(CurrentModuleUnit->getTopLevelModule());
+}
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index 6f501965552e..dc1470bf7a9d 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -840,21 +840,21 @@ public:
/// false - otherwise.
bool isOrderedRegion() const {
if (const SharingMapTy *Top = getTopOfStackOrNull())
- return Top->OrderedRegion.hasValue();
+ return Top->OrderedRegion.has_value();
return false;
}
/// Returns optional parameter for the ordered region.
std::pair<const Expr *, OMPOrderedClause *> getOrderedRegionParam() const {
if (const SharingMapTy *Top = getTopOfStackOrNull())
if (Top->OrderedRegion)
- return Top->OrderedRegion.getValue();
+ return Top->OrderedRegion.value();
return std::make_pair(nullptr, nullptr);
}
/// Returns true, if parent region is ordered (has associated
/// 'ordered' clause), false - otherwise.
bool isParentOrderedRegion() const {
if (const SharingMapTy *Parent = getSecondOnStackOrNull())
- return Parent->OrderedRegion.hasValue();
+ return Parent->OrderedRegion.has_value();
return false;
}
/// Returns optional parameter for the ordered region.
@@ -862,7 +862,7 @@ public:
getParentOrderedRegionParam() const {
if (const SharingMapTy *Parent = getSecondOnStackOrNull())
if (Parent->OrderedRegion)
- return Parent->OrderedRegion.getValue();
+ return Parent->OrderedRegion.value();
return std::make_pair(nullptr, nullptr);
}
/// Marks current region as nowait (it has a 'nowait' clause).
@@ -7831,9 +7831,9 @@ public:
/// Return true if any expression is dependent.
bool dependent() const;
/// Returns true if the initializer forms non-rectangular loop.
- bool doesInitDependOnLC() const { return InitDependOnLC.hasValue(); }
+ bool doesInitDependOnLC() const { return InitDependOnLC.has_value(); }
/// Returns true if the condition forms non-rectangular loop.
- bool doesCondDependOnLC() const { return CondDependOnLC.hasValue(); }
+ bool doesCondDependOnLC() const { return CondDependOnLC.has_value(); }
/// Returns index of the loop we depend on (starting from 1), or 0 otherwise.
unsigned getLoopDependentIdx() const {
return InitDependOnLC.value_or(CondDependOnLC.value_or(0));
@@ -7942,18 +7942,18 @@ bool OpenMPIterationSpaceChecker::setStep(Expr *NewStep, bool Subtract) {
if (!TestIsLessOp)
TestIsLessOp = IsConstPos || (IsUnsigned && !Subtract);
if (UB &&
- (IsConstZero || (TestIsLessOp.getValue()
- ? (IsConstNeg || (IsUnsigned && Subtract))
- : (IsConstPos || (IsUnsigned && !Subtract))))) {
+ (IsConstZero ||
+ (TestIsLessOp.value() ? (IsConstNeg || (IsUnsigned && Subtract))
+ : (IsConstPos || (IsUnsigned && !Subtract))))) {
SemaRef.Diag(NewStep->getExprLoc(),
diag::err_omp_loop_incr_not_compatible)
- << LCDecl << TestIsLessOp.getValue() << NewStep->getSourceRange();
+ << LCDecl << TestIsLessOp.value() << NewStep->getSourceRange();
SemaRef.Diag(ConditionLoc,
diag::note_omp_loop_cond_requres_compatible_incr)
- << TestIsLessOp.getValue() << ConditionSrcRange;
+ << TestIsLessOp.value() << ConditionSrcRange;
return true;
}
- if (TestIsLessOp.getValue() == Subtract) {
+ if (TestIsLessOp.value() == Subtract) {
NewStep =
SemaRef.CreateBuiltinUnaryOp(NewStep->getExprLoc(), UO_Minus, NewStep)
.get();
@@ -8708,8 +8708,8 @@ Expr *OpenMPIterationSpaceChecker::buildNumIterations(
UBVal = MinUB.get();
}
}
- Expr *UBExpr = TestIsLessOp.getValue() ? UBVal : LBVal;
- Expr *LBExpr = TestIsLessOp.getValue() ? LBVal : UBVal;
+ Expr *UBExpr = TestIsLessOp.value() ? UBVal : LBVal;
+ Expr *LBExpr = TestIsLessOp.value() ? LBVal : UBVal;
Expr *Upper = tryBuildCapture(SemaRef, UBExpr, Captures).get();
Expr *Lower = tryBuildCapture(SemaRef, LBExpr, Captures).get();
if (!Upper || !Lower)
@@ -8772,12 +8772,12 @@ std::pair<Expr *, Expr *> OpenMPIterationSpaceChecker::buildMinMaxValues(
// init value.
Expr *MinExpr = nullptr;
Expr *MaxExpr = nullptr;
- Expr *LBExpr = TestIsLessOp.getValue() ? LB : UB;
- Expr *UBExpr = TestIsLessOp.getValue() ? UB : LB;
- bool LBNonRect = TestIsLessOp.getValue() ? InitDependOnLC.hasValue()
- : CondDependOnLC.hasValue();
- bool UBNonRect = TestIsLessOp.getValue() ? CondDependOnLC.hasValue()
- : InitDependOnLC.hasValue();
+ Expr *LBExpr = TestIsLessOp.value() ? LB : UB;
+ Expr *UBExpr = TestIsLessOp.value() ? UB : LB;
+ bool LBNonRect = TestIsLessOp.value() ? InitDependOnLC.has_value()
+ : CondDependOnLC.has_value();
+ bool UBNonRect = TestIsLessOp.value() ? CondDependOnLC.has_value()
+ : InitDependOnLC.has_value();
Expr *Lower =
LBNonRect ? LBExpr : tryBuildCapture(SemaRef, LBExpr, Captures).get();
Expr *Upper =
@@ -8901,8 +8901,8 @@ Expr *OpenMPIterationSpaceChecker::buildPreCond(
ExprResult CondExpr = SemaRef.BuildBinOp(
S, DefaultLoc,
- TestIsLessOp.getValue() ? (TestIsStrictOp ? BO_LT : BO_LE)
- : (TestIsStrictOp ? BO_GT : BO_GE),
+ TestIsLessOp.value() ? (TestIsStrictOp ? BO_LT : BO_LE)
+ : (TestIsStrictOp ? BO_GT : BO_GE),
NewLB.get(), NewUB.get());
if (CondExpr.isUsable()) {
if (!SemaRef.Context.hasSameUnqualifiedType(CondExpr.get()->getType(),
@@ -8978,12 +8978,10 @@ Expr *OpenMPIterationSpaceChecker::buildOrderedLoopData(
!SemaRef.getLangOpts().CPlusPlus)
return nullptr;
// Upper - Lower
- Expr *Upper = TestIsLessOp.getValue()
- ? Cnt
- : tryBuildCapture(SemaRef, LB, Captures).get();
- Expr *Lower = TestIsLessOp.getValue()
- ? tryBuildCapture(SemaRef, LB, Captures).get()
- : Cnt;
+ Expr *Upper =
+ TestIsLessOp.value() ? Cnt : tryBuildCapture(SemaRef, LB, Captures).get();
+ Expr *Lower =
+ TestIsLessOp.value() ? tryBuildCapture(SemaRef, LB, Captures).get() : Cnt;
if (!Upper || !Lower)
return nullptr;
@@ -11570,7 +11568,7 @@ protected:
bool checkType(ErrorInfoTy &ErrorInfo) const;
static bool CheckValue(const Expr *E, ErrorInfoTy &ErrorInfo,
- bool ShouldBeLValue) {
+ bool ShouldBeLValue, bool ShouldBeInteger = false) {
if (ShouldBeLValue && !E->isLValue()) {
ErrorInfo.Error = ErrorTy::XNotLValue;
ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = E->getExprLoc();
@@ -11586,8 +11584,7 @@ protected:
ErrorInfo.ErrorRange = ErrorInfo.NoteRange = E->getSourceRange();
return false;
}
-
- if (!QTy->isIntegerType()) {
+ if (ShouldBeInteger && !QTy->isIntegerType()) {
ErrorInfo.Error = ErrorTy::NotInteger;
ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = E->getExprLoc();
ErrorInfo.ErrorRange = ErrorInfo.NoteRange = E->getSourceRange();
@@ -11890,7 +11887,7 @@ bool OpenMPAtomicCompareCaptureChecker::checkType(ErrorInfoTy &ErrorInfo) {
if (V && !CheckValue(V, ErrorInfo, true))
return false;
- if (R && !CheckValue(R, ErrorInfo, true))
+ if (R && !CheckValue(R, ErrorInfo, true, true))
return false;
return true;
@@ -22588,27 +22585,27 @@ void Sema::ActOnOpenMPDeclareTargetName(NamedDecl *ND, SourceLocation Loc,
auto *VD = cast<ValueDecl>(ND);
llvm::Optional<OMPDeclareTargetDeclAttr *> ActiveAttr =
OMPDeclareTargetDeclAttr::getActiveAttr(VD);
- if (ActiveAttr && ActiveAttr.getValue()->getDevType() != DTCI.DT &&
- ActiveAttr.getValue()->getLevel() == Level) {
+ if (ActiveAttr && ActiveAttr.value()->getDevType() != DTCI.DT &&
+ ActiveAttr.value()->getLevel() == Level) {
Diag(Loc, diag::err_omp_device_type_mismatch)
<< OMPDeclareTargetDeclAttr::ConvertDevTypeTyToStr(DTCI.DT)
<< OMPDeclareTargetDeclAttr::ConvertDevTypeTyToStr(
- ActiveAttr.getValue()->getDevType());
+ ActiveAttr.value()->getDevType());
return;
}
- if (ActiveAttr && ActiveAttr.getValue()->getMapType() != MT &&
- ActiveAttr.getValue()->getLevel() == Level) {
+ if (ActiveAttr && ActiveAttr.value()->getMapType() != MT &&
+ ActiveAttr.value()->getLevel() == Level) {
Diag(Loc, diag::err_omp_declare_target_to_and_link) << ND;
return;
}
- if (ActiveAttr && ActiveAttr.getValue()->getLevel() == Level)
+ if (ActiveAttr && ActiveAttr.value()->getLevel() == Level)
return;
Expr *IndirectE = nullptr;
bool IsIndirect = false;
if (DTCI.Indirect) {
- IndirectE = DTCI.Indirect.getValue();
+ IndirectE = DTCI.Indirect.value();
if (!IndirectE)
IsIndirect = true;
}
@@ -22702,13 +22699,13 @@ void Sema::checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D,
llvm::Optional<OMPDeclareTargetDeclAttr *> ActiveAttr =
OMPDeclareTargetDeclAttr::getActiveAttr(VD);
unsigned Level = DeclareTargetNesting.size();
- if (ActiveAttr && ActiveAttr.getValue()->getLevel() >= Level)
+ if (ActiveAttr && ActiveAttr.value()->getLevel() >= Level)
return;
DeclareTargetContextInfo &DTCI = DeclareTargetNesting.back();
Expr *IndirectE = nullptr;
bool IsIndirect = false;
if (DTCI.Indirect) {
- IndirectE = DTCI.Indirect.getValue();
+ IndirectE = DTCI.Indirect.value();
if (!IndirectE)
IsIndirect = true;
}
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index dbfe6164bda2..67cf8f0371c5 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -2695,8 +2695,15 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
for (TemplateParameterList::iterator NewParam = NewParams->begin(),
NewParamEnd = NewParams->end();
NewParam != NewParamEnd; ++NewParam) {
- // Variables used to diagnose redundant default arguments
+ // Whether we've seen a duplicate default argument in the same translation
+ // unit.
bool RedundantDefaultArg = false;
+ // Whether we've found inconsis inconsitent default arguments in different
+ // translation unit.
+ bool InconsistentDefaultArg = false;
+ // The name of the module which contains the inconsistent default argument.
+ std::string PrevModuleName;
+
SourceLocation OldDefaultLoc;
SourceLocation NewDefaultLoc;
@@ -2729,7 +2736,16 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
OldDefaultLoc = OldTypeParm->getDefaultArgumentLoc();
NewDefaultLoc = NewTypeParm->getDefaultArgumentLoc();
SawDefaultArgument = true;
- RedundantDefaultArg = true;
+
+ if (!OldTypeParm->getOwningModule() ||
+ isModuleUnitOfCurrentTU(OldTypeParm->getOwningModule()))
+ RedundantDefaultArg = true;
+ else if (!getASTContext().isSameDefaultTemplateArgument(OldTypeParm,
+ NewTypeParm)) {
+ InconsistentDefaultArg = true;
+ PrevModuleName =
+ OldTypeParm->getImportedOwningModule()->getFullModuleName();
+ }
PreviousDefaultArgLoc = NewDefaultLoc;
} else if (OldTypeParm && OldTypeParm->hasDefaultArgument()) {
// Merge the default argument from the old declaration to the
@@ -2774,7 +2790,15 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
OldDefaultLoc = OldNonTypeParm->getDefaultArgumentLoc();
NewDefaultLoc = NewNonTypeParm->getDefaultArgumentLoc();
SawDefaultArgument = true;
- RedundantDefaultArg = true;
+ if (!OldNonTypeParm->getOwningModule() ||
+ isModuleUnitOfCurrentTU(OldNonTypeParm->getOwningModule()))
+ RedundantDefaultArg = true;
+ else if (!getASTContext().isSameDefaultTemplateArgument(
+ OldNonTypeParm, NewNonTypeParm)) {
+ InconsistentDefaultArg = true;
+ PrevModuleName =
+ OldNonTypeParm->getImportedOwningModule()->getFullModuleName();
+ }
PreviousDefaultArgLoc = NewDefaultLoc;
} else if (OldNonTypeParm && OldNonTypeParm->hasDefaultArgument()) {
// Merge the default argument from the old declaration to the
@@ -2818,7 +2842,15 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
OldDefaultLoc = OldTemplateParm->getDefaultArgument().getLocation();
NewDefaultLoc = NewTemplateParm->getDefaultArgument().getLocation();
SawDefaultArgument = true;
- RedundantDefaultArg = true;
+ if (!OldTemplateParm->getOwningModule() ||
+ isModuleUnitOfCurrentTU(OldTemplateParm->getOwningModule()))
+ RedundantDefaultArg = true;
+ else if (!getASTContext().isSameDefaultTemplateArgument(
+ OldTemplateParm, NewTemplateParm)) {
+ InconsistentDefaultArg = true;
+ PrevModuleName =
+ OldTemplateParm->getImportedOwningModule()->getFullModuleName();
+ }
PreviousDefaultArgLoc = NewDefaultLoc;
} else if (OldTemplateParm && OldTemplateParm->hasDefaultArgument()) {
// Merge the default argument from the old declaration to the
@@ -2845,13 +2877,32 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
Invalid = true;
}
+ // [basic.def.odr]/13:
+ // There can be more than one definition of a
+ // ...
+ // default template argument
+ // ...
+ // in a program provided that each definition appears in a different
+ // translation unit and the definitions satisfy the [same-meaning
+ // criteria of the ODR].
+ //
+ // Simply, the design of modules allows the definition of template default
+ // argument to be repeated across translation unit. Note that the ODR is
+ // checked elsewhere. But it is still not allowed to repeat template default
+ // argument in the same translation unit.
if (RedundantDefaultArg) {
- // C++ [temp.param]p12:
- // A template-parameter shall not be given default arguments
- // by two different declarations in the same scope.
Diag(NewDefaultLoc, diag::err_template_param_default_arg_redefinition);
Diag(OldDefaultLoc, diag::note_template_param_prev_default_arg);
Invalid = true;
+ } else if (InconsistentDefaultArg) {
+ // We could only diagnose about the case that the OldParam is imported.
+ // The case NewParam is imported should be handled in ASTReader.
+ Diag(NewDefaultLoc,
+ diag::err_template_param_default_arg_inconsistent_redefinition);
+ Diag(OldDefaultLoc,
+ diag::note_template_param_prev_default_arg_in_other_module)
+ << PrevModuleName;
+ Invalid = true;
} else if (MissingDefaultArg && TPC != TPC_FunctionTemplate) {
// C++ [temp.param]p11:
// If a template-parameter of a class template has a default
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index d7558017948a..bd166ff6f594 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -469,8 +469,8 @@ static void instantiateOMPDeclareVariantAttr(
if (!DeclVarData)
return;
- E = DeclVarData.getValue().second;
- FD = DeclVarData.getValue().first;
+ E = DeclVarData.value().second;
+ FD = DeclVarData.value().first;
if (auto *VariantDRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts())) {
if (auto *VariantFD = dyn_cast<FunctionDecl>(VariantDRE->getDecl())) {
@@ -4840,7 +4840,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
/*Complain*/DefinitionRequired)) {
if (DefinitionRequired)
Function->setInvalidDecl();
- else if (TSK == TSK_ExplicitInstantiationDefinition) {
+ else if (TSK == TSK_ExplicitInstantiationDefinition ||
+ (Function->isConstexpr() && !Recursive)) {
// Try again at the end of the translation unit (at which point a
// definition will be required).
assert(!Recursive);
@@ -4855,7 +4856,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
Diag(PatternDecl->getLocation(), diag::note_forward_template_decl);
if (getLangOpts().CPlusPlus11)
Diag(PointOfInstantiation, diag::note_inst_declaration_hint)
- << Function;
+ << Function;
}
}
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index d853805bf97e..04ade0a3b9d0 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -1462,18 +1462,19 @@ bool ASTReader::ReadSLocEntry(int ID) {
unsigned RecCode = MaybeRecCode.get();
if (RecCode == SM_SLOC_BUFFER_BLOB_COMPRESSED) {
- if (!llvm::zlib::isAvailable()) {
+ if (!llvm::compression::zlib::isAvailable()) {
Error("zlib is not available");
return nullptr;
}
- SmallString<0> Uncompressed;
- if (llvm::Error E =
- llvm::zlib::uncompress(Blob, Uncompressed, Record[0])) {
+ SmallVector<uint8_t, 0> Uncompressed;
+ if (llvm::Error E = llvm::compression::zlib::uncompress(
+ llvm::arrayRefFromStringRef(Blob), Uncompressed, Record[0])) {
Error("could not decompress embedded file contents: " +
llvm::toString(std::move(E)));
return nullptr;
}
- return llvm::MemoryBuffer::getMemBufferCopy(Uncompressed, Name);
+ return llvm::MemoryBuffer::getMemBufferCopy(
+ llvm::toStringRef(Uncompressed), Name);
} else if (RecCode == SM_SLOC_BUFFER_BLOB) {
return llvm::MemoryBuffer::getMemBuffer(Blob.drop_back(1), Name, true);
} else {
@@ -5171,8 +5172,9 @@ namespace {
bool ReadPreprocessorOptions(const PreprocessorOptions &PPOpts,
bool Complain,
std::string &SuggestedPredefines) override {
- return checkPreprocessorOptions(ExistingPPOpts, PPOpts, nullptr, FileMgr,
- SuggestedPredefines, ExistingLangOpts);
+ return checkPreprocessorOptions(PPOpts, ExistingPPOpts, /*Diags=*/nullptr,
+ FileMgr, SuggestedPredefines,
+ ExistingLangOpts);
}
};
diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
index 1787909bb6f7..fac8fc141d2c 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -1888,8 +1888,8 @@ void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS) {
// without this file existing on disk.
if (!U.Size || (!U.ModTime && IncludeTimestamps)) {
PP->Diag(U.FileNameLoc, diag::err_module_no_size_mtime_for_header)
- << WritingModule->getFullModuleName() << U.Size.hasValue()
- << U.FileName;
+ << WritingModule->getFullModuleName() << U.Size.has_value()
+ << U.FileName;
continue;
}
@@ -2000,12 +2000,13 @@ static void emitBlob(llvm::BitstreamWriter &Stream, StringRef Blob,
// Compress the buffer if possible. We expect that almost all PCM
// consumers will not want its contents.
- SmallString<0> CompressedBuffer;
- if (llvm::zlib::isAvailable()) {
- llvm::zlib::compress(Blob.drop_back(1), CompressedBuffer);
+ SmallVector<uint8_t, 0> CompressedBuffer;
+ if (llvm::compression::zlib::isAvailable()) {
+ llvm::compression::zlib::compress(
+ llvm::arrayRefFromStringRef(Blob.drop_back(1)), CompressedBuffer);
RecordDataType Record[] = {SM_SLOC_BUFFER_BLOB_COMPRESSED, Blob.size() - 1};
Stream.EmitRecordWithBlob(SLocBufferBlobCompressedAbbrv, Record,
- CompressedBuffer);
+ llvm::toStringRef(CompressedBuffer));
return;
}
diff --git a/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp b/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
index 330ca90b7659..ca76e2d83381 100644
--- a/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
@@ -769,7 +769,7 @@ void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
if (!errorNode)
errorNode = C.generateNonFatalErrorNode();
- if (!errorNode.getValue())
+ if (!errorNode.value())
continue;
SmallString<128> sbuf;
@@ -787,7 +787,7 @@ void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
os << "'";
auto R = std::make_unique<PathSensitiveBugReport>(*BT, os.str(),
- errorNode.getValue());
+ errorNode.value());
R->addRange(msg.getArgSourceRange(I));
C.emitReport(std::move(R));
}
diff --git a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
index 2e4c8e643698..987cf65d6fec 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
@@ -848,7 +848,7 @@ SVal CStringChecker::getCStringLength(CheckerContext &C, ProgramStateRef &state,
SValBuilder &svalBuilder = C.getSValBuilder();
QualType sizeTy = svalBuilder.getContext().getSizeType();
const StringLiteral *strLit = cast<StringRegion>(MR)->getStringLiteral();
- return svalBuilder.makeIntVal(strLit->getByteLength(), sizeTy);
+ return svalBuilder.makeIntVal(strLit->getLength(), sizeTy);
}
case MemRegion::SymbolicRegionKind:
case MemRegion::AllocaRegionKind:
diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index 92d7cef78b13..36464707d06a 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -1189,9 +1189,10 @@ MallocChecker::performKernelMalloc(const CallEvent &Call, CheckerContext &C,
}
NonLoc Flags = V.castAs<NonLoc>();
- NonLoc ZeroFlag = C.getSValBuilder()
- .makeIntVal(KernelZeroFlagVal.getValue(), FlagsEx->getType())
- .castAs<NonLoc>();
+ NonLoc ZeroFlag =
+ C.getSValBuilder()
+ .makeIntVal(KernelZeroFlagVal.value(), FlagsEx->getType())
+ .castAs<NonLoc>();
SVal MaskedFlagsUC = C.getSValBuilder().evalBinOpNN(State, BO_And,
Flags, ZeroFlag,
FlagsEx->getType());
@@ -1239,7 +1240,7 @@ void MallocChecker::checkKernelMalloc(const CallEvent &Call,
llvm::Optional<ProgramStateRef> MaybeState =
performKernelMalloc(Call, C, State);
if (MaybeState)
- State = MaybeState.getValue();
+ State = MaybeState.value();
else
State = MallocMemAux(C, Call, Call.getArgExpr(0), UndefinedVal(), State,
AF_Malloc);
diff --git a/clang/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp
index 3481936e572b..fb6afd0fdabc 100644
--- a/clang/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp
@@ -136,10 +136,10 @@ void NonNullParamChecker::checkPreCall(const CallEvent &Call,
if (!DV)
continue;
- assert(!HasRefTypeParam || isa<Loc>(DV.getValue()));
+ assert(!HasRefTypeParam || isa<Loc>(DV.value()));
// Process the case when the argument is not a location.
- if (ExpectedToBeNonNull && !isa<Loc>(DV.getValue())) {
+ if (ExpectedToBeNonNull && !isa<Loc>(DV.value())) {
// If the argument is a union type, we want to handle a potential
// transparent_union GCC extension.
if (!ArgE)
diff --git a/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
index 9da44d5c0d39..aa3f4524798a 100644
--- a/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
@@ -234,7 +234,8 @@ void UnixAPIMisuseChecker::CheckOpenVariant(CheckerContext &C,
}
NonLoc oflags = V.castAs<NonLoc>();
NonLoc ocreateFlag = C.getSValBuilder()
- .makeIntVal(Val_O_CREAT.getValue(), oflagsEx->getType()).castAs<NonLoc>();
+ .makeIntVal(Val_O_CREAT.value(), oflagsEx->getType())
+ .castAs<NonLoc>();
SVal maskedFlagsUC = C.getSValBuilder().evalBinOpNN(state, BO_And,
oflags, ocreateFlag,
oflagsEx->getType());
diff --git a/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp b/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
index 79d19a3b99f2..009cbd4559b5 100644
--- a/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
+++ b/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
@@ -78,7 +78,7 @@ AnalyzerOptions::getExplorationStrategy() const {
ExplorationStrategyKind::BFSBlockDFSContents)
.Default(None);
assert(K && "User mode is invalid.");
- return K.getValue();
+ return K.value();
}
CTUPhase1InliningKind AnalyzerOptions::getCTUPhase1Inlining() const {
@@ -89,7 +89,7 @@ CTUPhase1InliningKind AnalyzerOptions::getCTUPhase1Inlining() const {
.Case("all", CTUPhase1InliningKind::All)
.Default(None);
assert(K && "CTU inlining mode is invalid.");
- return K.getValue();
+ return K.value();
}
IPAKind AnalyzerOptions::getIPAMode() const {
@@ -102,7 +102,7 @@ IPAKind AnalyzerOptions::getIPAMode() const {
.Default(None);
assert(K && "IPA Mode is invalid.");
- return K.getValue();
+ return K.value();
}
bool
diff --git a/clang/lib/StaticAnalyzer/Core/BugReporter.cpp b/clang/lib/StaticAnalyzer/Core/BugReporter.cpp
index a2efe14f1045..4d6b82e63f6a 100644
--- a/clang/lib/StaticAnalyzer/Core/BugReporter.cpp
+++ b/clang/lib/StaticAnalyzer/Core/BugReporter.cpp
@@ -2363,15 +2363,15 @@ PathSensitiveBugReport::getInterestingnessKind(const MemRegion *R) const {
}
bool PathSensitiveBugReport::isInteresting(SVal V) const {
- return getInterestingnessKind(V).hasValue();
+ return getInterestingnessKind(V).has_value();
}
bool PathSensitiveBugReport::isInteresting(SymbolRef sym) const {
- return getInterestingnessKind(sym).hasValue();
+ return getInterestingnessKind(sym).has_value();
}
bool PathSensitiveBugReport::isInteresting(const MemRegion *R) const {
- return getInterestingnessKind(R).hasValue();
+ return getInterestingnessKind(R).has_value();
}
bool PathSensitiveBugReport::isInteresting(const LocationContext *LC) const {
diff --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index 5b72c91ccd74..2caa5bbc16df 100644
--- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -2950,7 +2950,7 @@ PathDiagnosticPieceRef ConditionBRVisitor::VisitTrueTest(
PathDiagnosticLocation Loc(Cond, SM, LCtx);
auto event = std::make_shared<PathDiagnosticEventPiece>(Loc, Message);
if (shouldPrune)
- event->setPrunable(shouldPrune.getValue());
+ event->setPrunable(shouldPrune.value());
return event;
}
@@ -3084,9 +3084,9 @@ bool ConditionBRVisitor::printValue(const Expr *CondVarExpr, raw_ostream &Out,
Out << (TookTrue ? "not equal to 0" : "0");
} else {
if (Ty->isBooleanType())
- Out << (IntValue.getValue()->getBoolValue() ? "true" : "false");
+ Out << (IntValue.value()->getBoolValue() ? "true" : "false");
else
- Out << *IntValue.getValue();
+ Out << *IntValue.value();
}
return true;
@@ -3282,7 +3282,7 @@ void FalsePositiveRefutationBRVisitor::finalizeVisitor(
if (!IsSAT)
return;
- if (!IsSAT.getValue())
+ if (!IsSAT.value())
BR.markInvalid("Infeasible constraints", EndPathNode->getLocationContext());
}
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
index 5f8a84591b2a..e1649f0b3df6 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
@@ -1016,7 +1016,7 @@ bool ExprEngine::shouldInlineCall(const CallEvent &Call, const Decl *D,
// Check if this function has been marked as non-inlinable.
Optional<bool> MayInline = Engine.FunctionSummaries->mayInline(D);
if (MayInline) {
- if (!MayInline.getValue())
+ if (!MayInline.value())
return false;
} else {
diff --git a/clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp b/clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
index 93c19a688b9a..d35646bfba91 100644
--- a/clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
+++ b/clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
@@ -407,11 +407,11 @@ void PlistPrinter::ReportMacroExpansions(raw_ostream &o, unsigned indent) {
// Output the macro name.
Indent(o, indent) << "<key>name</key>";
- EmitString(o, MacroName.getValue()) << '\n';
+ EmitString(o, MacroName.value()) << '\n';
// Output what it expands into.
Indent(o, indent) << "<key>expansion</key>";
- EmitString(o, ExpansionText.getValue()) << '\n';
+ EmitString(o, ExpansionText.value()) << '\n';
// Finish up.
--indent;
diff --git a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
index 13fac37899cd..cf3d13ffb7ba 100644
--- a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
+++ b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
@@ -113,6 +113,8 @@ nonloc::SymbolVal SValBuilder::makeNonLoc(const SymExpr *operand,
QualType fromTy, QualType toTy) {
assert(operand);
assert(!Loc::isLocType(toTy));
+ if (fromTy == toTy)
+ return operand;
return nonloc::SymbolVal(SymMgr.getCastSymbol(operand, fromTy, toTy));
}
@@ -1101,6 +1103,10 @@ nonloc::SymbolVal SValBuilder::simplifySymbolCast(nonloc::SymbolVal V,
SymbolRef RootSym = cast<SymbolCast>(SE)->getOperand();
QualType RT = RootSym->getType().getCanonicalType();
+ // FIXME support simplification from non-integers.
+ if (!RT->isIntegralOrEnumerationType())
+ return makeNonLoc(SE, T, CastTy);
+
BasicValueFactory &BVF = getBasicValueFactory();
APSIntType CTy = BVF.getAPSIntType(CastTy);
APSIntType TTy = BVF.getAPSIntType(T);
diff --git a/clang/lib/Support/RISCVVIntrinsicUtils.cpp b/clang/lib/Support/RISCVVIntrinsicUtils.cpp
index d4d3f22c9327..19eb65b39b0a 100644
--- a/clang/lib/Support/RISCVVIntrinsicUtils.cpp
+++ b/clang/lib/Support/RISCVVIntrinsicUtils.cpp
@@ -114,7 +114,7 @@ bool RVVType::verifyType() const {
return false;
if (isFloat() && ElementBitwidth == 8)
return false;
- unsigned V = Scale.getValue();
+ unsigned V = Scale.value();
switch (ElementBitwidth) {
case 1:
case 8:
@@ -798,7 +798,7 @@ RVVType::computeTypes(BasicType BT, int Log2LMUL, unsigned NF,
if (!T)
return llvm::None;
// Record legal type index
- Types.push_back(T.getValue());
+ Types.push_back(T.value());
}
return Types;
}
diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp
index 26c2b2b2f394..43127ea2df98 100644
--- a/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp
+++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp
@@ -9,16 +9,19 @@
#include "clang/Tooling/DependencyScanning/DependencyScanningTool.h"
#include "clang/Frontend/Utils.h"
-namespace clang {
-namespace tooling {
-namespace dependencies {
+using namespace clang;
+using namespace tooling;
+using namespace dependencies;
std::vector<std::string> FullDependencies::getCommandLine(
- std::function<StringRef(ModuleID)> LookupPCMPath) const {
+ llvm::function_ref<std::string(const ModuleID &, ModuleOutputKind)>
+ LookupModuleOutput) const {
std::vector<std::string> Ret = getCommandLineWithoutModulePaths();
- for (ModuleID MID : ClangModuleDeps)
- Ret.push_back(("-fmodule-file=" + LookupPCMPath(MID)).str());
+ for (ModuleID MID : ClangModuleDeps) {
+ auto PCM = LookupModuleOutput(MID, ModuleOutputKind::ModuleFile);
+ Ret.push_back("-fmodule-file=" + PCM);
+ }
return Ret;
}
@@ -192,7 +195,3 @@ DependencyScanningTool::getFullDependencies(
return std::move(Result);
return Consumer.getFullDependencies(CommandLine);
}
-
-} // end namespace dependencies
-} // end namespace tooling
-} // end namespace clang
diff --git a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
index f7d96130b971..725bb2c318ac 100644
--- a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
+++ b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
@@ -8,6 +8,7 @@
#include "clang/Tooling/DependencyScanning/ModuleDepCollector.h"
+#include "clang/Basic/MakeSupport.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Tooling/DependencyScanning/DependencyScanningWorker.h"
@@ -56,6 +57,9 @@ CompilerInvocation ModuleDepCollector::makeInvocationForModuleBuildWithoutPaths(
CI.getFrontendOpts().OutputFile.clear();
CI.getCodeGenOpts().MainFileName.clear();
CI.getCodeGenOpts().DwarfDebugFlags.clear();
+ CI.getDiagnosticOpts().DiagnosticSerializationFile.clear();
+ CI.getDependencyOutputOpts().OutputFile.clear();
+ CI.getDependencyOutputOpts().Targets.clear();
CI.getFrontendOpts().ProgramAction = frontend::GenerateModule;
CI.getLangOpts()->ModuleName = Deps.ID.ModuleName;
@@ -107,18 +111,47 @@ serializeCompilerInvocation(const CompilerInvocation &CI) {
return std::vector<std::string>{Args.begin(), Args.end()};
}
+static std::vector<std::string> splitString(std::string S, char Separator) {
+ SmallVector<StringRef> Segments;
+ StringRef(S).split(Segments, Separator, /*MaxSplit=*/-1, /*KeepEmpty=*/false);
+ std::vector<std::string> Result;
+ Result.reserve(Segments.size());
+ for (StringRef Segment : Segments)
+ Result.push_back(Segment.str());
+ return Result;
+}
+
std::vector<std::string> ModuleDeps::getCanonicalCommandLine(
- std::function<StringRef(ModuleID)> LookupPCMPath) const {
+ llvm::function_ref<std::string(const ModuleID &, ModuleOutputKind)>
+ LookupModuleOutput) const {
CompilerInvocation CI(BuildInvocation);
FrontendOptions &FrontendOpts = CI.getFrontendOpts();
InputKind ModuleMapInputKind(FrontendOpts.DashX.getLanguage(),
InputKind::Format::ModuleMap);
FrontendOpts.Inputs.emplace_back(ClangModuleMapFile, ModuleMapInputKind);
- FrontendOpts.OutputFile = std::string(LookupPCMPath(ID));
+ FrontendOpts.OutputFile =
+ LookupModuleOutput(ID, ModuleOutputKind::ModuleFile);
+ if (HadSerializedDiagnostics)
+ CI.getDiagnosticOpts().DiagnosticSerializationFile =
+ LookupModuleOutput(ID, ModuleOutputKind::DiagnosticSerializationFile);
+ if (HadDependencyFile) {
+ DependencyOutputOptions &DepOpts = CI.getDependencyOutputOpts();
+ DepOpts.OutputFile =
+ LookupModuleOutput(ID, ModuleOutputKind::DependencyFile);
+ DepOpts.Targets = splitString(
+ LookupModuleOutput(ID, ModuleOutputKind::DependencyTargets), '\0');
+ if (!DepOpts.OutputFile.empty() && DepOpts.Targets.empty()) {
+ // Fallback to -o as dependency target, as in the driver.
+ SmallString<128> Target;
+ quoteMakeTarget(FrontendOpts.OutputFile, Target);
+ DepOpts.Targets.push_back(std::string(Target));
+ }
+ }
for (ModuleID MID : ClangModuleDeps)
- FrontendOpts.ModuleFiles.emplace_back(LookupPCMPath(MID));
+ FrontendOpts.ModuleFiles.push_back(
+ LookupModuleOutput(MID, ModuleOutputKind::ModuleFile));
return serializeCompilerInvocation(CI);
}
@@ -309,6 +342,12 @@ ModuleID ModuleDepCollectorPP::handleTopLevelModule(const Module *M) {
optimizeHeaderSearchOpts(BuildInvocation.getHeaderSearchOpts(),
*MDC.ScanInstance.getASTReader(), *MF);
});
+ MD.HadSerializedDiagnostics = !MDC.OriginalInvocation.getDiagnosticOpts()
+ .DiagnosticSerializationFile.empty();
+ MD.HadDependencyFile =
+ !MDC.OriginalInvocation.getDependencyOutputOpts().OutputFile.empty();
+ // FIXME: HadSerializedDiagnostics and HadDependencyFile should be included in
+ // the context hash since it can affect the command-line.
MD.ID.ContextHash = MD.BuildInvocation.getModuleHash();
llvm::DenseSet<const Module *> AddedModules;
diff --git a/clang/tools/clang-format/ClangFormat.cpp b/clang/tools/clang-format/ClangFormat.cpp
index 07110a0db091..269bc59506b2 100644
--- a/clang/tools/clang-format/ClangFormat.cpp
+++ b/clang/tools/clang-format/ClangFormat.cpp
@@ -70,16 +70,18 @@ static cl::opt<std::string>
cl::desc("The name of the predefined style used as a\n"
"fallback in case clang-format is invoked with\n"
"-style=file, but can not find the .clang-format\n"
- "file to use.\n"
+ "file to use. Defaults to 'LLVM'.\n"
"Use -fallback-style=none to skip formatting."),
cl::init(clang::format::DefaultFallbackStyle),
cl::cat(ClangFormatCategory));
static cl::opt<std::string> AssumeFileName(
"assume-filename",
- cl::desc("Override filename used to determine the language.\n"
- "When reading from stdin, clang-format assumes this\n"
- "filename to determine the language.\n"
+ cl::desc("Set filename used to determine the language and to find\n"
+ ".clang-format file.\n"
+ "Only used when reading from stdin.\n"
+ "If this is not passed, the .clang-format file is searched\n"
+ "relative to the current working directory when reading stdin.\n"
"Unrecognized filenames are treated as C++.\n"
"supported:\n"
" CSharp: .cs\n"
@@ -244,8 +246,12 @@ static bool fillRanges(MemoryBuffer *Code,
errs() << "error: invalid <start line>:<end line> pair\n";
return true;
}
+ if (FromLine < 1) {
+ errs() << "error: start line should be at least 1\n";
+ return true;
+ }
if (FromLine > ToLine) {
- errs() << "error: start line should be less than end line\n";
+ errs() << "error: start line should not exceed end line\n";
return true;
}
SourceLocation Start = Sources.translateLineCol(ID, FromLine, 1);
diff --git a/clang/tools/driver/driver.cpp b/clang/tools/driver/driver.cpp
index 0e21106535ec..34335a599a00 100644
--- a/clang/tools/driver/driver.cpp
+++ b/clang/tools/driver/driver.cpp
@@ -408,7 +408,7 @@ int clang_main(int Argc, char **Argv) {
llvm::Optional<std::string> OptCL = llvm::sys::Process::GetEnv("CL");
if (OptCL) {
SmallVector<const char *, 8> PrependedOpts;
- getCLEnvVarOptions(OptCL.getValue(), Saver, PrependedOpts);
+ getCLEnvVarOptions(OptCL.value(), Saver, PrependedOpts);
// Insert right after the program name to prepend to the argument list.
Args.insert(Args.begin() + 1, PrependedOpts.begin(), PrependedOpts.end());
@@ -417,7 +417,7 @@ int clang_main(int Argc, char **Argv) {
llvm::Optional<std::string> Opt_CL_ = llvm::sys::Process::GetEnv("_CL_");
if (Opt_CL_) {
SmallVector<const char *, 8> AppendedOpts;
- getCLEnvVarOptions(Opt_CL_.getValue(), Saver, AppendedOpts);
+ getCLEnvVarOptions(Opt_CL_.value(), Saver, AppendedOpts);
// Insert at the end of the argument list to append.
Args.append(AppendedOpts.begin(), AppendedOpts.end());
diff --git a/clang/utils/TableGen/RISCVVEmitter.cpp b/clang/utils/TableGen/RISCVVEmitter.cpp
index 068e6a0c072c..db4cd77d8c53 100644
--- a/clang/utils/TableGen/RISCVVEmitter.cpp
+++ b/clang/utils/TableGen/RISCVVEmitter.cpp
@@ -105,6 +105,16 @@ void emitCodeGenSwitchBody(const RVVIntrinsic *RVVI, raw_ostream &OS) {
return;
}
+ // Cast pointer operand of vector load intrinsic.
+ for (const auto &I : enumerate(RVVI->getInputTypes())) {
+ if (I.value()->isPointer()) {
+ assert(RVVI->getIntrinsicTypes().front() == -1 &&
+ "RVVI should be vector load intrinsic.");
+ OS << " Ops[" << I.index() << "] = Builder.CreateBitCast(Ops[";
+ OS << I.index() << "], ResultType->getPointerTo());\n";
+ }
+ }
+
if (RVVI->isMasked()) {
if (RVVI->hasVL()) {
OS << " std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);\n";
@@ -218,7 +228,7 @@ void RVVEmitter::createHeader(raw_ostream &OS) {
auto T = RVVType::computeType(BasicType::Int8, Log2LMUL,
PrototypeDescriptor::Mask);
if (T)
- printType(T.getValue());
+ printType(T.value());
}
// Print RVV int/float types.
for (char I : StringRef("csil")) {
@@ -226,13 +236,13 @@ void RVVEmitter::createHeader(raw_ostream &OS) {
for (int Log2LMUL : Log2LMULs) {
auto T = RVVType::computeType(BT, Log2LMUL, PrototypeDescriptor::Vector);
if (T) {
- printType(T.getValue());
+ printType(T.value());
auto UT = RVVType::computeType(
BT, Log2LMUL,
PrototypeDescriptor(BaseTypeModifier::Vector,
VectorTypeModifier::NoModifier,
TypeModifier::UnsignedInteger));
- printType(UT.getValue());
+ printType(UT.value());
}
}
}
@@ -241,7 +251,7 @@ void RVVEmitter::createHeader(raw_ostream &OS) {
auto T = RVVType::computeType(BasicType::Float16, Log2LMUL,
PrototypeDescriptor::Vector);
if (T)
- printType(T.getValue());
+ printType(T.value());
}
OS << "#endif\n";
@@ -250,7 +260,7 @@ void RVVEmitter::createHeader(raw_ostream &OS) {
auto T = RVVType::computeType(BasicType::Float32, Log2LMUL,
PrototypeDescriptor::Vector);
if (T)
- printType(T.getValue());
+ printType(T.value());
}
OS << "#endif\n";
@@ -259,7 +269,7 @@ void RVVEmitter::createHeader(raw_ostream &OS) {
auto T = RVVType::computeType(BasicType::Float64, Log2LMUL,
PrototypeDescriptor::Vector);
if (T)
- printType(T.getValue());
+ printType(T.value());
}
OS << "#endif\n\n";