diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2022-07-14 18:50:02 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2022-07-14 18:50:02 +0000 |
commit | 1f917f69ff07f09b6dbb670971f57f8efe718b84 (patch) | |
tree | 99293cbc1411737cd995dac10a99b2c40ef0944c /clang | |
parent | 145449b1e420787bb99721a429341fa6be3adfb6 (diff) |
Diffstat (limited to 'clang')
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"; |