diff --git a/clang-tools-extra/clang-tidy/bugprone/BranchCloneCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/BranchCloneCheck.cpp index eb54aaa994457..e40b27585d3dd 100644 --- a/clang-tools-extra/clang-tidy/bugprone/BranchCloneCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/BranchCloneCheck.cpp @@ -59,7 +59,8 @@ namespace bugprone { void BranchCloneCheck::registerMatchers(MatchFinder *Finder) { Finder->addMatcher( - ifStmt(stmt().bind("if"), + ifStmt(unless(allOf(isConstexpr(), isInTemplateInstantiation())), + stmt().bind("if"), hasParent(stmt(unless(ifStmt(hasElse(equalsBoundNode("if")))))), hasElse(stmt().bind("else"))), this); diff --git a/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp index 81ae45a008961..bcdb445948d92 100644 --- a/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp @@ -152,6 +152,15 @@ static std::string getCondVarNames(const Stmt *Cond) { return Result; } +static bool isKnownFalse(const Expr &Cond, const ASTContext &Ctx) { + if (Cond.isValueDependent()) + return false; + bool Result = false; + if (Cond.EvaluateAsBooleanCondition(Result, Ctx)) + return !Result; + return false; +} + void InfiniteLoopCheck::registerMatchers(MatchFinder *Finder) { const auto LoopCondition = allOf( hasCondition( @@ -170,17 +179,36 @@ void InfiniteLoopCheck::check(const MatchFinder::MatchResult &Result) { const auto *LoopStmt = Result.Nodes.getNodeAs("loop-stmt"); const auto *Func = Result.Nodes.getNodeAs("func"); + if (isKnownFalse(*Cond, *Result.Context)) + return; + + bool ShouldHaveConditionVariables = true; + if (const auto *While = dyn_cast(LoopStmt)) { + if (const VarDecl *LoopVarDecl = While->getConditionVariable()) { + if (const Expr *Init = LoopVarDecl->getInit()) { + ShouldHaveConditionVariables = false; + Cond = Init; + } + } + } + if (isAtLeastOneCondVarChanged(Func, LoopStmt, Cond, Result.Context)) return; std::string CondVarNames = getCondVarNames(Cond); - if (CondVarNames.empty()) + if (ShouldHaveConditionVariables && CondVarNames.empty()) return; - diag(LoopStmt->getBeginLoc(), - "this loop is infinite; none of its condition variables (%0)" - " are updated in the loop body") + if (CondVarNames.empty()) { + diag(LoopStmt->getBeginLoc(), + "this loop is infinite; it does not check any variables in the" + " condition"); + } else { + diag(LoopStmt->getBeginLoc(), + "this loop is infinite; none of its condition variables (%0)" + " are updated in the loop body") << CondVarNames; + } } } // namespace bugprone diff --git a/clang-tools-extra/clang-tidy/bugprone/MoveForwardingReferenceCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/MoveForwardingReferenceCheck.cpp index bf6f2f6ed0358..8953f95159a98 100644 --- a/clang-tools-extra/clang-tidy/bugprone/MoveForwardingReferenceCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/MoveForwardingReferenceCheck.cpp @@ -33,7 +33,7 @@ static void replaceMoveWithForward(const UnresolvedLookupExpr *Callee, if (CallRange.isValid()) { const std::string TypeName = - TypeParmDecl->getIdentifier() + (TypeParmDecl->getIdentifier() && !TypeParmDecl->isImplicit()) ? TypeParmDecl->getName().str() : (llvm::Twine("decltype(") + ParmVar->getName() + ")").str(); diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/InitVariablesCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/InitVariablesCheck.cpp index 8a628317a302f..a5d9275afaf79 100644 --- a/clang-tools-extra/clang-tidy/cppcoreguidelines/InitVariablesCheck.cpp +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/InitVariablesCheck.cpp @@ -29,11 +29,15 @@ InitVariablesCheck::InitVariablesCheck(StringRef Name, MathHeader(Options.get("MathHeader", "math.h")) {} void InitVariablesCheck::registerMatchers(MatchFinder *Finder) { - Finder->addMatcher(varDecl(unless(hasInitializer(anything())), - unless(isInstantiated()), isLocalVarDecl(), - unless(isStaticLocal()), isDefinition()) - .bind("vardecl"), - this); + std::string BadDecl = "badDecl"; + Finder->addMatcher( + varDecl(unless(hasInitializer(anything())), unless(isInstantiated()), + isLocalVarDecl(), unless(isStaticLocal()), isDefinition(), + optionally(hasParent(declStmt(hasParent( + cxxForRangeStmt(hasLoopVariable(varDecl().bind(BadDecl))))))), + unless(equalsBoundNode(BadDecl))) + .bind("vardecl"), + this); } void InitVariablesCheck::registerPPCallbacks(const SourceManager &SM, diff --git a/clang-tools-extra/clang-tidy/readability/BracesAroundStatementsCheck.cpp b/clang-tools-extra/clang-tidy/readability/BracesAroundStatementsCheck.cpp index 117ef36d78fe8..da0bef32c0915 100644 --- a/clang-tools-extra/clang-tidy/readability/BracesAroundStatementsCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/BracesAroundStatementsCheck.cpp @@ -123,7 +123,10 @@ void BracesAroundStatementsCheck::storeOptions( } void BracesAroundStatementsCheck::registerMatchers(MatchFinder *Finder) { - Finder->addMatcher(ifStmt().bind("if"), this); + Finder->addMatcher( + ifStmt(unless(allOf(isConstexpr(), isInTemplateInstantiation()))) + .bind("if"), + this); Finder->addMatcher(whileStmt().bind("while"), this); Finder->addMatcher(doStmt().bind("do"), this); Finder->addMatcher(forStmt().bind("for"), this); diff --git a/clang-tools-extra/clang-tidy/readability/ElseAfterReturnCheck.cpp b/clang-tools-extra/clang-tidy/readability/ElseAfterReturnCheck.cpp index 93b197a52a523..b3b4e0de2bf07 100644 --- a/clang-tools-extra/clang-tidy/readability/ElseAfterReturnCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/ElseAfterReturnCheck.cpp @@ -27,6 +27,8 @@ static const char WarningMessage[] = "do not use 'else' after '%0'"; static const char WarnOnUnfixableStr[] = "WarnOnUnfixable"; const DeclRefExpr *findUsage(const Stmt *Node, int64_t DeclIdentifier) { + if (!Node) + return nullptr; if (const auto *DeclRef = dyn_cast(Node)) { if (DeclRef->getDecl()->getID() == DeclIdentifier) { return DeclRef; @@ -44,6 +46,8 @@ const DeclRefExpr *findUsage(const Stmt *Node, int64_t DeclIdentifier) { const DeclRefExpr * findUsageRange(const Stmt *Node, const llvm::iterator_range &DeclIdentifiers) { + if (!Node) + return nullptr; if (const auto *DeclRef = dyn_cast(Node)) { if (llvm::is_contained(DeclIdentifiers, DeclRef->getDecl()->getID())) { return DeclRef; diff --git a/clang-tools-extra/clangd/CodeComplete.cpp b/clang-tools-extra/clangd/CodeComplete.cpp index 045b78d0779ff..86268b6c25ec4 100644 --- a/clang-tools-extra/clangd/CodeComplete.cpp +++ b/clang-tools-extra/clangd/CodeComplete.cpp @@ -1842,6 +1842,8 @@ CompletionItem CodeCompletion::render(const CodeCompleteOptions &Opts) const { if (InsertInclude && InsertInclude->Insertion) LSP.additionalTextEdits.push_back(*InsertInclude->Insertion); + LSP.score = Score.ExcludingName; + return LSP; } diff --git a/clang-tools-extra/clangd/FSProvider.cpp b/clang-tools-extra/clangd/FSProvider.cpp index 5d1434bf6f0bf..80d6be005cc41 100644 --- a/clang-tools-extra/clangd/FSProvider.cpp +++ b/clang-tools-extra/clangd/FSProvider.cpp @@ -19,7 +19,10 @@ namespace clangd { namespace { /// Always opens files in the underlying filesystem as "volatile", meaning they -/// won't be memory-mapped. This avoid locking the files on Windows. +/// won't be memory-mapped. Memory-mapping isn't desirable for clangd: +/// - edits to the underlying files change contents MemoryBuffers owned by +// SourceManager, breaking its invariants and leading to crashes +/// - it locks files on windows, preventing edits class VolatileFileSystem : public llvm::vfs::ProxyFileSystem { public: explicit VolatileFileSystem(llvm::IntrusiveRefCntPtr FS) @@ -34,7 +37,7 @@ class VolatileFileSystem : public llvm::vfs::ProxyFileSystem { if (!File) return File; // Try to guess preamble files, they can be memory-mapped even on Windows as - // clangd has exclusive access to those. + // clangd has exclusive access to those and nothing else should touch them. llvm::StringRef FileName = llvm::sys::path::filename(Path); if (FileName.startswith("preamble-") && FileName.endswith(".pch")) return File; @@ -70,15 +73,11 @@ class VolatileFileSystem : public llvm::vfs::ProxyFileSystem { llvm::IntrusiveRefCntPtr clang::clangd::RealFileSystemProvider::getFileSystem() const { -// Avoid using memory-mapped files on Windows, they cause file locking issues. -// FIXME: Try to use a similar approach in Sema instead of relying on -// propagation of the 'isVolatile' flag through all layers. -#ifdef _WIN32 + // Avoid using memory-mapped files. + // FIXME: Try to use a similar approach in Sema instead of relying on + // propagation of the 'isVolatile' flag through all layers. return new VolatileFileSystem( llvm::vfs::createPhysicalFileSystem().release()); -#else - return llvm::vfs::createPhysicalFileSystem().release(); -#endif } } // namespace clangd } // namespace clang diff --git a/clang-tools-extra/clangd/FSProvider.h b/clang-tools-extra/clangd/FSProvider.h index 2295789250696..1fe3ba864a33d 100644 --- a/clang-tools-extra/clangd/FSProvider.h +++ b/clang-tools-extra/clangd/FSProvider.h @@ -30,7 +30,6 @@ class FileSystemProvider { class RealFileSystemProvider : public FileSystemProvider { public: - // FIXME: returns the single real FS instance, which is not threadsafe. llvm::IntrusiveRefCntPtr getFileSystem() const override; }; diff --git a/clang-tools-extra/clangd/FindTarget.cpp b/clang-tools-extra/clangd/FindTarget.cpp index d8ce0b69283f5..82a2e8c27d566 100644 --- a/clang-tools-extra/clangd/FindTarget.cpp +++ b/clang-tools-extra/clangd/FindTarget.cpp @@ -35,6 +35,7 @@ #include "llvm/Support/Compiler.h" #include "llvm/Support/raw_ostream.h" #include +#include namespace clang { namespace clangd { @@ -134,6 +135,35 @@ const Type *getPointeeType(const Type *T) { return FirstArg.getAsType().getTypePtrOrNull(); } +const NamedDecl *getTemplatePattern(const NamedDecl *D) { + if (const CXXRecordDecl *CRD = dyn_cast(D)) { + return CRD->getTemplateInstantiationPattern(); + } else if (const FunctionDecl *FD = dyn_cast(D)) { + return FD->getTemplateInstantiationPattern(); + } else if (auto *VD = dyn_cast(D)) { + // Hmm: getTIP returns its arg if it's not an instantiation?! + VarDecl *T = VD->getTemplateInstantiationPattern(); + return (T == D) ? nullptr : T; + } else if (const auto *ED = dyn_cast(D)) { + return ED->getInstantiatedFromMemberEnum(); + } else if (isa(D) || isa(D)) { + if (const auto *Parent = llvm::dyn_cast(D->getDeclContext())) + if (const DeclContext *ParentPat = + dyn_cast_or_null(getTemplatePattern(Parent))) + for (const NamedDecl *BaseND : ParentPat->lookup(D->getDeclName())) + if (!BaseND->isImplicit() && BaseND->getKind() == D->getKind()) + return BaseND; + } else if (const auto *ECD = dyn_cast(D)) { + if (const auto *ED = dyn_cast(ECD->getDeclContext())) { + if (const EnumDecl *Pattern = ED->getInstantiatedFromMemberEnum()) { + for (const NamedDecl *BaseECD : Pattern->lookup(ECD->getDeclName())) + return BaseECD; + } + } + } + return nullptr; +} + // TargetFinder locates the entities that an AST node refers to. // // Typically this is (possibly) one declaration and (possibly) one type, but @@ -167,37 +197,12 @@ const Type *getPointeeType(const Type *T) { struct TargetFinder { using RelSet = DeclRelationSet; using Rel = DeclRelation; - llvm::SmallDenseMap Decls; - RelSet Flags; - static const NamedDecl *getTemplatePattern(const NamedDecl *D) { - if (const CXXRecordDecl *CRD = dyn_cast(D)) { - return CRD->getTemplateInstantiationPattern(); - } else if (const FunctionDecl *FD = dyn_cast(D)) { - return FD->getTemplateInstantiationPattern(); - } else if (auto *VD = dyn_cast(D)) { - // Hmm: getTIP returns its arg if it's not an instantiation?! - VarDecl *T = VD->getTemplateInstantiationPattern(); - return (T == D) ? nullptr : T; - } else if (const auto *ED = dyn_cast(D)) { - return ED->getInstantiatedFromMemberEnum(); - } else if (isa(D) || isa(D)) { - if (const auto *Parent = llvm::dyn_cast(D->getDeclContext())) - if (const DeclContext *ParentPat = - dyn_cast_or_null(getTemplatePattern(Parent))) - for (const NamedDecl *BaseND : ParentPat->lookup(D->getDeclName())) - if (!BaseND->isImplicit() && BaseND->getKind() == D->getKind()) - return BaseND; - } else if (const auto *ECD = dyn_cast(D)) { - if (const auto *ED = dyn_cast(ECD->getDeclContext())) { - if (const EnumDecl *Pattern = ED->getInstantiatedFromMemberEnum()) { - for (const NamedDecl *BaseECD : Pattern->lookup(ECD->getDeclName())) - return BaseECD; - } - } - } - return nullptr; - } +private: + llvm::SmallDenseMap> + Decls; + RelSet Flags; template void debug(T &Node, RelSet Flags) { dlog("visit [{0}] {1}", Flags, @@ -207,10 +212,22 @@ struct TargetFinder { void report(const NamedDecl *D, RelSet Flags) { dlog("--> [{0}] {1}", Flags, nodeToString(ast_type_traits::DynTypedNode::create(*D))); - Decls[D] |= Flags; + auto It = Decls.try_emplace(D, std::make_pair(Flags, Decls.size())); + // If already exists, update the flags. + if (!It.second) + It.first->second.first |= Flags; } public: + llvm::SmallVector, 1> takeDecls() const { + using ValTy = std::pair; + llvm::SmallVector Result; + Result.resize(Decls.size()); + for (const auto &Elem : Decls) + Result[Elem.second.second] = {Elem.first, Elem.second.first}; + return Result; + } + void add(const Decl *Dcl, RelSet Flags) { const NamedDecl *D = llvm::dyn_cast(Dcl); if (!D) @@ -485,7 +502,7 @@ allTargetDecls(const ast_type_traits::DynTypedNode &N) { else if (const CXXCtorInitializer *CCI = N.get()) Finder.add(CCI, Flags); - return {Finder.Decls.begin(), Finder.Decls.end()}; + return Finder.takeDecls(); } llvm::SmallVector diff --git a/clang-tools-extra/clangd/FormattedString.cpp b/clang-tools-extra/clangd/FormattedString.cpp index 881c34e007143..9cb732eabcf84 100644 --- a/clang-tools-extra/clangd/FormattedString.cpp +++ b/clang-tools-extra/clangd/FormattedString.cpp @@ -16,6 +16,7 @@ #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/raw_ostream.h" #include +#include #include #include #include @@ -117,16 +118,52 @@ std::string renderBlocks(llvm::ArrayRef> Children, void (Block::*RenderFunc)(llvm::raw_ostream &) const) { std::string R; llvm::raw_string_ostream OS(R); - for (auto &C : Children) + + // Trim rulers. + Children = Children.drop_while( + [](const std::unique_ptr &C) { return C->isRuler(); }); + auto Last = llvm::find_if( + llvm::reverse(Children), + [](const std::unique_ptr &C) { return !C->isRuler(); }); + Children = Children.drop_back(Children.end() - Last.base()); + + bool LastBlockWasRuler = true; + for (const auto &C : Children) { + if (C->isRuler() && LastBlockWasRuler) + continue; + LastBlockWasRuler = C->isRuler(); ((*C).*RenderFunc)(OS); - return llvm::StringRef(OS.str()).trim().str(); + } + + // Get rid of redundant empty lines introduced in plaintext while imitating + // padding in markdown. + std::string AdjustedResult; + llvm::StringRef TrimmedText(OS.str()); + TrimmedText = TrimmedText.trim(); + + llvm::copy_if(TrimmedText, std::back_inserter(AdjustedResult), + [&TrimmedText](const char &C) { + return !llvm::StringRef(TrimmedText.data(), + &C - TrimmedText.data() + 1) + // We allow at most two newlines. + .endswith("\n\n\n"); + }); + + return AdjustedResult; } -// Puts a vertical space between blocks inside a document. -class Spacer : public Block { +// Seperates two blocks with extra spacing. Note that it might render strangely +// in vscode if the trailing block is a codeblock, see +// https://github.com/microsoft/vscode/issues/88416 for details. +class Ruler : public Block { public: - void renderMarkdown(llvm::raw_ostream &OS) const override { OS << '\n'; } + void renderMarkdown(llvm::raw_ostream &OS) const override { + // Note that we need an extra new line before the ruler, otherwise we might + // make previous block a title instead of introducing a ruler. + OS << "\n---\n"; + } void renderPlainText(llvm::raw_ostream &OS) const override { OS << '\n'; } + bool isRuler() const override { return true; } }; class CodeBlock : public Block { @@ -272,7 +309,7 @@ Paragraph &Document::addParagraph() { return *static_cast(Children.back().get()); } -void Document::addSpacer() { Children.push_back(std::make_unique()); } +void Document::addRuler() { Children.push_back(std::make_unique()); } void Document::addCodeBlock(std::string Code, std::string Language) { Children.emplace_back( diff --git a/clang-tools-extra/clangd/FormattedString.h b/clang-tools-extra/clangd/FormattedString.h index 1b7e9fc752119..effd03725925b 100644 --- a/clang-tools-extra/clangd/FormattedString.h +++ b/clang-tools-extra/clangd/FormattedString.h @@ -33,6 +33,7 @@ class Block { std::string asMarkdown() const; std::string asPlainText() const; + virtual bool isRuler() const { return false; } virtual ~Block() = default; }; @@ -82,8 +83,8 @@ class Document { public: /// Adds a semantical block that will be separate from others. Paragraph &addParagraph(); - /// Inserts a vertical space into the document. - void addSpacer(); + /// Inserts a horizontal separator to the document. + void addRuler(); /// Adds a block of code. This translates to a ``` block in markdown. In plain /// text representation, the code block will be surrounded by newlines. void addCodeBlock(std::string Code, std::string Language = "cpp"); diff --git a/clang-tools-extra/clangd/Hover.cpp b/clang-tools-extra/clangd/Hover.cpp index 526f2220efa69..834c9d041872d 100644 --- a/clang-tools-extra/clangd/Hover.cpp +++ b/clang-tools-extra/clangd/Hover.cpp @@ -13,6 +13,7 @@ #include "FindTarget.h" #include "FormattedString.h" #include "Logger.h" +#include "ParsedAST.h" #include "Selection.h" #include "SourceCode.h" #include "index/SymbolCollector.h" @@ -21,13 +22,20 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclBase.h" #include "clang/AST/DeclTemplate.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" #include "clang/AST/PrettyPrinter.h" #include "clang/AST/Type.h" +#include "clang/Basic/Specifiers.h" #include "clang/Index/IndexSymbol.h" +#include "llvm/ADT/None.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" #include @@ -116,6 +124,15 @@ void printParams(llvm::raw_ostream &OS, } } +std::string printType(QualType QT, const PrintingPolicy &Policy) { + // TypePrinter doesn't resolve decltypes, so resolve them here. + // FIXME: This doesn't handle composite types that contain a decltype in them. + // We should rather have a printing policy for that. + while (const auto *DT = QT->getAs()) + QT = DT->getUnderlyingType(); + return QT.getAsString(Policy); +} + std::vector fetchTemplateParameters(const TemplateParameterList *Params, const PrintingPolicy &PP) { @@ -124,8 +141,7 @@ fetchTemplateParameters(const TemplateParameterList *Params, for (const Decl *Param : *Params) { HoverInfo::Param P; - P.Type.emplace(); - if (const auto TTP = dyn_cast(Param)) { + if (const auto *TTP = dyn_cast(Param)) { P.Type = TTP->wasDeclaredWithTypename() ? "typename" : "class"; if (TTP->isParameterPack()) *P.Type += "..."; @@ -134,21 +150,21 @@ fetchTemplateParameters(const TemplateParameterList *Params, P.Name = TTP->getNameAsString(); if (TTP->hasDefaultArgument()) P.Default = TTP->getDefaultArgument().getAsString(PP); - } else if (const auto NTTP = dyn_cast(Param)) { + } else if (const auto *NTTP = dyn_cast(Param)) { if (IdentifierInfo *II = NTTP->getIdentifier()) P.Name = II->getName().str(); - llvm::raw_string_ostream Out(*P.Type); - NTTP->getType().print(Out, PP); + P.Type = printType(NTTP->getType(), PP); if (NTTP->isParameterPack()) - Out << "..."; + *P.Type += "..."; if (NTTP->hasDefaultArgument()) { P.Default.emplace(); llvm::raw_string_ostream Out(*P.Default); NTTP->getDefaultArgument()->printPretty(Out, nullptr, PP); } - } else if (const auto TTPD = dyn_cast(Param)) { + } else if (const auto *TTPD = dyn_cast(Param)) { + P.Type.emplace(); llvm::raw_string_ostream OS(*P.Type); OS << "template <"; printParams(OS, @@ -190,15 +206,23 @@ const FunctionDecl *getUnderlyingFunction(const Decl *D) { // Returns the decl that should be used for querying comments, either from index // or AST. const NamedDecl *getDeclForComment(const NamedDecl *D) { - if (auto *CTSD = llvm::dyn_cast(D)) - if (!CTSD->isExplicitInstantiationOrSpecialization()) - return CTSD->getTemplateInstantiationPattern(); - if (auto *VTSD = llvm::dyn_cast(D)) - if (!VTSD->isExplicitInstantiationOrSpecialization()) - return VTSD->getTemplateInstantiationPattern(); - if (auto *FD = D->getAsFunction()) - if (FD->isTemplateInstantiation()) - return FD->getTemplateInstantiationPattern(); + if (const auto *TSD = llvm::dyn_cast(D)) { + // Template may not be instantiated e.g. if the type didn't need to be + // complete; fallback to primary template. + if (TSD->getTemplateSpecializationKind() == TSK_Undeclared) + return TSD->getSpecializedTemplate(); + if (const auto *TIP = TSD->getTemplateInstantiationPattern()) + return TIP; + } + if (const auto *TSD = llvm::dyn_cast(D)) { + if (TSD->getTemplateSpecializationKind() == TSK_Undeclared) + return TSD->getSpecializedTemplate(); + if (const auto *TIP = TSD->getTemplateInstantiationPattern()) + return TIP; + } + if (const auto *FD = D->getAsFunction()) + if (const auto *TIP = FD->getTemplateInstantiationPattern()) + return TIP; return D; } @@ -234,7 +258,7 @@ void fillFunctionTypeAndParams(HoverInfo &HI, const Decl *D, HI.Parameters->emplace_back(); auto &P = HI.Parameters->back(); if (!PVD->getType().isNull()) { - P.Type = PVD->getType().getAsString(Policy); + P.Type = printType(PVD->getType(), Policy); } else { std::string Param; llvm::raw_string_ostream OS(Param); @@ -251,20 +275,19 @@ void fillFunctionTypeAndParams(HoverInfo &HI, const Decl *D, } } - if (const auto *CCD = llvm::dyn_cast(FD)) { - // Constructor's "return type" is the class type. - HI.ReturnType = declaredType(CCD->getParent()).getAsString(Policy); - // Don't provide any type for the constructor itself. - } else if (llvm::isa(FD)) { - HI.ReturnType = "void"; - } else { - HI.ReturnType = FD->getReturnType().getAsString(Policy); + // We don't want any type info, if name already contains it. This is true for + // constructors/destructors and conversion operators. + const auto NK = FD->getDeclName().getNameKind(); + if (NK == DeclarationName::CXXConstructorName || + NK == DeclarationName::CXXDestructorName || + NK == DeclarationName::CXXConversionFunctionName) + return; - QualType FunctionType = FD->getType(); - if (const VarDecl *VD = llvm::dyn_cast(D)) // Lambdas - FunctionType = VD->getType().getDesugaredType(D->getASTContext()); - HI.Type = FunctionType.getAsString(Policy); - } + HI.ReturnType = printType(FD->getReturnType(), Policy); + QualType QT = FD->getType(); + if (const VarDecl *VD = llvm::dyn_cast(D)) // Lambdas + QT = VD->getType().getDesugaredType(D->getASTContext()); + HI.Type = printType(QT, Policy); // FIXME: handle variadics. } @@ -335,7 +358,7 @@ HoverInfo getHoverContents(const NamedDecl *D, const SymbolIndex *Index) { fetchTemplateParameters(TD->getTemplateParameters(), Policy); D = TD; } else if (const FunctionDecl *FD = D->getAsFunction()) { - if (const auto FTD = FD->getDescribedTemplate()) { + if (const auto *FTD = FD->getDescribedTemplate()) { HI.TemplateParameters = fetchTemplateParameters(FTD->getTemplateParameters(), Policy); D = FTD; @@ -346,7 +369,7 @@ HoverInfo getHoverContents(const NamedDecl *D, const SymbolIndex *Index) { if (const FunctionDecl *FD = getUnderlyingFunction(D)) fillFunctionTypeAndParams(HI, D, FD, Policy); else if (const auto *VD = dyn_cast(D)) - HI.Type = VD->getType().getAsString(Policy); + HI.Type = printType(VD->getType(), Policy); // Fill in value with evaluated initializer if possible. if (const auto *Var = dyn_cast(D)) { @@ -410,6 +433,51 @@ HoverInfo getHoverContents(const DefinedMacro &Macro, ParsedAST &AST) { } return HI; } + +bool isLiteral(const Expr *E) { + // Unfortunately there's no common base Literal classes inherits from + // (apart from Expr), therefore this is a nasty blacklist. + return llvm::isa(E) || llvm::isa(E) || + llvm::isa(E) || + llvm::isa(E) || + llvm::isa(E) || llvm::isa(E) || + llvm::isa(E) || llvm::isa(E) || + llvm::isa(E) || llvm::isa(E); +} + +llvm::StringLiteral getNameForExpr(const Expr *E) { + // FIXME: Come up with names for `special` expressions. + // + // It's an known issue for GCC5, https://godbolt.org/z/Z_tbgi. Work around + // that by using explicit conversion constructor. + // + // TODO: Once GCC5 is fully retired and not the minimal requirement as stated + // in `GettingStarted`, please remove the explicit conversion constructor. + return llvm::StringLiteral("expression"); +} + +// Generates hover info for evaluatable expressions. +// FIXME: Support hover for literals (esp user-defined) +llvm::Optional getHoverContents(const Expr *E, ParsedAST &AST) { + // There's not much value in hovering over "42" and getting a hover card + // saying "42 is an int", similar for other literals. + if (isLiteral(E)) + return llvm::None; + + HoverInfo HI; + // For expressions we currently print the type and the value, iff it is + // evaluatable. + if (auto Val = printExprValue(E, AST.getASTContext())) { + auto Policy = + printingPolicyForDecls(AST.getASTContext().getPrintingPolicy()); + Policy.SuppressTagKeyword = true; + HI.Type = printType(E->getType(), Policy); + HI.Value = *Val; + HI.Name = getNameForExpr(E); + return HI; + } + return llvm::None; +} } // namespace llvm::Optional getHover(ParsedAST &AST, Position Pos, @@ -439,11 +507,11 @@ llvm::Optional getHover(ParsedAST &AST, Position Pos, // Look for a close enclosing expression to show the value of. if (!HI->Value) HI->Value = printExprValue(N, AST.getASTContext()); + } else if (const Expr *E = N->ASTNode.get()) { + HI = getHoverContents(E, AST); } // FIXME: support hovers for other nodes? - // - certain expressions (sizeof etc) // - built-in types - // - literals (esp user-defined) } } @@ -464,37 +532,46 @@ llvm::Optional getHover(ParsedAST &AST, Position Pos, markup::Document HoverInfo::present() const { markup::Document Output; // Header contains a text of the form: - // variable `var` : `int` + // variable `var` // // class `X` // - // function `foo` → `int` + // function `foo` + // + // expression + // // Note that we are making use of a level-3 heading because VSCode renders // level 1 and 2 headers in a huge font, see // https://github.com/microsoft/vscode/issues/88417 for details. markup::Paragraph &Header = Output.addHeading(3); - Header.appendText(index::getSymbolKindString(Kind)); + if (Kind != index::SymbolKind::Unknown) + Header.appendText(index::getSymbolKindString(Kind)); assert(!Name.empty() && "hover triggered on a nameless symbol"); Header.appendCode(Name); - if (ReturnType) { - Header.appendText("→"); - Header.appendCode(*ReturnType); - } else if (Type) { - Header.appendText(":"); - Header.appendCode(*Type); - } - // For functions we display signature in a list form, e.g.: - // - `bool param1` - // - `int param2 = 5` - if (Parameters && !Parameters->empty()) { - markup::BulletList &L = Output.addBulletList(); - for (const auto &Param : *Parameters) { - std::string Buffer; - llvm::raw_string_ostream OS(Buffer); - OS << Param; - L.addItem().addParagraph().appendCode(std::move(OS.str())); + // Put a linebreak after header to increase readability. + Output.addRuler(); + // Print Types on their own lines to reduce chances of getting line-wrapped by + // editor, as they might be long. + if (ReturnType) { + // For functions we display signature in a list form, e.g.: + // → `x` + // Parameters: + // - `bool param1` + // - `int param2 = 5` + Output.addParagraph().appendText("→").appendCode(*ReturnType); + if (Parameters && !Parameters->empty()) { + Output.addParagraph().appendText("Parameters:"); + markup::BulletList &L = Output.addBulletList(); + for (const auto &Param : *Parameters) { + std::string Buffer; + llvm::raw_string_ostream OS(Buffer); + OS << Param; + L.addItem().addParagraph().appendCode(std::move(OS.str())); + } } + } else if (Type) { + Output.addParagraph().appendText("Type: ").appendCode(*Type); } if (Value) { @@ -507,6 +584,7 @@ markup::Document HoverInfo::present() const { Output.addParagraph().appendText(Documentation); if (!Definition.empty()) { + Output.addRuler(); std::string ScopeComment; // Drop trailing "::". if (!LocalScope.empty()) { diff --git a/clang-tools-extra/clangd/Protocol.cpp b/clang-tools-extra/clangd/Protocol.cpp index 29ceb1da5456e..7aca377cebe2a 100644 --- a/clang-tools-extra/clangd/Protocol.cpp +++ b/clang-tools-extra/clangd/Protocol.cpp @@ -826,6 +826,7 @@ llvm::json::Value toJSON(const CompletionItem &CI) { Result["additionalTextEdits"] = llvm::json::Array(CI.additionalTextEdits); if (CI.deprecated) Result["deprecated"] = CI.deprecated; + Result["score"] = CI.score; return std::move(Result); } diff --git a/clang-tools-extra/clangd/Protocol.h b/clang-tools-extra/clangd/Protocol.h index 1b999f1131d45..3b86935017cde 100644 --- a/clang-tools-extra/clangd/Protocol.h +++ b/clang-tools-extra/clangd/Protocol.h @@ -995,6 +995,13 @@ struct CompletionItem { /// Indicates if this item is deprecated. bool deprecated = false; + /// This is Clangd extension. + /// The score that Clangd calculates to rank completion items. This score can + /// be used to adjust the ranking on the client side. + /// NOTE: This excludes fuzzy matching score which is typically calculated on + /// the client side. + float score = 0.f; + // TODO(krasimir): The following optional fields defined by the language // server protocol are unsupported: // diff --git a/clang-tools-extra/clangd/Shutdown.cpp b/clang-tools-extra/clangd/Shutdown.cpp index dfea46d8dfeb8..36d977570a4fe 100644 --- a/clang-tools-extra/clangd/Shutdown.cpp +++ b/clang-tools-extra/clangd/Shutdown.cpp @@ -9,6 +9,7 @@ #include "Shutdown.h" #include +#include #include namespace clang { diff --git a/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp b/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp index 6d27149ef6d4b..ca3d74b8dcac0 100644 --- a/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp +++ b/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp @@ -16,6 +16,7 @@ #include "SourceCode.h" #include "refactor/Tweak.h" #include "clang/AST/ASTTypeTraits.h" +#include "clang/AST/Attr.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclBase.h" #include "clang/AST/DeclCXX.h" @@ -155,7 +156,7 @@ getFunctionSourceCode(const FunctionDecl *FD, llvm::StringRef TargetNamespace, "define outline: couldn't find a context for target"); llvm::Error Errors = llvm::Error::success(); - tooling::Replacements QualifierInsertions; + tooling::Replacements DeclarationCleanups; // Finds the first unqualified name in function return type and name, then // qualifies those to be valid in TargetContext. @@ -180,7 +181,7 @@ getFunctionSourceCode(const FunctionDecl *FD, llvm::StringRef TargetNamespace, const NamedDecl *ND = Ref.Targets.front(); const std::string Qualifier = getQualification( AST, *TargetContext, SM.getLocForStartOfFile(SM.getMainFileID()), ND); - if (auto Err = QualifierInsertions.add( + if (auto Err = DeclarationCleanups.add( tooling::Replacement(SM, Ref.NameLoc, 0, Qualifier))) Errors = llvm::joinErrors(std::move(Errors), std::move(Err)); }); @@ -205,14 +206,72 @@ getFunctionSourceCode(const FunctionDecl *FD, llvm::StringRef TargetNamespace, assert(Tok != Tokens.rend()); DelRange.setBegin(Tok->location()); if (auto Err = - QualifierInsertions.add(tooling::Replacement(SM, DelRange, ""))) + DeclarationCleanups.add(tooling::Replacement(SM, DelRange, ""))) Errors = llvm::joinErrors(std::move(Errors), std::move(Err)); } } + auto DelAttr = [&](const Attr *A) { + if (!A) + return; + auto AttrTokens = + TokBuf.spelledForExpanded(TokBuf.expandedTokens(A->getRange())); + assert(A->getLocation().isValid()); + if (!AttrTokens || AttrTokens->empty()) { + Errors = llvm::joinErrors( + std::move(Errors), + llvm::createStringError( + llvm::inconvertibleErrorCode(), + llvm::StringRef("define outline: Can't move out of line as " + "function has a macro `") + + A->getSpelling() + "` specifier.")); + return; + } + CharSourceRange DelRange = + syntax::Token::range(SM, AttrTokens->front(), AttrTokens->back()) + .toCharRange(SM); + if (auto Err = + DeclarationCleanups.add(tooling::Replacement(SM, DelRange, ""))) + Errors = llvm::joinErrors(std::move(Errors), std::move(Err)); + }; + + DelAttr(FD->getAttr()); + DelAttr(FD->getAttr()); + + if (FD->isVirtualAsWritten()) { + SourceRange SpecRange{FD->getBeginLoc(), FD->getLocation()}; + bool HasErrors = true; + + // Clang allows duplicating virtual specifiers so check for multiple + // occurances. + for (const auto &Tok : TokBuf.expandedTokens(SpecRange)) { + if (Tok.kind() != tok::kw_virtual) + continue; + auto Spelling = TokBuf.spelledForExpanded(llvm::makeArrayRef(Tok)); + if (!Spelling) { + HasErrors = true; + break; + } + HasErrors = false; + CharSourceRange DelRange = + syntax::Token::range(SM, Spelling->front(), Spelling->back()) + .toCharRange(SM); + if (auto Err = + DeclarationCleanups.add(tooling::Replacement(SM, DelRange, ""))) + Errors = llvm::joinErrors(std::move(Errors), std::move(Err)); + } + if (HasErrors) { + Errors = llvm::joinErrors( + std::move(Errors), + llvm::createStringError(llvm::inconvertibleErrorCode(), + "define outline: Can't move out of line as " + "function has a macro `virtual` specifier.")); + } + } + if (Errors) return std::move(Errors); - return getFunctionSourceAfterReplacements(FD, QualifierInsertions); + return getFunctionSourceAfterReplacements(FD, DeclarationCleanups); } struct InsertionPoint { diff --git a/clang-tools-extra/clangd/test/completion-auto-trigger.test b/clang-tools-extra/clangd/test/completion-auto-trigger.test index 46871b9d3e34c..cf7261e904330 100644 --- a/clang-tools-extra/clangd/test/completion-auto-trigger.test +++ b/clang-tools-extra/clangd/test/completion-auto-trigger.test @@ -24,6 +24,7 @@ # CHECK-NEXT: "insertTextFormat": 1, # CHECK-NEXT: "kind": 5, # CHECK-NEXT: "label": " size", +# CHECK-NEXT: "score": {{[0-9]+.[0-9]+}}, # CHECK-NEXT: "sortText": "{{.*}}size", # CHECK-NEXT: "textEdit": { # CHECK-NEXT: "newText": "size", @@ -46,6 +47,7 @@ # CHECK-NEXT: "insertTextFormat": 1, # CHECK-NEXT: "kind": 10, # CHECK-NEXT: "label": " default_capacity", +# CHECK-NEXT: "score": {{[0-9]+.[0-9]+}}, # CHECK-NEXT: "sortText": "{{.*}}default_capacity", # CHECK-NEXT: "textEdit": { # CHECK-NEXT: "newText": "default_capacity", @@ -86,6 +88,7 @@ # CHECK-NEXT: "insertTextFormat": 1, # CHECK-NEXT: "kind": 6, # CHECK-NEXT: "label": " ns_member", +# CHECK-NEXT: "score": {{[0-9]+.[0-9]+}}, # CHECK-NEXT: "sortText": "{{.*}}ns_member", # CHECK-NEXT: "textEdit": { # CHECK-NEXT: "newText": "ns_member", diff --git a/clang-tools-extra/clangd/test/completion-snippets.test b/clang-tools-extra/clangd/test/completion-snippets.test index 22cd0821b2241..7dc980943859b 100644 --- a/clang-tools-extra/clangd/test/completion-snippets.test +++ b/clang-tools-extra/clangd/test/completion-snippets.test @@ -33,6 +33,7 @@ # CHECK-NEXT: "insertTextFormat": 2, # CHECK-NEXT: "kind": 3, # CHECK-NEXT: "label": " func_with_args(int a, int b)", +# CHECK-NEXT: "score": {{[0-9]+.[0-9]+}}, # CHECK-NEXT: "sortText": "{{.*}}func_with_args" # CHECK-NEXT: "textEdit": { # CHECK-NEXT: "newText": "func_with_args(${1:int a}, ${2:int b})", diff --git a/clang-tools-extra/clangd/test/completion.test b/clang-tools-extra/clangd/test/completion.test index 0094d4740b259..d6376b3bfe51b 100644 --- a/clang-tools-extra/clangd/test/completion.test +++ b/clang-tools-extra/clangd/test/completion.test @@ -17,6 +17,7 @@ # CHECK-NEXT: "insertTextFormat": 1, # CHECK-NEXT: "kind": 5, # CHECK-NEXT: "label": " a", +# CHECK-NEXT: "score": {{[0-9]+.[0-9]+}}, # CHECK-NEXT: "sortText": "{{.*}}a" # CHECK-NEXT: "textEdit": { # CHECK-NEXT: "newText": "a", @@ -50,6 +51,7 @@ # CHECK-NEXT: "insertTextFormat": 1, # CHECK-NEXT: "kind": 5, # CHECK-NEXT: "label": " b", +# CHECK-NEXT: "score": {{[0-9]+.[0-9]+}}, # CHECK-NEXT: "sortText": "{{.*}}b" # CHECK-NEXT: "textEdit": { # CHECK-NEXT: "newText": "b", diff --git a/clang-tools-extra/clangd/test/hover.test b/clang-tools-extra/clangd/test/hover.test index 2162ff9abcdc3..ec8d0488fa5ed 100644 --- a/clang-tools-extra/clangd/test/hover.test +++ b/clang-tools-extra/clangd/test/hover.test @@ -9,7 +9,7 @@ # CHECK-NEXT: "result": { # CHECK-NEXT: "contents": { # CHECK-NEXT: "kind": "plaintext", -# CHECK-NEXT: "value": "function foo → void\n\nvoid foo()" +# CHECK-NEXT: "value": "function foo\n\n→ void\n\nvoid foo()" # CHECK-NEXT: }, # CHECK-NEXT: "range": { # CHECK-NEXT: "end": { diff --git a/clang-tools-extra/clangd/test/protocol.test b/clang-tools-extra/clangd/test/protocol.test index 3e16c9ec9b334..5e852d1d9deeb 100644 --- a/clang-tools-extra/clangd/test/protocol.test +++ b/clang-tools-extra/clangd/test/protocol.test @@ -39,6 +39,7 @@ Content-Length: 146 # CHECK-NEXT: "insertTextFormat": 1, # CHECK-NEXT: "kind": 5, # CHECK-NEXT: "label": " a", +# CHECK-NEXT: "score": {{[0-9]+.[0-9]+}}, # CHECK-NEXT: "sortText": "{{.*}}" # CHECK: ] # CHECK-NEXT: } @@ -68,6 +69,7 @@ Content-Length: 146 # CHECK-NEXT: "insertTextFormat": 1, # CHECK-NEXT: "kind": 5, # CHECK-NEXT: "label": " a", +# CHECK-NEXT: "score": {{[0-9]+.[0-9]+}}, # CHECK-NEXT: "sortText": "{{.*}}" # CHECK: ] # CHECK-NEXT: } @@ -97,6 +99,7 @@ Content-Length: 146 # CHECK-NEXT: "insertTextFormat": 1, # CHECK-NEXT: "kind": 5, # CHECK-NEXT: "label": " a", +# CHECK-NEXT: "score": {{[0-9]+.[0-9]+}}, # CHECK-NEXT: "sortText": "{{.*}}" # CHECK: ] # CHECK-NEXT: } diff --git a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp index 8017fc98b8ef1..3e9b97dc3b3ca 100644 --- a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp +++ b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp @@ -1643,6 +1643,7 @@ TEST(CompletionTest, Render) { Include.Header = "\"foo.h\""; C.Kind = CompletionItemKind::Method; C.Score.Total = 1.0; + C.Score.ExcludingName = .5; C.Origin = SymbolOrigin::AST | SymbolOrigin::Static; CodeCompleteOptions Opts; @@ -1660,6 +1661,7 @@ TEST(CompletionTest, Render) { EXPECT_THAT(R.additionalTextEdits, IsEmpty()); EXPECT_EQ(R.sortText, sortText(1.0, "x")); EXPECT_FALSE(R.deprecated); + EXPECT_EQ(R.score, .5f); Opts.EnableSnippets = true; R = C.render(Opts); diff --git a/clang-tools-extra/clangd/unittests/FormattedStringTests.cpp b/clang-tools-extra/clangd/unittests/FormattedStringTests.cpp index 0a85a4cb27d92..6489aa05f8440 100644 --- a/clang-tools-extra/clangd/unittests/FormattedStringTests.cpp +++ b/clang-tools-extra/clangd/unittests/FormattedStringTests.cpp @@ -136,13 +136,37 @@ bar)pt"; EXPECT_EQ(D.asPlainText(), ExpectedText); } -TEST(Document, Spacer) { +TEST(Document, Ruler) { Document D; D.addParagraph().appendText("foo"); - D.addSpacer(); + D.addRuler(); + + // Ruler followed by paragraph. D.addParagraph().appendText("bar"); - EXPECT_EQ(D.asMarkdown(), "foo \n\nbar"); + EXPECT_EQ(D.asMarkdown(), "foo \n\n---\nbar"); + EXPECT_EQ(D.asPlainText(), "foo\n\nbar"); + + D = Document(); + D.addParagraph().appendText("foo"); + D.addRuler(); + D.addCodeBlock("bar"); + // Ruler followed by a codeblock. + EXPECT_EQ(D.asMarkdown(), "foo \n\n---\n```cpp\nbar\n```"); EXPECT_EQ(D.asPlainText(), "foo\n\nbar"); + + // Ruler followed by another ruler + D = Document(); + D.addParagraph().appendText("foo"); + D.addRuler(); + D.addRuler(); + EXPECT_EQ(D.asMarkdown(), "foo"); + EXPECT_EQ(D.asPlainText(), "foo"); + + // Multiple rulers between blocks + D.addRuler(); + D.addParagraph().appendText("foo"); + EXPECT_EQ(D.asMarkdown(), "foo \n\n---\nfoo"); + EXPECT_EQ(D.asPlainText(), "foo\n\nfoo"); } TEST(Document, Heading) { @@ -182,15 +206,11 @@ foo foo ```)md"; EXPECT_EQ(D.asMarkdown(), ExpectedMarkdown); - // FIXME: we shouldn't have 2 empty lines in between. A solution might be - // having a `verticalMargin` method for blocks, and let container insert new - // lines according to that before/after blocks. ExpectedPlainText = R"pt(foo bar baz - foo)pt"; EXPECT_EQ(D.asPlainText(), ExpectedPlainText); } diff --git a/clang-tools-extra/clangd/unittests/HoverTests.cpp b/clang-tools-extra/clangd/unittests/HoverTests.cpp index 866ff975429f9..bdac5be0ac35e 100644 --- a/clang-tools-extra/clangd/unittests/HoverTests.cpp +++ b/clang-tools-extra/clangd/unittests/HoverTests.cpp @@ -327,7 +327,6 @@ class Foo {})cpp"; HI.Name = "X"; HI.LocalScope = "X::"; // FIXME: X:: HI.Kind = index::SymbolKind::Constructor; - HI.ReturnType = "X"; HI.Definition = "X()"; HI.Parameters.emplace(); }}, @@ -337,10 +336,18 @@ class Foo {})cpp"; HI.Name = "~X"; HI.LocalScope = "X::"; HI.Kind = index::SymbolKind::Destructor; - HI.ReturnType = "void"; HI.Definition = "~X()"; HI.Parameters.emplace(); }}, + {"class X { operator [[in^t]](); };", + [](HoverInfo &HI) { + HI.NamespaceScope = ""; + HI.Name = "operator int"; + HI.LocalScope = "X::"; + HI.Kind = index::SymbolKind::ConversionFunction; + HI.Definition = "operator int()"; + HI.Parameters.emplace(); + }}, // auto on lambda {R"cpp( @@ -547,6 +554,25 @@ class Foo {})cpp"; HI.Name = "Foo"; HI.Kind = index::SymbolKind::Class; }}, + {// Falls back to primary template, when the type is not instantiated. + R"cpp( + // comment from primary + template class Foo {}; + // comment from specialization + template class Foo {}; + void foo() { + [[Fo^o]] *x = nullptr; + } + )cpp", + [](HoverInfo &HI) { + HI.Name = "Foo"; + HI.Kind = index::SymbolKind::Class; + HI.NamespaceScope = ""; + HI.Definition = "template <> class Foo"; + // FIXME: Maybe force instantiation to make use of real template + // pattern. + HI.Documentation = "comment from primary"; + }}, }; for (const auto &Case : Cases) { SCOPED_TRACE(Case.Code); @@ -554,7 +580,12 @@ class Foo {})cpp"; Annotations T(Case.Code); TestTU TU = TestTU::withCode(T.code()); TU.ExtraArgs.push_back("-std=c++17"); + // FIXME: This is no longer necessary, as the default behavior is no delayed + // parsing in the triplet below. TU.ExtraArgs.push_back("-fno-delayed-template-parsing"); + // Types might be different depending on the target triplet, we chose a + // fixed one to make sure tests passes on different platform. + TU.ExtraArgs.push_back("--target=x86_64-pc-linux-gnu"); auto AST = TU.build(); ASSERT_TRUE(AST.getDiagnostics().empty()); @@ -601,6 +632,19 @@ TEST(Hover, NoHover) { R"cpp(// non-named decls don't get hover. Don't crash! ^static_assert(1, ""); )cpp", + R"cpp(// non-evaluatable expr + template void foo() { + (void)[[size^of]](T); + })cpp", + // literals + "auto x = t^rue;", + "auto x = '^A';", + "auto x = ^(int){42};", + "auto x = ^42.;", + "auto x = ^42.0i;", + "auto x = ^42;", + "auto x = ^nullptr;", + "auto x = ^\"asdf\";", }; for (const auto &Test : Tests) { @@ -1501,6 +1545,76 @@ TEST(Hover, All) { HI.Name = "cls > >"; HI.Documentation = "type of nested templates."; }}, + { + R"cpp(// type with decltype + int a; + decltype(a) [[b^]] = a;)cpp", + [](HoverInfo &HI) { + HI.Definition = "decltype(a) b = a"; + HI.Kind = index::SymbolKind::Variable; + HI.NamespaceScope = ""; + HI.Name = "b"; + HI.Type = "int"; + }}, + { + R"cpp(// type with decltype + int a; + decltype(a) c; + decltype(c) [[b^]] = a;)cpp", + [](HoverInfo &HI) { + HI.Definition = "decltype(c) b = a"; + HI.Kind = index::SymbolKind::Variable; + HI.NamespaceScope = ""; + HI.Name = "b"; + HI.Type = "int"; + }}, + { + R"cpp(// type with decltype + int a; + const decltype(a) [[b^]] = a;)cpp", + [](HoverInfo &HI) { + HI.Definition = "const decltype(a) b = a"; + HI.Kind = index::SymbolKind::Variable; + HI.NamespaceScope = ""; + HI.Name = "b"; + HI.Type = "int"; + }}, + { + R"cpp(// type with decltype + int a; + auto [[f^oo]](decltype(a) x) -> decltype(a) { return 0; })cpp", + [](HoverInfo &HI) { + HI.Definition = "auto foo(decltype(a) x) -> decltype(a)"; + HI.Kind = index::SymbolKind::Function; + HI.NamespaceScope = ""; + HI.Name = "foo"; + // FIXME: Handle composite types with decltype with a printing + // policy. + HI.Type = "auto (decltype(a)) -> decltype(a)"; + HI.ReturnType = "int"; + HI.Parameters = { + {std::string("int"), std::string("x"), llvm::None}}; + }}, + { + R"cpp(// sizeof expr + void foo() { + (void)[[size^of]](char); + })cpp", + [](HoverInfo &HI) { + HI.Name = "expression"; + HI.Type = "unsigned long"; + HI.Value = "1"; + }}, + { + R"cpp(// alignof expr + void foo() { + (void)[[align^of]](char); + })cpp", + [](HoverInfo &HI) { + HI.Name = "expression"; + HI.Type = "unsigned long"; + HI.Value = "1"; + }}, }; // Create a tiny index, so tests above can verify documentation is fetched. @@ -1518,6 +1632,9 @@ TEST(Hover, All) { TestTU TU = TestTU::withCode(T.code()); TU.ExtraArgs.push_back("-std=c++17"); TU.ExtraArgs.push_back("-Wno-gnu-designator"); + // Types might be different depending on the target triplet, we chose a + // fixed one to make sure tests passes on different platform. + TU.ExtraArgs.push_back("--target=x86_64-pc-linux-gnu"); auto AST = TU.build(); for (const auto &D : AST.getDiagnostics()) ADD_FAILURE() << D; @@ -1529,6 +1646,7 @@ TEST(Hover, All) { Expected.SymRange = T.range(); Case.ExpectedBuilder(Expected); + SCOPED_TRACE(H->present().asPlainText()); EXPECT_EQ(H->NamespaceScope, Expected.NamespaceScope); EXPECT_EQ(H->LocalScope, Expected.LocalScope); EXPECT_EQ(H->Name, Expected.Name); @@ -1642,7 +1760,7 @@ TEST(Hover, Present) { HI.Kind = index::SymbolKind::Unknown; HI.Name = "X"; }, - R"( X)", + R"(X)", }, { [](HoverInfo &HI) { @@ -1666,6 +1784,7 @@ TEST(Hover, Present) { HI.NamespaceScope.emplace(); }, R"(class foo + documentation template class Foo {})", @@ -1688,7 +1807,10 @@ template class Foo {})", HI.NamespaceScope = "ns::"; HI.Definition = "ret_type foo(params) {}"; }, - R"(function foo → ret_type + R"(function foo + +→ ret_type +Parameters: - - type - type foo @@ -1706,7 +1828,9 @@ ret_type foo(params) {})", HI.Type = "type"; HI.Definition = "def"; }, - R"(variable foo : type + R"(variable foo + +Type: type Value = value // In test::bar @@ -1727,11 +1851,37 @@ TEST(Hover, PresentHeadings) { HoverInfo HI; HI.Kind = index::SymbolKind::Variable; HI.Name = "foo"; - HI.Type = "type"; - EXPECT_EQ(HI.present().asMarkdown(), "### variable `foo` \\: `type`"); + EXPECT_EQ(HI.present().asMarkdown(), "### variable `foo`"); } +// This is a separate test as rulers behave differently in markdown vs +// plaintext. +TEST(Hover, PresentRulers) { + HoverInfo HI; + HI.Kind = index::SymbolKind::Variable; + HI.Name = "foo"; + HI.Value = "val"; + HI.Definition = "def"; + + llvm::StringRef ExpectedMarkdown = R"md(### variable `foo` + +--- +Value \= `val` + +--- +```cpp +def +```)md"; + EXPECT_EQ(HI.present().asMarkdown(), ExpectedMarkdown); + + llvm::StringRef ExpectedPlaintext = R"pt(variable foo + +Value = val + +def)pt"; + EXPECT_EQ(HI.present().asPlainText(), ExpectedPlaintext); +} } // namespace } // namespace clangd } // namespace clang diff --git a/clang-tools-extra/clangd/unittests/TweakTests.cpp b/clang-tools-extra/clangd/unittests/TweakTests.cpp index 38f958c961737..adbdbe71761da 100644 --- a/clang-tools-extra/clangd/unittests/TweakTests.cpp +++ b/clang-tools-extra/clangd/unittests/TweakTests.cpp @@ -2065,6 +2065,80 @@ TEST_F(DefineOutlineTest, ApplyTest) { };)cpp", "Foo::Foo(int z) __attribute__((weak)) : bar(2){}\n", }, + // Virt specifiers. + { + R"cpp( + struct A { + virtual void f^oo() {} + };)cpp", + R"cpp( + struct A { + virtual void foo() ; + };)cpp", + " void A::foo() {}\n", + }, + { + R"cpp( + struct A { + virtual virtual void virtual f^oo() {} + };)cpp", + R"cpp( + struct A { + virtual virtual void virtual foo() ; + };)cpp", + " void A::foo() {}\n", + }, + { + R"cpp( + struct A { + virtual void foo() = 0; + }; + struct B : A { + void fo^o() override {} + };)cpp", + R"cpp( + struct A { + virtual void foo() = 0; + }; + struct B : A { + void foo() override ; + };)cpp", + "void B::foo() {}\n", + }, + { + R"cpp( + struct A { + virtual void foo() = 0; + }; + struct B : A { + void fo^o() final {} + };)cpp", + R"cpp( + struct A { + virtual void foo() = 0; + }; + struct B : A { + void foo() final ; + };)cpp", + "void B::foo() {}\n", + }, + { + R"cpp( + struct A { + virtual void foo() = 0; + }; + struct B : A { + void fo^o() final override {} + };)cpp", + R"cpp( + struct A { + virtual void foo() = 0; + }; + struct B : A { + void foo() final override ; + };)cpp", + "void B::foo() {}\n", + }, }; for (const auto &Case : Cases) { SCOPED_TRACE(Case.Test); @@ -2078,6 +2152,8 @@ TEST_F(DefineOutlineTest, HandleMacros) { llvm::StringMap EditedFiles; ExtraFiles["Test.cpp"] = ""; FileName = "Test.hpp"; + ExtraArgs.push_back("-DVIRTUAL=virtual"); + ExtraArgs.push_back("-DOVER=override"); struct { llvm::StringRef Test; @@ -2115,6 +2191,48 @@ TEST_F(DefineOutlineTest, HandleMacros) { #define TARGET foo void TARGET();)cpp", "void TARGET(){ return; }"}, + {R"cpp(#define VIRT virtual + struct A { + VIRT void f^oo() {} + };)cpp", + R"cpp(#define VIRT virtual + struct A { + VIRT void foo() ; + };)cpp", + " void A::foo() {}\n"}, + {R"cpp( + struct A { + VIRTUAL void f^oo() {} + };)cpp", + R"cpp( + struct A { + VIRTUAL void foo() ; + };)cpp", + " void A::foo() {}\n"}, + {R"cpp( + struct A { + virtual void foo() = 0; + }; + struct B : A { + void fo^o() OVER {} + };)cpp", + R"cpp( + struct A { + virtual void foo() = 0; + }; + struct B : A { + void foo() OVER ; + };)cpp", + "void B::foo() {}\n"}, + {R"cpp(#define STUPID_MACRO(X) virtual + struct A { + STUPID_MACRO(sizeof sizeof int) void f^oo() {} + };)cpp", + R"cpp(#define STUPID_MACRO(X) virtual + struct A { + STUPID_MACRO(sizeof sizeof int) void foo() ; + };)cpp", + " void A::foo() {}\n"}, }; for (const auto &Case : Cases) { SCOPED_TRACE(Case.Test); @@ -2226,6 +2344,49 @@ TEST_F(DefineOutlineTest, QualifyFunctionName) { << Case.TestHeader; } } + +TEST_F(DefineOutlineTest, FailsMacroSpecifier) { + FileName = "Test.hpp"; + ExtraFiles["Test.cpp"] = ""; + ExtraArgs.push_back("-DFINALOVER=final override"); + + std::pair Cases[] = { + { + R"cpp( + #define VIRT virtual void + struct A { + VIRT fo^o() {} + };)cpp", + "fail: define outline: Can't move out of line as function has a " + "macro `virtual` specifier."}, + { + R"cpp( + #define OVERFINAL final override + struct A { + virtual void foo() {} + }; + struct B : A { + void fo^o() OVERFINAL {} + };)cpp", + "fail: define outline: Can't move out of line as function has a " + "macro `override` specifier.\ndefine outline: Can't move out of line " + "as function has a macro `final` specifier."}, + { + R"cpp( + struct A { + virtual void foo() {} + }; + struct B : A { + void fo^o() FINALOVER {} + };)cpp", + "fail: define outline: Can't move out of line as function has a " + "macro `override` specifier.\ndefine outline: Can't move out of line " + "as function has a macro `final` specifier."}, + }; + for (const auto &Case : Cases) { + EXPECT_EQ(apply(Case.first), Case.second); + } +} } // namespace } // namespace clangd } // namespace clang diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 52e98cb23f50f..fbd55e36d6fd5 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -1,6 +1,6 @@ -==================================================== -Extra Clang Tools 10.0.0 (In-Progress) Release Notes -==================================================== +====================================== +Extra Clang Tools 10.0.0 Release Notes +====================================== .. contents:: :local: @@ -8,12 +8,6 @@ Extra Clang Tools 10.0.0 (In-Progress) Release Notes Written by the `LLVM Team `_ -.. warning:: - - These are in-progress notes for the upcoming Extra Clang Tools 10 release. - Release notes for previous releases can be found on - `the Download Page `_. - Introduction ============ @@ -27,11 +21,6 @@ For more information about Clang or LLVM, including information about the latest release, please see the `Clang Web Site `_ or the `LLVM Web Site `_. -Note that if you are reading this file from a Subversion checkout or the -main Clang web page, this document applies to the *next* release, not -the current one. To see the release notes for a specific release, please -see the `releases page `_. - What's New in Extra Clang Tools 10.0.0? ======================================= @@ -39,30 +28,61 @@ Some of the major new features and improvements to Extra Clang Tools are listed here. Generic improvements to Extra Clang Tools as a whole or to its underlying infrastructure are described first, followed by tool-specific sections. -Major New Features ------------------- - -... Improvements to clangd ---------------------- -The improvements are... +- clangd documentation is now found at https://clangd.llvm.org/ -Improvements to clang-doc -------------------------- +- Go-to-definition, hover, find-references etc use a new mechanism to identify + what is under the cursor, which is (hopefully) more consistent and accurate. -- :doc:`clang-doc ` now generates documentation in HTML format. +- clangd should be able to reliably locate the standard library/SDK on macOS. + +- Shutdown more cleanly on receiving a signal. In particular temporary PCH files + should be cleaned up. + +- Find references now works on macros. + +- clangd can be more easily used remotely or in a docker container. + + The ``--path-mappings`` flag translates between local and remote paths. + +- Experimental support for renaming across files (behind the + ``--cross-file-rename`` flag). + +- Hover now exposes more information, including the type of symbols and the + value of constant expressions. + +- Go to definition now works in dependent code in more cases, by assuming the + primary template is used. + +- Better recovery and reporting when the compile command for a file can't be + fully parsed. + +- Switch header/source (an extension) now uses index information in addition + to filename heuristics, and is much more robust. -Improvements to clang-query ---------------------------- +- Semantic selection (expand/contract selection) is supported. -The improvements are... +- Semantic highlighting is more robust, highlights more types of tokens, and + as an extension provides information about inactive preprocessor regions. -Improvements to clang-rename ----------------------------- +- Code completion results now include an extension field ``score``. -The improvements are... + This allows clients to incorporate clangd quality signals when re-ranking code + completion after client-side fuzzy-matching. + +- New refactorings: + define function out-of-line, define function in-line, extract function, + remove using namespace directive, localize Objective-C string. + +- Bug fixes and performance improvements :-) + +Improvements to clang-doc +------------------------- + +- :doc:`clang-doc ` now generates documentation in HTML format. Improvements to clang-tidy -------------------------- @@ -73,7 +93,7 @@ New checks - New :doc:`bugprone-bad-signal-to-kill-thread ` check. - Finds ``pthread_kill`` function calls when a thread is terminated by + Finds ``pthread_kill`` function calls when a thread is terminated by raising ``SIGTERM`` signal. - New :doc:`bugprone-dynamic-static-initializers @@ -168,7 +188,7 @@ New checks - New :doc:`readability-qualified-auto ` check. - Adds pointer and ``const`` qualifications to ``auto``-typed variables + Adds pointer and ``const`` qualifications to ``auto``-typed variables that are deduced to pointers and ``const`` pointers. - New :doc:`readability-redundant-access-specifiers @@ -253,25 +273,6 @@ Renamed checks - The 'objc-avoid-spinlock' check was renamed to :doc:`darwin-avoid-spinlock ` -Improvements to include-fixer ------------------------------ - -The improvements are... - -Improvements to clang-include-fixer ------------------------------------ - -The improvements are... - -Improvements to modularize --------------------------- - -The improvements are... - -Improvements to pp-trace ------------------------- - -The improvements are... Clang-tidy visual studio plugin ------------------------------- diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone-branch-clone-if-constexpr-template.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone-branch-clone-if-constexpr-template.cpp new file mode 100644 index 0000000000000..382330139c8c5 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone-branch-clone-if-constexpr-template.cpp @@ -0,0 +1,58 @@ +// RUN: %check_clang_tidy %s bugprone-branch-clone %t -- -- -std=c++17 + +void handle(int); + +template +void shouldFail() { + if constexpr (Index == 0) { + // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: repeated branch in conditional chain [bugprone-branch-clone] + handle(0); + } else if constexpr (Index == 1) { + handle(1); + } else { + handle(0); + } +} + +template +void shouldPass() { + if constexpr (Index == 0) { + handle(0); + } else if constexpr (Index == 1) { + handle(1); + } else { + handle(2); + } +} + +void shouldFailNonTemplate() { + constexpr unsigned Index = 1; + if constexpr (Index == 0) { + // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: repeated branch in conditional chain [bugprone-branch-clone] + handle(0); + } else if constexpr (Index == 1) { + handle(1); + } else { + handle(0); + } +} + +void shouldPassNonTemplate() { + constexpr unsigned Index = 1; + if constexpr (Index == 0) { + handle(0); + } else if constexpr (Index == 1) { + handle(1); + } else { + handle(2); + } +} + +void run() { + shouldFail<0>(); + shouldFail<1>(); + shouldFail<2>(); + shouldPass<0>(); + shouldPass<1>(); + shouldPass<2>(); +} diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone-infinite-loop.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone-infinite-loop.cpp index 33d94820b0f69..427b5f0272b94 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/bugprone-infinite-loop.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone-infinite-loop.cpp @@ -4,10 +4,20 @@ void simple_infinite_loop1() { int i = 0; int j = 0; while (i < 10) { - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (i) are updated in the loop body [bugprone-infinite-loop] + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (i) are updated in the loop body [bugprone-infinite-loop] j++; } + while (int k = 10) { + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; it does not check any variables in the condition [bugprone-infinite-loop] + j--; + } + + while (int k = 10) { + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; it does not check any variables in the condition [bugprone-infinite-loop] + k--; + } + do { // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (i) are updated in the loop body [bugprone-infinite-loop] j++; @@ -27,6 +37,16 @@ void simple_infinite_loop2() { j++; } + while (int k = Limit) { + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (Limit) are updated in the loop body [bugprone-infinite-loop] + j--; + } + + while (int k = Limit) { + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (Limit) are updated in the loop body [bugprone-infinite-loop] + k--; + } + do { // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (i, Limit) are updated in the loop body [bugprone-infinite-loop] j++; @@ -44,6 +64,22 @@ void simple_not_infinite1() { // Not an error since 'Limit' is updated. Limit--; } + + while (Limit--) { + // Not an error since 'Limit' is updated. + i++; + } + + while (int k = Limit) { + // Not an error since 'Limit' is updated. + Limit--; + } + + while (int k = Limit--) { + // Not an error since 'Limit' is updated. + i++; + } + do { Limit--; } while (i < Limit); @@ -318,3 +354,12 @@ void lambda_capture() { (*p)++; } while (i < Limit); } + +void evaluatable(bool CondVar) { + for (; false && CondVar;) { + } + while (false && CondVar) { + } + do { + } while (false && CondVar); +} diff --git a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-init-variables.cpp b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-init-variables.cpp index d43e44808a49a..4c92e1976f917 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-init-variables.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-init-variables.cpp @@ -78,3 +78,9 @@ void init_unit_tests() { int parens(42); int braces{42}; } + +template +void f(RANGE r) { + for (char c : r) { + } +} diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability-braces-around-statements-constexpr-if-templates.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability-braces-around-statements-constexpr-if-templates.cpp new file mode 100644 index 0000000000000..988125f9ce2d7 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/readability-braces-around-statements-constexpr-if-templates.cpp @@ -0,0 +1,48 @@ +// RUN: %check_clang_tidy %s readability-braces-around-statements %t -- -- -std=c++17 + +void handle(bool); + +template +void shouldFail() { + if constexpr (branch) + // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: statement should be inside braces [readability-braces-around-statements] + handle(true); + else + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: statement should be inside braces [readability-braces-around-statements] + handle(false); +} + +template +void shouldPass() { + if constexpr (branch) { + handle(true); + } else { + handle(false); + } +} + +void shouldFailNonTemplate() { + constexpr bool branch = false; + if constexpr (branch) + // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: statement should be inside braces [readability-braces-around-statements] + handle(true); + else + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: statement should be inside braces [readability-braces-around-statements] + handle(false); +} + +void shouldPass() { + constexpr bool branch = false; + if constexpr (branch) { + handle(true); + } else { + handle(false); + } +} + +void run() { + shouldFail(); + shouldFail(); + shouldPass(); + shouldPass(); +} diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability-else-after-return.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability-else-after-return.cpp index 69ac9eb295713..1e3b4cf5755aa 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/readability-else-after-return.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/readability-else-after-return.cpp @@ -213,3 +213,16 @@ int lifeTimeExtensionTests(int a) { return b; } } + +void test_B44745() { + // This is the actual minimum test case for the crash in bug 44745. We aren't + // too worried about the warning or fix here, more we don't want a crash. + // CHECK-MESSAGES: :[[@LINE+3]]:5: warning: do not use 'else' after 'return' [readability-else-after-return] + if (auto X = false) { + return; + } else { + for (;;) { + } + } + return; +} diff --git a/clang/docs/AttributeReference.rst b/clang/docs/AttributeReference.rst index a763ddeaeb106..273bbb1f90c08 100644 --- a/clang/docs/AttributeReference.rst +++ b/clang/docs/AttributeReference.rst @@ -1,13 +1,6187 @@ .. ------------------------------------------------------------------- NOTE: This file is automatically generated by running clang-tblgen - -gen-attr-docs. Do not edit this file by hand!! The contents for - this file are automatically generated by a server-side process. - - Please do not commit this file. The file exists for local testing - purposes only. + -gen-attr-docs. Do not edit this file by hand!! ------------------------------------------------------------------- =================== Attributes in Clang -=================== \ No newline at end of file +=================== +.. contents:: + :local: + +.. |br| raw:: html + +
+ +Introduction +============ + +This page lists the attributes currently supported by Clang. + +Function Attributes +=================== + + +#pragma omp declare simd +------------------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "","","","","","``omp declare simd``","" + +The `declare simd` construct can be applied to a function to enable the creation +of one or more versions that can process multiple arguments using SIMD +instructions from a single invocation in a SIMD loop. The `declare simd` +directive is a declarative directive. There may be multiple `declare simd` +directives for a function. The use of a `declare simd` construct on a function +enables the creation of SIMD versions of the associated function that can be +used to process multiple arguments from a single invocation from a SIMD loop +concurrently. +The syntax of the `declare simd` construct is as follows: + + .. code-block:: none + + #pragma omp declare simd [clause[[,] clause] ...] new-line + [#pragma omp declare simd [clause[[,] clause] ...] new-line] + [...] + function definition or declaration + +where clause is one of the following: + + .. code-block:: none + + simdlen(length) + linear(argument-list[:constant-linear-step]) + aligned(argument-list[:alignment]) + uniform(argument-list) + inbranch + notinbranch + + +#pragma omp declare target +-------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "","","","","","``omp declare target``","" + +The `declare target` directive specifies that variables and functions are mapped +to a device for OpenMP offload mechanism. + +The syntax of the declare target directive is as follows: + + .. code-block:: c + + #pragma omp declare target new-line + declarations-definition-seq + #pragma omp end declare target new-line + +or + + .. code-block:: c + + #pragma omp declare target (extended-list) new-line + +or + + .. code-block:: c + + #pragma omp declare target clause[ [,] clause ... ] new-line + +where clause is one of the following: + + + .. code-block:: c + + to(extended-list) + link(list) + device_type(host | nohost | any) + + +#pragma omp declare variant +--------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "","","","","","``omp declare variant``","" + +The `declare variant` directive declares a specialized variant of a base + function and specifies the context in which that specialized variant is used. + The declare variant directive is a declarative directive. +The syntax of the `declare variant` construct is as follows: + + .. code-block:: none + + #pragma omp declare variant(variant-func-id) clause new-line + [#pragma omp declare variant(variant-func-id) clause new-line] + [...] + function definition or declaration + +where clause is one of the following: + + .. code-block:: none + + match(context-selector-specification) + +and where `variant-func-id` is the name of a function variant that is either a + base language identifier or, for C++, a template-id. + + +_Noreturn +--------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "","","","","``_Noreturn``","","" + +A function declared as ``_Noreturn`` shall not return to its caller. The +compiler will generate a diagnostic for a function declared as ``_Noreturn`` +that appears to be capable of returning to its caller. Despite being a type +specifier, the ``_Noreturn`` attribute cannot be specified on a function +pointer type. + + +abi_tag +------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``abi_tag``","``gnu::abi_tag``","","","","","Yes" + +The ``abi_tag`` attribute can be applied to a function, variable, class or +inline namespace declaration to modify the mangled name of the entity. It gives +the ability to distinguish between different versions of the same entity but +with different ABI versions supported. For example, a newer version of a class +could have a different set of data members and thus have a different size. Using +the ``abi_tag`` attribute, it is possible to have different mangled names for +a global variable of the class type. Therefore, the old code could keep using +the old manged name and the new code will use the new mangled name with tags. + + +acquire_capability, acquire_shared_capability +--------------------------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``acquire_capability`` |br| ``acquire_shared_capability`` |br| ``exclusive_lock_function`` |br| ``shared_lock_function``","``clang::acquire_capability`` |br| ``clang::acquire_shared_capability``","","","","","" + +Marks a function as acquiring a capability. + + +alloc_align +----------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``alloc_align``","``gnu::alloc_align``","","","","","" + +Use ``__attribute__((alloc_align())`` on a function +declaration to specify that the return value of the function (which must be a +pointer type) is at least as aligned as the value of the indicated parameter. The +parameter is given by its index in the list of formal parameters; the first +parameter has index 1 unless the function is a C++ non-static member function, +in which case the first parameter has index 2 to account for the implicit ``this`` +parameter. + +.. code-block:: c++ + + // The returned pointer has the alignment specified by the first parameter. + void *a(size_t align) __attribute__((alloc_align(1))); + + // The returned pointer has the alignment specified by the second parameter. + void *b(void *v, size_t align) __attribute__((alloc_align(2))); + + // The returned pointer has the alignment specified by the second visible + // parameter, however it must be adjusted for the implicit 'this' parameter. + void *Foo::b(void *v, size_t align) __attribute__((alloc_align(3))); + +Note that this attribute merely informs the compiler that a function always +returns a sufficiently aligned pointer. It does not cause the compiler to +emit code to enforce that alignment. The behavior is undefined if the returned +poitner is not sufficiently aligned. + + +alloc_size +---------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``alloc_size``","``gnu::alloc_size``","","","","","Yes" + +The ``alloc_size`` attribute can be placed on functions that return pointers in +order to hint to the compiler how many bytes of memory will be available at the +returned pointer. ``alloc_size`` takes one or two arguments. + +- ``alloc_size(N)`` implies that argument number N equals the number of + available bytes at the returned pointer. +- ``alloc_size(N, M)`` implies that the product of argument number N and + argument number M equals the number of available bytes at the returned + pointer. + +Argument numbers are 1-based. + +An example of how to use ``alloc_size`` + +.. code-block:: c + + void *my_malloc(int a) __attribute__((alloc_size(1))); + void *my_calloc(int a, int b) __attribute__((alloc_size(1, 2))); + + int main() { + void *const p = my_malloc(100); + assert(__builtin_object_size(p, 0) == 100); + void *const a = my_calloc(20, 5); + assert(__builtin_object_size(a, 0) == 100); + } + +.. Note:: This attribute works differently in clang than it does in GCC. + Specifically, clang will only trace ``const`` pointers (as above); we give up + on pointers that are not marked as ``const``. In the vast majority of cases, + this is unimportant, because LLVM has support for the ``alloc_size`` + attribute. However, this may cause mildly unintuitive behavior when used with + other attributes, such as ``enable_if``. + + +allocator +--------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "","","","``allocator``","","","" + +The ``__declspec(allocator)`` attribute is applied to functions that allocate +memory, such as operator new in C++. When CodeView debug information is emitted +(enabled by ``clang -gcodeview`` or ``clang-cl /Z7``), Clang will attempt to +record the code offset of heap allocation call sites in the debug info. It will +also record the type being allocated using some local heuristics. The Visual +Studio debugger uses this information to `profile memory usage`_. + +.. _profile memory usage: https://docs.microsoft.com/en-us/visualstudio/profiling/memory-usage + +This attribute does not affect optimizations in any way, unlike GCC's +``__attribute__((malloc))``. + + +artificial +---------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``artificial``","``gnu::artificial``","","","","","" + +The ``artificial`` attribute can be applied to an inline function. If such a +function is inlined, the attribute indicates that debuggers should associate +the resulting instructions with the call site, rather than with the +corresponding line within the inlined callee. + + +assert_capability, assert_shared_capability +------------------------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``assert_capability`` |br| ``assert_shared_capability``","``clang::assert_capability`` |br| ``clang::assert_shared_capability``","","","","","" + +Marks a function that dynamically tests whether a capability is held, and halts +the program if it is not held. + + +assume_aligned +-------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``assume_aligned``","``gnu::assume_aligned``","","","","","Yes" + +Use ``__attribute__((assume_aligned([,]))`` on a function +declaration to specify that the return value of the function (which must be a +pointer type) has the specified offset, in bytes, from an address with the +specified alignment. The offset is taken to be zero if omitted. + +.. code-block:: c++ + + // The returned pointer value has 32-byte alignment. + void *a() __attribute__((assume_aligned (32))); + + // The returned pointer value is 4 bytes greater than an address having + // 32-byte alignment. + void *b() __attribute__((assume_aligned (32, 4))); + +Note that this attribute provides information to the compiler regarding a +condition that the code already ensures is true. It does not cause the compiler +to enforce the provided alignment assumption. + + +availability +------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``availability``","``clang::availability``","``clang::availability``","","","","Yes" + +The ``availability`` attribute can be placed on declarations to describe the +lifecycle of that declaration relative to operating system versions. Consider +the function declaration for a hypothetical function ``f``: + +.. code-block:: c++ + + void f(void) __attribute__((availability(macos,introduced=10.4,deprecated=10.6,obsoleted=10.7))); + +The availability attribute states that ``f`` was introduced in macOS 10.4, +deprecated in macOS 10.6, and obsoleted in macOS 10.7. This information +is used by Clang to determine when it is safe to use ``f``: for example, if +Clang is instructed to compile code for macOS 10.5, a call to ``f()`` +succeeds. If Clang is instructed to compile code for macOS 10.6, the call +succeeds but Clang emits a warning specifying that the function is deprecated. +Finally, if Clang is instructed to compile code for macOS 10.7, the call +fails because ``f()`` is no longer available. + +The availability attribute is a comma-separated list starting with the +platform name and then including clauses specifying important milestones in the +declaration's lifetime (in any order) along with additional information. Those +clauses can be: + +introduced=\ *version* + The first version in which this declaration was introduced. + +deprecated=\ *version* + The first version in which this declaration was deprecated, meaning that + users should migrate away from this API. + +obsoleted=\ *version* + The first version in which this declaration was obsoleted, meaning that it + was removed completely and can no longer be used. + +unavailable + This declaration is never available on this platform. + +message=\ *string-literal* + Additional message text that Clang will provide when emitting a warning or + error about use of a deprecated or obsoleted declaration. Useful to direct + users to replacement APIs. + +replacement=\ *string-literal* + Additional message text that Clang will use to provide Fix-It when emitting + a warning about use of a deprecated declaration. The Fix-It will replace + the deprecated declaration with the new declaration specified. + +Multiple availability attributes can be placed on a declaration, which may +correspond to different platforms. For most platforms, the availability +attribute with the platform corresponding to the target platform will be used; +any others will be ignored. However, the availability for ``watchOS`` and +``tvOS`` can be implicitly inferred from an ``iOS`` availability attribute. +Any explicit availability attributes for those platforms are still prefered over +the implicitly inferred availability attributes. If no availability attribute +specifies availability for the current target platform, the availability +attributes are ignored. Supported platforms are: + +``ios`` + Apple's iOS operating system. The minimum deployment target is specified by + the ``-mios-version-min=*version*`` or ``-miphoneos-version-min=*version*`` + command-line arguments. + +``macos`` + Apple's macOS operating system. The minimum deployment target is + specified by the ``-mmacosx-version-min=*version*`` command-line argument. + ``macosx`` is supported for backward-compatibility reasons, but it is + deprecated. + +``tvos`` + Apple's tvOS operating system. The minimum deployment target is specified by + the ``-mtvos-version-min=*version*`` command-line argument. + +``watchos`` + Apple's watchOS operating system. The minimum deployment target is specified by + the ``-mwatchos-version-min=*version*`` command-line argument. + +A declaration can typically be used even when deploying back to a platform +version prior to when the declaration was introduced. When this happens, the +declaration is `weakly linked +`_, +as if the ``weak_import`` attribute were added to the declaration. A +weakly-linked declaration may or may not be present a run-time, and a program +can determine whether the declaration is present by checking whether the +address of that declaration is non-NULL. + +The flag ``strict`` disallows using API when deploying back to a +platform version prior to when the declaration was introduced. An +attempt to use such API before its introduction causes a hard error. +Weakly-linking is almost always a better API choice, since it allows +users to query availability at runtime. + +If there are multiple declarations of the same entity, the availability +attributes must either match on a per-platform basis or later +declarations must not have availability attributes for that +platform. For example: + +.. code-block:: c + + void g(void) __attribute__((availability(macos,introduced=10.4))); + void g(void) __attribute__((availability(macos,introduced=10.4))); // okay, matches + void g(void) __attribute__((availability(ios,introduced=4.0))); // okay, adds a new platform + void g(void); // okay, inherits both macos and ios availability from above. + void g(void) __attribute__((availability(macos,introduced=10.5))); // error: mismatch + +When one method overrides another, the overriding method can be more widely available than the overridden method, e.g.,: + +.. code-block:: objc + + @interface A + - (id)method __attribute__((availability(macos,introduced=10.4))); + - (id)method2 __attribute__((availability(macos,introduced=10.4))); + @end + + @interface B : A + - (id)method __attribute__((availability(macos,introduced=10.3))); // okay: method moved into base class later + - (id)method __attribute__((availability(macos,introduced=10.5))); // error: this method was available via the base class in 10.4 + @end + +Starting with the macOS 10.12 SDK, the ``API_AVAILABLE`` macro from +```` can simplify the spelling: + +.. code-block:: objc + + @interface A + - (id)method API_AVAILABLE(macos(10.11))); + - (id)otherMethod API_AVAILABLE(macos(10.11), ios(11.0)); + @end + +Availability attributes can also be applied using a ``#pragma clang attribute``. +Any explicit availability attribute whose platform corresponds to the target +platform is applied to a declaration regardless of the availability attributes +specified in the pragma. For example, in the code below, +``hasExplicitAvailabilityAttribute`` will use the ``macOS`` availability +attribute that is specified with the declaration, whereas +``getsThePragmaAvailabilityAttribute`` will use the ``macOS`` availability +attribute that is applied by the pragma. + +.. code-block:: c + + #pragma clang attribute push (__attribute__((availability(macOS, introduced=10.12))), apply_to=function) + void getsThePragmaAvailabilityAttribute(void); + void hasExplicitAvailabilityAttribute(void) __attribute__((availability(macos,introduced=10.4))); + #pragma clang attribute pop + +For platforms like ``watchOS`` and ``tvOS``, whose availability attributes can +be implicitly inferred from an ``iOS`` availability attribute, the logic is +slightly more complex. The explicit and the pragma-applied availability +attributes whose platform corresponds to the target platform are applied as +described in the previous paragraph. However, the implicitly inferred attributes +are applied to a declaration only when there is no explicit or pragma-applied +availability attribute whose platform corresponds to the target platform. For +example, the function below will receive the ``tvOS`` availability from the +pragma rather than using the inferred ``iOS`` availability from the declaration: + +.. code-block:: c + + #pragma clang attribute push (__attribute__((availability(tvOS, introduced=12.0))), apply_to=function) + void getsThePragmaTVOSAvailabilityAttribute(void) __attribute__((availability(iOS,introduced=11.0))); + #pragma clang attribute pop + +The compiler is also able to apply implicly inferred attributes from a pragma +as well. For example, when targeting ``tvOS``, the function below will receive +a ``tvOS`` availability attribute that is implicitly inferred from the ``iOS`` +availability attribute applied by the pragma: + +.. code-block:: c + + #pragma clang attribute push (__attribute__((availability(iOS, introduced=12.0))), apply_to=function) + void infersTVOSAvailabilityFromPragma(void); + #pragma clang attribute pop + +The implicit attributes that are inferred from explicitly specified attributes +whose platform corresponds to the target platform are applied to the declaration +even if there is an availability attribute that can be inferred from a pragma. +For example, the function below will receive the ``tvOS, introduced=11.0`` +availability that is inferred from the attribute on the declaration rather than +inferring availability from the pragma: + +.. code-block:: c + + #pragma clang attribute push (__attribute__((availability(iOS, unavailable))), apply_to=function) + void infersTVOSAvailabilityFromAttributeNextToDeclaration(void) + __attribute__((availability(iOS,introduced=11.0))); + #pragma clang attribute pop + +Also see the documentation for `@available +`_ + + +callback +-------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``callback``","``clang::callback``","``clang::callback``","","","","Yes" + +The ``callback`` attribute specifies that the annotated function may invoke the +specified callback zero or more times. The callback, as well as the passed +arguments, are identified by their parameter name or position (starting with +1!) in the annotated function. The first position in the attribute identifies +the callback callee, the following positions declare describe its arguments. +The callback callee is required to be callable with the number, and order, of +the specified arguments. The index `0`, or the identifier `this`, is used to +represent an implicit "this" pointer in class methods. If there is no implicit +"this" pointer it shall not be referenced. The index '-1', or the name "__", +represents an unknown callback callee argument. This can be a value which is +not present in the declared parameter list, or one that is, but is potentially +inspected, captured, or modified. Parameter names and indices can be mixed in +the callback attribute. + +The ``callback`` attribute, which is directly translated to ``callback`` +metadata , make the +connection between the call to the annotated function and the callback callee. +This can enable interprocedural optimizations which were otherwise impossible. +If a function parameter is mentioned in the ``callback`` attribute, through its +position, it is undefined if that parameter is used for anything other than the +actual callback. Inspected, captured, or modified parameters shall not be +listed in the ``callback`` metadata. + +Example encodings for the callback performed by `pthread_create` are shown +below. The explicit attribute annotation indicates that the third parameter +(`start_routine`) is called zero or more times by the `pthread_create` function, +and that the fourth parameter (`arg`) is passed along. Note that the callback +behavior of `pthread_create` is automatically recognized by Clang. In addition, +the declarations of `__kmpc_fork_teams` and `__kmpc_fork_call`, generated for +`#pragma omp target teams` and `#pragma omp parallel`, respectively, are also +automatically recognized as broker functions. Further functions might be added +in the future. + + .. code-block:: c + + __attribute__((callback (start_routine, arg))) + int pthread_create(pthread_t *thread, const pthread_attr_t *attr, + void *(*start_routine) (void *), void *arg); + + __attribute__((callback (3, 4))) + int pthread_create(pthread_t *thread, const pthread_attr_t *attr, + void *(*start_routine) (void *), void *arg); + + +carries_dependency +------------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``carries_dependency``","``carries_dependency``","","","","","Yes" + +The ``carries_dependency`` attribute specifies dependency propagation into and +out of functions. + +When specified on a function or Objective-C method, the ``carries_dependency`` +attribute means that the return value carries a dependency out of the function, +so that the implementation need not constrain ordering upon return from that +function. Implementations of the function and its caller may choose to preserve +dependencies instead of emitting memory ordering instructions such as fences. + +Note, this attribute does not change the meaning of the program, but may result +in generation of more efficient code. + + +cf_consumed +----------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``cf_consumed``","``clang::cf_consumed``","``clang::cf_consumed``","","","","Yes" + +The behavior of a function with respect to reference counting for Foundation +(Objective-C), CoreFoundation (C) and OSObject (C++) is determined by a naming +convention (e.g. functions starting with "get" are assumed to return at +``+0``). + +It can be overriden using a family of the following attributes. In +Objective-C, the annotation ``__attribute__((ns_returns_retained))`` applied to +a function communicates that the object is returned at ``+1``, and the caller +is responsible for freeing it. +Similiarly, the annotation ``__attribute__((ns_returns_not_retained))`` +specifies that the object is returned at ``+0`` and the ownership remains with +the callee. +The annotation ``__attribute__((ns_consumes_self))`` specifies that +the Objective-C method call consumes the reference to ``self``, e.g. by +attaching it to a supplied parameter. +Additionally, parameters can have an annotation +``__attribute__((ns_consumed))``, which specifies that passing an owned object +as that parameter effectively transfers the ownership, and the caller is no +longer responsible for it. +These attributes affect code generation when interacting with ARC code, and +they are used by the Clang Static Analyzer. + +In C programs using CoreFoundation, a similar set of attributes: +``__attribute__((cf_returns_not_retained))``, +``__attribute__((cf_returns_retained))`` and ``__attribute__((cf_consumed))`` +have the same respective semantics when applied to CoreFoundation objects. +These attributes affect code generation when interacting with ARC code, and +they are used by the Clang Static Analyzer. + +Finally, in C++ interacting with XNU kernel (objects inheriting from OSObject), +the same attribute family is present: +``__attribute__((os_returns_not_retained))``, +``__attribute__((os_returns_retained))`` and ``__attribute__((os_consumed))``, +with the same respective semantics. +Similar to ``__attribute__((ns_consumes_self))``, +``__attribute__((os_consumes_this))`` specifies that the method call consumes +the reference to "this" (e.g., when attaching it to a different object supplied +as a parameter). +Out parameters (parameters the function is meant to write into, +either via pointers-to-pointers or references-to-pointers) +may be annotated with ``__attribute__((os_returns_retained))`` +or ``__attribute__((os_returns_not_retained))`` which specifies that the object +written into the out parameter should (or respectively should not) be released +after use. +Since often out parameters may or may not be written depending on the exit +code of the function, +annotations ``__attribute__((os_returns_retained_on_zero))`` +and ``__attribute__((os_returns_retained_on_non_zero))`` specify that +an out parameter at ``+1`` is written if and only if the function returns a zero +(respectively non-zero) error code. +Observe that return-code-dependent out parameter annotations are only +available for retained out parameters, as non-retained object do not have to be +released by the callee. +These attributes are only used by the Clang Static Analyzer. + +The family of attributes ``X_returns_X_retained`` can be added to functions, +C++ methods, and Objective-C methods and properties. +Attributes ``X_consumed`` can be added to parameters of methods, functions, +and Objective-C methods. + + +cf_returns_not_retained +----------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``cf_returns_not_retained``","``clang::cf_returns_not_retained``","``clang::cf_returns_not_retained``","","","","" + +The behavior of a function with respect to reference counting for Foundation +(Objective-C), CoreFoundation (C) and OSObject (C++) is determined by a naming +convention (e.g. functions starting with "get" are assumed to return at +``+0``). + +It can be overriden using a family of the following attributes. In +Objective-C, the annotation ``__attribute__((ns_returns_retained))`` applied to +a function communicates that the object is returned at ``+1``, and the caller +is responsible for freeing it. +Similiarly, the annotation ``__attribute__((ns_returns_not_retained))`` +specifies that the object is returned at ``+0`` and the ownership remains with +the callee. +The annotation ``__attribute__((ns_consumes_self))`` specifies that +the Objective-C method call consumes the reference to ``self``, e.g. by +attaching it to a supplied parameter. +Additionally, parameters can have an annotation +``__attribute__((ns_consumed))``, which specifies that passing an owned object +as that parameter effectively transfers the ownership, and the caller is no +longer responsible for it. +These attributes affect code generation when interacting with ARC code, and +they are used by the Clang Static Analyzer. + +In C programs using CoreFoundation, a similar set of attributes: +``__attribute__((cf_returns_not_retained))``, +``__attribute__((cf_returns_retained))`` and ``__attribute__((cf_consumed))`` +have the same respective semantics when applied to CoreFoundation objects. +These attributes affect code generation when interacting with ARC code, and +they are used by the Clang Static Analyzer. + +Finally, in C++ interacting with XNU kernel (objects inheriting from OSObject), +the same attribute family is present: +``__attribute__((os_returns_not_retained))``, +``__attribute__((os_returns_retained))`` and ``__attribute__((os_consumed))``, +with the same respective semantics. +Similar to ``__attribute__((ns_consumes_self))``, +``__attribute__((os_consumes_this))`` specifies that the method call consumes +the reference to "this" (e.g., when attaching it to a different object supplied +as a parameter). +Out parameters (parameters the function is meant to write into, +either via pointers-to-pointers or references-to-pointers) +may be annotated with ``__attribute__((os_returns_retained))`` +or ``__attribute__((os_returns_not_retained))`` which specifies that the object +written into the out parameter should (or respectively should not) be released +after use. +Since often out parameters may or may not be written depending on the exit +code of the function, +annotations ``__attribute__((os_returns_retained_on_zero))`` +and ``__attribute__((os_returns_retained_on_non_zero))`` specify that +an out parameter at ``+1`` is written if and only if the function returns a zero +(respectively non-zero) error code. +Observe that return-code-dependent out parameter annotations are only +available for retained out parameters, as non-retained object do not have to be +released by the callee. +These attributes are only used by the Clang Static Analyzer. + +The family of attributes ``X_returns_X_retained`` can be added to functions, +C++ methods, and Objective-C methods and properties. +Attributes ``X_consumed`` can be added to parameters of methods, functions, +and Objective-C methods. + + +cf_returns_retained +------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``cf_returns_retained``","``clang::cf_returns_retained``","``clang::cf_returns_retained``","","","","" + +The behavior of a function with respect to reference counting for Foundation +(Objective-C), CoreFoundation (C) and OSObject (C++) is determined by a naming +convention (e.g. functions starting with "get" are assumed to return at +``+0``). + +It can be overriden using a family of the following attributes. In +Objective-C, the annotation ``__attribute__((ns_returns_retained))`` applied to +a function communicates that the object is returned at ``+1``, and the caller +is responsible for freeing it. +Similiarly, the annotation ``__attribute__((ns_returns_not_retained))`` +specifies that the object is returned at ``+0`` and the ownership remains with +the callee. +The annotation ``__attribute__((ns_consumes_self))`` specifies that +the Objective-C method call consumes the reference to ``self``, e.g. by +attaching it to a supplied parameter. +Additionally, parameters can have an annotation +``__attribute__((ns_consumed))``, which specifies that passing an owned object +as that parameter effectively transfers the ownership, and the caller is no +longer responsible for it. +These attributes affect code generation when interacting with ARC code, and +they are used by the Clang Static Analyzer. + +In C programs using CoreFoundation, a similar set of attributes: +``__attribute__((cf_returns_not_retained))``, +``__attribute__((cf_returns_retained))`` and ``__attribute__((cf_consumed))`` +have the same respective semantics when applied to CoreFoundation objects. +These attributes affect code generation when interacting with ARC code, and +they are used by the Clang Static Analyzer. + +Finally, in C++ interacting with XNU kernel (objects inheriting from OSObject), +the same attribute family is present: +``__attribute__((os_returns_not_retained))``, +``__attribute__((os_returns_retained))`` and ``__attribute__((os_consumed))``, +with the same respective semantics. +Similar to ``__attribute__((ns_consumes_self))``, +``__attribute__((os_consumes_this))`` specifies that the method call consumes +the reference to "this" (e.g., when attaching it to a different object supplied +as a parameter). +Out parameters (parameters the function is meant to write into, +either via pointers-to-pointers or references-to-pointers) +may be annotated with ``__attribute__((os_returns_retained))`` +or ``__attribute__((os_returns_not_retained))`` which specifies that the object +written into the out parameter should (or respectively should not) be released +after use. +Since often out parameters may or may not be written depending on the exit +code of the function, +annotations ``__attribute__((os_returns_retained_on_zero))`` +and ``__attribute__((os_returns_retained_on_non_zero))`` specify that +an out parameter at ``+1`` is written if and only if the function returns a zero +(respectively non-zero) error code. +Observe that return-code-dependent out parameter annotations are only +available for retained out parameters, as non-retained object do not have to be +released by the callee. +These attributes are only used by the Clang Static Analyzer. + +The family of attributes ``X_returns_X_retained`` can be added to functions, +C++ methods, and Objective-C methods and properties. +Attributes ``X_consumed`` can be added to parameters of methods, functions, +and Objective-C methods. + + +cfi_canonical_jump_table +------------------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``cfi_canonical_jump_table``","``clang::cfi_canonical_jump_table``","``clang::cfi_canonical_jump_table``","","","","Yes" + +.. _langext-cfi_canonical_jump_table: + +Use ``__attribute__((cfi_canonical_jump_table))`` on a function declaration to +make the function's CFI jump table canonical. See :ref:`the CFI documentation +` for more details. + + +clang_arm_mve_alias +------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``__clang_arm_mve_alias``","``clang::__clang_arm_mve_alias``","``clang::__clang_arm_mve_alias``","","","","Yes" + +This attribute is used in the implementation of the ACLE intrinsics +for the Arm MVE instruction set. It allows the intrinsic functions to +be declared using the names defined in ACLE, and still be recognized +as clang builtins equivalent to the underlying name. For example, +``arm_mve.h`` declares the function ``vaddq_u32`` with +``__attribute__((__clang_arm_mve_alias(__builtin_arm_mve_vaddq_u32)))``, +and similarly, one of the type-overloaded declarations of ``vaddq`` +will have the same attribute. This ensures that both functions are +recognized as that clang builtin, and in the latter case, the choice +of which builtin to identify the function as can be deferred until +after overload resolution. + +This attribute can only be used to set up the aliases for the MVE +intrinsic functions; it is intended for use only inside ``arm_mve.h``, +and is not a general mechanism for declaring arbitrary aliases for +clang builtin functions. + + +code_seg +-------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "","","","``code_seg``","","","" + +The ``__declspec(code_seg)`` attribute enables the placement of code into separate +named segments that can be paged or locked in memory individually. This attribute +is used to control the placement of instantiated templates and compiler-generated +code. See the documentation for `__declspec(code_seg)`_ on MSDN. + +.. _`__declspec(code_seg)`: http://msdn.microsoft.com/en-us/library/dn636922.aspx + + +convergent +---------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``convergent``","``clang::convergent``","``clang::convergent``","","","","Yes" + +The ``convergent`` attribute can be placed on a function declaration. It is +translated into the LLVM ``convergent`` attribute, which indicates that the call +instructions of a function with this attribute cannot be made control-dependent +on any additional values. + +In languages designed for SPMD/SIMT programming model, e.g. OpenCL or CUDA, +the call instructions of a function with this attribute must be executed by +all work items or threads in a work group or sub group. + +This attribute is different from ``noduplicate`` because it allows duplicating +function calls if it can be proved that the duplicated function calls are +not made control-dependent on any additional values, e.g., unrolling a loop +executed by all work items. + +Sample usage: +.. code-block:: c + + void convfunc(void) __attribute__((convergent)); + // Setting it as a C++11 attribute is also valid in a C++ program. + // void convfunc(void) [[clang::convergent]]; + + +cpu_dispatch +------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``cpu_dispatch``","``clang::cpu_dispatch``","``clang::cpu_dispatch``","``cpu_dispatch``","","","Yes" + +The ``cpu_specific`` and ``cpu_dispatch`` attributes are used to define and +resolve multiversioned functions. This form of multiversioning provides a +mechanism for declaring versions across translation units and manually +specifying the resolved function list. A specified CPU defines a set of minimum +features that are required for the function to be called. The result of this is +that future processors execute the most restrictive version of the function the +new processor can execute. + +Function versions are defined with ``cpu_specific``, which takes one or more CPU +names as a parameter. For example: + +.. code-block:: c + + // Declares and defines the ivybridge version of single_cpu. + __attribute__((cpu_specific(ivybridge))) + void single_cpu(void){} + + // Declares and defines the atom version of single_cpu. + __attribute__((cpu_specific(atom))) + void single_cpu(void){} + + // Declares and defines both the ivybridge and atom version of multi_cpu. + __attribute__((cpu_specific(ivybridge, atom))) + void multi_cpu(void){} + +A dispatching (or resolving) function can be declared anywhere in a project's +source code with ``cpu_dispatch``. This attribute takes one or more CPU names +as a parameter (like ``cpu_specific``). Functions marked with ``cpu_dispatch`` +are not expected to be defined, only declared. If such a marked function has a +definition, any side effects of the function are ignored; trivial function +bodies are permissible for ICC compatibility. + +.. code-block:: c + + // Creates a resolver for single_cpu above. + __attribute__((cpu_dispatch(ivybridge, atom))) + void single_cpu(void){} + + // Creates a resolver for multi_cpu, but adds a 3rd version defined in another + // translation unit. + __attribute__((cpu_dispatch(ivybridge, atom, sandybridge))) + void multi_cpu(void){} + +Note that it is possible to have a resolving function that dispatches based on +more or fewer options than are present in the program. Specifying fewer will +result in the omitted options not being considered during resolution. Specifying +a version for resolution that isn't defined in the program will result in a +linking failure. + +It is also possible to specify a CPU name of ``generic`` which will be resolved +if the executing processor doesn't satisfy the features required in the CPU +name. The behavior of a program executing on a processor that doesn't satisfy +any option of a multiversioned function is undefined. + + +cpu_specific +------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``cpu_specific``","``clang::cpu_specific``","``clang::cpu_specific``","``cpu_specific``","","","Yes" + +The ``cpu_specific`` and ``cpu_dispatch`` attributes are used to define and +resolve multiversioned functions. This form of multiversioning provides a +mechanism for declaring versions across translation units and manually +specifying the resolved function list. A specified CPU defines a set of minimum +features that are required for the function to be called. The result of this is +that future processors execute the most restrictive version of the function the +new processor can execute. + +Function versions are defined with ``cpu_specific``, which takes one or more CPU +names as a parameter. For example: + +.. code-block:: c + + // Declares and defines the ivybridge version of single_cpu. + __attribute__((cpu_specific(ivybridge))) + void single_cpu(void){} + + // Declares and defines the atom version of single_cpu. + __attribute__((cpu_specific(atom))) + void single_cpu(void){} + + // Declares and defines both the ivybridge and atom version of multi_cpu. + __attribute__((cpu_specific(ivybridge, atom))) + void multi_cpu(void){} + +A dispatching (or resolving) function can be declared anywhere in a project's +source code with ``cpu_dispatch``. This attribute takes one or more CPU names +as a parameter (like ``cpu_specific``). Functions marked with ``cpu_dispatch`` +are not expected to be defined, only declared. If such a marked function has a +definition, any side effects of the function are ignored; trivial function +bodies are permissible for ICC compatibility. + +.. code-block:: c + + // Creates a resolver for single_cpu above. + __attribute__((cpu_dispatch(ivybridge, atom))) + void single_cpu(void){} + + // Creates a resolver for multi_cpu, but adds a 3rd version defined in another + // translation unit. + __attribute__((cpu_dispatch(ivybridge, atom, sandybridge))) + void multi_cpu(void){} + +Note that it is possible to have a resolving function that dispatches based on +more or fewer options than are present in the program. Specifying fewer will +result in the omitted options not being considered during resolution. Specifying +a version for resolution that isn't defined in the program will result in a +linking failure. + +It is also possible to specify a CPU name of ``generic`` which will be resolved +if the executing processor doesn't satisfy the features required in the CPU +name. The behavior of a program executing on a processor that doesn't satisfy +any option of a multiversioned function is undefined. + + +diagnose_if +----------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``diagnose_if``","","","","","","" + +The ``diagnose_if`` attribute can be placed on function declarations to emit +warnings or errors at compile-time if calls to the attributed function meet +certain user-defined criteria. For example: + +.. code-block:: c + + int abs(int a) + __attribute__((diagnose_if(a >= 0, "Redundant abs call", "warning"))); + int must_abs(int a) + __attribute__((diagnose_if(a >= 0, "Redundant abs call", "error"))); + + int val = abs(1); // warning: Redundant abs call + int val2 = must_abs(1); // error: Redundant abs call + int val3 = abs(val); + int val4 = must_abs(val); // Because run-time checks are not emitted for + // diagnose_if attributes, this executes without + // issue. + + +``diagnose_if`` is closely related to ``enable_if``, with a few key differences: + +* Overload resolution is not aware of ``diagnose_if`` attributes: they're + considered only after we select the best candidate from a given candidate set. +* Function declarations that differ only in their ``diagnose_if`` attributes are + considered to be redeclarations of the same function (not overloads). +* If the condition provided to ``diagnose_if`` cannot be evaluated, no + diagnostic will be emitted. + +Otherwise, ``diagnose_if`` is essentially the logical negation of ``enable_if``. + +As a result of bullet number two, ``diagnose_if`` attributes will stack on the +same function. For example: + +.. code-block:: c + + int foo() __attribute__((diagnose_if(1, "diag1", "warning"))); + int foo() __attribute__((diagnose_if(1, "diag2", "warning"))); + + int bar = foo(); // warning: diag1 + // warning: diag2 + int (*fooptr)(void) = foo; // warning: diag1 + // warning: diag2 + + constexpr int supportsAPILevel(int N) { return N < 5; } + int baz(int a) + __attribute__((diagnose_if(!supportsAPILevel(10), + "Upgrade to API level 10 to use baz", "error"))); + int baz(int a) + __attribute__((diagnose_if(!a, "0 is not recommended.", "warning"))); + + int (*bazptr)(int) = baz; // error: Upgrade to API level 10 to use baz + int v = baz(0); // error: Upgrade to API level 10 to use baz + +Query for this feature with ``__has_attribute(diagnose_if)``. + + +disable_tail_calls +------------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``disable_tail_calls``","``clang::disable_tail_calls``","``clang::disable_tail_calls``","","","","Yes" + +The ``disable_tail_calls`` attribute instructs the backend to not perform tail call optimization inside the marked function. + +For example: + + .. code-block:: c + + int callee(int); + + int foo(int a) __attribute__((disable_tail_calls)) { + return callee(a); // This call is not tail-call optimized. + } + +Marking virtual functions as ``disable_tail_calls`` is legal. + + .. code-block:: c++ + + int callee(int); + + class Base { + public: + [[clang::disable_tail_calls]] virtual int foo1() { + return callee(); // This call is not tail-call optimized. + } + }; + + class Derived1 : public Base { + public: + int foo1() override { + return callee(); // This call is tail-call optimized. + } + }; + + +enable_if +--------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``enable_if``","","","","","","Yes" + +.. Note:: Some features of this attribute are experimental. The meaning of + multiple enable_if attributes on a single declaration is subject to change in + a future version of clang. Also, the ABI is not standardized and the name + mangling may change in future versions. To avoid that, use asm labels. + +The ``enable_if`` attribute can be placed on function declarations to control +which overload is selected based on the values of the function's arguments. +When combined with the ``overloadable`` attribute, this feature is also +available in C. + +.. code-block:: c++ + + int isdigit(int c); + int isdigit(int c) __attribute__((enable_if(c <= -1 || c > 255, "chosen when 'c' is out of range"))) __attribute__((unavailable("'c' must have the value of an unsigned char or EOF"))); + + void foo(char c) { + isdigit(c); + isdigit(10); + isdigit(-10); // results in a compile-time error. + } + +The enable_if attribute takes two arguments, the first is an expression written +in terms of the function parameters, the second is a string explaining why this +overload candidate could not be selected to be displayed in diagnostics. The +expression is part of the function signature for the purposes of determining +whether it is a redeclaration (following the rules used when determining +whether a C++ template specialization is ODR-equivalent), but is not part of +the type. + +The enable_if expression is evaluated as if it were the body of a +bool-returning constexpr function declared with the arguments of the function +it is being applied to, then called with the parameters at the call site. If the +result is false or could not be determined through constant expression +evaluation, then this overload will not be chosen and the provided string may +be used in a diagnostic if the compile fails as a result. + +Because the enable_if expression is an unevaluated context, there are no global +state changes, nor the ability to pass information from the enable_if +expression to the function body. For example, suppose we want calls to +strnlen(strbuf, maxlen) to resolve to strnlen_chk(strbuf, maxlen, size of +strbuf) only if the size of strbuf can be determined: + +.. code-block:: c++ + + __attribute__((always_inline)) + static inline size_t strnlen(const char *s, size_t maxlen) + __attribute__((overloadable)) + __attribute__((enable_if(__builtin_object_size(s, 0) != -1))), + "chosen when the buffer size is known but 'maxlen' is not"))) + { + return strnlen_chk(s, maxlen, __builtin_object_size(s, 0)); + } + +Multiple enable_if attributes may be applied to a single declaration. In this +case, the enable_if expressions are evaluated from left to right in the +following manner. First, the candidates whose enable_if expressions evaluate to +false or cannot be evaluated are discarded. If the remaining candidates do not +share ODR-equivalent enable_if expressions, the overload resolution is +ambiguous. Otherwise, enable_if overload resolution continues with the next +enable_if attribute on the candidates that have not been discarded and have +remaining enable_if attributes. In this way, we pick the most specific +overload out of a number of viable overloads using enable_if. + +.. code-block:: c++ + + void f() __attribute__((enable_if(true, ""))); // #1 + void f() __attribute__((enable_if(true, ""))) __attribute__((enable_if(true, ""))); // #2 + + void g(int i, int j) __attribute__((enable_if(i, ""))); // #1 + void g(int i, int j) __attribute__((enable_if(j, ""))) __attribute__((enable_if(true))); // #2 + +In this example, a call to f() is always resolved to #2, as the first enable_if +expression is ODR-equivalent for both declarations, but #1 does not have another +enable_if expression to continue evaluating, so the next round of evaluation has +only a single candidate. In a call to g(1, 1), the call is ambiguous even though +#2 has more enable_if attributes, because the first enable_if expressions are +not ODR-equivalent. + +Query for this feature with ``__has_attribute(enable_if)``. + +Note that functions with one or more ``enable_if`` attributes may not have +their address taken, unless all of the conditions specified by said +``enable_if`` are constants that evaluate to ``true``. For example: + +.. code-block:: c + + const int TrueConstant = 1; + const int FalseConstant = 0; + int f(int a) __attribute__((enable_if(a > 0, ""))); + int g(int a) __attribute__((enable_if(a == 0 || a != 0, ""))); + int h(int a) __attribute__((enable_if(1, ""))); + int i(int a) __attribute__((enable_if(TrueConstant, ""))); + int j(int a) __attribute__((enable_if(FalseConstant, ""))); + + void fn() { + int (*ptr)(int); + ptr = &f; // error: 'a > 0' is not always true + ptr = &g; // error: 'a == 0 || a != 0' is not a truthy constant + ptr = &h; // OK: 1 is a truthy constant + ptr = &i; // OK: 'TrueConstant' is a truthy constant + ptr = &j; // error: 'FalseConstant' is a constant, but not truthy + } + +Because ``enable_if`` evaluation happens during overload resolution, +``enable_if`` may give unintuitive results when used with templates, depending +on when overloads are resolved. In the example below, clang will emit a +diagnostic about no viable overloads for ``foo`` in ``bar``, but not in ``baz``: + +.. code-block:: c++ + + double foo(int i) __attribute__((enable_if(i > 0, ""))); + void *foo(int i) __attribute__((enable_if(i <= 0, ""))); + template + auto bar() { return foo(I); } + + template + auto baz() { return foo(T::number); } + + struct WithNumber { constexpr static int number = 1; }; + void callThem() { + bar(); + baz(); + } + +This is because, in ``bar``, ``foo`` is resolved prior to template +instantiation, so the value for ``I`` isn't known (thus, both ``enable_if`` +conditions for ``foo`` fail). However, in ``baz``, ``foo`` is resolved during +template instantiation, so the value for ``T::number`` is known. + + +exclude_from_explicit_instantiation +----------------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``exclude_from_explicit_instantiation``","``clang::exclude_from_explicit_instantiation``","``clang::exclude_from_explicit_instantiation``","","","","Yes" + +The ``exclude_from_explicit_instantiation`` attribute opts-out a member of a +class template from being part of explicit template instantiations of that +class template. This means that an explicit instantiation will not instantiate +members of the class template marked with the attribute, but also that code +where an extern template declaration of the enclosing class template is visible +will not take for granted that an external instantiation of the class template +would provide those members (which would otherwise be a link error, since the +explicit instantiation won't provide those members). For example, let's say we +don't want the ``data()`` method to be part of libc++'s ABI. To make sure it +is not exported from the dylib, we give it hidden visibility: + + .. code-block:: c++ + + // in + template + class basic_string { + public: + __attribute__((__visibility__("hidden"))) + const value_type* data() const noexcept { ... } + }; + + template class basic_string; + +Since an explicit template instantiation declaration for ``basic_string`` +is provided, the compiler is free to assume that ``basic_string::data()`` +will be provided by another translation unit, and it is free to produce an +external call to this function. However, since ``data()`` has hidden visibility +and the explicit template instantiation is provided in a shared library (as +opposed to simply another translation unit), ``basic_string::data()`` +won't be found and a link error will ensue. This happens because the compiler +assumes that ``basic_string::data()`` is part of the explicit template +instantiation declaration, when it really isn't. To tell the compiler that +``data()`` is not part of the explicit template instantiation declaration, the +``exclude_from_explicit_instantiation`` attribute can be used: + + .. code-block:: c++ + + // in + template + class basic_string { + public: + __attribute__((__visibility__("hidden"))) + __attribute__((exclude_from_explicit_instantiation)) + const value_type* data() const noexcept { ... } + }; + + template class basic_string; + +Now, the compiler won't assume that ``basic_string::data()`` is provided +externally despite there being an explicit template instantiation declaration: +the compiler will implicitly instantiate ``basic_string::data()`` in the +TUs where it is used. + +This attribute can be used on static and non-static member functions of class +templates, static data members of class templates and member classes of class +templates. + + +export_name +----------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``export_name``","``clang::export_name``","``clang::export_name``","","","","Yes" + +Clang supports the ``__attribute__((export_name()))`` +attribute for the WebAssembly target. This attribute may be attached to a +function declaration, where it modifies how the symbol is to be exported +from the linked WebAssembly. + +WebAssembly functions are exported via string name. By default when a symbol +is exported, the export name for C/C++ symbols are the same as their C/C++ +symbol names. This attribute can be used to override the default behavior, and +request a specific string name be used instead. + + +flatten +------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``flatten``","``gnu::flatten``","","","","","Yes" + +The ``flatten`` attribute causes calls within the attributed function to +be inlined unless it is impossible to do so, for example if the body of the +callee is unavailable or if the callee has the ``noinline`` attribute. + + +force_align_arg_pointer +----------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``force_align_arg_pointer``","``gnu::force_align_arg_pointer``","","","","","" + +Use this attribute to force stack alignment. + +Legacy x86 code uses 4-byte stack alignment. Newer aligned SSE instructions +(like 'movaps') that work with the stack require operands to be 16-byte aligned. +This attribute realigns the stack in the function prologue to make sure the +stack can be used with SSE instructions. + +Note that the x86_64 ABI forces 16-byte stack alignment at the call site. +Because of this, 'force_align_arg_pointer' is not needed on x86_64, except in +rare cases where the caller does not align the stack properly (e.g. flow +jumps from i386 arch code). + + .. code-block:: c + + __attribute__ ((force_align_arg_pointer)) + void f () { + ... + } + + +format +------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``format``","``gnu::format``","","","","","" + +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. + +Please see `GCC documentation about format attribute +`_ to find details +about attribute syntax. + +Clang implements two kinds of checks with this attribute. + +#. Clang checks that the function with the ``format`` attribute is called with + a format string that uses format specifiers that are allowed, and that + arguments match the format string. This is the ``-Wformat`` warning, it is + on by default. + +#. Clang checks that the format string argument is a literal string. This is + the ``-Wformat-nonliteral`` warning, it is off by default. + + Clang implements this mostly the same way as GCC, but there is a difference + for functions that accept a ``va_list`` argument (for example, ``vprintf``). + GCC does not emit ``-Wformat-nonliteral`` warning for calls to such + functions. Clang does not warn if the format string comes from a function + parameter, where the function is annotated with a compatible attribute, + otherwise it warns. For example: + + .. code-block:: c + + __attribute__((__format__ (__scanf__, 1, 3))) + void foo(const char* s, char *buf, ...) { + va_list ap; + va_start(ap, buf); + + vprintf(s, ap); // warning: format string is not a string literal + } + + In this case we warn because ``s`` contains a format string for a + ``scanf``-like function, but it is passed to a ``printf``-like function. + + If the attribute is removed, clang still warns, because the format string is + not a string literal. + + Another example: + + .. code-block:: c + + __attribute__((__format__ (__printf__, 1, 3))) + void foo(const char* s, char *buf, ...) { + va_list ap; + va_start(ap, buf); + + vprintf(s, ap); // warning + } + + 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. + + +gnu_inline +---------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``gnu_inline``","``gnu::gnu_inline``","","","","","Yes" + +The ``gnu_inline`` changes the meaning of ``extern inline`` to use GNU inline +semantics, meaning: + +* If any declaration that is declared ``inline`` is not declared ``extern``, + then the ``inline`` keyword is just a hint. In particular, an out-of-line + definition is still emitted for a function with external linkage, even if all + call sites are inlined, unlike in C99 and C++ inline semantics. + +* If all declarations that are declared ``inline`` are also declared + ``extern``, then the function body is present only for inlining and no + out-of-line version is emitted. + +Some important consequences: ``static inline`` emits an out-of-line +version if needed, a plain ``inline`` definition emits an out-of-line version +always, and an ``extern inline`` definition (in a header) followed by a +(non-``extern``) ``inline`` declaration in a source file emits an out-of-line +version of the function in that source file but provides the function body for +inlining to all includers of the header. + +Either ``__GNUC_GNU_INLINE__`` (GNU inline semantics) or +``__GNUC_STDC_INLINE__`` (C99 semantics) will be defined (they are mutually +exclusive). If ``__GNUC_STDC_INLINE__`` is defined, then the ``gnu_inline`` +function attribute can be used to get GNU inline semantics on a per function +basis. If ``__GNUC_GNU_INLINE__`` is defined, then the translation unit is +already being compiled with GNU inline semantics as the implied default. It is +unspecified which macro is defined in a C++ compilation. + +GNU inline semantics are the default behavior with ``-std=gnu89``, +``-std=c89``, ``-std=c94``, or ``-fgnu89-inline``. + + +guard +----- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "","","","``guard``","","","" + +Code can indicate CFG checks are not wanted with the ``__declspec(guard(nocf))`` +attribute. This directs the compiler to not insert any CFG checks for the entire +function. This approach is typically used only sparingly in specific situations +where the programmer has manually inserted "CFG-equivalent" protection. The +programmer knows that they are calling through some read-only function table +whose address is obtained through read-only memory references and for which the +index is masked to the function table limit. This approach may also be applied +to small wrapper functions that are not inlined and that do nothing more than +make a call through a function pointer. Since incorrect usage of this directive +can compromise the security of CFG, the programmer must be very careful using +the directive. Typically, this usage is limited to very small functions that +only call one function. + +`Control Flow Guard documentation ` + + +ifunc +----- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``ifunc``","``gnu::ifunc``","","","","","Yes" + +``__attribute__((ifunc("resolver")))`` is used to mark that the address of a declaration should be resolved at runtime by calling a resolver function. + +The symbol name of the resolver function is given in quotes. A function with this name (after mangling) must be defined in the current translation unit; it may be ``static``. The resolver function should return a pointer. + +The ``ifunc`` attribute may only be used on a function declaration. A function declaration with an ``ifunc`` attribute is considered to be a definition of the declared entity. The entity must not have weak linkage; for example, in C++, it cannot be applied to a declaration if a definition at that location would be considered inline. + +Not all targets support this attribute. ELF target support depends on both the linker and runtime linker, and is available in at least lld 4.0 and later, binutils 2.20.1 and later, glibc v2.11.1 and later, and FreeBSD 9.1 and later. Non-ELF targets currently do not support this attribute. + + +import_module +------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``import_module``","``clang::import_module``","``clang::import_module``","","","","Yes" + +Clang supports the ``__attribute__((import_module()))`` +attribute for the WebAssembly target. This attribute may be attached to a +function declaration, where it modifies how the symbol is to be imported +within the WebAssembly linking environment. + +WebAssembly imports use a two-level namespace scheme, consisting of a module +name, which typically identifies a module from which to import, and a field +name, which typically identifies a field from that module to import. By +default, module names for C/C++ symbols are assigned automatically by the +linker. This attribute can be used to override the default behavior, and +request a specific module name be used instead. + + +import_name +----------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``import_name``","``clang::import_name``","``clang::import_name``","","","","Yes" + +Clang supports the ``__attribute__((import_name()))`` +attribute for the WebAssembly target. This attribute may be attached to a +function declaration, where it modifies how the symbol is to be imported +within the WebAssembly linking environment. + +WebAssembly imports use a two-level namespace scheme, consisting of a module +name, which typically identifies a module from which to import, and a field +name, which typically identifies a field from that module to import. By +default, field names for C/C++ symbols are the same as their C/C++ symbol +names. This attribute can be used to override the default behavior, and +request a specific field name be used instead. + + +internal_linkage +---------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``internal_linkage``","``clang::internal_linkage``","``clang::internal_linkage``","","","","Yes" + +The ``internal_linkage`` attribute changes the linkage type of the declaration to internal. +This is similar to C-style ``static``, but can be used on classes and class methods. When applied to a class definition, +this attribute affects all methods and static data members of that class. +This can be used to contain the ABI of a C++ library by excluding unwanted class methods from the export tables. + + +interrupt (ARM) +--------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``interrupt``","``gnu::interrupt``","","","","","" + +Clang supports the GNU style ``__attribute__((interrupt("TYPE")))`` attribute on +ARM targets. This attribute may be attached to a function definition and +instructs the backend to generate appropriate function entry/exit code so that +it can be used directly as an interrupt service routine. + +The parameter passed to the interrupt attribute is optional, but if +provided it must be a string literal with one of the following values: "IRQ", +"FIQ", "SWI", "ABORT", "UNDEF". + +The semantics are as follows: + +- If the function is AAPCS, Clang instructs the backend to realign the stack to + 8 bytes on entry. This is a general requirement of the AAPCS at public + interfaces, but may not hold when an exception is taken. Doing this allows + other AAPCS functions to be called. +- If the CPU is M-class this is all that needs to be done since the architecture + itself is designed in such a way that functions obeying the normal AAPCS ABI + constraints are valid exception handlers. +- If the CPU is not M-class, the prologue and epilogue are modified to save all + non-banked registers that are used, so that upon return the user-mode state + will not be corrupted. Note that to avoid unnecessary overhead, only + general-purpose (integer) registers are saved in this way. If VFP operations + are needed, that state must be saved manually. + + Specifically, interrupt kinds other than "FIQ" will save all core registers + except "lr" and "sp". "FIQ" interrupts will save r0-r7. +- If the CPU is not M-class, the return instruction is changed to one of the + canonical sequences permitted by the architecture for exception return. Where + possible the function itself will make the necessary "lr" adjustments so that + the "preferred return address" is selected. + + Unfortunately the compiler is unable to make this guarantee for an "UNDEF" + handler, where the offset from "lr" to the preferred return address depends on + the execution state of the code which generated the exception. In this case + a sequence equivalent to "movs pc, lr" will be used. + + +interrupt (AVR) +--------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``interrupt``","``gnu::interrupt``","","","","","Yes" + +Clang supports the GNU style ``__attribute__((interrupt))`` attribute on +AVR targets. This attribute may be attached to a function definition and instructs +the backend to generate appropriate function entry/exit code so that it can be used +directly as an interrupt service routine. + +On the AVR, the hardware globally disables interrupts when an interrupt is executed. +The first instruction of an interrupt handler declared with this attribute is a SEI +instruction to re-enable interrupts. See also the signal attribute that +does not insert a SEI instruction. + + +interrupt (MIPS) +---------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``interrupt``","``gnu::interrupt``","","","","","Yes" + +Clang supports the GNU style ``__attribute__((interrupt("ARGUMENT")))`` attribute on +MIPS targets. This attribute may be attached to a function definition and instructs +the backend to generate appropriate function entry/exit code so that it can be used +directly as an interrupt service routine. + +By default, the compiler will produce a function prologue and epilogue suitable for +an interrupt service routine that handles an External Interrupt Controller (eic) +generated interrupt. This behaviour can be explicitly requested with the "eic" +argument. + +Otherwise, for use with vectored interrupt mode, the argument passed should be +of the form "vector=LEVEL" where LEVEL is one of the following values: +"sw0", "sw1", "hw0", "hw1", "hw2", "hw3", "hw4", "hw5". The compiler will +then set the interrupt mask to the corresponding level which will mask all +interrupts up to and including the argument. + +The semantics are as follows: + +- The prologue is modified so that the Exception Program Counter (EPC) and + Status coprocessor registers are saved to the stack. The interrupt mask is + set so that the function can only be interrupted by a higher priority + interrupt. The epilogue will restore the previous values of EPC and Status. + +- The prologue and epilogue are modified to save and restore all non-kernel + registers as necessary. + +- The FPU is disabled in the prologue, as the floating pointer registers are not + spilled to the stack. + +- The function return sequence is changed to use an exception return instruction. + +- The parameter sets the interrupt mask for the function corresponding to the + interrupt level specified. If no mask is specified the interrupt mask + defaults to "eic". + + +interrupt (RISCV) +----------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``interrupt``","``gnu::interrupt``","","","","","Yes" + +Clang supports the GNU style ``__attribute__((interrupt))`` attribute on RISCV +targets. This attribute may be attached to a function definition and instructs +the backend to generate appropriate function entry/exit code so that it can be +used directly as an interrupt service routine. + +Permissible values for this parameter are ``user``, ``supervisor``, +and ``machine``. If there is no parameter, then it defaults to machine. + +Repeated interrupt attribute on the same declaration will cause a warning +to be emitted. In case of repeated declarations, the last one prevails. + +Refer to: +https://gcc.gnu.org/onlinedocs/gcc/RISC-V-Function-Attributes.html +https://riscv.org/specifications/privileged-isa/ +The RISC-V Instruction Set Manual Volume II: Privileged Architecture +Version 1.10. + + +kernel +------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``kernel``","","","","","","Yes" + +``__attribute__((kernel))`` is used to mark a ``kernel`` function in +RenderScript. + +In RenderScript, ``kernel`` functions are used to express data-parallel +computations. The RenderScript runtime efficiently parallelizes ``kernel`` +functions to run on computational resources such as multi-core CPUs and GPUs. +See the RenderScript_ documentation for more information. + +.. _RenderScript: https://developer.android.com/guide/topics/renderscript/compute.html + + +lifetimebound +------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``lifetimebound``","``clang::lifetimebound``","","","","","" + +The ``lifetimebound`` attribute indicates that a resource owned by +a function parameter or implicit object parameter +is retained by the return value of the annotated function +(or, for a parameter of a constructor, in the value of the constructed object). +It is only supported in C++. + +This attribute provides an experimental implementation of the facility +described in the C++ committee paper `P0936R0 `_, +and is subject to change as the design of the corresponding functionality +changes. + + +long_call, far +-------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``long_call`` |br| ``far``","``gnu::long_call`` |br| ``gnu::far``","","","","","Yes" + +Clang supports the ``__attribute__((long_call))``, ``__attribute__((far))``, +and ``__attribute__((near))`` attributes on MIPS targets. These attributes may +only be added to function declarations and change the code generated +by the compiler when directly calling the function. The ``near`` attribute +allows calls to the function to be made using the ``jal`` instruction, which +requires the function to be located in the same naturally aligned 256MB +segment as the caller. The ``long_call`` and ``far`` attributes are synonyms +and require the use of a different call sequence that works regardless +of the distance between the functions. + +These attributes have no effect for position-independent code. + +These attributes take priority over command line switches such +as ``-mlong-calls`` and ``-mno-long-calls``. + + +micromips +--------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``micromips``","``gnu::micromips``","","","","","Yes" + +Clang supports the GNU style ``__attribute__((micromips))`` and +``__attribute__((nomicromips))`` attributes on MIPS targets. These attributes +may be attached to a function definition and instructs the backend to generate +or not to generate microMIPS code for that function. + +These attributes override the `-mmicromips` and `-mno-micromips` options +on the command line. + + +mig_server_routine +------------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``mig_server_routine``","``clang::mig_server_routine``","``clang::mig_server_routine``","","","","Yes" + +The Mach Interface Generator release-on-success convention dictates +functions that follow it to only release arguments passed to them when they +return "success" (a ``kern_return_t`` error code that indicates that +no errors have occured). Otherwise the release is performed by the MIG client +that called the function. The annotation ``__attribute__((mig_server_routine))`` +is applied in order to specify which functions are expected to follow the +convention. This allows the Static Analyzer to find bugs caused by violations of +that convention. The attribute would normally appear on the forward declaration +of the actual server routine in the MIG server header, but it may also be +added to arbitrary functions that need to follow the same convention - for +example, a user can add them to auxiliary functions called by the server routine +that have their return value of type ``kern_return_t`` unconditionally returned +from the routine. The attribute can be applied to C++ methods, and in this case +it will be automatically applied to overrides if the method is virtual. The +attribute can also be written using C++11 syntax: ``[[mig::server_routine]]``. + + +min_vector_width +---------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``min_vector_width``","``clang::min_vector_width``","``clang::min_vector_width``","","","","Yes" + +Clang supports the ``__attribute__((min_vector_width(width)))`` attribute. This +attribute may be attached to a function and informs the backend that this +function desires vectors of at least this width to be generated. Target-specific +maximum vector widths still apply. This means even if you ask for something +larger than the target supports, you will only get what the target supports. +This attribute is meant to be a hint to control target heuristics that may +generate narrower vectors than what the target hardware supports. + +This is currently used by the X86 target to allow some CPUs that support 512-bit +vectors to be limited to using 256-bit vectors to avoid frequency penalties. +This is currently enabled with the ``-prefer-vector-width=256`` command line +option. The ``min_vector_width`` attribute can be used to prevent the backend +from trying to split vector operations to match the ``prefer-vector-width``. All +X86 vector intrinsics from x86intrin.h already set this attribute. Additionally, +use of any of the X86-specific vector builtins will implicitly set this +attribute on the calling function. The intent is that explicitly writing vector +code using the X86 intrinsics will prevent ``prefer-vector-width`` from +affecting the code. + + +no_builtin +---------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``no_builtin``","``clang::no_builtin``","``clang::no_builtin``","","","","Yes" + +.. Note:: This attribute is not yet fully implemented, it is validated but has +no effect on the generated code. + +The ``__attribute__((no_builtin))`` is similar to the ``-fno-builtin`` flag +except it is specific to the body of a function. The attribute may also be +applied to a virtual function but has no effect on the behavior of overriding +functions in a derived class. + +It accepts one or more strings corresponding to the specific names of the +builtins to disable (e.g. "memcpy", "memset"). +If the attribute is used without parameters it will disable all buitins at +once. + +.. code-block:: c++ + + // The compiler is not allowed to add any builtin to foo's body. + void foo(char* data, size_t count) __attribute__((no_builtin)) { + // The compiler is not allowed to convert the loop into + // `__builtin_memset(data, 0xFE, count);`. + for (size_t i = 0; i < count; ++i) + data[i] = 0xFE; + } + + // The compiler is not allowed to add the `memcpy` builtin to bar's body. + void bar(char* data, size_t count) __attribute__((no_builtin("memcpy"))) { + // The compiler is allowed to convert the loop into + // `__builtin_memset(data, 0xFE, count);` but cannot generate any + // `__builtin_memcpy` + for (size_t i = 0; i < count; ++i) + data[i] = 0xFE; + } + + +no_caller_saved_registers +------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``no_caller_saved_registers``","``gnu::no_caller_saved_registers``","","","","","" + +Use this attribute to indicate that the specified function has no +caller-saved registers. That is, all registers are callee-saved except for +registers used for passing parameters to the function or returning parameters +from the function. +The compiler saves and restores any modified registers that were not used for +passing or returning arguments to the function. + +The user can call functions specified with the 'no_caller_saved_registers' +attribute from an interrupt handler without saving and restoring all +call-clobbered registers. + +Note that 'no_caller_saved_registers' attribute is not a calling convention. +In fact, it only overrides the decision of which registers should be saved by +the caller, but not how the parameters are passed from the caller to the callee. + +For example: + + .. code-block:: c + + __attribute__ ((no_caller_saved_registers, fastcall)) + void f (int arg1, int arg2) { + ... + } + + In this case parameters 'arg1' and 'arg2' will be passed in registers. + In this case, on 32-bit x86 targets, the function 'f' will use ECX and EDX as + register parameters. However, it will not assume any scratch registers and + should save and restore any modified registers except for ECX and EDX. + + +no_sanitize +----------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``no_sanitize``","``clang::no_sanitize``","``clang::no_sanitize``","","","","Yes" + +Use the ``no_sanitize`` attribute on a function or a global variable +declaration to specify that a particular instrumentation or set of +instrumentations should not be applied. The attribute takes a list of +string literals, which have the same meaning as values accepted by the +``-fno-sanitize=`` flag. For example, +``__attribute__((no_sanitize("address", "thread")))`` specifies that +AddressSanitizer and ThreadSanitizer should not be applied to the +function or variable. + +See :ref:`Controlling Code Generation ` for a +full list of supported sanitizer flags. + + +no_sanitize_address, no_address_safety_analysis +----------------------------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``no_address_safety_analysis`` |br| ``no_sanitize_address`` |br| ``no_sanitize_thread`` |br| ``no_sanitize_memory``","``gnu::no_address_safety_analysis`` |br| ``gnu::no_sanitize_address`` |br| ``gnu::no_sanitize_thread`` |br| ``clang::no_sanitize_memory``","``clang::no_sanitize_memory``","","","","Yes" + +.. _langext-address_sanitizer: + +Use ``__attribute__((no_sanitize_address))`` on a function or a global +variable declaration to specify that address safety instrumentation +(e.g. AddressSanitizer) should not be applied. + + +no_sanitize_memory +------------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``no_address_safety_analysis`` |br| ``no_sanitize_address`` |br| ``no_sanitize_thread`` |br| ``no_sanitize_memory``","``gnu::no_address_safety_analysis`` |br| ``gnu::no_sanitize_address`` |br| ``gnu::no_sanitize_thread`` |br| ``clang::no_sanitize_memory``","``clang::no_sanitize_memory``","","","","Yes" + +.. _langext-memory_sanitizer: + +Use ``__attribute__((no_sanitize_memory))`` on a function declaration to +specify that checks for uninitialized memory should not be inserted +(e.g. by MemorySanitizer). The function may still be instrumented by the tool +to avoid false positives in other places. + + +no_sanitize_thread +------------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``no_address_safety_analysis`` |br| ``no_sanitize_address`` |br| ``no_sanitize_thread`` |br| ``no_sanitize_memory``","``gnu::no_address_safety_analysis`` |br| ``gnu::no_sanitize_address`` |br| ``gnu::no_sanitize_thread`` |br| ``clang::no_sanitize_memory``","``clang::no_sanitize_memory``","","","","Yes" + +.. _langext-thread_sanitizer: + +Use ``__attribute__((no_sanitize_thread))`` on a function declaration to +specify that checks for data races on plain (non-atomic) memory accesses should +not be inserted by ThreadSanitizer. The function is still instrumented by the +tool to avoid false positives and provide meaningful stack traces. + + +no_speculative_load_hardening +----------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``no_speculative_load_hardening``","``clang::no_speculative_load_hardening``","``clang::no_speculative_load_hardening``","","","","Yes" + +This attribute can be applied to a function declaration in order to indicate + that `Speculative Load Hardening `_ + is *not* needed for the function body. This can also be applied to a method + in Objective C. This attribute will take precedence over the command line flag in + the case where `-mspeculative-load-hardening `_ is specified. + + Warning: This attribute may not prevent Speculative Load Hardening from being + enabled for a function which inlines a function that has the + 'speculative_load_hardening' attribute. This is intended to provide a + maximally conservative model where the code that is marked with the + 'speculative_load_hardening' attribute will always (even when inlined) + be hardened. A user of this attribute may want to mark functions called by + a function they do not want to be hardened with the 'noinline' attribute. + + For example: + + .. code-block:: c + + __attribute__((speculative_load_hardening)) + int foo(int i) { + return i; + } + + // Note: bar() may still have speculative load hardening enabled if + // foo() is inlined into bar(). Mark foo() with __attribute__((noinline)) + // to avoid this situation. + __attribute__((no_speculative_load_hardening)) + int bar(int i) { + return foo(i); + } + + +no_split_stack +-------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``no_split_stack``","``gnu::no_split_stack``","","","","","Yes" + +The ``no_split_stack`` attribute disables the emission of the split stack +preamble for a particular function. It has no effect if ``-fsplit-stack`` +is not specified. + + +no_stack_protector +------------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``no_stack_protector``","``clang::no_stack_protector``","``clang::no_stack_protector``","","","","Yes" + +Clang supports the ``__attribute__((no_stack_protector))`` attribute which disables +the stack protector on the specified function. This attribute is useful for +selectively disabling the stack protector on some functions when building with +``-fstack-protector`` compiler option. + +For example, it disables the stack protector for the function ``foo`` but function +``bar`` will still be built with the stack protector with the ``-fstack-protector`` +option. + +.. code-block:: c + + int __attribute__((no_stack_protector)) + foo (int x); // stack protection will be disabled for foo. + + int bar(int y); // bar can be built with the stack protector. + + +noalias +------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "","","","``noalias``","","","" + +The ``noalias`` attribute indicates that the only memory accesses inside +function are loads and stores from objects pointed to by its pointer-typed +arguments, with arbitrary offsets. + + +nocf_check +---------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``nocf_check``","``gnu::nocf_check``","","","","","Yes" + +Jump Oriented Programming attacks rely on tampering with addresses used by +indirect call / jmp, e.g. redirect control-flow to non-programmer +intended bytes in the binary. +X86 Supports Indirect Branch Tracking (IBT) as part of Control-Flow +Enforcement Technology (CET). IBT instruments ENDBR instructions used to +specify valid targets of indirect call / jmp. +The ``nocf_check`` attribute has two roles: +1. Appertains to a function - do not add ENDBR instruction at the beginning of +the function. +2. Appertains to a function pointer - do not track the target function of this +pointer (by adding nocf_check prefix to the indirect-call instruction). + + +nodiscard, warn_unused_result +----------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``warn_unused_result``","``nodiscard`` |br| ``clang::warn_unused_result`` |br| ``gnu::warn_unused_result``","``nodiscard``","","","","Yes" + +Clang supports the ability to diagnose when the results of a function call +expression are discarded under suspicious circumstances. A diagnostic is +generated when a function or its return type is marked with ``[[nodiscard]]`` +(or ``__attribute__((warn_unused_result))``) and the function call appears as a +potentially-evaluated discarded-value expression that is not explicitly cast to +`void`. + +A string literal may optionally be provided to the attribute, which will be +reproduced in any resulting diagnostics. Redeclarations using different forms +of the attribute (with or without the string literal or with different string +literal contents) are allowed. If there are redeclarations of the entity with +differing string literals, it is unspecified which one will be used by Clang +in any resulting diagnostics. + +.. code-block: c++ + struct [[nodiscard]] error_info { /*...*/ }; + error_info enable_missile_safety_mode(); + + void launch_missiles(); + void test_missiles() { + enable_missile_safety_mode(); // diagnoses + launch_missiles(); + } + error_info &foo(); + void f() { foo(); } // Does not diagnose, error_info is a reference. + +Additionally, discarded temporaries resulting from a call to a constructor +marked with ``[[nodiscard]]`` or a constructor of a type marked +``[[nodiscard]]`` will also diagnose. This also applies to type conversions that +use the annotated ``[[nodiscard]]`` constructor or result in an annotated type. + +.. code-block: c++ + struct [[nodiscard]] marked_type {/*..*/ }; + struct marked_ctor { + [[nodiscard]] marked_ctor(); + marked_ctor(int); + }; + + struct S { + operator marked_type() const; + [[nodiscard]] operator int() const; + }; + + void usages() { + marked_type(); // diagnoses. + marked_ctor(); // diagnoses. + marked_ctor(3); // Does not diagnose, int constructor isn't marked nodiscard. + + S s; + static_cast(s); // diagnoses + (int)s; // diagnoses + } + + +noduplicate +----------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``noduplicate``","``clang::noduplicate``","``clang::noduplicate``","","","","Yes" + +The ``noduplicate`` attribute can be placed on function declarations to control +whether function calls to this function can be duplicated or not as a result of +optimizations. This is required for the implementation of functions with +certain special requirements, like the OpenCL "barrier" function, that might +need to be run concurrently by all the threads that are executing in lockstep +on the hardware. For example this attribute applied on the function +"nodupfunc" in the code below avoids that: + +.. code-block:: c + + void nodupfunc() __attribute__((noduplicate)); + // Setting it as a C++11 attribute is also valid + // void nodupfunc() [[clang::noduplicate]]; + void foo(); + void bar(); + + nodupfunc(); + if (a > n) { + foo(); + } else { + bar(); + } + +gets possibly modified by some optimizations into code similar to this: + +.. code-block:: c + + if (a > n) { + nodupfunc(); + foo(); + } else { + nodupfunc(); + bar(); + } + +where the call to "nodupfunc" is duplicated and sunk into the two branches +of the condition. + + +nomicromips +----------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``nomicromips``","``gnu::nomicromips``","","","","","Yes" + +Clang supports the GNU style ``__attribute__((micromips))`` and +``__attribute__((nomicromips))`` attributes on MIPS targets. These attributes +may be attached to a function definition and instructs the backend to generate +or not to generate microMIPS code for that function. + +These attributes override the `-mmicromips` and `-mno-micromips` options +on the command line. + + +noreturn +-------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "","``noreturn``","","","","","Yes" + +A function declared as ``[[noreturn]]`` shall not return to its caller. The +compiler will generate a diagnostic for a function declared as ``[[noreturn]]`` +that appears to be capable of returning to its caller. + + +not_tail_called +--------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``not_tail_called``","``clang::not_tail_called``","``clang::not_tail_called``","","","","Yes" + +The ``not_tail_called`` attribute prevents tail-call optimization on statically bound calls. It has no effect on indirect calls. Virtual functions, objective-c methods, and functions marked as ``always_inline`` cannot be marked as ``not_tail_called``. + +For example, it prevents tail-call optimization in the following case: + + .. code-block:: c + + int __attribute__((not_tail_called)) foo1(int); + + int foo2(int a) { + return foo1(a); // No tail-call optimization on direct calls. + } + +However, it doesn't prevent tail-call optimization in this case: + + .. code-block:: c + + int __attribute__((not_tail_called)) foo1(int); + + int foo2(int a) { + int (*fn)(int) = &foo1; + + // not_tail_called has no effect on an indirect call even if the call can be + // resolved at compile time. + return (*fn)(a); + } + +Marking virtual functions as ``not_tail_called`` is an error: + + .. code-block:: c++ + + class Base { + public: + // not_tail_called on a virtual function is an error. + [[clang::not_tail_called]] virtual int foo1(); + + virtual int foo2(); + + // Non-virtual functions can be marked ``not_tail_called``. + [[clang::not_tail_called]] int foo3(); + }; + + class Derived1 : public Base { + public: + int foo1() override; + + // not_tail_called on a virtual function is an error. + [[clang::not_tail_called]] int foo2() override; + }; + + +nothrow +------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``nothrow``","``gnu::nothrow``","","``nothrow``","","","Yes" + +Clang supports the GNU style ``__attribute__((nothrow))`` and Microsoft style +``__declspec(nothrow)`` attribute as an equivalent of `noexcept` on function +declarations. This attribute informs the compiler that the annotated function +does not throw an exception. This prevents exception-unwinding. This attribute +is particularly useful on functions in the C Standard Library that are +guaranteed to not throw an exception. + + +ns_consumed +----------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``ns_consumed``","``clang::ns_consumed``","``clang::ns_consumed``","","","","Yes" + +The behavior of a function with respect to reference counting for Foundation +(Objective-C), CoreFoundation (C) and OSObject (C++) is determined by a naming +convention (e.g. functions starting with "get" are assumed to return at +``+0``). + +It can be overriden using a family of the following attributes. In +Objective-C, the annotation ``__attribute__((ns_returns_retained))`` applied to +a function communicates that the object is returned at ``+1``, and the caller +is responsible for freeing it. +Similiarly, the annotation ``__attribute__((ns_returns_not_retained))`` +specifies that the object is returned at ``+0`` and the ownership remains with +the callee. +The annotation ``__attribute__((ns_consumes_self))`` specifies that +the Objective-C method call consumes the reference to ``self``, e.g. by +attaching it to a supplied parameter. +Additionally, parameters can have an annotation +``__attribute__((ns_consumed))``, which specifies that passing an owned object +as that parameter effectively transfers the ownership, and the caller is no +longer responsible for it. +These attributes affect code generation when interacting with ARC code, and +they are used by the Clang Static Analyzer. + +In C programs using CoreFoundation, a similar set of attributes: +``__attribute__((cf_returns_not_retained))``, +``__attribute__((cf_returns_retained))`` and ``__attribute__((cf_consumed))`` +have the same respective semantics when applied to CoreFoundation objects. +These attributes affect code generation when interacting with ARC code, and +they are used by the Clang Static Analyzer. + +Finally, in C++ interacting with XNU kernel (objects inheriting from OSObject), +the same attribute family is present: +``__attribute__((os_returns_not_retained))``, +``__attribute__((os_returns_retained))`` and ``__attribute__((os_consumed))``, +with the same respective semantics. +Similar to ``__attribute__((ns_consumes_self))``, +``__attribute__((os_consumes_this))`` specifies that the method call consumes +the reference to "this" (e.g., when attaching it to a different object supplied +as a parameter). +Out parameters (parameters the function is meant to write into, +either via pointers-to-pointers or references-to-pointers) +may be annotated with ``__attribute__((os_returns_retained))`` +or ``__attribute__((os_returns_not_retained))`` which specifies that the object +written into the out parameter should (or respectively should not) be released +after use. +Since often out parameters may or may not be written depending on the exit +code of the function, +annotations ``__attribute__((os_returns_retained_on_zero))`` +and ``__attribute__((os_returns_retained_on_non_zero))`` specify that +an out parameter at ``+1`` is written if and only if the function returns a zero +(respectively non-zero) error code. +Observe that return-code-dependent out parameter annotations are only +available for retained out parameters, as non-retained object do not have to be +released by the callee. +These attributes are only used by the Clang Static Analyzer. + +The family of attributes ``X_returns_X_retained`` can be added to functions, +C++ methods, and Objective-C methods and properties. +Attributes ``X_consumed`` can be added to parameters of methods, functions, +and Objective-C methods. + + +ns_consumes_self +---------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``ns_consumes_self``","``clang::ns_consumes_self``","``clang::ns_consumes_self``","","","","Yes" + +The behavior of a function with respect to reference counting for Foundation +(Objective-C), CoreFoundation (C) and OSObject (C++) is determined by a naming +convention (e.g. functions starting with "get" are assumed to return at +``+0``). + +It can be overriden using a family of the following attributes. In +Objective-C, the annotation ``__attribute__((ns_returns_retained))`` applied to +a function communicates that the object is returned at ``+1``, and the caller +is responsible for freeing it. +Similiarly, the annotation ``__attribute__((ns_returns_not_retained))`` +specifies that the object is returned at ``+0`` and the ownership remains with +the callee. +The annotation ``__attribute__((ns_consumes_self))`` specifies that +the Objective-C method call consumes the reference to ``self``, e.g. by +attaching it to a supplied parameter. +Additionally, parameters can have an annotation +``__attribute__((ns_consumed))``, which specifies that passing an owned object +as that parameter effectively transfers the ownership, and the caller is no +longer responsible for it. +These attributes affect code generation when interacting with ARC code, and +they are used by the Clang Static Analyzer. + +In C programs using CoreFoundation, a similar set of attributes: +``__attribute__((cf_returns_not_retained))``, +``__attribute__((cf_returns_retained))`` and ``__attribute__((cf_consumed))`` +have the same respective semantics when applied to CoreFoundation objects. +These attributes affect code generation when interacting with ARC code, and +they are used by the Clang Static Analyzer. + +Finally, in C++ interacting with XNU kernel (objects inheriting from OSObject), +the same attribute family is present: +``__attribute__((os_returns_not_retained))``, +``__attribute__((os_returns_retained))`` and ``__attribute__((os_consumed))``, +with the same respective semantics. +Similar to ``__attribute__((ns_consumes_self))``, +``__attribute__((os_consumes_this))`` specifies that the method call consumes +the reference to "this" (e.g., when attaching it to a different object supplied +as a parameter). +Out parameters (parameters the function is meant to write into, +either via pointers-to-pointers or references-to-pointers) +may be annotated with ``__attribute__((os_returns_retained))`` +or ``__attribute__((os_returns_not_retained))`` which specifies that the object +written into the out parameter should (or respectively should not) be released +after use. +Since often out parameters may or may not be written depending on the exit +code of the function, +annotations ``__attribute__((os_returns_retained_on_zero))`` +and ``__attribute__((os_returns_retained_on_non_zero))`` specify that +an out parameter at ``+1`` is written if and only if the function returns a zero +(respectively non-zero) error code. +Observe that return-code-dependent out parameter annotations are only +available for retained out parameters, as non-retained object do not have to be +released by the callee. +These attributes are only used by the Clang Static Analyzer. + +The family of attributes ``X_returns_X_retained`` can be added to functions, +C++ methods, and Objective-C methods and properties. +Attributes ``X_consumed`` can be added to parameters of methods, functions, +and Objective-C methods. + + +ns_returns_autoreleased +----------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``ns_returns_autoreleased``","``clang::ns_returns_autoreleased``","``clang::ns_returns_autoreleased``","","","","" + +The behavior of a function with respect to reference counting for Foundation +(Objective-C), CoreFoundation (C) and OSObject (C++) is determined by a naming +convention (e.g. functions starting with "get" are assumed to return at +``+0``). + +It can be overriden using a family of the following attributes. In +Objective-C, the annotation ``__attribute__((ns_returns_retained))`` applied to +a function communicates that the object is returned at ``+1``, and the caller +is responsible for freeing it. +Similiarly, the annotation ``__attribute__((ns_returns_not_retained))`` +specifies that the object is returned at ``+0`` and the ownership remains with +the callee. +The annotation ``__attribute__((ns_consumes_self))`` specifies that +the Objective-C method call consumes the reference to ``self``, e.g. by +attaching it to a supplied parameter. +Additionally, parameters can have an annotation +``__attribute__((ns_consumed))``, which specifies that passing an owned object +as that parameter effectively transfers the ownership, and the caller is no +longer responsible for it. +These attributes affect code generation when interacting with ARC code, and +they are used by the Clang Static Analyzer. + +In C programs using CoreFoundation, a similar set of attributes: +``__attribute__((cf_returns_not_retained))``, +``__attribute__((cf_returns_retained))`` and ``__attribute__((cf_consumed))`` +have the same respective semantics when applied to CoreFoundation objects. +These attributes affect code generation when interacting with ARC code, and +they are used by the Clang Static Analyzer. + +Finally, in C++ interacting with XNU kernel (objects inheriting from OSObject), +the same attribute family is present: +``__attribute__((os_returns_not_retained))``, +``__attribute__((os_returns_retained))`` and ``__attribute__((os_consumed))``, +with the same respective semantics. +Similar to ``__attribute__((ns_consumes_self))``, +``__attribute__((os_consumes_this))`` specifies that the method call consumes +the reference to "this" (e.g., when attaching it to a different object supplied +as a parameter). +Out parameters (parameters the function is meant to write into, +either via pointers-to-pointers or references-to-pointers) +may be annotated with ``__attribute__((os_returns_retained))`` +or ``__attribute__((os_returns_not_retained))`` which specifies that the object +written into the out parameter should (or respectively should not) be released +after use. +Since often out parameters may or may not be written depending on the exit +code of the function, +annotations ``__attribute__((os_returns_retained_on_zero))`` +and ``__attribute__((os_returns_retained_on_non_zero))`` specify that +an out parameter at ``+1`` is written if and only if the function returns a zero +(respectively non-zero) error code. +Observe that return-code-dependent out parameter annotations are only +available for retained out parameters, as non-retained object do not have to be +released by the callee. +These attributes are only used by the Clang Static Analyzer. + +The family of attributes ``X_returns_X_retained`` can be added to functions, +C++ methods, and Objective-C methods and properties. +Attributes ``X_consumed`` can be added to parameters of methods, functions, +and Objective-C methods. + + +ns_returns_not_retained +----------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``ns_returns_not_retained``","``clang::ns_returns_not_retained``","``clang::ns_returns_not_retained``","","","","" + +The behavior of a function with respect to reference counting for Foundation +(Objective-C), CoreFoundation (C) and OSObject (C++) is determined by a naming +convention (e.g. functions starting with "get" are assumed to return at +``+0``). + +It can be overriden using a family of the following attributes. In +Objective-C, the annotation ``__attribute__((ns_returns_retained))`` applied to +a function communicates that the object is returned at ``+1``, and the caller +is responsible for freeing it. +Similiarly, the annotation ``__attribute__((ns_returns_not_retained))`` +specifies that the object is returned at ``+0`` and the ownership remains with +the callee. +The annotation ``__attribute__((ns_consumes_self))`` specifies that +the Objective-C method call consumes the reference to ``self``, e.g. by +attaching it to a supplied parameter. +Additionally, parameters can have an annotation +``__attribute__((ns_consumed))``, which specifies that passing an owned object +as that parameter effectively transfers the ownership, and the caller is no +longer responsible for it. +These attributes affect code generation when interacting with ARC code, and +they are used by the Clang Static Analyzer. + +In C programs using CoreFoundation, a similar set of attributes: +``__attribute__((cf_returns_not_retained))``, +``__attribute__((cf_returns_retained))`` and ``__attribute__((cf_consumed))`` +have the same respective semantics when applied to CoreFoundation objects. +These attributes affect code generation when interacting with ARC code, and +they are used by the Clang Static Analyzer. + +Finally, in C++ interacting with XNU kernel (objects inheriting from OSObject), +the same attribute family is present: +``__attribute__((os_returns_not_retained))``, +``__attribute__((os_returns_retained))`` and ``__attribute__((os_consumed))``, +with the same respective semantics. +Similar to ``__attribute__((ns_consumes_self))``, +``__attribute__((os_consumes_this))`` specifies that the method call consumes +the reference to "this" (e.g., when attaching it to a different object supplied +as a parameter). +Out parameters (parameters the function is meant to write into, +either via pointers-to-pointers or references-to-pointers) +may be annotated with ``__attribute__((os_returns_retained))`` +or ``__attribute__((os_returns_not_retained))`` which specifies that the object +written into the out parameter should (or respectively should not) be released +after use. +Since often out parameters may or may not be written depending on the exit +code of the function, +annotations ``__attribute__((os_returns_retained_on_zero))`` +and ``__attribute__((os_returns_retained_on_non_zero))`` specify that +an out parameter at ``+1`` is written if and only if the function returns a zero +(respectively non-zero) error code. +Observe that return-code-dependent out parameter annotations are only +available for retained out parameters, as non-retained object do not have to be +released by the callee. +These attributes are only used by the Clang Static Analyzer. + +The family of attributes ``X_returns_X_retained`` can be added to functions, +C++ methods, and Objective-C methods and properties. +Attributes ``X_consumed`` can be added to parameters of methods, functions, +and Objective-C methods. + + +ns_returns_retained +------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``ns_returns_retained``","``clang::ns_returns_retained``","``clang::ns_returns_retained``","","","","" + +The behavior of a function with respect to reference counting for Foundation +(Objective-C), CoreFoundation (C) and OSObject (C++) is determined by a naming +convention (e.g. functions starting with "get" are assumed to return at +``+0``). + +It can be overriden using a family of the following attributes. In +Objective-C, the annotation ``__attribute__((ns_returns_retained))`` applied to +a function communicates that the object is returned at ``+1``, and the caller +is responsible for freeing it. +Similiarly, the annotation ``__attribute__((ns_returns_not_retained))`` +specifies that the object is returned at ``+0`` and the ownership remains with +the callee. +The annotation ``__attribute__((ns_consumes_self))`` specifies that +the Objective-C method call consumes the reference to ``self``, e.g. by +attaching it to a supplied parameter. +Additionally, parameters can have an annotation +``__attribute__((ns_consumed))``, which specifies that passing an owned object +as that parameter effectively transfers the ownership, and the caller is no +longer responsible for it. +These attributes affect code generation when interacting with ARC code, and +they are used by the Clang Static Analyzer. + +In C programs using CoreFoundation, a similar set of attributes: +``__attribute__((cf_returns_not_retained))``, +``__attribute__((cf_returns_retained))`` and ``__attribute__((cf_consumed))`` +have the same respective semantics when applied to CoreFoundation objects. +These attributes affect code generation when interacting with ARC code, and +they are used by the Clang Static Analyzer. + +Finally, in C++ interacting with XNU kernel (objects inheriting from OSObject), +the same attribute family is present: +``__attribute__((os_returns_not_retained))``, +``__attribute__((os_returns_retained))`` and ``__attribute__((os_consumed))``, +with the same respective semantics. +Similar to ``__attribute__((ns_consumes_self))``, +``__attribute__((os_consumes_this))`` specifies that the method call consumes +the reference to "this" (e.g., when attaching it to a different object supplied +as a parameter). +Out parameters (parameters the function is meant to write into, +either via pointers-to-pointers or references-to-pointers) +may be annotated with ``__attribute__((os_returns_retained))`` +or ``__attribute__((os_returns_not_retained))`` which specifies that the object +written into the out parameter should (or respectively should not) be released +after use. +Since often out parameters may or may not be written depending on the exit +code of the function, +annotations ``__attribute__((os_returns_retained_on_zero))`` +and ``__attribute__((os_returns_retained_on_non_zero))`` specify that +an out parameter at ``+1`` is written if and only if the function returns a zero +(respectively non-zero) error code. +Observe that return-code-dependent out parameter annotations are only +available for retained out parameters, as non-retained object do not have to be +released by the callee. +These attributes are only used by the Clang Static Analyzer. + +The family of attributes ``X_returns_X_retained`` can be added to functions, +C++ methods, and Objective-C methods and properties. +Attributes ``X_consumed`` can be added to parameters of methods, functions, +and Objective-C methods. + + +objc_method_family +------------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``objc_method_family``","``clang::objc_method_family``","``clang::objc_method_family``","","","","Yes" + +Many methods in Objective-C have conventional meanings determined by their +selectors. It is sometimes useful to be able to mark a method as having a +particular conventional meaning despite not having the right selector, or as +not having the conventional meaning that its selector would suggest. For these +use cases, we provide an attribute to specifically describe the "method family" +that a method belongs to. + +**Usage**: ``__attribute__((objc_method_family(X)))``, where ``X`` is one of +``none``, ``alloc``, ``copy``, ``init``, ``mutableCopy``, or ``new``. This +attribute can only be placed at the end of a method declaration: + +.. code-block:: objc + + - (NSString *)initMyStringValue __attribute__((objc_method_family(none))); + +Users who do not wish to change the conventional meaning of a method, and who +merely want to document its non-standard retain and release semantics, should +use the retaining behavior attributes (``ns_returns_retained``, +``ns_returns_not_retained``, etc). + +Query for this feature with ``__has_attribute(objc_method_family)``. + + +objc_requires_super +------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``objc_requires_super``","``clang::objc_requires_super``","``clang::objc_requires_super``","","","","Yes" + +Some Objective-C classes allow a subclass to override a particular method in a +parent class but expect that the overriding method also calls the overridden +method in the parent class. For these cases, we provide an attribute to +designate that a method requires a "call to ``super``" in the overriding +method in the subclass. + +**Usage**: ``__attribute__((objc_requires_super))``. This attribute can only +be placed at the end of a method declaration: + +.. code-block:: objc + + - (void)foo __attribute__((objc_requires_super)); + +This attribute can only be applied the method declarations within a class, and +not a protocol. Currently this attribute does not enforce any placement of +where the call occurs in the overriding method (such as in the case of +``-dealloc`` where the call must appear at the end). It checks only that it +exists. + +Note that on both OS X and iOS that the Foundation framework provides a +convenience macro ``NS_REQUIRES_SUPER`` that provides syntactic sugar for this +attribute: + +.. code-block:: objc + + - (void)foo NS_REQUIRES_SUPER; + +This macro is conditionally defined depending on the compiler's support for +this attribute. If the compiler does not support the attribute the macro +expands to nothing. + +Operationally, when a method has this annotation the compiler will warn if the +implementation of an override in a subclass does not call super. For example: + +.. code-block:: objc + + warning: method possibly missing a [super AnnotMeth] call + - (void) AnnotMeth{}; + ^ + + +optnone +------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``optnone``","``clang::optnone``","``clang::optnone``","","","","Yes" + +The ``optnone`` attribute suppresses essentially all optimizations +on a function or method, regardless of the optimization level applied to +the compilation unit as a whole. This is particularly useful when you +need to debug a particular function, but it is infeasible to build the +entire application without optimization. Avoiding optimization on the +specified function can improve the quality of the debugging information +for that function. + +This attribute is incompatible with the ``always_inline`` and ``minsize`` +attributes. + + +os_consumed +----------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``os_consumed``","``clang::os_consumed``","``clang::os_consumed``","","","","Yes" + +The behavior of a function with respect to reference counting for Foundation +(Objective-C), CoreFoundation (C) and OSObject (C++) is determined by a naming +convention (e.g. functions starting with "get" are assumed to return at +``+0``). + +It can be overriden using a family of the following attributes. In +Objective-C, the annotation ``__attribute__((ns_returns_retained))`` applied to +a function communicates that the object is returned at ``+1``, and the caller +is responsible for freeing it. +Similiarly, the annotation ``__attribute__((ns_returns_not_retained))`` +specifies that the object is returned at ``+0`` and the ownership remains with +the callee. +The annotation ``__attribute__((ns_consumes_self))`` specifies that +the Objective-C method call consumes the reference to ``self``, e.g. by +attaching it to a supplied parameter. +Additionally, parameters can have an annotation +``__attribute__((ns_consumed))``, which specifies that passing an owned object +as that parameter effectively transfers the ownership, and the caller is no +longer responsible for it. +These attributes affect code generation when interacting with ARC code, and +they are used by the Clang Static Analyzer. + +In C programs using CoreFoundation, a similar set of attributes: +``__attribute__((cf_returns_not_retained))``, +``__attribute__((cf_returns_retained))`` and ``__attribute__((cf_consumed))`` +have the same respective semantics when applied to CoreFoundation objects. +These attributes affect code generation when interacting with ARC code, and +they are used by the Clang Static Analyzer. + +Finally, in C++ interacting with XNU kernel (objects inheriting from OSObject), +the same attribute family is present: +``__attribute__((os_returns_not_retained))``, +``__attribute__((os_returns_retained))`` and ``__attribute__((os_consumed))``, +with the same respective semantics. +Similar to ``__attribute__((ns_consumes_self))``, +``__attribute__((os_consumes_this))`` specifies that the method call consumes +the reference to "this" (e.g., when attaching it to a different object supplied +as a parameter). +Out parameters (parameters the function is meant to write into, +either via pointers-to-pointers or references-to-pointers) +may be annotated with ``__attribute__((os_returns_retained))`` +or ``__attribute__((os_returns_not_retained))`` which specifies that the object +written into the out parameter should (or respectively should not) be released +after use. +Since often out parameters may or may not be written depending on the exit +code of the function, +annotations ``__attribute__((os_returns_retained_on_zero))`` +and ``__attribute__((os_returns_retained_on_non_zero))`` specify that +an out parameter at ``+1`` is written if and only if the function returns a zero +(respectively non-zero) error code. +Observe that return-code-dependent out parameter annotations are only +available for retained out parameters, as non-retained object do not have to be +released by the callee. +These attributes are only used by the Clang Static Analyzer. + +The family of attributes ``X_returns_X_retained`` can be added to functions, +C++ methods, and Objective-C methods and properties. +Attributes ``X_consumed`` can be added to parameters of methods, functions, +and Objective-C methods. + + +os_consumes_this +---------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``os_consumes_this``","``clang::os_consumes_this``","``clang::os_consumes_this``","","","","" + +The behavior of a function with respect to reference counting for Foundation +(Objective-C), CoreFoundation (C) and OSObject (C++) is determined by a naming +convention (e.g. functions starting with "get" are assumed to return at +``+0``). + +It can be overriden using a family of the following attributes. In +Objective-C, the annotation ``__attribute__((ns_returns_retained))`` applied to +a function communicates that the object is returned at ``+1``, and the caller +is responsible for freeing it. +Similiarly, the annotation ``__attribute__((ns_returns_not_retained))`` +specifies that the object is returned at ``+0`` and the ownership remains with +the callee. +The annotation ``__attribute__((ns_consumes_self))`` specifies that +the Objective-C method call consumes the reference to ``self``, e.g. by +attaching it to a supplied parameter. +Additionally, parameters can have an annotation +``__attribute__((ns_consumed))``, which specifies that passing an owned object +as that parameter effectively transfers the ownership, and the caller is no +longer responsible for it. +These attributes affect code generation when interacting with ARC code, and +they are used by the Clang Static Analyzer. + +In C programs using CoreFoundation, a similar set of attributes: +``__attribute__((cf_returns_not_retained))``, +``__attribute__((cf_returns_retained))`` and ``__attribute__((cf_consumed))`` +have the same respective semantics when applied to CoreFoundation objects. +These attributes affect code generation when interacting with ARC code, and +they are used by the Clang Static Analyzer. + +Finally, in C++ interacting with XNU kernel (objects inheriting from OSObject), +the same attribute family is present: +``__attribute__((os_returns_not_retained))``, +``__attribute__((os_returns_retained))`` and ``__attribute__((os_consumed))``, +with the same respective semantics. +Similar to ``__attribute__((ns_consumes_self))``, +``__attribute__((os_consumes_this))`` specifies that the method call consumes +the reference to "this" (e.g., when attaching it to a different object supplied +as a parameter). +Out parameters (parameters the function is meant to write into, +either via pointers-to-pointers or references-to-pointers) +may be annotated with ``__attribute__((os_returns_retained))`` +or ``__attribute__((os_returns_not_retained))`` which specifies that the object +written into the out parameter should (or respectively should not) be released +after use. +Since often out parameters may or may not be written depending on the exit +code of the function, +annotations ``__attribute__((os_returns_retained_on_zero))`` +and ``__attribute__((os_returns_retained_on_non_zero))`` specify that +an out parameter at ``+1`` is written if and only if the function returns a zero +(respectively non-zero) error code. +Observe that return-code-dependent out parameter annotations are only +available for retained out parameters, as non-retained object do not have to be +released by the callee. +These attributes are only used by the Clang Static Analyzer. + +The family of attributes ``X_returns_X_retained`` can be added to functions, +C++ methods, and Objective-C methods and properties. +Attributes ``X_consumed`` can be added to parameters of methods, functions, +and Objective-C methods. + + +os_returns_not_retained +----------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``os_returns_not_retained``","``clang::os_returns_not_retained``","``clang::os_returns_not_retained``","","","","Yes" + +The behavior of a function with respect to reference counting for Foundation +(Objective-C), CoreFoundation (C) and OSObject (C++) is determined by a naming +convention (e.g. functions starting with "get" are assumed to return at +``+0``). + +It can be overriden using a family of the following attributes. In +Objective-C, the annotation ``__attribute__((ns_returns_retained))`` applied to +a function communicates that the object is returned at ``+1``, and the caller +is responsible for freeing it. +Similiarly, the annotation ``__attribute__((ns_returns_not_retained))`` +specifies that the object is returned at ``+0`` and the ownership remains with +the callee. +The annotation ``__attribute__((ns_consumes_self))`` specifies that +the Objective-C method call consumes the reference to ``self``, e.g. by +attaching it to a supplied parameter. +Additionally, parameters can have an annotation +``__attribute__((ns_consumed))``, which specifies that passing an owned object +as that parameter effectively transfers the ownership, and the caller is no +longer responsible for it. +These attributes affect code generation when interacting with ARC code, and +they are used by the Clang Static Analyzer. + +In C programs using CoreFoundation, a similar set of attributes: +``__attribute__((cf_returns_not_retained))``, +``__attribute__((cf_returns_retained))`` and ``__attribute__((cf_consumed))`` +have the same respective semantics when applied to CoreFoundation objects. +These attributes affect code generation when interacting with ARC code, and +they are used by the Clang Static Analyzer. + +Finally, in C++ interacting with XNU kernel (objects inheriting from OSObject), +the same attribute family is present: +``__attribute__((os_returns_not_retained))``, +``__attribute__((os_returns_retained))`` and ``__attribute__((os_consumed))``, +with the same respective semantics. +Similar to ``__attribute__((ns_consumes_self))``, +``__attribute__((os_consumes_this))`` specifies that the method call consumes +the reference to "this" (e.g., when attaching it to a different object supplied +as a parameter). +Out parameters (parameters the function is meant to write into, +either via pointers-to-pointers or references-to-pointers) +may be annotated with ``__attribute__((os_returns_retained))`` +or ``__attribute__((os_returns_not_retained))`` which specifies that the object +written into the out parameter should (or respectively should not) be released +after use. +Since often out parameters may or may not be written depending on the exit +code of the function, +annotations ``__attribute__((os_returns_retained_on_zero))`` +and ``__attribute__((os_returns_retained_on_non_zero))`` specify that +an out parameter at ``+1`` is written if and only if the function returns a zero +(respectively non-zero) error code. +Observe that return-code-dependent out parameter annotations are only +available for retained out parameters, as non-retained object do not have to be +released by the callee. +These attributes are only used by the Clang Static Analyzer. + +The family of attributes ``X_returns_X_retained`` can be added to functions, +C++ methods, and Objective-C methods and properties. +Attributes ``X_consumed`` can be added to parameters of methods, functions, +and Objective-C methods. + + +os_returns_retained +------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``os_returns_retained``","``clang::os_returns_retained``","``clang::os_returns_retained``","","","","Yes" + +The behavior of a function with respect to reference counting for Foundation +(Objective-C), CoreFoundation (C) and OSObject (C++) is determined by a naming +convention (e.g. functions starting with "get" are assumed to return at +``+0``). + +It can be overriden using a family of the following attributes. In +Objective-C, the annotation ``__attribute__((ns_returns_retained))`` applied to +a function communicates that the object is returned at ``+1``, and the caller +is responsible for freeing it. +Similiarly, the annotation ``__attribute__((ns_returns_not_retained))`` +specifies that the object is returned at ``+0`` and the ownership remains with +the callee. +The annotation ``__attribute__((ns_consumes_self))`` specifies that +the Objective-C method call consumes the reference to ``self``, e.g. by +attaching it to a supplied parameter. +Additionally, parameters can have an annotation +``__attribute__((ns_consumed))``, which specifies that passing an owned object +as that parameter effectively transfers the ownership, and the caller is no +longer responsible for it. +These attributes affect code generation when interacting with ARC code, and +they are used by the Clang Static Analyzer. + +In C programs using CoreFoundation, a similar set of attributes: +``__attribute__((cf_returns_not_retained))``, +``__attribute__((cf_returns_retained))`` and ``__attribute__((cf_consumed))`` +have the same respective semantics when applied to CoreFoundation objects. +These attributes affect code generation when interacting with ARC code, and +they are used by the Clang Static Analyzer. + +Finally, in C++ interacting with XNU kernel (objects inheriting from OSObject), +the same attribute family is present: +``__attribute__((os_returns_not_retained))``, +``__attribute__((os_returns_retained))`` and ``__attribute__((os_consumed))``, +with the same respective semantics. +Similar to ``__attribute__((ns_consumes_self))``, +``__attribute__((os_consumes_this))`` specifies that the method call consumes +the reference to "this" (e.g., when attaching it to a different object supplied +as a parameter). +Out parameters (parameters the function is meant to write into, +either via pointers-to-pointers or references-to-pointers) +may be annotated with ``__attribute__((os_returns_retained))`` +or ``__attribute__((os_returns_not_retained))`` which specifies that the object +written into the out parameter should (or respectively should not) be released +after use. +Since often out parameters may or may not be written depending on the exit +code of the function, +annotations ``__attribute__((os_returns_retained_on_zero))`` +and ``__attribute__((os_returns_retained_on_non_zero))`` specify that +an out parameter at ``+1`` is written if and only if the function returns a zero +(respectively non-zero) error code. +Observe that return-code-dependent out parameter annotations are only +available for retained out parameters, as non-retained object do not have to be +released by the callee. +These attributes are only used by the Clang Static Analyzer. + +The family of attributes ``X_returns_X_retained`` can be added to functions, +C++ methods, and Objective-C methods and properties. +Attributes ``X_consumed`` can be added to parameters of methods, functions, +and Objective-C methods. + + +os_returns_retained_on_non_zero +------------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``os_returns_retained_on_non_zero``","``clang::os_returns_retained_on_non_zero``","``clang::os_returns_retained_on_non_zero``","","","","Yes" + +The behavior of a function with respect to reference counting for Foundation +(Objective-C), CoreFoundation (C) and OSObject (C++) is determined by a naming +convention (e.g. functions starting with "get" are assumed to return at +``+0``). + +It can be overriden using a family of the following attributes. In +Objective-C, the annotation ``__attribute__((ns_returns_retained))`` applied to +a function communicates that the object is returned at ``+1``, and the caller +is responsible for freeing it. +Similiarly, the annotation ``__attribute__((ns_returns_not_retained))`` +specifies that the object is returned at ``+0`` and the ownership remains with +the callee. +The annotation ``__attribute__((ns_consumes_self))`` specifies that +the Objective-C method call consumes the reference to ``self``, e.g. by +attaching it to a supplied parameter. +Additionally, parameters can have an annotation +``__attribute__((ns_consumed))``, which specifies that passing an owned object +as that parameter effectively transfers the ownership, and the caller is no +longer responsible for it. +These attributes affect code generation when interacting with ARC code, and +they are used by the Clang Static Analyzer. + +In C programs using CoreFoundation, a similar set of attributes: +``__attribute__((cf_returns_not_retained))``, +``__attribute__((cf_returns_retained))`` and ``__attribute__((cf_consumed))`` +have the same respective semantics when applied to CoreFoundation objects. +These attributes affect code generation when interacting with ARC code, and +they are used by the Clang Static Analyzer. + +Finally, in C++ interacting with XNU kernel (objects inheriting from OSObject), +the same attribute family is present: +``__attribute__((os_returns_not_retained))``, +``__attribute__((os_returns_retained))`` and ``__attribute__((os_consumed))``, +with the same respective semantics. +Similar to ``__attribute__((ns_consumes_self))``, +``__attribute__((os_consumes_this))`` specifies that the method call consumes +the reference to "this" (e.g., when attaching it to a different object supplied +as a parameter). +Out parameters (parameters the function is meant to write into, +either via pointers-to-pointers or references-to-pointers) +may be annotated with ``__attribute__((os_returns_retained))`` +or ``__attribute__((os_returns_not_retained))`` which specifies that the object +written into the out parameter should (or respectively should not) be released +after use. +Since often out parameters may or may not be written depending on the exit +code of the function, +annotations ``__attribute__((os_returns_retained_on_zero))`` +and ``__attribute__((os_returns_retained_on_non_zero))`` specify that +an out parameter at ``+1`` is written if and only if the function returns a zero +(respectively non-zero) error code. +Observe that return-code-dependent out parameter annotations are only +available for retained out parameters, as non-retained object do not have to be +released by the callee. +These attributes are only used by the Clang Static Analyzer. + +The family of attributes ``X_returns_X_retained`` can be added to functions, +C++ methods, and Objective-C methods and properties. +Attributes ``X_consumed`` can be added to parameters of methods, functions, +and Objective-C methods. + + +os_returns_retained_on_zero +--------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``os_returns_retained_on_zero``","``clang::os_returns_retained_on_zero``","``clang::os_returns_retained_on_zero``","","","","Yes" + +The behavior of a function with respect to reference counting for Foundation +(Objective-C), CoreFoundation (C) and OSObject (C++) is determined by a naming +convention (e.g. functions starting with "get" are assumed to return at +``+0``). + +It can be overriden using a family of the following attributes. In +Objective-C, the annotation ``__attribute__((ns_returns_retained))`` applied to +a function communicates that the object is returned at ``+1``, and the caller +is responsible for freeing it. +Similiarly, the annotation ``__attribute__((ns_returns_not_retained))`` +specifies that the object is returned at ``+0`` and the ownership remains with +the callee. +The annotation ``__attribute__((ns_consumes_self))`` specifies that +the Objective-C method call consumes the reference to ``self``, e.g. by +attaching it to a supplied parameter. +Additionally, parameters can have an annotation +``__attribute__((ns_consumed))``, which specifies that passing an owned object +as that parameter effectively transfers the ownership, and the caller is no +longer responsible for it. +These attributes affect code generation when interacting with ARC code, and +they are used by the Clang Static Analyzer. + +In C programs using CoreFoundation, a similar set of attributes: +``__attribute__((cf_returns_not_retained))``, +``__attribute__((cf_returns_retained))`` and ``__attribute__((cf_consumed))`` +have the same respective semantics when applied to CoreFoundation objects. +These attributes affect code generation when interacting with ARC code, and +they are used by the Clang Static Analyzer. + +Finally, in C++ interacting with XNU kernel (objects inheriting from OSObject), +the same attribute family is present: +``__attribute__((os_returns_not_retained))``, +``__attribute__((os_returns_retained))`` and ``__attribute__((os_consumed))``, +with the same respective semantics. +Similar to ``__attribute__((ns_consumes_self))``, +``__attribute__((os_consumes_this))`` specifies that the method call consumes +the reference to "this" (e.g., when attaching it to a different object supplied +as a parameter). +Out parameters (parameters the function is meant to write into, +either via pointers-to-pointers or references-to-pointers) +may be annotated with ``__attribute__((os_returns_retained))`` +or ``__attribute__((os_returns_not_retained))`` which specifies that the object +written into the out parameter should (or respectively should not) be released +after use. +Since often out parameters may or may not be written depending on the exit +code of the function, +annotations ``__attribute__((os_returns_retained_on_zero))`` +and ``__attribute__((os_returns_retained_on_non_zero))`` specify that +an out parameter at ``+1`` is written if and only if the function returns a zero +(respectively non-zero) error code. +Observe that return-code-dependent out parameter annotations are only +available for retained out parameters, as non-retained object do not have to be +released by the callee. +These attributes are only used by the Clang Static Analyzer. + +The family of attributes ``X_returns_X_retained`` can be added to functions, +C++ methods, and Objective-C methods and properties. +Attributes ``X_consumed`` can be added to parameters of methods, functions, +and Objective-C methods. + + +overloadable +------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``overloadable``","``clang::overloadable``","``clang::overloadable``","","","","Yes" + +Clang provides support for C++ function overloading in C. Function overloading +in C is introduced using the ``overloadable`` attribute. For example, one +might provide several overloaded versions of a ``tgsin`` function that invokes +the appropriate standard function computing the sine of a value with ``float``, +``double``, or ``long double`` precision: + +.. code-block:: c + + #include + float __attribute__((overloadable)) tgsin(float x) { return sinf(x); } + double __attribute__((overloadable)) tgsin(double x) { return sin(x); } + long double __attribute__((overloadable)) tgsin(long double x) { return sinl(x); } + +Given these declarations, one can call ``tgsin`` with a ``float`` value to +receive a ``float`` result, with a ``double`` to receive a ``double`` result, +etc. Function overloading in C follows the rules of C++ function overloading +to pick the best overload given the call arguments, with a few C-specific +semantics: + +* Conversion from ``float`` or ``double`` to ``long double`` is ranked as a + floating-point promotion (per C99) rather than as a floating-point conversion + (as in C++). + +* A conversion from a pointer of type ``T*`` to a pointer of type ``U*`` is + considered a pointer conversion (with conversion rank) if ``T`` and ``U`` are + compatible types. + +* A conversion from type ``T`` to a value of type ``U`` is permitted if ``T`` + and ``U`` are compatible types. This conversion is given "conversion" rank. + +* If no viable candidates are otherwise available, we allow a conversion from a + pointer of type ``T*`` to a pointer of type ``U*``, where ``T`` and ``U`` are + incompatible. This conversion is ranked below all other types of conversions. + Please note: ``U`` lacking qualifiers that are present on ``T`` is sufficient + for ``T`` and ``U`` to be incompatible. + +The declaration of ``overloadable`` functions is restricted to function +declarations and definitions. If a function is marked with the ``overloadable`` +attribute, then all declarations and definitions of functions with that name, +except for at most one (see the note below about unmarked overloads), must have +the ``overloadable`` attribute. In addition, redeclarations of a function with +the ``overloadable`` attribute must have the ``overloadable`` attribute, and +redeclarations of a function without the ``overloadable`` attribute must *not* +have the ``overloadable`` attribute. e.g., + +.. code-block:: c + + int f(int) __attribute__((overloadable)); + float f(float); // error: declaration of "f" must have the "overloadable" attribute + int f(int); // error: redeclaration of "f" must have the "overloadable" attribute + + int g(int) __attribute__((overloadable)); + int g(int) { } // error: redeclaration of "g" must also have the "overloadable" attribute + + int h(int); + int h(int) __attribute__((overloadable)); // error: declaration of "h" must not + // have the "overloadable" attribute + +Functions marked ``overloadable`` must have prototypes. Therefore, the +following code is ill-formed: + +.. code-block:: c + + int h() __attribute__((overloadable)); // error: h does not have a prototype + +However, ``overloadable`` functions are allowed to use a ellipsis even if there +are no named parameters (as is permitted in C++). This feature is particularly +useful when combined with the ``unavailable`` attribute: + +.. code-block:: c++ + + void honeypot(...) __attribute__((overloadable, unavailable)); // calling me is an error + +Functions declared with the ``overloadable`` attribute have their names mangled +according to the same rules as C++ function names. For example, the three +``tgsin`` functions in our motivating example get the mangled names +``_Z5tgsinf``, ``_Z5tgsind``, and ``_Z5tgsine``, respectively. There are two +caveats to this use of name mangling: + +* Future versions of Clang may change the name mangling of functions overloaded + in C, so you should not depend on an specific mangling. To be completely + safe, we strongly urge the use of ``static inline`` with ``overloadable`` + functions. + +* The ``overloadable`` attribute has almost no meaning when used in C++, + because names will already be mangled and functions are already overloadable. + However, when an ``overloadable`` function occurs within an ``extern "C"`` + linkage specification, it's name *will* be mangled in the same way as it + would in C. + +For the purpose of backwards compatibility, at most one function with the same +name as other ``overloadable`` functions may omit the ``overloadable`` +attribute. In this case, the function without the ``overloadable`` attribute +will not have its name mangled. + +For example: + +.. code-block:: c + + // Notes with mangled names assume Itanium mangling. + int f(int); + int f(double) __attribute__((overloadable)); + void foo() { + f(5); // Emits a call to f (not _Z1fi, as it would with an overload that + // was marked with overloadable). + f(1.0); // Emits a call to _Z1fd. + } + +Support for unmarked overloads is not present in some versions of clang. You may +query for it using ``__has_extension(overloadable_unmarked)``. + +Query for this attribute with ``__has_attribute(overloadable)``. + + +patchable_function_entry +------------------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``patchable_function_entry``","``gnu::patchable_function_entry``","","","","","Yes" + +``__attribute__((patchable_function_entry(N,M)))`` is used to generate M NOPs +before the function entry and N-M NOPs after the function entry. This attribute +takes precedence over the command line option ``-fpatchable-function-entry=N,M``. +``M`` defaults to 0 if omitted. + + +preserve_access_index +--------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``preserve_access_index``","``clang::preserve_access_index``","``clang::preserve_access_index``","","","","Yes" + +Clang supports the ``__attribute__((preserve_access_index))`` +attribute for the BPF target. This attribute may be attached to a +struct or union declaration, where if -g is specified, it enables +preserving struct or union member access debuginfo indicies of this +struct or union, similar to clang ``__builtin_preserve_acceess_index()``. + + +reinitializes +------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``reinitializes``","``clang::reinitializes``","","","","","" + +The ``reinitializes`` attribute can be applied to a non-static, non-const C++ +member function to indicate that this member function reinitializes the entire +object to a known state, independent of the previous state of the object. + +This attribute can be interpreted by static analyzers that warn about uses of an +object that has been left in an indeterminate state by a move operation. If a +member function marked with the ``reinitializes`` attribute is called on a +moved-from object, the analyzer can conclude that the object is no longer in an +indeterminate state. + +A typical example where this attribute would be used is on functions that clear +a container class: + +.. code-block:: c++ + + template + class Container { + public: + ... + [[clang::reinitializes]] void Clear(); + ... + }; + + +release_capability, release_shared_capability +--------------------------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``release_capability`` |br| ``release_shared_capability`` |br| ``release_generic_capability`` |br| ``unlock_function``","``clang::release_capability`` |br| ``clang::release_shared_capability`` |br| ``clang::release_generic_capability`` |br| ``clang::unlock_function``","","","","","" + +Marks a function as releasing a capability. + + +short_call, near +---------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``short_call`` |br| ``near``","``gnu::short_call`` |br| ``gnu::near``","","","","","Yes" + +Clang supports the ``__attribute__((long_call))``, ``__attribute__((far))``, +``__attribute__((short__call))``, and ``__attribute__((near))`` attributes +on MIPS targets. These attributes may only be added to function declarations +and change the code generated by the compiler when directly calling +the function. The ``short_call`` and ``near`` attributes are synonyms and +allow calls to the function to be made using the ``jal`` instruction, which +requires the function to be located in the same naturally aligned 256MB segment +as the caller. The ``long_call`` and ``far`` attributes are synonyms and +require the use of a different call sequence that works regardless +of the distance between the functions. + +These attributes have no effect for position-independent code. + +These attributes take priority over command line switches such +as ``-mlong-calls`` and ``-mno-long-calls``. + + +signal +------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``signal``","``gnu::signal``","","","","","Yes" + +Clang supports the GNU style ``__attribute__((signal))`` attribute on +AVR targets. This attribute may be attached to a function definition and instructs +the backend to generate appropriate function entry/exit code so that it can be used +directly as an interrupt service routine. + +Interrupt handler functions defined with the signal attribute do not re-enable interrupts. + + +speculative_load_hardening +-------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``speculative_load_hardening``","``clang::speculative_load_hardening``","``clang::speculative_load_hardening``","","","","Yes" + +This attribute can be applied to a function declaration in order to indicate + that `Speculative Load Hardening `_ + should be enabled for the function body. This can also be applied to a method + in Objective C. This attribute will take precedence over the command line flag in + the case where `-mno-speculative-load-hardening `_ is specified. + + Speculative Load Hardening is a best-effort mitigation against + information leak attacks that make use of control flow + miss-speculation - specifically miss-speculation of whether a branch + is taken or not. Typically vulnerabilities enabling such attacks are + classified as "Spectre variant #1". Notably, this does not attempt to + mitigate against miss-speculation of branch target, classified as + "Spectre variant #2" vulnerabilities. + + When inlining, the attribute is sticky. Inlining a function that + carries this attribute will cause the caller to gain the + attribute. This is intended to provide a maximally conservative model + where the code in a function annotated with this attribute will always + (even after inlining) end up hardened. + + +sycl_kernel +----------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``sycl_kernel``","``clang::sycl_kernel``","``clang::sycl_kernel``","","","","" + +The ``sycl_kernel`` attribute specifies that a function template will be used +to outline device code and to generate an OpenCL kernel. +Here is a code example of the SYCL program, which demonstrates the compiler's +outlining job: +.. code-block:: c++ + + int foo(int x) { return ++x; } + + using namespace cl::sycl; + queue Q; + buffer a(range<1>{1024}); + Q.submit([&](handler& cgh) { + auto A = a.get_access(cgh); + cgh.parallel_for(range<1>{1024}, [=](id<1> index) { + A[index] = index[0] + foo(42); + }); + } + +A C++ function object passed to the ``parallel_for`` is called a "SYCL kernel". +A SYCL kernel defines the entry point to the "device part" of the code. The +compiler will emit all symbols accessible from a "kernel". In this code +example, the compiler will emit "foo" function. More details about the +compilation of functions for the device part can be found in the SYCL 1.2.1 +specification Section 6.4. +To show to the compiler entry point to the "device part" of the code, the SYCL +runtime can use the ``sycl_kernel`` attribute in the following way: +.. code-block:: c++ +namespace cl { +namespace sycl { +class handler { + template + __attribute__((sycl_kernel)) void sycl_kernel_function(KernelType KernelFuncObj) { + // ... + KernelFuncObj(); + } + + template + void parallel_for(range NumWorkItems, KernelType KernelFunc) { +#ifdef __SYCL_DEVICE_ONLY__ + sycl_kernel_function(KernelFunc); +#else + // Host implementation +#endif + } +}; +} // namespace sycl +} // namespace cl + +The compiler will also generate an OpenCL kernel using the function marked with +the ``sycl_kernel`` attribute. +Here is the list of SYCL device compiler expectations with regard to the +function marked with the ``sycl_kernel`` attribute: + +- The function must be a template with at least two type template parameters. + The compiler generates an OpenCL kernel and uses the first template parameter + as a unique name for the generated OpenCL kernel. The host application uses + this unique name to invoke the OpenCL kernel generated for the SYCL kernel + specialized by this name and second template parameter ``KernelType`` (which + might be an unnamed function object type). +- The function must have at least one parameter. The first parameter is + required to be a function object type (named or unnamed i.e. lambda). The + compiler uses function object type fields to generate OpenCL kernel + parameters. +- The function must return void. The compiler reuses the body of marked functions to + generate the OpenCL kernel body, and the OpenCL kernel must return `void`. + +The SYCL kernel in the previous code sample meets these expectations. + + +target +------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``target``","``gnu::target``","","","","","Yes" + +Clang supports the GNU style ``__attribute__((target("OPTIONS")))`` attribute. +This attribute may be attached to a function definition and instructs +the backend to use different code generation options than were passed on the +command line. + +The current set of options correspond to the existing "subtarget features" for +the target with or without a "-mno-" in front corresponding to the absence +of the feature, as well as ``arch="CPU"`` which will change the default "CPU" +for the function. + +For AArch64, the attribute also allows the "branch-protection=" option, +where the permissible arguments and their effect on code generation are the same +as for the command-line option ``-mbranch-protection``. + +Example "subtarget features" from the x86 backend include: "mmx", "sse", "sse4.2", +"avx", "xop" and largely correspond to the machine specific options handled by +the front end. + +Additionally, this attribute supports function multiversioning for ELF based +x86/x86-64 targets, which can be used to create multiple implementations of the +same function that will be resolved at runtime based on the priority of their +``target`` attribute strings. A function is considered a multiversioned function +if either two declarations of the function have different ``target`` attribute +strings, or if it has a ``target`` attribute string of ``default``. For +example: + + .. code-block:: c++ + + __attribute__((target("arch=atom"))) + void foo() {} // will be called on 'atom' processors. + __attribute__((target("default"))) + void foo() {} // will be called on any other processors. + +All multiversioned functions must contain a ``default`` (fallback) +implementation, otherwise usages of the function are considered invalid. +Additionally, a function may not become multiversioned after its first use. + + +try_acquire_capability, try_acquire_shared_capability +----------------------------------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``try_acquire_capability`` |br| ``try_acquire_shared_capability``","``clang::try_acquire_capability`` |br| ``clang::try_acquire_shared_capability``","","","","","" + +Marks a function that attempts to acquire a capability. This function may fail to +actually acquire the capability; they accept a Boolean value determining +whether acquiring the capability means success (true), or failing to acquire +the capability means success (false). + + +xray_always_instrument, xray_never_instrument, xray_log_args +------------------------------------------------------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``xray_always_instrument`` |br| ``xray_never_instrument``","``clang::xray_always_instrument`` |br| ``clang::xray_never_instrument``","``clang::xray_always_instrument`` |br| ``clang::xray_never_instrument``","","","","Yes" + +``__attribute__((xray_always_instrument))`` or ``[[clang::xray_always_instrument]]`` is used to mark member functions (in C++), methods (in Objective C), and free functions (in C, C++, and Objective C) to be instrumented with XRay. This will cause the function to always have space at the beginning and exit points to allow for runtime patching. + +Conversely, ``__attribute__((xray_never_instrument))`` or ``[[clang::xray_never_instrument]]`` will inhibit the insertion of these instrumentation points. + +If a function has neither of these attributes, they become subject to the XRay heuristics used to determine whether a function should be instrumented or otherwise. + +``__attribute__((xray_log_args(N)))`` or ``[[clang::xray_log_args(N)]]`` is used to preserve N function arguments for the logging function. Currently, only N==1 is supported. + + +xray_always_instrument, xray_never_instrument, xray_log_args +------------------------------------------------------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``xray_log_args``","``clang::xray_log_args``","``clang::xray_log_args``","","","","Yes" + +``__attribute__((xray_always_instrument))`` or ``[[clang::xray_always_instrument]]`` is used to mark member functions (in C++), methods (in Objective C), and free functions (in C, C++, and Objective C) to be instrumented with XRay. This will cause the function to always have space at the beginning and exit points to allow for runtime patching. + +Conversely, ``__attribute__((xray_never_instrument))`` or ``[[clang::xray_never_instrument]]`` will inhibit the insertion of these instrumentation points. + +If a function has neither of these attributes, they become subject to the XRay heuristics used to determine whether a function should be instrumented or otherwise. + +``__attribute__((xray_log_args(N)))`` or ``[[clang::xray_log_args(N)]]`` is used to preserve N function arguments for the logging function. Currently, only N==1 is supported. + + +Variable Attributes +=================== + + +always_destroy +-------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``always_destroy``","``clang::always_destroy``","","","","","Yes" + +The ``always_destroy`` attribute specifies that a variable with static or thread +storage duration should have its exit-time destructor run. This attribute is the +default unless clang was invoked with -fno-c++-static-destructors. + + +dllexport +--------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``dllexport``","``gnu::dllexport``","","``dllexport``","","","Yes" + +The ``__declspec(dllexport)`` attribute declares a variable, function, or +Objective-C interface to be exported from the module. It is available under the +``-fdeclspec`` flag for compatibility with various compilers. The primary use +is for COFF object files which explicitly specify what interfaces are available +for external use. See the dllexport_ documentation on MSDN for more +information. + +.. _dllexport: https://msdn.microsoft.com/en-us/library/3y1sfaz2.aspx + + +dllimport +--------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``dllimport``","``gnu::dllimport``","","``dllimport``","","","Yes" + +The ``__declspec(dllimport)`` attribute declares a variable, function, or +Objective-C interface to be imported from an external module. It is available +under the ``-fdeclspec`` flag for compatibility with various compilers. The +primary use is for COFF object files which explicitly specify what interfaces +are imported from external modules. See the dllimport_ documentation on MSDN +for more information. + +.. _dllimport: https://msdn.microsoft.com/en-us/library/3y1sfaz2.aspx + + +init_seg +-------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "","","","","","``init_seg``","" + +The attribute applied by ``pragma init_seg()`` controls the section into +which global initialization function pointers are emitted. It is only +available with ``-fms-extensions``. Typically, this function pointer is +emitted into ``.CRT$XCU`` on Windows. The user can change the order of +initialization by using a different section name with the same +``.CRT$XC`` prefix and a suffix that sorts lexicographically before or +after the standard ``.CRT$XCU`` sections. See the init_seg_ +documentation on MSDN for more information. + +.. _init_seg: http://msdn.microsoft.com/en-us/library/7977wcck(v=vs.110).aspx + + +maybe_unused, unused +-------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``unused``","``maybe_unused`` |br| ``gnu::unused``","``maybe_unused``","","","","" + +When passing the ``-Wunused`` flag to Clang, entities that are unused by the +program may be diagnosed. The ``[[maybe_unused]]`` (or +``__attribute__((unused))``) attribute can be used to silence such diagnostics +when the entity cannot be removed. For instance, a local variable may exist +solely for use in an ``assert()`` statement, which makes the local variable +unused when ``NDEBUG`` is defined. + +The attribute may be applied to the declaration of a class, a typedef, a +variable, a function or method, a function parameter, an enumeration, an +enumerator, a non-static data member, or a label. + +.. code-block: c++ + #include + + [[maybe_unused]] void f([[maybe_unused]] bool thing1, + [[maybe_unused]] bool thing2) { + [[maybe_unused]] bool b = thing1 && thing2; + assert(b); + } + + +no_destroy +---------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``no_destroy``","``clang::no_destroy``","","","","","Yes" + +The ``no_destroy`` attribute specifies that a variable with static or thread +storage duration shouldn't have its exit-time destructor run. Annotating every +static and thread duration variable with this attribute is equivalent to +invoking clang with -fno-c++-static-destructors. + +If a variable is declared with this attribute, clang doesn't access check or +generate the type's destructor. If you have a type that you only want to be +annotated with ``no_destroy``, you can therefore declare the destructor private: + +.. code-block:: c++ + + struct only_no_destroy { + only_no_destroy(); + private: + ~only_no_destroy(); + }; + + [[clang::no_destroy]] only_no_destroy global; // fine! + +Note that destructors are still required for subobjects of aggregates annotated +with this attribute. This is because previously constructed subobjects need to +be destroyed if an exception gets thrown before the initialization of the +complete object is complete. For instance: + +.. code-block::c++ + + void f() { + try { + [[clang::no_destroy]] + static only_no_destroy array[10]; // error, only_no_destroy has a private destructor. + } catch (...) { + // Handle the error + } + } + +Here, if the construction of `array[9]` fails with an exception, `array[0..8]` +will be destroyed, so the element's destructor needs to be accessible. + + +nodebug +------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``nodebug``","``gnu::nodebug``","","","","","Yes" + +The ``nodebug`` attribute allows you to suppress debugging information for a +function or method, or for a variable that is not a parameter or a non-static +data member. + + +noescape +-------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``noescape``","``clang::noescape``","``clang::noescape``","","","","Yes" + +``noescape`` placed on a function parameter of a pointer type is used to inform +the compiler that the pointer cannot escape: that is, no reference to the object +the pointer points to that is derived from the parameter value will survive +after the function returns. Users are responsible for making sure parameters +annotated with ``noescape`` do not actuallly escape. + +For example: + +.. code-block:: c + + int *gp; + + void nonescapingFunc(__attribute__((noescape)) int *p) { + *p += 100; // OK. + } + + void escapingFunc(__attribute__((noescape)) int *p) { + gp = p; // Not OK. + } + +Additionally, when the parameter is a `block pointer +`, the same restriction +applies to copies of the block. For example: + +.. code-block:: c + + typedef void (^BlockTy)(); + BlockTy g0, g1; + + void nonescapingFunc(__attribute__((noescape)) BlockTy block) { + block(); // OK. + } + + void escapingFunc(__attribute__((noescape)) BlockTy block) { + g0 = block; // Not OK. + g1 = Block_copy(block); // Not OK either. + } + + +nosvm +----- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``nosvm``","","","","","","Yes" + +OpenCL 2.0 supports the optional ``__attribute__((nosvm))`` qualifier for +pointer variable. It informs the compiler that the pointer does not refer +to a shared virtual memory region. See OpenCL v2.0 s6.7.2 for details. + +Since it is not widely used and has been removed from OpenCL 2.1, it is ignored +by Clang. + + +objc_externally_retained +------------------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``objc_externally_retained``","``clang::objc_externally_retained``","``clang::objc_externally_retained``","","","","Yes" + +The ``objc_externally_retained`` attribute can be applied to strong local +variables, functions, methods, or blocks to opt into +`externally-retained semantics +`_. + +When applied to the definition of a function, method, or block, every parameter +of the function with implicit strong retainable object pointer type is +considered externally-retained, and becomes ``const``. By explicitly annotating +a parameter with ``__strong``, you can opt back into the default +non-externally-retained behaviour for that parameter. For instance, +``first_param`` is externally-retained below, but not ``second_param``: + +.. code-block:: objc + + __attribute__((objc_externally_retained)) + void f(NSArray *first_param, __strong NSArray *second_param) { + // ... + } + +Likewise, when applied to a strong local variable, that variable becomes +``const`` and is considered externally-retained. + +When compiled without ``-fobjc-arc``, this attribute is ignored. + + +pass_object_size, pass_dynamic_object_size +------------------------------------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``pass_object_size`` |br| ``pass_dynamic_object_size``","``clang::pass_object_size`` |br| ``clang::pass_dynamic_object_size``","``clang::pass_object_size`` |br| ``clang::pass_dynamic_object_size``","","","","Yes" + +.. Note:: The mangling of functions with parameters that are annotated with + ``pass_object_size`` is subject to change. You can get around this by + using ``__asm__("foo")`` to explicitly name your functions, thus preserving + your ABI; also, non-overloadable C functions with ``pass_object_size`` are + not mangled. + +The ``pass_object_size(Type)`` attribute can be placed on function parameters to +instruct clang to call ``__builtin_object_size(param, Type)`` at each callsite +of said function, and implicitly pass the result of this call in as an invisible +argument of type ``size_t`` directly after the parameter annotated with +``pass_object_size``. Clang will also replace any calls to +``__builtin_object_size(param, Type)`` in the function by said implicit +parameter. + +Example usage: + +.. code-block:: c + + int bzero1(char *const p __attribute__((pass_object_size(0)))) + __attribute__((noinline)) { + int i = 0; + for (/**/; i < (int)__builtin_object_size(p, 0); ++i) { + p[i] = 0; + } + return i; + } + + int main() { + char chars[100]; + int n = bzero1(&chars[0]); + assert(n == sizeof(chars)); + return 0; + } + +If successfully evaluating ``__builtin_object_size(param, Type)`` at the +callsite is not possible, then the "failed" value is passed in. So, using the +definition of ``bzero1`` from above, the following code would exit cleanly: + +.. code-block:: c + + int main2(int argc, char *argv[]) { + int n = bzero1(argv); + assert(n == -1); + return 0; + } + +``pass_object_size`` plays a part in overload resolution. If two overload +candidates are otherwise equally good, then the overload with one or more +parameters with ``pass_object_size`` is preferred. This implies that the choice +between two identical overloads both with ``pass_object_size`` on one or more +parameters will always be ambiguous; for this reason, having two such overloads +is illegal. For example: + +.. code-block:: c++ + + #define PS(N) __attribute__((pass_object_size(N))) + // OK + void Foo(char *a, char *b); // Overload A + // OK -- overload A has no parameters with pass_object_size. + void Foo(char *a PS(0), char *b PS(0)); // Overload B + // Error -- Same signature (sans pass_object_size) as overload B, and both + // overloads have one or more parameters with the pass_object_size attribute. + void Foo(void *a PS(0), void *b); + + // OK + void Bar(void *a PS(0)); // Overload C + // OK + void Bar(char *c PS(1)); // Overload D + + void main() { + char known[10], *unknown; + Foo(unknown, unknown); // Calls overload B + Foo(known, unknown); // Calls overload B + Foo(unknown, known); // Calls overload B + Foo(known, known); // Calls overload B + + Bar(known); // Calls overload D + Bar(unknown); // Calls overload D + } + +Currently, ``pass_object_size`` is a bit restricted in terms of its usage: + +* Only one use of ``pass_object_size`` is allowed per parameter. + +* It is an error to take the address of a function with ``pass_object_size`` on + any of its parameters. If you wish to do this, you can create an overload + without ``pass_object_size`` on any parameters. + +* It is an error to apply the ``pass_object_size`` attribute to parameters that + are not pointers. Additionally, any parameter that ``pass_object_size`` is + applied to must be marked ``const`` at its function's definition. + +Clang also supports the ``pass_dynamic_object_size`` attribute, which behaves +identically to ``pass_object_size``, but evaluates a call to +``__builtin_dynamic_object_size`` at the callee instead of +``__builtin_object_size``. ``__builtin_dynamic_object_size`` provides some extra +runtime checks when the object size can't be determined at compile-time. You can +read more about ``__builtin_dynamic_object_size`` `here +`_. + + +require_constant_initialization, constinit (C++20) +-------------------------------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``require_constant_initialization``","``clang::require_constant_initialization``","","","``constinit``","","Yes" + +This attribute specifies that the variable to which it is attached is intended +to have a `constant initializer `_ +according to the rules of [basic.start.static]. The variable is required to +have static or thread storage duration. If the initialization of the variable +is not a constant initializer an error will be produced. This attribute may +only be used in C++; the ``constinit`` spelling is only accepted in C++20 +onwards. + +Note that in C++03 strict constant expression checking is not done. Instead +the attribute reports if Clang can emit the variable as a constant, even if it's +not technically a 'constant initializer'. This behavior is non-portable. + +Static storage duration variables with constant initializers avoid hard-to-find +bugs caused by the indeterminate order of dynamic initialization. They can also +be safely used during dynamic initialization across translation units. + +This attribute acts as a compile time assertion that the requirements +for constant initialization have been met. Since these requirements change +between dialects and have subtle pitfalls it's important to fail fast instead +of silently falling back on dynamic initialization. + +The first use of the attribute on a variable must be part of, or precede, the +initializing declaration of the variable. C++20 requires the ``constinit`` +spelling of the attribute to be present on the initializing declaration if it +is used anywhere. The other spellings can be specified on a forward declaration +and omitted on a later initializing declaration. + +.. code-block:: c++ + + // -std=c++14 + #define SAFE_STATIC [[clang::require_constant_initialization]] + struct T { + constexpr T(int) {} + ~T(); // non-trivial + }; + SAFE_STATIC T x = {42}; // Initialization OK. Doesn't check destructor. + SAFE_STATIC T y = 42; // error: variable does not have a constant initializer + // copy initialization is not a constant expression on a non-literal type. + + +section, __declspec(allocate) +----------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``section``","``gnu::section``","","``allocate``","","","Yes" + +The ``section`` attribute allows you to specify a specific section a +global variable or function should be in after translation. + + +swift_context +------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``swift_context``","``clang::swift_context``","``clang::swift_context``","","","","Yes" + +The ``swift_context`` attribute marks a parameter of a ``swiftcall`` +function as having the special context-parameter ABI treatment. + +This treatment generally passes the context value in a special register +which is normally callee-preserved. + +A ``swift_context`` parameter must either be the last parameter or must be +followed by a ``swift_error_result`` parameter (which itself must always be +the last parameter). + +A context parameter must have pointer or reference type. + + +swift_error_result +------------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``swift_error_result``","``clang::swift_error_result``","``clang::swift_error_result``","","","","Yes" + +The ``swift_error_result`` attribute marks a parameter of a ``swiftcall`` +function as having the special error-result ABI treatment. + +This treatment generally passes the underlying error value in and out of +the function through a special register which is normally callee-preserved. +This is modeled in C by pretending that the register is addressable memory: + +- The caller appears to pass the address of a variable of pointer type. + The current value of this variable is copied into the register before + the call; if the call returns normally, the value is copied back into the + variable. + +- The callee appears to receive the address of a variable. This address + is actually a hidden location in its own stack, initialized with the + value of the register upon entry. When the function returns normally, + the value in that hidden location is written back to the register. + +A ``swift_error_result`` parameter must be the last parameter, and it must be +preceded by a ``swift_context`` parameter. + +A ``swift_error_result`` parameter must have type ``T**`` or ``T*&`` for some +type T. Note that no qualifiers are permitted on the intermediate level. + +It is undefined behavior if the caller does not pass a pointer or +reference to a valid object. + +The standard convention is that the error value itself (that is, the +value stored in the apparent argument) will be null upon function entry, +but this is not enforced by the ABI. + + +swift_indirect_result +--------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``swift_indirect_result``","``clang::swift_indirect_result``","``clang::swift_indirect_result``","","","","Yes" + +The ``swift_indirect_result`` attribute marks a parameter of a ``swiftcall`` +function as having the special indirect-result ABI treatment. + +This treatment gives the parameter the target's normal indirect-result +ABI treatment, which may involve passing it differently from an ordinary +parameter. However, only the first indirect result will receive this +treatment. Furthermore, low-level lowering may decide that a direct result +must be returned indirectly; if so, this will take priority over the +``swift_indirect_result`` parameters. + +A ``swift_indirect_result`` parameter must either be the first parameter or +follow another ``swift_indirect_result`` parameter. + +A ``swift_indirect_result`` parameter must have type ``T*`` or ``T&`` for +some object type ``T``. If ``T`` is a complete type at the point of +definition of a function, it is undefined behavior if the argument +value does not point to storage of adequate size and alignment for a +value of type ``T``. + +Making indirect results explicit in the signature allows C functions to +directly construct objects into them without relying on language +optimizations like C++'s named return value optimization (NRVO). + + +swiftcall +--------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``swiftcall``","``clang::swiftcall``","``clang::swiftcall``","","","","" + +The ``swiftcall`` attribute indicates that a function should be called +using the Swift calling convention for a function or function pointer. + +The lowering for the Swift calling convention, as described by the Swift +ABI documentation, occurs in multiple phases. The first, "high-level" +phase breaks down the formal parameters and results into innately direct +and indirect components, adds implicit paraameters for the generic +signature, and assigns the context and error ABI treatments to parameters +where applicable. The second phase breaks down the direct parameters +and results from the first phase and assigns them to registers or the +stack. The ``swiftcall`` convention only handles this second phase of +lowering; the C function type must accurately reflect the results +of the first phase, as follows: + +- Results classified as indirect by high-level lowering should be + represented as parameters with the ``swift_indirect_result`` attribute. + +- Results classified as direct by high-level lowering should be represented + as follows: + + - First, remove any empty direct results. + + - If there are no direct results, the C result type should be ``void``. + + - If there is one direct result, the C result type should be a type with + the exact layout of that result type. + + - If there are a multiple direct results, the C result type should be + a struct type with the exact layout of a tuple of those results. + +- Parameters classified as indirect by high-level lowering should be + represented as parameters of pointer type. + +- Parameters classified as direct by high-level lowering should be + omitted if they are empty types; otherwise, they should be represented + as a parameter type with a layout exactly matching the layout of the + Swift parameter type. + +- The context parameter, if present, should be represented as a trailing + parameter with the ``swift_context`` attribute. + +- The error result parameter, if present, should be represented as a + trailing parameter (always following a context parameter) with the + ``swift_error_result`` attribute. + +``swiftcall`` does not support variadic arguments or unprototyped functions. + +The parameter ABI treatment attributes are aspects of the function type. +A function type which which applies an ABI treatment attribute to a +parameter is a different type from an otherwise-identical function type +that does not. A single parameter may not have multiple ABI treatment +attributes. + +Support for this feature is target-dependent, although it should be +supported on every target that Swift supports. Query for this support +with ``__has_attribute(swiftcall)``. This implies support for the +``swift_context``, ``swift_error_result``, and ``swift_indirect_result`` +attributes. + + +thread +------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "","","","``thread``","","","" + +The ``__declspec(thread)`` attribute declares a variable with thread local +storage. It is available under the ``-fms-extensions`` flag for MSVC +compatibility. See the documentation for `__declspec(thread)`_ on MSDN. + +.. _`__declspec(thread)`: http://msdn.microsoft.com/en-us/library/9w1sdazb.aspx + +In Clang, ``__declspec(thread)`` is generally equivalent in functionality to the +GNU ``__thread`` keyword. The variable must not have a destructor and must have +a constant initializer, if any. The attribute only applies to variables +declared with static storage duration, such as globals, class static data +members, and static locals. + + +tls_model +--------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``tls_model``","``gnu::tls_model``","","","","","Yes" + +The ``tls_model`` attribute allows you to specify which thread-local storage +model to use. It accepts the following strings: + +* global-dynamic +* local-dynamic +* initial-exec +* local-exec + +TLS models are mutually exclusive. + + +uninitialized +------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``uninitialized``","``clang::uninitialized``","","","","","" + +The command-line parameter ``-ftrivial-auto-var-init=*`` can be used to +initialize trivial automatic stack variables. By default, trivial automatic +stack variables are uninitialized. This attribute is used to override the +command-line parameter, forcing variables to remain uninitialized. It has no +semantic meaning in that using uninitialized values is undefined behavior, +it rather documents the programmer's intent. + + +Field Attributes +================ + + +no_unique_address +----------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "","``no_unique_address``","","","","","" + +The ``no_unique_address`` attribute allows tail padding in a non-static data +member to overlap other members of the enclosing class (and in the special +case when the type is empty, permits it to fully overlap other members). +The field is laid out as if a base class were encountered at the corresponding +point within the class (except that it does not share a vptr with the enclosing +object). + +Example usage: + +.. code-block:: c++ + + template struct my_vector { + T *p; + [[no_unique_address]] Alloc alloc; + // ... + }; + static_assert(sizeof(my_vector>) == sizeof(int*)); + +``[[no_unique_address]]`` is a standard C++20 attribute. Clang supports its use +in C++11 onwards. + + +Type Attributes +=============== + + +__ptr32 +------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "","","","","``__ptr32``","","" + +The ``__ptr32`` qualifier represents a native pointer on a 32-bit system. On a +64-bit system, a pointer with ``__ptr32`` is extended to a 64-bit pointer. The +``__sptr`` and ``__uptr`` qualifiers can be used to specify whether the pointer +is sign extended or zero extended. This qualifier is enabled under +``-fms-extensions``. + + +__ptr64 +------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "","","","","``__ptr64``","","" + +The ``__ptr64`` qualifier represents a native pointer on a 64-bit system. On a +32-bit system, a ``__ptr64`` pointer is truncated to a 32-bit pointer. This +qualifier is enabled under ``-fms-extensions``. + + +__sptr +------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "","","","","``__sptr``","","" + +The ``__sptr`` qualifier specifies that a 32-bit pointer should be sign +extended when converted to a 64-bit pointer. + + +__uptr +------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "","","","","``__uptr``","","" + +The ``__uptr`` qualifier specifies that a 32-bit pointer should be zero +extended when converted to a 64-bit pointer. + + +align_value +----------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``align_value``","","","","","","Yes" + +The align_value attribute can be added to the typedef of a pointer type or the +declaration of a variable of pointer or reference type. It specifies that the +pointer will point to, or the reference will bind to, only objects with at +least the provided alignment. This alignment value must be some positive power +of 2. + + .. code-block:: c + + typedef double * aligned_double_ptr __attribute__((align_value(64))); + void foo(double & x __attribute__((align_value(128)), + aligned_double_ptr y) { ... } + +If the pointer value does not have the specified alignment at runtime, the +behavior of the program is undefined. + + +hip_pinned_shadow +----------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``hip_pinned_shadow``","","","``__hip_pinned_shadow__``","","","Yes" + +The GNU style attribute __attribute__((hip_pinned_shadow)) or MSVC style attribute +__declspec(hip_pinned_shadow) can be added to the definition of a global variable +to indicate it is a HIP pinned shadow variable. A HIP pinned shadow variable can +be accessed on both device side and host side. It has external linkage and is +not initialized on device side. It has internal linkage and is initialized by +the initializer on host side. + + +noderef +------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``noderef``","``clang::noderef``","``clang::noderef``","","","","" + +The ``noderef`` attribute causes clang to diagnose dereferences of annotated pointer types. +This is ideally used with pointers that point to special memory which cannot be read +from or written to, but allowing for the pointer to be used in pointer arithmetic. +The following are examples of valid expressions where dereferences are diagnosed: + +.. code-block:: c + + int __attribute__((noderef)) *p; + int x = *p; // warning + + int __attribute__((noderef)) **p2; + x = **p2; // warning + + int * __attribute__((noderef)) *p3; + p = *p3; // warning + + struct S { + int a; + }; + struct S __attribute__((noderef)) *s; + x = s->a; // warning + x = (*s).a; // warning + +Not all dereferences may diagnose a warning if the value directed by the pointer may not be +accessed. The following are examples of valid expressions where may not be diagnosed: + +.. code-block:: c + + int *q; + int __attribute__((noderef)) *p; + q = &*p; + q = *&p; + + struct S { + int a; + }; + struct S __attribute__((noderef)) *s; + p = &s->a; + p = &(*s).a; + +``noderef`` is currently only supported for pointers and arrays and not usable for +references or Objective-C object pointers. + +.. code-block: c++ + + int x = 2; + int __attribute__((noderef)) &y = x; // warning: 'noderef' can only be used on an array or pointer type + +.. code-block: objc + + id __attribute__((noderef)) obj = [NSObject new]; // warning: 'noderef' can only be used on an array or pointer type + + +objc_class_stub +--------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``objc_class_stub``","``clang::objc_class_stub``","``clang::objc_class_stub``","","","","Yes" + +This attribute specifies that the Objective-C class to which it applies is +instantiated at runtime. + +Unlike ``__attribute__((objc_runtime_visible))``, a class having this attribute +still has a "class stub" that is visible to the linker. This allows categories +to be defined. Static message sends with the class as a receiver use a special +access pattern to ensure the class is lazily instantiated from the class stub. + +Classes annotated with this attribute cannot be subclassed and cannot have +implementations defined for them. This attribute is intended for use in +Swift-generated headers for classes defined in Swift. + +Adding or removing this attribute to a class is an ABI-breaking change. + + +Statement Attributes +==================== + + +#pragma clang loop +------------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "","","","","","``clang loop`` |br| ``unroll`` |br| ``nounroll`` |br| ``unroll_and_jam`` |br| ``nounroll_and_jam``","" + +The ``#pragma clang loop`` directive allows loop optimization hints to be +specified for the subsequent loop. The directive allows pipelining to be +disabled, or vectorization, vector predication, interleaving, and unrolling to +be enabled or disabled. Vector width, vector predication, interleave count, +unrolling count, and the initiation interval for pipelining can be explicitly +specified. See `language extensions +`_ +for details. + + +#pragma unroll, #pragma nounroll +-------------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "","","","","","``clang loop`` |br| ``unroll`` |br| ``nounroll`` |br| ``unroll_and_jam`` |br| ``nounroll_and_jam``","" + +Loop unrolling optimization hints can be specified with ``#pragma unroll`` and +``#pragma nounroll``. The pragma is placed immediately before a for, while, +do-while, or c++11 range-based for loop. + +Specifying ``#pragma unroll`` without a parameter directs the loop unroller to +attempt to fully unroll the loop if the trip count is known at compile time and +attempt to partially unroll the loop if the trip count is not known at compile +time: + +.. code-block:: c++ + + #pragma unroll + for (...) { + ... + } + +Specifying the optional parameter, ``#pragma unroll _value_``, directs the +unroller to unroll the loop ``_value_`` times. The parameter may optionally be +enclosed in parentheses: + +.. code-block:: c++ + + #pragma unroll 16 + for (...) { + ... + } + + #pragma unroll(16) + for (...) { + ... + } + +Specifying ``#pragma nounroll`` indicates that the loop should not be unrolled: + +.. code-block:: c++ + + #pragma nounroll + for (...) { + ... + } + +``#pragma unroll`` and ``#pragma unroll _value_`` have identical semantics to +``#pragma clang loop unroll(full)`` and +``#pragma clang loop unroll_count(_value_)`` respectively. ``#pragma nounroll`` +is equivalent to ``#pragma clang loop unroll(disable)``. See +`language extensions +`_ +for further details including limitations of the unroll hints. + + +__read_only, __write_only, __read_write (read_only, write_only, read_write) +--------------------------------------------------------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "","","","","``__read_only`` |br| ``read_only`` |br| ``__write_only`` |br| ``write_only`` |br| ``__read_write`` |br| ``read_write``","","" + +The access qualifiers must be used with image object arguments or pipe arguments +to declare if they are being read or written by a kernel or function. + +The read_only/__read_only, write_only/__write_only and read_write/__read_write +names are reserved for use as access qualifiers and shall not be used otherwise. + +.. code-block:: c + + kernel void + foo (read_only image2d_t imageA, + write_only image2d_t imageB) { + ... + } + +In the above example imageA is a read-only 2D image object, and imageB is a +write-only 2D image object. + +The read_write (or __read_write) qualifier can not be used with pipe. + +More details can be found in the OpenCL C language Spec v2.0, Section 6.6. + + +fallthrough +----------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``fallthrough``","``fallthrough`` |br| ``clang::fallthrough`` |br| ``gnu::fallthrough``","``fallthrough``","","","","" + +The ``fallthrough`` (or ``clang::fallthrough``) attribute is used +to annotate intentional fall-through +between switch labels. It can only be applied to a null statement placed at a +point of execution between any statement and the next switch label. It is +common to mark these places with a specific comment, but this attribute is +meant to replace comments with a more strict annotation, which can be checked +by the compiler. This attribute doesn't change semantics of the code and can +be used wherever an intended fall-through occurs. It is designed to mimic +control-flow statements like ``break;``, so it can be placed in most places +where ``break;`` can, but only if there are no statements on the execution path +between it and the next switch label. + +By default, Clang does not warn on unannotated fallthrough from one ``switch`` +case to another. Diagnostics on fallthrough without a corresponding annotation +can be enabled with the ``-Wimplicit-fallthrough`` argument. + +Here is an example: + +.. code-block:: c++ + + // compile with -Wimplicit-fallthrough + switch (n) { + case 22: + case 33: // no warning: no statements between case labels + f(); + case 44: // warning: unannotated fall-through + g(); + [[clang::fallthrough]]; + case 55: // no warning + if (x) { + h(); + break; + } + else { + i(); + [[clang::fallthrough]]; + } + case 66: // no warning + p(); + [[clang::fallthrough]]; // warning: fallthrough annotation does not + // directly precede case label + q(); + case 77: // warning: unannotated fall-through + r(); + } + + +intel_reqd_sub_group_size +------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``intel_reqd_sub_group_size``","","","","","","Yes" + +The optional attribute intel_reqd_sub_group_size can be used to indicate that +the kernel must be compiled and executed with the specified subgroup size. When +this attribute is present, get_max_sub_group_size() is guaranteed to return the +specified integer value. This is important for the correctness of many subgroup +algorithms, and in some cases may be used by the compiler to generate more optimal +code. See `cl_intel_required_subgroup_size +` +for details. + + +opencl_unroll_hint +------------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``opencl_unroll_hint``","","","","","","" + +The opencl_unroll_hint attribute qualifier can be used to specify that a loop +(for, while and do loops) can be unrolled. This attribute qualifier can be +used to specify full unrolling or partial unrolling by a specified amount. +This is a compiler hint and the compiler may ignore this directive. See +`OpenCL v2.0 `_ +s6.11.5 for details. + + +suppress +-------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "","``gsl::suppress``","","","","","" + +The ``[[gsl::suppress]]`` attribute suppresses specific +clang-tidy diagnostics for rules of the `C++ Core Guidelines`_ in a portable +way. The attribute can be attached to declarations, statements, and at +namespace scope. + +.. code-block:: c++ + + [[gsl::suppress("Rh-public")]] + void f_() { + int *p; + [[gsl::suppress("type")]] { + p = reinterpret_cast(7); + } + } + namespace N { + [[clang::suppress("type", "bounds")]]; + ... + } + +.. _`C++ Core Guidelines`: https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#inforce-enforcement + + +Declaration Attributes +====================== + + +Owner +----- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "","``gsl::Owner``","","","","","Yes" + +.. Note:: This attribute is experimental and its effect on analysis is subject to change in + a future version of clang. + +The attribute ``[[gsl::Owner(T)]]`` applies to structs and classes that own an +object of type ``T``: + +.. code-block:: c++ + + class [[gsl::Owner(int)]] IntOwner { + private: + int value; + public: + int *getInt() { return &value; } + }; + +The argument ``T`` is optional and is ignored. +This attribute may be used by analysis tools and has no effect on code +generation. A ``void`` argument means that the class can own any type. + +See Pointer_ for an example. + + +Pointer +------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "","``gsl::Pointer``","","","","","Yes" + +.. Note:: This attribute is experimental and its effect on analysis is subject to change in + a future version of clang. + +The attribute ``[[gsl::Pointer(T)]]`` applies to structs and classes that behave +like pointers to an object of type ``T``: + +.. code-block:: c++ + + class [[gsl::Pointer(int)]] IntPointer { + private: + int *valuePointer; + public: + int *getInt() { return &valuePointer; } + }; + +The argument ``T`` is optional and is ignored. +This attribute may be used by analysis tools and has no effect on code +generation. A ``void`` argument means that the pointer can point to any type. + +Example: +When constructing an instance of a class annotated like this (a Pointer) from +an instance of a class annotated with ``[[gsl::Owner]]`` (an Owner), +then the analysis will consider the Pointer to point inside the Owner. +When the Owner's lifetime ends, it will consider the Pointer to be dangling. + +.. code-block:: c++ + + int f() { + IntPointer P; + if (true) { + IntOwner O(7); + P = IntPointer(O); // P "points into" O + } // P is dangling + return P.get(); // error: Using a dangling Pointer. + } + + +__single_inhertiance, __multiple_inheritance, __virtual_inheritance +------------------------------------------------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "","","","","``__single_inheritance`` |br| ``__multiple_inheritance`` |br| ``__virtual_inheritance`` |br| ``__unspecified_inheritance``","","" + +This collection of keywords is enabled under ``-fms-extensions`` and controls +the pointer-to-member representation used on ``*-*-win32`` targets. + +The ``*-*-win32`` targets utilize a pointer-to-member representation which +varies in size and alignment depending on the definition of the underlying +class. + +However, this is problematic when a forward declaration is only available and +no definition has been made yet. In such cases, Clang is forced to utilize the +most general representation that is available to it. + +These keywords make it possible to use a pointer-to-member representation other +than the most general one regardless of whether or not the definition will ever +be present in the current translation unit. + +This family of keywords belong between the ``class-key`` and ``class-name``: + +.. code-block:: c++ + + struct __single_inheritance S; + int S::*i; + struct S {}; + +This keyword can be applied to class templates but only has an effect when used +on full specializations: + +.. code-block:: c++ + + template struct __single_inheritance A; // warning: inheritance model ignored on primary template + template struct __multiple_inheritance A; // warning: inheritance model ignored on partial specialization + template <> struct __single_inheritance A; + +Note that choosing an inheritance model less general than strictly necessary is +an error: + +.. code-block:: c++ + + struct __multiple_inheritance S; // error: inheritance model does not match definition + int S::*i; + struct S {}; + + +asm +--- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "","","","","``asm`` |br| ``__asm__``","","" + +This attribute can be used on a function or variable to specify its symbol name. + +On some targets, all C symbols are prefixed by default with a single character, typically ``_``. This was done historically to distinguish them from symbols used by other languages. (This prefix is also added to the standard Itanium C++ ABI prefix on "mangled" symbol names, so that e.g. on such targets the true symbol name for a C++ variable declared as ``int cppvar;`` would be ``__Z6cppvar``; note the two underscores.) This prefix is *not* added to the symbol names specified by the ``asm`` attribute; programmers wishing to match a C symbol name must compensate for this. + +For example, consider the following C code: + +.. code-block:: c + + int var1 asm("altvar") = 1; // "altvar" in symbol table. + int var2 = 1; // "_var2" in symbol table. + + void func1(void) asm("altfunc"); + void func1(void) {} // "altfunc" in symbol table. + void func2(void) {} // "_func2" in symbol table. + +Clang's implementation of this attribute is compatible with GCC's, `documented here `_. + +While it is possible to use this attribute to name a special symbol used internally by the compiler, such as an LLVM intrinsic, this is neither recommended nor supported and may cause the compiler to crash or miscompile. Users who wish to gain access to intrinsic behavior are strongly encouraged to request new builtin functions. + + +deprecated +---------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``deprecated``","``gnu::deprecated`` |br| ``deprecated``","``deprecated``","``deprecated``","","","" + +The ``deprecated`` attribute can be applied to a function, a variable, or a +type. This is useful when identifying functions, variables, or types that are +expected to be removed in a future version of a program. + +Consider the function declaration for a hypothetical function ``f``: + +.. code-block:: c++ + + void f(void) __attribute__((deprecated("message", "replacement"))); + +When spelled as `__attribute__((deprecated))`, the deprecated attribute can have +two optional string arguments. The first one is the message to display when +emitting the warning; the second one enables the compiler to provide a Fix-It +to replace the deprecated name with a new name. Otherwise, when spelled as +`[[gnu::deprecated]] or [[deprecated]]`, the attribute can have one optional +string argument which is the message to display when emitting the warning. + + +empty_bases +----------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "","","","``empty_bases``","","","" + +The empty_bases attribute permits the compiler to utilize the +empty-base-optimization more frequently. +This attribute only applies to struct, class, and union types. +It is only supported when using the Microsoft C++ ABI. + + +enum_extensibility +------------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``enum_extensibility``","``clang::enum_extensibility``","``clang::enum_extensibility``","","","","Yes" + +Attribute ``enum_extensibility`` is used to distinguish between enum definitions +that are extensible and those that are not. The attribute can take either +``closed`` or ``open`` as an argument. ``closed`` indicates a variable of the +enum type takes a value that corresponds to one of the enumerators listed in the +enum definition or, when the enum is annotated with ``flag_enum``, a value that +can be constructed using values corresponding to the enumerators. ``open`` +indicates a variable of the enum type can take any values allowed by the +standard and instructs clang to be more lenient when issuing warnings. + +.. code-block:: c + + enum __attribute__((enum_extensibility(closed))) ClosedEnum { + A0, A1 + }; + + enum __attribute__((enum_extensibility(open))) OpenEnum { + B0, B1 + }; + + enum __attribute__((enum_extensibility(closed),flag_enum)) ClosedFlagEnum { + C0 = 1 << 0, C1 = 1 << 1 + }; + + enum __attribute__((enum_extensibility(open),flag_enum)) OpenFlagEnum { + D0 = 1 << 0, D1 = 1 << 1 + }; + + void foo1() { + enum ClosedEnum ce; + enum OpenEnum oe; + enum ClosedFlagEnum cfe; + enum OpenFlagEnum ofe; + + ce = A1; // no warnings + ce = 100; // warning issued + oe = B1; // no warnings + oe = 100; // no warnings + cfe = C0 | C1; // no warnings + cfe = C0 | C1 | 4; // warning issued + ofe = D0 | D1; // no warnings + ofe = D0 | D1 | 4; // no warnings + } + + +external_source_symbol +---------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``external_source_symbol``","``clang::external_source_symbol``","``clang::external_source_symbol``","","","","Yes" + +The ``external_source_symbol`` attribute specifies that a declaration originates +from an external source and describes the nature of that source. + +The fact that Clang is capable of recognizing declarations that were defined +externally can be used to provide better tooling support for mixed-language +projects or projects that rely on auto-generated code. For instance, an IDE that +uses Clang and that supports mixed-language projects can use this attribute to +provide a correct 'jump-to-definition' feature. For a concrete example, +consider a protocol that's defined in a Swift file: + +.. code-block:: swift + + @objc public protocol SwiftProtocol { + func method() + } + +This protocol can be used from Objective-C code by including a header file that +was generated by the Swift compiler. The declarations in that header can use +the ``external_source_symbol`` attribute to make Clang aware of the fact +that ``SwiftProtocol`` actually originates from a Swift module: + +.. code-block:: objc + + __attribute__((external_source_symbol(language="Swift",defined_in="module"))) + @protocol SwiftProtocol + @required + - (void) method; + @end + +Consequently, when 'jump-to-definition' is performed at a location that +references ``SwiftProtocol``, the IDE can jump to the original definition in +the Swift source file rather than jumping to the Objective-C declaration in the +auto-generated header file. + +The ``external_source_symbol`` attribute is a comma-separated list that includes +clauses that describe the origin and the nature of the particular declaration. +Those clauses can be: + +language=\ *string-literal* + The name of the source language in which this declaration was defined. + +defined_in=\ *string-literal* + The name of the source container in which the declaration was defined. The + exact definition of source container is language-specific, e.g. Swift's + source containers are modules, so ``defined_in`` should specify the Swift + module name. + +generated_declaration + This declaration was automatically generated by some tool. + +The clauses can be specified in any order. The clauses that are listed above are +all optional, but the attribute has to have at least one clause. + + +flag_enum +--------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``flag_enum``","``clang::flag_enum``","``clang::flag_enum``","","","","Yes" + +This attribute can be added to an enumerator to signal to the compiler that it +is intended to be used as a flag type. This will cause the compiler to assume +that the range of the type includes all of the values that you can get by +manipulating bits of the enumerator when issuing warnings. + + +layout_version +-------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "","","","``layout_version``","","","" + +The layout_version attribute requests that the compiler utilize the class +layout rules of a particular compiler version. +This attribute only applies to struct, class, and union types. +It is only supported when using the Microsoft C++ ABI. + + +lto_visibility_public +--------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``lto_visibility_public``","``clang::lto_visibility_public``","``clang::lto_visibility_public``","","","","Yes" + +See :doc:`LTOVisibility`. + + +novtable +-------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "","","","``novtable``","","","" + +This attribute can be added to a class declaration or definition to signal to +the compiler that constructors and destructors will not reference the virtual +function table. It is only supported when using the Microsoft C++ ABI. + + +objc_boxable +------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``objc_boxable``","``clang::objc_boxable``","``clang::objc_boxable``","","","","Yes" + +Structs and unions marked with the ``objc_boxable`` attribute can be used +with the Objective-C boxed expression syntax, ``@(...)``. + +**Usage**: ``__attribute__((objc_boxable))``. This attribute +can only be placed on a declaration of a trivially-copyable struct or union: + +.. code-block:: objc + + struct __attribute__((objc_boxable)) some_struct { + int i; + }; + union __attribute__((objc_boxable)) some_union { + int i; + float f; + }; + typedef struct __attribute__((objc_boxable)) _some_struct some_struct; + + // ... + + some_struct ss; + NSValue *boxed = @(ss); + + +objc_direct +----------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``objc_direct``","``clang::objc_direct``","``clang::objc_direct``","","","","Yes" + +The ``objc_direct`` attribute can be used to mark an Objective-C method as +being *direct*. A direct method is treated statically like an ordinary method, +but dynamically it behaves more like a C function. This lowers some of the costs +associated with the method but also sacrifices some of the ordinary capabilities +of Objective-C methods. + +A message send of a direct method calls the implementation directly, as if it +were a C function, rather than using ordinary Objective-C method dispatch. This +is substantially faster and potentially allows the implementation to be inlined, +but it also means the method cannot be overridden in subclasses or replaced +dynamically, as ordinary Objective-C methods can. + +Furthermore, a direct method is not listed in the class's method lists. This +substantially reduces the code-size overhead of the method but also means it +cannot be called dynamically using ordinary Objective-C method dispatch at all; +in particular, this means that it cannot override a superclass method or satisfy +a protocol requirement. + +Because a direct method cannot be overridden, it is an error to perform +a ``super`` message send of one. + +Although a message send of a direct method causes the method to be called +directly as if it were a C function, it still obeys Objective-C semantics in other +ways: + +- If the receiver is ``nil``, the message send does nothing and returns the zero value + for the return type. + +- A message send of a direct class method will cause the class to be initialized, + including calling the ``+initialize`` method if present. + +- The implicit ``_cmd`` parameter containing the method's selector is still defined. + In order to minimize code-size costs, the implementation will not emit a reference + to the selector if the parameter is unused within the method. + +Symbols for direct method implementations are implicitly given hidden +visibility, meaning that they can only be called within the same linkage unit. + +It is an error to do any of the following: + +- declare a direct method in a protocol, +- declare an override of a direct method with a method in a subclass, +- declare an override of a non-direct method with a direct method in a subclass, +- declare a method with different directness in different class interfaces, or +- implement a non-direct method (as declared in any class interface) with a direct method. + +If any of these rules would be violated if every method defined in an +``@implementation`` within a single linkage unit were declared in an +appropriate class interface, the program is ill-formed with no diagnostic +required. If a violation of this rule is not diagnosed, behavior remains +well-defined; this paragraph is simply reserving the right to diagnose such +conflicts in the future, not to treat them as undefined behavior. + +Additionally, Clang will warn about any ``@selector`` expression that +names a selector that is only known to be used for direct methods. + +For the purpose of these rules, a "class interface" includes a class's primary +``@interface`` block, its class extensions, its categories, its declared protocols, +and all the class interfaces of its superclasses. + +An Objective-C property can be declared with the ``direct`` property +attribute. If a direct property declaration causes an implicit declaration of +a getter or setter method (that is, if the given method is not explicitly +declared elsewhere), the method is declared to be direct. + +Some programmers may wish to make many methods direct at once. In order +to simplify this, the ``objc_direct_members`` attribute is provided; see its +documentation for more information. + + +objc_direct_members +------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``objc_direct_members``","``clang::objc_direct_members``","``clang::objc_direct_members``","","","","Yes" + +The ``objc_direct_members`` attribute can be placed on an Objective-C +``@interface`` or ``@implementation`` to mark that methods declared +therein should be considered direct by default. See the documentation +for ``objc_direct`` for more information about direct methods. + +When ``objc_direct_members`` is placed on an ``@interface`` block, every +method in the block is considered to be declared as direct. This includes any +implicit method declarations introduced by property declarations. If the method +redeclares a non-direct method, the declaration is ill-formed, exactly as if the +method was annotated with the ``objc_direct`` attribute. ``objc_direct_members`` +cannot be placed on the primary interface of a class, only on category or class +extension interfaces. + +When ``objc_direct_members`` is placed on an ``@implementation`` block, +methods defined in the block are considered to be declared as direct unless +they have been previously declared as non-direct in any interface of the class. +This includes the implicit method definitions introduced by synthesized +properties, including auto-synthesized properties. + + +objc_nonlazy_class +------------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``objc_nonlazy_class``","``clang::objc_nonlazy_class``","``clang::objc_nonlazy_class``","","","","Yes" + +This attribute can be added to an Objective-C ``@interface`` or +``@implementation`` declaration to add the class to the list of non-lazily +initialized classes. A non-lazy class will be initialized eagerly when the +Objective-C runtime is loaded. This is required for certain system classes which +have instances allocated in non-standard ways, such as the classes for blocks +and constant strings. Adding this attribute is essentially equivalent to +providing a trivial `+load` method but avoids the (fairly small) load-time +overheads associated with defining and calling such a method. + + +objc_runtime_name +----------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``objc_runtime_name``","``clang::objc_runtime_name``","``clang::objc_runtime_name``","","","","Yes" + +By default, the Objective-C interface or protocol identifier is used +in the metadata name for that object. The `objc_runtime_name` +attribute allows annotated interfaces or protocols to use the +specified string argument in the object's metadata name instead of the +default name. + +**Usage**: ``__attribute__((objc_runtime_name("MyLocalName")))``. This attribute +can only be placed before an @protocol or @interface declaration: + +.. code-block:: objc + + __attribute__((objc_runtime_name("MyLocalName"))) + @interface Message + @end + + +objc_runtime_visible +-------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``objc_runtime_visible``","``clang::objc_runtime_visible``","``clang::objc_runtime_visible``","","","","Yes" + +This attribute specifies that the Objective-C class to which it applies is +visible to the Objective-C runtime but not to the linker. Classes annotated +with this attribute cannot be subclassed and cannot have categories defined for +them. + + +objc_subclassing_restricted +--------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``objc_subclassing_restricted``","``clang::objc_subclassing_restricted``","``clang::objc_subclassing_restricted``","","","","Yes" + +This attribute can be added to an Objective-C ``@interface`` declaration to +ensure that this class cannot be subclassed. + + +selectany +--------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``selectany``","``gnu::selectany``","","``selectany``","","","" + +This attribute appertains to a global symbol, causing it to have a weak +definition ( +`linkonce `_ +), allowing the linker to select any definition. + +For more information see +`gcc documentation `_ +or `msvc documentation `_. + + +transparent_union +----------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``transparent_union``","``gnu::transparent_union``","","","","","" + +This attribute can be applied to a union to change the behaviour of calls to +functions that have an argument with a transparent union type. The compiler +behaviour is changed in the following manner: + +- A value whose type is any member of the transparent union can be passed as an + argument without the need to cast that value. + +- The argument is passed to the function using the calling convention of the + first member of the transparent union. Consequently, all the members of the + transparent union should have the same calling convention as its first member. + +Transparent unions are not supported in C++. + + +trivial_abi +----------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``trivial_abi``","``clang::trivial_abi``","","","","","Yes" + +The ``trivial_abi`` attribute can be applied to a C++ class, struct, or union. +It instructs the compiler to pass and return the type using the C ABI for the +underlying type when the type would otherwise be considered non-trivial for the +purpose of calls. +A class annotated with `trivial_abi` can have non-trivial destructors or copy/move constructors without automatically becoming non-trivial for the purposes of calls. For example: + + .. code-block:: c++ + + // A is trivial for the purposes of calls because `trivial_abi` makes the + // user-provided special functions trivial. + struct __attribute__((trivial_abi)) A { + ~A(); + A(const A &); + A(A &&); + int x; + }; + + // B's destructor and copy/move constructor are considered trivial for the + // purpose of calls because A is trivial. + struct B { + A a; + }; + +If a type is trivial for the purposes of calls, has a non-trivial destructor, +and is passed as an argument by value, the convention is that the callee will +destroy the object before returning. + +Attribute ``trivial_abi`` has no effect in the following cases: + +- The class directly declares a virtual base or virtual methods. +- The class has a base class that is non-trivial for the purposes of calls. +- The class has a non-static data member whose type is non-trivial for the purposes of calls, which includes: + + - classes that are non-trivial for the purposes of calls + - __weak-qualified types in Objective-C++ + - arrays of any of the above + + +AMD GPU Attributes +================== + + +amdgpu_flat_work_group_size +--------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``amdgpu_flat_work_group_size``","``clang::amdgpu_flat_work_group_size``","","","","","Yes" + +The flat work-group size is the number of work-items in the work-group size +specified when the kernel is dispatched. It is the product of the sizes of the +x, y, and z dimension of the work-group. + +Clang supports the +``__attribute__((amdgpu_flat_work_group_size(, )))`` attribute for the +AMDGPU target. This attribute may be attached to a kernel function definition +and is an optimization hint. + +```` parameter specifies the minimum flat work-group size, and ```` +parameter specifies the maximum flat work-group size (must be greater than +````) to which all dispatches of the kernel will conform. Passing ``0, 0`` +as ``, `` implies the default behavior (``128, 256``). + +If specified, the AMDGPU target backend might be able to produce better machine +code for barriers and perform scratch promotion by estimating available group +segment size. + +An error will be given if: + - Specified values violate subtarget specifications; + - Specified values are not compatible with values provided through other + attributes. + + +amdgpu_num_sgpr +--------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``amdgpu_num_sgpr``","``clang::amdgpu_num_sgpr``","","","","","Yes" + +Clang supports the ``__attribute__((amdgpu_num_sgpr()))`` and +``__attribute__((amdgpu_num_vgpr()))`` attributes for the AMDGPU +target. These attributes may be attached to a kernel function definition and are +an optimization hint. + +If these attributes are specified, then the AMDGPU target backend will attempt +to limit the number of SGPRs and/or VGPRs used to the specified value(s). The +number of used SGPRs and/or VGPRs may further be rounded up to satisfy the +allocation requirements or constraints of the subtarget. Passing ``0`` as +``num_sgpr`` and/or ``num_vgpr`` implies the default behavior (no limits). + +These attributes can be used to test the AMDGPU target backend. It is +recommended that the ``amdgpu_waves_per_eu`` attribute be used to control +resources such as SGPRs and VGPRs since it is aware of the limits for different +subtargets. + +An error will be given if: + - Specified values violate subtarget specifications; + - Specified values are not compatible with values provided through other + attributes; + - The AMDGPU target backend is unable to create machine code that can meet the + request. + + +amdgpu_num_vgpr +--------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``amdgpu_num_vgpr``","``clang::amdgpu_num_vgpr``","","","","","Yes" + +Clang supports the ``__attribute__((amdgpu_num_sgpr()))`` and +``__attribute__((amdgpu_num_vgpr()))`` attributes for the AMDGPU +target. These attributes may be attached to a kernel function definition and are +an optimization hint. + +If these attributes are specified, then the AMDGPU target backend will attempt +to limit the number of SGPRs and/or VGPRs used to the specified value(s). The +number of used SGPRs and/or VGPRs may further be rounded up to satisfy the +allocation requirements or constraints of the subtarget. Passing ``0`` as +``num_sgpr`` and/or ``num_vgpr`` implies the default behavior (no limits). + +These attributes can be used to test the AMDGPU target backend. It is +recommended that the ``amdgpu_waves_per_eu`` attribute be used to control +resources such as SGPRs and VGPRs since it is aware of the limits for different +subtargets. + +An error will be given if: + - Specified values violate subtarget specifications; + - Specified values are not compatible with values provided through other + attributes; + - The AMDGPU target backend is unable to create machine code that can meet the + request. + + +amdgpu_waves_per_eu +------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``amdgpu_waves_per_eu``","``clang::amdgpu_waves_per_eu``","","","","","Yes" + +A compute unit (CU) is responsible for executing the wavefronts of a work-group. +It is composed of one or more execution units (EU), which are responsible for +executing the wavefronts. An EU can have enough resources to maintain the state +of more than one executing wavefront. This allows an EU to hide latency by +switching between wavefronts in a similar way to symmetric multithreading on a +CPU. In order to allow the state for multiple wavefronts to fit on an EU, the +resources used by a single wavefront have to be limited. For example, the number +of SGPRs and VGPRs. Limiting such resources can allow greater latency hiding, +but can result in having to spill some register state to memory. + +Clang supports the ``__attribute__((amdgpu_waves_per_eu([, ])))`` +attribute for the AMDGPU target. This attribute may be attached to a kernel +function definition and is an optimization hint. + +```` parameter specifies the requested minimum number of waves per EU, and +*optional* ```` parameter specifies the requested maximum number of waves +per EU (must be greater than ```` if specified). If ```` is omitted, +then there is no restriction on the maximum number of waves per EU other than +the one dictated by the hardware for which the kernel is compiled. Passing +``0, 0`` as ``, `` implies the default behavior (no limits). + +If specified, this attribute allows an advanced developer to tune the number of +wavefronts that are capable of fitting within the resources of an EU. The AMDGPU +target backend can use this information to limit resources, such as number of +SGPRs, number of VGPRs, size of available group and private memory segments, in +such a way that guarantees that at least ```` wavefronts and at most +```` wavefronts are able to fit within the resources of an EU. Requesting +more wavefronts can hide memory latency but limits available registers which +can result in spilling. Requesting fewer wavefronts can help reduce cache +thrashing, but can reduce memory latency hiding. + +This attribute controls the machine code generated by the AMDGPU target backend +to ensure it is capable of meeting the requested values. However, when the +kernel is executed, there may be other reasons that prevent meeting the request, +for example, there may be wavefronts from other kernels executing on the EU. + +An error will be given if: + - Specified values violate subtarget specifications; + - Specified values are not compatible with values provided through other + attributes; + - The AMDGPU target backend is unable to create machine code that can meet the + request. + + +Calling Conventions +=================== +Clang supports several different calling conventions, depending on the target +platform and architecture. The calling convention used for a function determines +how parameters are passed, how results are returned to the caller, and other +low-level details of calling a function. + +aarch64_vector_pcs +------------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``aarch64_vector_pcs``","``clang::aarch64_vector_pcs``","``clang::aarch64_vector_pcs``","","","","" + +On AArch64 targets, this attribute changes the calling convention of a +function to preserve additional floating-point and Advanced SIMD registers +relative to the default calling convention used for AArch64. + +This means it is more efficient to call such functions from code that performs +extensive floating-point and vector calculations, because fewer live SIMD and FP +registers need to be saved. This property makes it well-suited for e.g. +floating-point or vector math library functions, which are typically leaf +functions that require a small number of registers. + +However, using this attribute also means that it is more expensive to call +a function that adheres to the default calling convention from within such +a function. Therefore, it is recommended that this attribute is only used +for leaf functions. + +For more information, see the documentation for `aarch64_vector_pcs`_ on +the Arm Developer website. + +.. _`aarch64_vector_pcs`: https://developer.arm.com/products/software-development-tools/hpc/arm-compiler-for-hpc/vector-function-abi + + +fastcall +-------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``fastcall``","``gnu::fastcall``","","","``__fastcall`` |br| ``_fastcall``","","" + +On 32-bit x86 targets, this attribute changes the calling convention of a +function to use ECX and EDX as register parameters and clear parameters off of +the stack on return. This convention does not support variadic calls or +unprototyped functions in C, and has no effect on x86_64 targets. This calling +convention is supported primarily for compatibility with existing code. Users +seeking register parameters should use the ``regparm`` attribute, which does +not require callee-cleanup. See the documentation for `__fastcall`_ on MSDN. + +.. _`__fastcall`: http://msdn.microsoft.com/en-us/library/6xa169sk.aspx + + +ms_abi +------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``ms_abi``","``gnu::ms_abi``","","","","","" + +On non-Windows x86_64 targets, this attribute changes the calling convention of +a function to match the default convention used on Windows x86_64. This +attribute has no effect on Windows targets or non-x86_64 targets. + + +pcs +--- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``pcs``","``gnu::pcs``","","","","","" + +On ARM targets, this attribute can be used to select calling conventions +similar to ``stdcall`` on x86. Valid parameter values are "aapcs" and +"aapcs-vfp". + + +preserve_all +------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``preserve_all``","``clang::preserve_all``","``clang::preserve_all``","","","","" + +On X86-64 and AArch64 targets, this attribute changes the calling convention of +a function. The ``preserve_all`` calling convention attempts to make the code +in the caller even less intrusive than the ``preserve_most`` calling convention. +This calling convention also behaves identical to the ``C`` calling convention +on how arguments and return values are passed, but it uses a different set of +caller/callee-saved registers. This removes the burden of saving and +recovering a large register set before and after the call in the caller. If +the arguments are passed in callee-saved registers, then they will be +preserved by the callee across the call. This doesn't apply for values +returned in callee-saved registers. + +- On X86-64 the callee preserves all general purpose registers, except for + R11. R11 can be used as a scratch register. Furthermore it also preserves + all floating-point registers (XMMs/YMMs). + +The idea behind this convention is to support calls to runtime functions +that don't need to call out to any other functions. + +This calling convention, like the ``preserve_most`` calling convention, will be +used by a future version of the Objective-C runtime and should be considered +experimental at this time. + + +preserve_most +------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``preserve_most``","``clang::preserve_most``","``clang::preserve_most``","","","","" + +On X86-64 and AArch64 targets, this attribute changes the calling convention of +a function. The ``preserve_most`` calling convention attempts to make the code +in the caller as unintrusive as possible. This convention behaves identically +to the ``C`` calling convention on how arguments and return values are passed, +but it uses a different set of caller/callee-saved registers. This alleviates +the burden of saving and recovering a large register set before and after the +call in the caller. If the arguments are passed in callee-saved registers, +then they will be preserved by the callee across the call. This doesn't +apply for values returned in callee-saved registers. + +- On X86-64 the callee preserves all general purpose registers, except for + R11. R11 can be used as a scratch register. Floating-point registers + (XMMs/YMMs) are not preserved and need to be saved by the caller. + +The idea behind this convention is to support calls to runtime functions +that have a hot path and a cold path. The hot path is usually a small piece +of code that doesn't use many registers. The cold path might need to call out to +another function and therefore only needs to preserve the caller-saved +registers, which haven't already been saved by the caller. The +`preserve_most` calling convention is very similar to the ``cold`` calling +convention in terms of caller/callee-saved registers, but they are used for +different types of function calls. ``coldcc`` is for function calls that are +rarely executed, whereas `preserve_most` function calls are intended to be +on the hot path and definitely executed a lot. Furthermore ``preserve_most`` +doesn't prevent the inliner from inlining the function call. + +This calling convention will be used by a future version of the Objective-C +runtime and should therefore still be considered experimental at this time. +Although this convention was created to optimize certain runtime calls to +the Objective-C runtime, it is not limited to this runtime and might be used +by other runtimes in the future too. The current implementation only +supports X86-64 and AArch64, but the intention is to support more architectures +in the future. + + +regcall +------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``regcall``","``gnu::regcall``","","","``__regcall``","","" + +On x86 targets, this attribute changes the calling convention to +`__regcall`_ convention. This convention aims to pass as many arguments +as possible in registers. It also tries to utilize registers for the +return value whenever it is possible. + +.. _`__regcall`: https://software.intel.com/en-us/node/693069 + + +regparm +------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``regparm``","``gnu::regparm``","","","","","" + +On 32-bit x86 targets, the regparm attribute causes the compiler to pass +the first three integer parameters in EAX, EDX, and ECX instead of on the +stack. This attribute has no effect on variadic functions, and all parameters +are passed via the stack as normal. + + +stdcall +------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``stdcall``","``gnu::stdcall``","","","``__stdcall`` |br| ``_stdcall``","","" + +On 32-bit x86 targets, this attribute changes the calling convention of a +function to clear parameters off of the stack on return. This convention does +not support variadic calls or unprototyped functions in C, and has no effect on +x86_64 targets. This calling convention is used widely by the Windows API and +COM applications. See the documentation for `__stdcall`_ on MSDN. + +.. _`__stdcall`: http://msdn.microsoft.com/en-us/library/zxk0tw93.aspx + + +thiscall +-------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``thiscall``","``gnu::thiscall``","","","``__thiscall`` |br| ``_thiscall``","","" + +On 32-bit x86 targets, this attribute changes the calling convention of a +function to use ECX for the first parameter (typically the implicit ``this`` +parameter of C++ methods) and clear parameters off of the stack on return. This +convention does not support variadic calls or unprototyped functions in C, and +has no effect on x86_64 targets. See the documentation for `__thiscall`_ on +MSDN. + +.. _`__thiscall`: http://msdn.microsoft.com/en-us/library/ek8tkfbw.aspx + + +vectorcall +---------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``vectorcall``","``clang::vectorcall``","``clang::vectorcall``","","``__vectorcall`` |br| ``_vectorcall``","","" + +On 32-bit x86 *and* x86_64 targets, this attribute changes the calling +convention of a function to pass vector parameters in SSE registers. + +On 32-bit x86 targets, this calling convention is similar to ``__fastcall``. +The first two integer parameters are passed in ECX and EDX. Subsequent integer +parameters are passed in memory, and callee clears the stack. On x86_64 +targets, the callee does *not* clear the stack, and integer parameters are +passed in RCX, RDX, R8, and R9 as is done for the default Windows x64 calling +convention. + +On both 32-bit x86 and x86_64 targets, vector and floating point arguments are +passed in XMM0-XMM5. Homogeneous vector aggregates of up to four elements are +passed in sequential SSE registers if enough are available. If AVX is enabled, +256 bit vectors are passed in YMM0-YMM5. Any vector or aggregate type that +cannot be passed in registers for any reason is passed by reference, which +allows the caller to align the parameter memory. + +See the documentation for `__vectorcall`_ on MSDN for more details. + +.. _`__vectorcall`: http://msdn.microsoft.com/en-us/library/dn375768.aspx + + +Consumed Annotation Checking +============================ +Clang supports additional attributes for checking basic resource management +properties, specifically for unique objects that have a single owning reference. +The following attributes are currently supported, although **the implementation +for these annotations is currently in development and are subject to change.** + +callable_when +------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``callable_when``","``clang::callable_when``","","","","","Yes" + +Use ``__attribute__((callable_when(...)))`` to indicate what states a method +may be called in. Valid states are unconsumed, consumed, or unknown. Each +argument to this attribute must be a quoted string. E.g.: + +``__attribute__((callable_when("unconsumed", "unknown")))`` + + +consumable +---------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``consumable``","``clang::consumable``","","","","","Yes" + +Each ``class`` that uses any of the typestate annotations must first be marked +using the ``consumable`` attribute. Failure to do so will result in a warning. + +This attribute accepts a single parameter that must be one of the following: +``unknown``, ``consumed``, or ``unconsumed``. + + +param_typestate +--------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``param_typestate``","``clang::param_typestate``","","","","","Yes" + +This attribute specifies expectations about function parameters. Calls to an +function with annotated parameters will issue a warning if the corresponding +argument isn't in the expected state. The attribute is also used to set the +initial state of the parameter when analyzing the function's body. + + +return_typestate +---------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``return_typestate``","``clang::return_typestate``","","","","","Yes" + +The ``return_typestate`` attribute can be applied to functions or parameters. +When applied to a function the attribute specifies the state of the returned +value. The function's body is checked to ensure that it always returns a value +in the specified state. On the caller side, values returned by the annotated +function are initialized to the given state. + +When applied to a function parameter it modifies the state of an argument after +a call to the function returns. The function's body is checked to ensure that +the parameter is in the expected state before returning. + + +set_typestate +------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``set_typestate``","``clang::set_typestate``","","","","","Yes" + +Annotate methods that transition an object into a new state with +``__attribute__((set_typestate(new_state)))``. The new state must be +unconsumed, consumed, or unknown. + + +test_typestate +-------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``test_typestate``","``clang::test_typestate``","","","","","Yes" + +Use ``__attribute__((test_typestate(tested_state)))`` to indicate that a method +returns true if the object is in the specified state.. + + +Type Safety Checking +==================== +Clang supports additional attributes to enable checking type safety properties +that can't be enforced by the C type system. To see warnings produced by these +checks, ensure that -Wtype-safety is enabled. Use cases include: + +* MPI library implementations, where these attributes enable checking that + the buffer type matches the passed ``MPI_Datatype``; +* for HDF5 library there is a similar use case to MPI; +* checking types of variadic functions' arguments for functions like + ``fcntl()`` and ``ioctl()``. + +You can detect support for these attributes with ``__has_attribute()``. For +example: + +.. code-block:: c++ + + #if defined(__has_attribute) + # if __has_attribute(argument_with_type_tag) && \ + __has_attribute(pointer_with_type_tag) && \ + __has_attribute(type_tag_for_datatype) + # define ATTR_MPI_PWT(buffer_idx, type_idx) __attribute__((pointer_with_type_tag(mpi,buffer_idx,type_idx))) + /* ... other macros ... */ + # endif + #endif + + #if !defined(ATTR_MPI_PWT) + # define ATTR_MPI_PWT(buffer_idx, type_idx) + #endif + + int MPI_Send(void *buf, int count, MPI_Datatype datatype /*, other args omitted */) + ATTR_MPI_PWT(1,3); + +argument_with_type_tag +---------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``argument_with_type_tag`` |br| ``pointer_with_type_tag``","``clang::argument_with_type_tag`` |br| ``clang::pointer_with_type_tag``","``clang::argument_with_type_tag`` |br| ``clang::pointer_with_type_tag``","","","","" + +Use ``__attribute__((argument_with_type_tag(arg_kind, arg_idx, +type_tag_idx)))`` on a function declaration to specify that the function +accepts a type tag that determines the type of some other argument. + +This attribute is primarily useful for checking arguments of variadic functions +(``pointer_with_type_tag`` can be used in most non-variadic cases). + +In the attribute prototype above: + * ``arg_kind`` is an identifier that should be used when annotating all + applicable type tags. + * ``arg_idx`` provides the position of a function argument. The expected type of + this function argument will be determined by the function argument specified + by ``type_tag_idx``. In the code example below, "3" means that the type of the + function's third argument will be determined by ``type_tag_idx``. + * ``type_tag_idx`` provides the position of a function argument. This function + argument will be a type tag. The type tag will determine the expected type of + the argument specified by ``arg_idx``. In the code example below, "2" means + that the type tag associated with the function's second argument should agree + with the type of the argument specified by ``arg_idx``. + +For example: + +.. code-block:: c++ + + int fcntl(int fd, int cmd, ...) + __attribute__(( argument_with_type_tag(fcntl,3,2) )); + // The function's second argument will be a type tag; this type tag will + // determine the expected type of the function's third argument. + + +pointer_with_type_tag +--------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``argument_with_type_tag`` |br| ``pointer_with_type_tag``","``clang::argument_with_type_tag`` |br| ``clang::pointer_with_type_tag``","``clang::argument_with_type_tag`` |br| ``clang::pointer_with_type_tag``","","","","" + +Use ``__attribute__((pointer_with_type_tag(ptr_kind, ptr_idx, type_tag_idx)))`` +on a function declaration to specify that the function accepts a type tag that +determines the pointee type of some other pointer argument. + +In the attribute prototype above: + * ``ptr_kind`` is an identifier that should be used when annotating all + applicable type tags. + * ``ptr_idx`` provides the position of a function argument; this function + argument will have a pointer type. The expected pointee type of this pointer + type will be determined by the function argument specified by + ``type_tag_idx``. In the code example below, "1" means that the pointee type + of the function's first argument will be determined by ``type_tag_idx``. + * ``type_tag_idx`` provides the position of a function argument; this function + argument will be a type tag. The type tag will determine the expected pointee + type of the pointer argument specified by ``ptr_idx``. In the code example + below, "3" means that the type tag associated with the function's third + argument should agree with the pointee type of the pointer argument specified + by ``ptr_idx``. + +For example: + +.. code-block:: c++ + + typedef int MPI_Datatype; + int MPI_Send(void *buf, int count, MPI_Datatype datatype /*, other args omitted */) + __attribute__(( pointer_with_type_tag(mpi,1,3) )); + // The function's 3rd argument will be a type tag; this type tag will + // determine the expected pointee type of the function's 1st argument. + + +type_tag_for_datatype +--------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``type_tag_for_datatype``","``clang::type_tag_for_datatype``","``clang::type_tag_for_datatype``","","","","" + +When declaring a variable, use +``__attribute__((type_tag_for_datatype(kind, type)))`` to create a type tag that +is tied to the ``type`` argument given to the attribute. + +In the attribute prototype above: + * ``kind`` is an identifier that should be used when annotating all applicable + type tags. + * ``type`` indicates the name of the type. + +Clang supports annotating type tags of two forms. + + * **Type tag that is a reference to a declared identifier.** + Use ``__attribute__((type_tag_for_datatype(kind, type)))`` when declaring that + identifier: + + .. code-block:: c++ + + typedef int MPI_Datatype; + extern struct mpi_datatype mpi_datatype_int + __attribute__(( type_tag_for_datatype(mpi,int) )); + #define MPI_INT ((MPI_Datatype) &mpi_datatype_int) + // &mpi_datatype_int is a type tag. It is tied to type "int". + + * **Type tag that is an integral literal.** + Declare a ``static const`` variable with an initializer value and attach + ``__attribute__((type_tag_for_datatype(kind, type)))`` on that declaration: + + .. code-block:: c++ + + typedef int MPI_Datatype; + static const MPI_Datatype mpi_datatype_int + __attribute__(( type_tag_for_datatype(mpi,int) )) = 42; + #define MPI_INT ((MPI_Datatype) 42) + // The number 42 is a type tag. It is tied to type "int". + + +The ``type_tag_for_datatype`` attribute also accepts an optional third argument +that determines how the type of the function argument specified by either +``arg_idx`` or ``ptr_idx`` is compared against the type associated with the type +tag. (Recall that for the ``argument_with_type_tag`` attribute, the type of the +function argument specified by ``arg_idx`` is compared against the type +associated with the type tag. Also recall that for the ``pointer_with_type_tag`` +attribute, the pointee type of the function argument specified by ``ptr_idx`` is +compared against the type associated with the type tag.) There are two supported +values for this optional third argument: + + * ``layout_compatible`` will cause types to be compared according to + layout-compatibility rules (In C++11 [class.mem] p 17, 18, see the + layout-compatibility rules for two standard-layout struct types and for two + standard-layout union types). This is useful when creating a type tag + associated with a struct or union type. For example: + + .. code-block:: c++ + + /* In mpi.h */ + typedef int MPI_Datatype; + struct internal_mpi_double_int { double d; int i; }; + extern struct mpi_datatype mpi_datatype_double_int + __attribute__(( type_tag_for_datatype(mpi, + struct internal_mpi_double_int, layout_compatible) )); + + #define MPI_DOUBLE_INT ((MPI_Datatype) &mpi_datatype_double_int) + + int MPI_Send(void *buf, int count, MPI_Datatype datatype, ...) + __attribute__(( pointer_with_type_tag(mpi,1,3) )); + + /* In user code */ + struct my_pair { double a; int b; }; + struct my_pair *buffer; + MPI_Send(buffer, 1, MPI_DOUBLE_INT /*, ... */); // no warning because the + // layout of my_pair is + // compatible with that of + // internal_mpi_double_int + + struct my_int_pair { int a; int b; } + struct my_int_pair *buffer2; + MPI_Send(buffer2, 1, MPI_DOUBLE_INT /*, ... */); // warning because the + // layout of my_int_pair + // does not match that of + // internal_mpi_double_int + + * ``must_be_null`` specifies that the function argument specified by either + ``arg_idx`` (for the ``argument_with_type_tag`` attribute) or ``ptr_idx`` (for + the ``pointer_with_type_tag`` attribute) should be a null pointer constant. + The second argument to the ``type_tag_for_datatype`` attribute is ignored. For + example: + + .. code-block:: c++ + + /* In mpi.h */ + typedef int MPI_Datatype; + extern struct mpi_datatype mpi_datatype_null + __attribute__(( type_tag_for_datatype(mpi, void, must_be_null) )); + + #define MPI_DATATYPE_NULL ((MPI_Datatype) &mpi_datatype_null) + int MPI_Send(void *buf, int count, MPI_Datatype datatype, ...) + __attribute__(( pointer_with_type_tag(mpi,1,3) )); + + /* In user code */ + struct my_pair { double a; int b; }; + struct my_pair *buffer; + MPI_Send(buffer, 1, MPI_DATATYPE_NULL /*, ... */); // warning: MPI_DATATYPE_NULL + // was specified but buffer + // is not a null pointer + + +OpenCL Address Spaces +===================== +The address space qualifier may be used to specify the region of memory that is +used to allocate the object. OpenCL supports the following address spaces: +__generic(generic), __global(global), __local(local), __private(private), +__constant(constant). + + .. code-block:: c + + __constant int c = ...; + + __generic int* foo(global int* g) { + __local int* l; + private int p; + ... + return l; + } + +More details can be found in the OpenCL C language Spec v2.0, Section 6.5. + +__constant, constant, [[clang::opencl_constant]] +------------------------------------------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``opencl_constant``","``clang::opencl_constant``","``clang::opencl_constant``","","``__constant`` |br| ``constant``","","" + +The constant address space attribute signals that an object is located in +a constant (non-modifiable) memory region. It is available to all work items. +Any type can be annotated with the constant address space attribute. Objects +with the constant address space qualifier can be declared in any scope and must +have an initializer. + + +__generic, generic, [[clang::opencl_generic]] +--------------------------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``opencl_generic``","``clang::opencl_generic``","``clang::opencl_generic``","","``__generic`` |br| ``generic``","","" + +The generic address space attribute is only available with OpenCL v2.0 and later. +It can be used with pointer types. Variables in global and local scope and +function parameters in non-kernel functions can have the generic address space +type attribute. It is intended to be a placeholder for any other address space +except for '__constant' in OpenCL code which can be used with multiple address +spaces. + + +__global, global, [[clang::opencl_global]] +------------------------------------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``opencl_global``","``clang::opencl_global``","``clang::opencl_global``","","``__global`` |br| ``global``","","" + +The global address space attribute specifies that an object is allocated in +global memory, which is accessible by all work items. The content stored in this +memory area persists between kernel executions. Pointer types to the global +address space are allowed as function parameters or local variables. Starting +with OpenCL v2.0, the global address space can be used with global (program +scope) variables and static local variable as well. + + +__local, local, [[clang::opencl_local]] +--------------------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``opencl_local``","``clang::opencl_local``","``clang::opencl_local``","","``__local`` |br| ``local``","","" + +The local address space specifies that an object is allocated in the local (work +group) memory area, which is accessible to all work items in the same work +group. The content stored in this memory region is not accessible after +the kernel execution ends. In a kernel function scope, any variable can be in +the local address space. In other scopes, only pointer types to the local address +space are allowed. Local address space variables cannot have an initializer. + + +__private, private, [[clang::opencl_private]] +--------------------------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``opencl_private``","``clang::opencl_private``","``clang::opencl_private``","","``__private`` |br| ``private``","","" + +The private address space specifies that an object is allocated in the private +(work item) memory. Other work items cannot access the same memory area and its +content is destroyed after work item execution ends. Local variables can be +declared in the private address space. Function arguments are always in the +private address space. Kernel function arguments of a pointer or an array type +cannot point to the private address space. + + +Nullability Attributes +====================== +Whether a particular pointer may be "null" is an important concern when working with pointers in the C family of languages. The various nullability attributes indicate whether a particular pointer can be null or not, which makes APIs more expressive and can help static analysis tools identify bugs involving null pointers. Clang supports several kinds of nullability attributes: the ``nonnull`` and ``returns_nonnull`` attributes indicate which function or method parameters and result types can never be null, while nullability type qualifiers indicate which pointer types can be null (``_Nullable``) or cannot be null (``_Nonnull``). + +The nullability (type) qualifiers express whether a value of a given pointer type can be null (the ``_Nullable`` qualifier), doesn't have a defined meaning for null (the ``_Nonnull`` qualifier), or for which the purpose of null is unclear (the ``_Null_unspecified`` qualifier). Because nullability qualifiers are expressed within the type system, they are more general than the ``nonnull`` and ``returns_nonnull`` attributes, allowing one to express (for example) a nullable pointer to an array of nonnull pointers. Nullability qualifiers are written to the right of the pointer to which they apply. For example: + + .. code-block:: c + + // No meaningful result when 'ptr' is null (here, it happens to be undefined behavior). + int fetch(int * _Nonnull ptr) { return *ptr; } + + // 'ptr' may be null. + int fetch_or_zero(int * _Nullable ptr) { + return ptr ? *ptr : 0; + } + + // A nullable pointer to non-null pointers to const characters. + const char *join_strings(const char * _Nonnull * _Nullable strings, unsigned n); + +In Objective-C, there is an alternate spelling for the nullability qualifiers that can be used in Objective-C methods and properties using context-sensitive, non-underscored keywords. For example: + + .. code-block:: objective-c + + @interface NSView : NSResponder + - (nullable NSView *)ancestorSharedWithView:(nonnull NSView *)aView; + @property (assign, nullable) NSView *superview; + @property (readonly, nonnull) NSArray *subviews; + @end + +_Nonnull +-------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "","","","","``_Nonnull``","","" + +The ``_Nonnull`` nullability qualifier indicates that null is not a meaningful value for a value of the ``_Nonnull`` pointer type. For example, given a declaration such as: + + .. code-block:: c + + int fetch(int * _Nonnull ptr); + +a caller of ``fetch`` should not provide a null value, and the compiler will produce a warning if it sees a literal null value passed to ``fetch``. Note that, unlike the declaration attribute ``nonnull``, the presence of ``_Nonnull`` does not imply that passing null is undefined behavior: ``fetch`` is free to consider null undefined behavior or (perhaps for backward-compatibility reasons) defensively handle null. + + +_Null_unspecified +----------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "","","","","``_Null_unspecified``","","" + +The ``_Null_unspecified`` nullability qualifier indicates that neither the ``_Nonnull`` nor ``_Nullable`` qualifiers make sense for a particular pointer type. It is used primarily to indicate that the role of null with specific pointers in a nullability-annotated header is unclear, e.g., due to overly-complex implementations or historical factors with a long-lived API. + + +_Nullable +--------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "","","","","``_Nullable``","","" + +The ``_Nullable`` nullability qualifier indicates that a value of the ``_Nullable`` pointer type can be null. For example, given: + + .. code-block:: c + + int fetch_or_zero(int * _Nullable ptr); + +a caller of ``fetch_or_zero`` can provide null. + + +nonnull +------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``nonnull``","``gnu::nonnull``","","","","","" + +The ``nonnull`` attribute indicates that some function parameters must not be null, and can be used in several different ways. It's original usage (`from GCC `_) is as a function (or Objective-C method) attribute that specifies which parameters of the function are nonnull in a comma-separated list. For example: + + .. code-block:: c + + extern void * my_memcpy (void *dest, const void *src, size_t len) + __attribute__((nonnull (1, 2))); + +Here, the ``nonnull`` attribute indicates that parameters 1 and 2 +cannot have a null value. Omitting the parenthesized list of parameter indices means that all parameters of pointer type cannot be null: + + .. code-block:: c + + extern void * my_memcpy (void *dest, const void *src, size_t len) + __attribute__((nonnull)); + +Clang also allows the ``nonnull`` attribute to be placed directly on a function (or Objective-C method) parameter, eliminating the need to specify the parameter index ahead of type. For example: + + .. code-block:: c + + extern void * my_memcpy (void *dest __attribute__((nonnull)), + const void *src __attribute__((nonnull)), size_t len); + +Note that the ``nonnull`` attribute indicates that passing null to a non-null parameter is undefined behavior, which the optimizer may take advantage of to, e.g., remove null checks. The ``_Nonnull`` type qualifier indicates that a pointer cannot be null in a more general manner (because it is part of the type system) and does not imply undefined behavior, making it more widely applicable. + + +returns_nonnull +--------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``returns_nonnull``","``gnu::returns_nonnull``","","","","","Yes" + +The ``returns_nonnull`` attribute indicates that a particular function (or Objective-C method) always returns a non-null pointer. For example, a particular system ``malloc`` might be defined to terminate a process when memory is not available rather than returning a null pointer: + + .. code-block:: c + + extern void * malloc (size_t size) __attribute__((returns_nonnull)); + +The ``returns_nonnull`` attribute implies that returning a null pointer is undefined behavior, which the optimizer may take advantage of. The ``_Nonnull`` type qualifier indicates that a pointer cannot be null in a more general manner (because it is part of the type system) and does not imply undefined behavior, making it more widely applicable + + +Handle Attributes +================= +Handles are a way to identify resources like files, sockets, and processes. +They are more opaque than pointers and widely used in system programming. They +have similar risks such as never releasing a resource associated with a handle, +attempting to use a handle that was already released, or trying to release a +handle twice. Using the annotations below it is possible to make the ownership +of the handles clear: whose responsibility is to release them. They can also +aid static analysis tools to find bugs. + +acquire_handle +-------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``acquire_handle``","``clang::acquire_handle``","``clang::acquire_handle``","","","","Yes" + +If this annotation is on a function or a function type it is assumed to return +a new handle. In case this annotation is on an output parameter, +the function is assumed to fill the corresponding argument with a new +handle. + +.. code-block:: c++ + + // Output arguments from Zircon. + zx_status_t zx_socket_create(uint32_t options, + zx_handle_t __attribute__((acquire_handle)) * out0, + zx_handle_t* out1 [[clang::acquire_handle]]); + + + // Returned handle. + [[clang::acquire_handle]] int open(const char *path, int oflag, ... ); + int open(const char *path, int oflag, ... ) __attribute__((acquire_handle)); + + +release_handle +-------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``release_handle``","``clang::release_handle``","``clang::release_handle``","","","","Yes" + +If a function parameter is annotated with `release_handle` it is assumed to +close the handle. It is also assumed to require an open handle to work with. + +.. code-block:: c++ + + zx_status_t zx_handle_close(zx_handle_t handle [[clang::release_handle]]); + + +use_handle +---------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``use_handle``","``clang::use_handle``","``clang::use_handle``","","","","Yes" + +A function taking a handle by value might close the handle. If a function +parameter is annotated with `use_handle` it is assumed to not to change +the state of the handle. It is also assumed to require an open handle to work with. + +.. code-block:: c++ + + zx_status_t zx_port_wait(zx_handle_t handle [[clang::use_handle]], + zx_time_t deadline, + zx_port_packet_t* packet); + + diff --git a/clang/docs/ClangCommandLineReference.rst b/clang/docs/ClangCommandLineReference.rst index 5b8a96b61b3de..10c14db1b8957 100644 --- a/clang/docs/ClangCommandLineReference.rst +++ b/clang/docs/ClangCommandLineReference.rst @@ -90,7 +90,7 @@ Run the static analyzer .. option:: --analyzer-output -Static analyzer report output format (html\|plist\|plist-multi-file\|plist-html\|text). +Static analyzer report output format (html\|plist\|plist-multi-file\|plist-html\|sarif\|text). .. option:: -ansi, --ansi @@ -122,14 +122,6 @@ Output path for the plist report .. option:: -bundle\_loader .. program:: clang -.. option:: -cfguard - -Emit tables and checks for Windows Control Flow Guard. - -.. option:: -cfguard-no-checks - -Emit tables required for Windows Control Flow Guard without checks. - .. option:: -client\_name .. option:: -compatibility\_version @@ -200,6 +192,10 @@ Filename (or -) to write dependency output to Emit Clang AST files for source inputs +.. option:: -enable-trivial-auto-var-init-zero-knowing-it-will-be-removed-from-clang + +Trivial automatic variable initialization to zero is only here for benchmarks, it'll eventually be removed, and I'm OK with that because I'm only using it to benchmark + .. option:: -exported\_symbols\_list .. option:: -faligned-new= @@ -212,10 +208,6 @@ Use approximate transcendental functions Flush denormal floating point values to zero in CUDA device mode. -.. option:: -fcuda-rdc, -fno-cuda-rdc - -Generate relocatable device code, also known as separate compilation mode. - .. option:: -fcuda-short-ptr, -fno-cuda-short-ptr Use 32-bit pointers for accessing const/local/shared address spaces. @@ -224,8 +216,20 @@ Use 32-bit pointers for accessing const/local/shared address spaces. Reserve register r19 (Hexagon only) +.. option:: -fgpu-allow-device-init, -fno-gpu-allow-device-init + +Allow device side init function in HIP + +.. option:: -fgpu-rdc, -fcuda-rdc, -fno-gpu-rdc + +Generate relocatable device code, also known as separate compilation mode. + .. option:: -fheinous-gnu-extensions +.. option:: -fhip-new-launch-api, -fno-hip-new-launch-api + +Use new kernel launching API for HIP. + .. option:: -flat\_namespace .. option:: -fopenmp-targets=,... @@ -248,6 +252,10 @@ Specify comma-separated list of triples OpenMP offloading targets to be supporte Add -rpath with architecture-specific resource directory to the linker flags +.. option:: -fsanitize-system-blacklist= + +Path to system blacklist file for sanitizers + .. option:: --gcc-toolchain=, -gcc-toolchain Use the gcc toolchain at the given directory @@ -256,6 +264,16 @@ Use the gcc toolchain at the given directory Generate CodeView debug information +.. option:: -gcodeview-ghash, -gno-codeview-ghash + +Emit type record hashes in a .debug$H section + +.. option:: -ginline-line-tables, -gno-inline-line-tables + +.. option:: --gpu-max-threads-per-block= + +Default max threads per block for kernel launch bounds for HIP + .. option:: -headerpad\_max\_install\_names .. option:: -help, --help @@ -280,6 +298,8 @@ Make the next included directory (-I or -F) an indexer header map .. option:: -install\_name +.. option:: -interface-stub-version= + .. option:: -keep\_private\_externs .. option:: -lazy\_framework @@ -290,6 +310,10 @@ Make the next included directory (-I or -F) an indexer header map .. option:: -mbig-endian, -EB +.. option:: -mbranch-protection= + +Enforce targets of indirect branches and function returns + .. option:: --migrate Run the migrator @@ -334,12 +358,14 @@ Disable builtin #include directories .. option:: -nocudainc -.. option:: -nocudalib - .. option:: -nodefaultlibs .. option:: -nofixprebinding +.. option:: -nogpulib, -nocudalib + +Do not link device library for CUDA/HIP device compilation + .. option:: -nolibc .. option:: -nomultidefs @@ -594,6 +620,12 @@ Statically link the sanitizer runtime .. option:: -static-libstdc++ +.. option:: -static-openmp + +Use the static host OpenMP runtime while linking. + +.. option:: -static-pie + .. option:: -std-default= .. option:: -stdlib=, --stdlib=, --stdlib @@ -614,10 +646,6 @@ C++ standard library to use Generate code for the given target -.. option:: --print-supported-cpus - -Print supported cpu models for the given target - .. option:: -time Time individual commands @@ -638,6 +666,10 @@ Enable some traditional CPP emulation .. option:: -unexported\_symbols\_list +.. option:: -unwindlib=, --unwindlib= + +Unwind library to use + .. option:: -v, --verbose Show commands to run and use verbose output @@ -696,10 +728,18 @@ Only run preprocess and compilation steps Only run preprocess, compile, and assemble steps +.. option:: -emit-interface-stubs + +Generate Inteface Stub Files. + .. option:: -emit-llvm Use the LLVM representation for assembler and object files +.. option:: -emit-merged-ifs + +Generate Interface Stub Files, emit merged text not binary. + .. option:: -fsyntax-only .. option:: -module-file-info @@ -800,15 +840,7 @@ Don't use blacklist file for sanitizers .. option:: -fparse-all-comments -.. option:: -frecord-command-line, -frecord-gcc-switches, -fno-record-command-line, -fno-record-gcc-switches - -Generate a section named ".GCC.command.line" containing the clang driver -command-line. After linking, the section may contain multiple command lines, -which will be individually terminated by null bytes. Separate arguments within -a command line are combined with spaces; spaces and backslashes within an -argument are escaped with backslashes. This format differs from the format of -the equivalent section produced by GCC with the -frecord-gcc-switches flag. -This option is currently only supported on ELF targets. +.. option:: -frecord-command-line, -fno-record-command-line, -frecord-gcc-switches .. option:: -fsanitize-address-field-padding= @@ -818,24 +850,26 @@ Level of field padding for AddressSanitizer Enable linker dead stripping of globals in AddressSanitizer -.. option:: -fsanitize-address-use-odr-indicator, -fno-sanitize-address-use-odr-indicator - -Enable ODR indicator globals to avoid false ODR violation reports in partially sanitized programs at the cost of an increase in binary size - .. option:: -fsanitize-address-poison-custom-array-cookie, -fno-sanitize-address-poison-custom-array-cookie -Enable "poisoning" array cookies when allocating arrays with a custom operator new\[\] in Address Sanitizer, preventing accesses to the cookies from user code. An array cookie is a small implementation-defined header added to certain array allocations to record metadata such as the length of the array. Accesses to array cookies from user code are technically allowed by the standard but are more likely to be the result of an out-of-bounds array access. - -An operator new\[\] is "custom" if it is not one of the allocation functions provided by the C++ standard library. Array cookies from non-custom allocation functions are always poisoned. +Enable poisoning array cookies when using custom operator new\[\] in AddressSanitizer .. option:: -fsanitize-address-use-after-scope, -fno-sanitize-address-use-after-scope Enable use-after-scope detection in AddressSanitizer +.. option:: -fsanitize-address-use-odr-indicator, -fno-sanitize-address-use-odr-indicator + +Enable ODR indicator globals to avoid false ODR violation reports in partially sanitized programs at the cost of an increase in binary size + .. option:: -fsanitize-blacklist= Path to blacklist file for sanitizers +.. option:: -fsanitize-cfi-canonical-jump-tables, -fno-sanitize-cfi-canonical-jump-tables + +Make the jump table addresses canonical in the symbol table + .. option:: -fsanitize-cfi-cross-dso, -fno-sanitize-cfi-cross-dso Enable control flow integrity (CFI) checks for cross-DSO calls. @@ -848,7 +882,13 @@ Generalize pointers in CFI indirect call type signature checks Specify the type of coverage instrumentation for Sanitizers -.. option:: -fsanitize-link-c++-runtime +.. option:: -fsanitize-hwaddress-abi= + +Select the HWAddressSanitizer ABI to target (interceptor or platform, default interceptor). This option is currently unused. + +.. option:: -fsanitize-link-c++-runtime, -fno-sanitize-link-c++-runtime + +.. option:: -fsanitize-link-runtime, -fno-sanitize-link-runtime .. option:: -fsanitize-memory-track-origins, -fno-sanitize-memory-track-origins @@ -910,6 +950,10 @@ Enable function outlining (AArch64 only) .. option:: --param , --param= +.. option:: -print-supported-cpus, --print-supported-cpus, -mcpu=?, -mtune=? + +Print supported cpu models for the given target (if target is not specified, it will print the supported cpus for the default target) + .. option:: -std=, --std=, --std Language standard to compile for @@ -951,6 +995,10 @@ Pass the comma separated arguments in to the preprocessor Pass to the preprocessor +.. option:: -fmacro-prefix-map= + +remap file source paths in predefined preprocessor macros + Include path management ----------------------- @@ -1080,10 +1128,20 @@ Set directory to include search path with prefix Add directory to SYSTEM include search path, absolute paths are relative to -isysroot +.. option:: --libomptarget-nvptx-path= + +Path to libomptarget-nvptx libraries + .. option:: --ptxas-path= Path to ptxas (used for compiling CUDA code) +.. program:: clang1 +.. option:: -stdlib++-isystem +.. program:: clang + +Use directory as the C++ standard library include path + .. option:: --system-header-prefix=, --no-system-header-prefix=, --system-header-prefix Treat all #include paths starting with as including a system header. @@ -1235,6 +1293,10 @@ Use ANSI escape codes for diagnostics Use Apple's kernel extensions ABI +.. option:: -fapple-link-rtlib + +Force linking the clang builtins runtime library + .. option:: -fapple-pragma-pack, -fno-apple-pragma-pack Enable Apple gcc-compatible #pragma pack handling @@ -1289,6 +1351,8 @@ Enable C++ static destructor registration (the default) Instrument control-flow architecture protection. Options: return, branch, full, none. +.. option:: -fcf-runtime-abi= + .. option:: -fchar8\_t, -fno-char8\_t Enable C++ builtin type char8\_t @@ -1313,6 +1377,10 @@ Use colors in diagnostics .. option:: -fconstexpr-steps= +.. option:: -fconvergent-functions + +Assume functions may be convergent + .. option:: -fcoroutines-ts, -fno-coroutines-ts Enable support for the C++ Coroutines TS @@ -1323,6 +1391,16 @@ Generate coverage mapping to enable code coverage analysis .. option:: -fcreate-profile +.. option:: -fcs-profile-generate + +Generate instrumented code to collect context sensitive execution counts into default.profraw (overridden by LLVM\_PROFILE\_FILE env var) + +.. program:: clang1 +.. option:: -fcs-profile-generate= +.. program:: clang + +Generate instrumented code to collect context sensitive execution counts into /default.profraw (overridden by LLVM\_PROFILE\_FILE env var) + .. option:: -fcxx-exceptions, -fno-cxx-exceptions Enable C++ exceptions @@ -1333,6 +1411,14 @@ Enable C++ exceptions Place each data in its own section (ELF Only) +.. option:: -fdebug-compilation-dir , -fdebug-compilation-dir= + +The compilation directory to embed in the debug info. + +.. option:: -fdebug-default-version= + +Default DWARF version to use, if a -g option caused DWARF debug info to be produced + .. option:: -fdebug-info-for-profiling, -fno-debug-info-for-profiling Emit extra debug info to make sample profile more accurate. @@ -1349,6 +1435,10 @@ Emit macro debug information remap file source paths in debug info +.. option:: -fdebug-ranges-base-address, -fno-debug-ranges-base-address + +Use DWARF base address selection entries in debug\_ranges + .. option:: -fdebug-types-section, -fno-debug-types-section Place debug types in their own section (ELF Only) @@ -1439,12 +1529,20 @@ Enable support for exception handling .. option:: -fexec-charset= +.. option:: -fexperimental-new-constant-interpreter + +Enable the experimental new constant interpreter + .. option:: -fextdirs=, --extdirs , --extdirs= .. option:: -ffast-math, -fno-fast-math Allow aggressive, lossy floating-point optimizations +.. option:: -ffile-prefix-map= + +remap file source paths in debug info and predefined preprocessor macros + .. option:: -ffinite-math-only, -fno-finite-math-only .. option:: -ffixed-point, -fno-fixed-point @@ -1453,6 +1551,10 @@ Enable fixed point types .. option:: -ffor-scope, -fno-for-scope +.. option:: -fforce-dwarf-frame, -fno-force-dwarf-frame + +Always emit a debug frame section + .. option:: -fforce-emit-vtables, -fno-force-emit-vtables Emits more virtual tables to improve devirtualization @@ -1463,7 +1565,15 @@ Enable support for int128\_t type .. option:: -ffp-contract= -Form fused FP ops (e.g. FMAs): fast (everywhere) \| on (according to FP\_CONTRACT pragma, default) \| off (never fuse) +Form fused FP ops (e.g. FMAs): fast (everywhere) \| on (according to FP\_CONTRACT pragma) \| off (never fuse). Default is 'fast' for CUDA/HIP and 'on' otherwise. + +.. option:: -ffp-exception-behavior= + +Specifies the exception behavior of floating-point operations. + +.. option:: -ffp-model= + +Controls the semantics of floating-point calculations. .. option:: -ffreestanding @@ -1487,6 +1597,10 @@ Generate output compatible with the standard GNU Objective-C runtime Use the gnu89 inline semantics +.. option:: -fgnuc-version= + +Sets various macros to claim compatibility with the given GCC version (default is 4.2.1) + .. option:: -fhonor-infinities, -fhonor-infinites, -fno-honor-infinities .. option:: -fhonor-nans, -fno-honor-nans @@ -1517,13 +1631,19 @@ Like -finstrument-functions, but insert the calls after inlining Enable the integrated assembler +.. option:: -fintegrated-cc1, -fno-integrated-cc1 + +Run cc1 in-process + .. option:: -fjump-tables, -fno-jump-tables .. option:: -fkeep-static-consts Keep static const variables even if unused -.. option:: -flax-vector-conversions, -fno-lax-vector-conversions +.. option:: -flax-vector-conversions=, -flax-vector-conversions (equivalent to -flax-vector-conversions=integer), -fno-lax-vector-conversions (equivalent to -flax-vector-conversions=none) + +Enable implicit vector bit-casts .. option:: -flimited-precision= @@ -1591,6 +1711,10 @@ Like -fmodules-decluse but requires all headers to be in modules Enable support for the C++ Modules TS +.. option:: -fmodules-validate-input-files-content + +Validate PCM input files based on content if mtime differs + .. option:: -fms-compatibility, -fno-ms-compatibility Enable full Microsoft Visual C++ compatibility @@ -1605,7 +1729,7 @@ Accept some non-standard constructs supported by the Microsoft compiler .. option:: -fms-memptr-rep= -.. option:: -fms-volatile +.. option:: -fms-volatile .. option:: -fmsc-version= @@ -1643,8 +1767,20 @@ Control emission of RTTI data .. option:: -fno-strict-modules-decluse +.. option:: -fno-temp-file + +Directly create compilation output files. This may lead to incorrect incremental builds if the compiler crashes + +.. option:: -fno-virtual-function\_elimination + .. option:: -fno-working-directory +.. option:: -fno\_modules-validate-input-files-content + +.. program:: clang1 +.. option:: -fno\_pch-validate-input-files-content +.. program:: clang + .. option:: -fnoxray-link-deps .. option:: -fobjc-abi-version= @@ -1657,6 +1793,8 @@ Synthesize retain and release calls for Objective-C pointers Use EH-safe code when synthesizing retains and releases in -fobjc-arc +.. option:: -fobjc-convert-messages-to-runtime-calls, -fno-objc-convert-messages-to-runtime-calls + .. option:: -fobjc-exceptions, -fno-objc-exceptions Enable Objective-C exceptions @@ -1701,8 +1839,7 @@ Emit OpenMP code only for SIMD-based constructs. .. option:: -foptimization-record-file= -Implies -fsave-optimization-record. On Darwin platforms, this - cannot be used with multiple -arch options. +Specify the output name of the file containing the optimization remarks. Implies -fsave-optimization-record. On Darwin platforms, this cannot be used with multiple -arch options. .. option:: -foptimization-record-passes= @@ -1710,6 +1847,10 @@ Only include passes which match a specified regular expression in the generated .. option:: -foptimize-sibling-calls, -fno-optimize-sibling-calls +.. option:: -forder-file-instrumentation + +Generate instrumented code to collect order file into default.profraw file (overridden by '=' form of option or LLVM\_PROFILE\_FILE env var) + .. option:: -foutput-class-dir=, --output-class-directory , --output-class-directory= .. option:: -fpack-struct, -fno-pack-struct @@ -1724,12 +1865,24 @@ Specify the default maximum struct packing alignment Recognize and construct Pascal-style string literals +.. option:: -fpass-plugin= + +Load pass plugin from a dynamic shared object file (only with new pass manager). + +.. option:: -fpatchable-function-entry= + +Generate M NOPs before function entry and N-M NOPs after function entry + .. option:: -fpcc-struct-return Override the default ABI to return all structs on the stack .. option:: -fpch-preprocess +.. option:: -fpch-validate-input-files-content + +Validate PCH input files based on content if mtime differs + .. option:: -fpic, -fno-pic .. option:: -fpie, -fno-pie @@ -1748,6 +1901,14 @@ Load the named plugin (dynamic shared object) .. option:: -fprofile-dir= +.. option:: -fprofile-exclude-files= + +Instrument only functions from files where names don't match all the regexes separated by a semi-colon + +.. option:: -fprofile-filter-files= + +Instrument only functions from files where names match any regex separated by a semi-colon + .. option:: -fprofile-generate, -fno-profile-generate Generate instrumented code to collect execution counts into default.profraw (overridden by LLVM\_PROFILE\_FILE env var) @@ -1776,6 +1937,10 @@ Generate instrumented code to collect execution counts into (overridden b Use instrumentation data for profile-guided optimization +.. option:: -fprofile-remapping-file=, -fprofile-remapping-file + +Use the remappings described in to match the profile data against names in the program + .. option:: -fprofile-sample-accurate, -fauto-profile-accurate, -fno-profile-sample-accurate Specifies that the sample profile is accurate. If the sample @@ -1831,6 +1996,8 @@ Turn on loop reroller .. option:: -fropi, -fno-ropi +.. option:: -frounding-math, -fno-rounding-math + .. option:: -frtti, -fno-rtti .. option:: -frwpi, -fno-rwpi @@ -1843,7 +2010,7 @@ Generate a YAML optimization record file .. option:: -fsave-optimization-record= .. program:: clang -Generate an optimization record file in a specific format. +Generate an optimization record file in a specific format .. option:: -fseh-exceptions @@ -1893,19 +2060,23 @@ Enable the superword-level parallelism vectorization passes Provide minimal debug info in the object/executable to facilitate online symbolication/stack traces in the absence of .dwo/.dwp files when using Split DWARF +.. option:: -fsplit-lto-unit, -fno-split-lto-unit + +Enables splitting of the LTO unit. + .. option:: -fsplit-stack .. option:: -fstack-protector, -fno-stack-protector -Enable stack protectors for functions potentially vulnerable to stack smashing +Enable stack protectors for some functions vulnerable to stack smashing. This uses a loose heuristic which considers functions vulnerable if they contain a char (or 8bit integer) array or constant sized calls to alloca, which are of greater size than ssp-buffer-size (default: 8 bytes). All variable sized calls to alloca are considered vulnerable .. option:: -fstack-protector-all -Force the usage of stack protectors for all functions +Enable stack protectors for all functions .. option:: -fstack-protector-strong -Use a strong heuristic to apply stack protectors to functions +Enable stack protectors for some functions vulnerable to stack smashing. Compared to -fstack-protector, this uses a stronger heuristic that includes functions containing arrays of any size (and any type), as well as any calls to alloca or the taking of an address from a local variable .. option:: -fstack-size-section, -fno-stack-size-section @@ -1937,6 +2108,8 @@ Enable optimizations based on the strict rules for overwriting polymorphic C++ o .. option:: -fstruct-path-tbaa, -fno-struct-path-tbaa +.. option:: -fsymbol-partition= + .. option:: -ftabstop= .. option:: -ftemplate-backtrace-limit= @@ -1947,6 +2120,10 @@ Enable optimizations based on the strict rules for overwriting polymorphic C++ o .. option:: -ftest-coverage +.. option:: -fthin-link-bitcode= + +Write minimized bitcode to for the ThinLTO thin link only + .. option:: -fthinlto-index= Perform ThinLTO importing using provided function summary index @@ -1957,8 +2134,10 @@ Perform ThinLTO importing using provided function summary index .. option:: -ftime-trace -Turn on time profiler. Results can be analyzed with chrome://tracing or -`Speedscope App `_ for flamegraph visualization + +Turn on time profiler. Generates JSON file based on output filename. Results +can be analyzed with chrome://tracing or `Speedscope App +`_ for flamegraph visualization. .. option:: -ftime-trace-granularity= @@ -1988,6 +2167,10 @@ Specify the function to be called on overflow Process trigraph sequences +.. option:: -ftrivial-auto-var-init= + +Initialize trivial automatic stack variables: uninitialized (default) \| pattern + .. option:: -funique-section-names, -fno-unique-section-names Use unique names for text and data sections (ELF Only) @@ -2016,6 +2199,10 @@ Use .init\_array instead of .ctors .. option:: -fuse-line-directives, -fno-use-line-directives +.. option:: -fvalidate-ast-input-files-content + +Compute and store the hash of input files used to build an AST. Files with mismatching mtime's are considered valid if both contents is identical + .. option:: -fveclib= Use the given vector functions library @@ -2024,7 +2211,15 @@ Use the given vector functions library Enable the loop vectorization passes -.. option:: -fverbose-asm, -fno-verbose-asm, -dA +.. option:: -fverbose-asm, -dA, -fno-verbose-asm + +.. option:: -fvirtual-function-elimination + +Enables dead virtual function elimination optimization. Requires -flto=full + +.. option:: -fvisibility-global-new-delete-hidden + +Give global C++ operator new and delete declarations hidden visibility .. option:: -fvisibility-inlines-hidden @@ -2038,6 +2233,10 @@ Give global types 'default' visibility and global functions and variables 'hidde Set the default symbol visibility for all global declarations +.. option:: -fwasm-exceptions + +Use WebAssembly style exceptions + .. option:: -fwhole-program-vtables, -fno-whole-program-vtables Enables whole-program vtable optimization. Requires -flto @@ -2164,6 +2363,130 @@ Target-dependent compilation options Put objects of at most bytes into small data section (MIPS / Hexagon) +.. option:: -ffixed-x1 + +Reserve the 1 register (AArch64/RISC-V only) + +.. option:: -ffixed-x10 + +Reserve the 10 register (AArch64/RISC-V only) + +.. option:: -ffixed-x11 + +Reserve the 11 register (AArch64/RISC-V only) + +.. option:: -ffixed-x12 + +Reserve the 12 register (AArch64/RISC-V only) + +.. option:: -ffixed-x13 + +Reserve the 13 register (AArch64/RISC-V only) + +.. option:: -ffixed-x14 + +Reserve the 14 register (AArch64/RISC-V only) + +.. option:: -ffixed-x15 + +Reserve the 15 register (AArch64/RISC-V only) + +.. option:: -ffixed-x16 + +Reserve the 16 register (AArch64/RISC-V only) + +.. option:: -ffixed-x17 + +Reserve the 17 register (AArch64/RISC-V only) + +.. option:: -ffixed-x18 + +Reserve the 18 register (AArch64/RISC-V only) + +.. option:: -ffixed-x19 + +Reserve the 19 register (AArch64/RISC-V only) + +.. option:: -ffixed-x2 + +Reserve the 2 register (AArch64/RISC-V only) + +.. option:: -ffixed-x20 + +Reserve the 20 register (AArch64/RISC-V only) + +.. option:: -ffixed-x21 + +Reserve the 21 register (AArch64/RISC-V only) + +.. option:: -ffixed-x22 + +Reserve the 22 register (AArch64/RISC-V only) + +.. option:: -ffixed-x23 + +Reserve the 23 register (AArch64/RISC-V only) + +.. option:: -ffixed-x24 + +Reserve the 24 register (AArch64/RISC-V only) + +.. option:: -ffixed-x25 + +Reserve the 25 register (AArch64/RISC-V only) + +.. option:: -ffixed-x26 + +Reserve the 26 register (AArch64/RISC-V only) + +.. option:: -ffixed-x27 + +Reserve the 27 register (AArch64/RISC-V only) + +.. option:: -ffixed-x28 + +Reserve the 28 register (AArch64/RISC-V only) + +.. option:: -ffixed-x29 + +Reserve the 29 register (AArch64/RISC-V only) + +.. option:: -ffixed-x3 + +Reserve the 3 register (AArch64/RISC-V only) + +.. option:: -ffixed-x30 + +Reserve the 30 register (AArch64/RISC-V only) + +.. option:: -ffixed-x31 + +Reserve the 31 register (AArch64/RISC-V only) + +.. option:: -ffixed-x4 + +Reserve the 4 register (AArch64/RISC-V only) + +.. option:: -ffixed-x5 + +Reserve the 5 register (AArch64/RISC-V only) + +.. option:: -ffixed-x6 + +Reserve the 6 register (AArch64/RISC-V only) + +.. option:: -ffixed-x7 + +Reserve the 7 register (AArch64/RISC-V only) + +.. option:: -ffixed-x8 + +Reserve the 8 register (AArch64/RISC-V only) + +.. option:: -ffixed-x9 + +Reserve the 9 register (AArch64/RISC-V only) + .. option:: -m16 .. option:: -m32 @@ -2172,6 +2495,12 @@ Put objects of at most bytes into small data section (MIPS / Hexagon) .. option:: -mabi= +.. option:: -malign-branch-boundary= + +.. option:: -malign-branch-prefix-size= + +.. option:: -malign-branch=,... + .. option:: -malign-double Align doubles to two words in structs (x86 only) @@ -2184,13 +2513,15 @@ Align doubles to two words in structs (x86 only) Link stack frames through backchain on System Z -.. option:: -mcmodel= +.. option:: -mbranches-within-32B-boundaries -.. option:: -mconsole +.. option:: -mcmodel=, -mcmodel=medany (equivalent to -mcmodel=medium), -mcmodel=medlow (equivalent to -mcmodel=small) -.. option:: -mcpu=, -mv5 (equivalent to -mcpu=hexagonv5), -mv55 (equivalent to -mcpu=hexagonv55), -mv60 (equivalent to -mcpu=hexagonv60), -mv62 (equivalent to -mcpu=hexagonv62), -mv65 (equivalent to -mcpu=hexagonv65) +.. option:: -mconsole -Use -mcpu=? to see a list of supported cpu models. +.. program:: clang1 +.. option:: -mcpu=, -mv5 (equivalent to -mcpu=hexagonv5), -mv55 (equivalent to -mcpu=hexagonv55), -mv60 (equivalent to -mcpu=hexagonv60), -mv62 (equivalent to -mcpu=hexagonv62), -mv65 (equivalent to -mcpu=hexagonv65), -mv66 (equivalent to -mcpu=hexagonv66) +.. program:: clang .. option:: -mcrc, -mno-crc @@ -2224,6 +2555,8 @@ Enable merging of globals .. option:: -mhwdiv=, --mhwdiv , --mhwdiv= +.. option:: -mhwmult= + .. option:: -miamcu, -mno-iamcu Use Intel MCU ABI @@ -2246,7 +2579,7 @@ Generate branches with extended addressability, usually via indirect jumps. .. option:: -mmacosx-version-min=, -mmacos-version-min= -Set macOS deployment target +Set Mac OS X deployment target .. option:: -mmcu= @@ -2254,12 +2587,20 @@ Set macOS deployment target Set the default structure layout to be compatible with the Microsoft compiler standard +.. option:: -mnop-mcount + +Generate mcount/\_\_fentry\_\_ calls as nops. To activate they need to be patched in. + .. option:: -momit-leaf-frame-pointer, -mno-omit-leaf-frame-pointer Omit frame pointer setup for leaf functions .. option:: -moslib= +.. option:: -mpacked-stack, -mno-packed-stack + +Use packed stack layout (SystemZ only). + .. option:: -mpie-copy-relocations, -mno-pie-copy-relocations Use copy relocations support for PIE builds @@ -2278,6 +2619,10 @@ Enable hexagon-qdsp6 backward compatibility .. option:: -mrecip=,... .. program:: clang +.. option:: -mrecord-mcount + +Generate a \_\_mcount\_loc section entry for each \_\_fentry\_\_ call. + .. option:: -mred-zone, -mno-red-zone .. option:: -mregparm= @@ -2300,6 +2645,8 @@ Select return address signing scope Use software floating point +.. option:: -mspeculative-load-hardening, -mno-speculative-load-hardening + .. option:: -mstack-alignment= Set the stack alignment @@ -2324,9 +2671,17 @@ The thread model to use, e.g. posix, single (posix by default) .. option:: -mthumb, -mno-thumb -.. option:: -mtune= +.. option:: -mtls-direct-seg-refs, -mno-tls-direct-seg-refs + +Enable direct TLS access through segment registers (default) -Use -mtune=? to see a list of supported cpu models. +.. option:: -mtls-size= + +Specify bit size of immediate TLS offsets (AArch64 ELF only): 12 (for 4KB) \| 24 (for 16MB, default) \| 32 (for 4GB) \| 48 (for 256TB, needs -mcmodel=large) + +.. program:: clang1 +.. option:: -mtune= +.. program:: clang .. option:: -mtvos-version-min=, -mappletvos-version-min= @@ -2338,56 +2693,16 @@ Use -mtune=? to see a list of supported cpu models. .. option:: -mwatchos-version-min= +.. option:: -mwavefrontsize64, -mno-wavefrontsize64 + +Wavefront size 64 is used + .. option:: -mwindows .. option:: -mx32 AARCH64 ------- -.. option:: -ffixed-x1 - -Reserve the x1 register (AArch64 only) - -.. option:: -ffixed-x2 - -Reserve the x2 register (AArch64 only) - -.. option:: -ffixed-x3 - -Reserve the x3 register (AArch64 only) - -.. option:: -ffixed-x4 - -Reserve the x4 register (AArch64 only) - -.. option:: -ffixed-x5 - -Reserve the x5 register (AArch64 only) - -.. option:: -ffixed-x6 - -Reserve the x6 register (AArch64 only) - -.. option:: -ffixed-x7 - -Reserve the x7 register (AArch64 only) - -.. option:: -ffixed-x18 - -Reserve the x18 register (AArch64 only) - -.. option:: -ffixed-x20 - -Reserve the x20 register (AArch64 only) - -.. option:: -fcall-saved-x8 - -Make the x8 register call-saved (AArch64 only) - -.. option:: -fcall-saved-x9 - -Make the x9 register call-saved (AArch64 only) - .. option:: -fcall-saved-x10 Make the x10 register call-saved (AArch64 only) @@ -2416,6 +2731,14 @@ Make the x15 register call-saved (AArch64 only) Make the x18 register call-saved (AArch64 only) +.. option:: -fcall-saved-x8 + +Make the x8 register call-saved (AArch64 only) + +.. option:: -fcall-saved-x9 + +Make the x9 register call-saved (AArch64 only) + .. option:: -mfix-cortex-a53-835769, -mno-fix-cortex-a53-835769 Workaround Cortex-A53 erratum 835769 (AArch64 only) @@ -2426,14 +2749,17 @@ Generate code which only uses the general purpose registers (AArch64 only) AMDGPU ------ +.. option:: -mcode-object-v3, -mno-code-object-v3 + +Enable code object v3 (AMDGPU only) + .. option:: -mcumode, -mno-cumode -CU wavefront execution mode is used if enabled and WGP wavefront execution mode -is used if disabled (AMDGPU only) +CU wavefront execution mode is used (AMDGPU only) -.. option:: -mwavefrontsize64, -mno-wavefrontsize64 +.. option:: -msram-ecc, -mno-sram-ecc -Wavefront size 64 is used if enabled and wavefront size 32 if disabled (AMDGPU only) +Enable SRAM ECC (AMDGPU only) .. option:: -mxnack, -mno-xnack @@ -2445,6 +2771,10 @@ ARM Reserve the r9 register (ARM only) +.. option:: -mcmse + +Allow use of CMSE (Armv8-M Security Extensions) + .. option:: -mexecute-only, -mno-execute-only, -mpure-code Disallow generation of data access to code sections (ARM only) @@ -2467,7 +2797,7 @@ Disallow generation of deprecated IT blocks for ARMv8. It is on by default for A .. option:: -mtp= -Read thread pointer from coprocessor register (ARM only) +Thread pointer access method (AArch32/AArch64 only) .. option:: -munaligned-access, -mno-unaligned-access @@ -2621,18 +2951,34 @@ PowerPC .. option:: -msecure-plt +.. option:: -mspe, -mno-spe + .. option:: -mvsx, -mno-vsx WebAssembly ----------- +.. option:: -matomics, -mno-atomics + +.. option:: -mbulk-memory, -mno-bulk-memory + .. option:: -mexception-handling, -mno-exception-handling +.. option:: -mmultivalue, -mno-multivalue + +.. option:: -mmutable-globals, -mno-mutable-globals + .. option:: -mnontrapping-fptoint, -mno-nontrapping-fptoint +.. option:: -mreference-types, -mno-reference-types + .. option:: -msign-ext, -mno-sign-ext .. option:: -msimd128, -mno-simd128 +.. option:: -mtail-call, -mno-tail-call + +.. option:: -munimplemented-simd128, -mno-unimplemented-simd128 + X86 --- .. option:: -m3dnow, -mno-3dnow @@ -2647,10 +2993,10 @@ X86 .. option:: -mavx2, -mno-avx2 -.. option:: -mavx512bitalg, -mno-avx512bitalg - .. option:: -mavx512bf16, -mno-avx512bf16 +.. option:: -mavx512bitalg, -mno-avx512bitalg + .. option:: -mavx512bw, -mno-avx512bw .. option:: -mavx512cd, -mno-avx512cd @@ -2719,8 +3065,6 @@ X86 .. option:: -mmovdiri, -mno-movdiri -.. option:: -mmpx, -mno-mpx - .. option:: -mmwaitx, -mno-mwaitx .. option:: -mpclmul, -mno-pclmul @@ -2777,6 +3121,8 @@ X86 .. option:: -mvpclmulqdq, -mno-vpclmulqdq +.. option:: -mvzeroupper, -mno-vzeroupper + .. option:: -mwaitpkg, -mno-waitpkg .. option:: -mwbnoinvd, -mno-wbnoinvd @@ -2799,6 +3145,26 @@ RISCV Enable linker relaxation +.. option:: -msave-restore, -mno-save-restore + +Enable using library calls for save and restore + +Long double flags +----------------- +Selects the long double implementation + +.. option:: -mlong-double-128 + +Force long double to be 128 bits + +.. option:: -mlong-double-64 + +Force long double to be 64 bits + +.. option:: -mlong-double-80 + +Force long double to be 80 bits, padded to 128 bits for storage + Optimization level ~~~~~~~~~~~~~~~~~~ @@ -2820,6 +3186,10 @@ Kind and level of debug information Generate source-level debug information +.. option:: -gdwarf + +Generate source-level debug information with the default dwarf version + .. option:: -gdwarf-2 Generate source-level debug information with dwarf version 2 @@ -2828,7 +3198,7 @@ Generate source-level debug information with dwarf version 2 Generate source-level debug information with dwarf version 3 -.. option:: -gdwarf-4, -gdwarf +.. option:: -gdwarf-4 Generate source-level debug information with dwarf version 4 @@ -2856,6 +3226,10 @@ ___________ .. option:: -ggdb3 +.. option:: -gline-directives-only + +Emit debug line info directives only + .. option:: -gline-tables-only, -g1, -gmlt Emit debug line number tables only @@ -2886,10 +3260,16 @@ Embed source text in DWARF debug sections .. option:: -gpubnames, -gno-pubnames -.. option:: -grecord-command-line, -grecord-gcc-switches, -gno-record-command-line, -gno-record-gcc-switches +.. option:: -grecord-command-line, -gno-record-command-line, -grecord-gcc-switches .. option:: -gsplit-dwarf +.. program:: clang1 +.. option:: -gsplit-dwarf= +.. program:: clang + +Set DWARF fission mode to either 'split' or 'single' + .. option:: -gstrict-dwarf, -gno-strict-dwarf .. option:: -gz diff --git a/clang/docs/CommandGuide/clang.rst b/clang/docs/CommandGuide/clang.rst index 7b0873600fc3b..6947450beb43d 100644 --- a/clang/docs/CommandGuide/clang.rst +++ b/clang/docs/CommandGuide/clang.rst @@ -278,9 +278,18 @@ Language Selection and Mode Options Make all string literals default to writable. This disables uniquing of strings and other optimizations. -.. option:: -flax-vector-conversions +.. option:: -flax-vector-conversions, -flax-vector-conversions=, -fno-lax-vector-conversions Allow loose type checking rules for implicit vector conversions. + Possible values of : + + - ``none``: allow no implicit conversions between vectors + - ``integer``: allow implicit bitcasts between integer vectors of the same + overall bit-width + - ``all``: allow implicit bitcasts between any vectors of the same + overall bit-width + + defaults to ``integer`` if unspecified. .. option:: -fblocks diff --git a/clang/docs/DiagnosticsReference.rst b/clang/docs/DiagnosticsReference.rst index 7d9b1e8359a8d..afd38929fb651 100644 --- a/clang/docs/DiagnosticsReference.rst +++ b/clang/docs/DiagnosticsReference.rst @@ -207,17 +207,6 @@ This diagnostic is enabled by default. Controls `-Wpointer-bool-conversion`_, `-Wstring-compare`_, `-Wtautological-pointer-compare`_. --Waddress-of-array-temporary ----------------------------- -This diagnostic is enabled by default. - -**Diagnostic text:** - -+---------------------------------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`pointer is initialized by a temporary array, which will be destroyed at the end of the full-expression`| -+---------------------------------------------------------------------------------------------------------------------------------------------+ - - -Waddress-of-packed-member -------------------------- This diagnostic is enabled by default. @@ -244,26 +233,20 @@ This diagnostic is an error by default, but the flag ``-Wno-address-of-temporary ------------------ This diagnostic flag exists for GCC compatibility, and has no effect in Clang. --Waligned-allocation-unavailable --------------------------------- -This diagnostic is an error by default, but the flag ``-Wno-aligned-allocation-unavailable`` can be used to disable the error. - -**Diagnostic text:** - -+--------------------------------------------------+--------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -|:error:`error:` |nbsp| :diagtext:`aligned` |nbsp| |+------------------------+| |nbsp| :diagtext:`function of type '`:placeholder:`B`:diagtext:`' is only available on` |nbsp| :placeholder:`C` |nbsp| :placeholder:`D` |nbsp| :diagtext:`or newer`| -| ||:diagtext:`allocation` || | -| |+------------------------+| | -| ||:diagtext:`deallocation`|| | -| |+------------------------+| | -+--------------------------------------------------+--------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - - -Wall ----- Some of the diagnostics controlled by this flag are enabled by default. -Controls `-Wmost`_, `-Wparentheses`_, `-Wswitch`_, `-Wswitch-bool`_. +Controls `-Wmisleading-indentation`_, `-Wmost`_, `-Wparentheses`_, `-Wswitch`_, `-Wswitch-bool`_. + + +-Walloca +-------- +**Diagnostic text:** + ++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`use of function` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is discouraged; there is no way to check for failure but failure may still occur, resulting in a possibly exploitable security vulnerability`| ++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -Walloca-with-align-alignof @@ -325,6 +308,17 @@ This diagnostic is enabled by default. +-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +-Wambiguous-reversed-operator +----------------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`ISO C++20 considers use of overloaded operator '`:placeholder:`A`:diagtext:`' (with operand types` |nbsp| :placeholder:`B` |nbsp| :diagtext:`and` |nbsp| :placeholder:`C`:diagtext:`) to be ambiguous despite there being a unique best viable function`| ++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + + -Wanalyzer-incompatible-plugin ------------------------------ This diagnostic is enabled by default. @@ -336,6 +330,29 @@ This diagnostic is enabled by default. +----------------------------------------------------------------------------------------------------------------------------------------+ +-Wanon-enum-enum-conversion +--------------------------- +Some of the diagnostics controlled by this flag are enabled by default. + +Also controls `-Wdeprecated-anon-enum-enum-conversion`_. + +**Diagnostic text:** + ++---------------------------+--------------------------------------------+-----------------------------------------------+ +|:warning:`warning:` |nbsp| |+------------------------------------------+| |nbsp| :diagtext:`different enumeration types`| +| ||:diagtext:`arithmetic between` || | +| |+------------------------------------------+| | +| ||:diagtext:`bitwise operation between` || | +| |+------------------------------------------+| | +| ||:diagtext:`comparison of` || | +| |+------------------------------------------+| | +| ||:diagtext:`conditional expression between`|| | +| |+------------------------------------------+| | +| ||:diagtext:`compound assignment of` || | +| |+------------------------------------------+| | ++---------------------------+--------------------------------------------+-----------------------------------------------+ + + -Wanonymous-pack-parens ----------------------- This diagnostic is enabled by default. @@ -473,6 +490,17 @@ This diagnostic is enabled by default. +-----------------------------------------------------------------------------------------------------------------------------+ +-Wargument-outside-range +------------------------ +This diagnostic is an error by default, but the flag ``-Wno-argument-outside-range`` can be used to disable the error. + +**Diagnostic text:** + ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:error:`error:` |nbsp| :diagtext:`argument value` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is outside the valid range \[`:placeholder:`B`:diagtext:`,` |nbsp| :placeholder:`C`:diagtext:`\]`| ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + + -Warray-bounds -------------- This diagnostic is enabled by default. @@ -491,9 +519,17 @@ This diagnostic is enabled by default. |:warning:`warning:` |nbsp| :diagtext:`array index` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is before the beginning of the array`| +----------------------------------------------------------------------------------------------------------------------------------+ -+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`array argument is too small; contains` |nbsp| :placeholder:`A` |nbsp| :diagtext:`elements, callee requires at least` |nbsp| :placeholder:`B`| -+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ ++---------------------------------------------------------------------------+----------------------------------------------------------------------------+--------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`array argument is too small;` |nbsp| |+--------------------------------------------------------------------------+|:diagtext:`, callee requires at least` |nbsp| :placeholder:`B`| +| ||+------------------------------------------------------------------------+|| | +| |||:diagtext:`contains` |nbsp| :placeholder:`A` |nbsp| :diagtext:`elements`||| | +| ||+------------------------------------------------------------------------+|| | +| |+--------------------------------------------------------------------------+| | +| ||+----------------------------------------------+ || | +| |||:diagtext:`is of size` |nbsp| :placeholder:`A`| || | +| ||+----------------------------------------------+ || | +| |+--------------------------------------------------------------------------+| | ++---------------------------------------------------------------------------+----------------------------------------------------------------------------+--------------------------------------------------------------+ +-----------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`'static' has no effect on zero-length arrays`| @@ -572,13 +608,41 @@ This diagnostic is enabled by default. -Wat-protocol ------------- +This diagnostic flag exists for GCC compatibility, and has no effect in Clang. + +-Watimport-in-framework-header +------------------------------ This diagnostic is enabled by default. **Diagnostic text:** -+-------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`@protocol is using a forward protocol declaration of` |nbsp| :placeholder:`A`| -+-------------------------------------------------------------------------------------------------------------------+ ++------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`use of '@import' in framework header is discouraged, including this header requires -fmodules`| ++------------------------------------------------------------------------------------------------------------------------------------+ + + +-Watomic-alignment +------------------ +This diagnostic is enabled by default. + +**Diagnostic text:** + ++---------------------------+------------------------+------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| |+----------------------+| |nbsp| :diagtext:`atomic operation may incur significant performance penalty`| +| ||:diagtext:`large` || | +| |+----------------------+| | +| ||:diagtext:`misaligned`|| | +| |+----------------------+| | ++---------------------------+------------------------+------------------------------------------------------------------------------+ + + +-Watomic-implicit-seq-cst +------------------------- +**Diagnostic text:** + ++---------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary`| ++---------------------------------------------------------------------------------------------------------------------------------------+ -Watomic-memory-ordering @@ -690,6 +754,20 @@ This diagnostic is enabled by default. |:warning:`warning:` |nbsp| :diagtext:`'unavailable' availability overrides all other availability information`| +--------------------------------------------------------------------------------------------------------------+ ++------------------------------------------------------------------------------+----------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`ignoring availability attribute` |nbsp| |+--------------------------------------+| +| ||:diagtext:`on '+load' method` || +| |+--------------------------------------+| +| ||:diagtext:`with constructor attribute`|| +| |+--------------------------------------+| +| ||:diagtext:`with destructor attribute` || +| |+--------------------------------------+| ++------------------------------------------------------------------------------+----------------------------------------+ + ++---------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`only 'unavailable' and 'deprecated' are supported for Swift availability`| ++---------------------------------------------------------------------------------------------------------------+ + +------------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`unknown platform` |nbsp| :placeholder:`A` |nbsp| :diagtext:`in availability macro`| +------------------------------------------------------------------------------------------------------------------------+ @@ -731,6 +809,33 @@ This diagnostic is enabled by default. +---------------------------+--------------------------------+---------------------------------------------------------------------------------------------------+-----------------------------------------------+--------------------------------+ +-Wavr-rtlib-linking-quirks +-------------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++----------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`support for linking stdlibs for microcontroller '`:placeholder:`A`:diagtext:`' is not implemented`| ++----------------------------------------------------------------------------------------------------------------------------------------+ + ++-------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`no avr-gcc installation can be found on the system, cannot link standard libraries`| ++-------------------------------------------------------------------------------------------------------------------------+ + ++--------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`no avr-libc installation can be found on the system, cannot link standard libraries`| ++--------------------------------------------------------------------------------------------------------------------------+ + ++--------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`no target microcontroller specified on command line, cannot link standard libraries, please pass -mmcu=`| ++--------------------------------------------------------------------------------------------------------------------------------------------------------+ + ++-----------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`standard library not linked and so no interrupt vector table or compiler runtime routines will be linked`| ++-----------------------------------------------------------------------------------------------------------------------------------------------+ + + -Wbackend-plugin ---------------- This diagnostic is enabled by default. @@ -779,31 +884,44 @@ Also controls `-Wc++98-compat-bind-to-temporary-copy`_. | |+---------------------+| +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------+ -+--------------------------------------------------------------------+-----------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`no viable constructor` |nbsp| |+---------------------------------------+| |nbsp| :diagtext:`of type` |nbsp| :placeholder:`B`:diagtext:`; C++98 requires a copy constructor when binding a reference to a temporary`| -| ||:diagtext:`copying variable` || | -| |+---------------------------------------+| | -| ||:diagtext:`copying parameter` || | -| |+---------------------------------------+| | -| ||:diagtext:`returning object` || | -| |+---------------------------------------+| | -| ||:diagtext:`throwing object` || | -| |+---------------------------------------+| | -| ||:diagtext:`copying member subobject` || | -| |+---------------------------------------+| | -| ||:diagtext:`copying array element` || | -| |+---------------------------------------+| | -| ||:diagtext:`allocating object` || | -| |+---------------------------------------+| | -| ||:diagtext:`copying temporary` || | -| |+---------------------------------------+| | -| ||:diagtext:`initializing base subobject`|| | -| |+---------------------------------------+| | -| ||:diagtext:`initializing vector element`|| | -| |+---------------------------------------+| | -| ||:diagtext:`capturing value` || | -| |+---------------------------------------+| | -+--------------------------------------------------------------------+-----------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------+ ++--------------------------------------------------------------------+------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`no viable constructor` |nbsp| |+----------------------------------------------------+| |nbsp| :diagtext:`of type` |nbsp| :placeholder:`B`:diagtext:`; C++98 requires a copy constructor when binding a reference to a temporary`| +| ||:diagtext:`copying variable` || | +| |+----------------------------------------------------+| | +| ||:diagtext:`copying parameter` || | +| |+----------------------------------------------------+| | +| ||:diagtext:`returning object` || | +| |+----------------------------------------------------+| | +| ||:diagtext:`initializing statement expression result`|| | +| |+----------------------------------------------------+| | +| ||:diagtext:`throwing object` || | +| |+----------------------------------------------------+| | +| ||:diagtext:`copying member subobject` || | +| |+----------------------------------------------------+| | +| ||:diagtext:`copying array element` || | +| |+----------------------------------------------------+| | +| ||:diagtext:`allocating object` || | +| |+----------------------------------------------------+| | +| ||:diagtext:`copying temporary` || | +| |+----------------------------------------------------+| | +| ||:diagtext:`initializing base subobject` || | +| |+----------------------------------------------------+| | +| ||:diagtext:`initializing vector element` || | +| |+----------------------------------------------------+| | +| ||:diagtext:`capturing value` || | +| |+----------------------------------------------------+| | ++--------------------------------------------------------------------+------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------+ + + +-Wbinding-in-condition +---------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++--------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`ISO C++17 does not permit structured binding declaration in a condition`| ++--------------------------------------------------------------------------------------------------------------+ -Wbitfield-constant-conversion @@ -857,12 +975,21 @@ This diagnostic is enabled by default. +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------+ --Wbitwise-op-parentheses ------------------------- +-Wbitwise-conditional-parentheses +--------------------------------- This diagnostic is enabled by default. **Diagnostic text:** ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`operator '?:' has lower precedence than '`:placeholder:`A`:diagtext:`'; '`:placeholder:`A`:diagtext:`' will be evaluated first`| ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + + +-Wbitwise-op-parentheses +------------------------ +**Diagnostic text:** + +-----------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`'`:placeholder:`A`:diagtext:`' within '`:placeholder:`B`:diagtext:`'`| +-----------------------------------------------------------------------------------------------------------+ @@ -897,6 +1024,21 @@ Also controls `-Wpointer-bool-conversion`_, `-Wundefined-bool-conversion`_. Synonym for `-Wbool-conversion`_. +-Wbool-operation +---------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++-------------------------------------------------------------------------------+-------------------------------------------------+--------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`bitwise negation of a boolean expression`|+-----------------------------------------------+| |nbsp| :diagtext:`did you mean logical negation?`| +| ||:diagtext:`;` || | +| |+-----------------------------------------------+| | +| || |nbsp| :diagtext:`always evaluates to 'true';`|| | +| |+-----------------------------------------------+| | ++-------------------------------------------------------------------------------+-------------------------------------------------+--------------------------------------------------+ + + -Wbraced-scalar-init -------------------- This diagnostic is enabled by default. @@ -923,6 +1065,17 @@ This diagnostic is enabled by default. +-------------------------------------------------------------------------------------------------------+ +-Wbuiltin-assume-aligned-alignment +---------------------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++---------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`requested alignment must be` |nbsp| :placeholder:`A` |nbsp| :diagtext:`bytes or smaller; maximum alignment assumed`| ++---------------------------------------------------------------------------------------------------------------------------------------------------------+ + + -Wbuiltin-macro-redefined ------------------------- This diagnostic is enabled by default. @@ -944,9 +1097,9 @@ This diagnostic is enabled by default. **Diagnostic text:** -+------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`will always overflow destination buffer`| -+------------------------------------------------------------------------------------------------------+ ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`'`:placeholder:`A`:diagtext:`' will always overflow; destination buffer has size` |nbsp| :placeholder:`B`:diagtext:`, but size argument is` |nbsp| :placeholder:`C`| ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -Wbuiltin-requires-header @@ -1180,28 +1333,6 @@ Also controls `-Wc++11-extra-semi`_, `-Wc++11-inline-namespace`_, `-Wc++11-long- |:warning:`warning:` |nbsp| :diagtext:`default template arguments for a function template are a C++11 extension`| +---------------------------------------------------------------------------------------------------------------+ -+-------------------------------------------------------------------+---------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`first declaration of` |nbsp| |+-------------------------------------+| |nbsp| :diagtext:`specialization of` |nbsp| :placeholder:`B` |nbsp| :diagtext:`outside namespace` |nbsp| :placeholder:`C` |nbsp| :diagtext:`is a C++11 extension`| -| ||:diagtext:`class template` || | -| |+-------------------------------------+| | -| ||:diagtext:`class template partial` || | -| |+-------------------------------------+| | -| ||:diagtext:`variable template` || | -| |+-------------------------------------+| | -| ||:diagtext:`variable template partial`|| | -| |+-------------------------------------+| | -| ||:diagtext:`function template` || | -| |+-------------------------------------+| | -| ||:diagtext:`member function` || | -| |+-------------------------------------+| | -| ||:diagtext:`static data member` || | -| |+-------------------------------------+| | -| ||:diagtext:`member class` || | -| |+-------------------------------------+| | -| ||:diagtext:`member enumeration` || | -| |+-------------------------------------+| | -+-------------------------------------------------------------------+---------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - +------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`'typename' occurs outside of a template`| +------------------------------------------------------------------------------+ @@ -1260,19 +1391,21 @@ Some of the diagnostics controlled by this flag are enabled by default. **Diagnostic text:** -+-----------------------+----------------------------------------+--------+--------------------------------------------------------------------------------------------------------------------------+ -|:error:`error:` |nbsp| |+--------------------------------------+| |nbsp| |+------------------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`case value` || ||+--------------------------------------------------------------------------------------------------------------+ || -| |+--------------------------------------+| |||:diagtext:`cannot be narrowed from type` |nbsp| :placeholder:`C` |nbsp| :diagtext:`to` |nbsp| :placeholder:`D`| || -| ||:diagtext:`enumerator value` || ||+--------------------------------------------------------------------------------------------------------------+ || -| |+--------------------------------------+| |+------------------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`non-type template argument`|| ||+----------------------------------------------------------------------------------------------------------------------+|| -| |+--------------------------------------+| |||:diagtext:`evaluates to` |nbsp| :placeholder:`C`:diagtext:`, which cannot be narrowed to type` |nbsp| :placeholder:`D`||| -| ||:diagtext:`array size` || ||+----------------------------------------------------------------------------------------------------------------------+|| -| |+--------------------------------------+| |+------------------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`constexpr if condition` || | | -| |+--------------------------------------+| | | -+-----------------------+----------------------------------------+--------+--------------------------------------------------------------------------------------------------------------------------+ ++-----------------------+-----------------------------------------+--------+--------------------------------------------------------------------------------------------------------------------------+ +|:error:`error:` |nbsp| |+---------------------------------------+| |nbsp| |+------------------------------------------------------------------------------------------------------------------------+| +| ||:diagtext:`case value` || ||+--------------------------------------------------------------------------------------------------------------+ || +| |+---------------------------------------+| |||:diagtext:`cannot be narrowed from type` |nbsp| :placeholder:`C` |nbsp| :diagtext:`to` |nbsp| :placeholder:`D`| || +| ||:diagtext:`enumerator value` || ||+--------------------------------------------------------------------------------------------------------------+ || +| |+---------------------------------------+| |+------------------------------------------------------------------------------------------------------------------------+| +| ||:diagtext:`non-type template argument` || ||+----------------------------------------------------------------------------------------------------------------------+|| +| |+---------------------------------------+| |||:diagtext:`evaluates to` |nbsp| :placeholder:`C`:diagtext:`, which cannot be narrowed to type` |nbsp| :placeholder:`D`||| +| ||:diagtext:`array size` || ||+----------------------------------------------------------------------------------------------------------------------+|| +| |+---------------------------------------+| |+------------------------------------------------------------------------------------------------------------------------+| +| ||:diagtext:`constexpr if condition` || | | +| |+---------------------------------------+| | | +| ||:diagtext:`explicit specifier argument`|| | | +| |+---------------------------------------+| | | ++-----------------------+-----------------------------------------+--------+--------------------------------------------------------------------------------------------------------------------------+ +-----------------------------------------------------------------------------------------------------------------------------------------------------------------------+ |:error:`error:` |nbsp| :diagtext:`constant expression evaluates to` |nbsp| :placeholder:`A` |nbsp| :diagtext:`which cannot be narrowed to type` |nbsp| :placeholder:`B`| @@ -1402,6 +1535,10 @@ Some of the diagnostics controlled by this flag are enabled by default. **Diagnostic text:** ++--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`ISO C++ standards before C++17 do not allow new expression for type` |nbsp| :placeholder:`A` |nbsp| :diagtext:`to use list-initialization`| ++--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + +------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`constexpr if is a C++17 extension`| +------------------------------------------------------------------------+ @@ -1499,51 +1636,287 @@ Synonym for `-Wc++17-compat-mangling`_. Synonym for `-Wc++17-extensions`_. --Wc++2a-compat +-Wc++20-compat -------------- +Some of the diagnostics controlled by this flag are enabled by default. + **Diagnostic text:** ++------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`'consteval' specifier is incompatible with C++ standards before C++20`| ++------------------------------------------------------------------------------------------------------------+ + ++------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`'constinit' specifier is incompatible with C++ standards before C++20`| ++------------------------------------------------------------------------------------------------------------+ + ++-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`aggregate initialization of type` |nbsp| :placeholder:`A` |nbsp| :diagtext:`with user-declared constructors is incompatible with C++20`| ++-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + ++------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`this expression will be parsed as explicit(bool) in C++20`| ++------------------------------------------------------------------------------------------------+ + ++------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`'<=>' is a single token in C++20; add a space to avoid a change in behavior`| ++------------------------------------------------------------------------------------------------------------------+ + ++--------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`type of UTF-8 string literal will change from array of const char to array of const char8\_t in C++20`| ++--------------------------------------------------------------------------------------------------------------------------------------------+ + +-------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`'`:placeholder:`A`:diagtext:`' is a keyword in C++2a`| +|:warning:`warning:` |nbsp| :diagtext:`'`:placeholder:`A`:diagtext:`' is a keyword in C++20`| +-------------------------------------------------------------------------------------------+ --Wc++2a-compat-pedantic +-Wc++20-compat-pedantic ----------------------- -Synonym for `-Wc++2a-compat`_. +Synonym for `-Wc++20-compat`_. --Wc++2a-extensions +-Wc++20-designator +------------------ +**Diagnostic text:** + ++------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`designated initializers are a C++20 extension`| ++------------------------------------------------------------------------------------+ + + +-Wc++20-extensions ------------------ Some of the diagnostics controlled by this flag are enabled by default. +Also controls `-Wc++20-designator`_. + **Diagnostic text:** ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`use of function template name with no prior declaration in function call with explicit template arguments is a C++20 extension`| ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + +----------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`default member initializer for bit-field is a C++2a extension`| +|:warning:`warning:` |nbsp| :diagtext:`default member initializer for bit-field is a C++20 extension`| +----------------------------------------------------------------------------------------------------+ ++-----------------------------------------------------------------------------------+-------------------------+----------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`use of this statement in a constexpr` |nbsp| |+-----------------------+| |nbsp| :diagtext:`is a C++20 extension`| +| ||:diagtext:`function` || | +| |+-----------------------+| | +| ||:diagtext:`constructor`|| | +| |+-----------------------+| | ++-----------------------------------------------------------------------------------+-------------------------+----------------------------------------+ + ++----------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`constexpr constructor that does not initialize all members is a C++20 extension`| ++----------------------------------------------------------------------------------------------------------------------+ + ++------------------------------------------------------------------------------+-------------------------+----------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`function try block in constexpr` |nbsp| |+-----------------------+| |nbsp| :diagtext:`is a C++20 extension`| +| ||:diagtext:`function` || | +| |+-----------------------+| | +| ||:diagtext:`constructor`|| | +| |+-----------------------+| | ++------------------------------------------------------------------------------+-------------------------+----------------------------------------+ + ++------------------------------------------------------------------------------------+-------------------------+----------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`uninitialized variable in a constexpr` |nbsp| |+-----------------------+| |nbsp| :diagtext:`is a C++20 extension`| +| ||:diagtext:`function` || | +| |+-----------------------+| | +| ||:diagtext:`constructor`|| | +| |+-----------------------+| | ++------------------------------------------------------------------------------------+-------------------------+----------------------------------------+ + ++---------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`constexpr union constructor that does not initialize any member is a C++20 extension`| ++---------------------------------------------------------------------------------------------------------------------------+ + ++---------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`use of the` |nbsp| :placeholder:`A` |nbsp| :diagtext:`attribute is a C++20 extension`| ++---------------------------------------------------------------------------------------------------------------------------+ + ++---------------------------------------------------------------------------------+--------------------------------------------------------------+----------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`decomposition declaration declared` |nbsp| |+------------------------------------------------------------+| |nbsp| :diagtext:`is a C++20 extension`| +| ||+------------------------------------------+ || | +| |||:diagtext:`'`:placeholder:`B`:diagtext:`'`| || | +| ||+------------------------------------------+ || | +| |+------------------------------------------------------------+| | +| ||+----------------------------------------------------------+|| | +| |||:diagtext:`with '`:placeholder:`B`:diagtext:`' specifiers`||| | +| ||+----------------------------------------------------------+|| | +| |+------------------------------------------------------------+| | ++---------------------------------------------------------------------------------+--------------------------------------------------------------+----------------------------------------+ + ++-------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`defaulted comparison operators are a C++20 extension`| ++-------------------------------------------------------------------------------------------+ + +--------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`explicit capture of 'this' with a capture default of '=' is a C++2a extension`| +|:warning:`warning:` |nbsp| :diagtext:`explicit capture of 'this' with a capture default of '=' is a C++20 extension`| +--------------------------------------------------------------------------------------------------------------------+ ++--------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`explicit(bool) is a C++20 extension`| ++--------------------------------------------------------------------------+ + ++-----------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`range-based for loop initialization statements are a C++20 extension`| ++-----------------------------------------------------------------------------------------------------------+ + ++---------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`initialized lambda pack captures are a C++20 extension`| ++---------------------------------------------------------------------------------------------+ + ++----------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`inline nested namespace definition is a C++20 extension`| ++----------------------------------------------------------------------------------------------+ + ++--------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`explicit template parameter list for lambdas is a C++20 extension`| ++--------------------------------------------------------------------------------------------------------+ + +--------------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`invoking a pointer to a 'const &' member function on an rvalue is a C++2a extension`| +|:warning:`warning:` |nbsp| :diagtext:`invoking a pointer to a 'const &' member function on an rvalue is a C++20 extension`| +--------------------------------------------------------------------------------------------------------------------------+ +-Wc++2a-compat +-------------- +Synonym for `-Wc++20-compat`_. + + +-Wc++2a-compat-pedantic +----------------------- +Synonym for `-Wc++20-compat-pedantic`_. + + +-Wc++2a-extensions +------------------ +Synonym for `-Wc++20-extensions`_. + + -Wc++98-c++11-c++14-c++17-compat -------------------------------- **Diagnostic text:** ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`use of function template name with no prior function template declaration in function call with explicit template arguments is incompatible with C++ standards before C++20`| ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + +-------------------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`default member initializer for bit-field is incompatible with C++ standards before C++2a`| +|:warning:`warning:` |nbsp| :diagtext:`default member initializer for bit-field is incompatible with C++ standards before C++20`| +-------------------------------------------------------------------------------------------------------------------------------+ ++-----------------------------------------------------------------------------------+-------------------------+-------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`use of this statement in a constexpr` |nbsp| |+-----------------------+| |nbsp| :diagtext:`is incompatible with C++ standards before C++20`| +| ||:diagtext:`function` || | +| |+-----------------------+| | +| ||:diagtext:`constructor`|| | +| |+-----------------------+| | ++-----------------------------------------------------------------------------------+-------------------------+-------------------------------------------------------------------+ + ++-------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`constexpr constructor that does not initialize all members is incompatible with C++ standards before C++20`| ++-------------------------------------------------------------------------------------------------------------------------------------------------+ + ++------------------------------------------------------------------------------+-------------------------+-------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`function try block in constexpr` |nbsp| |+-----------------------+| |nbsp| :diagtext:`is incompatible with C++ standards before C++20`| +| ||:diagtext:`function` || | +| |+-----------------------+| | +| ||:diagtext:`constructor`|| | +| |+-----------------------+| | ++------------------------------------------------------------------------------+-------------------------+-------------------------------------------------------------------+ + ++------------------------------------------------------------------------------------+-------------------------+-------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`uninitialized variable in a constexpr` |nbsp| |+-----------------------+| |nbsp| :diagtext:`is incompatible with C++ standards before C++20`| +| ||:diagtext:`function` || | +| |+-----------------------+| | +| ||:diagtext:`constructor`|| | +| |+-----------------------+| | ++------------------------------------------------------------------------------------+-------------------------+-------------------------------------------------------------------+ + ++------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`constexpr union constructor that does not initialize any member is incompatible with C++ standards before C++20`| ++------------------------------------------------------------------------------------------------------------------------------------------------------+ + ++-------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`virtual constexpr functions are incompatible with C++ standards before C++20`| ++-------------------------------------------------------------------------------------------------------------------+ + ++---------------------------------------------------------------------------------+--------------------------------------------------------------+-------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`decomposition declaration declared` |nbsp| |+------------------------------------------------------------+| |nbsp| :diagtext:`is incompatible with C++ standards before C++20`| +| ||+------------------------------------------+ || | +| |||:diagtext:`'`:placeholder:`B`:diagtext:`'`| || | +| ||+------------------------------------------+ || | +| |+------------------------------------------------------------+| | +| ||+----------------------------------------------------------+|| | +| |||:diagtext:`with '`:placeholder:`B`:diagtext:`' specifiers`||| | +| ||+----------------------------------------------------------+|| | +| |+------------------------------------------------------------+| | ++---------------------------------------------------------------------------------+--------------------------------------------------------------+-------------------------------------------------------------------+ + ++----------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`defaulted comparison operators are incompatible with C++ standards before C++20`| ++----------------------------------------------------------------------------------------------------------------------+ + ++-------------------------------------------------------------------------+--------------------------------------+----------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`explicitly defaulting this` |nbsp| |+------------------------------------+| |nbsp| :diagtext:`with a type different from the implicit type is incompatible with C++ standards before C++20`| +| ||:diagtext:`default constructor` || | +| |+------------------------------------+| | +| ||:diagtext:`copy constructor` || | +| |+------------------------------------+| | +| ||:diagtext:`move constructor` || | +| |+------------------------------------+| | +| ||:diagtext:`copy assignment operator`|| | +| |+------------------------------------+| | +| ||:diagtext:`move assignment operator`|| | +| |+------------------------------------+| | +| ||:diagtext:`destructor` || | +| |+------------------------------------+| | ++-------------------------------------------------------------------------+--------------------------------------+----------------------------------------------------------------------------------------------------------------+ + +-----------------------------------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`explicit capture of 'this' with a capture default of '=' is incompatible with C++ standards before C++2a`| +|:warning:`warning:` |nbsp| :diagtext:`explicit capture of 'this' with a capture default of '=' is incompatible with C++ standards before C++20`| +-----------------------------------------------------------------------------------------------------------------------------------------------+ ++-----------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`explicit(bool) is incompatible with C++ standards before C++20`| ++-----------------------------------------------------------------------------------------------------+ + ++--------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`range-based for loop initialization statements are incompatible with C++ standards before C++20`| ++--------------------------------------------------------------------------------------------------------------------------------------+ + ++------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`initialized lambda capture packs are incompatible with C++ standards before C++20`| ++------------------------------------------------------------------------------------------------------------------------+ + ++-------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`inline nested namespace definition is incompatible with C++ standards before C++20`| ++-------------------------------------------------------------------------------------------------------------------------+ + ++---------------------------+----------------------------------+-----------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| |+--------------------------------+| |nbsp| :diagtext:`of lambda is incompatible with C++ standards before C++20`| +| ||:diagtext:`default construction`|| | +| |+--------------------------------+| | +| ||:diagtext:`assignment` || | +| |+--------------------------------+| | ++---------------------------+----------------------------------+-----------------------------------------------------------------------------+ + ++-----------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`explicit template parameter list for lambdas is incompatible with C++ standards before C++20`| ++-----------------------------------------------------------------------------------------------------------------------------------+ + ++-----------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`'<=>' operator is incompatible with C++ standards before C++20`| ++-----------------------------------------------------------------------------------------------------+ + ++----------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`'char8\_t' type specifier is incompatible with C++ standards before C++20`| ++----------------------------------------------------------------------------------------------------------------+ + -Wc++98-c++11-c++14-c++17-compat-pedantic ----------------------------------------- @@ -1551,8 +1924,12 @@ Also controls `-Wc++98-c++11-c++14-c++17-compat`_. **Diagnostic text:** ++---------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`designated initializers are incompatible with C++ standards before C++20`| ++---------------------------------------------------------------------------------------------------------------+ + +-----------------------------------------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`invoking a pointer to a 'const &' member function on an rvalue is incompatible with C++ standards before C++2a`| +|:warning:`warning:` |nbsp| :diagtext:`invoking a pointer to a 'const &' member function on an rvalue is incompatible with C++ standards before C++20`| +-----------------------------------------------------------------------------------------------------------------------------------------------------+ @@ -1560,6 +1937,16 @@ Also controls `-Wc++98-c++11-c++14-c++17-compat`_. -------------------------- **Diagnostic text:** ++------------------------------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`class template argument deduction is incompatible with C++ standards before C++17`|+---------------------------------------------------------------------------------+| +| || || +| |+---------------------------------------------------------------------------------+| +| ||+-------------------------------------------------------------------------------+|| +| |||:diagtext:`; for compatibility, use explicit type name` |nbsp| :placeholder:`B`||| +| ||+-------------------------------------------------------------------------------+|| +| |+---------------------------------------------------------------------------------+| ++------------------------------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------+ + +---------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`constexpr if is incompatible with C++ standards before C++17`| +---------------------------------------------------------------------------------------------------+ @@ -1688,10 +2075,18 @@ Also controls `-Wc++98-c++11-c++14-compat`_. |:warning:`warning:` |nbsp| :diagtext:`'decltype(auto)' type specifier is incompatible with C++ standards before C++14`| +----------------------------------------------------------------------------------------------------------------------+ ++------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`return type deduction is incompatible with C++ standards before C++14`| ++------------------------------------------------------------------------------------------------------------+ + +--------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`digit separators are incompatible with C++ standards before C++14`| +--------------------------------------------------------------------------------------------------------+ ++----------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`generic lambdas are incompatible with C++11`| ++----------------------------------------------------------------------------------+ + +-------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`initialized lambda captures are incompatible with C++ standards before C++14`| +-------------------------------------------------------------------------------------------------------------------+ @@ -1801,9 +2196,13 @@ Also controls `-Wc++98-c++11-c++14-c++17-compat`_, `-Wc++98-c++11-c++14-compat`_ |:warning:`warning:` |nbsp| :diagtext:`jump from this goto statement to its label is incompatible with C++98`| +------------------------------------------------------------------------------------------------------------+ -+---------------------------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`jump from this indirect goto statement to one of its possible targets is incompatible with C++98`| -+---------------------------------------------------------------------------------------------------------------------------------------+ ++-------------------------------------------------------------+----------------------+--------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`jump from this` |nbsp| |+--------------------+| |nbsp| :diagtext:`goto statement to one of its possible targets is incompatible with C++98`| +| ||:diagtext:`indirect`|| | +| |+--------------------+| | +| ||:diagtext:`asm` || | +| |+--------------------+| | ++-------------------------------------------------------------+----------------------+--------------------------------------------------------------------------------------------+ +------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`initialization of initializer\_list object is incompatible with C++98`| @@ -1855,7 +2254,7 @@ Also controls `-Wc++98-c++11-c++14-c++17-compat`_, `-Wc++98-c++11-c++14-compat`_ +---------------------------+------------------------------+------------------------------------------------------------------------------------------------+--------------------------------------+----------------------------------------------+ |:warning:`warning:` |nbsp| |+----------------------------+| |nbsp| :diagtext:`member` |nbsp| :placeholder:`B` |nbsp| :diagtext:`with a non-trivial` |nbsp| |+------------------------------------+| |nbsp| :diagtext:`is incompatible with C++98`| -| ||:diagtext:`anonymous struct`|| ||:diagtext:`constructor` || | +| ||:diagtext:`anonymous struct`|| ||:diagtext:`default constructor` || | | |+----------------------------+| |+------------------------------------+| | | ||:diagtext:`union` || ||:diagtext:`copy constructor` || | | |+----------------------------+| |+------------------------------------+| | @@ -1949,28 +2348,6 @@ Also controls `-Wc++98-c++11-c++14-c++17-compat`_, `-Wc++98-c++11-c++14-compat`_ |:warning:`warning:` |nbsp| :diagtext:`default template arguments for a function template are incompatible with C++98`| +---------------------------------------------------------------------------------------------------------------------+ -+---------------------------+---------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| |+-------------------------------------+| |nbsp| :diagtext:`specialization of` |nbsp| :placeholder:`B` |nbsp| :diagtext:`outside namespace` |nbsp| :placeholder:`C` |nbsp| :diagtext:`is incompatible with C++98`| -| ||:diagtext:`class template` || | -| |+-------------------------------------+| | -| ||:diagtext:`class template partial` || | -| |+-------------------------------------+| | -| ||:diagtext:`variable template` || | -| |+-------------------------------------+| | -| ||:diagtext:`variable template partial`|| | -| |+-------------------------------------+| | -| ||:diagtext:`function template` || | -| |+-------------------------------------+| | -| ||:diagtext:`member function` || | -| |+-------------------------------------+| | -| ||:diagtext:`static data member` || | -| |+-------------------------------------+| | -| ||:diagtext:`member class` || | -| |+-------------------------------------+| | -| ||:diagtext:`member enumeration` || | -| |+-------------------------------------+| | -+---------------------------+---------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - +----------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`trailing return types are incompatible with C++98`| +----------------------------------------------------------------------------------------+ @@ -2022,29 +2399,42 @@ Also controls `-Wc++98-c++11-c++14-c++17-compat`_, `-Wc++98-c++11-c++14-compat`_ ------------------------------------- **Diagnostic text:** -+---------------------------+-----------------------------------------+----------------------------------------------------------------------------------------------------------------------------+------------------------------------------------+----------------------------+ -|:warning:`warning:` |nbsp| |+---------------------------------------+| |nbsp| :diagtext:`of type` |nbsp| :placeholder:`C` |nbsp| :diagtext:`when binding a reference to a temporary would` |nbsp| |+----------------------------------------------+| |nbsp| :diagtext:`in C++98`| -| ||:diagtext:`copying variable` || ||:diagtext:`invoke an inaccessible constructor`|| | -| |+---------------------------------------+| |+----------------------------------------------+| | -| ||:diagtext:`copying parameter` || ||:diagtext:`find no viable constructor` || | -| |+---------------------------------------+| |+----------------------------------------------+| | -| ||:diagtext:`returning object` || ||:diagtext:`find ambiguous constructors` || | -| |+---------------------------------------+| |+----------------------------------------------+| | -| ||:diagtext:`throwing object` || ||:diagtext:`invoke a deleted constructor` || | -| |+---------------------------------------+| |+----------------------------------------------+| | -| ||:diagtext:`copying member subobject` || | | | -| |+---------------------------------------+| | | | -| ||:diagtext:`copying array element` || | | | -| |+---------------------------------------+| | | | -| ||:diagtext:`allocating object` || | | | -| |+---------------------------------------+| | | | -| ||:diagtext:`copying temporary` || | | | -| |+---------------------------------------+| | | | -| ||:diagtext:`initializing base subobject`|| | | | -| |+---------------------------------------+| | | | -| ||:diagtext:`initializing vector element`|| | | | -| |+---------------------------------------+| | | | -+---------------------------+-----------------------------------------+----------------------------------------------------------------------------------------------------------------------------+------------------------------------------------+----------------------------+ ++---------------------------+------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------+------------------------------------------------+----------------------------+ +|:warning:`warning:` |nbsp| |+----------------------------------------------------+| |nbsp| :diagtext:`of type` |nbsp| :placeholder:`C` |nbsp| :diagtext:`when binding a reference to a temporary would` |nbsp| |+----------------------------------------------+| |nbsp| :diagtext:`in C++98`| +| ||:diagtext:`copying variable` || ||:diagtext:`invoke an inaccessible constructor`|| | +| |+----------------------------------------------------+| |+----------------------------------------------+| | +| ||:diagtext:`copying parameter` || ||:diagtext:`find no viable constructor` || | +| |+----------------------------------------------------+| |+----------------------------------------------+| | +| ||:diagtext:`returning object` || ||:diagtext:`find ambiguous constructors` || | +| |+----------------------------------------------------+| |+----------------------------------------------+| | +| ||:diagtext:`initializing statement expression result`|| ||:diagtext:`invoke a deleted constructor` || | +| |+----------------------------------------------------+| |+----------------------------------------------+| | +| ||:diagtext:`throwing object` || | | | +| |+----------------------------------------------------+| | | | +| ||:diagtext:`copying member subobject` || | | | +| |+----------------------------------------------------+| | | | +| ||:diagtext:`copying array element` || | | | +| |+----------------------------------------------------+| | | | +| ||:diagtext:`allocating object` || | | | +| |+----------------------------------------------------+| | | | +| ||:diagtext:`copying temporary` || | | | +| |+----------------------------------------------------+| | | | +| ||:diagtext:`initializing base subobject` || | | | +| |+----------------------------------------------------+| | | | +| ||:diagtext:`initializing vector element` || | | | +| |+----------------------------------------------------+| | | | +| ||:diagtext:`capturing value` || | | | +| |+----------------------------------------------------+| | | | ++---------------------------+------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------+------------------------------------------------+----------------------------+ + + +-Wc++98-compat-extra-semi +------------------------- +**Diagnostic text:** + ++-------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`extra ';' outside of a function is incompatible with C++98`| ++-------------------------------------------------------------------------------------------------+ -Wc++98-compat-local-type-template-args @@ -2058,7 +2448,7 @@ Also controls `-Wc++98-c++11-c++14-c++17-compat`_, `-Wc++98-c++11-c++14-compat`_ -Wc++98-compat-pedantic ----------------------- -Also controls `-Wc++98-c++11-c++14-c++17-compat-pedantic`_, `-Wc++98-c++11-c++14-compat-pedantic`_, `-Wc++98-c++11-compat-pedantic`_, `-Wc++98-compat`_, `-Wc++98-compat-bind-to-temporary-copy`_. +Also controls `-Wc++98-c++11-c++14-c++17-compat-pedantic`_, `-Wc++98-c++11-c++14-compat-pedantic`_, `-Wc++98-c++11-compat-pedantic`_, `-Wc++98-compat`_, `-Wc++98-compat-bind-to-temporary-copy`_, `-Wc++98-compat-extra-semi`_. **Diagnostic text:** @@ -2098,10 +2488,6 @@ Also controls `-Wc++98-c++11-c++14-c++17-compat-pedantic`_, `-Wc++98-c++11-c++14 |:warning:`warning:` |nbsp| :diagtext:`#line number greater than 32767 is incompatible with C++98`| +-------------------------------------------------------------------------------------------------+ -+-------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`extra ';' outside of a function is incompatible with C++98`| -+-------------------------------------------------------------------------------------------------+ - +----------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`variadic macros are incompatible with C++98`| +----------------------------------------------------------------------------------+ @@ -2124,25 +2510,13 @@ Also controls `-Wc++98-c++11-c++14-c++17-compat-pedantic`_, `-Wc++98-c++11-c++14 |:warning:`warning:` |nbsp| :diagtext:`anonymous unions are a C11 extension`| +---------------------------------------------------------------------------+ -+----------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is a C11-specific feature`| -+----------------------------------------------------------------------------------------+ - +----------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`anonymous structs are a C11 extension`| +----------------------------------------------------------------------------+ -+------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`generic selections are a C11-specific feature`| -+------------------------------------------------------------------------------------+ - -+--------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`\_Noreturn functions are a C11-specific feature`| -+--------------------------------------------------------------------------------------+ - -+---------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`\_Static\_assert is a C11-specific feature`| -+---------------------------------------------------------------------------------+ ++----------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`'`:placeholder:`A`:diagtext:`' is a C11 extension`| ++----------------------------------------------------------------------------------------+ -Wc99-compat @@ -2172,10 +2546,37 @@ Some of the diagnostics controlled by this flag are enabled by default. +------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+----------------------------------+ +-Wc99-designator +---------------- +Some of the diagnostics controlled by this flag are enabled by default. + +Also controls `-Wc++20-designator`_. + +**Diagnostic text:** + ++--------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`designated initializers are a C99 feature`| ++--------------------------------------------------------------------------------+ + ++----------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`array designators are a C99 extension`| ++----------------------------------------------------------------------------+ + ++--------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`mixture of designated and non-designated initializers in the same initializer list is a C99 extension`| ++--------------------------------------------------------------------------------------------------------------------------------------------+ + ++-----------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`nested designators are a C99 extension`| ++-----------------------------------------------------------------------------+ + + -Wc99-extensions ---------------- Some of the diagnostics controlled by this flag are enabled by default. +Also controls `-Wc99-designator`_. + **Diagnostic text:** +-----------------------------------------------------------------------------------------------+ @@ -2196,6 +2597,10 @@ Some of the diagnostics controlled by this flag are enabled by default. |:warning:`warning:` |nbsp| :diagtext:`compound literals are a C99-specific feature`| +-----------------------------------------------------------------------------------+ ++----------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`'`:placeholder:`A`:diagtext:`' is a C99 extension`| ++----------------------------------------------------------------------------------------+ + +-------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`flexible array members are a C99 feature`| +-------------------------------------------------------------------------------+ @@ -2208,10 +2613,6 @@ Some of the diagnostics controlled by this flag are enabled by default. |:warning:`warning:` |nbsp| :diagtext:`ISO C99 requires whitespace after the macro name`| +---------------------------------------------------------------------------------------+ -+--------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`designated initializers are a C99 feature`| -+--------------------------------------------------------------------------------+ - +------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`empty macro arguments are a C99 feature`| +------------------------------------------------------------------------------+ @@ -2225,6 +2626,21 @@ Some of the diagnostics controlled by this flag are enabled by default. +---------------------------------------------------------------------------------------+ +-Wcall-to-pure-virtual-from-ctor-dtor +------------------------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------------+----------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`call to pure virtual member function` |nbsp| :placeholder:`A` |nbsp| :diagtext:`has undefined behavior; overrides of` |nbsp| :placeholder:`A` |nbsp| :diagtext:`in subclasses are not available in the` |nbsp| |+-----------------------+| |nbsp| :diagtext:`of` |nbsp| :placeholder:`C`| +| ||:diagtext:`constructor`|| | +| |+-----------------------+| | +| ||:diagtext:`destructor` || | +| |+-----------------------+| | ++-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------------+----------------------------------------------+ + + -Wcast-align ------------ **Diagnostic text:** @@ -2275,6 +2691,29 @@ This diagnostic is enabled by default. +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +-Wcast-qual-unrelated +--------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++---------------------------------------------------------------------+-----------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`ISO C++ does not allow` |nbsp| |+---------------------------------+| |nbsp| :diagtext:`from` |nbsp| :placeholder:`B` |nbsp| :diagtext:`to` |nbsp| :placeholder:`C` |nbsp| :diagtext:`because it casts away qualifiers, even though the source and destination types are unrelated`| +| ||:diagtext:`const\_cast` || | +| |+---------------------------------+| | +| ||:diagtext:`static\_cast` || | +| |+---------------------------------+| | +| ||:diagtext:`reinterpret\_cast` || | +| |+---------------------------------+| | +| ||:diagtext:`dynamic\_cast` || | +| |+---------------------------------+| | +| ||:diagtext:`C-style cast` || | +| |+---------------------------------+| | +| ||:diagtext:`functional-style cast`|| | +| |+---------------------------------+| | ++---------------------------------------------------------------------+-----------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + + -Wchar-align ------------ This diagnostic flag exists for GCC compatibility, and has no effect in Clang. @@ -2310,13 +2749,13 @@ This diagnostic is enabled by default. |:warning:`warning:` |nbsp| :diagtext:`support for '/Yc' and '/Yu' with different filenames not implemented yet; flags ignored`| +------------------------------------------------------------------------------------------------------------------------------+ -+--------------------------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`support for '`:placeholder:`A`:diagtext:`' without a filename not implemented yet; flag ignored`| -+--------------------------------------------------------------------------------------------------------------------------------------+ ++-------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`#pragma hdrstop filename not supported, /Fp can be used to specify precompiled header filename`| ++-------------------------------------------------------------------------------------------------------------------------------------+ -+----------------------------------------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`support for '`:placeholder:`A`:diagtext:`' without a corresponding /FI flag not implemented yet; flag ignored`| -+----------------------------------------------------------------------------------------------------------------------------------------------------+ ++-----------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`definition of macro` |nbsp| :placeholder:`A` |nbsp| :diagtext:`does not match definition in precompiled header`| ++-----------------------------------------------------------------------------------------------------------------------------------------------------+ -Wclass-varargs @@ -2397,6 +2836,17 @@ This diagnostic is enabled by default. +----------------------------------------------------------------------------------------------------------------------+ +-Wconcepts-ts-compat +-------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++---------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`ISO C++20 does not permit the 'bool' keyword after 'concept'`| ++---------------------------------------------------------------------------------------------------+ + + -Wconditional-type-mismatch --------------------------- This diagnostic is enabled by default. @@ -2444,7 +2894,7 @@ This diagnostic is enabled by default. --------------------- This diagnostic is enabled by default. -Also controls `-Wbitfield-constant-conversion`_. +Also controls `-Wbitfield-constant-conversion`_, `-Wobjc-bool-constant-conversion`_. **Diagnostic text:** @@ -2453,6 +2903,17 @@ Also controls `-Wbitfield-constant-conversion`_. +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +-Wconstant-evaluated +-------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++--------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`'`:placeholder:`A`:diagtext:`' will always evaluate to 'true' in a manifestly constant-evaluated expression`| ++--------------------------------------------------------------------------------------------------------------------------------------------------+ + + -Wconstant-logical-operand -------------------------- This diagnostic is enabled by default. @@ -2516,7 +2977,7 @@ This diagnostic is enabled by default. ------------ Some of the diagnostics controlled by this flag are enabled by default. -Also controls `-Wbitfield-enum-conversion`_, `-Wbool-conversion`_, `-Wconstant-conversion`_, `-Wenum-conversion`_, `-Wfloat-conversion`_, `-Wint-conversion`_, `-Wliteral-conversion`_, `-Wnon-literal-null-conversion`_, `-Wnull-conversion`_, `-Wobjc-literal-conversion`_, `-Wshorten-64-to-32`_, `-Wsign-conversion`_, `-Wstring-conversion`_. +Also controls `-Wbitfield-enum-conversion`_, `-Wbool-conversion`_, `-Wconstant-conversion`_, `-Wenum-conversion`_, `-Wfloat-conversion`_, `-Wimplicit-float-conversion`_, `-Wimplicit-int-conversion`_, `-Wint-conversion`_, `-Wliteral-conversion`_, `-Wnon-literal-null-conversion`_, `-Wnull-conversion`_, `-Wobjc-literal-conversion`_, `-Wshorten-64-to-32`_, `-Wsign-conversion`_, `-Wstring-conversion`_. **Diagnostic text:** @@ -2524,18 +2985,14 @@ Also controls `-Wbitfield-enum-conversion`_, `-Wbool-conversion`_, `-Wconstant-c |:warning:`warning:` |nbsp| :diagtext:`implicit conversion discards imaginary component:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`to` |nbsp| :placeholder:`B`| +--------------------------------------------------------------------------------------------------------------------------------------------------------------+ -+----------------------------------------------------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`implicit conversion loses floating-point precision:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`to` |nbsp| :placeholder:`B`| -+----------------------------------------------------------------------------------------------------------------------------------------------------------------+ - -+---------------------------------------------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`implicit conversion loses integer precision:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`to` |nbsp| :placeholder:`B`| -+---------------------------------------------------------------------------------------------------------------------------------------------------------+ - +--------------------------------------------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`implicit conversion turns vector to scalar:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`to` |nbsp| :placeholder:`B`| +--------------------------------------------------------------------------------------------------------------------------------------------------------+ ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`passing non-generic address space pointer to` |nbsp| :placeholder:`A` |nbsp| :diagtext:`may cause dynamic conversion affecting performance`| ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + +-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`non-type template argument with value '`:placeholder:`A`:diagtext:`' converted to '`:placeholder:`B`:diagtext:`' for unsigned template parameter of type` |nbsp| :placeholder:`C`| +-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ @@ -2593,10 +3050,30 @@ Synonym for `-W#warnings`_. +------------------------------------------------------------------------------------------------------------+----------------------+--------------------------------------------------------------------------------------------+------------------------+ +-Wctad-maybe-unsupported +------------------------ +**Diagnostic text:** + ++--------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`may not intend to support class template argument deduction`| ++--------------------------------------------------------------------------------------------------------------------------+ + + -Wctor-dtor-privacy ------------------- This diagnostic flag exists for GCC compatibility, and has no effect in Clang. +-Wctu +----- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`imported AST from '`:placeholder:`A`:diagtext:`' had been generated for a different target, current:` |nbsp| :placeholder:`B`:diagtext:`, imported:` |nbsp| :placeholder:`C`| ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + + -Wcuda-compat ------------- Some of the diagnostics controlled by this flag are enabled by default. @@ -2637,6 +3114,55 @@ Some of the diagnostics controlled by this flag are enabled by default. +---------------------------------------------------------------------------------------------------------------------------------------+--------------------+----------------------------------------------------------------------------+ +-Wdangling +---------- +This diagnostic is enabled by default. + +Also controls `-Wdangling-field`_, `-Wdangling-gsl`_, `-Wdangling-initializer-list`_, `-Wreturn-stack-address`_. + +**Diagnostic text:** + ++---------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------+----------------------------+---------------------------------------------------------------+ +|:warning:`warning:` |nbsp| |+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| |nbsp| |+--------------------------+|:diagtext:`will be destroyed at the end of the full-expression`| +| ||+-----------------------------+---------------------------------------------------------+--------+------------------------------------------------------------------------+|| ||+------------------------+|| | +| |||:diagtext:`temporary` |nbsp| |+-------------------------------------------------------+| |nbsp| |+----------------------------------------------------------------------+||| |||:placeholder:`D` |nbsp| ||| | +| ||| ||:diagtext:`whose address is used as value of` || ||+-------------------------------+------------------------------------+|||| ||+------------------------+|| | +| ||| |+-------------------------------------------------------+| |||+-----------------------------+|:diagtext:`member of local variable`||||| |+--------------------------+| | +| ||| ||+--------------------------------+--------------------+|| |||| || ||||| || || | +| ||| |||+------------------------------+|:diagtext:`bound to`||| |||+-----------------------------+| ||||| |+--------------------------+| | +| ||| |||| || ||| ||||:diagtext:`reference` |nbsp| || ||||| | | | +| ||| |||+------------------------------+| ||| |||+-----------------------------+| ||||| | | | +| ||| ||||:diagtext:`implicitly` |nbsp| || ||| ||+-------------------------------+------------------------------------+|||| | | | +| ||| |||+------------------------------+| ||| |+----------------------------------------------------------------------+||| | | | +| ||| ||+--------------------------------+--------------------+|| ||+-------------------------+-----------------------+ |||| | | | +| ||| |+-------------------------------------------------------+| |||:diagtext:`local` |nbsp| |+---------------------+| |||| | | | +| ||| | | ||| ||:diagtext:`variable` || |||| | | | +| ||| | | ||| |+---------------------+| |||| | | | +| ||| | | ||| ||:diagtext:`reference`|| |||| | | | +| ||| | | ||| |+---------------------+| |||| | | | +| ||| | | ||+-------------------------+-----------------------+ |||| | | | +| ||| | | |+----------------------------------------------------------------------+||| | | | +| ||+-----------------------------+---------------------------------------------------------+--------+------------------------------------------------------------------------+|| | | | +| |+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| | | | +| ||+---------------------------------+----------------------------------------------------------+ || | | | +| |||:diagtext:`array backing` |nbsp| |+--------------------------------------------------------+| || | | | +| ||| ||:diagtext:`initializer list subobject of local variable`|| || | | | +| ||| |+--------------------------------------------------------+| || | | | +| ||| ||:diagtext:`local initializer list` || || | | | +| ||| |+--------------------------------------------------------+| || | | | +| ||+---------------------------------+----------------------------------------------------------+ || | | | +| |+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| | | | ++---------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------+----------------------------+---------------------------------------------------------------+ + ++---------------------------------------------------------------------------+-----------------------------------------------+------------------------------------------------------------------------------------------------------------------------------+---------------------------+--------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`sorry, lifetime extension of` |nbsp| |+---------------------------------------------+| |nbsp| :diagtext:`created by aggregate initialization using default member initializer is not supported; lifetime of` |nbsp| |+-------------------------+| |nbsp| :diagtext:`will end at the end of the full-expression`| +| ||:diagtext:`temporary` || ||:diagtext:`temporary` || | +| |+---------------------------------------------+| |+-------------------------+| | +| ||:diagtext:`backing array of initializer list`|| ||:diagtext:`backing array`|| | +| |+---------------------------------------------+| |+-------------------------+| | ++---------------------------------------------------------------------------+-----------------------------------------------+------------------------------------------------------------------------------------------------------------------------------+---------------------------+--------------------------------------------------------------+ + + -Wdangling-else --------------- This diagnostic is enabled by default. @@ -2654,21 +3180,48 @@ This diagnostic is enabled by default. **Diagnostic text:** -+---------------------------------------------------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`binding reference member` |nbsp| :placeholder:`A` |nbsp| :diagtext:`to stack allocated parameter` |nbsp| :placeholder:`B`| -+---------------------------------------------------------------------------------------------------------------------------------------------------------------+ ++-------------------------------------------------------------------------------------------------------------------------------------+-----------------------+------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`binding reference member` |nbsp| :placeholder:`A` |nbsp| :diagtext:`to stack allocated` |nbsp| |+---------------------+| |nbsp| :placeholder:`B`| +| ||:diagtext:`variable` || | +| |+---------------------+| | +| ||:diagtext:`parameter`|| | +| |+---------------------+| | ++-------------------------------------------------------------------------------------------------------------------------------------+-----------------------+------------------------+ -+----------------------------------------------------------------+----------------------------------+----------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`binding reference` |nbsp| |+--------------------------------+|:diagtext:`member` |nbsp| :placeholder:`A` |nbsp| :diagtext:`to a temporary value`| -| || || | -| |+--------------------------------+| | -| ||:diagtext:`subobject of` |nbsp| || | -| |+--------------------------------+| | -+----------------------------------------------------------------+----------------------------------+----------------------------------------------------------------------------------+ ++---------------------------+--------------------------------------------------------+--------+----------------------------------+--------------------------------------------------+----------------------+------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| |+------------------------------------------------------+| |nbsp| |+--------------------------------+|:diagtext:`member` |nbsp| :placeholder:`A` |nbsp| |+--------------------+| |nbsp| :diagtext:`a temporary object whose lifetime is shorter than the lifetime of the constructed object`| +| ||:diagtext:`reference` || || || ||:diagtext:`binds to`|| | +| |+------------------------------------------------------+| |+--------------------------------+| |+--------------------+| | +| ||:diagtext:`backing array for 'std::initializer\_list'`|| ||:diagtext:`subobject of` |nbsp| || ||:diagtext:`is` || | +| |+------------------------------------------------------+| |+--------------------------------+| |+--------------------+| | ++---------------------------+--------------------------------------------------------+--------+----------------------------------+--------------------------------------------------+----------------------+------------------------------------------------------------------------------------------------------------+ -+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`initializing pointer member` |nbsp| :placeholder:`A` |nbsp| :diagtext:`with the stack address of parameter` |nbsp| :placeholder:`B`| -+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ ++-----------------------------------------------------------------------------------------------------------------------------------------------+-----------------------+------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`initializing pointer member` |nbsp| :placeholder:`A` |nbsp| :diagtext:`with the stack address of` |nbsp| |+---------------------+| |nbsp| :placeholder:`B`| +| ||:diagtext:`variable` || | +| |+---------------------+| | +| ||:diagtext:`parameter`|| | +| |+---------------------+| | ++-----------------------------------------------------------------------------------------------------------------------------------------------+-----------------------+------------------------+ + ++--------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`temporary bound to reference member of allocated object will be destroyed at the end of the full-expression`| ++--------------------------------------------------------------------------------------------------------------------------------------------------+ + + +-Wdangling-gsl +-------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++---------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`object backing the pointer will be destroyed at the end of the full-expression`| ++---------------------------------------------------------------------------------------------------------------------+ + ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`initializing pointer member` |nbsp| :placeholder:`A` |nbsp| :diagtext:`to point to a temporary object whose lifetime is shorter than the lifetime of the constructed object`| ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -Wdangling-initializer-list @@ -2677,13 +3230,24 @@ This diagnostic is enabled by default. **Diagnostic text:** -+-----------------------------------------------------------------------------------------------------------------+---------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`array backing the initializer list will be destroyed at the end of` |nbsp| |+-------------------------------+| -| ||:diagtext:`the full-expression`|| -| |+-------------------------------+| -| ||:diagtext:`the constructor` || -| |+-------------------------------+| -+-----------------------------------------------------------------------------------------------------------------+---------------------------------+ ++------------------------------------------------------------+----------------------------------------------------------------+-----------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`array backing` |nbsp| |+--------------------------------------------------------------+| |nbsp| :diagtext:`will be destroyed at the end of the full-expression`| +| ||:diagtext:`initializer list subobject of the allocated object`|| | +| |+--------------------------------------------------------------+| | +| ||:diagtext:`the allocated initializer list` || | +| |+--------------------------------------------------------------+| | ++------------------------------------------------------------+----------------------------------------------------------------+-----------------------------------------------------------------------+ + + +-Wdarwin-sdk-settings +--------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++----------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`SDK settings were ignored as 'SDKSettings.json' could not be parsed`| ++----------------------------------------------------------------------------------------------------------+ -Wdate-time @@ -2726,6 +3290,43 @@ This diagnostic is enabled by default. +-----------------------------------------------------------------------------------+ +-Wdefaulted-function-deleted +---------------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++-------------------------------------------------------------------+------------------------+--------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`explicitly defaulted` |nbsp| |+----------------------+| |nbsp| :diagtext:`comparison operator` |nbsp| :diagtext:`is implicitly deleted`| +| ||:diagtext:`` || | +| |+----------------------+| | +| ||:diagtext:`equality` || | +| |+----------------------+| | +| ||:diagtext:`three-way` || | +| |+----------------------+| | +| ||:diagtext:`equality` || | +| |+----------------------+| | +| ||:diagtext:`relational`|| | +| |+----------------------+| | ++-------------------------------------------------------------------+------------------------+--------------------------------------------------------------------------------+ + ++-------------------------------------------------------------------+--------------------------------------+-----------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`explicitly defaulted` |nbsp| |+------------------------------------+| |nbsp| :diagtext:`is implicitly deleted`| +| ||:diagtext:`default constructor` || | +| |+------------------------------------+| | +| ||:diagtext:`copy constructor` || | +| |+------------------------------------+| | +| ||:diagtext:`move constructor` || | +| |+------------------------------------+| | +| ||:diagtext:`copy assignment operator`|| | +| |+------------------------------------+| | +| ||:diagtext:`move assignment operator`|| | +| |+------------------------------------+| | +| ||:diagtext:`destructor` || | +| |+------------------------------------+| | ++-------------------------------------------------------------------+--------------------------------------+-----------------------------------------+ + + -Wdelegating-ctor-cycles ------------------------ This diagnostic is an error by default, but the flag ``-Wno-delegating-ctor-cycles`` can be used to disable the error. @@ -2737,6 +3338,21 @@ This diagnostic is an error by default, but the flag ``-Wno-delegating-ctor-cycl +------------------------------------------------------------------------------------------------------------------------+ +-Wdelete-abstract-non-virtual-dtor +---------------------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++---------------------------+------------------------+------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| |+----------------------+| |nbsp| :diagtext:`called on` |nbsp| :placeholder:`B` |nbsp| :diagtext:`that is abstract but has non-virtual destructor`| +| ||:diagtext:`delete` || | +| |+----------------------+| | +| ||:diagtext:`destructor`|| | +| |+----------------------+| | ++---------------------------+------------------------+------------------------------------------------------------------------------------------------------------------------+ + + -Wdelete-incomplete ------------------- This diagnostic is enabled by default. @@ -2752,20 +3368,10 @@ This diagnostic is enabled by default. +--------------------------------------------------------------------------------------------------------------------------------------------------+ --Wdelete-non-virtual-dtor -------------------------- -Some of the diagnostics controlled by this flag are enabled by default. - +-Wdelete-non-abstract-non-virtual-dtor +-------------------------------------- **Diagnostic text:** -+---------------------------+------------------------+------------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| |+----------------------+| |nbsp| :diagtext:`called on` |nbsp| :placeholder:`B` |nbsp| :diagtext:`that is abstract but has non-virtual destructor`| -| ||:diagtext:`delete` || | -| |+----------------------+| | -| ||:diagtext:`destructor`|| | -| |+----------------------+| | -+---------------------------+------------------------+------------------------------------------------------------------------------------------------------------------------+ - +---------------------------+------------------------+----------------------------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| |+----------------------+| |nbsp| :diagtext:`called on non-final` |nbsp| :placeholder:`B` |nbsp| :diagtext:`that has virtual functions but non-virtual destructor`| | ||:diagtext:`delete` || | @@ -2775,11 +3381,18 @@ Some of the diagnostics controlled by this flag are enabled by default. +---------------------------+------------------------+----------------------------------------------------------------------------------------------------------------------------------------+ +-Wdelete-non-virtual-dtor +------------------------- +Some of the diagnostics controlled by this flag are enabled by default. + +Controls `-Wdelete-abstract-non-virtual-dtor`_, `-Wdelete-non-abstract-non-virtual-dtor`_. + + -Wdeprecated ------------ Some of the diagnostics controlled by this flag are enabled by default. -Also controls `-Wdeprecated-attributes`_, `-Wdeprecated-declarations`_, `-Wdeprecated-dynamic-exception-spec`_, `-Wdeprecated-increment-bool`_, `-Wdeprecated-register`_, `-Wdeprecated-writable-strings`_. +Also controls `-Wdeprecated-anon-enum-enum-conversion`_, `-Wdeprecated-array-compare`_, `-Wdeprecated-attributes`_, `-Wdeprecated-comma-subscript`_, `-Wdeprecated-copy`_, `-Wdeprecated-copy-dtor`_, `-Wdeprecated-declarations`_, `-Wdeprecated-dynamic-exception-spec`_, `-Wdeprecated-enum-compare`_, `-Wdeprecated-enum-compare-conditional`_, `-Wdeprecated-enum-enum-conversion`_, `-Wdeprecated-enum-float-conversion`_, `-Wdeprecated-increment-bool`_, `-Wdeprecated-register`_, `-Wdeprecated-this-capture`_, `-Wdeprecated-volatile`_, `-Wdeprecated-writable-strings`_. **Diagnostic text:** @@ -2791,20 +3404,6 @@ Also controls `-Wdeprecated-attributes`_, `-Wdeprecated-declarations`_, `-Wdepre |:warning:`warning:` |nbsp| :diagtext:`access declarations are deprecated; use using declarations instead`| +---------------------------------------------------------------------------------------------------------+ -+--------------------------------------------------------------------------+---------------------------------+-----------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`definition of implicit copy` |nbsp| |+-------------------------------+| |nbsp| :diagtext:`for` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is deprecated because it has a user-declared` |nbsp| |+------------------------------------------------------------+| -| ||:diagtext:`constructor` || ||+------------------------+---------------------------------+|| -| |+-------------------------------+| |||:diagtext:`copy` |nbsp| |+-------------------------------+||| -| ||:diagtext:`assignment operator`|| ||| ||:diagtext:`assignment operator`|||| -| |+-------------------------------+| ||| |+-------------------------------+||| -| | | ||| ||:diagtext:`constructor` |||| -| | | ||| |+-------------------------------+||| -| | | ||+------------------------+---------------------------------+|| -| | | |+------------------------------------------------------------+| -| | | ||:diagtext:`destructor` || -| | | |+------------------------------------------------------------+| -+--------------------------------------------------------------------------+---------------------------------+-----------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------+ - +-------------------------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`out-of-line definition of constexpr static data member is redundant in C++17 and is deprecated`| +-------------------------------------------------------------------------------------------------------------------------------------+ @@ -2817,6 +3416,10 @@ Also controls `-Wdeprecated-attributes`_, `-Wdeprecated-declarations`_, `-Wdepre |:warning:`warning:` |nbsp| :diagtext:`treating '`:placeholder:`A`:diagtext:`' input as '`:placeholder:`B`:diagtext:`' when in C++ mode, this behavior is deprecated`| +--------------------------------------------------------------------------------------------------------------------------------------------------------------------+ ++----------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`-fconcepts-ts is deprecated - use '-std=c++20' for Concepts support`| ++----------------------------------------------------------------------------------------------------------+ + +-----------------------------------------------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`OpenCL version` |nbsp| :placeholder:`A` |nbsp| :diagtext:`does not support the option '`:placeholder:`B`:diagtext:`'`| +-----------------------------------------------------------------------------------------------------------------------------------------------------------+ @@ -2826,15 +3429,84 @@ Also controls `-Wdeprecated-attributes`_, `-Wdeprecated-declarations`_, `-Wdepre +------------------------------------------------------------------------------------+ +-Wdeprecated-anon-enum-enum-conversion +-------------------------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++---------------------------+--------------------------------------------+--------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| |+------------------------------------------+| |nbsp| :diagtext:`different enumeration types` |nbsp| :diagtext:`is deprecated`| +| ||:diagtext:`arithmetic between` || | +| |+------------------------------------------+| | +| ||:diagtext:`bitwise operation between` || | +| |+------------------------------------------+| | +| ||:diagtext:`comparison of` || | +| |+------------------------------------------+| | +| ||:diagtext:`conditional expression between`|| | +| |+------------------------------------------+| | +| ||:diagtext:`compound assignment of` || | +| |+------------------------------------------+| | ++---------------------------+--------------------------------------------+--------------------------------------------------------------------------------+ + + +-Wdeprecated-array-compare +-------------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++-----------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`comparison between two arrays is deprecated; to compare array addresses, use unary '+' to decay operands to pointers`| ++-----------------------------------------------------------------------------------------------------------------------------------------------------------+ + + -Wdeprecated-attributes ----------------------- This diagnostic is enabled by default. **Diagnostic text:** -+------------------------------------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`specifying vector types with the 'mode' attribute is deprecated; use the 'vector\_size' attribute instead`| -+------------------------------------------------------------------------------------------------------------------------------------------------+ ++------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`specifying vector types with the 'mode' attribute is deprecated; use the 'vector\_size' attribute instead`| ++------------------------------------------------------------------------------------------------------------------------------------------------+ + + +-Wdeprecated-comma-subscript +---------------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++--------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`top-level comma expression in array subscript is deprecated`| ++--------------------------------------------------------------------------------------------------+ + + +-Wdeprecated-copy +----------------- +**Diagnostic text:** + ++--------------------------------------------------------------------------+---------------------------------+----------------------------------------------------------------------------------------------------------------------------+---------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`definition of implicit copy` |nbsp| |+-------------------------------+| |nbsp| :diagtext:`for` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is deprecated because it has a user-declared copy` |nbsp| |+-------------------------------+| +| ||:diagtext:`constructor` || ||:diagtext:`assignment operator`|| +| |+-------------------------------+| |+-------------------------------+| +| ||:diagtext:`assignment operator`|| ||:diagtext:`constructor` || +| |+-------------------------------+| |+-------------------------------+| ++--------------------------------------------------------------------------+---------------------------------+----------------------------------------------------------------------------------------------------------------------------+---------------------------------+ + + +-Wdeprecated-copy-dtor +---------------------- +**Diagnostic text:** + ++--------------------------------------------------------------------------+---------------------------------+--------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`definition of implicit copy` |nbsp| |+-------------------------------+| |nbsp| :diagtext:`for` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is deprecated because it has a user-declared destructor`| +| ||:diagtext:`constructor` || | +| |+-------------------------------+| | +| ||:diagtext:`assignment operator`|| | +| |+-------------------------------+| | ++--------------------------------------------------------------------------+---------------------------------+--------------------------------------------------------------------------------------------------------------------------+ -Wdeprecated-declarations @@ -2877,6 +3549,90 @@ This diagnostic is enabled by default. +--------------------------------------------------------------------------------------+ +-Wdeprecated-enum-compare +------------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++---------------------------+--------------------------------------------+--------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| |+------------------------------------------+| |nbsp| :diagtext:`different enumeration types` |nbsp| :diagtext:`is deprecated`| +| ||:diagtext:`arithmetic between` || | +| |+------------------------------------------+| | +| ||:diagtext:`bitwise operation between` || | +| |+------------------------------------------+| | +| ||:diagtext:`comparison of` || | +| |+------------------------------------------+| | +| ||:diagtext:`conditional expression between`|| | +| |+------------------------------------------+| | +| ||:diagtext:`compound assignment of` || | +| |+------------------------------------------+| | ++---------------------------+--------------------------------------------+--------------------------------------------------------------------------------+ + + +-Wdeprecated-enum-compare-conditional +------------------------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++---------------------------+--------------------------------------------+--------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| |+------------------------------------------+| |nbsp| :diagtext:`different enumeration types` |nbsp| :diagtext:`is deprecated`| +| ||:diagtext:`arithmetic between` || | +| |+------------------------------------------+| | +| ||:diagtext:`bitwise operation between` || | +| |+------------------------------------------+| | +| ||:diagtext:`comparison of` || | +| |+------------------------------------------+| | +| ||:diagtext:`conditional expression between`|| | +| |+------------------------------------------+| | +| ||:diagtext:`compound assignment of` || | +| |+------------------------------------------+| | ++---------------------------+--------------------------------------------+--------------------------------------------------------------------------------+ + + +-Wdeprecated-enum-enum-conversion +--------------------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++---------------------------+--------------------------------------------+--------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| |+------------------------------------------+| |nbsp| :diagtext:`different enumeration types` |nbsp| :diagtext:`is deprecated`| +| ||:diagtext:`arithmetic between` || | +| |+------------------------------------------+| | +| ||:diagtext:`bitwise operation between` || | +| |+------------------------------------------+| | +| ||:diagtext:`comparison of` || | +| |+------------------------------------------+| | +| ||:diagtext:`conditional expression between`|| | +| |+------------------------------------------+| | +| ||:diagtext:`compound assignment of` || | +| |+------------------------------------------+| | ++---------------------------+--------------------------------------------+--------------------------------------------------------------------------------+ + + +-Wdeprecated-enum-float-conversion +---------------------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++---------------------------+--------------------------------------------+--------+----------------------------+--------------------------------------------------------+------------------+--------+----------------------------+---------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| |+------------------------------------------+| |nbsp| |+--------------------------+| |nbsp| :diagtext:`type` |nbsp| :placeholder:`C` |nbsp| |+----------------+| |nbsp| |+--------------------------+| |nbsp| :diagtext:`type` |nbsp| :placeholder:`D` |nbsp| :diagtext:`is deprecated`| +| ||:diagtext:`arithmetic between` || ||:diagtext:`floating-point`|| ||:diagtext:`with`|| ||:diagtext:`enumeration` || | +| |+------------------------------------------+| |+--------------------------+| |+----------------+| |+--------------------------+| | +| ||:diagtext:`bitwise operation between` || ||:diagtext:`enumeration` || ||:diagtext:`from`|| ||:diagtext:`floating-point`|| | +| |+------------------------------------------+| |+--------------------------+| |+----------------+| |+--------------------------+| | +| ||:diagtext:`comparison of` || | | ||:diagtext:`and` || | | | +| |+------------------------------------------+| | | |+----------------+| | | | +| ||:diagtext:`conditional expression between`|| | | | | | | | +| |+------------------------------------------+| | | | | | | | +| ||:diagtext:`compound assignment of` || | | | | | | | +| |+------------------------------------------+| | | | | | | | ++---------------------------+--------------------------------------------+--------+----------------------------+--------------------------------------------------------+------------------+--------+----------------------------+---------------------------------------------------------------------------------+ + + -Wdeprecated-implementations ---------------------------- **Diagnostic text:** @@ -2957,6 +3713,50 @@ This diagnostic is enabled by default. +-------------------------------------------------------------------------------------------------------------------+ +-Wdeprecated-this-capture +------------------------- +**Diagnostic text:** + ++-------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`implicit capture of 'this' with a capture default of '=' is deprecated`| ++-------------------------------------------------------------------------------------------------------------+ + + +-Wdeprecated-volatile +--------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++--------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`compound assignment to object of volatile-qualified type` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is deprecated`| ++--------------------------------------------------------------------------------------------------------------------------------------------------------+ + ++---------------------------+-----------------------+-----------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| |+---------------------+| |nbsp| :diagtext:`of object of volatile-qualified type` |nbsp| :placeholder:`B` |nbsp| :diagtext:`is deprecated`| +| ||:diagtext:`decrement`|| | +| |+---------------------+| | +| ||:diagtext:`increment`|| | +| |+---------------------+| | ++---------------------------+-----------------------+-----------------------------------------------------------------------------------------------------------------+ + ++----------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`use of result of assignment to object of volatile-qualified type` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is deprecated`| ++----------------------------------------------------------------------------------------------------------------------------------------------------------------+ + ++---------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`volatile-qualified parameter type` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is deprecated`| ++---------------------------------------------------------------------------------------------------------------------------------+ + ++------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`volatile-qualified return type` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is deprecated`| ++------------------------------------------------------------------------------------------------------------------------------+ + ++---------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`volatile qualifier in structured binding declaration is deprecated`| ++---------------------------------------------------------------------------------------------------------+ + + -Wdeprecated-writable-strings ----------------------------- Synonym for `-Wc++11-compat-deprecated-writable-strings`_. @@ -3140,6 +3940,14 @@ Also controls `-Wdocumentation-deprecated-sync`_, `-Wdocumentation-html`_. |:warning:`warning:` |nbsp| :diagtext:`expected quoted string after equals sign`| +-------------------------------------------------------------------------------+ ++----------------------------------------+----------------+-------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`'`|+--------------+|:placeholder:`B`:diagtext:`' command does not have a valid word argument`| +| ||:diagtext:`\\`|| | +| |+--------------+| | +| ||:diagtext:`@` || | +| |+--------------+| | ++----------------------------------------+----------------+-------------------------------------------------------------------------+ + +-----------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`parameter '`:placeholder:`A`:diagtext:`' is already documented`| +-----------------------------------------------------------------------------------------------------+ @@ -3213,9 +4021,13 @@ Also controls `-Wdocumentation-deprecated-sync`_, `-Wdocumentation-html`_. ------------------------------- **Diagnostic text:** -+----------------------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`declaration is marked with '\\deprecated' command but does not have a deprecation attribute`| -+----------------------------------------------------------------------------------------------------------------------------------+ ++-------------------------------------------------------------------+----------------+-------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`declaration is marked with '`|+--------------+|:diagtext:`deprecated' command but does not have a deprecation attribute`| +| ||:diagtext:`\\`|| | +| |+--------------+| | +| ||:diagtext:`@` || | +| |+--------------+| | ++-------------------------------------------------------------------+----------------+-------------------------------------------------------------------------+ -Wdocumentation-html @@ -3283,7 +4095,7 @@ Also controls `-Wdocumentation-unknown-command`_. -Wduplicate-decl-specifier -------------------------- -This diagnostic is enabled by default. +Some of the diagnostics controlled by this flag are enabled by default. **Diagnostic text:** @@ -3295,6 +4107,14 @@ This diagnostic is enabled by default. |:warning:`warning:` |nbsp| :diagtext:`duplicate '`:placeholder:`A`:diagtext:`' declaration specifier`| +-----------------------------------------------------------------------------------------------------+ ++-------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`multiple identical address spaces specified for type`| ++-------------------------------------------------------------------------------------------+ + ++-----------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`duplicate '`:placeholder:`A`:diagtext:`' declaration specifier`| ++-----------------------------------------------------------------------------------------------------+ + -Wduplicate-enum ---------------- @@ -3418,6 +4238,21 @@ This diagnostic is enabled by default. +-------------------------------------------------------------------------------------------------+ +-Wempty-init-stmt +----------------- +**Diagnostic text:** + ++--------------------------------------------------------------------------+-----------------------------+---------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`empty initialization statement of '`|+---------------------------+|:diagtext:`' has no effect`| +| ||:diagtext:`if` || | +| |+---------------------------+| | +| ||:diagtext:`switch` || | +| |+---------------------------+| | +| ||:diagtext:`range-based for`|| | +| |+---------------------------+| | ++--------------------------------------------------------------------------+-----------------------------+---------------------------+ + + -Wempty-translation-unit ------------------------ **Diagnostic text:** @@ -3447,13 +4282,46 @@ Synonym for `-Wextra-tokens`_. -------------- This diagnostic is enabled by default. -Also controls `-Wenum-compare-switch`_. +Also controls `-Wdeprecated-enum-compare`_, `-Wenum-compare-switch`_. **Diagnostic text:** -+------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`comparison of two values with different enumeration types`| -+------------------------------------------------------------------------------------------------+ ++---------------------------+--------------------------------------------+-----------------------------------------------+ +|:warning:`warning:` |nbsp| |+------------------------------------------+| |nbsp| :diagtext:`different enumeration types`| +| ||:diagtext:`arithmetic between` || | +| |+------------------------------------------+| | +| ||:diagtext:`bitwise operation between` || | +| |+------------------------------------------+| | +| ||:diagtext:`comparison of` || | +| |+------------------------------------------+| | +| ||:diagtext:`conditional expression between`|| | +| |+------------------------------------------+| | +| ||:diagtext:`compound assignment of` || | +| |+------------------------------------------+| | ++---------------------------+--------------------------------------------+-----------------------------------------------+ + + +-Wenum-compare-conditional +-------------------------- +Some of the diagnostics controlled by this flag are enabled by default. + +Also controls `-Wdeprecated-enum-compare-conditional`_. + +**Diagnostic text:** + ++---------------------------+--------------------------------------------+-----------------------------------------------+ +|:warning:`warning:` |nbsp| |+------------------------------------------+| |nbsp| :diagtext:`different enumeration types`| +| ||:diagtext:`arithmetic between` || | +| |+------------------------------------------+| | +| ||:diagtext:`bitwise operation between` || | +| |+------------------------------------------+| | +| ||:diagtext:`comparison of` || | +| |+------------------------------------------+| | +| ||:diagtext:`conditional expression between`|| | +| |+------------------------------------------+| | +| ||:diagtext:`compound assignment of` || | +| |+------------------------------------------+| | ++---------------------------+--------------------------------------------+-----------------------------------------------+ -Wenum-compare-switch @@ -3462,14 +4330,16 @@ This diagnostic is enabled by default. **Diagnostic text:** -+--------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`comparison of two values with different enumeration types in switch statement`| -+--------------------------------------------------------------------------------------------------------------------+ ++----------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`comparison of different enumeration types in switch statement`| ++----------------------------------------------------------------------------------------------------+ -Wenum-conversion ----------------- -This diagnostic is enabled by default. +Some of the diagnostics controlled by this flag are enabled by default. + +Also controls `-Wenum-compare-conditional`_, `-Wenum-enum-conversion`_, `-Wenum-float-conversion`_. **Diagnostic text:** @@ -3478,6 +4348,52 @@ This diagnostic is enabled by default. +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +-Wenum-enum-conversion +---------------------- +Some of the diagnostics controlled by this flag are enabled by default. + +Also controls `-Wdeprecated-enum-enum-conversion`_. + +**Diagnostic text:** + ++---------------------------+--------------------------------------------+-----------------------------------------------+ +|:warning:`warning:` |nbsp| |+------------------------------------------+| |nbsp| :diagtext:`different enumeration types`| +| ||:diagtext:`arithmetic between` || | +| |+------------------------------------------+| | +| ||:diagtext:`bitwise operation between` || | +| |+------------------------------------------+| | +| ||:diagtext:`comparison of` || | +| |+------------------------------------------+| | +| ||:diagtext:`conditional expression between`|| | +| |+------------------------------------------+| | +| ||:diagtext:`compound assignment of` || | +| |+------------------------------------------+| | ++---------------------------+--------------------------------------------+-----------------------------------------------+ + + +-Wenum-float-conversion +----------------------- +Some of the diagnostics controlled by this flag are enabled by default. + +Also controls `-Wdeprecated-enum-float-conversion`_. + +**Diagnostic text:** + ++---------------------------+--------------------------------------------+--------+----------------------------+--------------------------------------------------------+------------------+--------+----------------------------+------------------------------------------------+ +|:warning:`warning:` |nbsp| |+------------------------------------------+| |nbsp| |+--------------------------+| |nbsp| :diagtext:`type` |nbsp| :placeholder:`C` |nbsp| |+----------------+| |nbsp| |+--------------------------+| |nbsp| :diagtext:`type` |nbsp| :placeholder:`D`| +| ||:diagtext:`arithmetic between` || ||:diagtext:`floating-point`|| ||:diagtext:`with`|| ||:diagtext:`enumeration` || | +| |+------------------------------------------+| |+--------------------------+| |+----------------+| |+--------------------------+| | +| ||:diagtext:`bitwise operation between` || ||:diagtext:`enumeration` || ||:diagtext:`from`|| ||:diagtext:`floating-point`|| | +| |+------------------------------------------+| |+--------------------------+| |+----------------+| |+--------------------------+| | +| ||:diagtext:`comparison of` || | | ||:diagtext:`and` || | | | +| |+------------------------------------------+| | | |+----------------+| | | | +| ||:diagtext:`conditional expression between`|| | | | | | | | +| |+------------------------------------------+| | | | | | | | +| ||:diagtext:`compound assignment of` || | | | | | | | +| |+------------------------------------------+| | | | | | | | ++---------------------------+--------------------------------------------+--------+----------------------------+--------------------------------------------------------+------------------+--------+----------------------------+------------------------------------------------+ + + -Wenum-too-large ---------------- This diagnostic is enabled by default. @@ -3540,6 +4456,21 @@ Some of the diagnostics controlled by this flag are enabled by default. +-------------------------------------------------------------------------------------------------+ +-Wexperimental-isel +------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`-fexperimental-isel support for the '`:placeholder:`A`:diagtext:`' architecture is incomplete`| ++------------------------------------------------------------------------------------------------------------------------------------+ + ++----------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`-fexperimental-isel support is incomplete for this architecture at the current optimization level`| ++----------------------------------------------------------------------------------------------------------------------------------------+ + + -Wexplicit-initialize-call -------------------------- This diagnostic is enabled by default. @@ -3564,13 +4495,34 @@ This diagnostic is enabled by default. +-------------------------------------------------------------------------------------------------------------------------------------+ --Wextended-offsetof -------------------- +-Wexport-unnamed +---------------- +This diagnostic is enabled by default. + **Diagnostic text:** -+--------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`using extended field designator is an extension`| -+--------------------------------------------------------------------------------------+ ++------------------------------------------------------------------------+------------------------------+------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`ISO C++20 does not permit` |nbsp| |+----------------------------+| |nbsp| :diagtext:`declaration to appear in an export block`| +| ||:diagtext:`an empty` || | +| |+----------------------------+| | +| ||:diagtext:`a static\_assert`|| | +| |+----------------------------+| | ++------------------------------------------------------------------------+------------------------------+------------------------------------------------------------+ + ++-------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`ISO C++20 does not permit a declaration that does not introduce any names to be exported`| ++-------------------------------------------------------------------------------------------------------------------------------+ + + +-Wexport-using-directive +------------------------ +This diagnostic is enabled by default. + +**Diagnostic text:** + ++-----------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`ISO C++20 does not permit using directive to be exported`| ++-----------------------------------------------------------------------------------------------+ -Wextern-c-compat @@ -3603,7 +4555,7 @@ This diagnostic is enabled by default. ------- Some of the diagnostics controlled by this flag are enabled by default. -Also controls `-Wignored-qualifiers`_, `-Winitializer-overrides`_, `-Wmissing-field-initializers`_, `-Wmissing-method-return-type`_, `-Wnull-pointer-arithmetic`_, `-Wsemicolon-before-method-body`_, `-Wsign-compare`_, `-Wunused-parameter`_. +Also controls `-Wdeprecated-copy`_, `-Wempty-init-stmt`_, `-Wignored-qualifiers`_, `-Winitializer-overrides`_, `-Wmissing-field-initializers`_, `-Wmissing-method-return-type`_, `-Wnull-pointer-arithmetic`_, `-Wsemicolon-before-method-body`_, `-Wsign-compare`_, `-Wunused-parameter`_. **Diagnostic text:** @@ -3625,7 +4577,7 @@ This diagnostic is enabled by default. -Wextra-semi ------------ -Also controls `-Wc++11-extra-semi`_. +Also controls `-Wc++11-extra-semi`_, `-Wc++98-compat-extra-semi`_. **Diagnostic text:** @@ -3648,6 +4600,17 @@ Also controls `-Wc++11-extra-semi`_. +---------------------------------------------------------------------------------+ +-Wextra-semi-stmt +----------------- +Also controls `-Wempty-init-stmt`_. + +**Diagnostic text:** + ++-------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`empty expression statement has no effect; remove unnecessary ';' to silence this warning`| ++-------------------------------------------------------------------------------------------------------------------------------+ + + -Wextra-tokens -------------- This diagnostic is enabled by default. @@ -3674,6 +4637,30 @@ This diagnostic is enabled by default. +------------------------------------------------------------------------------+ +-Wfinal-dtor-non-final-class +---------------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++---------------------------------------------------------------------+--------------------+--------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`class with destructor marked '`|+------------------+|:diagtext:`' cannot be inherited from`| +| ||:diagtext:`final` || | +| |+------------------+| | +| ||:diagtext:`sealed`|| | +| |+------------------+| | ++---------------------------------------------------------------------+--------------------+--------------------------------------+ + + +-Wfixed-enum-extension +---------------------- +**Diagnostic text:** + ++-----------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`enumeration types with a fixed underlying type are a Clang extension`| ++-----------------------------------------------------------------------------------------------------------+ + + -Wflag-enum ----------- This diagnostic is enabled by default. @@ -3722,9 +4709,13 @@ Also controls `-Wfloat-overflow-conversion`_, `-Wfloat-zero-conversion`_. --------------------------- **Diagnostic text:** -+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`implicit conversion of out of range value from` |nbsp| :placeholder:`A` |nbsp| :diagtext:`to` |nbsp| :placeholder:`B` |nbsp| :diagtext:`changes value from` |nbsp| :placeholder:`C` |nbsp| :diagtext:`to` |nbsp| :placeholder:`D`| -+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ ++-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`implicit conversion from` |nbsp| :placeholder:`A` |nbsp| :diagtext:`to` |nbsp| :placeholder:`B` |nbsp| :diagtext:`changes value from` |nbsp| :placeholder:`C` |nbsp| :diagtext:`to` |nbsp| :placeholder:`D`| ++-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + ++-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`implicit conversion of out of range value from` |nbsp| :placeholder:`A` |nbsp| :diagtext:`to` |nbsp| :placeholder:`B` |nbsp| :diagtext:`is undefined`| ++-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -Wfloat-zero-conversion @@ -3791,6 +4782,10 @@ Also controls `-Wformat-extra-args`_, `-Wformat-invalid-specifier`_, `-Wformat-s | |+--------------------------------------------+| | +---------------------------+----------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------+ ++----------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`using '`:placeholder:`A`:diagtext:`' format specifier, but argument has boolean value`| ++----------------------------------------------------------------------------------------------------------------------------+ + +------------------------------------------------------------------------------------------------------------------------------------+-----------------------------+------------------------+ |:warning:`warning:` |nbsp| :diagtext:`format specifies type` |nbsp| :placeholder:`A` |nbsp| :diagtext:`but the argument has` |nbsp| |+---------------------------+| |nbsp| :placeholder:`B`| | ||:diagtext:`type` || | @@ -3960,6 +4955,14 @@ This diagnostic is enabled by default. ----------------- **Diagnostic text:** ++---------------------------+----------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| |+--------------------------------------------+| |nbsp| :diagtext:`'`:placeholder:`A`:diagtext:`' should not be used as format arguments; add an explicit cast to` |nbsp| :placeholder:`B` |nbsp| :diagtext:`instead`| +| ||:diagtext:`values of type` || | +| |+--------------------------------------------+| | +| ||:diagtext:`enum values with underlying type`|| | +| |+--------------------------------------------+| | ++---------------------------+----------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + +------------------------------------------------------------------------------------------------------------------------------------+-----------------------------+------------------------+ |:warning:`warning:` |nbsp| :diagtext:`format specifies type` |nbsp| :placeholder:`A` |nbsp| :diagtext:`but the argument has` |nbsp| |+---------------------------+| |nbsp| :placeholder:`B`| | ||:diagtext:`type` || | @@ -3980,6 +4983,19 @@ This diagnostic is enabled by default. +---------------------------------------------------------------------------------------------------+ +-Wformat-type-confusion +----------------------- +**Diagnostic text:** + ++------------------------------------------------------------------------------------------------------------------------------------+-----------------------------+------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`format specifies type` |nbsp| :placeholder:`A` |nbsp| :diagtext:`but the argument has` |nbsp| |+---------------------------+| |nbsp| :placeholder:`B`| +| ||:diagtext:`type` || | +| |+---------------------------+| | +| ||:diagtext:`underlying type`|| | +| |+---------------------------+| | ++------------------------------------------------------------------------------------------------------------------------------------+-----------------------------+------------------------+ + + -Wformat-y2k ------------ This diagnostic flag exists for GCC compatibility, and has no effect in Clang. @@ -4002,6 +5018,21 @@ Some of the diagnostics controlled by this flag are enabled by default. Controls `-Wformat-nonliteral`_, `-Wformat-security`_, `-Wformat-y2k`_. +-Wfortify-source +---------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`'`:placeholder:`A`:diagtext:`' will always overflow; destination buffer has size` |nbsp| :placeholder:`B`:diagtext:`, but size argument is` |nbsp| :placeholder:`C`| ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`'`:placeholder:`A`:diagtext:`' size argument is too large; destination buffer has size` |nbsp| :placeholder:`B`:diagtext:`, but size argument is` |nbsp| :placeholder:`C`| ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + + -Wfour-char-constants --------------------- **Diagnostic text:** @@ -4024,6 +5055,17 @@ The text of this diagnostic is not controlled by Clang. +--------------------------------------------------------------------------------------------------------------------------------------+ +-Wframework-include-private-from-public +--------------------------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++-------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`public framework header includes private framework header '`:placeholder:`A`:diagtext:`'`| ++-------------------------------------------------------------------------------------------------------------------------------+ + + -Wfunction-def-in-objc-container -------------------------------- This diagnostic is enabled by default. @@ -4035,6 +5077,21 @@ This diagnostic is enabled by default. +--------------------------------------------------------------------------------------------------------+ +-Wfunction-multiversion +----------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++-------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`body of cpu\_dispatch function will be ignored`| ++-------------------------------------------------------------------------------------+ + ++---------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`CPU list contains duplicate entries; attribute ignored`| ++---------------------------------------------------------------------------------------------+ + + -Wfuture-compat --------------- This diagnostic flag exists for GCC compatibility, and has no effect in Clang. @@ -4073,6 +5130,14 @@ Some of the diagnostics controlled by this flag are enabled by default. |:warning:`warning:` |nbsp| :diagtext:`GCC does not allow an attribute in this position on a function declaration`| +-----------------------------------------------------------------------------------------------------------------+ ++------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`GCC does not allow the` |nbsp| :placeholder:`A` |nbsp| :diagtext:`attribute to be written on a type`| ++------------------------------------------------------------------------------------------------------------------------------------------+ + ++-------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`GCC does not allow variable declarations in for loop initializers before C99`| ++-------------------------------------------------------------------------------------------------------------------+ + +----------------------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`'`:placeholder:`A`:diagtext:`' is bound to current loop, GCC binds it to the enclosing loop`| +----------------------------------------------------------------------------------------------------------------------------------+ @@ -4303,6 +5368,17 @@ Some of the diagnostics controlled by this flag are enabled by default. +-----------------------------------------------------------------------------+ +-Wgnu-inline-cpp-without-extern +------------------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`'gnu\_inline' attribute without 'extern' in C++ treated as externally available, this changed in Clang 10`| ++------------------------------------------------------------------------------------------------------------------------------------------------+ + + -Wgnu-label-as-value -------------------- **Diagnostic text:** @@ -4418,6 +5494,17 @@ This diagnostic is enabled by default. +--------------------------------------------------------------------------------------------+ +-Whip-only +---------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++-------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`'`:placeholder:`A`:diagtext:`' is ignored since it is only supported for HIP`| ++-------------------------------------------------------------------------------------------------------------------+ + + -Widiomatic-parentheses ----------------------- **Diagnostic text:** @@ -4433,6 +5520,10 @@ This diagnostic is enabled by default. **Diagnostic text:** ++--------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`'trivial\_abi' cannot be applied to` |nbsp| :placeholder:`A`| ++--------------------------------------------------------------------------------------------------+ + +---------------------------+-------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| |+-----------------+| |nbsp| :diagtext:`will always resolve to` |nbsp| :placeholder:`A` |nbsp| :diagtext:`even if weak definition of` |nbsp| :placeholder:`B` |nbsp| :diagtext:`is overridden`| | ||:diagtext:`alias`|| | @@ -4461,6 +5552,10 @@ This diagnostic is enabled by default. |:warning:`warning:` |nbsp| :diagtext:`attribute` |nbsp| :placeholder:`A` |nbsp| :diagtext:`after definition is ignored`| +-----------------------------------------------------------------------------------------------------------------------+ ++---------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`'dllexport' attribute ignored on explicit instantiation definition`| ++---------------------------------------------------------------------------------------------------------+ + +--------------------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`attribute can only be applied to instance variables or properties`| +--------------------------------------------------------------------------------------------------------------------------------+ @@ -4557,124 +5652,64 @@ This diagnostic is enabled by default. |:warning:`warning:` |nbsp| :diagtext:`\_\_weak attribute cannot be specified on an automatic variable when ARC is not enabled`| +------------------------------------------------------------------------------------------------------------------------------+ -+------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`attribute only applies to` |nbsp| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`functions` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`unions` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`variables and functions` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`functions and global variables` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`functions, variables, and Objective-C interfaces` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`functions and methods` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`parameters` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`functions, methods and blocks` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`functions, methods, and classes` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`functions, methods, and parameters` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`functions, methods, and global variables` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`classes` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`enums` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`variables` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`methods` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`fields and global variables` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`structs` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`parameters and typedefs` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`variables and typedefs` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`thread-local variables` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`variables and fields` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`variables, data members and tag types` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`types and namespaces` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`Objective-C interfaces` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`methods and properties` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`functions, methods, and properties` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`struct or union` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`struct, union or class` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`types` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`Objective-C instance methods` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`init methods of interface or class extension declarations` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`variables, functions and classes` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`functions, variables, classes, and Objective-C interfaces` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`Objective-C protocols` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`variables with static or thread storage duration` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`functions, methods, properties, and global variables` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`structs, unions, and typedefs` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`structs and typedefs` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`interface or protocol declarations` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`kernel functions` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`non-K&R-style functions` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`variables, enums, fields and typedefs` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`functions, methods, enums, and classes` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`structs, classes, variables, functions, and inline namespaces` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`variables, functions, methods, types, enumerations, enumerators, labels, and non-static data members`|| -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`classes and enumerations` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`named declarations` || -| |+----------------------------------------------------------------------------------------------------------------+| -+------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------+ ++------------------------------------------------------------------------------------------------+---------------------------------------------------+ +|:warning:`warning:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`attribute only applies to` |nbsp| |+-------------------------------------------------+| +| ||:diagtext:`functions` || +| |+-------------------------------------------------+| +| ||:diagtext:`unions` || +| |+-------------------------------------------------+| +| ||:diagtext:`variables and functions` || +| |+-------------------------------------------------+| +| ||:diagtext:`functions and methods` || +| |+-------------------------------------------------+| +| ||:diagtext:`functions, methods and blocks` || +| |+-------------------------------------------------+| +| ||:diagtext:`functions, methods, and parameters` || +| |+-------------------------------------------------+| +| ||:diagtext:`variables` || +| |+-------------------------------------------------+| +| ||:diagtext:`variables and fields` || +| |+-------------------------------------------------+| +| ||:diagtext:`variables, data members and tag types`|| +| |+-------------------------------------------------+| +| ||:diagtext:`types and namespaces` || +| |+-------------------------------------------------+| +| ||:diagtext:`variables, functions and classes` || +| |+-------------------------------------------------+| +| ||:diagtext:`kernel functions` || +| |+-------------------------------------------------+| +| ||:diagtext:`non-K&R-style functions` || +| |+-------------------------------------------------+| ++------------------------------------------------------------------------------------------------+---------------------------------------------------+ + ++----------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`attribute only applies to` |nbsp| :placeholder:`B`| ++----------------------------------------------------------------------------------------------------------------+ +--------------------------------------------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`attribute` |nbsp| :placeholder:`A` |nbsp| :diagtext:`ignored, because it cannot be applied to omitted return type`| +--------------------------------------------------------------------------------------------------------------------------------------------------------+ -+----------------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`calling convention` |nbsp| :placeholder:`A` |nbsp| :diagtext:`ignored for this target`| -+----------------------------------------------------------------------------------------------------------------------------+ - -+-------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`calling convention ignored on constructor/destructor`| -+-------------------------------------------------------------------------------------------------------------------+ - -+--------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`calling convention ignored on variadic function`| -+--------------------------------------------------------------------------------------------------------------+ ++----------------------------------------------------------------------------------------------------------+---------------------------------------+ +|:warning:`warning:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`calling convention is not supported` |nbsp| |+-------------------------------------+| +| ||:diagtext:`for this target` || +| |+-------------------------------------+| +| ||:diagtext:`on variadic function` || +| |+-------------------------------------+| +| ||:diagtext:`on constructor/destructor`|| +| |+-------------------------------------+| +| ||:diagtext:`on builtin function` || +| |+-------------------------------------+| ++----------------------------------------------------------------------------------------------------------+---------------------------------------+ +-------------------------------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`attribute` |nbsp| :placeholder:`A` |nbsp| :diagtext:`ignored, because it cannot be applied to a type`| +-------------------------------------------------------------------------------------------------------------------------------------------+ ++--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`ignoring \_\_declspec(allocator) because the function return type` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is not a pointer or reference type`| ++--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + +------------------------------------------------------------------------------------------------------------------------+-----------------------+----------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`attribute` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is ignored, place it after "`|+---------------------+|:diagtext:`" to apply attribute to type declaration`| | ||:diagtext:`class` || | @@ -4721,35 +5756,63 @@ This diagnostic is enabled by default. | |+----------------------------------+| +---------------------------------------------------------------------------+------------------------------------+ ++------------------------------------------------------------------------------------------------------------------+-----------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`'objc\_externally\_retained' can only be applied to local variables` |nbsp| |+---------------------------------+| +| ||:diagtext:`of retainable type` || +| |+---------------------------------+| +| ||:diagtext:`with strong ownership`|| +| |+---------------------------------+| ++------------------------------------------------------------------------------------------------------------------+-----------------------------------+ + +--------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`'internal\_linkage' attribute on a non-static local variable is ignored`| +--------------------------------------------------------------------------------------------------------------+ ++---------------------------+--------------------+-------------------------------------------------------------------------------------+----------------------------------+ +|:warning:`warning:` |nbsp| |+------------------+| |nbsp| :diagtext:`'interrupt' attribute only applies to functions that have` |nbsp| |+--------------------------------+| +| ||:diagtext:`MIPS` || ||:diagtext:`no parameters` || +| |+------------------+| |+--------------------------------+| +| ||:diagtext:`MSP430`|| ||:diagtext:`a 'void' return type`|| +| |+------------------+| |+--------------------------------+| +| ||:diagtext:`RISC-V`|| | | +| |+------------------+| | | ++---------------------------+--------------------+-------------------------------------------------------------------------------------+----------------------------------+ + +--------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`qualifiers after comma in declarator list are ignored`| +--------------------------------------------------------------------------------------------+ -+-------------------------------------------------------------------------------------------------------------+----------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`MIPS 'interrupt' attribute only applies to functions that have` |nbsp| |+--------------------------------+| -| ||:diagtext:`no parameters` || -| |+--------------------------------+| -| ||:diagtext:`a 'void' return type`|| -| |+--------------------------------+| -+-------------------------------------------------------------------------------------------------------------+----------------------------------+ ++------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`'mig\_server\_routine' attribute only applies to routines that return a kern\_return\_t`| ++------------------------------------------------------------------------------------------------------------------------------+ +---------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`unknown attribute '`:placeholder:`A`:diagtext:`'`| +---------------------------------------------------------------------------------------+ -+------------------------------------------------------------------------------------------------+-----------------------------------+------------------------------+ -|:warning:`warning:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`attribute only applies to` |nbsp| |+---------------------------------+| |nbsp| :diagtext:`parameters`| -| ||:diagtext:`Objective-C object` || | -| |+---------------------------------+| | -| ||:diagtext:`pointer` || | -| |+---------------------------------+| | -| ||:diagtext:`pointer-to-CF-pointer`|| | -| |+---------------------------------+| | -+------------------------------------------------------------------------------------------------+-----------------------------------+------------------------------+ ++-------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`'nocf\_check' attribute ignored; use -fcf-protection to enable the attribute`| ++-------------------------------------------------------------------------------------------------------------------+ + ++---------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`'noderef' can only be used on an array or pointer type`| ++---------------------------------------------------------------------------------------------+ + ++--------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`'nothrow' attribute conflicts with exception specification; attribute ignored`| ++--------------------------------------------------------------------------------------------------------------------+ + ++------------------------------------------------------------------------------------------------+---------------------------------------------------+------------------------------+ +|:warning:`warning:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`attribute only applies to` |nbsp| |+-------------------------------------------------+| |nbsp| :diagtext:`parameters`| +| ||:diagtext:`Objective-C object` || | +| |+-------------------------------------------------+| | +| ||:diagtext:`pointer` || | +| |+-------------------------------------------------+| | +| ||:diagtext:`pointer-to-CF-pointer` || | +| |+-------------------------------------------------+| | +| ||:diagtext:`pointer/reference-to-OSObject-pointer`|| | +| |+-------------------------------------------------+| | ++------------------------------------------------------------------------------------------------+---------------------------------------------------+------------------------------+ +------------------------------------------------------------------------------------------------+------------------------+---------------------------------------+--------------------------------------+ |:warning:`warning:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`attribute only applies to` |nbsp| |+----------------------+| |nbsp| :diagtext:`that return` |nbsp| |+------------------------------------+| @@ -4761,10 +5824,42 @@ This diagnostic is enabled by default. | |+----------------------+| |+------------------------------------+| +------------------------------------------------------------------------------------------------+------------------------+---------------------------------------+--------------------------------------+ ++----------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`attribute isn't implemented by this Objective-C runtime`| ++----------------------------------------------------------------------------------------------------------------------+ + ++--------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`direct attribute on property` |nbsp| :placeholder:`A` |nbsp| :diagtext:`ignored (not implemented by this Objective-C runtime)`| ++--------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + +--------------------------------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`attribute is deprecated and ignored in OpenCL version` |nbsp| :placeholder:`B`| +--------------------------------------------------------------------------------------------------------------------------------------------+ ++---------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`'require\_constant\_initialization' attribute added after initialization of variable`| ++---------------------------------------------------------------------------------------------------------------------------+ + ++----------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`repeated RISC-V 'interrupt' attribute`| ++----------------------------------------------------------------------------+ + ++----------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`template parameter of a function template with the 'sycl\_kernel' attribute cannot be a non-type template parameter`| ++----------------------------------------------------------------------------------------------------------------------------------------------------------+ + ++-------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`function template with 'sycl\_kernel' attribute must have a single parameter`| ++-------------------------------------------------------------------------------------------------------------------+ + ++-----------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`'sycl\_kernel' attribute only applies to a function template with at least two template parameters`| ++-----------------------------------------------------------------------------------------------------------------------------------------+ + ++---------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`function template with 'sycl\_kernel' attribute must have a 'void' return type`| ++---------------------------------------------------------------------------------------------------------------------+ + +---------------------------+-----------------------+---------------------------------------------------------------------------------------------------------------------------------------------+-----------------------+-------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| |+---------------------+| |nbsp| :diagtext:`of field` |nbsp| :placeholder:`B` |nbsp| :diagtext:`(`:placeholder:`C` |nbsp| :diagtext:`bits) does not match the` |nbsp| |+---------------------+| |nbsp| :diagtext:`of the first field in transparent union; transparent\_union attribute ignored`| | ||:diagtext:`alignment`|| ||:diagtext:`alignment`|| | @@ -4803,13 +5898,17 @@ This diagnostic is enabled by default. |:warning:`warning:` |nbsp| :diagtext:`\_\_declspec attribute` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is not supported`| +-------------------------------------------------------------------------------------------------------------------------+ -+-------------------------------------------------------+-------------------------+----------------------------------+---------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`ignoring` |nbsp| |+-----------------------+|+--------------------------------+| |nbsp| :diagtext:`'`:placeholder:`C`:diagtext:`' in the target attribute string`| -| ||:diagtext:`unsupported`||| || | -| |+-----------------------+|+--------------------------------+| | -| ||:diagtext:`duplicate` ||| |nbsp| :diagtext:`architecture`|| | -| |+-----------------------+|+--------------------------------+| | -+-------------------------------------------------------+-------------------------+----------------------------------+---------------------------------------------------------------------------------+ ++---------------------------+-------------------------+----------------------------------+---------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| |+-----------------------+|+--------------------------------+| |nbsp| :diagtext:`'`:placeholder:`C`:diagtext:`' in the 'target' attribute string; 'target' attribute ignored`| +| ||:diagtext:`unsupported`||| || | +| |+-----------------------+|+--------------------------------+| | +| ||:diagtext:`duplicate` ||| |nbsp| :diagtext:`architecture`|| | +| |+-----------------------+|+--------------------------------+| | ++---------------------------+-------------------------+----------------------------------+---------------------------------------------------------------------------------------------------------------+ + ++----------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`'\_\_clang\_\_' is a predefined macro name, not an attribute scope specifier; did you mean '\_Clang' instead?`| ++----------------------------------------------------------------------------------------------------------------------------------------------------+ -Wignored-optimization-argument @@ -4842,11 +5941,22 @@ This diagnostic is enabled by default. +------------------------------------------------------------------------------------------+------------------------------------------------------------------------------+ +-Wignored-pragma-optimize +------------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++--------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`'#pragma optimize' is not supported`| ++--------------------------------------------------------------------------+ + + -Wignored-pragmas ----------------- This diagnostic is enabled by default. -Also controls `-Wignored-pragma-intrinsic`_. +Also controls `-Wignored-pragma-intrinsic`_, `-Wignored-pragma-optimize`_. **Diagnostic text:** @@ -4882,6 +5992,10 @@ Also controls `-Wignored-pragma-intrinsic`_. |:warning:`warning:` |nbsp| :diagtext:`unexpected debug command '`:placeholder:`A`:diagtext:`'`| +----------------------------------------------------------------------------------------------+ ++------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`unknown module '`:placeholder:`A`:diagtext:`'`| ++------------------------------------------------------------------------------------+ + +------------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`expected action or ')' in '#pragma` |nbsp| :placeholder:`A`:diagtext:`' - ignored`| +------------------------------------------------------------------------------------------------------------------------+ @@ -4894,6 +6008,10 @@ Also controls `-Wignored-pragma-intrinsic`_. |:warning:`warning:` |nbsp| :diagtext:`missing ':' or ')' after` |nbsp| :placeholder:`A` |nbsp| :diagtext:`- ignoring`| +---------------------------------------------------------------------------------------------------------------------+ ++----------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`expected ',' in '#pragma` |nbsp| :placeholder:`A`:diagtext:`'`| ++----------------------------------------------------------------------------------------------------+ + +---------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`expected identifier in '#pragma` |nbsp| :placeholder:`A`:diagtext:`' - ignored`| +---------------------------------------------------------------------------------------------------------------------+ @@ -4942,6 +6060,10 @@ Also controls `-Wignored-pragma-intrinsic`_. |:warning:`warning:` |nbsp| :diagtext:`expected push, pop or a string literal for the section name in '#pragma` |nbsp| :placeholder:`A`:diagtext:`' - ignored`| +-------------------------------------------------------------------------------------------------------------------------------------------------------------+ ++--------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`expected string literal in '#pragma` |nbsp| :placeholder:`A`:diagtext:`' - ignoring`| ++--------------------------------------------------------------------------------------------------------------------------+ + +---------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`extra tokens at end of '#pragma` |nbsp| :placeholder:`A`:diagtext:`' - ignored`| +---------------------------------------------------------------------------------------------------------------------+ @@ -4958,10 +6080,30 @@ Also controls `-Wignored-pragma-intrinsic`_. |:warning:`warning:` |nbsp| :diagtext:`unknown action for '#pragma` |nbsp| :placeholder:`A`:diagtext:`' - ignored`| +-----------------------------------------------------------------------------------------------------------------+ ++------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`unexpected argument '`:placeholder:`A`:diagtext:`' to '#pragma` |nbsp| :placeholder:`B`:diagtext:`'`|+------------------------------------------------+| +| || || +| |+------------------------------------------------+| +| ||+----------------------------------------------+|| +| |||:diagtext:`; expected` |nbsp| :placeholder:`D`||| +| ||+----------------------------------------------+|| +| |+------------------------------------------------+| ++------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------+ + +------------------------------------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`unknown action '`:placeholder:`B`:diagtext:`' for '#pragma` |nbsp| :placeholder:`A`:diagtext:`' - ignored`| +------------------------------------------------------------------------------------------------------------------------------------------------+ ++--------------------------------------------------------------------------------------------------------+--------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`missing argument to '#pragma` |nbsp| :placeholder:`A`:diagtext:`'`|+------------------------------------------------+| +| || || +| |+------------------------------------------------+| +| ||+----------------------------------------------+|| +| |||:diagtext:`; expected` |nbsp| :placeholder:`C`||| +| ||+----------------------------------------------+|| +| |+------------------------------------------------+| ++--------------------------------------------------------------------------------------------------------+--------------------------------------------------+ + +----------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`incorrect use of '#pragma ms\_struct on\|off' - ignored`| +----------------------------------------------------------------------------------------------+ @@ -5039,13 +6181,13 @@ Some of the diagnostics controlled by this flag are enabled by default. |:warning:`warning:` |nbsp| :diagtext:`'`:placeholder:`A`:diagtext:`' qualifier on omitted return type` |nbsp| :placeholder:`B` |nbsp| :diagtext:`has no effect`| +---------------------------------------------------------------------------------------------------------------------------------------------------------------+ -+------------------------------------------------------------------------------------+---------------+------------------------------------------+-------------------+-----------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`'`:placeholder:`A`:diagtext:`' type qualifier`|+-------------+| |nbsp| :diagtext:`on return type` |nbsp| |+-----------------+| |nbsp| :diagtext:`no effect`| -| || || ||:diagtext:`:has` || | -| |+-------------+| |+-----------------+| | -| ||:diagtext:`s`|| ||:diagtext:`:have`|| | -| |+-------------+| |+-----------------+| | -+------------------------------------------------------------------------------------+---------------+------------------------------------------+-------------------+-----------------------------+ ++------------------------------------------------------------------------------------+---------------+------------------------------------------+------------------+-----------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`'`:placeholder:`A`:diagtext:`' type qualifier`|+-------------+| |nbsp| :diagtext:`on return type` |nbsp| |+----------------+| |nbsp| :diagtext:`no effect`| +| || || ||:diagtext:`has` || | +| |+-------------+| |+----------------+| | +| ||:diagtext:`s`|| ||:diagtext:`have`|| | +| |+-------------+| |+----------------+| | ++------------------------------------------------------------------------------------+---------------+------------------------------------------+------------------+-----------------------------+ +---------------------------------------------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`'`:placeholder:`A`:diagtext:`' qualifier on function type` |nbsp| :placeholder:`B` |nbsp| :diagtext:`has no effect`| @@ -5126,19 +6268,43 @@ Also controls `-Wimplicit-fallthrough-per-function`_. +------------------------------------------------------------------------------------------------------------------+ +-Wimplicit-fixed-point-conversion +--------------------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`implicit conversion from` |nbsp| :placeholder:`A` |nbsp| :diagtext:`cannot fit within the range of values for` |nbsp| :placeholder:`B`| ++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + + +-Wimplicit-float-conversion +--------------------------- +Some of the diagnostics controlled by this flag are enabled by default. + +Also controls `-Wimplicit-int-float-conversion`_, `-Wobjc-signed-char-bool-implicit-float-conversion`_. + +**Diagnostic text:** + ++----------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`implicit conversion loses floating-point precision:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`to` |nbsp| :placeholder:`B`| ++----------------------------------------------------------------------------------------------------------------------------------------------------------------+ + ++--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`implicit conversion when assigning computation result loses floating-point precision:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`to` |nbsp| :placeholder:`B`| ++--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + + -Wimplicit-function-declaration ------------------------------- Some of the diagnostics controlled by this flag are enabled by default. **Diagnostic text:** -+----------------------------------------------------------------------------------------------------------------------------------------+--------------------+ -|:warning:`warning:` |nbsp| :diagtext:`implicit declaration of function` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is invalid in` |nbsp| |+------------------+| -| ||:diagtext:`C99` || -| |+------------------+| -| ||:diagtext:`OpenCL`|| -| |+------------------+| -+----------------------------------------------------------------------------------------------------------------------------------------+--------------------+ ++------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`implicit declaration of function` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is invalid in C99`| ++------------------------------------------------------------------------------------------------------------------------------------+ +---------------------------------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`implicitly declaring library function '`:placeholder:`A`:diagtext:`' with type` |nbsp| :placeholder:`B`| @@ -5164,6 +6330,36 @@ This diagnostic is enabled by default. +--------------------------------------------------------------------------------+ +-Wimplicit-int-conversion +------------------------- +Also controls `-Wobjc-signed-char-bool-implicit-int-conversion`_. + +**Diagnostic text:** + ++---------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`higher order bits are zeroes after implicit conversion`| ++---------------------------------------------------------------------------------------------+ + ++---------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`implicit conversion loses integer precision:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`to` |nbsp| :placeholder:`B`| ++---------------------------------------------------------------------------------------------------------------------------------------------------------+ + + +-Wimplicit-int-float-conversion +------------------------------- +Some of the diagnostics controlled by this flag are enabled by default. + +**Diagnostic text:** + ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`implicit conversion from` |nbsp| :placeholder:`A` |nbsp| :diagtext:`to` |nbsp| :placeholder:`B` |nbsp| :diagtext:`may lose precision`| ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + ++-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`implicit conversion from` |nbsp| :placeholder:`C` |nbsp| :diagtext:`to` |nbsp| :placeholder:`D` |nbsp| :diagtext:`changes value from` |nbsp| :placeholder:`A` |nbsp| :diagtext:`to` |nbsp| :placeholder:`B`| ++-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + + -Wimplicit-retain-self ---------------------- **Diagnostic text:** @@ -5214,9 +6410,9 @@ This diagnostic is enabled by default. **Diagnostic text:** -+------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`#include\_next with absolute path`| -+------------------------------------------------------------------------+ ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`#include\_next in file found relative to primary source file or found by absolute path; will search from start of include path`| ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -Winclude-next-outside-header @@ -5225,9 +6421,9 @@ This diagnostic is enabled by default. **Diagnostic text:** -+----------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`#include\_next in primary source file`| -+----------------------------------------------------------------------------+ ++--------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`#include\_next in primary source file; will search from start of include path`| ++--------------------------------------------------------------------------------------------------------------------+ -Wincompatible-exception-spec @@ -5295,6 +6491,10 @@ This diagnostic is an error by default, but the flag ``-Wno-incompatible-ms-stru |:error:`error:` |nbsp| :diagtext:`ms\_struct may not produce Microsoft-compatible layouts for classes with base classes or virtual functions`| +---------------------------------------------------------------------------------------------------------------------------------------------+ ++------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:error:`error:` |nbsp| :diagtext:`ms\_struct may not produce Microsoft-compatible layouts with fundamental data types with sizes that aren't a power of two`| ++------------------------------------------------------------------------------------------------------------------------------------------------------------+ + -Wincompatible-pointer-types ---------------------------- @@ -5365,6 +6565,14 @@ This diagnostic is enabled by default. | |+--------------------------------------------------------------+| | +---------------------------+----------------------------------------------------------------+---------------------------------------+ ++---------------------------+-------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| |+-----------------------------+| |nbsp| :diagtext:`from` |nbsp| :placeholder:`B` |nbsp| :diagtext:`to` |nbsp| :placeholder:`C` |nbsp| :diagtext:`changes address space of nested pointers`| +| ||:diagtext:`reinterpret\_cast`|| | +| |+-----------------------------+| | +| ||:diagtext:`C-style cast` || | +| |+-----------------------------+| | ++---------------------------+-------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------+ + -Wincompatible-property-type ---------------------------- @@ -5388,6 +6596,17 @@ This diagnostic is enabled by default. +------------------------------------------------------------------------------------------------------------------------------------+ +-Wincomplete-framework-module-declaration +----------------------------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`skipping '`:placeholder:`A`:diagtext:`' because module declaration of '`:placeholder:`B`:diagtext:`' lacks the 'framework' qualifier`| ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + + -Wincomplete-implementation --------------------------- This diagnostic is enabled by default. @@ -5406,6 +6625,17 @@ Some of the diagnostics controlled by this flag are enabled by default. Controls `-Wincomplete-umbrella`_, `-Wnon-modular-include-in-module`_. +-Wincomplete-setjmp-declaration +------------------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`declaration of built-in function '`:placeholder:`A`:diagtext:`' requires the declaration of the 'jmp\_buf' type, commonly provided in the header .`| ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + + -Wincomplete-umbrella --------------------- This diagnostic is enabled by default. @@ -5492,13 +6722,21 @@ This diagnostic is enabled by default. **Diagnostic text:** -+---------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`initializer overrides prior initialization of this subobject`| -+---------------------------------------------------------------------------------------------------+ ++----------------------------------------------------------+-------------------------------+------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`initializer` |nbsp| |+-----------------------------+|:diagtext:`overrides prior initialization of this subobject`| +| ||:diagtext:`partially` |nbsp| || | +| |+-----------------------------+| | +| || || | +| |+-----------------------------+| | ++----------------------------------------------------------+-------------------------------+------------------------------------------------------------+ -+---------------------------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`subobject initialization overrides initialization of other fields within its enclosing subobject`| -+---------------------------------------------------------------------------------------------------------------------------------------+ ++----------------------------------------------------------+-------------------------------+------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`initializer` |nbsp| |+-----------------------------+|:diagtext:`overrides prior initialization of this subobject`| +| ||:diagtext:`partially` |nbsp| || | +| |+-----------------------------+| | +| || || | +| |+-----------------------------+| | ++----------------------------------------------------------+-------------------------------+------------------------------------------------------------+ -Winjected-class-name @@ -5599,6 +6837,19 @@ This diagnostic is enabled by default. Synonym for `-Wint-conversion`_. +-Wint-in-bool-context +--------------------- +**Diagnostic text:** + ++--------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`converting the enum constant to a boolean`| ++--------------------------------------------------------------------------------+ + ++--------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`converting the result of '<<' to a boolean; did you mean '(`:placeholder:`A`:diagtext:`) != 0'?`| ++--------------------------------------------------------------------------------------------------------------------------------------+ + + -Wint-to-pointer-cast --------------------- This diagnostic is enabled by default. @@ -5642,6 +6893,18 @@ Also controls `-Wignored-optimization-argument`_. **Diagnostic text:** ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`the given MCU supports` |nbsp| :placeholder:`A` |nbsp| :diagtext:`hardware multiply, but -mhwmult is set to` |nbsp| :placeholder:`B`:diagtext:`.`| ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`no MCU device specified, but '-mhwmult' is set to 'auto', assuming no hardware multiply. Use -mmcu to specify a MSP430 device, or -mhwmult to set hardware multiply type explicitly.`| ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + ++----------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`the given MCU does not support hardware multiply, but -mhwmult is set to` |nbsp| :placeholder:`A`:diagtext:`.`| ++----------------------------------------------------------------------------------------------------------------------------------------------------+ + +-----------------------------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`the object size sanitizer has no effect at -O0, but is explicitly enabled:` |nbsp| :placeholder:`A`| +-----------------------------------------------------------------------------------------------------------------------------------------+ @@ -5650,6 +6913,10 @@ Also controls `-Wignored-optimization-argument`_. |:warning:`warning:` |nbsp| :diagtext:`optimization level '`:placeholder:`A`:diagtext:`' is not supported; using '`:placeholder:`B`:placeholder:`C`:diagtext:`' instead`| +-----------------------------------------------------------------------------------------------------------------------------------------------------------------------+ ++--------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`ignoring extension '`:placeholder:`A`:diagtext:`' because the '`:placeholder:`B`:diagtext:`' architecture does not support it`| ++--------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + -Winvalid-constexpr ------------------- @@ -5707,6 +6974,17 @@ This diagnostic is an error by default, but the flag ``-Wno-invalid-ios-deployme +------------------------------------------------------------------------------------------------------------------------------------------------------------+ +-Winvalid-no-builtin-names +-------------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++-----------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`'`:placeholder:`A`:diagtext:`' is not a valid builtin name for` |nbsp| :placeholder:`B`| ++-----------------------------------------------------------------------------------------------------------------------------+ + + -Winvalid-noreturn ------------------ This diagnostic is enabled by default. @@ -5900,6 +7178,10 @@ This diagnostic is enabled by default. |:warning:`warning:` |nbsp| :diagtext:`implicit conversion from` |nbsp| :placeholder:`A` |nbsp| :diagtext:`to` |nbsp| :placeholder:`B` |nbsp| :diagtext:`changes value from` |nbsp| :placeholder:`C` |nbsp| :diagtext:`to` |nbsp| :placeholder:`D`| +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ ++-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`implicit conversion of out of range value from` |nbsp| :placeholder:`A` |nbsp| :diagtext:`to` |nbsp| :placeholder:`B` |nbsp| :diagtext:`is undefined`| ++-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + -Wliteral-range --------------- @@ -5946,8 +7228,6 @@ This diagnostic is enabled by default. -Wlogical-op-parentheses ------------------------ -This diagnostic is enabled by default. - **Diagnostic text:** +---------------------------------------------------------+ @@ -6065,6 +7345,21 @@ This diagnostic is enabled by default. +----------------------------------------------------------------+---------------------------------------+------------------------------------------------------+ +-Wmemset-transposed-args +------------------------ +This diagnostic is enabled by default. + +**Diagnostic text:** + ++---------------------------+-----------------------------------------------------+---------------------------------------------------------------+ +|:warning:`warning:` |nbsp| |+---------------------------------------------------+|:diagtext:`; did you mean to transpose the last two arguments?`| +| ||:diagtext:`'size' argument to memset is '0'` || | +| |+---------------------------------------------------+| | +| ||:diagtext:`setting buffer to a 'sizeof' expression`|| | +| |+---------------------------------------------------+| | ++---------------------------+-----------------------------------------------------+---------------------------------------------------------------+ + + -Wmemsize-comparison -------------------- This diagnostic is enabled by default. @@ -6093,7 +7388,7 @@ This diagnostic is enabled by default. ----------- Some of the diagnostics controlled by this flag are enabled by default. -Controls `-Winconsistent-dllimport`_, `-Wmicrosoft-anon-tag`_, `-Wmicrosoft-cast`_, `-Wmicrosoft-charize`_, `-Wmicrosoft-comment-paste`_, `-Wmicrosoft-const-init`_, `-Wmicrosoft-cpp-macro`_, `-Wmicrosoft-default-arg-redefinition`_, `-Wmicrosoft-end-of-file`_, `-Wmicrosoft-enum-forward-reference`_, `-Wmicrosoft-enum-value`_, `-Wmicrosoft-exception-spec`_, `-Wmicrosoft-explicit-constructor-call`_, `-Wmicrosoft-extra-qualification`_, `-Wmicrosoft-fixed-enum`_, `-Wmicrosoft-flexible-array`_, `-Wmicrosoft-goto`_, `-Wmicrosoft-include`_, `-Wmicrosoft-mutable-reference`_, `-Wmicrosoft-pure-definition`_, `-Wmicrosoft-redeclare-static`_, `-Wmicrosoft-sealed`_, `-Wmicrosoft-template`_, `-Wmicrosoft-union-member-reference`_, `-Wmicrosoft-unqualified-friend`_, `-Wmicrosoft-using-decl`_, `-Wmicrosoft-void-pseudo-dtor`_. +Controls `-Winconsistent-dllimport`_, `-Wmicrosoft-anon-tag`_, `-Wmicrosoft-cast`_, `-Wmicrosoft-charize`_, `-Wmicrosoft-comment-paste`_, `-Wmicrosoft-const-init`_, `-Wmicrosoft-cpp-macro`_, `-Wmicrosoft-default-arg-redefinition`_, `-Wmicrosoft-drectve-section`_, `-Wmicrosoft-end-of-file`_, `-Wmicrosoft-enum-forward-reference`_, `-Wmicrosoft-enum-value`_, `-Wmicrosoft-exception-spec`_, `-Wmicrosoft-explicit-constructor-call`_, `-Wmicrosoft-extra-qualification`_, `-Wmicrosoft-fixed-enum`_, `-Wmicrosoft-flexible-array`_, `-Wmicrosoft-goto`_, `-Wmicrosoft-include`_, `-Wmicrosoft-mutable-reference`_, `-Wmicrosoft-pure-definition`_, `-Wmicrosoft-redeclare-static`_, `-Wmicrosoft-sealed`_, `-Wmicrosoft-template`_, `-Wmicrosoft-union-member-reference`_, `-Wmicrosoft-unqualified-friend`_, `-Wmicrosoft-using-decl`_, `-Wmicrosoft-void-pseudo-dtor`_. -Wmicrosoft-anon-tag @@ -6187,6 +7482,17 @@ This diagnostic is enabled by default. +-----------------------------------------------------------------------+ +-Wmicrosoft-drectve-section +--------------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++---------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`#pragma` |nbsp| :placeholder:`A`:diagtext:`(".drectve") has undefined behavior, use #pragma comment(linker, ...) instead`| ++---------------------------------------------------------------------------------------------------------------------------------------------------------------+ + + -Wmicrosoft-end-of-file ----------------------- **Diagnostic text:** @@ -6333,6 +7639,17 @@ This diagnostic is enabled by default. +----------------------------------------------------------------------------------------------------------+ +-Wmicrosoft-inaccessible-base +----------------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`accessing inaccessible direct base` |nbsp| :placeholder:`A` |nbsp| :diagtext:`of` |nbsp| :placeholder:`B` |nbsp| :diagtext:`is a Microsoft extension`| ++-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + + -Wmicrosoft-include ------------------- This diagnostic is enabled by default. @@ -6390,6 +7707,8 @@ This diagnostic is enabled by default. -------------------- This diagnostic is enabled by default. +Also controls `-Wmicrosoft-template-shadow`_. + **Diagnostic text:** +------------------------------------------------------------------------------------------------------------------------------------------------------+ @@ -6400,10 +7719,6 @@ This diagnostic is enabled by default. |:warning:`warning:` |nbsp| :diagtext:`use of identifier` |nbsp| :placeholder:`A` |nbsp| :diagtext:`found via unqualified lookup into dependent bases of class templates is a Microsoft extension`| +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -+--------------------------------------------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`explicit specialization of` |nbsp| :placeholder:`A` |nbsp| :diagtext:`within class scope is a Microsoft extension`| -+--------------------------------------------------------------------------------------------------------------------------------------------------------+ - +-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`using the undeclared type` |nbsp| :placeholder:`A` |nbsp| :diagtext:`as a default template argument is a Microsoft extension`| +-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ @@ -6412,37 +7727,52 @@ This diagnostic is enabled by default. |:warning:`warning:` |nbsp| :diagtext:`non-type template argument containing a dereference operation is a Microsoft extension`| +-----------------------------------------------------------------------------------------------------------------------------+ -+---------------------------+---------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| |+-------------------------------------+| |nbsp| :diagtext:`specialization of` |nbsp| :placeholder:`B` |nbsp| :diagtext:`outside namespace enclosing` |nbsp| :placeholder:`C` |nbsp| :diagtext:`is a Microsoft extension`| -| ||:diagtext:`class template` || | -| |+-------------------------------------+| | -| ||:diagtext:`class template partial` || | -| |+-------------------------------------+| | -| ||:diagtext:`variable template` || | -| |+-------------------------------------+| | -| ||:diagtext:`variable template partial`|| | -| |+-------------------------------------+| | -| ||:diagtext:`function template` || | -| |+-------------------------------------+| | -| ||:diagtext:`member function` || | -| |+-------------------------------------+| | -| ||:diagtext:`static data member` || | -| |+-------------------------------------+| | -| ||:diagtext:`member class` || | -| |+-------------------------------------+| | -| ||:diagtext:`member enumeration` || | -| |+-------------------------------------+| | -+---------------------------+---------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ ++---------------------------+---------------------------------------+-----------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------+--------------------------------------------+ +|:warning:`warning:` |nbsp| |+-------------------------------------+| |nbsp| :diagtext:`specialization of` |nbsp| :placeholder:`B` |nbsp| :diagtext:`not in` |nbsp| |+----------------------------------------------------------------------------------------+| |nbsp| :diagtext:`is a Microsoft extension`| +| ||:diagtext:`class template` || ||+---------------------------------------------------------+ || | +| |+-------------------------------------+| |||:diagtext:`a namespace enclosing` |nbsp| :placeholder:`C`| || | +| ||:diagtext:`class template partial` || ||+---------------------------------------------------------+ || | +| |+-------------------------------------+| |+----------------------------------------------------------------------------------------+| | +| ||:diagtext:`variable template` || ||+--------------------------------------------------------------------------------------+|| | +| |+-------------------------------------+| |||:diagtext:`class` |nbsp| :placeholder:`C` |nbsp| :diagtext:`or an enclosing namespace`||| | +| ||:diagtext:`variable template partial`|| ||+--------------------------------------------------------------------------------------+|| | +| |+-------------------------------------+| |+----------------------------------------------------------------------------------------+| | +| ||:diagtext:`function template` || | | | +| |+-------------------------------------+| | | | +| ||:diagtext:`member function` || | | | +| |+-------------------------------------+| | | | +| ||:diagtext:`static data member` || | | | +| |+-------------------------------------+| | | | +| ||:diagtext:`member class` || | | | +| |+-------------------------------------+| | | | +| ||:diagtext:`member enumeration` || | | | +| |+-------------------------------------+| | | | ++---------------------------+---------------------------------------+-----------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------+--------------------------------------------+ +------------------------------------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`template argument for template type parameter must be a type; omitted 'typename' is a Microsoft extension`| +------------------------------------------------------------------------------------------------------------------------------------------------+ ++-------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`'static' can only be specified inside the class definition`| ++-------------------------------------------------------------------------------------------------+ + +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`use of undeclared identifier` |nbsp| :placeholder:`A`:diagtext:`; unqualified lookup into dependent bases of class template` |nbsp| :placeholder:`B` |nbsp| :diagtext:`is a Microsoft extension`| +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +-Wmicrosoft-template-shadow +--------------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++---------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`declaration of` |nbsp| :placeholder:`A` |nbsp| :diagtext:`shadows template parameter`| ++---------------------------------------------------------------------------------------------------------------------------+ + + -Wmicrosoft-union-member-reference ---------------------------------- This diagnostic is enabled by default. @@ -6487,6 +7817,32 @@ This diagnostic is enabled by default. +------------------------------------------------------------------------------------------------+ +-Wmisexpect +----------- +**Diagnostic text:** + ++-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`Potential performance regression from use of \_\_builtin\_expect(): Annotation was correct on` |nbsp| :placeholder:`A` |nbsp| :diagtext:`of profiled executions.`| ++-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + + +-Wmisleading-indentation +------------------------ +**Diagnostic text:** + ++------------------------------------------------------------------------------------------------------+-------------------+-------------+ +|:warning:`warning:` |nbsp| :diagtext:`misleading indentation; statement is not part of the previous '`|+-----------------+|:diagtext:`'`| +| ||:diagtext:`if` || | +| |+-----------------+| | +| ||:diagtext:`else` || | +| |+-----------------+| | +| ||:diagtext:`for` || | +| |+-----------------+| | +| ||:diagtext:`while`|| | +| |+-----------------+| | ++------------------------------------------------------------------------------------------------------+-------------------+-------------+ + + -Wmismatched-new-delete ----------------------- This diagnostic is enabled by default. @@ -6528,25 +7884,25 @@ This diagnostic is enabled by default. ----------------- **Diagnostic text:** -+---------------------------------------------------------------------------------+--------------------------+------------------------------+-----------------------------------------------------------+--------------------------+------------------------------+ -|:warning:`warning:` |nbsp| :placeholder:`C` |nbsp| :diagtext:`defined as` |nbsp| |+------------------------+|+----------------------------+| |nbsp| :diagtext:`here but previously declared as` |nbsp| |+------------------------+|+----------------------------+| -| ||:diagtext:`a struct` ||| || ||:diagtext:`a struct` ||| || -| |+------------------------+|+----------------------------+| |+------------------------+|+----------------------------+| -| ||:diagtext:`an interface`||| |nbsp| :diagtext:`template`|| ||:diagtext:`an interface`||| |nbsp| :diagtext:`template`|| -| |+------------------------+|+----------------------------+| |+------------------------+|+----------------------------+| -| ||:diagtext:`a class` || | ||:diagtext:`a class` || | -| |+------------------------+| | |+------------------------+| | -+---------------------------------------------------------------------------------+--------------------------+------------------------------+-----------------------------------------------------------+--------------------------+------------------------------+ ++---------------------------------------------------------------------------------+--------------------------+------------------------------+-----------------------------------------------------------+--------------------------+------------------------------+----------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :placeholder:`C` |nbsp| :diagtext:`defined as` |nbsp| |+------------------------+|+----------------------------+| |nbsp| :diagtext:`here but previously declared as` |nbsp| |+------------------------+|+----------------------------+|:diagtext:`; this is valid, but may result in linker errors under the Microsoft C++ ABI`| +| ||:diagtext:`a struct` ||| || ||:diagtext:`a struct` ||| || | +| |+------------------------+|+----------------------------+| |+------------------------+|+----------------------------+| | +| ||:diagtext:`an interface`||| |nbsp| :diagtext:`template`|| ||:diagtext:`an interface`||| |nbsp| :diagtext:`template`|| | +| |+------------------------+|+----------------------------+| |+------------------------+|+----------------------------+| | +| ||:diagtext:`a class` || | ||:diagtext:`a class` || | | +| |+------------------------+| | |+------------------------+| | | ++---------------------------------------------------------------------------------+--------------------------+------------------------------+-----------------------------------------------------------+--------------------------+------------------------------+----------------------------------------------------------------------------------------+ -+---------------------------+-----------------------+------------------------------+--------------------------------------------------------------------------------+-----------------------+------------------------------+ -|:warning:`warning:` |nbsp| |+---------------------+|+----------------------------+| |nbsp| :placeholder:`C` |nbsp| :diagtext:`was previously declared as a` |nbsp| |+---------------------+|+----------------------------+| -| ||:diagtext:`struct` ||| || ||:diagtext:`struct` ||| || -| |+---------------------+|+----------------------------+| |+---------------------+|+----------------------------+| -| ||:diagtext:`interface`||| |nbsp| :diagtext:`template`|| ||:diagtext:`interface`||| |nbsp| :diagtext:`template`|| -| |+---------------------+|+----------------------------+| |+---------------------+|+----------------------------+| -| ||:diagtext:`class` || | ||:diagtext:`class` || | -| |+---------------------+| | |+---------------------+| | -+---------------------------+-----------------------+------------------------------+--------------------------------------------------------------------------------+-----------------------+------------------------------+ ++---------------------------+-----------------------+------------------------------+--------------------------------------------------------------------------------+-----------------------+------------------------------+----------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| |+---------------------+|+----------------------------+| |nbsp| :placeholder:`C` |nbsp| :diagtext:`was previously declared as a` |nbsp| |+---------------------+|+----------------------------+|:diagtext:`; this is valid, but may result in linker errors under the Microsoft C++ ABI`| +| ||:diagtext:`struct` ||| || ||:diagtext:`struct` ||| || | +| |+---------------------+|+----------------------------+| |+---------------------+|+----------------------------+| | +| ||:diagtext:`interface`||| |nbsp| :diagtext:`template`|| ||:diagtext:`interface`||| |nbsp| :diagtext:`template`|| | +| |+---------------------+|+----------------------------+| |+---------------------+|+----------------------------+| | +| ||:diagtext:`class` || | ||:diagtext:`class` || | | +| |+---------------------+| | |+---------------------+| | | ++---------------------------+-----------------------+------------------------------+--------------------------------------------------------------------------------+-----------------------+------------------------------+----------------------------------------------------------------------------------------+ -Wmissing-braces @@ -6558,6 +7914,17 @@ This diagnostic is enabled by default. +----------------------------------------------------------------------------------------+ +-Wmissing-constinit +------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++---------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`'constinit' specifier missing on initializing declaration of` |nbsp| :placeholder:`A`| ++---------------------------------------------------------------------------------------------------------------------------+ + + -Wmissing-declarations ---------------------- This diagnostic is enabled by default. @@ -6755,6 +8122,21 @@ This diagnostic is enabled by default. +----------------------------------------------------------------------------------------------------------------+ +-Rmodule-import +--------------- +**Diagnostic text:** + ++------------------------------------------------------------------------------------+-----------------------------------------------------------+-------------------------------------------------------+ +|:remark:`remark:` |nbsp| :diagtext:`importing module '`:placeholder:`A`:diagtext:`'`|+---------------------------------------------------------+| |nbsp| :diagtext:`from '`:placeholder:`B`:diagtext:`'`| +| || || | +| |+---------------------------------------------------------+| | +| ||+-------------------------------------------------------+|| | +| ||| |nbsp| :diagtext:`into '`:placeholder:`D`:diagtext:`'`||| | +| ||+-------------------------------------------------------+|| | +| |+---------------------------------------------------------+| | ++------------------------------------------------------------------------------------+-----------------------------------------------------------+-------------------------------------------------------+ + + -Wmodule-import-in-extern-c --------------------------- This diagnostic is an error by default, but the flag ``-Wno-module-import-in-extern-c`` can be used to disable the error. @@ -6792,12 +8174,12 @@ This diagnostic is an error by default, but the flag ``-Wno-modules-import-neste ------ Some of the diagnostics controlled by this flag are enabled by default. -Controls `-Wcast-of-sel-type`_, `-Wchar-subscripts`_, `-Wcomment`_, `-Wdelete-non-virtual-dtor`_, `-Wextern-c-compat`_, `-Wfor-loop-analysis`_, `-Wformat`_, `-Wimplicit`_, `-Winfinite-recursion`_, `-Wmismatched-tags`_, `-Wmissing-braces`_, `-Wmove`_, `-Wmultichar`_, `-Wobjc-designated-initializers`_, `-Wobjc-flexible-array`_, `-Wobjc-missing-super-calls`_, `-Woverloaded-virtual`_, `-Wprivate-extern`_, `-Wreorder`_, `-Wreturn-type`_, `-Wself-assign`_, `-Wself-move`_, `-Wsizeof-array-argument`_, `-Wsizeof-array-decay`_, `-Wstring-plus-int`_, `-Wtrigraphs`_, `-Wuninitialized`_, `-Wunknown-pragmas`_, `-Wunused`_, `-Wuser-defined-warnings`_, `-Wvolatile-register-var`_. +Controls `-Wcast-of-sel-type`_, `-Wchar-subscripts`_, `-Wcomment`_, `-Wdelete-non-virtual-dtor`_, `-Wextern-c-compat`_, `-Wfor-loop-analysis`_, `-Wformat`_, `-Wimplicit`_, `-Winfinite-recursion`_, `-Wint-in-bool-context`_, `-Wmismatched-tags`_, `-Wmissing-braces`_, `-Wmove`_, `-Wmultichar`_, `-Wobjc-designated-initializers`_, `-Wobjc-flexible-array`_, `-Wobjc-missing-super-calls`_, `-Woverloaded-virtual`_, `-Wprivate-extern`_, `-Wrange-loop-construct`_, `-Wreorder`_, `-Wreturn-type`_, `-Wself-assign`_, `-Wself-move`_, `-Wsizeof-array-argument`_, `-Wsizeof-array-decay`_, `-Wstring-plus-int`_, `-Wtautological-compare`_, `-Wtrigraphs`_, `-Wuninitialized`_, `-Wunknown-pragmas`_, `-Wunused`_, `-Wuser-defined-warnings`_, `-Wvolatile-register-var`_. -Wmove ------ -Controls `-Wpessimizing-move`_, `-Wredundant-move`_, `-Wself-move`_. +Controls `-Wpessimizing-move`_, `-Wredundant-move`_, `-Wreturn-std-move`_, `-Wself-move`_. -Wmsvc-include @@ -6888,6 +8270,25 @@ This diagnostic is enabled by default. +----------------------------------------------------------------+ +-Wnoderef +--------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++----------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`dereferencing` |nbsp| :placeholder:`A`:diagtext:`; was declared with a 'noderef' type`| ++----------------------------------------------------------------------------------------------------------------------------+ + ++-----------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`dereferencing expression marked as 'noderef'`| ++-----------------------------------------------------------------------------------+ + ++-----------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`casting to dereferenceable pointer removes 'noderef' attribute`| ++-----------------------------------------------------------------------------------------------------+ + + -Wnoexcept-type --------------- Synonym for `-Wc++17-compat-mangling`_. @@ -7033,6 +8434,25 @@ This diagnostic is enabled by default. +---------------------------------------------------------------------------------------------------------------------+ +-Wnontrivial-memaccess +---------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++---------------------------+-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------+ +|:warning:`warning:` |nbsp| |+-----------------------------+| |nbsp| :diagtext:`this` |nbsp| :placeholder:`B` |nbsp| :diagtext:`call is a pointer to record` |nbsp| :placeholder:`C` |nbsp| :diagtext:`that is not trivial to` |nbsp| |+----------------------------------------+| +| ||:diagtext:`destination for` || ||:diagtext:`primitive-default-initialize`|| +| |+-----------------------------+| |+----------------------------------------+| +| ||:diagtext:`source of` || ||:diagtext:`primitive-copy` || +| |+-----------------------------+| |+----------------------------------------+| +| ||:diagtext:`first operand of` || | | +| |+-----------------------------+| | | +| ||:diagtext:`second operand of`|| | | +| |+-----------------------------+| | | ++---------------------------+-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------+ + + -Wnsconsumed-mismatch --------------------- This diagnostic is enabled by default. @@ -7274,15 +8694,37 @@ This diagnostic is enabled by default. +---------------------------------------------------------------------------------------------------------------------------+-------------------------+---------------------------------------------------------------------------------------------------------------------------------+ +-Wobjc-bool-constant-conversion +------------------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`implicit conversion from constant value` |nbsp| :placeholder:`A` |nbsp| :diagtext:`to 'BOOL'; the only well defined values for 'BOOL' are YES and NO`| ++-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + + +-Wobjc-boxing +------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++-------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`string is ill-formed as UTF-8 and will become a null` |nbsp| :placeholder:`A` |nbsp| :diagtext:`when boxed`| ++-------------------------------------------------------------------------------------------------------------------------------------------------+ + + -Wobjc-circular-container ------------------------- This diagnostic is enabled by default. **Diagnostic text:** -+-----------------------------------------------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`adding '`:placeholder:`A`:diagtext:`' to '`:placeholder:`B`:diagtext:`' might cause circular dependency in container`| -+-----------------------------------------------------------------------------------------------------------------------------------------------------------+ ++-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`adding` |nbsp| :placeholder:`A` |nbsp| :diagtext:`to` |nbsp| :placeholder:`B` |nbsp| :diagtext:`might cause circular dependency in container`| ++-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -Wobjc-cocoa-api @@ -7504,6 +8946,15 @@ This diagnostic is enabled by default. +-----------------------------------------------------------------------------------------------------------------------------+ +-Wobjc-property-assign-on-object-type +------------------------------------- +**Diagnostic text:** + ++--------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`'assign' property of object type may become a dangling reference; consider using 'unsafe\_unretained'`| ++--------------------------------------------------------------------------------------------------------------------------------------------+ + + -Wobjc-property-implementation ------------------------------ This diagnostic is enabled by default. @@ -7654,6 +9105,33 @@ This diagnostic is enabled by default. +-------------------------------------------------------------------------------------------------------------------------------+ +-Wobjc-signed-char-bool +----------------------- +Some of the diagnostics controlled by this flag are enabled by default. + +Controls `-Wobjc-bool-constant-conversion`_, `-Wobjc-signed-char-bool-implicit-float-conversion`_, `-Wobjc-signed-char-bool-implicit-int-conversion`_, `-Wtautological-objc-bool-compare`_. + + +-Wobjc-signed-char-bool-implicit-float-conversion +------------------------------------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++----------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`implicit conversion from floating-point type` |nbsp| :placeholder:`A` |nbsp| :diagtext:`to 'BOOL'`| ++----------------------------------------------------------------------------------------------------------------------------------------+ + + +-Wobjc-signed-char-bool-implicit-int-conversion +----------------------------------------------- +**Diagnostic text:** + ++----------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`implicit conversion from integral type` |nbsp| :placeholder:`A` |nbsp| :diagtext:`to 'BOOL'`| ++----------------------------------------------------------------------------------------------------------------------------------+ + + -Wobjc-string-compare --------------------- This diagnostic is enabled by default. @@ -7699,10 +9177,102 @@ This diagnostic is enabled by default. **Diagnostic text:** ++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`template parameter lists have a different number of parameters (`:placeholder:`A` |nbsp| :diagtext:`vs` |nbsp| :placeholder:`B`:diagtext:`)`| ++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + ++------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`template parameter has different kinds in different translation units`| ++------------------------------------------------------------------------------------------------------------+ + ++-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`field` |nbsp| :placeholder:`A` |nbsp| :diagtext:`declared with incompatible types in different translation units (`:placeholder:`B` |nbsp| :diagtext:`vs.` |nbsp| :placeholder:`C`:diagtext:`)`| ++-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + ++-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`external function` |nbsp| :placeholder:`A` |nbsp| :diagtext:`declared with incompatible types in different translation units (`:placeholder:`B` |nbsp| :diagtext:`vs.` |nbsp| :placeholder:`C`:diagtext:`)`| ++-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + ++-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`instance variable` |nbsp| :placeholder:`A` |nbsp| :diagtext:`declared with incompatible types in different translation units (`:placeholder:`B` |nbsp| :diagtext:`vs.` |nbsp| :placeholder:`C`:diagtext:`)`| ++-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + ++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`non-type template parameter declared with incompatible types in different translation units (`:placeholder:`A` |nbsp| :diagtext:`vs.` |nbsp| :placeholder:`B`:diagtext:`)`| ++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + ++---------------------------+----------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| |+--------------------+| |nbsp| :diagtext:`method` |nbsp| :placeholder:`B` |nbsp| :diagtext:`has a different number of parameters in different translation units (`:placeholder:`C` |nbsp| :diagtext:`vs.` |nbsp| :placeholder:`D`:diagtext:`)`| +| ||:diagtext:`class` || | +| |+--------------------+| | +| ||:diagtext:`instance`|| | +| |+--------------------+| | ++---------------------------+----------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + ++---------------------------+----------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| |+--------------------+| |nbsp| :diagtext:`method` |nbsp| :placeholder:`B` |nbsp| :diagtext:`has a parameter with a different types in different translation units (`:placeholder:`C` |nbsp| :diagtext:`vs.` |nbsp| :placeholder:`D`:diagtext:`)`| +| ||:diagtext:`class` || | +| |+--------------------+| | +| ||:diagtext:`instance`|| | +| |+--------------------+| | ++---------------------------+----------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + ++---------------------------+----------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| |+--------------------+| |nbsp| :diagtext:`method` |nbsp| :placeholder:`B` |nbsp| :diagtext:`has incompatible result types in different translation units (`:placeholder:`C` |nbsp| :diagtext:`vs.` |nbsp| :placeholder:`D`:diagtext:`)`| +| ||:diagtext:`class` || | +| |+--------------------+| | +| ||:diagtext:`instance`|| | +| |+--------------------+| | ++---------------------------+----------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + ++---------------------------+----------------------+-------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| |+--------------------+| |nbsp| :diagtext:`method` |nbsp| :placeholder:`B` |nbsp| :diagtext:`is variadic in one translation unit and not variadic in another`| +| ||:diagtext:`class` || | +| |+--------------------+| | +| ||:diagtext:`instance`|| | +| |+--------------------+| | ++---------------------------+----------------------+-------------------------------------------------------------------------------------------------------------------------------------+ + ++----------------------------------------------------------------------------------------------------------------------+-------------------------+--------------------------------------------------+-------------------------+-----------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`property` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is implemented with` |nbsp| |+-----------------------+| |nbsp| :diagtext:`in one translation but` |nbsp| |+-----------------------+| |nbsp| :diagtext:`in another translation unit`| +| ||:diagtext:`@synthesize`|| ||:diagtext:`@dynamic` || | +| |+-----------------------+| |+-----------------------+| | +| ||:diagtext:`@dynamic` || ||:diagtext:`@synthesize`|| | +| |+-----------------------+| |+-----------------------+| | ++----------------------------------------------------------------------------------------------------------------------+-------------------------+--------------------------------------------------+-------------------------+-----------------------------------------------+ + ++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`property` |nbsp| :placeholder:`A` |nbsp| :diagtext:`declared with incompatible types in different translation units (`:placeholder:`B` |nbsp| :diagtext:`vs.` |nbsp| :placeholder:`C`:diagtext:`)`| ++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + ++---------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`class` |nbsp| :placeholder:`A` |nbsp| :diagtext:`has incompatible superclasses`| ++---------------------------------------------------------------------------------------------------------------------+ + ++-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`property` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is synthesized to different ivars in different translation units (`:placeholder:`B` |nbsp| :diagtext:`vs.` |nbsp| :placeholder:`C`:diagtext:`)`| ++-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + ++------------------------------------------------------------------------------------+-------------------+----------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`parameter kind mismatch; parameter is` |nbsp| |+-----------------+| |nbsp| :diagtext:`parameter pack`| +| ||:diagtext:`not a`|| | +| |+-----------------+| | +| ||:diagtext:`a` || | +| |+-----------------+| | ++------------------------------------------------------------------------------------+-------------------+----------------------------------+ + +--------------------------------------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`type` |nbsp| :placeholder:`A` |nbsp| :diagtext:`has incompatible definitions in different translation units`| +--------------------------------------------------------------------------------------------------------------------------------------------------+ ++-----------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`external variable` |nbsp| :placeholder:`A` |nbsp| :diagtext:`defined in multiple translation units`| ++-----------------------------------------------------------------------------------------------------------------------------------------+ + ++-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`external variable` |nbsp| :placeholder:`A` |nbsp| :diagtext:`declared with incompatible types in different translation units (`:placeholder:`B` |nbsp| :diagtext:`vs.` |nbsp| :placeholder:`C`:diagtext:`)`| ++-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + -Wold-style-cast ---------------- @@ -7728,6 +9298,13 @@ This diagnostic is enabled by default. +----------------------------------------------------------------------------------------------------------------------------+ +-Wopenmp +-------- +Some of the diagnostics controlled by this flag are enabled by default. + +Controls `-Wopenmp-clauses`_, `-Wopenmp-loop-form`_, `-Wopenmp-mapping`_, `-Wopenmp-target`_, `-Wsource-uses-openmp`_. + + -Wopenmp-clauses ---------------- This diagnostic is enabled by default. @@ -7738,6 +9315,14 @@ This diagnostic is enabled by default. |:warning:`warning:` |nbsp| :diagtext:`aligned clause will be ignored because the requested alignment is not a power of 2`| +-------------------------------------------------------------------------------------------------------------------------+ ++----------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`allocator with the 'thread' trait access has unspecified behavior on '`:placeholder:`A`:diagtext:`' directive`| ++----------------------------------------------------------------------------------------------------------------------------------------------------+ + ++------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`unknown context selector in '`:placeholder:`A`:diagtext:`' context selector set of 'omp declare variant' directive, ignored`| ++------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + +---------------------------------------------------------------------------------+---------------------------------------------------+-------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`zero linear step (`:placeholder:`A` |nbsp| |+-------------------------------------------------+|:diagtext:`should probably be const)`| | || || | @@ -7746,6 +9331,20 @@ This diagnostic is enabled by default. | |+-------------------------------------------------+| | +---------------------------------------------------------------------------------+---------------------------------------------------+-------------------------------------+ ++---------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`more than one 'device\_type' clause is specified`| ++---------------------------------------------------------------------------------------+ + ++---------------------------------------------------------------------------+----------------------------------------------+-----------------------------------------------------------+----------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`allocate directive specifies` |nbsp| |+--------------------------------------------+| |nbsp| :diagtext:`allocator while previously used` |nbsp| |+--------------------------------------------+| +| ||:diagtext:`default` || ||:diagtext:`default` || +| |+--------------------------------------------+| |+--------------------------------------------+| +| ||+------------------------------------------+|| ||+------------------------------------------+|| +| |||:diagtext:`'`:placeholder:`B`:diagtext:`'`||| |||:diagtext:`'`:placeholder:`D`:diagtext:`'`||| +| ||+------------------------------------------+|| ||+------------------------------------------+|| +| |+--------------------------------------------+| |+--------------------------------------------+| ++---------------------------------------------------------------------------+----------------------------------------------+-----------------------------------------------------------+----------------------------------------------+ + -Wopenmp-loop-form ------------------ @@ -7762,16 +9361,37 @@ This diagnostic is enabled by default. +-----------------------------------------------------------------------------------------------------------------------------+ +-Wopenmp-mapping +---------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++----------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`Type` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is not trivially copyable and not guaranteed to be mapped correctly`| ++----------------------------------------------------------------------------------------------------------------------------------------------------------+ + + -Wopenmp-target --------------- This diagnostic is enabled by default. +Also controls `-Wopenmp-mapping`_. + **Diagnostic text:** +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`The OpenMP offloading target '`:placeholder:`A`:diagtext:`' is similar to target '`:placeholder:`B`:diagtext:`' already specified - will be ignored.`| +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ ++-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`No library '`:placeholder:`A`:diagtext:`' found in the default clang lib directory or in LIBRARY\_PATH. Expect degraded performance due to no inlining of runtime functions on target devices.`| ++-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + ++-----------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`declaration marked as declare target after first use, it may lead to incorrect results`| ++-----------------------------------------------------------------------------------------------------------------------------+ + +-----------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`declaration is not declared in any declare target region`| +-----------------------------------------------------------------------------------------------+ @@ -7787,14 +9407,14 @@ This diagnostic is enabled by default. |:warning:`warning:` |nbsp| :diagtext:`option '-ffine-grained-bitfield-accesses' cannot be enabled together with a sanitizer; flag ignored`| +------------------------------------------------------------------------------------------------------------------------------------------+ ++-------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`The '`:placeholder:`A`:diagtext:`' architecture does not support -moutline; flag ignored`| ++-------------------------------------------------------------------------------------------------------------------------------+ + +----------------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`option '`:placeholder:`A`:diagtext:`' was ignored by the PS4 toolchain, using '-fPIC'`| +----------------------------------------------------------------------------------------------------------------------------+ -+-------------------------------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`ignoring '-mabicalls' option as it cannot be used with non position-independent code and the N64 ABI`| -+-------------------------------------------------------------------------------------------------------------------------------------------+ - +-------------------------------------------------------------------------------------------------------------------+-------------------------------------------+----------------------+ |:warning:`warning:` |nbsp| :diagtext:`ignoring '-mlong-calls' option as it is not currently supported with` |nbsp| |+-----------------------------------------+|:diagtext:`-mabicalls`| | || || | @@ -7803,6 +9423,29 @@ This diagnostic is enabled by default. | |+-----------------------------------------+| | +-------------------------------------------------------------------------------------------------------------------+-------------------------------------------+----------------------+ ++-----------------------------------------------------------------------------------------------------------------------+-------------------------------+----------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`ignoring '`:placeholder:`A`:diagtext:`' option as it cannot be used with` |nbsp| |+-----------------------------+| |nbsp| :diagtext:`-mabicalls and the N64 ABI`| +| ||:diagtext:`implicit usage of`|| | +| |+-----------------------------+| | +| || || | +| |+-----------------------------+| | ++-----------------------------------------------------------------------------------------------------------------------+-------------------------------+----------------------------------------------+ + ++----------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`auto-vectorization requires HVX, use -mhvx to enable it`| ++----------------------------------------------------------------------------------------------+ + + +-Wordered-compare-function-pointers +----------------------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`ordered comparison of function pointers (`:placeholder:`A` |nbsp| :diagtext:`and` |nbsp| :placeholder:`B`:diagtext:`)`| ++------------------------------------------------------------------------------------------------------------------------------------------------------------+ + -Wout-of-line-declaration ------------------------- @@ -7885,6 +9528,7 @@ This diagnostic is enabled by default. | |+---------------------+| +-----------------------------------------------------------------------------------------------+-----------------------+ + -Woverride-init --------------- Synonym for `-Winitializer-overrides`_. @@ -7989,9 +9633,9 @@ This diagnostic is enabled by default. -Wparentheses ------------- -This diagnostic is enabled by default. +Some of the diagnostics controlled by this flag are enabled by default. -Also controls `-Wbitwise-op-parentheses`_, `-Wdangling-else`_, `-Wlogical-not-parentheses`_, `-Wlogical-op-parentheses`_, `-Woverloaded-shift-op-parentheses`_, `-Wparentheses-equality`_, `-Wshift-op-parentheses`_. +Also controls `-Wbitwise-conditional-parentheses`_, `-Wbitwise-op-parentheses`_, `-Wdangling-else`_, `-Wlogical-not-parentheses`_, `-Wlogical-op-parentheses`_, `-Woverloaded-shift-op-parentheses`_, `-Wparentheses-equality`_, `-Wshift-op-parentheses`_. **Diagnostic text:** @@ -8079,10 +9723,14 @@ This diagnostic is enabled by default. -Wpedantic ---------- -Also controls `-Wc++11-extra-semi`_, `-Wc++11-long-long`_, `-Wc++14-binary-literal`_, `-Wc11-extensions`_, `-Wcomplex-component-init`_, `-Wdeclaration-after-statement`_, `-Wdollar-in-identifier-extension`_, `-Wembedded-directive`_, `-Wempty-translation-unit`_, `-Wextended-offsetof`_, `-Wflexible-array-extensions`_, `-Wformat-pedantic`_, `-Wfour-char-constants`_, `-Wgnu-anonymous-struct`_, `-Wgnu-auto-type`_, `-Wgnu-binary-literal`_, `-Wgnu-case-range`_, `-Wgnu-complex-integer`_, `-Wgnu-compound-literal-initializer`_, `-Wgnu-conditional-omitted-operand`_, `-Wgnu-empty-initializer`_, `-Wgnu-empty-struct`_, `-Wgnu-flexible-array-initializer`_, `-Wgnu-flexible-array-union-member`_, `-Wgnu-folding-constant`_, `-Wgnu-imaginary-constant`_, `-Wgnu-include-next`_, `-Wgnu-label-as-value`_, `-Wgnu-redeclared-enum`_, `-Wgnu-statement-expression`_, `-Wgnu-union-cast`_, `-Wgnu-zero-line-directive`_, `-Wgnu-zero-variadic-macro-arguments`_, `-Wimport-preprocessor-directive-pedantic`_, `-Wkeyword-macro`_, `-Wlanguage-extension-token`_, `-Wlong-long`_, `-Wmicrosoft-charize`_, `-Wmicrosoft-comment-paste`_, `-Wmicrosoft-cpp-macro`_, `-Wmicrosoft-end-of-file`_, `-Wmicrosoft-enum-value`_, `-Wmicrosoft-fixed-enum`_, `-Wmicrosoft-flexible-array`_, `-Wmicrosoft-redeclare-static`_, `-Wnested-anon-types`_, `-Wnullability-extension`_, `-Woverlength-strings`_, `-Wretained-language-linkage`_, `-Wundefined-internal-type`_, `-Wvla-extension`_, `-Wzero-length-array`_. +Also controls `-Wc++11-extra-semi`_, `-Wc++11-long-long`_, `-Wc++14-binary-literal`_, `-Wc++20-designator`_, `-Wc11-extensions`_, `-Wcomplex-component-init`_, `-Wdeclaration-after-statement`_, `-Wdollar-in-identifier-extension`_, `-Wembedded-directive`_, `-Wempty-translation-unit`_, `-Wfixed-enum-extension`_, `-Wflexible-array-extensions`_, `-Wfour-char-constants`_, `-Wgnu-anonymous-struct`_, `-Wgnu-auto-type`_, `-Wgnu-binary-literal`_, `-Wgnu-case-range`_, `-Wgnu-complex-integer`_, `-Wgnu-compound-literal-initializer`_, `-Wgnu-conditional-omitted-operand`_, `-Wgnu-empty-initializer`_, `-Wgnu-empty-struct`_, `-Wgnu-flexible-array-initializer`_, `-Wgnu-flexible-array-union-member`_, `-Wgnu-folding-constant`_, `-Wgnu-imaginary-constant`_, `-Wgnu-include-next`_, `-Wgnu-label-as-value`_, `-Wgnu-redeclared-enum`_, `-Wgnu-statement-expression`_, `-Wgnu-union-cast`_, `-Wgnu-zero-line-directive`_, `-Wgnu-zero-variadic-macro-arguments`_, `-Wimport-preprocessor-directive-pedantic`_, `-Wkeyword-macro`_, `-Wlanguage-extension-token`_, `-Wlong-long`_, `-Wmicrosoft-charize`_, `-Wmicrosoft-comment-paste`_, `-Wmicrosoft-cpp-macro`_, `-Wmicrosoft-end-of-file`_, `-Wmicrosoft-enum-value`_, `-Wmicrosoft-fixed-enum`_, `-Wmicrosoft-flexible-array`_, `-Wmicrosoft-redeclare-static`_, `-Wnested-anon-types`_, `-Wnullability-extension`_, `-Woverlength-strings`_, `-Wretained-language-linkage`_, `-Wundefined-internal-type`_, `-Wvla-extension`_, `-Wzero-length-array`_. **Diagnostic text:** ++-----------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`duplicate '`:placeholder:`A`:diagtext:`' declaration specifier`| ++-----------------------------------------------------------------------------------------------------+ + +------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`'enable\_if' is a clang extension`| +------------------------------------------------------------------------+ @@ -8115,38 +9763,44 @@ Also controls `-Wc++11-extra-semi`_, `-Wc++11-long-long`_, `-Wc++14-binary-liter | |+------------------+| | +--------------------------------------------------------+--------------------+------------------------------------------------------------+ -+--------------------------------------------------------------------+-----------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`no viable constructor` |nbsp| |+---------------------------------------+| |nbsp| :diagtext:`of type` |nbsp| :placeholder:`B`:diagtext:`; C++98 requires a copy constructor when binding a reference to a temporary`| -| ||:diagtext:`copying variable` || | -| |+---------------------------------------+| | -| ||:diagtext:`copying parameter` || | -| |+---------------------------------------+| | -| ||:diagtext:`returning object` || | -| |+---------------------------------------+| | -| ||:diagtext:`throwing object` || | -| |+---------------------------------------+| | -| ||:diagtext:`copying member subobject` || | -| |+---------------------------------------+| | -| ||:diagtext:`copying array element` || | -| |+---------------------------------------+| | -| ||:diagtext:`allocating object` || | -| |+---------------------------------------+| | -| ||:diagtext:`copying temporary` || | -| |+---------------------------------------+| | -| ||:diagtext:`initializing base subobject`|| | -| |+---------------------------------------+| | -| ||:diagtext:`initializing vector element`|| | -| |+---------------------------------------+| | -| ||:diagtext:`capturing value` || | -| |+---------------------------------------+| | -+--------------------------------------------------------------------+-----------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------+ ++--------------------------------------------------------------------+------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`no viable constructor` |nbsp| |+----------------------------------------------------+| |nbsp| :diagtext:`of type` |nbsp| :placeholder:`B`:diagtext:`; C++98 requires a copy constructor when binding a reference to a temporary`| +| ||:diagtext:`copying variable` || | +| |+----------------------------------------------------+| | +| ||:diagtext:`copying parameter` || | +| |+----------------------------------------------------+| | +| ||:diagtext:`returning object` || | +| |+----------------------------------------------------+| | +| ||:diagtext:`initializing statement expression result`|| | +| |+----------------------------------------------------+| | +| ||:diagtext:`throwing object` || | +| |+----------------------------------------------------+| | +| ||:diagtext:`copying member subobject` || | +| |+----------------------------------------------------+| | +| ||:diagtext:`copying array element` || | +| |+----------------------------------------------------+| | +| ||:diagtext:`allocating object` || | +| |+----------------------------------------------------+| | +| ||:diagtext:`copying temporary` || | +| |+----------------------------------------------------+| | +| ||:diagtext:`initializing base subobject` || | +| |+----------------------------------------------------+| | +| ||:diagtext:`initializing vector element` || | +| |+----------------------------------------------------+| | +| ||:diagtext:`capturing value` || | +| |+----------------------------------------------------+| | ++--------------------------------------------------------------------+------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------+ + ++--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`ISO C++ standards before C++17 do not allow new expression for type` |nbsp| :placeholder:`A` |nbsp| :diagtext:`to use list-initialization`| ++--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +--------------------------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`parameter` |nbsp| :placeholder:`A` |nbsp| :diagtext:`was not declared, defaulting to type 'int'`| +--------------------------------------------------------------------------------------------------------------------------------------+ +--------------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`invoking a pointer to a 'const &' member function on an rvalue is a C++2a extension`| +|:warning:`warning:` |nbsp| :diagtext:`invoking a pointer to a 'const &' member function on an rvalue is a C++20 extension`| +--------------------------------------------------------------------------------------------------------------------------+ +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ @@ -8185,25 +9839,33 @@ Also controls `-Wc++11-extra-semi`_, `-Wc++11-long-long`_, `-Wc++14-binary-liter |:warning:`warning:` |nbsp| :diagtext:`flexible array members are a C99 feature`| +-------------------------------------------------------------------------------+ -+---------------------------------------------------------------+-----------------------+--------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`invalid application of '`|+---------------------+|:diagtext:`' to a function type`| -| ||:diagtext:`sizeof` || | -| |+---------------------+| | -| ||:diagtext:`alignof` || | -| |+---------------------+| | -| ||:diagtext:`vec\_step`|| | -| |+---------------------+| | -+---------------------------------------------------------------+-----------------------+--------------------------------+ - -+---------------------------------------------------------------+-----------------------+----------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`invalid application of '`|+---------------------+|:diagtext:`' to a void type`| -| ||:diagtext:`sizeof` || | -| |+---------------------+| | -| ||:diagtext:`alignof` || | -| |+---------------------+| | -| ||:diagtext:`vec\_step`|| | -| |+---------------------+| | -+---------------------------------------------------------------+-----------------------+----------------------------+ ++---------------------------------------------------------------+-----------------------------------------------------+--------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`invalid application of '`|+---------------------------------------------------+|:diagtext:`' to a function type`| +| ||:diagtext:`sizeof` || | +| |+---------------------------------------------------+| | +| ||:diagtext:`alignof` || | +| |+---------------------------------------------------+| | +| ||:diagtext:`vec\_step` || | +| |+---------------------------------------------------+| | +| ||:diagtext:`\_\_builtin\_omp\_required\_simd\_align`|| | +| |+---------------------------------------------------+| | +| ||:diagtext:`\_\_alignof` || | +| |+---------------------------------------------------+| | ++---------------------------------------------------------------+-----------------------------------------------------+--------------------------------+ + ++---------------------------------------------------------------+-----------------------------------------------------+----------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`invalid application of '`|+---------------------------------------------------+|:diagtext:`' to a void type`| +| ||:diagtext:`sizeof` || | +| |+---------------------------------------------------+| | +| ||:diagtext:`alignof` || | +| |+---------------------------------------------------+| | +| ||:diagtext:`vec\_step` || | +| |+---------------------------------------------------+| | +| ||:diagtext:`\_\_builtin\_omp\_required\_simd\_align`|| | +| |+---------------------------------------------------+| | +| ||:diagtext:`\_\_alignof` || | +| |+---------------------------------------------------+| | ++---------------------------------------------------------------+-----------------------------------------------------+----------------------------+ +-------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`ISO C90 does not allow subscripting non-lvalue array`| @@ -8305,6 +9967,10 @@ Also controls `-Wc++11-extra-semi`_, `-Wc++11-long-long`_, `-Wc++14-binary-liter |:warning:`warning:` |nbsp| :diagtext:`use of the` |nbsp| :placeholder:`A` |nbsp| :diagtext:`attribute is a C++17 extension`| +---------------------------------------------------------------------------------------------------------------------------+ ++---------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`use of the` |nbsp| :placeholder:`A` |nbsp| :diagtext:`attribute is a C++20 extension`| ++---------------------------------------------------------------------------------------------------------------------------+ + +-----------------------------------------------------------------------------+--------------------+---------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`types declared in an anonymous` |nbsp| |+------------------+| |nbsp| :diagtext:`are a Microsoft extension`| | ||:diagtext:`struct`|| | @@ -8313,6 +9979,14 @@ Also controls `-Wc++11-extra-semi`_, `-Wc++11-long-long`_, `-Wc++14-binary-liter | |+------------------+| | +-----------------------------------------------------------------------------+--------------------+---------------------------------------------+ ++------------------------------------------------------------------------------------------------------------------------------------+-----------------------------+------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`format specifies type` |nbsp| :placeholder:`A` |nbsp| :diagtext:`but the argument has` |nbsp| |+---------------------------+| |nbsp| :placeholder:`B`| +| ||:diagtext:`type` || | +| |+---------------------------+| | +| ||:diagtext:`underlying type`|| | +| |+---------------------------+| | ++------------------------------------------------------------------------------------------------------------------------------------+-----------------------------+------------------------+ + +---------------------------------------------------+----------------------+-----------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`void` |nbsp| |+--------------------+| |nbsp| :placeholder:`A` |nbsp| :diagtext:`should not return void expression`| | ||:diagtext:`function`|| | @@ -8323,10 +9997,6 @@ Also controls `-Wc++11-extra-semi`_, `-Wc++11-long-long`_, `-Wc++14-binary-liter | |+--------------------+| | +---------------------------------------------------+----------------------+-----------------------------------------------------------------------------+ -+--------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`'`:placeholder:`A`:diagtext:`' cannot be signed or unsigned`| -+--------------------------------------------------------------------------------------------------+ - +---------------------------+----------------------------------+------------------------------+-----------------------+----------------------------+ |:warning:`warning:` |nbsp| |+--------------------------------+|:diagtext:`array size` |nbsp| |+---------------------+|:diagtext:`is a C99 feature`| | ||:diagtext:`qualifier in` |nbsp| || || || | @@ -8379,6 +10049,10 @@ Also controls `-Wc++11-extra-semi`_, `-Wc++11-long-long`_, `-Wc++14-binary-liter |:warning:`warning:` |nbsp| :diagtext:`enumeration types with a fixed underlying type are a C++11 extension`| +-----------------------------------------------------------------------------------------------------------+ ++----------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`'`:placeholder:`A`:diagtext:`' is a C99 extension`| ++----------------------------------------------------------------------------------------+ + +-----------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`use of GNU array range extension`| +-----------------------------------------------------------------------+ @@ -8451,6 +10125,10 @@ Also controls `-Wc++11-extra-semi`_, `-Wc++11-long-long`_, `-Wc++14-binary-liter |:warning:`warning:` |nbsp| :diagtext:`empty macro arguments are a C99 feature`| +------------------------------------------------------------------------------+ ++--------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`variadic macros are a Clang extension in OpenCL`| ++--------------------------------------------------------------------------------------+ + +----------------------------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`C requires #line number to be less than` |nbsp| :placeholder:`A`:diagtext:`, allowed as extension`| +----------------------------------------------------------------------------------------------------------------------------------------+ @@ -8510,25 +10188,33 @@ Some of the diagnostics controlled by this flag are enabled by default. | |+---------------------+| |+-------------+| | +----------------------------------------------------+-----------------------+---------------------------+---------------+----------------------------------------------+ -+---------------------------------------------------------------+-----------------------+--------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`invalid application of '`|+---------------------+|:diagtext:`' to a function type`| -| ||:diagtext:`sizeof` || | -| |+---------------------+| | -| ||:diagtext:`alignof` || | -| |+---------------------+| | -| ||:diagtext:`vec\_step`|| | -| |+---------------------+| | -+---------------------------------------------------------------+-----------------------+--------------------------------+ - -+---------------------------------------------------------------+-----------------------+----------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`invalid application of '`|+---------------------+|:diagtext:`' to a void type`| -| ||:diagtext:`sizeof` || | -| |+---------------------+| | -| ||:diagtext:`alignof` || | -| |+---------------------+| | -| ||:diagtext:`vec\_step`|| | -| |+---------------------+| | -+---------------------------------------------------------------+-----------------------+----------------------------+ ++---------------------------------------------------------------+-----------------------------------------------------+--------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`invalid application of '`|+---------------------------------------------------+|:diagtext:`' to a function type`| +| ||:diagtext:`sizeof` || | +| |+---------------------------------------------------+| | +| ||:diagtext:`alignof` || | +| |+---------------------------------------------------+| | +| ||:diagtext:`vec\_step` || | +| |+---------------------------------------------------+| | +| ||:diagtext:`\_\_builtin\_omp\_required\_simd\_align`|| | +| |+---------------------------------------------------+| | +| ||:diagtext:`\_\_alignof` || | +| |+---------------------------------------------------+| | ++---------------------------------------------------------------+-----------------------------------------------------+--------------------------------+ + ++---------------------------------------------------------------+-----------------------------------------------------+----------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`invalid application of '`|+---------------------------------------------------+|:diagtext:`' to a void type`| +| ||:diagtext:`sizeof` || | +| |+---------------------------------------------------+| | +| ||:diagtext:`alignof` || | +| |+---------------------------------------------------+| | +| ||:diagtext:`vec\_step` || | +| |+---------------------------------------------------+| | +| ||:diagtext:`\_\_builtin\_omp\_required\_simd\_align`|| | +| |+---------------------------------------------------+| | +| ||:diagtext:`\_\_alignof` || | +| |+---------------------------------------------------+| | ++---------------------------------------------------------------+-----------------------------------------------------+----------------------------+ +-----------------------------------------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`subtraction of pointers to type` |nbsp| :placeholder:`A` |nbsp| :diagtext:`of zero size has undefined behavior`| @@ -8560,6 +10246,32 @@ This diagnostic is enabled by default. +-------------------------------------------------+------------------------------+---------------------------------------------------------------------------------+ +-Wpointer-compare +----------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++---------------------------------------------------------------------------------------------------------------------------+------------------------+-------------+ +|:warning:`warning:` |nbsp| :diagtext:`comparing a pointer to a null character constant; did you mean to compare to` |nbsp| |+----------------------+|:diagtext:`?`| +| ||:diagtext:`NULL` || | +| |+----------------------+| | +| ||:diagtext:`(void \*)0`|| | +| |+----------------------+| | ++---------------------------------------------------------------------------------------------------------------------------+------------------------+-------------+ + + +-Wpointer-integer-compare +------------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++-----------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`comparison between pointer and integer (`:placeholder:`A` |nbsp| :diagtext:`and` |nbsp| :placeholder:`B`:diagtext:`)`| ++-----------------------------------------------------------------------------------------------------------------------------------------------------------+ + + -Wpointer-sign -------------- This diagnostic is enabled by default. @@ -8600,6 +10312,15 @@ This diagnostic is enabled by default. +------------------------------------------------------------+ +-Wpoison-system-directories +--------------------------- +**Diagnostic text:** + ++----------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`include location '`:placeholder:`A`:diagtext:`' is unsafe for cross-compilation`| ++----------------------------------------------------------------------------------------------------------------------+ + + -Wpotentially-evaluated-expression ---------------------------------- This diagnostic is enabled by default. @@ -8726,26 +10447,34 @@ This diagnostic is enabled by default. **Diagnostic text:** -+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`top-level module '`:placeholder:`A`:diagtext:`' in private module map, expected a submodule of '`:placeholder:`B`:diagtext:`'`| -+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+ ++----------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`expected canonical name for private module '`:placeholder:`A`:diagtext:`'`| ++----------------------------------------------------------------------------------------------------------------+ + ++----------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`private submodule '`:placeholder:`A`:diagtext:`' in private module map, expected top-level module`| ++----------------------------------------------------------------------------------------------------------------------------------------+ +----------------------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`module '`:placeholder:`A`:diagtext:`' already re-exported as '`:placeholder:`B`:diagtext:`'`| +----------------------------------------------------------------------------------------------------------------------------------+ ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`no submodule named` |nbsp| :placeholder:`A` |nbsp| :diagtext:`in module '`:placeholder:`B`:diagtext:`'; using top level '`:placeholder:`C`:diagtext:`'`| ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + -Wprofile-instr-missing ----------------------- **Diagnostic text:** -+-----------------------------------------------------------------------------------------------------------------------------+---------------+---------------------------------------------+-------------------+---------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`profile data may be incomplete: of` |nbsp| :placeholder:`A` |nbsp| :diagtext:`function`|+-------------+|:diagtext:`,` |nbsp| :placeholder:`B` |nbsp| |+-----------------+| |nbsp| :diagtext:`no data`| -| || || ||:diagtext:`:has` || | -| |+-------------+| |+-----------------+| | -| ||:diagtext:`s`|| ||:diagtext:`:have`|| | -| |+-------------+| |+-----------------+| | -+-----------------------------------------------------------------------------------------------------------------------------+---------------+---------------------------------------------+-------------------+---------------------------+ ++-----------------------------------------------------------------------------------------------------------------------------+---------------+---------------------------------------------+------------------+---------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`profile data may be incomplete: of` |nbsp| :placeholder:`A` |nbsp| :diagtext:`function`|+-------------+|:diagtext:`,` |nbsp| :placeholder:`B` |nbsp| |+----------------+| |nbsp| :diagtext:`no data`| +| || || ||:diagtext:`has` || | +| |+-------------+| |+----------------+| | +| ||:diagtext:`s`|| ||:diagtext:`have`|| | +| |+-------------+| |+----------------+| | ++-----------------------------------------------------------------------------------------------------------------------------+---------------+---------------------------------------------+------------------+---------------------------+ -Wprofile-instr-out-of-date @@ -8754,13 +10483,13 @@ This diagnostic is enabled by default. **Diagnostic text:** -+------------------------------------------------------------------------------------------------------------------------------+---------------+---------------------------------------------+-------------------+--------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`profile data may be out of date: of` |nbsp| :placeholder:`A` |nbsp| :diagtext:`function`|+-------------+|:diagtext:`,` |nbsp| :placeholder:`B` |nbsp| |+-----------------+| |nbsp| :diagtext:`mismatched data that will be ignored`| -| || || ||:diagtext:`:has` || | -| |+-------------+| |+-----------------+| | -| ||:diagtext:`s`|| ||:diagtext:`:have`|| | -| |+-------------+| |+-----------------+| | -+------------------------------------------------------------------------------------------------------------------------------+---------------+---------------------------------------------+-------------------+--------------------------------------------------------+ ++------------------------------------------------------------------------------------------------------------------------------+---------------+---------------------------------------------+------------------+--------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`profile data may be out of date: of` |nbsp| :placeholder:`A` |nbsp| :diagtext:`function`|+-------------+|:diagtext:`,` |nbsp| :placeholder:`B` |nbsp| |+----------------+| |nbsp| :diagtext:`mismatched data that will be ignored`| +| || || ||:diagtext:`has` || | +| |+-------------+| |+----------------+| | +| ||:diagtext:`s`|| ||:diagtext:`have`|| | +| |+-------------+| |+----------------+| | ++------------------------------------------------------------------------------------------------------------------------------+---------------+---------------------------------------------+------------------+--------------------------------------------------------+ -Wprofile-instr-unprofiled @@ -8861,8 +10590,31 @@ This diagnostic is enabled by default. +---------------------------------------------------------------------------------------------------------+ +-Wquoted-include-in-framework-header +------------------------------------ +**Diagnostic text:** + ++-------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`double-quoted include "`:placeholder:`A`:diagtext:`" in framework header, expected angle-bracketed instead`| ++-------------------------------------------------------------------------------------------------------------------------------------------------+ + + -Wrange-loop-analysis --------------------- +Controls `-Wrange-loop-bind-reference`_, `-Wrange-loop-construct`_. + + +-Wrange-loop-bind-reference +--------------------------- +**Diagnostic text:** + ++-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`loop variable` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is always a copy because the range of type` |nbsp| :placeholder:`B` |nbsp| :diagtext:`does not return a reference`| ++-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + + +-Wrange-loop-construct +---------------------- **Diagnostic text:** +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ @@ -8873,10 +10625,6 @@ This diagnostic is enabled by default. |:warning:`warning:` |nbsp| :diagtext:`loop variable` |nbsp| :placeholder:`A` |nbsp| :diagtext:`of type` |nbsp| :placeholder:`B` |nbsp| :diagtext:`creates a copy from type` |nbsp| :placeholder:`C`| +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`loop variable` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is always a copy because the range of type` |nbsp| :placeholder:`B` |nbsp| :diagtext:`does not return a reference`| -+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - -Wreadonly-iboutlet-property ---------------------------- @@ -8985,6 +10733,13 @@ The text of this diagnostic is not controlled by Clang. -Wreorder --------- +Some of the diagnostics controlled by this flag are enabled by default. + +Controls `-Wreorder-ctor`_, `-Wreorder-init-list`_. + + +-Wreorder-ctor +-------------- **Diagnostic text:** +---------------------------+------------------------+-----------------------------------------------------------------------------+-------------------+------------------------+ @@ -8996,6 +10751,28 @@ The text of this diagnostic is not controlled by Clang. +---------------------------+------------------------+-----------------------------------------------------------------------------+-------------------+------------------------+ +-Wreorder-init-list +------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`ISO C++ requires field designators to be specified in declaration order; field` |nbsp| :placeholder:`B` |nbsp| :diagtext:`will be initialized after field` |nbsp| :placeholder:`A`| ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + + +-Wrequires-expression +--------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`this requires expression will only be checked for syntactic validity; did you intend to place it in a nested requirement? (add another 'requires' before the expression)`| ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + + -Wrequires-super-attribute -------------------------- This diagnostic is enabled by default. @@ -9064,13 +10841,35 @@ This diagnostic is enabled by default. | |+------------------------+| | +--------------------------------------------------------+--------------------------+------------------------------------------+ -+---------------------------+--------------------------+-------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| |+------------------------+| |nbsp| :diagtext:`stack memory associated with local variable` |nbsp| :placeholder:`B` |nbsp| :diagtext:`returned`| -| ||:diagtext:`address of` || | -| |+------------------------+| | -| ||:diagtext:`reference to`|| | -| |+------------------------+| | -+---------------------------+--------------------------+-------------------------------------------------------------------------------------------------------------------+ ++---------------------------+--------------------------+--------------------------------------------------------+----------------------------+----------------------------------------------------+ +|:warning:`warning:` |nbsp| |+------------------------+| |nbsp| :diagtext:`stack memory associated with` |nbsp| |+--------------------------+| |nbsp| :placeholder:`B` |nbsp| :diagtext:`returned`| +| ||:diagtext:`address of` || ||:diagtext:`local variable`|| | +| |+------------------------+| |+--------------------------+| | +| ||:diagtext:`reference to`|| ||:diagtext:`parameter` || | +| |+------------------------+| |+--------------------------+| | ++---------------------------+--------------------------+--------------------------------------------------------+----------------------------+----------------------------------------------------+ + + +-Wreturn-std-move +----------------- +**Diagnostic text:** + ++-------------------------------------------------------------------------------------------------------------------------------------+----------------------+---------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`local variable` |nbsp| :placeholder:`A` |nbsp| :diagtext:`will be copied despite being` |nbsp| |+--------------------+| |nbsp| :diagtext:`by name`| +| ||:diagtext:`returned`|| | +| |+--------------------+| | +| ||:diagtext:`thrown` || | +| |+--------------------+| | ++-------------------------------------------------------------------------------------------------------------------------------------+----------------------+---------------------------+ + + +-Wreturn-std-move-in-c++11 +-------------------------- +**Diagnostic text:** + ++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`prior to the resolution of a defect report against ISO C++11, local variable` |nbsp| :placeholder:`A` |nbsp| :diagtext:`would have been copied despite being returned by name, due to its not matching the function return type`| ++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -Wreturn-type @@ -9101,29 +10900,29 @@ Also controls `-Wreturn-type-c-linkage`_. | |+--------------------+| | +---------------------------------------------------+----------------------+-----------------------------------------------------------------+ -+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`control reaches end of coroutine; which is undefined behavior because the promise type` |nbsp| :placeholder:`A` |nbsp| :diagtext:`does not declare 'return\_void()'`| -+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ ++---------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`non-void coroutine does not return a value`| ++---------------------------------------------------------------------------------+ -+-------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`control reaches end of non-void function`| -+-------------------------------------------------------------------------------+ ++--------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`non-void function does not return a value`| ++--------------------------------------------------------------------------------+ -+-----------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`control reaches end of non-void lambda`| -+-----------------------------------------------------------------------------+ ++------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`non-void lambda does not return a value`| ++------------------------------------------------------------------------------+ -+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`control may reach end of coroutine; which is undefined behavior because the promise type` |nbsp| :placeholder:`A` |nbsp| :diagtext:`does not declare 'return\_void()'`| -+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ ++------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`non-void coroutine does not return a value in all control paths`| ++------------------------------------------------------------------------------------------------------+ -+---------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`control may reach end of non-void function`| -+---------------------------------------------------------------------------------+ ++-----------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`non-void function does not return a value in all control paths`| ++-----------------------------------------------------------------------------------------------------+ -+-------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`control may reach end of non-void lambda`| -+-------------------------------------------------------------------------------+ ++---------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`non-void lambda does not return a value in all control paths`| ++---------------------------------------------------------------------------------------------------+ +---------------------------------------------------+----------------------+-----------------------------------------------------------------+ |:error:`error:` |nbsp| :diagtext:`non-void` |nbsp| |+--------------------+| |nbsp| :placeholder:`A` |nbsp| :diagtext:`should return a value`| @@ -9149,17 +10948,6 @@ This diagnostic is enabled by default. +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ --Wrtti-for-exceptions ---------------------- -This diagnostic is enabled by default. - -**Diagnostic text:** - -+--------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`implicitly enabling rtti for exception handling`| -+--------------------------------------------------------------------------------------+ - - -Rsanitize-address ------------------ **Diagnostic text:** @@ -9199,9 +10987,17 @@ This diagnostic is enabled by default. |:warning:`warning:` |nbsp| :diagtext:`section attribute is specified on redeclared variable`| +--------------------------------------------------------------------------------------------+ -+----------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`section does not match previous declaration`| -+----------------------------------------------------------------------------------+ ++------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`duplicate code segment specifiers`| ++------------------------------------------------------------------------+ + ++---------------------------+---------------------+-------------------------------------------------------+ +|:warning:`warning:` |nbsp| |+-------------------+| |nbsp| :diagtext:`does not match previous declaration`| +| ||:diagtext:`codeseg`|| | +| |+-------------------+| | +| ||:diagtext:`section`|| | +| |+-------------------+| | ++---------------------------+---------------------+-------------------------------------------------------+ -Wselector @@ -9228,7 +11024,7 @@ Also controls `-Wselector-type-mismatch`_. ------------- Some of the diagnostics controlled by this flag are enabled by default. -Also controls `-Wself-assign-field`_. +Also controls `-Wself-assign-field`_, `-Wself-assign-overloaded`_. **Diagnostic text:** @@ -9252,6 +11048,15 @@ This diagnostic is enabled by default. +--------------------------------------------------------+-------------------------------+-----------------------------+ +-Wself-assign-overloaded +------------------------ +**Diagnostic text:** + ++------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`explicitly assigning value of variable of type` |nbsp| :placeholder:`A` |nbsp| :diagtext:`to itself`| ++------------------------------------------------------------------------------------------------------------------------------------------+ + + -Wself-move ----------- **Diagnostic text:** @@ -9357,9 +11162,15 @@ Controls `-Wshadow`_, `-Wshadow-field`_, `-Wshadow-field-in-constructor`_, `-Wsh -------------- **Diagnostic text:** -+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`non-static data member '`:placeholder:`A`:diagtext:`' of '`:placeholder:`B`:diagtext:`' shadows member inherited from type '`:placeholder:`C`:diagtext:`'`| -+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ ++---------------------------+------------------------------------+--------------------------------+--------------------------------------------------+----------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| |+----------------------------------+| |nbsp| :placeholder:`A` |nbsp| |+------------------------------------------------+|:diagtext:`shadows member inherited from type` |nbsp| :placeholder:`C`| +| ||:diagtext:`parameter` || || || | +| |+----------------------------------+| |+------------------------------------------------+| | +| ||:diagtext:`non-static data member`|| ||+----------------------------------------------+|| | +| |+----------------------------------+| |||:diagtext:`of` |nbsp| :placeholder:`B` |nbsp| ||| | +| | | ||+----------------------------------------------+|| | +| | | |+------------------------------------------------+| | ++---------------------------+------------------------------------+--------------------------------+--------------------------------------------------+----------------------------------------------------------------------+ -Wshadow-field-in-constructor @@ -9518,6 +11329,10 @@ This diagnostic is enabled by default. |:warning:`warning:` |nbsp| :diagtext:`operand of ? changes signedness:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`to` |nbsp| :placeholder:`B`| +---------------------------------------------------------------------------------------------------------------------------------------------+ ++-----------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`the resulting value is always non-negative after implicit conversion`| ++-----------------------------------------------------------------------------------------------------------+ + -Wsign-promo ------------ @@ -9532,6 +11347,17 @@ This diagnostic flag exists for GCC compatibility, and has no effect in Clang. +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +-Wsigned-unsigned-wchar +----------------------- +This diagnostic is an error by default, but the flag ``-Wno-signed-unsigned-wchar`` can be used to disable the error. + +**Diagnostic text:** + ++----------------------------------------------------------------------------------------------+ +|:error:`error:` |nbsp| :diagtext:`'`:placeholder:`A`:diagtext:`' cannot be signed or unsigned`| ++----------------------------------------------------------------------------------------------+ + + -Wsizeof-array-argument ----------------------- This diagnostic is enabled by default. @@ -9554,6 +11380,28 @@ This diagnostic is enabled by default. +--------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +-Wsizeof-array-div +------------------ +This diagnostic is enabled by default. + +**Diagnostic text:** + ++-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`expression does not compute the number of elements in this array; element type is` |nbsp| :placeholder:`A`:diagtext:`, not` |nbsp| :placeholder:`B`| ++-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + + +-Wsizeof-pointer-div +-------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++-------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`'`:placeholder:`A`:diagtext:`' will return the size of the pointer, not the array itself`| ++-------------------------------------------------------------------------------------------------------------------------------+ + + -Wsizeof-pointer-memaccess -------------------------- This diagnostic is enabled by default. @@ -9633,6 +11481,18 @@ Some of the diagnostics controlled by this flag are enabled by default. **Diagnostic text:** ++--------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`'#pragma omp declare variant' cannot be applied to the function that was defined already; the original function might be used`| ++--------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + ++----------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`'#pragma omp declare variant' cannot be applied for function after first usage; the original function might be used`| ++----------------------------------------------------------------------------------------------------------------------------------------------------------+ + ++------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`variant function in '#pragma omp declare variant' is itself marked as '#pragma omp declare variant'`| ++------------------------------------------------------------------------------------------------------------------------------------------+ + +------------------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`OpenMP only allows an ordered construct with the simd clause nested in a simd construct`| +------------------------------------------------------------------------------------------------------------------------------+ @@ -9651,6 +11511,17 @@ Some of the diagnostics controlled by this flag are enabled by default. +----------------------------------------------------------------------------------------------------------------------+ +-Wstack-exhausted +----------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++----------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`stack nearly exhausted; compilation time may suffer, and crashes due to stack overflow are likely`| ++----------------------------------------------------------------------------------------------------------------------------------------+ + + -Wstack-protector ----------------- This diagnostic flag exists for GCC compatibility, and has no effect in Clang. @@ -9728,6 +11599,17 @@ This diagnostic is enabled by default. +----------------------------------------------------------------------------------------------------------------------------------------------------+ +-Wstdlibcxx-not-found +--------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++-------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`include path for libstdc++ headers not found; pass '-stdlib=libc++' on the command line to use the libc++ standard library instead`| ++-------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + + -Wstrict-aliasing ----------------- This diagnostic flag exists for GCC compatibility, and has no effect in Clang. @@ -9817,13 +11699,13 @@ This diagnostic is enabled by default. **Diagnostic text:** -+---------------------------------------------------------------------------+------------------------------+--------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`result of comparison against` |nbsp| |+----------------------------+| |nbsp| :diagtext:`is unspecified (use strncmp instead)`| -| ||:diagtext:`a string literal`|| | -| |+----------------------------+| | -| ||:diagtext:`@encode` || | -| |+----------------------------+| | -+---------------------------------------------------------------------------+------------------------------+--------------------------------------------------------+ ++---------------------------------------------------------------------------+------------------------------+---------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`result of comparison against` |nbsp| |+----------------------------+| |nbsp| :diagtext:`is unspecified (use an explicit string comparison function instead)`| +| ||:diagtext:`a string literal`|| | +| |+----------------------------+| | +| ||:diagtext:`@encode` || | +| |+----------------------------+| | ++---------------------------------------------------------------------------+------------------------------+---------------------------------------------------------------------------------------+ -Wstring-conversion @@ -9896,6 +11778,24 @@ This diagnostic is enabled by default. +--------------------------------------------------------------------------------------------------------------------------------+ +-Wsuspicious-bzero +------------------ +This diagnostic is enabled by default. + +**Diagnostic text:** + ++----------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`'size' argument to bzero is '0'`| ++----------------------------------------------------------------------+ + + +-Wsuspicious-memaccess +---------------------- +This diagnostic is enabled by default. + +Controls `-Wdynamic-class-memaccess`_, `-Wmemset-transposed-args`_, `-Wnontrivial-memaccess`_, `-Wsizeof-pointer-memaccess`_, `-Wsuspicious-bzero`_. + + -Wswitch -------- This diagnostic is enabled by default. @@ -9906,25 +11806,25 @@ This diagnostic is enabled by default. |:warning:`warning:` |nbsp| :diagtext:`overflow converting case value to switch condition type (`:placeholder:`A` |nbsp| :diagtext:`to` |nbsp| :placeholder:`B`:diagtext:`)`| +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -+---------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| |+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| -| ||+-----------------------------------------------------------------------------------------------+ || -| |||:diagtext:`:enumeration value` |nbsp| :placeholder:`B` |nbsp| :diagtext:`not handled in switch`| || -| ||+-----------------------------------------------------------------------------------------------+ || -| |+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| -| ||+-----------------------------------------------------------------------------------------------------------------------------------------------+ || -| |||:diagtext:`:enumeration values` |nbsp| :placeholder:`B` |nbsp| :diagtext:`and` |nbsp| :placeholder:`C` |nbsp| :diagtext:`not handled in switch`| || -| ||+-----------------------------------------------------------------------------------------------------------------------------------------------+ || -| |+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| -| ||+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ || -| |||:diagtext:`:enumeration values` |nbsp| :placeholder:`B`:diagtext:`,` |nbsp| :placeholder:`C`:diagtext:`, and` |nbsp| :placeholder:`D` |nbsp| :diagtext:`not handled in switch`| || -| ||+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ || -| |+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| -| ||+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+|| -| |||:diagtext:`:`:placeholder:`A` |nbsp| :diagtext:`enumeration values not handled in switch:` |nbsp| :placeholder:`B`:diagtext:`,` |nbsp| :placeholder:`C`:diagtext:`,` |nbsp| :placeholder:`D`:diagtext:`...`||| -| ||+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+|| -| |+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| -+---------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ ++---------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| |+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| +| ||+----------------------------------------------------------------------------------------------+ || +| |||:diagtext:`enumeration value` |nbsp| :placeholder:`B` |nbsp| :diagtext:`not handled in switch`| || +| ||+----------------------------------------------------------------------------------------------+ || +| |+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| +| ||+----------------------------------------------------------------------------------------------------------------------------------------------+ || +| |||:diagtext:`enumeration values` |nbsp| :placeholder:`B` |nbsp| :diagtext:`and` |nbsp| :placeholder:`C` |nbsp| :diagtext:`not handled in switch`| || +| ||+----------------------------------------------------------------------------------------------------------------------------------------------+ || +| |+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| +| ||+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ || +| |||:diagtext:`enumeration values` |nbsp| :placeholder:`B`:diagtext:`,` |nbsp| :placeholder:`C`:diagtext:`, and` |nbsp| :placeholder:`D` |nbsp| :diagtext:`not handled in switch`| || +| ||+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ || +| |+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| +| ||+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+|| +| |||:placeholder:`A` |nbsp| :diagtext:`enumeration values not handled in switch:` |nbsp| :placeholder:`B`:diagtext:`,` |nbsp| :placeholder:`C`:diagtext:`,` |nbsp| :placeholder:`D`:diagtext:`...`||| +| ||+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+|| +| |+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| ++---------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`case value not in enumerated type` |nbsp| :placeholder:`A`| @@ -9950,25 +11850,25 @@ This diagnostic flag exists for GCC compatibility, and has no effect in Clang. ------------- **Diagnostic text:** -+---------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| |+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| -| ||+----------------------------------------------------------------------------------------------------------+ || -| |||:diagtext:`:enumeration value` |nbsp| :placeholder:`B` |nbsp| :diagtext:`not explicitly handled in switch`| || -| ||+----------------------------------------------------------------------------------------------------------+ || -| |+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| -| ||+----------------------------------------------------------------------------------------------------------------------------------------------------------+ || -| |||:diagtext:`:enumeration values` |nbsp| :placeholder:`B` |nbsp| :diagtext:`and` |nbsp| :placeholder:`C` |nbsp| :diagtext:`not explicitly handled in switch`| || -| ||+----------------------------------------------------------------------------------------------------------------------------------------------------------+ || -| |+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| -| ||+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ || -| |||:diagtext:`:enumeration values` |nbsp| :placeholder:`B`:diagtext:`,` |nbsp| :placeholder:`C`:diagtext:`, and` |nbsp| :placeholder:`D` |nbsp| :diagtext:`not explicitly handled in switch`| || -| ||+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ || -| |+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| -| ||+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+|| -| |||:diagtext:`:`:placeholder:`A` |nbsp| :diagtext:`enumeration values not explicitly handled in switch:` |nbsp| :placeholder:`B`:diagtext:`,` |nbsp| :placeholder:`C`:diagtext:`,` |nbsp| :placeholder:`D`:diagtext:`...`||| -| ||+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+|| -| |+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| -+---------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ ++---------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| |+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| +| ||+---------------------------------------------------------------------------------------------------------+ || +| |||:diagtext:`enumeration value` |nbsp| :placeholder:`B` |nbsp| :diagtext:`not explicitly handled in switch`| || +| ||+---------------------------------------------------------------------------------------------------------+ || +| |+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| +| ||+---------------------------------------------------------------------------------------------------------------------------------------------------------+ || +| |||:diagtext:`enumeration values` |nbsp| :placeholder:`B` |nbsp| :diagtext:`and` |nbsp| :placeholder:`C` |nbsp| :diagtext:`not explicitly handled in switch`| || +| ||+---------------------------------------------------------------------------------------------------------------------------------------------------------+ || +| |+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| +| ||+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ || +| |||:diagtext:`enumeration values` |nbsp| :placeholder:`B`:diagtext:`,` |nbsp| :placeholder:`C`:diagtext:`, and` |nbsp| :placeholder:`D` |nbsp| :diagtext:`not explicitly handled in switch`| || +| ||+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ || +| |+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| +| ||+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+|| +| |||:placeholder:`A` |nbsp| :diagtext:`enumeration values not explicitly handled in switch:` |nbsp| :placeholder:`B`:diagtext:`,` |nbsp| :placeholder:`C`:diagtext:`,` |nbsp| :placeholder:`D`:diagtext:`...`||| +| ||+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+|| +| |+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| ++---------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -Wsync-fetch-and-nand-semantics-changed @@ -9986,24 +11886,10 @@ This diagnostic is enabled by default. ------- This diagnostic flag exists for GCC compatibility, and has no effect in Clang. --Wtautological-compare ----------------------- -Some of the diagnostics controlled by this flag are enabled by default. - -Also controls `-Wtautological-constant-compare`_, `-Wtautological-overlap-compare`_, `-Wtautological-pointer-compare`_, `-Wtautological-undefined-compare`_. - +-Wtautological-bitwise-compare +------------------------------ **Diagnostic text:** -+---------------------------+---------------------------+--------------------------------------------------+------------------------+ -|:warning:`warning:` |nbsp| |+-------------------------+|:diagtext:`comparison always evaluates to` |nbsp| |+----------------------+| -| ||:diagtext:`self-` || ||:diagtext:`false` || -| |+-------------------------+| |+----------------------+| -| ||:diagtext:`array` |nbsp| || ||:diagtext:`true` || -| |+-------------------------+| |+----------------------+| -| | | ||:diagtext:`a constant`|| -| | | |+----------------------+| -+---------------------------+---------------------------+--------------------------------------------------+------------------------+ - +-------------------------------------------------------------------------------------+-------------------+ |:warning:`warning:` |nbsp| :diagtext:`bitwise comparison always evaluates to` |nbsp| |+-----------------+| | ||:diagtext:`false`|| @@ -10012,22 +11898,76 @@ Also controls `-Wtautological-constant-compare`_, `-Wtautological-overlap-compar | |+-----------------+| +-------------------------------------------------------------------------------------+-------------------+ ++----------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`bitwise or with non-zero value always evaluates to true`| ++----------------------------------------------------------------------------------------------+ + + +-Wtautological-compare +---------------------- +Some of the diagnostics controlled by this flag are enabled by default. + +Also controls `-Wtautological-bitwise-compare`_, `-Wtautological-constant-compare`_, `-Wtautological-objc-bool-compare`_, `-Wtautological-overlap-compare`_, `-Wtautological-pointer-compare`_, `-Wtautological-undefined-compare`_. + +**Diagnostic text:** + ++---------------------------+---------------------------------------------------------------+----------------------------------------+-------------------------+ +|:warning:`warning:` |nbsp| |+-------------------------------------------------------------+| |nbsp| :diagtext:`to 1 byte is` |nbsp| |+-----------------------+| +| ||:diagtext:`aligning a value` || ||:diagtext:`a no-op` || +| |+-------------------------------------------------------------+| |+-----------------------+| +| ||:diagtext:`the result of checking whether a value is aligned`|| ||:diagtext:`always true`|| +| |+-------------------------------------------------------------+| |+-----------------------+| ++---------------------------+---------------------------------------------------------------+----------------------------------------+-------------------------+ + ++---------------------------+---------------------------+--------------------------------------------------+--------------------------------------------+ +|:warning:`warning:` |nbsp| |+-------------------------+|:diagtext:`comparison always evaluates to` |nbsp| |+------------------------------------------+| +| ||:diagtext:`self-` || ||:diagtext:`a constant` || +| |+-------------------------+| |+------------------------------------------+| +| ||:diagtext:`array` |nbsp| || ||:diagtext:`true` || +| |+-------------------------+| |+------------------------------------------+| +| | | ||:diagtext:`false` || +| | | |+------------------------------------------+| +| | | ||:diagtext:`'std::strong\_ordering::equal'`|| +| | | |+------------------------------------------+| ++---------------------------+---------------------------+--------------------------------------------------+--------------------------------------------+ + -Wtautological-constant-compare ------------------------------- This diagnostic is enabled by default. -Also controls `-Wtautological-constant-out-of-range-compare`_, `-Wtautological-unsigned-enum-zero-compare`_, `-Wtautological-unsigned-zero-compare`_. +Also controls `-Wtautological-constant-out-of-range-compare`_. **Diagnostic text:** -+---------------------------------------------------------+------------------+--------------------------------+------------------+-------------------------------------+-------------------+ -|:warning:`warning:` |nbsp| :diagtext:`comparison` |nbsp| |+----------------+| |nbsp| :placeholder:`C` |nbsp| |+----------------+| |nbsp| :diagtext:`is always` |nbsp| |+-----------------+| -| ||:placeholder:`D`|| ||:placeholder:`B`|| ||:diagtext:`false`|| -| |+----------------+| |+----------------+| |+-----------------+| -| ||:placeholder:`B`|| ||:placeholder:`D`|| ||:diagtext:`true` || -| |+----------------+| |+----------------+| |+-----------------+| -+---------------------------------------------------------+------------------+--------------------------------+------------------+-------------------------------------+-------------------+ ++-----------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`converting the result of '?:' with integer constants to a boolean always evaluates to 'true'`| ++-----------------------------------------------------------------------------------------------------------------------------------+ + ++-------------------------------------------------------------------------------------------------------------+-------------------+ +|:warning:`warning:` |nbsp| :diagtext:`converting the result of '<<' to a boolean always evaluates to` |nbsp| |+-----------------+| +| ||:diagtext:`false`|| +| |+-----------------+| +| ||:diagtext:`true` || +| |+-----------------+| ++-------------------------------------------------------------------------------------------------------------+-------------------+ + ++----------------------------------------------------------------------+------------------------------------------------+--------------------------------+----------------------------------------------------------+-----------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`result of comparison of` |nbsp| |+----------------------------------------------+| |nbsp| :diagtext:`with` |nbsp| |+--------------------------------------------------------+| |nbsp| :diagtext:`is always` |nbsp| :placeholder:`E`| +| ||+--------------------------------------------+|| ||+------------------------------------------------------+|| | +| |||:diagtext:`constant` |nbsp| :placeholder:`A`||| |||:diagtext:`expression of type` |nbsp| :placeholder:`C`||| | +| ||+--------------------------------------------+|| ||+------------------------------------------------------+|| | +| |+----------------------------------------------+| |+--------------------------------------------------------+| | +| ||:diagtext:`true` || ||:diagtext:`boolean expression` || | +| |+----------------------------------------------+| |+--------------------------------------------------------+| | +| ||:diagtext:`false` || | | | +| |+----------------------------------------------+| | | | ++----------------------------------------------------------------------+------------------------------------------------+--------------------------------+----------------------------------------------------------+-----------------------------------------------------+ + + +-Wtautological-constant-in-range-compare +---------------------------------------- +Controls `-Wtautological-type-limit-compare`_, `-Wtautological-unsigned-enum-zero-compare`_, `-Wtautological-unsigned-zero-compare`_. -Wtautological-constant-out-of-range-compare @@ -10036,17 +11976,28 @@ This diagnostic is enabled by default. **Diagnostic text:** -+------------------------------------------------------------+------------------------------------------------+--------------------------------+----------------------------------------------------------+-------------------------------------+-------------------+ -|:warning:`warning:` |nbsp| :diagtext:`comparison of` |nbsp| |+----------------------------------------------+| |nbsp| :diagtext:`with` |nbsp| |+--------------------------------------------------------+| |nbsp| :diagtext:`is always` |nbsp| |+-----------------+| -| ||+--------------------------------------------+|| ||+------------------------------------------------------+|| ||:diagtext:`false`|| -| |||:diagtext:`constant` |nbsp| :placeholder:`A`||| |||:diagtext:`expression of type` |nbsp| :placeholder:`C`||| |+-----------------+| -| ||+--------------------------------------------+|| ||+------------------------------------------------------+|| ||:diagtext:`true` || -| |+----------------------------------------------+| |+--------------------------------------------------------+| |+-----------------+| -| ||:diagtext:`true` || ||:diagtext:`boolean expression` || | | -| |+----------------------------------------------+| |+--------------------------------------------------------+| | | -| ||:diagtext:`false` || | | | | -| |+----------------------------------------------+| | | | | -+------------------------------------------------------------+------------------------------------------------+--------------------------------+----------------------------------------------------------+-------------------------------------+-------------------+ ++----------------------------------------------------------------------+------------------------------------------------+--------------------------------+----------------------------------------------------------+-----------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`result of comparison of` |nbsp| |+----------------------------------------------+| |nbsp| :diagtext:`with` |nbsp| |+--------------------------------------------------------+| |nbsp| :diagtext:`is always` |nbsp| :placeholder:`E`| +| ||+--------------------------------------------+|| ||+------------------------------------------------------+|| | +| |||:diagtext:`constant` |nbsp| :placeholder:`A`||| |||:diagtext:`expression of type` |nbsp| :placeholder:`C`||| | +| ||+--------------------------------------------+|| ||+------------------------------------------------------+|| | +| |+----------------------------------------------+| |+--------------------------------------------------------+| | +| ||:diagtext:`true` || ||:diagtext:`boolean expression` || | +| |+----------------------------------------------+| |+--------------------------------------------------------+| | +| ||:diagtext:`false` || | | | +| |+----------------------------------------------+| | | | ++----------------------------------------------------------------------+------------------------------------------------+--------------------------------+----------------------------------------------------------+-----------------------------------------------------+ + + +-Wtautological-objc-bool-compare +-------------------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`result of comparison of constant` |nbsp| :placeholder:`A` |nbsp| :diagtext:`with expression of type 'BOOL' is always` |nbsp| :placeholder:`B`:diagtext:`, as the only well defined values for 'BOOL' are YES and NO`| ++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -Wtautological-overlap-compare @@ -10087,6 +12038,19 @@ This diagnostic is enabled by default. +------------------------------------------------------------+------------------------+----------------------------------------------------------+-------------------------+-----------------------------------------------------+-------------------+ +-Wtautological-type-limit-compare +--------------------------------- +**Diagnostic text:** + ++-------------------------------------------------------------------+------------------+--------------------------------+------------------+-----------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`result of comparison` |nbsp| |+----------------+| |nbsp| :placeholder:`C` |nbsp| |+----------------+| |nbsp| :diagtext:`is always` |nbsp| :placeholder:`E`| +| ||:placeholder:`D`|| ||:placeholder:`B`|| | +| |+----------------+| |+----------------+| | +| ||:placeholder:`B`|| ||:placeholder:`D`|| | +| |+----------------+| |+----------------+| | ++-------------------------------------------------------------------+------------------+--------------------------------+------------------+-----------------------------------------------------+ + + -Wtautological-undefined-compare -------------------------------- This diagnostic is enabled by default. @@ -10112,32 +12076,28 @@ This diagnostic is enabled by default. -Wtautological-unsigned-enum-zero-compare ----------------------------------------- -This diagnostic is enabled by default. - **Diagnostic text:** -+------------------------------------------------------------+--------------------------------------+--------------------------------+--------------------------------------+-------------------------------------+-------------------+ -|:warning:`warning:` |nbsp| :diagtext:`comparison of` |nbsp| |+------------------------------------+| |nbsp| :placeholder:`C` |nbsp| |+------------------------------------+| |nbsp| :diagtext:`is always` |nbsp| |+-----------------+| -| ||:placeholder:`D` || ||:diagtext:`unsigned enum expression`|| ||:diagtext:`false`|| -| |+------------------------------------+| |+------------------------------------+| |+-----------------+| -| ||:diagtext:`unsigned enum expression`|| ||:placeholder:`D` || ||:diagtext:`true` || -| |+------------------------------------+| |+------------------------------------+| |+-----------------+| -+------------------------------------------------------------+--------------------------------------+--------------------------------+--------------------------------------+-------------------------------------+-------------------+ ++----------------------------------------------------------------------+--------------------------------------+--------------------------------+--------------------------------------+-----------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`result of comparison of` |nbsp| |+------------------------------------+| |nbsp| :placeholder:`C` |nbsp| |+------------------------------------+| |nbsp| :diagtext:`is always` |nbsp| :placeholder:`E`| +| ||:placeholder:`D` || ||:diagtext:`unsigned enum expression`|| | +| |+------------------------------------+| |+------------------------------------+| | +| ||:diagtext:`unsigned enum expression`|| ||:placeholder:`D` || | +| |+------------------------------------+| |+------------------------------------+| | ++----------------------------------------------------------------------+--------------------------------------+--------------------------------+--------------------------------------+-----------------------------------------------------+ -Wtautological-unsigned-zero-compare ------------------------------------ -This diagnostic is enabled by default. - **Diagnostic text:** -+------------------------------------------------------------+---------------------------------+--------------------------------+---------------------------------+-------------------------------------+-------------------+ -|:warning:`warning:` |nbsp| :diagtext:`comparison of` |nbsp| |+-------------------------------+| |nbsp| :placeholder:`C` |nbsp| |+-------------------------------+| |nbsp| :diagtext:`is always` |nbsp| |+-----------------+| -| ||:placeholder:`D` || ||:diagtext:`unsigned expression`|| ||:diagtext:`false`|| -| |+-------------------------------+| |+-------------------------------+| |+-----------------+| -| ||:diagtext:`unsigned expression`|| ||:placeholder:`D` || ||:diagtext:`true` || -| |+-------------------------------+| |+-------------------------------+| |+-----------------+| -+------------------------------------------------------------+---------------------------------+--------------------------------+---------------------------------+-------------------------------------+-------------------+ ++----------------------------------------------------------------------+---------------------------------+--------------------------------+---------------------------------+-----------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`result of comparison of` |nbsp| |+-------------------------------+| |nbsp| :placeholder:`C` |nbsp| |+-------------------------------+| |nbsp| :diagtext:`is always` |nbsp| :placeholder:`E`| +| ||:placeholder:`D` || ||:diagtext:`unsigned expression`|| | +| |+-------------------------------+| |+-------------------------------+| | +| ||:diagtext:`unsigned expression`|| ||:placeholder:`D` || | +| |+-------------------------------+| |+-------------------------------+| | ++----------------------------------------------------------------------+---------------------------------+--------------------------------+---------------------------------+-----------------------------------------------------+ -Wtentative-definition-incomplete-type @@ -10188,17 +12148,17 @@ Controls `-Wthread-safety-analysis`_, `-Wthread-safety-attributes`_, `-Wthread-s |:warning:`warning:` |nbsp| :diagtext:`cannot call function '`:placeholder:`B`:diagtext:`' while` |nbsp| :placeholder:`A` |nbsp| :diagtext:`'`:placeholder:`C`:diagtext:`' is held`| +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -+---------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`calling function '`:placeholder:`B`:diagtext:`' requires holding` |nbsp| :placeholder:`A` |nbsp| |+--------------------------------------------------------+| -| ||+------------------------------------------+ || -| |||:diagtext:`'`:placeholder:`C`:diagtext:`'`| || -| ||+------------------------------------------+ || -| |+--------------------------------------------------------+| -| ||+------------------------------------------------------+|| -| |||:diagtext:`'`:placeholder:`C`:diagtext:`' exclusively`||| -| ||+------------------------------------------------------+|| -| |+--------------------------------------------------------+| -+---------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ ++---------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`calling function` |nbsp| :placeholder:`B` |nbsp| :diagtext:`requires holding` |nbsp| :placeholder:`A` |nbsp| |+--------------------------------------------------------+| +| ||+------------------------------------------+ || +| |||:diagtext:`'`:placeholder:`C`:diagtext:`'`| || +| ||+------------------------------------------+ || +| |+--------------------------------------------------------+| +| ||+------------------------------------------------------+|| +| |||:diagtext:`'`:placeholder:`C`:diagtext:`' exclusively`||| +| ||+------------------------------------------------------+|| +| |+--------------------------------------------------------+| ++---------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ +--------------------------------------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`'`:placeholder:`B`:diagtext:`' is acquired exclusively and shared in the same scope`| @@ -10224,45 +12184,45 @@ Controls `-Wthread-safety-analysis`_, `-Wthread-safety-attributes`_, `-Wthread-s | |+---------------------+| |+---------------------+| | +----------------------------------------------------------------------------------------------------------------------------------------+-----------------------+--------------------------------------------+-----------------------+--------------------------+ -+---------------------------+---------------------+---------------------------------------------------------------------------------------------------+-----------------------------------+ -|:warning:`warning:` |nbsp| |+-------------------+| |nbsp| :diagtext:`the value pointed to by '`:placeholder:`A`:diagtext:`' requires holding` |nbsp| |+---------------------------------+| -| ||:diagtext:`reading`|| ||:diagtext:`any mutex` || -| |+-------------------+| |+---------------------------------+| -| ||:diagtext:`writing`|| ||:diagtext:`any mutex exclusively`|| -| |+-------------------+| |+---------------------------------+| -+---------------------------+---------------------+---------------------------------------------------------------------------------------------------+-----------------------------------+ - -+---------------------------+---------------------+---------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ -|:warning:`warning:` |nbsp| |+-------------------+| |nbsp| :diagtext:`the value pointed to by '`:placeholder:`B`:diagtext:`' requires holding` |nbsp| :placeholder:`A` |nbsp| |+--------------------------------------------------------+| -| ||:diagtext:`reading`|| ||+------------------------------------------+ || -| |+-------------------+| |||:diagtext:`'`:placeholder:`C`:diagtext:`'`| || -| ||:diagtext:`writing`|| ||+------------------------------------------+ || -| |+-------------------+| |+--------------------------------------------------------+| -| | | ||+------------------------------------------------------+|| -| | | |||:diagtext:`'`:placeholder:`C`:diagtext:`' exclusively`||| -| | | ||+------------------------------------------------------+|| -| | | |+--------------------------------------------------------+| -+---------------------------+---------------------+---------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ - -+---------------------------+---------------------+------------------------------------------------------------------------------------+-----------------------------------+ -|:warning:`warning:` |nbsp| |+-------------------+| |nbsp| :diagtext:`variable '`:placeholder:`A`:diagtext:`' requires holding` |nbsp| |+---------------------------------+| -| ||:diagtext:`reading`|| ||:diagtext:`any mutex` || -| |+-------------------+| |+---------------------------------+| -| ||:diagtext:`writing`|| ||:diagtext:`any mutex exclusively`|| -| |+-------------------+| |+---------------------------------+| -+---------------------------+---------------------+------------------------------------------------------------------------------------+-----------------------------------+ - -+---------------------------+---------------------+------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ -|:warning:`warning:` |nbsp| |+-------------------+| |nbsp| :diagtext:`variable '`:placeholder:`B`:diagtext:`' requires holding` |nbsp| :placeholder:`A` |nbsp| |+--------------------------------------------------------+| -| ||:diagtext:`reading`|| ||+------------------------------------------+ || -| |+-------------------+| |||:diagtext:`'`:placeholder:`C`:diagtext:`'`| || -| ||:diagtext:`writing`|| ||+------------------------------------------+ || -| |+-------------------+| |+--------------------------------------------------------+| -| | | ||+------------------------------------------------------+|| -| | | |||:diagtext:`'`:placeholder:`C`:diagtext:`' exclusively`||| -| | | ||+------------------------------------------------------+|| -| | | |+--------------------------------------------------------+| -+---------------------------+---------------------+------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ ++---------------------------+---------------------+---------------------------------------------------------------------------------------------------------------+-----------------------------------+ +|:warning:`warning:` |nbsp| |+-------------------+| |nbsp| :diagtext:`the value pointed to by` |nbsp| :placeholder:`A` |nbsp| :diagtext:`requires holding` |nbsp| |+---------------------------------+| +| ||:diagtext:`reading`|| ||:diagtext:`any mutex` || +| |+-------------------+| |+---------------------------------+| +| ||:diagtext:`writing`|| ||:diagtext:`any mutex exclusively`|| +| |+-------------------+| |+---------------------------------+| ++---------------------------+---------------------+---------------------------------------------------------------------------------------------------------------+-----------------------------------+ + ++---------------------------+---------------------+---------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ +|:warning:`warning:` |nbsp| |+-------------------+| |nbsp| :diagtext:`the value pointed to by` |nbsp| :placeholder:`B` |nbsp| :diagtext:`requires holding` |nbsp| :placeholder:`A` |nbsp| |+--------------------------------------------------------+| +| ||:diagtext:`reading`|| ||+------------------------------------------+ || +| |+-------------------+| |||:diagtext:`'`:placeholder:`C`:diagtext:`'`| || +| ||:diagtext:`writing`|| ||+------------------------------------------+ || +| |+-------------------+| |+--------------------------------------------------------+| +| | | ||+------------------------------------------------------+|| +| | | |||:diagtext:`'`:placeholder:`C`:diagtext:`' exclusively`||| +| | | ||+------------------------------------------------------+|| +| | | |+--------------------------------------------------------+| ++---------------------------+---------------------+---------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ + ++---------------------------+---------------------+------------------------------------------------------------------------------------------------+-----------------------------------+ +|:warning:`warning:` |nbsp| |+-------------------+| |nbsp| :diagtext:`variable` |nbsp| :placeholder:`A` |nbsp| :diagtext:`requires holding` |nbsp| |+---------------------------------+| +| ||:diagtext:`reading`|| ||:diagtext:`any mutex` || +| |+-------------------+| |+---------------------------------+| +| ||:diagtext:`writing`|| ||:diagtext:`any mutex exclusively`|| +| |+-------------------+| |+---------------------------------+| ++---------------------------+---------------------+------------------------------------------------------------------------------------------------+-----------------------------------+ + ++---------------------------+---------------------+------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ +|:warning:`warning:` |nbsp| |+-------------------+| |nbsp| :diagtext:`variable` |nbsp| :placeholder:`B` |nbsp| :diagtext:`requires holding` |nbsp| :placeholder:`A` |nbsp| |+--------------------------------------------------------+| +| ||:diagtext:`reading`|| ||+------------------------------------------+ || +| |+-------------------+| |||:diagtext:`'`:placeholder:`C`:diagtext:`'`| || +| ||:diagtext:`writing`|| ||+------------------------------------------+ || +| |+-------------------+| |+--------------------------------------------------------+| +| | | ||+------------------------------------------------------+|| +| | | |||:diagtext:`'`:placeholder:`C`:diagtext:`' exclusively`||| +| | | ||+------------------------------------------------------+|| +| | | |+--------------------------------------------------------+| ++---------------------------+---------------------+------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ -Wthread-safety-attributes @@ -10289,6 +12249,14 @@ Controls `-Wthread-safety-analysis`_, `-Wthread-safety-attributes`_, `-Wthread-s |:warning:`warning:` |nbsp| :diagtext:`ignoring` |nbsp| :placeholder:`A` |nbsp| :diagtext:`attribute because its argument is invalid`| +------------------------------------------------------------------------------------------------------------------------------------+ ++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`attribute without capability arguments refers to 'this', but` |nbsp| :placeholder:`B` |nbsp| :diagtext:`isn't annotated with 'capability' or 'scoped\_lockable' attribute`| ++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + ++----------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`attribute without capability arguments can only be applied to non-static methods of a class`| ++----------------------------------------------------------------------------------------------------------------------------------------------------------+ + -Wthread-safety-beta -------------------- @@ -10312,70 +12280,70 @@ Controls `-Wthread-safety-analysis`_, `-Wthread-safety-attributes`_, `-Wthread-s ----------------------- **Diagnostic text:** -+---------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`calling function '`:placeholder:`B`:diagtext:`' requires holding` |nbsp| :placeholder:`A` |nbsp| |+--------------------------------------------------------+| -| ||+------------------------------------------+ || -| |||:diagtext:`'`:placeholder:`C`:diagtext:`'`| || -| ||+------------------------------------------+ || -| |+--------------------------------------------------------+| -| ||+------------------------------------------------------+|| -| |||:diagtext:`'`:placeholder:`C`:diagtext:`' exclusively`||| -| ||+------------------------------------------------------+|| -| |+--------------------------------------------------------+| -+---------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ - -+---------------------------+---------------------+---------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ -|:warning:`warning:` |nbsp| |+-------------------+| |nbsp| :diagtext:`the value pointed to by '`:placeholder:`B`:diagtext:`' requires holding` |nbsp| :placeholder:`A` |nbsp| |+--------------------------------------------------------+| -| ||:diagtext:`reading`|| ||+------------------------------------------+ || -| |+-------------------+| |||:diagtext:`'`:placeholder:`C`:diagtext:`'`| || -| ||:diagtext:`writing`|| ||+------------------------------------------+ || -| |+-------------------+| |+--------------------------------------------------------+| -| | | ||+------------------------------------------------------+|| -| | | |||:diagtext:`'`:placeholder:`C`:diagtext:`' exclusively`||| -| | | ||+------------------------------------------------------+|| -| | | |+--------------------------------------------------------+| -+---------------------------+---------------------+---------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ - -+---------------------------+---------------------+------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ -|:warning:`warning:` |nbsp| |+-------------------+| |nbsp| :diagtext:`variable '`:placeholder:`B`:diagtext:`' requires holding` |nbsp| :placeholder:`A` |nbsp| |+--------------------------------------------------------+| -| ||:diagtext:`reading`|| ||+------------------------------------------+ || -| |+-------------------+| |||:diagtext:`'`:placeholder:`C`:diagtext:`'`| || -| ||:diagtext:`writing`|| ||+------------------------------------------+ || -| |+-------------------+| |+--------------------------------------------------------+| -| | | ||+------------------------------------------------------+|| -| | | |||:diagtext:`'`:placeholder:`C`:diagtext:`' exclusively`||| -| | | ||+------------------------------------------------------+|| -| | | |+--------------------------------------------------------+| -+---------------------------+---------------------+------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ ++---------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`calling function` |nbsp| :placeholder:`B` |nbsp| :diagtext:`requires holding` |nbsp| :placeholder:`A` |nbsp| |+--------------------------------------------------------+| +| ||+------------------------------------------+ || +| |||:diagtext:`'`:placeholder:`C`:diagtext:`'`| || +| ||+------------------------------------------+ || +| |+--------------------------------------------------------+| +| ||+------------------------------------------------------+|| +| |||:diagtext:`'`:placeholder:`C`:diagtext:`' exclusively`||| +| ||+------------------------------------------------------+|| +| |+--------------------------------------------------------+| ++---------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ + ++---------------------------+---------------------+---------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ +|:warning:`warning:` |nbsp| |+-------------------+| |nbsp| :diagtext:`the value pointed to by` |nbsp| :placeholder:`B` |nbsp| :diagtext:`requires holding` |nbsp| :placeholder:`A` |nbsp| |+--------------------------------------------------------+| +| ||:diagtext:`reading`|| ||+------------------------------------------+ || +| |+-------------------+| |||:diagtext:`'`:placeholder:`C`:diagtext:`'`| || +| ||:diagtext:`writing`|| ||+------------------------------------------+ || +| |+-------------------+| |+--------------------------------------------------------+| +| | | ||+------------------------------------------------------+|| +| | | |||:diagtext:`'`:placeholder:`C`:diagtext:`' exclusively`||| +| | | ||+------------------------------------------------------+|| +| | | |+--------------------------------------------------------+| ++---------------------------+---------------------+---------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ + ++---------------------------+---------------------+------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ +|:warning:`warning:` |nbsp| |+-------------------+| |nbsp| :diagtext:`variable` |nbsp| :placeholder:`B` |nbsp| :diagtext:`requires holding` |nbsp| :placeholder:`A` |nbsp| |+--------------------------------------------------------+| +| ||:diagtext:`reading`|| ||+------------------------------------------+ || +| |+-------------------+| |||:diagtext:`'`:placeholder:`C`:diagtext:`'`| || +| ||:diagtext:`writing`|| ||+------------------------------------------+ || +| |+-------------------+| |+--------------------------------------------------------+| +| | | ||+------------------------------------------------------+|| +| | | |||:diagtext:`'`:placeholder:`C`:diagtext:`' exclusively`||| +| | | ||+------------------------------------------------------+|| +| | | |+--------------------------------------------------------+| ++---------------------------+---------------------+------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ -Wthread-safety-reference ------------------------- **Diagnostic text:** -+----------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`passing variable '`:placeholder:`B`:diagtext:`' by reference requires holding` |nbsp| :placeholder:`A` |nbsp| |+--------------------------------------------------------+| -| ||+------------------------------------------+ || -| |||:diagtext:`'`:placeholder:`C`:diagtext:`'`| || -| ||+------------------------------------------+ || -| |+--------------------------------------------------------+| -| ||+------------------------------------------------------+|| -| |||:diagtext:`'`:placeholder:`C`:diagtext:`' exclusively`||| -| ||+------------------------------------------------------+|| -| |+--------------------------------------------------------+| -+----------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ - -+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`passing the value that '`:placeholder:`B`:diagtext:`' points to by reference requires holding` |nbsp| :placeholder:`A` |nbsp| |+--------------------------------------------------------+| -| ||+------------------------------------------+ || -| |||:diagtext:`'`:placeholder:`C`:diagtext:`'`| || -| ||+------------------------------------------+ || -| |+--------------------------------------------------------+| -| ||+------------------------------------------------------+|| -| |||:diagtext:`'`:placeholder:`C`:diagtext:`' exclusively`||| -| ||+------------------------------------------------------+|| -| |+--------------------------------------------------------+| -+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ ++----------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`passing variable` |nbsp| :placeholder:`B` |nbsp| :diagtext:`by reference requires holding` |nbsp| :placeholder:`A` |nbsp| |+--------------------------------------------------------+| +| ||+------------------------------------------+ || +| |||:diagtext:`'`:placeholder:`C`:diagtext:`'`| || +| ||+------------------------------------------+ || +| |+--------------------------------------------------------+| +| ||+------------------------------------------------------+|| +| |||:diagtext:`'`:placeholder:`C`:diagtext:`' exclusively`||| +| ||+------------------------------------------------------+|| +| |+--------------------------------------------------------+| ++----------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ + ++--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`passing the value that` |nbsp| :placeholder:`B` |nbsp| :diagtext:`points to by reference requires holding` |nbsp| :placeholder:`A` |nbsp| |+--------------------------------------------------------+| +| ||+------------------------------------------+ || +| |||:diagtext:`'`:placeholder:`C`:diagtext:`'`| || +| ||+------------------------------------------+ || +| |+--------------------------------------------------------+| +| ||+------------------------------------------------------+|| +| |||:diagtext:`'`:placeholder:`C`:diagtext:`' exclusively`||| +| ||+------------------------------------------------------+|| +| |+--------------------------------------------------------+| ++--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ -Wthread-safety-verbose @@ -10412,7 +12380,13 @@ This diagnostic is enabled by default. -Wtype-limits ------------- -This diagnostic flag exists for GCC compatibility, and has no effect in Clang. +Synonym for `-Wtautological-constant-in-range-compare`_. + + +-Wtype-limits +------------- +Synonym for `-Wtautological-constant-in-range-compare`_. + -Wtype-safety ------------- @@ -10592,6 +12566,17 @@ This diagnostic is enabled by default. +---------------------------------------------------------------------------------------------------------------------------------------------------------+ +-Wunderaligned-exception-object +------------------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++---------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`underaligned exception object thrown`| ++---------------------------------------------------------------------------+ + + -Wunevaluated-expression ------------------------ This diagnostic is enabled by default. @@ -10656,6 +12641,17 @@ This diagnostic is enabled by default. +---------------------------------------------------------------------------------------------+ +-Wunicode-homoglyph +------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`treating Unicode character as identifier character rather than as '`:placeholder:`B`:diagtext:`' symbol`| ++-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + + -Wunicode-whitespace -------------------- This diagnostic is enabled by default. @@ -10667,6 +12663,17 @@ This diagnostic is enabled by default. +-------------------------------------------------------------------------------+ +-Wunicode-zero-width +-------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++----------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`identifier contains Unicode character that is invisible in some environments`| ++----------------------------------------------------------------------------------------------------------------------------------------------------+ + + -Wuninitialized --------------- Some of the diagnostics controlled by this flag are enabled by default. @@ -10687,9 +12694,13 @@ Also controls `-Wsometimes-uninitialized`_, `-Wstatic-self-init`_. |:warning:`warning:` |nbsp| :diagtext:`reference` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is not yet bound to a value when used here`| +--------------------------------------------------------------------------------------------------------------------------------------+ -+------------------------------------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`block pointer variable` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is uninitialized when captured by block`| -+------------------------------------------------------------------------------------------------------------------------------------------------+ ++-------------------------------------------------------------------------------------------------------------------+---------------------------+------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`block pointer variable` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is` |nbsp| |+-------------------------+| |nbsp| :diagtext:`when captured by block`| +| ||:diagtext:`uninitialized`|| | +| |+-------------------------+| | +| ||:diagtext:`null` || | +| |+-------------------------+| | ++-------------------------------------------------------------------------------------------------------------------+---------------------------+------------------------------------------+ +---------------------------------------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`variable` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is uninitialized when used within its own initialization`| @@ -10718,6 +12729,10 @@ This diagnostic is enabled by default. |:warning:`warning:` |nbsp| :diagtext:`unknown argument ignored in clang-cl: '`:placeholder:`A`:diagtext:`'`| +-----------------------------------------------------------------------------------------------------------+ ++--------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`unknown argument ignored in clang-cl '`:placeholder:`A`:diagtext:`'; did you mean '`:placeholder:`B`:diagtext:`'?`| ++--------------------------------------------------------------------------------------------------------------------------------------------------------+ + -Wunknown-attributes -------------------- @@ -10730,6 +12745,17 @@ This diagnostic is enabled by default. +-----------------------------------------------------------------------------------------------------------+ +-Wunknown-cuda-version +---------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++--------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`Unknown CUDA version` |nbsp| :placeholder:`A`:diagtext:`. Assuming the latest supported version` |nbsp| :placeholder:`B`| ++--------------------------------------------------------------------------------------------------------------------------------------------------------------+ + + -Wunknown-escape-sequence ------------------------- This diagnostic is enabled by default. @@ -10775,6 +12801,18 @@ Some of the diagnostics controlled by this flag are enabled by default. |:warning:`warning:` |nbsp| :diagtext:`unexpected token in pragma diagnostic`| +----------------------------------------------------------------------------+ ++----------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`#pragma execution\_character\_set expected '`:placeholder:`A`:diagtext:`'`| ++----------------------------------------------------------------------------------------------------------------+ + ++------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`#pragma execution\_character\_set invalid value '`:placeholder:`A`:diagtext:`', only 'UTF-8' is supported`| ++------------------------------------------------------------------------------------------------------------------------------------------------+ + ++-------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`#pragma execution\_character\_set expected 'push' or 'pop'`| ++-------------------------------------------------------------------------------------------------+ + +-------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`unknown pragma ignored`| +-------------------------------------------------------------+ @@ -11048,6 +13086,17 @@ This diagnostic is enabled by default. +-------------------------------------------------------------------------------------------------------------------------------------------------+ +-Wunsupported-target-opt +------------------------ +This diagnostic is enabled by default. + +**Diagnostic text:** + ++---------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`debug information option '`:placeholder:`A`:diagtext:`' is not supported for target '`:placeholder:`B`:diagtext:`'`| ++---------------------------------------------------------------------------------------------------------------------------------------------------------+ + + -Wunsupported-visibility ------------------------ This diagnostic is enabled by default. @@ -11131,6 +13180,10 @@ This diagnostic is enabled by default. |:warning:`warning:` |nbsp| :diagtext:`the flag '`:placeholder:`A`:diagtext:`' has been deprecated and will be ignored`| +----------------------------------------------------------------------------------------------------------------------+ ++--------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`ignoring -fdiscard-value-names for LLVM Bitcode`| ++--------------------------------------------------------------------------------------+ + -Wunused-comparison ------------------- @@ -11138,19 +13191,17 @@ This diagnostic is enabled by default. **Diagnostic text:** -+---------------------------+-----------------------------------------+--------------------------------------------+ -|:warning:`warning:` |nbsp| |+---------------------------------------+| |nbsp| :diagtext:`comparison result unused`| -| ||+----------------+--------------------+|| | -| |||+--------------+|:diagtext:`equality`||| | -| |||| || ||| | -| |||+--------------+| ||| | -| ||||:diagtext:`in`|| ||| | -| |||+--------------+| ||| | -| ||+----------------+--------------------+|| | -| |+---------------------------------------+| | -| ||:diagtext:`relational` || | -| |+---------------------------------------+| | -+---------------------------+-----------------------------------------+--------------------------------------------+ ++---------------------------+------------------------+--------------------------------------------+ +|:warning:`warning:` |nbsp| |+----------------------+| |nbsp| :diagtext:`comparison result unused`| +| ||:diagtext:`equality` || | +| |+----------------------+| | +| ||:diagtext:`inequality`|| | +| |+----------------------+| | +| ||:diagtext:`relational`|| | +| |+----------------------+| | +| ||:diagtext:`three-way` || | +| |+----------------------+| | ++---------------------------+------------------------+--------------------------------------------+ -Wunused-const-variable @@ -11290,6 +13341,10 @@ This diagnostic is enabled by default. |:warning:`warning:` |nbsp| :diagtext:`ignoring return value of function declared with` |nbsp| :placeholder:`A` |nbsp| :diagtext:`attribute`| +-------------------------------------------------------------------------------------------------------------------------------------------+ ++--------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`ignoring return value of function declared with` |nbsp| :placeholder:`A` |nbsp| :diagtext:`attribute:` |nbsp| :placeholder:`B`| ++--------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + -Wunused-template ----------------- @@ -11318,6 +13373,14 @@ Also controls `-Wunevaluated-expression`_, `-Wunused-comparison`_, `-Wunused-res |:warning:`warning:` |nbsp| :diagtext:`ignoring return value of function declared with` |nbsp| :placeholder:`A` |nbsp| :diagtext:`attribute`| +-------------------------------------------------------------------------------------------------------------------------------------------+ ++-----------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`ignoring temporary created by a constructor declared with` |nbsp| :placeholder:`A` |nbsp| :diagtext:`attribute`| ++-----------------------------------------------------------------------------------------------------------------------------------------------------+ + ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`ignoring temporary created by a constructor declared with` |nbsp| :placeholder:`A` |nbsp| :diagtext:`attribute:` |nbsp| :placeholder:`B`| ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + +----------------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`container access result unused - container access should not be used for side effects`| +----------------------------------------------------------------------------------------------------------------------------+ @@ -11572,6 +13635,25 @@ Also controls `-Wdeprecated-writable-strings`_. Synonym for `-Wwritable-strings`_. +-Wxor-used-as-pow +----------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++----------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`result of '`:placeholder:`A`:diagtext:`' is` |nbsp| :placeholder:`B`:diagtext:`; did you mean exponentiation?`| ++----------------------------------------------------------------------------------------------------------------------------------------------------+ + ++--------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`result of '`:placeholder:`A`:diagtext:`' is` |nbsp| :placeholder:`B`:diagtext:`; did you mean '`:placeholder:`C`:diagtext:`'?`| ++--------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`result of '`:placeholder:`A`:diagtext:`' is` |nbsp| :placeholder:`B`:diagtext:`; did you mean '`:placeholder:`C`:diagtext:`' (`:placeholder:`D`:diagtext:`)?`| ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + + -Wzero-as-null-pointer-constant ------------------------------- **Diagnostic text:** diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst index f1df9dd93f93d..456bcb305e3b9 100644 --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -122,7 +122,7 @@ of ``cxx_rvalue_references``. ``__has_cpp_attribute`` ----------------------- -This function-like macro is available in C++2a by default, and is provided as an +This function-like macro is available in C++20 by default, and is provided as an extension in earlier language standards. It takes a single argument that is the name of a double-square-bracket-style attribute. The argument can either be a single identifier or a scoped identifier. If the attribute is supported, a diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index e131e4f127803..a100d0a76b492 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -1,6 +1,6 @@ -======================================== -Clang 10.0.0 (In-Progress) Release Notes -======================================== +========================== +Clang 10.0.0 Release Notes +========================== .. contents:: :local: @@ -8,11 +8,6 @@ Clang 10.0.0 (In-Progress) Release Notes Written by the `LLVM Team `_ -.. warning:: - - These are in-progress notes for the upcoming Clang 10 release. - Release notes for previous releases can be found on - `the Download Page `_. Introduction ============ @@ -30,10 +25,6 @@ For more information about Clang or LLVM, including information about the latest release, please see the `Clang Web Site `_ or the `LLVM Web Site `_. -Note that if you are reading this file from a Subversion checkout or the -main Clang web page, this document applies to the *next* release, not -the current one. To see the release notes for a specific release, please -see the `releases page `_. What's New in Clang 10.0.0? =========================== @@ -46,28 +37,68 @@ sections with improvements to Clang's support for those languages. Major New Features ------------------ -- ... +- clang used to run the actual compilation in a subprocess ("clang -cc1"). + Now compilations are done in-process by default. ``-fno-integrated-cc1`` + restores the former behavior. The ``-v`` and ``-###`` flags will print + "(in-process)" when compilations are done in-process. + +- Concepts support. Clang now supports C++2a Concepts under the -std=c++2a flag. Improvements to Clang's diagnostics ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- -Wtautological-overlap-compare will warn on negative numbers and non-int +- ``-Wtautological-overlap-compare`` will warn on negative numbers and non-int types. -- -Wtautological-compare for self comparisons and - -Wtautological-overlap-compare will now look through member and array + +- ``-Wtautological-compare`` for self comparisons and + ``-Wtautological-overlap-compare`` will now look through member and array access to determine if two operand expressions are the same. -- -Wtautological-bitwise-compare is a new warning group. This group has the + +- ``-Wtautological-bitwise-compare`` is a new warning group. This group has the current warning which diagnoses the tautological comparison of a bitwise operation and a constant. The group also has the new warning which diagnoses when a bitwise-or with a non-negative value is converted to a bool, since that bool will always be true. -- -Wbitwise-conditional-parentheses will warn on operator precedence issues + +- ``-Wbitwise-conditional-parentheses`` will warn on operator precedence issues when mixing bitwise-and (&) and bitwise-or (|) operator with the conditional operator (?:). -- -Wrange-loop-analysis got several improvements. It no longer warns about a + +- ``-Wrange-loop-analysis`` got several improvements. It no longer warns about a copy being made when the result is bound to an rvalue reference. It no longer warns when an object of a small, trivially copyable type is copied. The - warning now offers fixits. It is now part of -Wall. + warning now offers fix-its. Excluding ``-Wrange-loop-bind-reference`` it is now + part of ``-Wall``. To reduce the number of false positives the diagnostic is + disabled in macros and template instantiations. + +- ``-Wmisleading-indentation`` has been added. This warning is similar to the GCC + warning of the same name. It warns about statements that are indented as if + they were part of a if/else/for/while statement but are not semantically + part of that if/else/for/while. + +- ``-Wbitwise-op-parentheses`` and ``-Wlogical-op-parentheses`` are disabled by default. + +- The new warnings ``-Wc99-designator`` and ``-Wreorder-init-list`` warn about + uses of C99 initializers in C++ mode for cases that are valid in C99 but not + in C++20. + +- The new warning ``-Wsizeof-array-div`` catches cases like + ``int arr[10]; ...sizeof(arr) / sizeof(short)...`` + (should be ``sizeof(arr) / sizeof(int)``), and the existing warning + ``-Wsizeof-pointer-div`` catches more cases. + +- The new warning ``-Wxor-used-as-pow`` warns on cases where it looks like + the xor operator ``^`` is used to be mean exponentiation, e.g. ``2 ^ 16``. + +- The new warning ``-Wfinal-dtor-non-final-class`` warns on classes that + have a final destructor but aren't themselves marked final. + +- ``-Wextra`` now enables ``-Wdeprecated-copy``. The warning deprecates + move and copy constructors in classes where an explicit destructor is + declared. This is for compatibility with GCC 9, and forward looking + for a change that's being considered for C++23. You can disable it with + ``-Wno-deprecated-copy``. + Non-comprehensive list of changes in this release ------------------------------------------------- @@ -86,28 +117,72 @@ Non-comprehensive list of changes in this release learned to sanitize pre/post increment/decrement of types with bit width smaller than ``int``. -- For X86 target, -march=skylake-avx512, -march=icelake-client, - -march=icelake-server, -march=cascadelake, -march=cooperlake will default to +* For X86 target, ``-march=skylake-avx512``, ``-march=icelake-client``, + ``-march=icelake-server``, ``-march=cascadelake``, ``-march=cooperlake`` will default to not using 512-bit zmm registers in vectorized code unless 512-bit intrinsics are used in the source code. 512-bit operations are known to cause the CPUs to run at a lower frequency which can impact performance. This behavior can be - changed by passing -mprefer-vector-width=512 on the command line. + changed by passing ``-mprefer-vector-width=512`` on the command line. -* clang now defaults to ``.init_array`` on Linux. It used to use ``.ctors`` if - the found gcc installation is older than 4.7.0. Add ``-fno-use-init-array`` to +* Clang now defaults to ``.init_array`` on Linux. It used to use ``.ctors`` if + the found GCC installation is older than 4.7.0. Add ``-fno-use-init-array`` to get the old behavior (``.ctors``). +* The behavior of the flag ``-flax-vector-conversions`` has been modified to + more closely match GCC, as described below. In Clang 10 onwards, command lines + specifying this flag do not permit implicit vector bitcasts between integer + vectors and floating-point vectors. Such conversions are still permitted by + default, however, and the default can be explicitly requested with the + Clang-specific flag ``-flax-vector-conversions=all``. In a future release of + Clang, we intend to change the default to ``-fno-lax-vector-conversions``. + +* Improved support for ``octeon`` MIPS-family CPU. Added ``octeon+`` to + the list of of CPUs accepted by the driver. + +* For the WebAssembly target, the ``wasm-opt`` tool will now be run if it is + found in the PATH, which can reduce code size. + +* For the RISC-V target, floating point registers can now be used in inline + assembly constraints. + New Compiler Flags ------------------ -- The -fgnuc-version= flag now controls the value of ``__GNUC__`` and related +- The ``-fgnuc-version=`` flag now controls the value of ``__GNUC__`` and related macros. This flag does not enable or disable any GCC extensions implemented in Clang. Setting the version to zero causes Clang to leave ``__GNUC__`` and other GNU-namespaced macros, such as ``__GXX_WEAK__``, undefined. -- vzeroupper insertion on X86 targets can now be disabled with -mno-vzeroupper. +- vzeroupper insertion on X86 targets can now be disabled with ``-mno-vzeroupper``. You can also force vzeroupper insertion to be used on CPUs that normally - wouldn't with -mvzeroupper. + wouldn't with ``-mvzeroupper``. + +- The ``-fno-concept-satisfaction-caching`` can be used to disable caching for + satisfactions of Concepts. The C++2a draft standard does not currently permit + this caching, but disabling it may incur significant compile-time costs. This + flag is intended for experimentation purposes and may be removed at any time; + please let us know if you encounter a situation where you need to specify this + flag for correct program behavior. + +- The ``-ffixed-xX`` flags now work on RISC-V. These reserve the corresponding + general-purpose registers. + +- RISC-V has added ``-mcmodel=medany`` and ``-mcmodel=medlow`` as aliases for + ``-mcmodel=small`` and ``-mcmodel=medium`` respectively. Preprocessor definitions + for ``__riscv_cmodel_medlow`` and ``__riscv_cmodel_medany`` have been corrected. + +- ``-fmacro-prefix-map=OLD=NEW`` substitutes directory prefix ``OLD`` for + ``NEW`` in predefined preprocessor macros such as ``__FILE__``. This helps + with reproducible builds that are location independent. The new + ``-ffile-prefix-map`` option is equivalent to specifying both + ``-fdebug-prefix-map`` and ``-fmacro-prefix-map``. + +- ``-fpatchable-function-entry=N[,M]`` is added to generate M NOPs before the + function entry and N-M NOPs after the function entry. This is used by AArch64 + ftrace in the Linux kernel. + +- ``-mbranches-within-32B-boundaries`` is added as an x86 assembler mitigation + for Intel's Jump Condition Code Erratum. Deprecated Compiler Flags ------------------------- @@ -115,11 +190,13 @@ Deprecated Compiler Flags The following options are deprecated and ignored. They will be removed in future versions of Clang. -- -mmpx used to enable the __MPX__ preprocessor define for the Intel MPX +- ``-mmpx`` used to enable the ``__MPX__`` preprocessor define for the Intel MPX instructions. There were no MPX intrinsics. -- -mno-mpx used to disable -mmpx and is the default behavior. -- ... +- ``-mno-mpx`` used to disable ``-mmpx`` and is the default behavior. + +- ``-fconcepts-ts`` previously used to enable experimental concepts support. Use + -std=c++2a instead to enable Concepts support. Modified Compiler Flags ----------------------- @@ -127,15 +204,37 @@ Modified Compiler Flags - RISC-V now sets the architecture (riscv32/riscv64) based on the value provided to the ``-march`` flag, overriding the target provided by ``-triple``. -New Pragmas in Clang --------------------- +- ``-flax-vector-conversions`` has been split into three different levels of + laxness, and has been updated to match the GCC semantics: + + - ``-flax-vector-conversions=all``: This is Clang's current default, and + permits implicit vector conversions (performed as bitcasts) between any + two vector types of the same overall bit-width. + Former synonym: ``-flax-vector-conversions`` (Clang <= 9). + + - ``-flax-vector-conversions=integer``: This permits implicit vector + conversions (performed as bitcasts) between any two integer vector types of + the same overall bit-width. + Synonym: ``-flax-vector-conversions`` (Clang >= 10). + + - ``-flax-vector-conversions=none``: Do not perform any implicit bitcasts + between vector types. + Synonym: ``-fno-lax-vector-conversions``. -- ... +- ``-debug-info-kind`` now has an option ``-debug-info-kind=constructor``, + which is one level below ``-debug-info-kind=limited``. This option causes + debug info for classes to be emitted only when a constructor is emitted. + +- RISC-V now chooses a slightly different sysroot path and defaults to using + compiler-rt if no GCC installation is detected. + +- RISC-V now supports multilibs in baremetal environments. This support does not + extend to supporting multilib aliases. Attribute Changes in Clang -------------------------- -- ... +- Support was added for function ``__attribute__((target("branch-protection=...")))`` Windows Support --------------- @@ -150,15 +249,17 @@ Windows Support error LNK2005: "bool const std::_Is_integral" (??$_Is_integral@H@std@@3_NB) already defined -C Language Changes in Clang ---------------------------- +- The ``.exe`` output suffix is now added implicitly in MinGW mode, when + Clang is running on Windows (matching GCC's behaviour) -- ... +- Fixed handling of TLS variables that are shared between object files + in MinGW environments -C11 Feature Support -^^^^^^^^^^^^^^^^^^^ +- The ``-cfguard`` flag now emits Windows Control Flow Guard checks on indirect + function calls. The previous behavior is still available with the + ``-cfguard-nochecks`` flag. These checks can be disabled for specific + functions using the new ``__declspec(guard(nocf))`` modifier. -... C++ Language Changes in Clang ----------------------------- @@ -168,11 +269,6 @@ C++ Language Changes in Clang how it behaved in previous Clang versions, a warning is emitted for this combination. -C++1z Feature Support -^^^^^^^^^^^^^^^^^^^^^ - -... - Objective-C Language Changes in Clang ------------------------------------- @@ -203,7 +299,7 @@ Objective-C Language Changes in Clang One particular issue you may run into is attempting to use a class as a key in a dictionary literal. This will now result in an error, - because ``Class`` is not convertable to ``id``. (Note that + because ``Class`` is not convertible to ``id``. (Note that this was already a warning in Objective-C mode.) While an arbitrary ``Class`` object is not guaranteed to implement ``NSCopying``, the default metaclass implementation does. Therefore, the recommended @@ -220,37 +316,79 @@ Objective-C Language Changes in Clang // Fix: add an explicit cast to 'id'. NSDictionary* d = @{(id)cls : @"Hello"}; -OpenCL C Language Changes in Clang ----------------------------------- +OpenCL Kernel Language Changes in Clang +--------------------------------------- + +Generic changes: + +- Made ``__private`` to be appear explicitly in diagnostics, AST, etc. +- Fixed diagnostics of ``enqueue_kernel``. + +OpenCL builtin functions: + +- The majority of the OpenCL builtin functions are now available through + the experimental `TableGen` driven ``-fdeclare-opencl-builtins`` option. +- Align the ``enqueue_marker`` declaration in standard ``opencl-c.h`` to the + OpenCL spec. +- Avoid a void pointer cast in the ``CLK_NULL_EVENT`` definition. +- Aligned OpenCL with c11 atomic fetch max/min. + +Changes in C++ for OpenCL: + +- Fixed language mode predefined macros for C++ mode. +- Allow OpenCL C style compound vector initialization. +- Improved destructor support. +- Implemented address space deduction for pointers/references + to arrays and auto variables. +- Added address spaces support for lambdas and ``constexpr``. +- Fixed misc address spaces usages in classes. -... ABI Changes in Clang -------------------- -- gcc passes vectors of __int128 in memory on X86-64. Clang historically +- GCC passes vectors of __int128 in memory on X86-64. Clang historically broke the vectors into multiple scalars using two 64-bit values for each - element. Clang now matches the gcc behavior on Linux and NetBSD. You can - switch back to old API behavior with flag: -fclang-abi-compat=9.0. + element. Clang now matches the GCC behavior on Linux and NetBSD. You can + switch back to old API behavior with flag: ``-fclang-abi-compat=9.0``. - RISC-V now chooses a default ``-march=`` and ``-mabi=`` to match (in almost all cases) the GCC defaults. On baremetal targets, where neither ``-march=`` nor ``-mabi=`` are specified, Clang now differs from GCC by defaulting to - ``-march=rv32imac -mabi=ilp32`` or ``-march=rv64imac -mabi=lp64`` depending on - the architecture in the target triple. These do not always match the defaults - in Clang 9. We strongly suggest that you explicitly pass `-march=` and - `-mabi=` when compiling for RISC-V, due to how extensible this architecture - is. + ``-march=rv32imac`` ``-mabi=ilp32`` or ``-march=rv64imac`` ``-mabi=lp64`` + depending on the architecture in the target triple. These do not always match + the defaults in Clang 9. We strongly suggest that you explicitly pass + ``-march=`` and ``-mabi=`` when compiling for RISC-V, due to how extensible + this architecture is. + +- RISC-V now uses `target-abi` module metadata to encode the chosen psABI. This + ensures that the correct lowering will be done by LLVM when LTO is enabled. + +- An issue with lowering return types in the RISC-V ILP32D psABI has been fixed. OpenMP Support in Clang ----------------------- -- ... +New features for OpenMP 5.0 were implemented. Use ``-fopenmp-version=50`` option to activate support for OpenMP 5.0. + +- Added support for ``device_type`` clause in declare target directive. +- Non-static and non-ordered loops are nonmonotonic by default. +- Teams-based directives can be used as a standalone directive. +- Added support for collapsing of non-rectangular loops. +- Added support for range-based loops. +- Added support for collapsing of imperfectly nested loops. +- Added support for ``master taskloop``, ``parallel master taskloop``, ``master taskloop simd`` and ``parallel master taskloop simd`` directives. +- Added support for ``if`` clauses in simd-based directives. +- Added support for unified shared memory for NVPTX target. +- Added support for nested atomic and simd directives are allowed in sims-based directives. +- Added support for non temporal clauses in sims-based directives. +- Added basic support for conditional lastprivate variables -CUDA Support in Clang ---------------------- +Other improvements: + +- Added basic analysis for use of the uninitialized variables in clauses. +- Bug fixes. -- ... Internal API Changes -------------------- @@ -286,12 +424,6 @@ release of Clang. Users of the build system should adjust accordingly. statically linking clang's components. This option will reduce the size of binary distributions at the expense of compiler performance. -- ... - -AST Matchers ------------- - -- ... clang-format ------------ @@ -311,7 +443,7 @@ clang-format - Clang-format has a new option called ``--dry-run`` or ``-n`` to emit a warning for clang-format violations. This can be used together - with --ferror-limit=N to limit the number of warnings per file and --Werror + with ``--ferror-limit=N`` to limit the number of warnings per file and ``--Werror`` to make warnings into errors. - Option *IncludeIsMainSourceRegex* has been added to allow for additional @@ -352,84 +484,104 @@ clang-format const x = foo ?? default; const z = foo?.bar?.baz; +- Option ``AlwaysBreakAfterReturnType`` now manages all operator functions. + libclang -------- -- ... +- Various changes to reduce discrepancies in destructor calls between the + generated ``CFG`` and the actual ``codegen``. + + In particular: + + - Respect C++17 copy elision; previously it would generate destructor calls + for elided temporaries, including in initialization and return statements. + + - Don't generate duplicate destructor calls for statement expressions. + + - Fix initialization lists. + + - Fix comma operator. + + - Change printing of implicit destructors to print the type instead of the + class name directly, matching the code for temporary object destructors. + The class name was blank for lambdas. + Static Analyzer --------------- -- The Clang analyzer checker ``DeadStores`` gets a new option called - ``WarnForDeadNestedAssignments`` to detect nested dead assignments - (enabled by default). -- ... +- New checker: ``alpha.cplusplus.PlacementNew`` to detect whether the storage + provided for default placement new is sufficiently large. -.. _release-notes-ubsan: +- New checker: ``fuchsia.HandleChecker`` to detect leaks related to Fuchsia + handles. -Undefined Behavior Sanitizer (UBSan) ------------------------------------- +- New checker: ``security.insecureAPI.decodeValueOfObjCType`` warns about + potential buffer overflows when using ``[NSCoder decodeValueOfObjCType:at:]`` -- * The ``pointer-overflow`` check was extended added to catch the cases where - a non-zero offset is applied to a null pointer, or the result of - applying the offset is a null pointer. - - .. code-block:: c++ - - #include // for intptr_t - - static char *getelementpointer_inbounds(char *base, unsigned long offset) { - // Potentially UB. - return base + offset; - } - - char *getelementpointer_unsafe(char *base, unsigned long offset) { - // Always apply offset. UB if base is ``nullptr`` and ``offset`` is not - // zero, or if ``base`` is non-``nullptr`` and ``offset`` is - // ``-reinterpret_cast(base)``. - return getelementpointer_inbounds(base, offset); - } - - char *getelementpointer_safe(char *base, unsigned long offset) { - // Cast pointer to integer, perform usual arithmetic addition, - // and cast to pointer. This is legal. - char *computed = - reinterpret_cast(reinterpret_cast(base) + offset); - // If either the pointer becomes non-``nullptr``, or becomes - // ``nullptr``, we must use ``computed`` result. - if (((base == nullptr) && (computed != nullptr)) || - ((base != nullptr) && (computed == nullptr))) - return computed; - // Else we can use ``getelementpointer_inbounds()``. - return getelementpointer_inbounds(base, offset); - } - -Core Analysis Improvements -========================== +- ``deadcode.DeadStores`` now warns about nested dead stores. -- ... +- Condition values that are relevant to the occurrence of a bug are far better + explained in bug reports. -New Issues Found -================ +- Despite still being at an alpha stage, checkers implementing taint analyses + and C++ iterator rules were improved greatly. -- ... +- Numerous smaller fixes. -Python Binding Changes ----------------------- +.. _release-notes-ubsan: -The following methods have been added: +Undefined Behavior Sanitizer (UBSan) +------------------------------------ -- ... +* The ``pointer-overflow`` check was extended added to catch the cases where + a non-zero offset is applied to a null pointer, or the result of + applying the offset is a null pointer. + + .. code-block:: c++ + + #include // for intptr_t + + static char *getelementpointer_inbounds(char *base, unsigned long offset) { + // Potentially UB. + return base + offset; + } + + char *getelementpointer_unsafe(char *base, unsigned long offset) { + // Always apply offset. UB if base is ``nullptr`` and ``offset`` is not + // zero, or if ``base`` is non-``nullptr`` and ``offset`` is + // ``-reinterpret_cast(base)``. + return getelementpointer_inbounds(base, offset); + } + + char *getelementpointer_safe(char *base, unsigned long offset) { + // Cast pointer to integer, perform usual arithmetic addition, + // and cast to pointer. This is legal. + char *computed = + reinterpret_cast(reinterpret_cast(base) + offset); + // If either the pointer becomes non-``nullptr``, or becomes + // ``nullptr``, we must use ``computed`` result. + if (((base == nullptr) && (computed != nullptr)) || + ((base != nullptr) && (computed == nullptr))) + return computed; + // Else we can use ``getelementpointer_inbounds()``. + return getelementpointer_inbounds(base, offset); + } + +Changes deferred to Clang-11 release +------------------------------------ + +- The next release of clang (clang-11) will upgrade the default C language + standard used if not specified via command line from gnu11 to gnu17. -Significant Known Problems -========================== Additional Information ====================== A wide variety of additional information is available on the `Clang web page `_. The web page contains versions of the -API documentation which are up-to-date with the Subversion version of +API documentation which are up-to-date with the Git version of the source code. You can access versions of these documents specific to this release by going into the "``clang/docs/``" directory in the Clang tree. diff --git a/clang/docs/UsersManual.rst b/clang/docs/UsersManual.rst index 856d5e34bbcc2..07157b9ad5f43 100644 --- a/clang/docs/UsersManual.rst +++ b/clang/docs/UsersManual.rst @@ -3297,59 +3297,58 @@ Execute ``clang-cl /?`` to see a list of supported options: CL.EXE COMPATIBILITY OPTIONS: /? Display available options /arch: Set architecture for code generation - /Brepro- Emit an object file which cannot be reproduced over time - /Brepro Emit an object file which can be reproduced over time + /Brepro- Write current time into COFF output (default) + /Brepro Do not write current time into COFF output (breaks link.exe /incremental) /clang: Pass to the clang driver - /C Don't discard comments when preprocessing + /C Do not discard comments when preprocessing /c Compile only /d1PP Retain macro definitions in /E mode /d1reportAllClassLayout Dump record layout information - /diagnostics:caret Enable caret and column diagnostics (on by default) + /diagnostics:caret Enable caret and column diagnostics (default) /diagnostics:classic Disable column and caret diagnostics /diagnostics:column Disable caret diagnostics but keep column info /D Define macro - /EH Exception handling model + /EH Set exception handling model /EP Disable linemarker output and preprocess to stdout /execution-charset: - Runtime encoding, supports only UTF-8 + Set runtime encoding, supports only UTF-8 /E Preprocess to stdout /fallback Fall back to cl.exe if clang-cl fails to compile /FA Output assembly code file during compilation - /Fa Output assembly code to this file during compilation (with /FA) - /Fe Set output executable file or directory (ends in / or \) + /Fa Set assembly output file name (with /FA) + /Fe Set output executable file name /FI Include file before parsing /Fi Set preprocess output file name (with /P) - /Fo Set output object file, or directory (ends in / or \) (with /c) + /Fo Set output object file (with /c) /fp:except- /fp:except /fp:fast /fp:precise /fp:strict - /Fp Set pch filename (with /Yc and /Yu) + /Fp Set pch file name (with /Yc and /Yu) /GA Assume thread-local variables are defined in the executable /Gd Set __cdecl as a default calling convention /GF- Disable string pooling /GF Enable string pooling (default) - /GR- Disable emission of RTTI data + /GR- Do not emit RTTI data /Gregcall Set __regcall as a default calling convention - /GR Enable emission of RTTI data + /GR Emit RTTI data (default) /Gr Set __fastcall as a default calling convention /GS- Disable buffer security check /GS Enable buffer security check (default) /Gs Use stack probes (default) /Gs Set stack probe size (default 4096) - /guard: Enable Control Flow Guard with /guard:cf, - or only the table with /guard:cf,nochecks + /guard: Enable Control Flow Guard with /guard:cf, or only the table with /guard:cf,nochecks /Gv Set __vectorcall as a default calling convention - /Gw- Don't put each data item in its own section + /Gw- Do not put each data item in its own section (default) /Gw Put each data item in its own section - /GX- Disable exception handling - /GX Enable exception handling - /Gy- Don't put each function in its own section (default) + /GX- Deprecated (like not passing /EH) + /GX Deprecated; use /EHsc + /Gy- Do not put each function in its own section (default) /Gy Put each function in its own section /Gz Set __stdcall as a default calling convention /help Display available options - /imsvc Add directory to system include search path, as if part of %INCLUDE% + /imsvc Add to system include search path, as if in %INCLUDE% /I Add directory to include search path /J Make char type unsigned /LDd Create debug DLL @@ -3359,35 +3358,37 @@ Execute ``clang-cl /?`` to see a list of supported options: /MD Use DLL run-time /MTd Use static debug run-time /MT Use static run-time - /O0 Disable optimization - /O1 Optimize for size (same as /Og /Os /Oy /Ob2 /GF /Gy) - /O2 Optimize for speed (same as /Og /Oi /Ot /Oy /Ob2 /GF /Gy) + /O1 Optimize for size (like /Og /Os /Oy /Ob2 /GF /Gy) + /O2 Optimize for speed (like /Og /Oi /Ot /Oy /Ob2 /GF /Gy) /Ob0 Disable function inlining - /Ob1 Only inline functions which are (explicitly or implicitly) marked inline + /Ob1 Only inline functions explicitly or implicitly marked inline /Ob2 Inline functions as deemed beneficial by the compiler /Od Disable optimization /Og No effect /Oi- Disable use of builtin functions /Oi Enable use of builtin functions + /openmp- Disable OpenMP support + /openmp:experimental Enable OpenMP support with experimental SIMD support + /openmp Enable OpenMP support /Os Optimize for size /Ot Optimize for speed - /Ox Deprecated (same as /Og /Oi /Ot /Oy /Ob2); use /O2 instead + /Ox Deprecated (like /Og /Oi /Ot /Oy /Ob2); use /O2 /Oy- Disable frame pointer omission (x86 only, default) /Oy Enable frame pointer omission (x86 only) /O Set multiple /O flags at once; e.g. '/O2y-' for '/O2 /Oy-' - /o Set output file or directory (ends in / or \) + /o Deprecated (set output file name); use /Fe or /Fe /P Preprocess to file /Qvec- Disable the loop vectorization passes /Qvec Enable the loop vectorization passes - /showFilenames- Don't print the name of each compiled file (default) + /showFilenames- Do not print the name of each compiled file (default) /showFilenames Print the name of each compiled file /showIncludes Print info about included files to stderr - /source-charset: Source encoding, supports only UTF-8 - /std: Language standard to compile for + /source-charset: Set source encoding, supports only UTF-8 + /std: Set C++ version (c++14,c++17,c++latest) /TC Treat all source files as C - /Tc Specify a C source file + /Tc Treat as C source file /TP Treat all source files as C++ - /Tp Specify a C++ source file + /Tp Treat as C++ source file /utf-8 Set source and runtime encoding to UTF-8 (default) /U Undefine macro /vd Control vtordisp placement @@ -3404,17 +3405,19 @@ Execute ``clang-cl /?`` to see a list of supported options: /W3 Enable -Wall /W4 Enable -Wall and -Wextra /Wall Enable -Weverything - /WX- Do not treat warnings as errors + /WX- Do not treat warnings as errors (default) /WX Treat warnings as errors /w Disable all warnings - /X Don't add %INCLUDE% to the include search path + /X Do not add %INCLUDE% to include search path /Y- Disable precompiled headers, overrides /Yc and /Yu /Yc Generate a pch file for all code up to and including /Yu Load a pch file and use it instead of all code up to and including /Z7 Enable CodeView debug information in object files - /Zc:char8_t Enable C++2a char8_t type - /Zc:char8_t- Disable C++2a char8_t type - /Zc:dllexportInlines- Don't dllexport/dllimport inline member functions of dllexport/import classes + /Zc:alignedNew- Disable C++17 aligned allocation functions + /Zc:alignedNew Enable C++17 aligned allocation functions + /Zc:char8_t- Disable char8_t from c++2a + /Zc:char8_t Enable char8_t from C++2a + /Zc:dllexportInlines- Do not dllexport/dllimport inline member functions of dllexport/import classes /Zc:dllexportInlines dllexport/dllimport inline member functions of dllexport/import classes (default) /Zc:sizedDealloc- Disable C++14 sized global deallocation functions /Zc:sizedDealloc Enable C++14 sized global deallocation functions @@ -3423,18 +3426,21 @@ Execute ``clang-cl /?`` to see a list of supported options: /Zc:threadSafeInit Enable thread-safe initialization of static variables /Zc:trigraphs- Disable trigraphs (default) /Zc:trigraphs Enable trigraphs - /Zc:twoPhase- Disable two-phase name lookup in templates + /Zc:twoPhase- Disable two-phase name lookup in templates (default) /Zc:twoPhase Enable two-phase name lookup in templates /Zd Emit debug line number tables only - /Zi Alias for /Z7. Does not produce PDBs. - /Zl Don't mention any default libraries in the object file - /Zp Set the default maximum struct packing alignment to 1 - /Zp Specify the default maximum struct packing alignment + /Zi Like /Z7 + /Zl Do not let object file auto-link default libraries + /Zp Set default maximum struct packing alignment to 1 + /Zp Set default maximum struct packing alignment /Zs Syntax-check only OPTIONS: -### Print (but do not run) the commands to run for this compilation --analyze Run the static analyzer + -enable-trivial-auto-var-init-zero-knowing-it-will-be-removed-from-clang + Trivial automatic variable initialization to zero is only here for benchmarks, it'll + eventually be removed, and I'm OK with that because I'm only using it to benchmark -faddrsig Emit an address-significance table -fansi-escape-codes Use ANSI escape codes for diagnostics -fblocks Enable the 'blocks' language feature @@ -3444,6 +3450,13 @@ Execute ``clang-cl /?`` to see a list of supported options: -fcomplete-member-pointers Require member pointer base types to be complete if they would be significant under the Microsoft ABI -fcoverage-mapping Generate coverage mapping to enable code coverage analysis + -fcs-profile-generate= + Generate instrumented code to collect context sensitive execution counts into + /default.profraw (overridden by LLVM_PROFILE_FILE env var) + -fcs-profile-generate Generate instrumented code to collect context sensitive execution counts into + default.profraw (overridden by LLVM_PROFILE_FILE env var) + -fdebug-compilation-dir + The compilation directory to embed in the debug info. -fdebug-macro Emit macro debug information -fdelayed-template-parsing Parse templated function definitions at the end of the translation unit @@ -3451,16 +3464,17 @@ Execute ``clang-cl /?`` to see a list of supported options: Print absolute paths in diagnostics -fdiagnostics-parseable-fixits Print fix-its in machine parseable form + -fgnuc-version= Sets various macros to claim compatibility with the given GCC version (default is 4.2.1) + -fintegrated-cc1 Run cc1 in-process -flto= Set LTO mode to either 'full' or 'thin' -flto Enable LTO in 'full' mode -fmerge-all-constants Allow merging of constants -fms-compatibility-version= - Dot-separated value representing the Microsoft compiler version - number to report in _MSC_VER (0 = don't define it (default)) + Dot-separated value representing the Microsoft compiler version number to report in + _MSC_VER (0 = don't define it (default)) -fms-compatibility Enable full Microsoft Visual C++ compatibility -fms-extensions Accept some non-standard constructs supported by the Microsoft compiler - -fmsc-version= Microsoft compiler version number to report in _MSC_VER - (0 = don't define it (default)) + -fmsc-version= Microsoft compiler version number to report in _MSC_VER (0 = don't define it (default)) -fno-addrsig Don't emit an address-significance table -fno-builtin- Disable implicit builtin knowledge of a specific function -fno-builtin Disable implicit builtin knowledge of functions @@ -3471,6 +3485,11 @@ Execute ``clang-cl /?`` to see a list of supported options: -fno-debug-macro Do not emit macro debug information -fno-delayed-template-parsing Disable delayed template parsing + -fno-integrated-cc1 Spawn a separate process for each cc1 + -fno-profile-generate Disable generation of profile instrumentation. + -fno-profile-instr-generate + Disable generation of profile instrumentation. + -fno-profile-instr-use Disable using instrumentation data for profile-guided optimization -fno-sanitize-address-poison-custom-array-cookie Disable poisoning array cookies when using custom operator new[] in AddressSanitizer -fno-sanitize-address-use-after-scope @@ -3478,6 +3497,8 @@ Execute ``clang-cl /?`` to see a list of supported options: -fno-sanitize-address-use-odr-indicator Disable ODR indicator globals -fno-sanitize-blacklist Don't use blacklist file for sanitizers + -fno-sanitize-cfi-canonical-jump-tables + Do not make the jump table addresses canonical in the symbol table -fno-sanitize-cfi-cross-dso Disable control flow integrity (CFI) checks for cross-DSO calls. -fno-sanitize-coverage= @@ -3498,17 +3519,26 @@ Execute ``clang-cl /?`` to see a list of supported options: -fno-sanitize-trap= Disable trapping for specified sanitizers -fno-standalone-debug Limit debug information produced to reduce size of debug binary + -fno-temp-file Directly create compilation output files. This may lead to incorrect incremental builds if the compiler crashes -fobjc-runtime= Specify the target Objective-C runtime kind and version + -forder-file-instrumentation + Generate instrumented code to collect order file into default.profraw file + (overridden by '=' form of option or LLVM_PROFILE_FILE env var) -fprofile-exclude-files= Instrument only functions from files where names don't match all the regexes separated by a semi-colon -fprofile-filter-files= Instrument only functions from files where names match any regex separated by a semi-colon + -fprofile-generate= + Generate instrumented code to collect execution counts into + /default.profraw (overridden by LLVM_PROFILE_FILE env var) + -fprofile-generate Generate instrumented code to collect execution counts into + default.profraw (overridden by LLVM_PROFILE_FILE env var) -fprofile-instr-generate= - Generate instrumented code to collect execution counts into - (overridden by LLVM_PROFILE_FILE env var) + Generate instrumented code to collect execution counts into + (overridden by LLVM_PROFILE_FILE env var) -fprofile-instr-generate - Generate instrumented code to collect execution counts into default.profraw file - (overridden by '=' form of option or LLVM_PROFILE_FILE env var) + Generate instrumented code to collect execution counts into + default.profraw file (overridden by '=' form of option or LLVM_PROFILE_FILE env var) -fprofile-instr-use= Use instrumentation data for profile-guided optimization -fprofile-remapping-file= @@ -3522,9 +3552,12 @@ Execute ``clang-cl /?`` to see a list of supported options: -fsanitize-address-use-after-scope Enable use-after-scope detection in AddressSanitizer -fsanitize-address-use-odr-indicator - Enable ODR indicator globals to avoid false ODR violation reports in partially sanitized programs at the cost of an increase in binary size + Enable ODR indicator globals to avoid false ODR violation reports in partially sanitized + programs at the cost of an increase in binary size -fsanitize-blacklist= Path to blacklist file for sanitizers + -fsanitize-cfi-canonical-jump-tables + Make the jump table addresses canonical in the symbol table -fsanitize-cfi-cross-dso Enable control flow integrity (CFI) checks for cross-DSO calls. -fsanitize-cfi-icall-generalize-pointers @@ -3532,7 +3565,8 @@ Execute ``clang-cl /?`` to see a list of supported options: -fsanitize-coverage= Specify the type of coverage instrumentation for Sanitizers -fsanitize-hwaddress-abi= - Select the HWAddressSanitizer ABI to target (interceptor or platform, default interceptor) + Select the HWAddressSanitizer ABI to target (interceptor or platform, + default interceptor). This option is currently unused. -fsanitize-memory-track-origins= Enable origins tracking in MemorySanitizer -fsanitize-memory-track-origins @@ -3542,6 +3576,8 @@ Execute ``clang-cl /?`` to see a list of supported options: -fsanitize-recover= Enable recovery for specified sanitizers -fsanitize-stats Enable sanitizer statistics gathering. + -fsanitize-system-blacklist= + Path to system blacklist file for sanitizers -fsanitize-thread-atomics Enable atomic operations instrumentation in ThreadSanitizer (default) -fsanitize-thread-func-entry-exit @@ -3551,18 +3587,31 @@ Execute ``clang-cl /?`` to see a list of supported options: -fsanitize-trap= Enable trapping for specified sanitizers -fsanitize-undefined-strip-path-components= Strip (or keep only, if negative) a given number of path components when emitting check metadata. - -fsanitize= Turn on runtime checks for various forms of undefined or suspicious - behavior. See user manual for available checks + -fsanitize= Turn on runtime checks for various forms of undefined or suspicious behavior. See user manual for available checks -fsplit-lto-unit Enables splitting of the LTO unit. -fstandalone-debug Emit full debug info for all types used by the program + -fthin-link-bitcode= + Write minimized bitcode to for the ThinLTO thin link only + -fthinlto-index= Perform ThinLTO importing using provided function summary index + -ftime-trace-granularity= + Minimum time granularity (in microseconds) traced by time profiler + -ftime-trace Turn on time profiler. Generates JSON file based on output filename. + -ftrivial-auto-var-init= + Initialize trivial automatic stack variables: uninitialized (default) | pattern + -fvirtual-function-elimination + Enables dead virtual function elimination optimization. Requires -flto=full -fwhole-program-vtables Enables whole-program vtable optimization. Requires -flto -gcodeview-ghash Emit type record hashes in a .debug$H section -gcodeview Generate CodeView debug information + -gdwarf Generate source-level debug information with the default dwarf version -gline-directives-only Emit debug line info directives only -gline-tables-only Emit debug line number tables only + -gno-inline-line-tables Don't emit inline line tables -miamcu Use Intel MCU ABI -mllvm Additional arguments to forward to LLVM's option processing -nobuiltininc Disable builtin #include directories + -print-supported-cpus Print supported cpu models for the given target + (if target is not specified, it will print the supported cpus for the default target) -Qunused-arguments Don't emit warning for unused driver arguments -R Enable the specified remark --target= Generate code for the given target diff --git a/clang/examples/clang-interpreter/main.cpp b/clang/examples/clang-interpreter/main.cpp index db6b0cce4fd17..c0aae47223068 100644 --- a/clang/examples/clang-interpreter/main.cpp +++ b/clang/examples/clang-interpreter/main.cpp @@ -56,7 +56,8 @@ class SimpleJIT { MangleAndInterner Mangle{ES, DL}; JITDylib &MainJD{ES.createJITDylib("
")}; RTDyldObjectLinkingLayer ObjectLayer{ES, createMemMgr}; - IRCompileLayer CompileLayer{ES, ObjectLayer, SimpleCompiler(*TM)}; + IRCompileLayer CompileLayer{ES, ObjectLayer, + std::make_unique(*TM)}; static std::unique_ptr createMemMgr() { return std::make_unique(); diff --git a/clang/include/clang/AST/ASTConcept.h b/clang/include/clang/AST/ASTConcept.h index 896d857d8c96c..3ebaad4eafdd8 100644 --- a/clang/include/clang/AST/ASTConcept.h +++ b/clang/include/clang/AST/ASTConcept.h @@ -22,10 +22,25 @@ #include namespace clang { class ConceptDecl; +class ConceptSpecializationExpr; + +/// The result of a constraint satisfaction check, containing the necessary +/// information to diagnose an unsatisfied constraint. +class ConstraintSatisfaction : public llvm::FoldingSetNode { + // The template-like entity that 'owns' the constraint checked here (can be a + // constrained entity or a concept). + const NamedDecl *ConstraintOwner = nullptr; + llvm::SmallVector TemplateArgs; + +public: + + ConstraintSatisfaction() = default; + + ConstraintSatisfaction(const NamedDecl *ConstraintOwner, + ArrayRef TemplateArgs) : + ConstraintOwner(ConstraintOwner), TemplateArgs(TemplateArgs.begin(), + TemplateArgs.end()) { } -/// \brief The result of a constraint satisfaction check, containing the -/// necessary information to diagnose an unsatisfied constraint. -struct ConstraintSatisfaction { using SubstitutionDiagnostic = std::pair; using Detail = llvm::PointerUnion; @@ -37,9 +52,13 @@ struct ConstraintSatisfaction { /// invalid expression. llvm::SmallVector, 4> Details; - // This can leak if used in an AST node, use ASTConstraintSatisfaction - // instead. - void *operator new(size_t bytes, ASTContext &C) = delete; + void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &C) { + Profile(ID, C, ConstraintOwner, TemplateArgs); + } + + static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &C, + const NamedDecl *ConstraintOwner, + ArrayRef TemplateArgs); }; /// Pairs of unsatisfied atomic constraint expressions along with the diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index fb269cef1ce8a..f8403cf13c4a0 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -88,6 +88,7 @@ class AtomicExpr; class BlockExpr; class BuiltinTemplateDecl; class CharUnits; +class ConceptDecl; class CXXABI; class CXXConstructorDecl; class CXXMethodDecl; @@ -211,7 +212,7 @@ class ASTContext : public RefCountedBase { mutable llvm::FoldingSet ObjCObjectPointerTypes; mutable llvm::FoldingSet DependentUnaryTransformTypes; - mutable llvm::FoldingSet AutoTypes; + mutable llvm::ContextualFoldingSet AutoTypes; mutable llvm::FoldingSet DeducedTemplateSpecializationTypes; mutable llvm::FoldingSet AtomicTypes; @@ -1542,7 +1543,9 @@ class ASTContext : public RefCountedBase { /// C++11 deduced auto type. QualType getAutoType(QualType DeducedType, AutoTypeKeyword Keyword, - bool IsDependent, bool IsPack = false) const; + bool IsDependent, bool IsPack = false, + ConceptDecl *TypeConstraintConcept = nullptr, + ArrayRef TypeConstraintArgs ={}) const; /// C++11 deduction pattern for 'auto' type. QualType getAutoDeductType() const; diff --git a/clang/include/clang/AST/ASTNodeTraverser.h b/clang/include/clang/AST/ASTNodeTraverser.h index e0ebb020e697c..9ebf64a12af5c 100644 --- a/clang/include/clang/AST/ASTNodeTraverser.h +++ b/clang/include/clang/AST/ASTNodeTraverser.h @@ -548,8 +548,8 @@ class ASTNodeTraverser } void VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D) { - if (const auto *TC = D->getPlaceholderTypeConstraint()) - Visit(TC->getImmediatelyDeclaredConstraint()); + if (const auto *E = D->getPlaceholderTypeConstraint()) + Visit(E); if (D->hasDefaultArgument()) Visit(D->getDefaultArgument(), SourceRange(), D->getDefaultArgStorage().getInheritedFrom(), diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h index b716ea453a5a0..2e8e31dbf4c7b 100644 --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/include/clang/AST/DeclCXX.h @@ -1893,6 +1893,37 @@ class CXXDeductionGuideDecl : public FunctionDecl { static bool classofKind(Kind K) { return K == CXXDeductionGuide; } }; +/// \brief Represents the body of a requires-expression. +/// +/// This decl exists merely to serve as the DeclContext for the local +/// parameters of the requires expression as well as other declarations inside +/// it. +/// +/// \code +/// template requires requires (T t) { {t++} -> regular; } +/// \endcode +/// +/// In this example, a RequiresExpr object will be generated for the expression, +/// and a RequiresExprBodyDecl will be created to hold the parameter t and the +/// template argument list imposed by the compound requirement. +class RequiresExprBodyDecl : public Decl, public DeclContext { + RequiresExprBodyDecl(ASTContext &C, DeclContext *DC, SourceLocation StartLoc) + : Decl(RequiresExprBody, DC, StartLoc), DeclContext(RequiresExprBody) {} + +public: + friend class ASTDeclReader; + friend class ASTDeclWriter; + + static RequiresExprBodyDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation StartLoc); + + static RequiresExprBodyDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == RequiresExprBody; } +}; + /// Represents a static or instance method of a struct/union/class. /// /// In the terminology of the C++ Standard, these are the (static and diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h index 7a55d04a0f352..7a9f623d8152b 100755 --- a/clang/include/clang/AST/DeclTemplate.h +++ b/clang/include/clang/AST/DeclTemplate.h @@ -1102,6 +1102,17 @@ class FunctionTemplateDecl : public RedeclarableTemplateDecl { /// template. ArrayRef getInjectedTemplateArgs(); + /// Return whether this function template is an abbreviated function template, + /// e.g. `void foo(auto x)` or `template void foo(auto x)` + bool isAbbreviated() const { + // Since the invented template parameters generated from 'auto' parameters + // are either appended to the end of the explicit template parameter list or + // form a new template paramter list, we can simply observe the last + // parameter to determine if such a thing happened. + const TemplateParameterList *TPL = getTemplateParameters(); + return TPL->getParam(TPL->size() - 1)->isImplicit(); + } + /// Merge \p Prev with our RedeclarableTemplateDecl::Common. void mergePrevDecl(FunctionTemplateDecl *Prev); @@ -1215,7 +1226,6 @@ class TemplateTypeParmDecl final : public TypeDecl, bool ParameterPack, bool HasTypeConstraint = false, Optional NumExpanded = None); - static TemplateTypeParmDecl *CreateDeserialized(const ASTContext &C, unsigned ID); static TemplateTypeParmDecl *CreateDeserialized(const ASTContext &C, @@ -1374,7 +1384,8 @@ class NonTypeTemplateParmDecl final : public DeclaratorDecl, protected TemplateParmPosition, private llvm::TrailingObjects> { + std::pair, + Expr *> { friend class ASTDeclReader; friend TrailingObjects; @@ -1429,10 +1440,12 @@ class NonTypeTemplateParmDecl final ArrayRef ExpandedTInfos); static NonTypeTemplateParmDecl *CreateDeserialized(ASTContext &C, - unsigned ID); + unsigned ID, + bool HasTypeConstraint); static NonTypeTemplateParmDecl *CreateDeserialized(ASTContext &C, unsigned ID, - unsigned NumExpandedTypes); + unsigned NumExpandedTypes, + bool HasTypeConstraint); using TemplateParmPosition::getDepth; using TemplateParmPosition::setDepth; @@ -1543,20 +1556,22 @@ class NonTypeTemplateParmDecl final return TypesAndInfos[I].second; } - /// Return the type-constraint in the placeholder type of this non-type + /// Return the constraint introduced by the placeholder type of this non-type /// template parameter (if any). - TypeConstraint *getPlaceholderTypeConstraint() const { - // TODO: Concepts: Implement once we have actual placeholders with type - // constraints. - return nullptr; + Expr *getPlaceholderTypeConstraint() const { + return hasPlaceholderTypeConstraint() ? *getTrailingObjects() : + nullptr; + } + + void setPlaceholderTypeConstraint(Expr *E) { + *getTrailingObjects() = E; } /// Determine whether this non-type template parameter's type has a /// placeholder with a type-constraint. bool hasPlaceholderTypeConstraint() const { - // TODO: Concepts: Implement once we have actual placeholders with type - // constraints. - return false; + auto *AT = getType()->getContainedAutoType(); + return AT && AT->isConstrained(); } /// \brief Get the associated-constraints of this template parameter. @@ -1566,8 +1581,8 @@ class NonTypeTemplateParmDecl final /// Use this instead of getPlaceholderImmediatelyDeclaredConstraint for /// concepts APIs that accept an ArrayRef of constraint expressions. void getAssociatedConstraints(llvm::SmallVectorImpl &AC) const { - if (TypeConstraint *TC = getPlaceholderTypeConstraint()) - AC.push_back(TC->getImmediatelyDeclaredConstraint()); + if (Expr *E = getPlaceholderTypeConstraint()) + AC.push_back(E); } // Implement isa/cast/dyncast/etc. diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 16956c27a114f..7ff53ef7c6534 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -3955,14 +3955,18 @@ class StmtExpr : public Expr { Stmt *SubStmt; SourceLocation LParenLoc, RParenLoc; public: - // FIXME: Does type-dependence need to be computed differently? - // FIXME: Do we need to compute instantiation instantiation-dependence for - // statements? (ugh!) - StmtExpr(CompoundStmt *substmt, QualType T, - SourceLocation lp, SourceLocation rp) : - Expr(StmtExprClass, T, VK_RValue, OK_Ordinary, - T->isDependentType(), false, false, false), - SubStmt(substmt), LParenLoc(lp), RParenLoc(rp) { } + StmtExpr(CompoundStmt *SubStmt, QualType T, SourceLocation LParenLoc, + SourceLocation RParenLoc, unsigned TemplateDepth) + : // We treat a statement-expression in a dependent context as + // always being value- and instantiation-dependent. This matches the + // behavior of lambda-expressions and GCC. + Expr(StmtExprClass, T, VK_RValue, OK_Ordinary, T->isDependentType(), + TemplateDepth != 0, TemplateDepth != 0, false), + SubStmt(SubStmt), LParenLoc(LParenLoc), RParenLoc(RParenLoc) { + // FIXME: A templated statement expression should have an associated + // DeclContext so that nested declarations always have a dependent context. + StmtExprBits.TemplateDepth = TemplateDepth; + } /// Build an empty statement expression. explicit StmtExpr(EmptyShell Empty) : Expr(StmtExprClass, Empty) { } @@ -3979,6 +3983,8 @@ class StmtExpr : public Expr { SourceLocation getRParenLoc() const { return RParenLoc; } void setRParenLoc(SourceLocation L) { RParenLoc = L; } + unsigned getTemplateDepth() const { return StmtExprBits.TemplateDepth; } + static bool classof(const Stmt *T) { return T->getStmtClass() == StmtExprClass; } diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h index 2c29409e0ca57..cea360d12e91e 100644 --- a/clang/include/clang/AST/ExprCXX.h +++ b/clang/include/clang/AST/ExprCXX.h @@ -14,7 +14,6 @@ #ifndef LLVM_CLANG_AST_EXPRCXX_H #define LLVM_CLANG_AST_EXPRCXX_H -#include "clang/AST/ASTConcept.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclBase.h" #include "clang/AST/DeclCXX.h" @@ -4836,99 +4835,6 @@ class BuiltinBitCastExpr final } }; -/// \brief Represents the specialization of a concept - evaluates to a prvalue -/// of type bool. -/// -/// According to C++2a [expr.prim.id]p3 an id-expression that denotes the -/// specialization of a concept results in a prvalue of type bool. -class ConceptSpecializationExpr final : public Expr, public ConceptReference, - private llvm::TrailingObjects { - friend class ASTStmtReader; - friend TrailingObjects; -public: - using SubstitutionDiagnostic = std::pair; - -protected: - /// \brief The number of template arguments in the tail-allocated list of - /// converted template arguments. - unsigned NumTemplateArgs; - - /// \brief Information about the satisfaction of the named concept with the - /// given arguments. If this expression is value dependent, this is to be - /// ignored. - ASTConstraintSatisfaction *Satisfaction; - - ConceptSpecializationExpr(const ASTContext &C, NestedNameSpecifierLoc NNS, - SourceLocation TemplateKWLoc, - DeclarationNameInfo ConceptNameInfo, - NamedDecl *FoundDecl, ConceptDecl *NamedConcept, - const ASTTemplateArgumentListInfo *ArgsAsWritten, - ArrayRef ConvertedArgs, - const ConstraintSatisfaction *Satisfaction); - - ConceptSpecializationExpr(EmptyShell Empty, unsigned NumTemplateArgs); - -public: - - static ConceptSpecializationExpr * - Create(const ASTContext &C, NestedNameSpecifierLoc NNS, - SourceLocation TemplateKWLoc, DeclarationNameInfo ConceptNameInfo, - NamedDecl *FoundDecl, ConceptDecl *NamedConcept, - const ASTTemplateArgumentListInfo *ArgsAsWritten, - ArrayRef ConvertedArgs, - const ConstraintSatisfaction *Satisfaction); - - static ConceptSpecializationExpr * - Create(ASTContext &C, EmptyShell Empty, unsigned NumTemplateArgs); - - ArrayRef getTemplateArguments() const { - return ArrayRef(getTrailingObjects(), - NumTemplateArgs); - } - - /// \brief Set new template arguments for this concept specialization. - void setTemplateArguments(ArrayRef Converted); - - /// \brief Whether or not the concept with the given arguments was satisfied - /// when the expression was created. - /// The expression must not be dependent. - bool isSatisfied() const { - assert(!isValueDependent() - && "isSatisfied called on a dependent ConceptSpecializationExpr"); - return Satisfaction->IsSatisfied; - } - - /// \brief Get elaborated satisfaction info about the template arguments' - /// satisfaction of the named concept. - /// The expression must not be dependent. - const ASTConstraintSatisfaction &getSatisfaction() const { - assert(!isValueDependent() - && "getSatisfaction called on dependent ConceptSpecializationExpr"); - return *Satisfaction; - } - - static bool classof(const Stmt *T) { - return T->getStmtClass() == ConceptSpecializationExprClass; - } - - SourceLocation getBeginLoc() const LLVM_READONLY { - return ConceptName.getBeginLoc(); - } - - SourceLocation getEndLoc() const LLVM_READONLY { - return ArgsAsWritten->RAngleLoc; - } - - // Iterators - child_range children() { - return child_range(child_iterator(), child_iterator()); - } - const_child_range children() const { - return const_child_range(const_child_iterator(), const_child_iterator()); - } -}; - } // namespace clang #endif // LLVM_CLANG_AST_EXPRCXX_H diff --git a/clang/include/clang/AST/ExprConcepts.h b/clang/include/clang/AST/ExprConcepts.h new file mode 100644 index 0000000000000..271d487e2fc9b --- /dev/null +++ b/clang/include/clang/AST/ExprConcepts.h @@ -0,0 +1,553 @@ +//===- ExprConcepts.h - C++2a Concepts expressions --------------*- 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 +// +//===----------------------------------------------------------------------===// +// +/// \file +/// Defines Expressions and AST nodes for C++2a concepts. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_EXPRCONCEPTS_H +#define LLVM_CLANG_AST_EXPRCONCEPTS_H + +#include "clang/AST/ASTContext.h" +#include "clang/AST/ASTConcept.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclarationName.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/Expr.h" +#include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/TemplateBase.h" +#include "clang/AST/Type.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/Support/TrailingObjects.h" +#include +#include + +namespace clang { +class ASTStmtReader; +class ASTStmtWriter; + +/// \brief Represents the specialization of a concept - evaluates to a prvalue +/// of type bool. +/// +/// According to C++2a [expr.prim.id]p3 an id-expression that denotes the +/// specialization of a concept results in a prvalue of type bool. +class ConceptSpecializationExpr final : public Expr, public ConceptReference, + private llvm::TrailingObjects { + friend class ASTStmtReader; + friend TrailingObjects; +public: + using SubstitutionDiagnostic = std::pair; + +protected: + /// \brief The number of template arguments in the tail-allocated list of + /// converted template arguments. + unsigned NumTemplateArgs; + + /// \brief Information about the satisfaction of the named concept with the + /// given arguments. If this expression is value dependent, this is to be + /// ignored. + ASTConstraintSatisfaction *Satisfaction; + + ConceptSpecializationExpr(const ASTContext &C, NestedNameSpecifierLoc NNS, + SourceLocation TemplateKWLoc, + DeclarationNameInfo ConceptNameInfo, + NamedDecl *FoundDecl, ConceptDecl *NamedConcept, + const ASTTemplateArgumentListInfo *ArgsAsWritten, + ArrayRef ConvertedArgs, + const ConstraintSatisfaction *Satisfaction); + + ConceptSpecializationExpr(const ASTContext &C, ConceptDecl *NamedConcept, + ArrayRef ConvertedArgs, + const ConstraintSatisfaction *Satisfaction, + bool Dependent, + bool ContainsUnexpandedParameterPack); + + ConceptSpecializationExpr(EmptyShell Empty, unsigned NumTemplateArgs); + +public: + + static ConceptSpecializationExpr * + Create(const ASTContext &C, NestedNameSpecifierLoc NNS, + SourceLocation TemplateKWLoc, DeclarationNameInfo ConceptNameInfo, + NamedDecl *FoundDecl, ConceptDecl *NamedConcept, + const ASTTemplateArgumentListInfo *ArgsAsWritten, + ArrayRef ConvertedArgs, + const ConstraintSatisfaction *Satisfaction); + + static ConceptSpecializationExpr * + Create(const ASTContext &C, ConceptDecl *NamedConcept, + ArrayRef ConvertedArgs, + const ConstraintSatisfaction *Satisfaction, + bool Dependent, + bool ContainsUnexpandedParameterPack); + + static ConceptSpecializationExpr * + Create(ASTContext &C, EmptyShell Empty, unsigned NumTemplateArgs); + + ArrayRef getTemplateArguments() const { + return ArrayRef(getTrailingObjects(), + NumTemplateArgs); + } + + /// \brief Set new template arguments for this concept specialization. + void setTemplateArguments(ArrayRef Converted); + + /// \brief Whether or not the concept with the given arguments was satisfied + /// when the expression was created. + /// The expression must not be dependent. + bool isSatisfied() const { + assert(!isValueDependent() + && "isSatisfied called on a dependent ConceptSpecializationExpr"); + return Satisfaction->IsSatisfied; + } + + /// \brief Get elaborated satisfaction info about the template arguments' + /// satisfaction of the named concept. + /// The expression must not be dependent. + const ASTConstraintSatisfaction &getSatisfaction() const { + assert(!isValueDependent() + && "getSatisfaction called on dependent ConceptSpecializationExpr"); + return *Satisfaction; + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ConceptSpecializationExprClass; + } + + SourceLocation getBeginLoc() const LLVM_READONLY { + return ConceptName.getBeginLoc(); + } + + SourceLocation getEndLoc() const LLVM_READONLY { + return ArgsAsWritten->RAngleLoc; + } + + // Iterators + child_range children() { + return child_range(child_iterator(), child_iterator()); + } + const_child_range children() const { + return const_child_range(const_child_iterator(), const_child_iterator()); + } +}; + +namespace concepts { + +/// \brief A static requirement that can be used in a requires-expression to +/// check properties of types and expression. +class Requirement { +public: + // Note - simple and compound requirements are both represented by the same + // class (ExprRequirement). + enum RequirementKind { RK_Type, RK_Simple, RK_Compound, RK_Nested }; +private: + const RequirementKind Kind; + bool Dependent : 1; + bool ContainsUnexpandedParameterPack : 1; + bool Satisfied : 1; +public: + struct SubstitutionDiagnostic { + StringRef SubstitutedEntity; + // FIXME: Store diagnostics semantically and not as prerendered strings. + // Fixing this probably requires serialization of PartialDiagnostic + // objects. + SourceLocation DiagLoc; + StringRef DiagMessage; + }; + + Requirement(RequirementKind Kind, bool IsDependent, + bool ContainsUnexpandedParameterPack, bool IsSatisfied = true) : + Kind(Kind), Dependent(IsDependent), + ContainsUnexpandedParameterPack(ContainsUnexpandedParameterPack), + Satisfied(IsSatisfied) {} + + RequirementKind getKind() const { return Kind; } + + bool isSatisfied() const { + assert(!Dependent && + "isSatisfied can only be called on non-dependent requirements."); + return Satisfied; + } + + void setSatisfied(bool IsSatisfied) { + assert(!Dependent && + "setSatisfied can only be called on non-dependent requirements."); + Satisfied = IsSatisfied; + } + + void setDependent(bool IsDependent) { Dependent = IsDependent; } + bool isDependent() const { return Dependent; } + + void setContainsUnexpandedParameterPack(bool Contains) { + ContainsUnexpandedParameterPack = Contains; + } + bool containsUnexpandedParameterPack() const { + return ContainsUnexpandedParameterPack; + } +}; + +/// \brief A requires-expression requirement which queries the existence of a +/// type name or type template specialization ('type' requirements). +class TypeRequirement : public Requirement { +public: + enum SatisfactionStatus { + SS_Dependent, + SS_SubstitutionFailure, + SS_Satisfied + }; +private: + llvm::PointerUnion Value; + SatisfactionStatus Status; +public: + friend ASTStmtReader; + friend ASTStmtWriter; + + /// \brief Construct a type requirement from a type. If the given type is not + /// dependent, this indicates that the type exists and the requirement will be + /// satisfied. Otherwise, the SubstitutionDiagnostic constructor is to be + /// used. + TypeRequirement(TypeSourceInfo *T); + + /// \brief Construct a type requirement when the nested name specifier is + /// invalid due to a bad substitution. The requirement is unsatisfied. + TypeRequirement(SubstitutionDiagnostic *Diagnostic) : + Requirement(RK_Type, false, false, false), Value(Diagnostic), + Status(SS_SubstitutionFailure) {} + + SatisfactionStatus getSatisfactionStatus() const { return Status; } + void setSatisfactionStatus(SatisfactionStatus Status) { + this->Status = Status; + } + + bool isSubstitutionFailure() const { + return Status == SS_SubstitutionFailure; + } + + SubstitutionDiagnostic *getSubstitutionDiagnostic() const { + assert(Status == SS_SubstitutionFailure && + "Attempted to get substitution diagnostic when there has been no " + "substitution failure."); + return Value.get(); + } + + TypeSourceInfo *getType() const { + assert(!isSubstitutionFailure() && + "Attempted to get type when there has been a substitution failure."); + return Value.get(); + } + + static bool classof(const Requirement *R) { + return R->getKind() == RK_Type; + } +}; + +/// \brief A requires-expression requirement which queries the validity and +/// properties of an expression ('simple' and 'compound' requirements). +class ExprRequirement : public Requirement { +public: + enum SatisfactionStatus { + SS_Dependent, + SS_ExprSubstitutionFailure, + SS_NoexceptNotMet, + SS_TypeRequirementSubstitutionFailure, + SS_ConstraintsNotSatisfied, + SS_Satisfied + }; + class ReturnTypeRequirement { + llvm::PointerIntPair< + llvm::PointerUnion, + 1, bool> + TypeConstraintInfo; + public: + friend ASTStmtReader; + friend ASTStmtWriter; + + /// \brief No return type requirement was specified. + ReturnTypeRequirement() : TypeConstraintInfo(nullptr, 0) {} + + /// \brief A return type requirement was specified but it was a + /// substitution failure. + ReturnTypeRequirement(SubstitutionDiagnostic *SubstDiag) : + TypeConstraintInfo(SubstDiag, 0) {} + + /// \brief A 'type constraint' style return type requirement. + /// \param TPL an invented template parameter list containing a single + /// type parameter with a type-constraint. + // TODO: Can we maybe not save the whole template parameter list and just + // the type constraint? Saving the whole TPL makes it easier to handle in + // serialization but is less elegant. + ReturnTypeRequirement(TemplateParameterList *TPL); + + bool isDependent() const { + return TypeConstraintInfo.getInt(); + } + + bool containsUnexpandedParameterPack() const { + if (!isTypeConstraint()) + return false; + return getTypeConstraintTemplateParameterList() + ->containsUnexpandedParameterPack(); + } + + bool isEmpty() const { + return TypeConstraintInfo.getPointer().isNull(); + } + + bool isSubstitutionFailure() const { + return !isEmpty() && + TypeConstraintInfo.getPointer().is(); + } + + bool isTypeConstraint() const { + return !isEmpty() && + TypeConstraintInfo.getPointer().is(); + } + + SubstitutionDiagnostic *getSubstitutionDiagnostic() const { + assert(isSubstitutionFailure()); + return TypeConstraintInfo.getPointer().get(); + } + + const TypeConstraint *getTypeConstraint() const; + + TemplateParameterList *getTypeConstraintTemplateParameterList() const { + assert(isTypeConstraint()); + return TypeConstraintInfo.getPointer().get(); + } + }; +private: + llvm::PointerUnion Value; + SourceLocation NoexceptLoc; // May be empty if noexcept wasn't specified. + ReturnTypeRequirement TypeReq; + ConceptSpecializationExpr *SubstitutedConstraintExpr; + SatisfactionStatus Status; +public: + friend ASTStmtReader; + friend ASTStmtWriter; + + /// \brief Construct a compound requirement. + /// \param E the expression which is checked by this requirement. + /// \param IsSimple whether this was a simple requirement in source. + /// \param NoexceptLoc the location of the noexcept keyword, if it was + /// specified, otherwise an empty location. + /// \param Req the requirement for the type of the checked expression. + /// \param Status the satisfaction status of this requirement. + ExprRequirement( + Expr *E, bool IsSimple, SourceLocation NoexceptLoc, + ReturnTypeRequirement Req, SatisfactionStatus Status, + ConceptSpecializationExpr *SubstitutedConstraintExpr = nullptr); + + /// \brief Construct a compound requirement whose expression was a + /// substitution failure. The requirement is not satisfied. + /// \param E the diagnostic emitted while instantiating the original + /// expression. + /// \param IsSimple whether this was a simple requirement in source. + /// \param NoexceptLoc the location of the noexcept keyword, if it was + /// specified, otherwise an empty location. + /// \param Req the requirement for the type of the checked expression (omit + /// if no requirement was specified). + ExprRequirement(SubstitutionDiagnostic *E, bool IsSimple, + SourceLocation NoexceptLoc, ReturnTypeRequirement Req = {}); + + bool isSimple() const { return getKind() == RK_Simple; } + bool isCompound() const { return getKind() == RK_Compound; } + + bool hasNoexceptRequirement() const { return NoexceptLoc.isValid(); } + SourceLocation getNoexceptLoc() const { return NoexceptLoc; } + + SatisfactionStatus getSatisfactionStatus() const { return Status; } + + bool isExprSubstitutionFailure() const { + return Status == SS_ExprSubstitutionFailure; + } + + const ReturnTypeRequirement &getReturnTypeRequirement() const { + return TypeReq; + } + + ConceptSpecializationExpr * + getReturnTypeRequirementSubstitutedConstraintExpr() const { + assert(Status >= SS_TypeRequirementSubstitutionFailure); + return SubstitutedConstraintExpr; + } + + SubstitutionDiagnostic *getExprSubstitutionDiagnostic() const { + assert(isExprSubstitutionFailure() && + "Attempted to get expression substitution diagnostic when there has " + "been no expression substitution failure"); + return Value.get(); + } + + Expr *getExpr() const { + assert(!isExprSubstitutionFailure() && + "ExprRequirement has no expression because there has been a " + "substitution failure."); + return Value.get(); + } + + static bool classof(const Requirement *R) { + return R->getKind() == RK_Compound || R->getKind() == RK_Simple; + } +}; + +/// \brief A requires-expression requirement which is satisfied when a general +/// constraint expression is satisfied ('nested' requirements). +class NestedRequirement : public Requirement { + llvm::PointerUnion Value; + const ASTConstraintSatisfaction *Satisfaction = nullptr; + +public: + friend ASTStmtReader; + friend ASTStmtWriter; + + NestedRequirement(SubstitutionDiagnostic *SubstDiag) : + Requirement(RK_Nested, /*Dependent=*/false, + /*ContainsUnexpandedParameterPack*/false, + /*Satisfied=*/false), Value(SubstDiag) {} + + NestedRequirement(Expr *Constraint) : + Requirement(RK_Nested, /*Dependent=*/true, + Constraint->containsUnexpandedParameterPack()), + Value(Constraint) { + assert(Constraint->isInstantiationDependent() && + "Nested requirement with non-dependent constraint must be " + "constructed with a ConstraintSatisfaction object"); + } + + NestedRequirement(ASTContext &C, Expr *Constraint, + const ConstraintSatisfaction &Satisfaction) : + Requirement(RK_Nested, Constraint->isInstantiationDependent(), + Constraint->containsUnexpandedParameterPack(), + Satisfaction.IsSatisfied), + Value(Constraint), + Satisfaction(ASTConstraintSatisfaction::Create(C, Satisfaction)) {} + + bool isSubstitutionFailure() const { + return Value.is(); + } + + SubstitutionDiagnostic *getSubstitutionDiagnostic() const { + assert(isSubstitutionFailure() && + "getSubstitutionDiagnostic() may not be called when there was no " + "substitution failure."); + return Value.get(); + } + + Expr *getConstraintExpr() const { + assert(!isSubstitutionFailure() && "getConstraintExpr() may not be called " + "on nested requirements with " + "substitution failures."); + return Value.get(); + } + + const ASTConstraintSatisfaction &getConstraintSatisfaction() const { + assert(!isSubstitutionFailure() && "getConstraintSatisfaction() may not be " + "called on nested requirements with " + "substitution failures."); + return *Satisfaction; + } + + static bool classof(const Requirement *R) { + return R->getKind() == RK_Nested; + } +}; + +} // namespace concepts + +/// C++2a [expr.prim.req]: +/// A requires-expression provides a concise way to express requirements on +/// template arguments. A requirement is one that can be checked by name +/// lookup (6.4) or by checking properties of types and expressions. +/// [...] +/// A requires-expression is a prvalue of type bool [...] +class RequiresExpr final : public Expr, + llvm::TrailingObjects { + friend TrailingObjects; + friend class ASTStmtReader; + + unsigned NumLocalParameters; + unsigned NumRequirements; + RequiresExprBodyDecl *Body; + SourceLocation RBraceLoc; + + unsigned numTrailingObjects(OverloadToken) const { + return NumLocalParameters; + } + + unsigned numTrailingObjects(OverloadToken) const { + return NumRequirements; + } + + RequiresExpr(ASTContext &C, SourceLocation RequiresKWLoc, + RequiresExprBodyDecl *Body, + ArrayRef LocalParameters, + ArrayRef Requirements, + SourceLocation RBraceLoc); + RequiresExpr(ASTContext &C, EmptyShell Empty, unsigned NumLocalParameters, + unsigned NumRequirements); + +public: + static RequiresExpr * + Create(ASTContext &C, SourceLocation RequiresKWLoc, + RequiresExprBodyDecl *Body, ArrayRef LocalParameters, + ArrayRef Requirements, + SourceLocation RBraceLoc); + static RequiresExpr * + Create(ASTContext &C, EmptyShell Empty, unsigned NumLocalParameters, + unsigned NumRequirements); + + ArrayRef getLocalParameters() const { + return {getTrailingObjects(), NumLocalParameters}; + } + + RequiresExprBodyDecl *getBody() const { return Body; } + + ArrayRef getRequirements() const { + return {getTrailingObjects(), NumRequirements}; + } + + /// \brief Whether or not the requires clause is satisfied. + /// The expression must not be dependent. + bool isSatisfied() const { + assert(!isValueDependent() + && "isSatisfied called on a dependent RequiresExpr"); + return RequiresExprBits.IsSatisfied; + } + + SourceLocation getRequiresKWLoc() const { + return RequiresExprBits.RequiresKWLoc; + } + + SourceLocation getRBraceLoc() const { return RBraceLoc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == RequiresExprClass; + } + + SourceLocation getBeginLoc() const LLVM_READONLY { + return RequiresExprBits.RequiresKWLoc; + } + SourceLocation getEndLoc() const LLVM_READONLY { + return RBraceLoc; + } + + // Iterators + child_range children() { + return child_range(child_iterator(), child_iterator()); + } + const_child_range children() const { + return const_child_range(const_child_iterator(), const_child_iterator()); + } +}; + +} // namespace clang + +#endif // LLVM_CLANG_AST_EXPRCONCEPTS_H \ No newline at end of file diff --git a/clang/include/clang/AST/PropertiesBase.td b/clang/include/clang/AST/PropertiesBase.td index 9aacdb9fee362..ba0f237a3bc3c 100644 --- a/clang/include/clang/AST/PropertiesBase.td +++ b/clang/include/clang/AST/PropertiesBase.td @@ -99,6 +99,8 @@ def DeclRef : RefPropertyType<"Decl"> { let ConstWhenWriting = 1; } SubclassPropertyType<"TagDecl", DeclRef>; def TemplateDeclRef : SubclassPropertyType<"TemplateDecl", DeclRef>; + def ConceptDeclRef : + SubclassPropertyType<"ConceptDecl", DeclRef>; def TemplateTypeParmDeclRef : SubclassPropertyType<"TemplateTypeParmDecl", DeclRef>; def TemplateTemplateParmDeclRef : diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index f8ab8e451d8c3..86521d82c6ff1 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -23,6 +23,7 @@ #include "clang/AST/DeclOpenMP.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" +#include "clang/AST/ExprConcepts.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" #include "clang/AST/ExprOpenMP.h" @@ -1039,7 +1040,13 @@ DEF_TRAVERSE_TYPE(UnaryTransformType, { TRY_TO(TraverseType(T->getUnderlyingType())); }) -DEF_TRAVERSE_TYPE(AutoType, { TRY_TO(TraverseType(T->getDeducedType())); }) +DEF_TRAVERSE_TYPE(AutoType, { + TRY_TO(TraverseType(T->getDeducedType())); + if (T->isConstrained()) { + TRY_TO(TraverseDecl(T->getTypeConstraintConcept())); + TRY_TO(TraverseTemplateArguments(T->getArgs(), T->getNumArgs())); + } +}) DEF_TRAVERSE_TYPE(DeducedTemplateSpecializationType, { TRY_TO(TraverseTemplateName(T->getTemplateName())); TRY_TO(TraverseType(T->getDeducedType())); @@ -1286,6 +1293,12 @@ DEF_TRAVERSE_TYPELOC(UnaryTransformType, { DEF_TRAVERSE_TYPELOC(AutoType, { TRY_TO(TraverseType(TL.getTypePtr()->getDeducedType())); + if (TL.isConstrained()) { + TRY_TO(TraverseNestedNameSpecifierLoc(TL.getNestedNameSpecifierLoc())); + TRY_TO(TraverseDeclarationNameInfo(TL.getConceptNameInfo())); + for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I) + TRY_TO(TraverseTemplateArgumentLoc(TL.getArgLoc(I))); + } }) DEF_TRAVERSE_TYPELOC(DeducedTemplateSpecializationType, { @@ -2138,6 +2151,8 @@ DEF_TRAVERSE_DECL(ParmVarDecl, { TRY_TO(TraverseStmt(D->getDefaultArg())); }) +DEF_TRAVERSE_DECL(RequiresExprBodyDecl, {}) + #undef DEF_TRAVERSE_DECL // ----------------- Stmt traversal ----------------- @@ -2709,6 +2724,28 @@ DEF_TRAVERSE_STMT(ConceptSpecializationExpr, { TRY_TO(TraverseConceptReference(*S)); }) +DEF_TRAVERSE_STMT(RequiresExpr, { + TRY_TO(TraverseDecl(S->getBody())); + for (ParmVarDecl *Parm : S->getLocalParameters()) + TRY_TO(TraverseDecl(Parm)); + for (concepts::Requirement *Req : S->getRequirements()) + if (auto *TypeReq = dyn_cast(Req)) { + if (!TypeReq->isSubstitutionFailure()) + TRY_TO(TraverseTypeLoc(TypeReq->getType()->getTypeLoc())); + } else if (auto *ExprReq = dyn_cast(Req)) { + if (!ExprReq->isExprSubstitutionFailure()) + TRY_TO(TraverseStmt(ExprReq->getExpr())); + auto &RetReq = ExprReq->getReturnTypeRequirement(); + if (RetReq.isTypeConstraint()) + TRY_TO(TraverseTemplateParameterListHelper( + RetReq.getTypeConstraintTemplateParameterList())); + } else { + auto *NestedReq = cast(Req); + if (!NestedReq->isSubstitutionFailure()) + TRY_TO(TraverseStmt(NestedReq->getConstraintExpr())); + } +}) + // These literals (all of them) do not need any action. DEF_TRAVERSE_STMT(IntegerLiteral, {}) DEF_TRAVERSE_STMT(FixedPointLiteral, {}) diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h index eaacb1a5b252e..3aa2745937b1e 100644 --- a/clang/include/clang/AST/Stmt.h +++ b/clang/include/clang/AST/Stmt.h @@ -588,6 +588,18 @@ class alignas(void *) Stmt { unsigned Kind : 2; }; + class StmtExprBitfields { + friend class ASTStmtReader; + friend class StmtExpr; + + unsigned : NumExprBits; + + /// The number of levels of template parameters enclosing this statement + /// expression. Used to determine if a statement expression remains + /// dependent after instantiation. + unsigned TemplateDepth; + }; + //===--- C++ Expression bitfields classes ---===// class CXXOperatorCallExprBitfields { @@ -910,6 +922,17 @@ class alignas(void *) Stmt { SourceLocation NameLoc; }; + class RequiresExprBitfields { + friend class ASTStmtReader; + friend class ASTStmtWriter; + friend class RequiresExpr; + + unsigned : NumExprBits; + + unsigned IsSatisfied : 1; + SourceLocation RequiresKWLoc; + }; + //===--- C++ Coroutines TS bitfields classes ---===// class CoawaitExprBitfields { @@ -985,6 +1008,9 @@ class alignas(void *) Stmt { PseudoObjectExprBitfields PseudoObjectExprBits; SourceLocExprBitfields SourceLocExprBits; + // GNU Extensions. + StmtExprBitfields StmtExprBits; + // C++ Expressions CXXOperatorCallExprBitfields CXXOperatorCallExprBits; CXXRewrittenBinaryOperatorBitfields CXXRewrittenBinaryOperatorBits; @@ -1008,6 +1034,7 @@ class alignas(void *) Stmt { UnresolvedMemberExprBitfields UnresolvedMemberExprBits; CXXNoexceptExprBitfields CXXNoexceptExprBits; SubstNonTypeTemplateParmExprBitfields SubstNonTypeTemplateParmExprBits; + RequiresExprBitfields RequiresExprBits; // C++ Coroutines TS expressions CoawaitExprBitfields CoawaitBits; diff --git a/clang/include/clang/AST/StmtVisitor.h b/clang/include/clang/AST/StmtVisitor.h index d3be93d228ccb..3e5155199eace 100644 --- a/clang/include/clang/AST/StmtVisitor.h +++ b/clang/include/clang/AST/StmtVisitor.h @@ -13,6 +13,7 @@ #ifndef LLVM_CLANG_AST_STMTVISITOR_H #define LLVM_CLANG_AST_STMTVISITOR_H +#include "clang/AST/ExprConcepts.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" #include "clang/AST/ExprOpenMP.h" diff --git a/clang/include/clang/AST/TemplateBase.h b/clang/include/clang/AST/TemplateBase.h index 058a5bc0a0674..93f7b62b8aea2 100644 --- a/clang/include/clang/AST/TemplateBase.h +++ b/clang/include/clang/AST/TemplateBase.h @@ -637,7 +637,7 @@ struct ASTTemplateArgumentListInfo final } static const ASTTemplateArgumentListInfo * - Create(ASTContext &C, const TemplateArgumentListInfo &List); + Create(const ASTContext &C, const TemplateArgumentListInfo &List); }; /// Represents an explicit template argument list in C++, e.g., @@ -702,6 +702,11 @@ inline const TemplateArgument & return getArgs()[Idx]; } +inline const TemplateArgument &AutoType::getArg(unsigned Idx) const { + assert(Idx < getNumArgs() && "Template argument out of range"); + return getArgs()[Idx]; +} + } // namespace clang #endif // LLVM_CLANG_AST_TEMPLATEBASE_H diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index f5955c45fafc5..abc8136653fa2 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -58,6 +58,7 @@ namespace clang { class ExtQuals; class QualType; +class ConceptDecl; class TagDecl; class Type; @@ -1683,6 +1684,15 @@ class alignas(8) Type : public ExtQualsTypeCommonBase { /// Was this placeholder type spelled as 'auto', 'decltype(auto)', /// or '__auto_type'? AutoTypeKeyword value. unsigned Keyword : 2; + + /// The number of template arguments in the type-constraints, which is + /// expected to be able to hold at least 1024 according to [implimits]. + /// However as this limit is somewhat easy to hit with template + /// metaprogramming we'd prefer to keep it as large as possible. + /// At the moment it has been left as a non-bitfield since this type + /// safely fits in 64 bits as an unsigned, so there is no reason to + /// introduce the performance impact of a bitfield. + unsigned NumArgs; }; class SubstTemplateTypeParmPackTypeBitfields { @@ -4814,8 +4824,7 @@ class SubstTemplateTypeParmPackType : public Type, public llvm::FoldingSetNode { /// Common base class for placeholders for types that get replaced by /// placeholder type deduction: C++11 auto, C++14 decltype(auto), C++17 deduced -/// class template types, and (eventually) constrained type names from the C++ -/// Concepts TS. +/// class template types, and constrained type names. /// /// These types are usually a placeholder for a deduced type. However, before /// the initializer is attached, or (usually) if the initializer is @@ -4860,18 +4869,50 @@ class DeducedType : public Type { } }; -/// Represents a C++11 auto or C++14 decltype(auto) type. -class AutoType : public DeducedType, public llvm::FoldingSetNode { +/// Represents a C++11 auto or C++14 decltype(auto) type, possibly constrained +/// by a type-constraint. +class alignas(8) AutoType : public DeducedType, public llvm::FoldingSetNode { friend class ASTContext; // ASTContext creates these + ConceptDecl *TypeConstraintConcept; + AutoType(QualType DeducedAsType, AutoTypeKeyword Keyword, - bool IsDeducedAsDependent, bool IsDeducedAsPack) - : DeducedType(Auto, DeducedAsType, IsDeducedAsDependent, - IsDeducedAsDependent, IsDeducedAsPack) { - AutoTypeBits.Keyword = (unsigned)Keyword; + bool IsDeducedAsDependent, bool IsDeducedAsPack, ConceptDecl *CD, + ArrayRef TypeConstraintArgs); + + const TemplateArgument *getArgBuffer() const { + return reinterpret_cast(this+1); + } + + TemplateArgument *getArgBuffer() { + return reinterpret_cast(this+1); } public: + /// Retrieve the template arguments. + const TemplateArgument *getArgs() const { + return getArgBuffer(); + } + + /// Retrieve the number of template arguments. + unsigned getNumArgs() const { + return AutoTypeBits.NumArgs; + } + + const TemplateArgument &getArg(unsigned Idx) const; // in TemplateBase.h + + ArrayRef getTypeConstraintArguments() const { + return {getArgs(), getNumArgs()}; + } + + ConceptDecl *getTypeConstraintConcept() const { + return TypeConstraintConcept; + } + + bool isConstrained() const { + return TypeConstraintConcept != nullptr; + } + bool isDecltypeAuto() const { return getKeyword() == AutoTypeKeyword::DecltypeAuto; } @@ -4880,18 +4921,15 @@ class AutoType : public DeducedType, public llvm::FoldingSetNode { return (AutoTypeKeyword)AutoTypeBits.Keyword; } - void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getDeducedType(), getKeyword(), isDependentType(), - containsUnexpandedParameterPack()); + void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) { + Profile(ID, Context, getDeducedType(), getKeyword(), isDependentType(), + getTypeConstraintConcept(), getTypeConstraintArguments()); } - static void Profile(llvm::FoldingSetNodeID &ID, QualType Deduced, - AutoTypeKeyword Keyword, bool IsDependent, bool IsPack) { - ID.AddPointer(Deduced.getAsOpaquePtr()); - ID.AddInteger((unsigned)Keyword); - ID.AddBoolean(IsDependent); - ID.AddBoolean(IsPack); - } + static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, + QualType Deduced, AutoTypeKeyword Keyword, + bool IsDependent, ConceptDecl *CD, + ArrayRef Arguments); static bool classof(const Type *T) { return T->getTypeClass() == Auto; diff --git a/clang/include/clang/AST/TypeLoc.h b/clang/include/clang/AST/TypeLoc.h index c3baaa3e4174e..3fc53d823c376 100644 --- a/clang/include/clang/AST/TypeLoc.h +++ b/clang/include/clang/AST/TypeLoc.h @@ -14,6 +14,7 @@ #ifndef LLVM_CLANG_AST_TYPELOC_H #define LLVM_CLANG_AST_TYPELOC_H +#include "clang/AST/DeclarationName.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/TemplateBase.h" #include "clang/AST/Type.h" @@ -34,6 +35,7 @@ namespace clang { class Attr; class ASTContext; class CXXRecordDecl; +class ConceptDecl; class Expr; class ObjCInterfaceDecl; class ObjCProtocolDecl; @@ -181,6 +183,11 @@ class TypeLoc { /// AttributedTypeLoc, for those type attributes that behave as qualifiers TypeLoc findExplicitQualifierLoc() const; + /// Get the typeloc of an AutoType whose type will be deduced for a variable + /// with an initializer of this type. This looks through declarators like + /// pointer types, but not through decltype or typedefs. + AutoTypeLoc getContainedAutoTypeLoc() const; + /// Initializes this to state that every location in this /// type is the given location. /// @@ -1923,8 +1930,137 @@ class DeducedTypeLoc : public InheritingConcreteTypeLoc {}; +struct AutoTypeLocInfo : TypeSpecLocInfo { + NestedNameSpecifierLoc NestedNameSpec; + SourceLocation TemplateKWLoc; + SourceLocation ConceptNameLoc; + NamedDecl *FoundDecl; + SourceLocation LAngleLoc; + SourceLocation RAngleLoc; +}; + class AutoTypeLoc - : public InheritingConcreteTypeLoc { + : public ConcreteTypeLoc { +public: + AutoTypeKeyword getAutoKeyword() const { + return getTypePtr()->getKeyword(); + } + + bool isConstrained() const { + return getTypePtr()->isConstrained(); + } + + const NestedNameSpecifierLoc &getNestedNameSpecifierLoc() const { + return getLocalData()->NestedNameSpec; + } + + void setNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) { + getLocalData()->NestedNameSpec = NNS; + } + + SourceLocation getTemplateKWLoc() const { + return getLocalData()->TemplateKWLoc; + } + + void setTemplateKWLoc(SourceLocation Loc) { + getLocalData()->TemplateKWLoc = Loc; + } + + SourceLocation getConceptNameLoc() const { + return getLocalData()->ConceptNameLoc; + } + + void setConceptNameLoc(SourceLocation Loc) { + getLocalData()->ConceptNameLoc = Loc; + } + + NamedDecl *getFoundDecl() const { + return getLocalData()->FoundDecl; + } + + void setFoundDecl(NamedDecl *D) { + getLocalData()->FoundDecl = D; + } + + ConceptDecl *getNamedConcept() const { + return getTypePtr()->getTypeConstraintConcept(); + } + + DeclarationNameInfo getConceptNameInfo() const; + + bool hasExplicitTemplateArgs() const { + return getLocalData()->LAngleLoc.isValid(); + } + + SourceLocation getLAngleLoc() const { + return this->getLocalData()->LAngleLoc; + } + + void setLAngleLoc(SourceLocation Loc) { + this->getLocalData()->LAngleLoc = Loc; + } + + SourceLocation getRAngleLoc() const { + return this->getLocalData()->RAngleLoc; + } + + void setRAngleLoc(SourceLocation Loc) { + this->getLocalData()->RAngleLoc = Loc; + } + + unsigned getNumArgs() const { + return getTypePtr()->getNumArgs(); + } + + void setArgLocInfo(unsigned i, TemplateArgumentLocInfo AI) { + getArgInfos()[i] = AI; + } + + TemplateArgumentLocInfo getArgLocInfo(unsigned i) const { + return getArgInfos()[i]; + } + + TemplateArgumentLoc getArgLoc(unsigned i) const { + return TemplateArgumentLoc(getTypePtr()->getTypeConstraintArguments()[i], + getArgLocInfo(i)); + } + + SourceRange getLocalSourceRange() const { + return{ + isConstrained() + ? (getNestedNameSpecifierLoc() + ? getNestedNameSpecifierLoc().getBeginLoc() + : (getTemplateKWLoc().isValid() + ? getTemplateKWLoc() + : getConceptNameLoc())) + : getNameLoc(), + getNameLoc() + }; + } + + void copy(AutoTypeLoc Loc) { + unsigned size = getFullDataSize(); + assert(size == Loc.getFullDataSize()); + memcpy(Data, Loc.Data, size); + } + + void initializeLocal(ASTContext &Context, SourceLocation Loc); + + unsigned getExtraLocalDataSize() const { + return getNumArgs() * sizeof(TemplateArgumentLocInfo); + } + + unsigned getExtraLocalDataAlignment() const { + return alignof(TemplateArgumentLocInfo); + } + +private: + TemplateArgumentLocInfo *getArgInfos() const { + return static_cast(getExtraLocalData()); + } }; class DeducedTemplateSpecializationTypeLoc diff --git a/clang/include/clang/AST/TypeProperties.td b/clang/include/clang/AST/TypeProperties.td index 4df2e2f77e2b3..3cf56e5a5629a 100644 --- a/clang/include/clang/AST/TypeProperties.td +++ b/clang/include/clang/AST/TypeProperties.td @@ -395,6 +395,13 @@ let Class = AutoType in { def : Property<"keyword", AutoTypeKeyword> { let Read = [{ node->getKeyword() }]; } + def : Property<"typeConstraintConcept", Optional> { + let Read = [{ makeOptionalFromPointer( + const_cast(node->getTypeConstraintConcept())) }]; + } + def : Property<"typeConstraintArguments", Array> { + let Read = [{ node->getTypeConstraintArguments() }]; + } // FIXME: better enumerated value // Only really required when the deduced type is null def : Property<"dependence", UInt32> { @@ -406,7 +413,9 @@ let Class = AutoType in { def : Creator<[{ return ctx.getAutoType(makeNullableFromOptional(deducedType), keyword, /*isDependentWithoutDeducedType*/ dependence > 0, - /*isPackWithoutDeducedType*/ dependence > 1); + /*isPackWithoutDeducedType*/ dependence > 1, + makePointerFromOptional(typeConstraintConcept), + typeConstraintArguments); }]>; } diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 03d36ae7ab324..7976d08a5258d 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -3995,8 +3995,6 @@ def PatchableFunctionEntryDocs : Documentation { before the function entry and N-M NOPs after the function entry. This attribute takes precedence over the command line option ``-fpatchable-function-entry=N,M``. ``M`` defaults to 0 if omitted. - -Currently, only M=0 is supported. }]; } diff --git a/clang/include/clang/Basic/Builtins.def b/clang/include/clang/Basic/Builtins.def index d388afe7fae6e..1a6c85ce2dd36 100644 --- a/clang/include/clang/Basic/Builtins.def +++ b/clang/include/clang/Basic/Builtins.def @@ -788,6 +788,9 @@ BUILTIN(__builtin_abort, "v", "Fnr") BUILTIN(__builtin_index, "c*cC*i", "Fn") BUILTIN(__builtin_rindex, "c*cC*i", "Fn") +// ignored glibc builtin, see https://sourceware.org/bugzilla/show_bug.cgi?id=25399 +BUILTIN(__warn_memset_zero_len, "v", "nU") + // Microsoft builtins. These are only active with -fms-extensions. LANGBUILTIN(_alloca, "v*z", "n", ALL_MS_LANGUAGES) LANGBUILTIN(__annotation, "wC*.","n", ALL_MS_LANGUAGES) diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def index 50fc1836282f5..1ecae98b13b15 100644 --- a/clang/include/clang/Basic/CodeGenOptions.def +++ b/clang/include/clang/Basic/CodeGenOptions.def @@ -111,6 +111,7 @@ CODEGENOPT(XRayAlwaysEmitTypedEvents , 1, 0) VALUE_CODEGENOPT(XRayInstructionThreshold , 32, 200) VALUE_CODEGENOPT(PatchableFunctionEntryCount , 32, 0) ///< Number of NOPs at function entry +VALUE_CODEGENOPT(PatchableFunctionEntryOffset , 32, 0) CODEGENOPT(InstrumentForProfiling , 1, 0) ///< Set when -pg is enabled. CODEGENOPT(CallFEntry , 1, 0) ///< Set when -mfentry is enabled. diff --git a/clang/include/clang/Basic/Cuda.h b/clang/include/clang/Basic/Cuda.h index ef5d24dcf888e..da572957d10dd 100644 --- a/clang/include/clang/Basic/Cuda.h +++ b/clang/include/clang/Basic/Cuda.h @@ -11,6 +11,7 @@ namespace llvm { class StringRef; +class Twine; class VersionTuple; } // namespace llvm @@ -30,7 +31,7 @@ enum class CudaVersion { }; const char *CudaVersionToString(CudaVersion V); // Input is "Major.Minor" -CudaVersion CudaStringToVersion(llvm::StringRef S); +CudaVersion CudaStringToVersion(const llvm::Twine &S); enum class CudaArch { UNKNOWN, diff --git a/clang/include/clang/Basic/DeclNodes.td b/clang/include/clang/Basic/DeclNodes.td index c2c23237285b2..d5bbc604819f8 100644 --- a/clang/include/clang/Basic/DeclNodes.td +++ b/clang/include/clang/Basic/DeclNodes.td @@ -100,5 +100,6 @@ def OMPThreadPrivate : DeclNode; def OMPAllocate : DeclNode; def OMPRequires : DeclNode; def Empty : DeclNode; +def RequiresExprBody : DeclNode, DeclContext; def LifetimeExtendedTemporary : DeclNode; diff --git a/clang/include/clang/Basic/DiagnosticASTKinds.td b/clang/include/clang/Basic/DiagnosticASTKinds.td index 95505b00344f8..a0c15ba1cb055 100644 --- a/clang/include/clang/Basic/DiagnosticASTKinds.td +++ b/clang/include/clang/Basic/DiagnosticASTKinds.td @@ -13,7 +13,7 @@ def note_expr_divide_by_zero : Note<"division by zero">; def note_constexpr_invalid_cast : Note< "%select{reinterpret_cast|dynamic_cast|cast that performs the conversions of" " a reinterpret_cast|cast from %1}0 is not allowed in a constant expression" - "%select{| in C++ standards before C++2a||}0">; + "%select{| in C++ standards before C++20||}0">; def note_constexpr_invalid_downcast : Note< "cannot cast object of dynamic type %0 to type %1">; def note_constexpr_overflow : Note< @@ -33,7 +33,7 @@ def note_constexpr_no_return : Note< "control reached end of constexpr function">; def note_constexpr_virtual_call : Note< "cannot evaluate call to virtual function in a constant expression " - "in C++ standards before C++2a">; + "in C++ standards before C++20">; def note_constexpr_pure_virtual_call : Note< "pure virtual function %q0 called">; def note_constexpr_polymorphic_unknown_dynamic_type : Note< @@ -102,7 +102,7 @@ def note_constexpr_var_init_non_constant : Note< "initializer of %0 is not a constant expression">; def note_constexpr_typeid_polymorphic : Note< "typeid applied to expression of polymorphic type %0 is " - "not allowed in a constant expression in C++ standards before C++2a">; + "not allowed in a constant expression in C++ standards before C++20">; def note_constexpr_void_comparison : Note< "comparison between unequal pointers to void has unspecified result">; def note_constexpr_temporary_here : Note<"temporary created here">; diff --git a/clang/include/clang/Basic/DiagnosticCommonKinds.td b/clang/include/clang/Basic/DiagnosticCommonKinds.td index d6281f157eea7..5c7803d71e128 100644 --- a/clang/include/clang/Basic/DiagnosticCommonKinds.td +++ b/clang/include/clang/Basic/DiagnosticCommonKinds.td @@ -120,7 +120,7 @@ def err_enum_template : Error<"enumeration cannot be a template">; def warn_cxx20_compat_consteval : Warning< "'consteval' specifier is incompatible with C++ standards before C++20">, - InGroup, DefaultIgnore; + InGroup, DefaultIgnore; } diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td index 0fe14e4e05bee..48ece91d3c456 100644 --- a/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -60,6 +60,9 @@ def err_drv_cuda_version_unsupported : Error< "but installation at %3 is %4. Use --cuda-path to specify a different CUDA " "install, pass a different GPU arch with --cuda-gpu-arch, or pass " "--no-cuda-version-check.">; +def warn_drv_unknown_cuda_version: Warning< + "Unknown CUDA version %0. Assuming the latest supported version %1">, + InGroup; def err_drv_cuda_host_arch : Error<"unsupported architecture '%0' for host compilation.">; def err_drv_mix_cuda_hip : Error<"Mixed Cuda and HIP compilation is not supported.">; def err_drv_invalid_thread_model_for_target : Error< @@ -268,6 +271,9 @@ def warn_drv_unsupported_debug_info_opt_for_target : Warning< InGroup; def warn_c_kext : Warning< "ignoring -fapple-kext which is valid for C++ and Objective-C++ only">; +def warn_ignoring_fdiscard_for_bitcode : Warning< + "ignoring -fdiscard-value-names for LLVM Bitcode">, + InGroup; def warn_drv_input_file_unused : Warning< "%0: '%1' input unused%select{ when '%3' is present|}2">, InGroup; @@ -408,7 +414,7 @@ def err_drv_unsupported_indirect_jump_opt : Error< def err_drv_unknown_indirect_jump_opt : Error< "unknown '-mindirect-jump=' option '%0'">; def err_drv_unsupported_fpatchable_function_entry_argument : Error< - "the second argument of '-fpatchable-function-entry' must be 0 or omitted">; + "the second argument of '-fpatchable-function-entry' must be smaller than the first argument">; def warn_drv_unable_to_find_directory_expected : Warning< "unable to find %0 directory, expected to be in '%1'">, diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td index a798b498d4e9a..87fdfc89c634d 100644 --- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td @@ -105,6 +105,9 @@ def err_fe_invalid_wchar_type : Error<"invalid wchar_t type '%0'; must be one of 'char', 'short', 'int'">; def err_fe_invalid_exception_model : Error<"invalid exception model '%0' for target '%1'">; +def warn_fe_concepts_ts_flag : Warning< + "-fconcepts-ts is deprecated - use '-std=c++20' for Concepts support">, + InGroup; def warn_fe_serialized_diag_merge_failure : Warning< "unable to merge a subprocess's serialized diagnostics">, @@ -172,9 +175,9 @@ def note_incompatible_analyzer_plugin_api : Note< def err_module_build_requires_fmodules : Error< "module compilation requires '-fmodules'">; def err_module_interface_requires_cpp_modules : Error< - "module interface compilation requires '-std=c++2a' or '-fmodules-ts'">; + "module interface compilation requires '-std=c++20' or '-fmodules-ts'">; def err_header_module_requires_modules : Error< - "header module compilation requires '-fmodules', '-std=c++2a', or " + "header module compilation requires '-fmodules', '-std=c++20', or " "'-fmodules-ts'">; def warn_module_config_mismatch : Warning< "module file %0 cannot be loaded due to a configuration mismatch with the current " diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index a15fb908c5374..8e43052f30e2e 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -187,10 +187,10 @@ def Deprecated : DiagGroup<"deprecated", [DeprecatedAnonEnumEnumConversion, DeprecatedWritableStr]>, DiagCategory<"Deprecations">; -def CXX2aDesignator : DiagGroup<"c++2a-designator">; +def CXX20Designator : DiagGroup<"c++20-designator">; // Allow -Wno-c99-designator to be used to turn off all warnings on valid C99 -// designators (including the warning controlled by -Wc++2a-designator). -def C99Designator : DiagGroup<"c99-designator", [CXX2aDesignator]>; +// designators (including the warning controlled by -Wc++20-designator). +def C99Designator : DiagGroup<"c99-designator", [CXX20Designator]>; def GNUDesignator : DiagGroup<"gnu-designator">; def DynamicExceptionSpec @@ -246,9 +246,9 @@ def CXXPre14CompatPedantic : DiagGroup<"c++98-c++11-compat-pedantic", def CXXPre17Compat : DiagGroup<"c++98-c++11-c++14-compat">; def CXXPre17CompatPedantic : DiagGroup<"c++98-c++11-c++14-compat-pedantic", [CXXPre17Compat]>; -def CXXPre2aCompat : DiagGroup<"c++98-c++11-c++14-c++17-compat">; -def CXXPre2aCompatPedantic : DiagGroup<"c++98-c++11-c++14-c++17-compat-pedantic", - [CXXPre2aCompat]>; +def CXXPre20Compat : DiagGroup<"c++98-c++11-c++14-c++17-compat">; +def CXXPre20CompatPedantic : DiagGroup<"c++98-c++11-c++14-c++17-compat-pedantic", + [CXXPre20Compat]>; def CXX98CompatBindToTemporaryCopy : DiagGroup<"c++98-compat-bind-to-temporary-copy">; @@ -262,7 +262,7 @@ def CXX98Compat : DiagGroup<"c++98-compat", CXX98CompatUnnamedTypeTemplateArgs, CXXPre14Compat, CXXPre17Compat, - CXXPre2aCompat]>; + CXXPre20Compat]>; // Warnings for C++11 features which are Extensions in C++98 mode. def CXX98CompatPedantic : DiagGroup<"c++98-compat-pedantic", [CXX98Compat, @@ -270,7 +270,7 @@ def CXX98CompatPedantic : DiagGroup<"c++98-compat-pedantic", CXX98CompatExtraSemi, CXXPre14CompatPedantic, CXXPre17CompatPedantic, - CXXPre2aCompatPedantic]>; + CXXPre20CompatPedantic]>; def CXX11Narrowing : DiagGroup<"c++11-narrowing">; @@ -296,33 +296,35 @@ def CXX11Compat : DiagGroup<"c++11-compat", CXX11CompatDeprecatedWritableStr, CXXPre14Compat, CXXPre17Compat, - CXXPre2aCompat]>; + CXXPre20Compat]>; def : DiagGroup<"c++0x-compat", [CXX11Compat]>; def CXX11CompatPedantic : DiagGroup<"c++11-compat-pedantic", [CXX11Compat, CXXPre14CompatPedantic, CXXPre17CompatPedantic, - CXXPre2aCompatPedantic]>; + CXXPre20CompatPedantic]>; def CXX14Compat : DiagGroup<"c++14-compat", [CXXPre17Compat, - CXXPre2aCompat]>; + CXXPre20Compat]>; def CXX14CompatPedantic : DiagGroup<"c++14-compat-pedantic", [CXX14Compat, CXXPre17CompatPedantic, - CXXPre2aCompatPedantic]>; + CXXPre20CompatPedantic]>; def CXX17Compat : DiagGroup<"c++17-compat", [DeprecatedRegister, DeprecatedIncrementBool, CXX17CompatMangling, - CXXPre2aCompat]>; + CXXPre20Compat]>; def CXX17CompatPedantic : DiagGroup<"c++17-compat-pedantic", [CXX17Compat, - CXXPre2aCompatPedantic]>; + CXXPre20CompatPedantic]>; def : DiagGroup<"c++1z-compat", [CXX17Compat]>; -def CXX2aCompat : DiagGroup<"c++2a-compat">; -def CXX2aCompatPedantic : DiagGroup<"c++2a-compat-pedantic", - [CXX2aCompat]>; +def CXX20Compat : DiagGroup<"c++20-compat">; +def CXX20CompatPedantic : DiagGroup<"c++20-compat-pedantic", + [CXX20Compat]>; +def : DiagGroup<"c++2a-compat", [CXX20Compat]>; +def : DiagGroup<"c++2a-compat-pedantic", [CXX20CompatPedantic]>; def ExitTimeDestructors : DiagGroup<"exit-time-destructors">; def FlexibleArrayExtensions : DiagGroup<"flexible-array-extensions">; @@ -384,7 +386,10 @@ def GNULabelsAsValue : DiagGroup<"gnu-label-as-value">; def LiteralRange : DiagGroup<"literal-range">; def LocalTypeTemplateArgs : DiagGroup<"local-type-template-args", [CXX98CompatLocalTypeTemplateArgs]>; -def RangeLoopAnalysis : DiagGroup<"range-loop-analysis">; +def RangeLoopConstruct : DiagGroup<"range-loop-construct">; +def RangeLoopBindReference : DiagGroup<"range-loop-bind-reference">; +def RangeLoopAnalysis : DiagGroup<"range-loop-analysis", + [RangeLoopConstruct, RangeLoopBindReference]>; def ForLoopAnalysis : DiagGroup<"for-loop-analysis">; def LoopAnalysis : DiagGroup<"loop-analysis", [ForLoopAnalysis, RangeLoopAnalysis]>; @@ -858,14 +863,15 @@ def Most : DiagGroup<"most", [ Comment, DeleteNonVirtualDtor, Format, + ForLoopAnalysis, Implicit, InfiniteRecursion, IntInBoolContext, - LoopAnalysis, MismatchedTags, MissingBraces, Move, MultiChar, + RangeLoopConstruct, Reorder, ReturnType, SelfAssignment, @@ -951,13 +957,14 @@ def CXX14 : DiagGroup<"c++14-extensions", [CXX14BinaryLiteral]>; // earlier C++ versions. def CXX17 : DiagGroup<"c++17-extensions">; -// A warning group for warnings about using C++2a features as extensions in +// A warning group for warnings about using C++20 features as extensions in // earlier C++ versions. -def CXX2a : DiagGroup<"c++2a-extensions", [CXX2aDesignator]>; +def CXX20 : DiagGroup<"c++20-extensions", [CXX20Designator]>; def : DiagGroup<"c++0x-extensions", [CXX11]>; def : DiagGroup<"c++1y-extensions", [CXX14]>; def : DiagGroup<"c++1z-extensions", [CXX17]>; +def : DiagGroup<"c++2a-extensions", [CXX20]>; def DelegatingCtorCycles : DiagGroup<"delegating-ctor-cycles">; @@ -1007,7 +1014,8 @@ def MicrosoftExplicitConstructorCall : DiagGroup< def MicrosoftEnumValue : DiagGroup<"microsoft-enum-value">; def MicrosoftDefaultArgRedefinition : DiagGroup<"microsoft-default-arg-redefinition">; -def MicrosoftTemplate : DiagGroup<"microsoft-template">; +def MicrosoftTemplateShadow : DiagGroup<"microsoft-template-shadow">; +def MicrosoftTemplate : DiagGroup<"microsoft-template", [MicrosoftTemplateShadow]>; def MicrosoftInconsistentDllImport : DiagGroup<"inconsistent-dllimport">; def MicrosoftRedeclareStatic : DiagGroup<"microsoft-redeclare-static">; def MicrosoftEnumForwardReference : @@ -1113,6 +1121,9 @@ def SerializedDiagnostics : DiagGroup<"serialized-diagnostics">; // compiling CUDA C/C++ but which is not compatible with the CUDA spec. def CudaCompat : DiagGroup<"cuda-compat">; +// Warning about unknown CUDA SDK version. +def CudaUnknownVersion: DiagGroup<"unknown-cuda-version">; + // A warning group for warnings about features supported by HIP but // ignored by CUDA. def HIPOnly : DiagGroup<"hip-only">; diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td b/clang/include/clang/Basic/DiagnosticLexKinds.td index b64cbc23f8100..9e0449d341047 100644 --- a/clang/include/clang/Basic/DiagnosticLexKinds.td +++ b/clang/include/clang/Basic/DiagnosticLexKinds.td @@ -31,12 +31,12 @@ def warn_cxx98_compat_less_colon_colon : Warning< InGroup, DefaultIgnore; def warn_cxx17_compat_spaceship : Warning< - "'<=>' operator is incompatible with C++ standards before C++2a">, - InGroup, DefaultIgnore; + "'<=>' operator is incompatible with C++ standards before C++20">, + InGroup, DefaultIgnore; def warn_cxx2a_compat_spaceship : Warning< - "'<=>' is a single token in C++2a; " + "'<=>' is a single token in C++20; " "add a space to avoid a change in behavior">, - InGroup; + InGroup; // Trigraphs. def trigraph_ignored : Warning<"trigraph ignored">, InGroup; @@ -78,8 +78,8 @@ def ext_token_used : Extension<"extension used">, def warn_cxx11_keyword : Warning<"'%0' is a keyword in C++11">, InGroup, DefaultIgnore; -def warn_cxx2a_keyword : Warning<"'%0' is a keyword in C++2a">, - InGroup, DefaultIgnore; +def warn_cxx2a_keyword : Warning<"'%0' is a keyword in C++20">, + InGroup, DefaultIgnore; def ext_unterminated_char_or_string : ExtWarn< "missing terminating %select{'|'\"'}0 character">, InGroup; diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index cc6a74ac3e6dd..33adf093693f4 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -33,10 +33,6 @@ def err_asm_goto_cannot_have_output : Error< let CategoryName = "Parse Issue" in { -def warn_cxx2a_compat_explicit_bool : Warning< - "this expression will be parsed as explicit(bool) in C++2a">, - InGroup, DefaultIgnore; - def ext_empty_translation_unit : Extension< "ISO C requires a translation unit to contain at least one declaration">, InGroup>; @@ -245,10 +241,10 @@ def warn_cxx14_compat_nested_namespace_definition : Warning< "nested namespace definition is incompatible with C++ standards before C++17">, InGroup, DefaultIgnore; def ext_inline_nested_namespace_definition : ExtWarn< - "inline nested namespace definition is a C++2a extension">, InGroup; + "inline nested namespace definition is a C++20 extension">, InGroup; def warn_cxx17_compat_inline_nested_namespace_definition : Warning< "inline nested namespace definition is incompatible with C++ standards before" - " C++2a">, InGroup, DefaultIgnore; + " C++20">, InGroup, DefaultIgnore; def err_inline_nested_namespace_definition : Error< "nested namespace definition cannot be 'inline'">; def err_expected_semi_after_attribute_list : Error< @@ -593,11 +589,11 @@ def warn_cxx14_compat_init_statement : Warning< "%select{if|switch}0 initialization statements are incompatible with " "C++ standards before C++17">, DefaultIgnore, InGroup; def ext_for_range_init_stmt : ExtWarn< - "range-based for loop initialization statements are a C++2a extension">, - InGroup; + "range-based for loop initialization statements are a C++20 extension">, + InGroup; def warn_cxx17_compat_for_range_init_stmt : Warning< "range-based for loop initialization statements are incompatible with " - "C++ standards before C++2a">, DefaultIgnore, InGroup; + "C++ standards before C++20">, DefaultIgnore, InGroup; def warn_empty_init_statement : Warning< "empty initialization statement of '%select{if|switch|range-based for}0' " "has no effect">, InGroup, DefaultIgnore; @@ -684,6 +680,15 @@ def err_ms_property_expected_comma_or_rparen : Error< def err_ms_property_initializer : Error< "property declaration cannot have an in-class initializer">; +def warn_cxx2a_compat_explicit_bool : Warning< + "this expression will be parsed as explicit(bool) in C++20">, + InGroup, DefaultIgnore; +def warn_cxx17_compat_explicit_bool : Warning< + "explicit(bool) is incompatible with C++ standards before C++20">, + InGroup, DefaultIgnore; +def ext_explicit_bool : ExtWarn<"explicit(bool) is a C++20 extension">, + InGroup; + /// C++ Templates def err_expected_template : Error<"expected template">; def err_unknown_template_name : Error< @@ -739,6 +744,33 @@ def err_friend_explicit_instantiation : Error< def err_explicit_instantiation_enum : Error< "enumerations cannot be explicitly instantiated">; def err_expected_template_parameter : Error<"expected template parameter">; +def note_ill_formed_requires_expression_outside_template : Note< + "requires expression outside a template declaration may not contain invalid " + "types or expressions">; +def err_empty_requires_expr : Error< + "a requires expression must contain at least one requirement">; +def err_requires_expr_parameter_list_ellipsis : Error< + "varargs not allowed in requires expression">; +def err_requires_expr_type_req_illegal_identifier : Error< + "expected identifier or template-id in type requirement">; +def err_requires_expr_type_req_template_args_on_non_template : Error< + "template arguments provided for non-template '%0'">; +def err_expected_semi_requirement : Error< + "expected ';' at end of requirement">; +def err_requires_expr_missing_arrow : Error< + "expected '->' before expression type requirement">; +def err_requires_expr_expected_type_constraint : Error< + "expected concept name with optional arguments">; +def err_requires_expr_simple_requirement_noexcept : Error< + "'noexcept' can only be used in a compound requirement (with '{' '}' around " + "the expression)">; +def err_requires_expr_simple_requirement_unexpected_tok : Error< + "unexpected %0 after expression; did you intend to use a compound " + "requirement (with '{' '}' around the expression)?">; +def warn_requires_expr_in_simple_requirement : Warning< + "this requires expression will only be checked for syntactic validity; did " + "you intend to place it in a nested requirement? (add another 'requires' " + "before the expression)">, InGroup>; def err_missing_dependent_template_keyword : Error< "use 'template' keyword to treat '%0' as a dependent template name">; @@ -812,11 +844,11 @@ def warn_cxx98_compat_nonstatic_member_init : Warning< "in-class initialization of non-static data members is incompatible with C++98">, InGroup, DefaultIgnore; def ext_bitfield_member_init: ExtWarn< - "default member initializer for bit-field is a C++2a extension">, - InGroup; + "default member initializer for bit-field is a C++20 extension">, + InGroup; def warn_cxx17_compat_bitfield_member_init: Warning< "default member initializer for bit-field is incompatible with " - "C++ standards before C++2a">, InGroup, DefaultIgnore; + "C++ standards before C++20">, InGroup, DefaultIgnore; def err_incomplete_array_member_init: Error< "array bound cannot be deduced from an in-class initializer">; @@ -912,13 +944,13 @@ def warn_cxx14_compat_constexpr_on_lambda : Warning< def ext_constexpr_on_lambda_cxx17 : ExtWarn< "'constexpr' on lambda expressions is a C++17 extension">, InGroup; -// C++2a template lambdas +// C++20 template lambdas def ext_lambda_template_parameter_list: ExtWarn< - "explicit template parameter list for lambdas is a C++2a extension">, - InGroup; + "explicit template parameter list for lambdas is a C++20 extension">, + InGroup; def warn_cxx17_compat_lambda_template_parameter_list: Warning< "explicit template parameter list for lambdas is incompatible with " - "C++ standards before C++2a">, InGroup, DefaultIgnore; + "C++ standards before C++20">, InGroup, DefaultIgnore; def err_lambda_template_parameter_list_empty : Error< "lambda template parameter list cannot be empty">; @@ -1337,8 +1369,10 @@ let CategoryName = "Concepts Issue" in { def err_concept_definition_not_identifier : Error< "name defined in concept definition must be an identifier">; def ext_concept_legacy_bool_keyword : ExtWarn< - "ISO C++2a does not permit the 'bool' keyword after 'concept'">, + "ISO C++20 does not permit the 'bool' keyword after 'concept'">, InGroup>; +def err_placeholder_expected_auto_or_decltype_auto : Error< + "expected 'auto' or 'decltype(auto)' after concept name">; } } // end of Parser diagnostics diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 7d8231d140e44..9173774205059 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -193,10 +193,10 @@ def ext_flexible_array_init : Extension< // C++20 designated initializers def ext_cxx_designated_init : Extension< - "designated initializers are a C++20 extension">, InGroup; + "designated initializers are a C++20 extension">, InGroup; def warn_cxx17_compat_designated_init : Warning< "designated initializers are incompatible with C++ standards before C++20">, - InGroup, DefaultIgnore; + InGroup, DefaultIgnore; def ext_designated_init_mixed : ExtWarn< "mixture of designated and non-designated initializers in the same " "initializer list is a C99 extension">, InGroup; @@ -444,13 +444,13 @@ def err_decomp_decl_spec : Error< "%plural{1:'%1'|:with '%1' specifiers}0">; def ext_decomp_decl_spec : ExtWarn< "decomposition declaration declared " - "%plural{1:'%1'|:with '%1' specifiers}0 is a C++2a extension">, - InGroup; + "%plural{1:'%1'|:with '%1' specifiers}0 is a C++20 extension">, + InGroup; def warn_cxx17_compat_decomp_decl_spec : Warning< "decomposition declaration declared " "%plural{1:'%1'|:with '%1' specifiers}0 " - "is incompatible with C++ standards before C++2a">, - InGroup, DefaultIgnore; + "is incompatible with C++ standards before C++20">, + InGroup, DefaultIgnore; def err_decomp_decl_type : Error< "decomposition declaration cannot be declared with type %0; " "declared type must be 'auto' or reference to 'auto'">; @@ -1949,7 +1949,7 @@ def err_init_list_bad_dest_type : Error< "list">; def warn_cxx2a_compat_aggregate_init_with_ctors : Warning< "aggregate initialization of type %0 with user-declared constructors " - "is incompatible with C++2a">, DefaultIgnore, InGroup; + "is incompatible with C++20">, DefaultIgnore, InGroup; def err_reference_bind_to_bitfield : Error< "%select{non-const|volatile}0 reference cannot bind to " @@ -2102,12 +2102,18 @@ def err_auto_not_allowed : Error< "|in template argument|in typedef|in type alias|in function return type" "|in conversion function type|here|in lambda parameter" "|in type allocated by 'new'|in K&R-style function parameter" - "|in template parameter|in friend declaration}1">; + "|in template parameter|in friend declaration|in function prototype that is " + "not a function declaration|in requires expression parameter}1">; def err_dependent_deduced_tst : Error< "typename specifier refers to " "%select{class template|function template|variable template|alias template|" "template template parameter|template}0 member in %1; " "argument deduction not allowed here">; +def err_deduced_tst : Error< + "typename specifier refers to " + "%select{class template|function template|variable template|alias template|" + "template template parameter|template}0; argument deduction not allowed " + "here">; def err_auto_not_allowed_var_inst : Error< "'auto' variable template instantiation is not allowed">; def err_auto_var_requires_init : Error< @@ -2372,17 +2378,17 @@ def warn_for_range_const_reference_copy : Warning< "loop variable %0 " "%diff{has type $ but is initialized with type $" "| is initialized with a value of a different type}1,2 resulting in a copy">, - InGroup, DefaultIgnore; + InGroup, DefaultIgnore; def note_use_type_or_non_reference : Note< "use non-reference type %0 to keep the copy or type %1 to prevent copying">; def warn_for_range_variable_always_copy : Warning< "loop variable %0 is always a copy because the range of type %1 does not " "return a reference">, - InGroup, DefaultIgnore; + InGroup, DefaultIgnore; def note_use_non_reference_type : Note<"use non-reference type %0">; def warn_for_range_copy : Warning< "loop variable %0 of type %1 creates a copy from type %2">, - InGroup, DefaultIgnore; + InGroup, DefaultIgnore; def note_use_reference_type : Note<"use reference type %0 to prevent copying">; def err_objc_for_range_init_stmt : Error< "initialization statement is not supported when iterating over Objective-C " @@ -2432,7 +2438,7 @@ def err_constexpr_redecl_mismatch : Error< def err_constexpr_virtual : Error<"virtual function cannot be constexpr">; def warn_cxx17_compat_constexpr_virtual : Warning< "virtual constexpr functions are incompatible with " - "C++ standards before C++2a">, InGroup, DefaultIgnore; + "C++ standards before C++20">, InGroup, DefaultIgnore; def err_constexpr_virtual_base : Error< "constexpr %select{member function|constructor}0 not allowed in " "%select{struct|interface|class}1 with virtual base " @@ -2458,11 +2464,11 @@ def warn_cxx11_compat_constexpr_body_invalid_stmt : Warning< InGroup, DefaultIgnore; def ext_constexpr_body_invalid_stmt_cxx2a : ExtWarn< "use of this statement in a constexpr %select{function|constructor}0 " - "is a C++2a extension">, InGroup; + "is a C++20 extension">, InGroup; def warn_cxx17_compat_constexpr_body_invalid_stmt : Warning< "use of this statement in a constexpr %select{function|constructor}0 " - "is incompatible with C++ standards before C++2a">, - InGroup, DefaultIgnore; + "is incompatible with C++ standards before C++20">, + InGroup, DefaultIgnore; def ext_constexpr_type_definition : ExtWarn< "type definition in a constexpr %select{function|constructor}0 " "is a C++14 extension">, InGroup; @@ -2488,11 +2494,11 @@ def err_constexpr_local_var_non_literal_type : Error< "%select{function|constructor}0">; def ext_constexpr_local_var_no_init : ExtWarn< "uninitialized variable in a constexpr %select{function|constructor}0 " - "is a C++20 extension">, InGroup; + "is a C++20 extension">, InGroup; def warn_cxx17_compat_constexpr_local_var_no_init : Warning< "uninitialized variable in a constexpr %select{function|constructor}0 " "is incompatible with C++ standards before C++20">, - InGroup, DefaultIgnore; + InGroup, DefaultIgnore; def ext_constexpr_function_never_constant_expr : ExtWarn< "constexpr %select{function|constructor}0 never produces a " "constant expression">, InGroup>, DefaultError; @@ -2518,29 +2524,29 @@ def warn_cxx11_compat_constexpr_body_multiple_return : Warning< def note_constexpr_body_previous_return : Note< "previous return statement is here">; -// C++2a function try blocks in constexpr +// C++20 function try blocks in constexpr def ext_constexpr_function_try_block_cxx2a : ExtWarn< "function try block in constexpr %select{function|constructor}0 is " - "a C++2a extension">, InGroup; + "a C++20 extension">, InGroup; def warn_cxx17_compat_constexpr_function_try_block : Warning< "function try block in constexpr %select{function|constructor}0 is " - "incompatible with C++ standards before C++2a">, - InGroup, DefaultIgnore; + "incompatible with C++ standards before C++20">, + InGroup, DefaultIgnore; def ext_constexpr_union_ctor_no_init : ExtWarn< "constexpr union constructor that does not initialize any member " - "is a C++20 extension">, InGroup; + "is a C++20 extension">, InGroup; def warn_cxx17_compat_constexpr_union_ctor_no_init : Warning< "constexpr union constructor that does not initialize any member " "is incompatible with C++ standards before C++20">, - InGroup, DefaultIgnore; + InGroup, DefaultIgnore; def ext_constexpr_ctor_missing_init : ExtWarn< "constexpr constructor that does not initialize all members " - "is a C++20 extension">, InGroup; + "is a C++20 extension">, InGroup; def warn_cxx17_compat_constexpr_ctor_missing_init : Warning< "constexpr constructor that does not initialize all members " "is incompatible with C++ standards before C++20">, - InGroup, DefaultIgnore; + InGroup, DefaultIgnore; def note_constexpr_ctor_missing_init : Note< "member not initialized by constructor">; def note_non_literal_no_constexpr_ctors : Note< @@ -2590,25 +2596,65 @@ def note_constraints_not_satisfied : Note< def note_substituted_constraint_expr_is_ill_formed : Note< "because substituted constraint expression is ill-formed%0">; def note_atomic_constraint_evaluated_to_false : Note< - "%select{and |because }0'%1' evaluated to false">; + "%select{and|because}0 '%1' evaluated to false">; def note_concept_specialization_constraint_evaluated_to_false : Note< - "%select{and |because }0'%1' evaluated to false">; + "%select{and|because}0 '%1' evaluated to false">; def note_single_arg_concept_specialization_constraint_evaluated_to_false : Note< - "%select{and |because }0%1 does not satisfy %2">; + "%select{and|because}0 %1 does not satisfy %2">; def note_atomic_constraint_evaluated_to_false_elaborated : Note< - "%select{and |because }0'%1' (%2 %3 %4) evaluated to false">; + "%select{and|because}0 '%1' (%2 %3 %4) evaluated to false">; def err_constrained_virtual_method : Error< "virtual function cannot have a requires clause">; def err_trailing_requires_clause_on_deduction_guide : Error< "deduction guide cannot have a requires clause">; def err_reference_to_function_with_unsatisfied_constraints : Error< "invalid reference to function %0: constraints not satisfied">; +def note_requires_expr_ill_formed_expr : Note< + "expression is invalid: %0">; +def note_requires_expr_no_implicit_conversion : Note< + "no implicit conversion exists between expression type %0 and expected type " + "%1">; +def err_requires_expr_local_parameter_default_argument : Error< + "default arguments not allowed for parameters of a requires expression">; +def err_requires_expr_parameter_referenced_in_evaluated_context : Error< + "constraint variable %0 cannot be used in an evaluated context">; +def note_expr_requirement_expr_substitution_error : Note< + "%select{and|because}0 '%1' would be invalid: %2">; +def note_expr_requirement_expr_unknown_substitution_error : Note< + "%select{and|because}0 '%1' would be invalid">; +def note_expr_requirement_noexcept_not_met : Note< + "%select{and|because}0 '%1' may throw an exception">; +def note_expr_requirement_type_requirement_substitution_error : Note< + "%select{and|because}0 '%1' would be invalid: %2">; +def note_expr_requirement_type_requirement_unknown_substitution_error : Note< + "%select{and|because}0 '%1' would be invalid">; +def note_expr_requirement_constraints_not_satisfied : Note< + "%select{and|because}0 type constraint '%1' was not satisfied:">; +def note_expr_requirement_constraints_not_satisfied_simple : Note< + "%select{and|because}0 %1 does not satisfy %2:">; +def note_type_requirement_substitution_error : Note< + "%select{and|because}0 '%1' would be invalid: %2">; +def note_type_requirement_unknown_substitution_error : Note< + "%select{and|because}0 '%1' would be invalid">; +def err_type_requirement_non_type_template : Error< + "'%0' refers to a %select{class template|function template|" + "variable template|alias template|template template parameter|template}1, " + "not a type template">; +def err_type_requirement_no_such_type : Error< + "'%0' does not name a type">; +def note_nested_requirement_substitution_error : Note< + "%select{and|because}0 '%1' would be invalid: %2">; +def note_nested_requirement_unknown_substitution_error : Note< + "%select{and|because}0 '%1' would be invalid">; def note_ambiguous_atomic_constraints : Note< "similar constraint expressions not considered equivalent; constraint " "expressions cannot be considered equivalent unless they originate from the " "same concept">; def note_ambiguous_atomic_constraints_similar_expression : Note< "similar constraint expression here">; +def err_unsupported_placeholder_constraint : Error< + "constrained placeholder types other than simple 'auto' on non-type template " + "parameters not supported yet">; def err_template_different_requires_clause : Error< "requires clause differs in template redeclaration">; @@ -2623,6 +2669,8 @@ def err_type_constraint_non_type_concept : Error< def err_type_constraint_missing_arguments : Error< "%0 requires more than 1 template argument; provide the remaining arguments " "explicitly to use it here">; +def err_placeholder_constraints_not_satisfied : Error< + "deduced type %0 does not satisfy %1">; // C++11 char16_t/char32_t def warn_cxx98_compat_unicode_type : Warning< @@ -2630,7 +2678,7 @@ def warn_cxx98_compat_unicode_type : Warning< InGroup, DefaultIgnore; def warn_cxx17_compat_unicode_type : Warning< "'char8_t' type specifier is incompatible with C++ standards before C++20">, - InGroup, DefaultIgnore; + InGroup, DefaultIgnore; // __make_integer_seq def err_integer_sequence_negative_length : Error< @@ -4162,7 +4210,7 @@ def err_ovl_no_viable_literal_operator : Error< def err_template_param_shadow : Error< "declaration of %0 shadows template parameter">; def ext_template_param_shadow : ExtWarn< - err_template_param_shadow.Text>, InGroup; + err_template_param_shadow.Text>, InGroup; def note_template_param_here : Note<"template parameter is declared here">; def warn_template_export_unsupported : Warning< "exported templates are unsupported">; @@ -4241,11 +4289,11 @@ def err_template_tag_noparams : Error< def warn_cxx17_compat_adl_only_template_id : Warning< "use of function template name with no prior function template " "declaration in function call with explicit template arguments " - "is incompatible with C++ standards before C++2a">, - InGroup, DefaultIgnore; + "is incompatible with C++ standards before C++20">, + InGroup, DefaultIgnore; def ext_adl_only_template_id : ExtWarn< "use of function template name with no prior declaration in function call " - "with explicit template arguments is a C++2a extension">, InGroup; + "with explicit template arguments is a C++20 extension">, InGroup; // C++ Template Argument Lists def err_template_missing_args : Error< @@ -4387,12 +4435,12 @@ def err_pointer_to_member_oper_value_classify: Error< "pointer-to-member function type %0 can only be called on an " "%select{rvalue|lvalue}1">; def ext_pointer_to_const_ref_member_on_rvalue : Extension< - "invoking a pointer to a 'const &' member function on an rvalue is a C++2a extension">, - InGroup, SFINAEFailure; + "invoking a pointer to a 'const &' member function on an rvalue is a C++20 extension">, + InGroup, SFINAEFailure; def warn_cxx17_compat_pointer_to_const_ref_member_on_rvalue : Warning< "invoking a pointer to a 'const &' member function on an rvalue is " - "incompatible with C++ standards before C++2a">, - InGroup, DefaultIgnore; + "incompatible with C++ standards before C++20">, + InGroup, DefaultIgnore; def ext_ms_deref_template_argument: ExtWarn< "non-type template argument containing a dereference operation is a " "Microsoft extension">, InGroup; @@ -4588,6 +4636,8 @@ def note_template_type_alias_instantiation_here : Note< "in instantiation of template type alias %0 requested here">; def note_template_exception_spec_instantiation_here : Note< "in instantiation of exception specification for %0 requested here">; +def note_template_requirement_instantiation_here : Note< + "in instantiation of requirement here">; def warn_var_template_missing : Warning<"instantiation of variable %q0 " "required here, but no definition is available">, InGroup; @@ -4623,6 +4673,8 @@ def note_template_default_arg_checking : Note< "while checking a default template argument used here">; def note_concept_specialization_here : Note< "while checking the satisfaction of concept '%0' requested here">; +def note_nested_requirement_here : Note< + "while checking the satisfaction of nested requirement requested here">; def note_checking_constraints_for_template_id_here : Note< "while checking constraint satisfaction for template '%0' required here">; def note_checking_constraints_for_var_spec_id_here : Note< @@ -4631,6 +4683,8 @@ def note_checking_constraints_for_var_spec_id_here : Note< def note_checking_constraints_for_class_spec_id_here : Note< "while checking constraint satisfaction for class template partial " "specialization '%0' required here">; +def note_checking_constraints_for_function_here : Note< + "while checking constraint satisfaction for function '%0' required here">; def note_constraint_substitution_here : Note< "while substituting template arguments into constraint expression here">; def note_constraint_normalization_here : Note< @@ -4756,8 +4810,12 @@ def err_typename_nested_not_found_requirement : Error< "declaration">; def err_typename_nested_not_type : Error< "typename specifier refers to non-type member %0 in %1">; -def note_typename_refers_here : Note< +def err_typename_not_type : Error< + "typename specifier refers to non-type %0">; +def note_typename_member_refers_here : Note< "referenced member %0 is declared here">; +def note_typename_refers_here : Note< + "referenced %0 is declared here">; def err_typename_missing : Error< "missing 'typename' prior to dependent type name '%0%1'">; def err_typename_missing_template : Error< @@ -6131,7 +6189,7 @@ def err_array_init_utf8_string_into_char : Error< "UTF-8 string literal%select{ is not permitted by '-fchar8_t'|}0">; def warn_cxx2a_compat_utf8_string : Warning< "type of UTF-8 string literal will change from array of const char to " - "array of const char8_t in C++2a">, InGroup, DefaultIgnore; + "array of const char8_t in C++20">, InGroup, DefaultIgnore; def note_cxx2a_compat_utf8_string_remove_u8 : Note< "remove 'u8' prefix to avoid a change of behavior; " "Clang encodes unprefixed narrow string literals as UTF-8">; @@ -6690,6 +6748,10 @@ def err_bad_cxx_cast_scalar_to_vector_different_size : Error< def err_bad_cxx_cast_vector_to_vector_different_size : Error< "%select{||reinterpret_cast||C-style cast|}0 from vector %1 " "to vector %2 of different size">; +def warn_bad_cxx_cast_nested_pointer_addr_space : Warning< + "%select{reinterpret_cast|C-style cast}0 from %1 to %2 " + "changes address space of nested pointers">, + InGroup; def err_bad_lvalue_to_rvalue_cast : Error< "cannot cast from lvalue of type %1 to rvalue reference type %2; types are " "not compatible">; @@ -7054,9 +7116,9 @@ let CategoryName = "Lambda Issue" in { "cannot deduce type for lambda capture %0 from initializer list">; def warn_cxx17_compat_init_capture_pack : Warning< "initialized lambda capture packs are incompatible with C++ standards " - "before C++2a">, InGroup, DefaultIgnore; + "before C++20">, InGroup, DefaultIgnore; def ext_init_capture_pack : ExtWarn< - "initialized lambda pack captures are a C++2a extension">, InGroup; + "initialized lambda pack captures are a C++20 extension">, InGroup; // C++14 generic lambdas. def warn_cxx11_compat_generic_lambda : Warning< @@ -7074,23 +7136,23 @@ let CategoryName = "Lambda Issue" in { def err_parameter_shadow_capture : Error< "a lambda parameter cannot shadow an explicitly captured entity">; - // C++2a [=, this] captures. + // C++20 [=, this] captures. def warn_cxx17_compat_equals_this_lambda_capture : Warning< "explicit capture of 'this' with a capture default of '=' is incompatible " - "with C++ standards before C++2a">, InGroup, DefaultIgnore; + "with C++ standards before C++20">, InGroup, DefaultIgnore; def ext_equals_this_lambda_capture_cxx2a : ExtWarn< "explicit capture of 'this' with a capture default of '=' " - "is a C++2a extension">, InGroup; + "is a C++20 extension">, InGroup; def warn_deprecated_this_capture : Warning< "implicit capture of 'this' with a capture default of '=' is deprecated">, InGroup, DefaultIgnore; def note_deprecated_this_capture : Note< "add an explicit capture of 'this' to capture '*this' by reference">; - // C++2a default constructible / assignable lambdas. + // C++20 default constructible / assignable lambdas. def warn_cxx17_compat_lambda_def_ctor_assign : Warning< "%select{default construction|assignment}0 of lambda is incompatible with " - "C++ standards before C++2a">, InGroup, DefaultIgnore; + "C++ standards before C++20">, InGroup, DefaultIgnore; } def err_return_in_captured_stmt : Error< @@ -7791,7 +7853,7 @@ def ext_cxx14_attr : Extension< def ext_cxx17_attr : Extension< "use of the %0 attribute is a C++17 extension">, InGroup; def ext_cxx2a_attr : Extension< - "use of the %0 attribute is a C++2a extension">, InGroup; + "use of the %0 attribute is a C++20 extension">, InGroup; def warn_unused_comparison : Warning< "%select{equality|inequality|relational|three-way}0 comparison result unused">, @@ -7805,7 +7867,7 @@ def err_incomplete_type_used_in_type_trait_expr : Error< // C++20 constinit and require_constant_initialization attribute def warn_cxx20_compat_constinit : Warning< "'constinit' specifier is incompatible with C++ standards before C++20">, - InGroup, DefaultIgnore; + InGroup, DefaultIgnore; def err_constinit_local_variable : Error< "local variable cannot be declared 'constinit'">; def err_require_constant_init_failed : Error< @@ -8260,7 +8322,7 @@ def note_deleted_type_mismatch : Note< def warn_cxx17_compat_defaulted_method_type_mismatch : Warning< "explicitly defaulting this %sub{select_special_member_kind}0 with a type " "different from the implicit type is incompatible with C++ standards before " - "C++2a">, InGroup, DefaultIgnore; + "C++20">, InGroup, DefaultIgnore; def warn_vbase_moved_multiple_times : Warning< "defaulted move assignment operator of %0 will move assign virtual base " "class %1 multiple times">, InGroup>; @@ -8274,10 +8336,10 @@ def select_defaulted_comparison_kind : TextSubstitution< "%select{|equality|three-way|equality|relational}0 comparison " "operator">; def ext_defaulted_comparison : ExtWarn< - "defaulted comparison operators are a C++20 extension">, InGroup; + "defaulted comparison operators are a C++20 extension">, InGroup; def warn_cxx17_compat_defaulted_comparison : Warning< "defaulted comparison operators are incompatible with C++ standards " - "before C++20">, InGroup, DefaultIgnore; + "before C++20">, InGroup, DefaultIgnore; def err_defaulted_comparison_template : Error< "comparison operator template cannot be defaulted">; def err_defaulted_comparison_out_of_class : Error< @@ -8334,6 +8396,12 @@ def note_defaulted_comparison_cannot_deduce : Note< "return type of defaulted 'operator<=>' cannot be deduced because " "return type %2 of three-way comparison for %select{|member|base class}0 %1 " "is not a standard comparison category type">; +def err_defaulted_comparison_cannot_deduce_undeduced_auto : Error< + "return type of defaulted 'operator<=>' cannot be deduced because " + "three-way comparison for %select{|member|base class}0 %1 " + "has a deduced return type and is not yet defined">; +def note_defaulted_comparison_cannot_deduce_undeduced_auto : Note< + "%select{|member|base class}0 %1 declared here">; def note_defaulted_comparison_cannot_deduce_callee : Note< "selected 'operator<=>' for %select{|member|base class}0 %1 declared here">; def err_incorrect_defaulted_comparison_constexpr : Error< diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index 068f206f44847..3319a31239768 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -237,7 +237,7 @@ LANGOPT(SizedDeallocation , 1, 0, "sized deallocation") LANGOPT(AlignedAllocation , 1, 0, "aligned allocation") LANGOPT(AlignedAllocationUnavailable, 1, 0, "aligned allocation functions are unavailable") LANGOPT(NewAlignOverride , 32, 0, "maximum alignment guaranteed by '::operator new(size_t)'") -LANGOPT(ConceptsTS , 1, 0, "enable C++ Extensions for Concepts") +LANGOPT(ConceptSatisfactionCaching , 1, 1, "enable satisfaction caching for C++2a Concepts") BENIGN_LANGOPT(ModulesCodegen , 1, 0, "Modules code generation") BENIGN_LANGOPT(ModulesDebugInfo , 1, 0, "Modules debug info") BENIGN_LANGOPT(ElideConstructors , 1, 1, "C++ copy constructor elision") diff --git a/clang/include/clang/Basic/LangStandards.def b/clang/include/clang/Basic/LangStandards.def index 427691fb71e94..7f1a24db7e9be 100644 --- a/clang/include/clang/Basic/LangStandards.def +++ b/clang/include/clang/Basic/LangStandards.def @@ -140,15 +140,17 @@ LANGSTANDARD(gnucxx17, "gnu++17", Digraphs | HexFloat | GNUMode) LANGSTANDARD_ALIAS_DEPR(gnucxx17, "gnu++1z") -LANGSTANDARD(cxx2a, "c++2a", - CXX, "Working draft for ISO C++ 2020", +LANGSTANDARD(cxx20, "c++20", + CXX, "ISO C++ 2020 DIS", LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | CPlusPlus17 | CPlusPlus2a | Digraphs | HexFloat) +LANGSTANDARD_ALIAS_DEPR(cxx20, "c++2a") -LANGSTANDARD(gnucxx2a, "gnu++2a", - CXX, "Working draft for ISO C++ 2020 with GNU extensions", +LANGSTANDARD(gnucxx20, "gnu++20", + CXX, "ISO C++ 2020 DIS with GNU extensions", LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | CPlusPlus17 | CPlusPlus2a | Digraphs | HexFloat | GNUMode) +LANGSTANDARD_ALIAS_DEPR(gnucxx20, "gnu++2a") // OpenCL LANGSTANDARD(opencl10, "cl1.0", diff --git a/clang/include/clang/Basic/StmtNodes.td b/clang/include/clang/Basic/StmtNodes.td index 294993298a18a..2333202968198 100644 --- a/clang/include/clang/Basic/StmtNodes.td +++ b/clang/include/clang/Basic/StmtNodes.td @@ -162,8 +162,9 @@ def CoawaitExpr : StmtNode; def DependentCoawaitExpr : StmtNode; def CoyieldExpr : StmtNode; -// C++2a Concepts expressions +// C++20 Concepts expressions def ConceptSpecializationExpr : StmtNode; +def RequiresExpr : StmtNode; // Obj-C Expressions. def ObjCStringLiteral : StmtNode; diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def index d58b0d987d71d..fec029ae995ed 100644 --- a/clang/include/clang/Basic/TokenKinds.def +++ b/clang/include/clang/Basic/TokenKinds.def @@ -373,7 +373,7 @@ CXX11_KEYWORD(nullptr , 0) CXX11_KEYWORD(static_assert , KEYMSCOMPAT) CXX11_KEYWORD(thread_local , 0) -// C++2a / concepts TS keywords +// C++2a keywords CONCEPTS_KEYWORD(concept) CONCEPTS_KEYWORD(requires) diff --git a/clang/include/clang/Driver/CC1Options.td b/clang/include/clang/Driver/CC1Options.td index 1d550eb15ea8f..d1f5ec5a3d4c2 100644 --- a/clang/include/clang/Driver/CC1Options.td +++ b/clang/include/clang/Driver/CC1Options.td @@ -372,6 +372,9 @@ def fsanitize_coverage_no_prune def fsanitize_coverage_stack_depth : Flag<["-"], "fsanitize-coverage-stack-depth">, HelpText<"Enable max stack depth tracing">; +def fpatchable_function_entry_offset_EQ + : Joined<["-"], "fpatchable-function-entry-offset=">, MetaVarName<"">, + HelpText<"Generate M NOPs before function entry">; def fprofile_instrument_EQ : Joined<["-"], "fprofile-instrument=">, HelpText<"Enable PGO instrumentation. The accepted value is clang, llvm, " "or none">, Values<"none,clang,llvm">; @@ -553,7 +556,10 @@ def ftest_module_file_extension_EQ : HelpText<"introduce a module file extension for testing purposes. " "The argument is parsed as blockname:major:minor:hashed:user info">; def fconcepts_ts : Flag<["-"], "fconcepts-ts">, - HelpText<"Enable C++ Extensions for Concepts.">; + HelpText<"Enable C++ Extensions for Concepts. (deprecated - use -std=c++2a)">; +def fno_concept_satisfaction_caching : Flag<["-"], + "fno-concept-satisfaction-caching">, + HelpText<"Disable satisfaction caching for C++2a Concepts.">; let Group = Action_Group in { @@ -853,6 +859,8 @@ def detailed_preprocessing_record : Flag<["-"], "detailed-preprocessing-record"> HelpText<"include a detailed record of preprocessing actions">; def setup_static_analyzer : Flag<["-"], "setup-static-analyzer">, HelpText<"Set up preprocessor for static analyzer (done automatically when static analyzer is run).">; +def disable_pragma_debug_crash : Flag<["-"], "disable-pragma-debug-crash">, + HelpText<"Disable any #pragma clang __debug that can lead to crashing behavior. This is meant for testing.">; //===----------------------------------------------------------------------===// // OpenCL Options diff --git a/clang/include/clang/Driver/Driver.h b/clang/include/clang/Driver/Driver.h index fd25663bd3587..6c3feaba05682 100644 --- a/clang/include/clang/Driver/Driver.h +++ b/clang/include/clang/Driver/Driver.h @@ -208,7 +208,7 @@ class Driver { /// When the clangDriver lib is used through clang.exe, this provides a /// shortcut for executing the -cc1 command-line directly, in the same /// process. - typedef int (*CC1ToolFunc)(ArrayRef argv); + typedef int (*CC1ToolFunc)(SmallVectorImpl &ArgV); CC1ToolFunc CC1Main = nullptr; private: diff --git a/clang/include/clang/Driver/Job.h b/clang/include/clang/Driver/Job.h index 0765b3c67d4e7..9a3cad23363b1 100644 --- a/clang/include/clang/Driver/Job.h +++ b/clang/include/clang/Driver/Job.h @@ -55,9 +55,6 @@ class Command { /// The list of program arguments which are inputs. llvm::opt::ArgStringList InputFilenames; - /// Whether to print the input filenames when executing. - bool PrintInputFilenames = false; - /// Response file name, if this command is set to use one, or nullptr /// otherwise const char *ResponseFile = nullptr; @@ -86,6 +83,12 @@ class Command { void writeResponseFile(raw_ostream &OS) const; public: + /// Whether to print the input filenames when executing. + bool PrintInputFilenames = false; + + /// Whether the command will be executed in this process or not. + bool InProcess = false; + Command(const Action &Source, const Tool &Creator, const char *Executable, const llvm::opt::ArgStringList &Arguments, ArrayRef Inputs); @@ -128,9 +131,6 @@ class Command { /// Print a command argument, and optionally quote it. static void printArg(llvm::raw_ostream &OS, StringRef Arg, bool Quote); - /// Set whether to print the input filenames when executing. - void setPrintInputFilenames(bool P) { PrintInputFilenames = P; } - protected: /// Optionally print the filenames to be compiled void PrintFileNames() const; @@ -139,7 +139,9 @@ class Command { /// Use the CC1 tool callback when available, to avoid creating a new process class CC1Command : public Command { public: - using Command::Command; + CC1Command(const Action &Source, const Tool &Creator, const char *Executable, + const llvm::opt::ArgStringList &Arguments, + ArrayRef Inputs); void Print(llvm::raw_ostream &OS, const char *Terminator, bool Quote, CrashReportInfo *CrashInfo = nullptr) const override; diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 1218172fd5b69..0a60873443fc0 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -1707,7 +1707,7 @@ def fno_max_type_align : Flag<["-"], "fno-max-type-align">, Group; def fpascal_strings : Flag<["-"], "fpascal-strings">, Group, Flags<[CC1Option]>, HelpText<"Recognize and construct Pascal-style string literals">; def fpatchable_function_entry_EQ : Joined<["-"], "fpatchable-function-entry=">, Group, Flags<[CC1Option]>, - HelpText<"Generate N NOPs at function entry">; + MetaVarName<"">, HelpText<"Generate M NOPs before function entry and N-M NOPs after function entry">; def fpcc_struct_return : Flag<["-"], "fpcc-struct-return">, Group, Flags<[CC1Option]>, HelpText<"Override the default ABI to return all structs on the stack">; def fpch_preprocess : Flag<["-"], "fpch-preprocess">, Group; @@ -2855,6 +2855,14 @@ def fintegrated_as : Flag<["-"], "fintegrated-as">, Flags<[DriverOption]>, def fno_integrated_as : Flag<["-"], "fno-integrated-as">, Flags<[CC1Option, DriverOption]>, Group, HelpText<"Disable the integrated assembler">; + +def fintegrated_cc1 : Flag<["-"], "fintegrated-cc1">, + Flags<[CoreOption, DriverOption]>, Group, + HelpText<"Run cc1 in-process">; +def fno_integrated_cc1 : Flag<["-"], "fno-integrated-cc1">, + Flags<[CoreOption, DriverOption]>, Group, + HelpText<"Spawn a separate process for each cc1">; + def : Flag<["-"], "integrated-as">, Alias, Flags<[DriverOption]>; def : Flag<["-"], "no-integrated-as">, Alias, Flags<[CC1Option, DriverOption]>; diff --git a/clang/include/clang/Lex/PreprocessorOptions.h b/clang/include/clang/Lex/PreprocessorOptions.h index abffbd03c3b48..8b2146059f850 100644 --- a/clang/include/clang/Lex/PreprocessorOptions.h +++ b/clang/include/clang/Lex/PreprocessorOptions.h @@ -189,6 +189,9 @@ class PreprocessorOptions { /// Set up preprocessor for RunAnalysis action. bool SetUpStaticAnalyzer = false; + /// Prevents intended crashes when using #pragma clang __debug. For testing. + bool DisablePragmaDebugCrash = false; + public: PreprocessorOptions() : PrecompiledPreambleBytes(0, false) {} diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index e320c96478188..41f46861d0895 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -806,6 +806,16 @@ class Parser : public CodeCompletionHandler { bool IsNewScope); bool TryAnnotateCXXScopeToken(bool EnteringContext = false); + bool MightBeCXXScopeToken() { + return Tok.is(tok::identifier) || Tok.is(tok::coloncolon) || + (Tok.is(tok::annot_template_id) && + NextToken().is(tok::coloncolon)) || + Tok.is(tok::kw_decltype) || Tok.is(tok::kw___super); + } + bool TryAnnotateOptionalCXXScopeToken(bool EnteringContext = false) { + return MightBeCXXScopeToken() && TryAnnotateCXXScopeToken(EnteringContext); + } + private: enum AnnotatedNameKind { /// Annotation has failed and emitted an error. @@ -1923,6 +1933,7 @@ class Parser : public CodeCompletionHandler { //===--------------------------------------------------------------------===// // C++ Concepts + ExprResult ParseRequiresExpression(); void ParseTrailingRequiresClause(Declarator &D); //===--------------------------------------------------------------------===// @@ -2395,6 +2406,11 @@ class Parser : public CodeCompletionHandler { /// rather than a less-than expression. TPResult isTemplateArgumentList(unsigned TokensToSkip); + /// Determine whether an '(' after an 'explicit' keyword is part of a C++20 + /// 'explicit(bool)' declaration, in earlier language modes where that is an + /// extension. + TPResult isExplicitBool(); + /// Determine whether an identifier has been tentatively declared as a /// non-type. Such tentative declarations should not be found to name a type /// during a tentative parse, but also should not be annotated as a non-type. @@ -2756,7 +2772,7 @@ class Parser : public CodeCompletionHandler { Declarator &D, SmallVectorImpl &ParamInfo); void ParseParameterDeclarationClause( - Declarator &D, + DeclaratorContext DeclaratorContext, ParsedAttributes &attrs, SmallVectorImpl &ParamInfo, SourceLocation &EllipsisLoc); @@ -3064,13 +3080,13 @@ class Parser : public CodeCompletionHandler { SourceLocation &RAngleLoc); bool ParseTemplateParameterList(unsigned Depth, SmallVectorImpl &TemplateParams); - bool isStartOfTemplateTypeParameter(bool &ScopeError); + TPResult isStartOfTemplateTypeParameter(); NamedDecl *ParseTemplateParameter(unsigned Depth, unsigned Position); NamedDecl *ParseTypeParameter(unsigned Depth, unsigned Position); NamedDecl *ParseTemplateTemplateParameter(unsigned Depth, unsigned Position); NamedDecl *ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position); bool isTypeConstraintAnnotation(); - bool TryAnnotateTypeConstraint(CXXScopeSpec &SS); + bool TryAnnotateTypeConstraint(); NamedDecl * ParseConstrainedTemplateTypeParameter(unsigned Depth, unsigned Position); void DiagnoseMisplacedEllipsis(SourceLocation EllipsisLoc, @@ -3096,7 +3112,8 @@ class Parser : public CodeCompletionHandler { UnqualifiedId &TemplateName, bool AllowTypeAnnotation = true, bool TypeConstraint = false); - void AnnotateTemplateIdTokenAsType(bool IsClassName = false); + void AnnotateTemplateIdTokenAsType(CXXScopeSpec &SS, + bool IsClassName = false); bool ParseTemplateArgumentList(TemplateArgList &TemplateArgs); ParsedTemplateArgument ParseTemplateTemplateArgument(); ParsedTemplateArgument ParseTemplateArgument(); diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h index aceec9cbe1c9e..1559b51ea77fc 100644 --- a/clang/include/clang/Sema/DeclSpec.h +++ b/clang/include/clang/Sema/DeclSpec.h @@ -349,6 +349,7 @@ class DeclSpec { unsigned TypeSpecOwned : 1; unsigned TypeSpecPipe : 1; unsigned TypeSpecSat : 1; + unsigned ConstrainedAuto : 1; // type-qualifiers unsigned TypeQualifiers : 5; // Bitwise OR of TQ. @@ -369,6 +370,7 @@ class DeclSpec { UnionParsedType TypeRep; Decl *DeclRep; Expr *ExprRep; + TemplateIdAnnotation *TemplateIdRep; }; /// ExplicitSpecifier - Store information about explicit spicifer. @@ -413,6 +415,9 @@ class DeclSpec { static bool isExprRep(TST T) { return (T == TST_typeofExpr || T == TST_decltype); } + static bool isTemplateIdRep(TST T) { + return (T == TST_auto || T == TST_decltype_auto); + } DeclSpec(const DeclSpec &) = delete; void operator=(const DeclSpec &) = delete; @@ -430,7 +435,8 @@ class DeclSpec { TypeSpecComplex(TSC_unspecified), TypeSpecSign(TSS_unspecified), TypeSpecType(TST_unspecified), TypeAltiVecVector(false), TypeAltiVecPixel(false), TypeAltiVecBool(false), TypeSpecOwned(false), - TypeSpecPipe(false), TypeSpecSat(false), TypeQualifiers(TQ_unspecified), + TypeSpecPipe(false), TypeSpecSat(false), ConstrainedAuto(false), + TypeQualifiers(TQ_unspecified), FS_inline_specified(false), FS_forceinline_specified(false), FS_virtual_specified(false), FS_noreturn_specified(false), Friend_specified(false), ConstexprSpecifier(CSK_unspecified), @@ -478,6 +484,7 @@ class DeclSpec { bool isTypeRep() const { return isTypeRep((TST) TypeSpecType); } bool isTypeSpecPipe() const { return TypeSpecPipe; } bool isTypeSpecSat() const { return TypeSpecSat; } + bool isConstrainedAuto() const { return ConstrainedAuto; } ParsedType getRepAsType() const { assert(isTypeRep((TST) TypeSpecType) && "DeclSpec does not store a type"); @@ -491,6 +498,11 @@ class DeclSpec { assert(isExprRep((TST) TypeSpecType) && "DeclSpec does not store an expr"); return ExprRep; } + TemplateIdAnnotation *getRepAsTemplateId() const { + assert(isTemplateIdRep((TST) TypeSpecType) && + "DeclSpec does not store a template id"); + return TemplateIdRep; + } CXXScopeSpec &getTypeSpecScope() { return TypeScope; } const CXXScopeSpec &getTypeSpecScope() const { return TypeScope; } @@ -666,6 +678,9 @@ class DeclSpec { SourceLocation TagNameLoc, const char *&PrevSpec, unsigned &DiagID, Decl *Rep, bool Owned, const PrintingPolicy &Policy); + bool SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID, TemplateIdAnnotation *Rep, + const PrintingPolicy &Policy); bool SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID, Expr *Rep, @@ -1757,7 +1772,8 @@ enum class DeclaratorContext { TemplateArgContext, // Any template argument (in template argument list). TemplateTypeArgContext, // Template type argument (in default argument). AliasDeclContext, // C++11 alias-declaration. - AliasTemplateContext // C++11 alias-declaration template. + AliasTemplateContext, // C++11 alias-declaration template. + RequiresExprContext // C++2a requires-expression. }; @@ -1830,6 +1846,14 @@ class Declarator { /// requires-clause, or null if no such clause was specified. Expr *TrailingRequiresClause; + /// If this declarator declares a template, its template parameter lists. + ArrayRef TemplateParameterLists; + + /// If the declarator declares an abbreviated function template, the innermost + /// template parameter list containing the invented and explicit template + /// parameters (if any). + TemplateParameterList *InventedTemplateParameterList; + #ifndef _MSC_VER union { #endif @@ -1860,7 +1884,8 @@ class Declarator { Redeclaration(false), Extension(false), ObjCIvar(false), ObjCWeakProperty(false), InlineStorageUsed(false), Attrs(ds.getAttributePool().getFactory()), AsmLabel(nullptr), - TrailingRequiresClause(nullptr) {} + TrailingRequiresClause(nullptr), + InventedTemplateParameterList(nullptr) {} ~Declarator() { clear(); @@ -1981,6 +2006,7 @@ class Declarator { case DeclaratorContext::TemplateTypeArgContext: case DeclaratorContext::TrailingReturnContext: case DeclaratorContext::TrailingReturnVarContext: + case DeclaratorContext::RequiresExprContext: return true; } llvm_unreachable("unknown context kind!"); @@ -2003,6 +2029,7 @@ class Declarator { case DeclaratorContext::TemplateParamContext: case DeclaratorContext::CXXCatchContext: case DeclaratorContext::ObjCCatchContext: + case DeclaratorContext::RequiresExprContext: return true; case DeclaratorContext::TypeNameContext: @@ -2039,6 +2066,7 @@ class Declarator { case DeclaratorContext::MemberContext: case DeclaratorContext::PrototypeContext: case DeclaratorContext::TemplateParamContext: + case DeclaratorContext::RequiresExprContext: // Maybe one day... return false; @@ -2116,6 +2144,7 @@ class Declarator { case DeclaratorContext::TemplateArgContext: case DeclaratorContext::TemplateTypeArgContext: case DeclaratorContext::TrailingReturnContext: + case DeclaratorContext::RequiresExprContext: return false; } llvm_unreachable("unknown context kind!"); @@ -2337,6 +2366,7 @@ class Declarator { case DeclaratorContext::TemplateTypeArgContext: case DeclaratorContext::TrailingReturnContext: case DeclaratorContext::TrailingReturnVarContext: + case DeclaratorContext::RequiresExprContext: return false; } llvm_unreachable("unknown context kind!"); @@ -2370,6 +2400,7 @@ class Declarator { case DeclaratorContext::TrailingReturnContext: case DeclaratorContext::TrailingReturnVarContext: case DeclaratorContext::TemplateTypeArgContext: + case DeclaratorContext::RequiresExprContext: return false; case DeclaratorContext::BlockContext: @@ -2422,6 +2453,30 @@ class Declarator { return TrailingRequiresClause != nullptr; } + /// Sets the template parameter lists that preceded the declarator. + void setTemplateParameterLists(ArrayRef TPLs) { + TemplateParameterLists = TPLs; + } + + /// The template parameter lists that preceded the declarator. + ArrayRef getTemplateParameterLists() const { + return TemplateParameterLists; + } + + /// Sets the template parameter list generated from the explicit template + /// parameters along with any invented template parameters from + /// placeholder-typed parameters. + void setInventedTemplateParameterList(TemplateParameterList *Invented) { + InventedTemplateParameterList = Invented; + } + + /// The template parameter list generated from the explicit template + /// parameters along with any invented template parameters from + /// placeholder-typed parameters, if there were any such parameters. + TemplateParameterList * getInventedTemplateParameterList() const { + return InventedTemplateParameterList; + } + /// takeAttributes - Takes attributes from the given parsed-attributes /// set and add them to this declarator. /// @@ -2622,6 +2677,26 @@ struct LambdaIntroducer { } }; +struct InventedTemplateParameterInfo { + /// The number of parameters in the template parameter list that were + /// explicitly specified by the user, as opposed to being invented by use + /// of an auto parameter. + unsigned NumExplicitTemplateParams = 0; + + /// If this is a generic lambda or abbreviated function template, use this + /// as the depth of each 'auto' parameter, during initial AST construction. + unsigned AutoTemplateParameterDepth = 0; + + /// Store the list of the template parameters for a generic lambda or an + /// abbreviated function template. + /// If this is a generic lambda or abbreviated function template, this holds + /// the explicit template parameters followed by the auto parameters + /// converted into TemplateTypeParmDecls. + /// It can be used to construct the generic lambda or abbreviated template's + /// template parameter list during initial AST construction. + SmallVector TemplateParams; +}; + } // end namespace clang #endif // LLVM_CLANG_SEMA_DECLSPEC_H diff --git a/clang/include/clang/Sema/ParsedTemplate.h b/clang/include/clang/Sema/ParsedTemplate.h index 0874905b38a5b..82d00494b0d6b 100644 --- a/clang/include/clang/Sema/ParsedTemplate.h +++ b/clang/include/clang/Sema/ParsedTemplate.h @@ -139,9 +139,8 @@ namespace clang { /// Information about a template-id annotation /// token. /// - /// A template-id annotation token contains the template declaration, - /// template arguments, whether those template arguments were types, - /// expressions, or template names, and the source locations for important + /// A template-id annotation token contains the template name, + /// template arguments, and the source locations for important /// tokens. All of the information about template arguments is allocated /// directly after this structure. /// A template-id annotation token can also be generated by a type-constraint @@ -152,9 +151,6 @@ namespace clang { : private llvm::TrailingObjects { friend TrailingObjects; - /// The nested-name-specifier that precedes the template name. - CXXScopeSpec SS; - /// TemplateKWLoc - The location of the template keyword. /// For e.g. typename T::template Y SourceLocation TemplateKWLoc; @@ -195,16 +191,15 @@ namespace clang { /// Creates a new TemplateIdAnnotation with NumArgs arguments and /// appends it to List. static TemplateIdAnnotation * - Create(CXXScopeSpec SS, SourceLocation TemplateKWLoc, - SourceLocation TemplateNameLoc, IdentifierInfo *Name, - OverloadedOperatorKind OperatorKind, + Create(SourceLocation TemplateKWLoc, SourceLocation TemplateNameLoc, + IdentifierInfo *Name, OverloadedOperatorKind OperatorKind, ParsedTemplateTy OpaqueTemplateName, TemplateNameKind TemplateKind, SourceLocation LAngleLoc, SourceLocation RAngleLoc, ArrayRef TemplateArgs, SmallVectorImpl &CleanupList) { TemplateIdAnnotation *TemplateId = new (llvm::safe_malloc( totalSizeToAlloc(TemplateArgs.size()))) - TemplateIdAnnotation(SS, TemplateKWLoc, TemplateNameLoc, Name, + TemplateIdAnnotation(TemplateKWLoc, TemplateNameLoc, Name, OperatorKind, OpaqueTemplateName, TemplateKind, LAngleLoc, RAngleLoc, TemplateArgs); CleanupList.push_back(TemplateId); @@ -221,17 +216,16 @@ namespace clang { private: TemplateIdAnnotation(const TemplateIdAnnotation &) = delete; - TemplateIdAnnotation(CXXScopeSpec SS, SourceLocation TemplateKWLoc, + TemplateIdAnnotation(SourceLocation TemplateKWLoc, SourceLocation TemplateNameLoc, IdentifierInfo *Name, OverloadedOperatorKind OperatorKind, ParsedTemplateTy OpaqueTemplateName, TemplateNameKind TemplateKind, SourceLocation LAngleLoc, SourceLocation RAngleLoc, ArrayRef TemplateArgs) noexcept - : SS(SS), TemplateKWLoc(TemplateKWLoc), - TemplateNameLoc(TemplateNameLoc), Name(Name), Operator(OperatorKind), - Template(OpaqueTemplateName), Kind(TemplateKind), - LAngleLoc(LAngleLoc), RAngleLoc(RAngleLoc), + : TemplateKWLoc(TemplateKWLoc), TemplateNameLoc(TemplateNameLoc), + Name(Name), Operator(OperatorKind), Template(OpaqueTemplateName), + Kind(TemplateKind), LAngleLoc(LAngleLoc), RAngleLoc(RAngleLoc), NumArgs(TemplateArgs.size()) { std::uninitialized_copy(TemplateArgs.begin(), TemplateArgs.end(), diff --git a/clang/include/clang/Sema/Scope.h b/clang/include/clang/Sema/Scope.h index 7848df8f70d9c..6133425a42a62 100644 --- a/clang/include/clang/Sema/Scope.h +++ b/clang/include/clang/Sema/Scope.h @@ -385,6 +385,12 @@ class Scope { return getFlags() & Scope::FunctionPrototypeScope; } + /// isFunctionDeclarationScope - Return true if this scope is a + /// function prototype scope. + bool isFunctionDeclarationScope() const { + return getFlags() & Scope::FunctionDeclarationScope; + } + /// isAtCatchScope - Return true if this scope is \@catch. bool isAtCatchScope() const { return getFlags() & Scope::AtCatchScope; diff --git a/clang/include/clang/Sema/ScopeInfo.h b/clang/include/clang/Sema/ScopeInfo.h index 4f7534f9ef1af..3c4847a2932cd 100644 --- a/clang/include/clang/Sema/ScopeInfo.h +++ b/clang/include/clang/Sema/ScopeInfo.h @@ -22,6 +22,7 @@ #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/SourceLocation.h" #include "clang/Sema/CleanupInfo.h" +#include "clang/Sema/DeclSpec.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseMapInfo.h" #include "llvm/ADT/MapVector.h" @@ -789,7 +790,8 @@ class CapturedRegionScopeInfo final : public CapturingScopeInfo { } }; -class LambdaScopeInfo final : public CapturingScopeInfo { +class LambdaScopeInfo final : + public CapturingScopeInfo, public InventedTemplateParameterInfo { public: /// The class that describes the lambda. CXXRecordDecl *Lambda = nullptr; @@ -823,25 +825,9 @@ class LambdaScopeInfo final : public CapturingScopeInfo { /// Packs introduced by this lambda, if any. SmallVector LocalPacks; - /// If this is a generic lambda, use this as the depth of - /// each 'auto' parameter, during initial AST construction. - unsigned AutoTemplateParameterDepth = 0; - - /// The number of parameters in the template parameter list that were - /// explicitly specified by the user, as opposed to being invented by use - /// of an auto parameter. - unsigned NumExplicitTemplateParams = 0; - /// Source range covering the explicit template parameter list (if it exists). SourceRange ExplicitTemplateParamsRange; - /// Store the list of the template parameters for a generic lambda. - /// If this is a generic lambda, this holds the explicit template parameters - /// followed by the auto parameters converted into TemplateTypeParmDecls. - /// It can be used to construct the generic lambda's template parameter list - /// during initial AST construction. - SmallVector TemplateParams; - /// If this is a generic lambda, and the template parameter /// list has been created (from the TemplateParams) then store /// a reference to it (cache it to avoid reconstructing it). diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 47a055f696b13..842e496022749 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -21,6 +21,7 @@ #include "clang/AST/DeclTemplate.h" #include "clang/AST/DeclarationName.h" #include "clang/AST/Expr.h" +#include "clang/AST/ExprConcepts.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" #include "clang/AST/ExternalASTSource.h" @@ -619,6 +620,32 @@ class Sema final { /// function, block, and method scopes that are currently active. SmallVector FunctionScopes; + /// The index of the first FunctionScope that corresponds to the current + /// context. + unsigned FunctionScopesStart = 0; + + ArrayRef getFunctionScopes() const { + return llvm::makeArrayRef(FunctionScopes.begin() + FunctionScopesStart, + FunctionScopes.end()); + } + + /// Stack containing information needed when in C++2a an 'auto' is encountered + /// in a function declaration parameter type specifier in order to invent a + /// corresponding template parameter in the enclosing abbreviated function + /// template. This information is also present in LambdaScopeInfo, stored in + /// the FunctionScopes stack. + SmallVector InventedParameterInfos; + + /// The index of the first InventedParameterInfo that refers to the current + /// context. + unsigned InventedParameterInfosStart = 0; + + ArrayRef getInventedParameterInfos() const { + return llvm::makeArrayRef(InventedParameterInfos.begin() + + InventedParameterInfosStart, + InventedParameterInfos.end()); + } + typedef LazyVector ExtVectorDeclsType; @@ -792,17 +819,24 @@ class Sema final { DeclContext *SavedContext; ProcessingContextState SavedContextState; QualType SavedCXXThisTypeOverride; + unsigned SavedFunctionScopesStart; + unsigned SavedInventedParameterInfosStart; public: ContextRAII(Sema &S, DeclContext *ContextToPush, bool NewThisContext = true) : S(S), SavedContext(S.CurContext), SavedContextState(S.DelayedDiagnostics.pushUndelayed()), - SavedCXXThisTypeOverride(S.CXXThisTypeOverride) + SavedCXXThisTypeOverride(S.CXXThisTypeOverride), + SavedFunctionScopesStart(S.FunctionScopesStart), + SavedInventedParameterInfosStart(S.InventedParameterInfosStart) { assert(ContextToPush && "pushing null context"); S.CurContext = ContextToPush; if (NewThisContext) S.CXXThisTypeOverride = QualType(); + // Any saved FunctionScopes do not refer to this context. + S.FunctionScopesStart = S.FunctionScopes.size(); + S.InventedParameterInfosStart = S.InventedParameterInfos.size(); } void pop() { @@ -810,6 +844,8 @@ class Sema final { S.CurContext = SavedContext; S.DelayedDiagnostics.popUndelayed(SavedContextState); S.CXXThisTypeOverride = SavedCXXThisTypeOverride; + S.FunctionScopesStart = SavedFunctionScopesStart; + S.InventedParameterInfosStart = SavedInventedParameterInfosStart; SavedContext = nullptr; } @@ -1424,6 +1460,11 @@ class Sema final { /// Retrieve the module loader associated with the preprocessor. ModuleLoader &getModuleLoader() const; + /// Invent a new identifier for parameters of abbreviated templates. + IdentifierInfo * + InventAbbreviatedTemplateParameterTypeName(IdentifierInfo *ParamName, + unsigned Index); + void emitAndClearUnusedLocalTypedefWarnings(); enum TUFragmentKind { @@ -1518,6 +1559,15 @@ class Sema final { /// WeakTopLevelDeclDecls - access to \#pragma weak-generated Decls SmallVectorImpl &WeakTopLevelDecls() { return WeakTopLevelDecl; } + /// Called before parsing a function declarator belonging to a function + /// declaration. + void ActOnStartFunctionDeclarationDeclarator(Declarator &D, + unsigned TemplateParameterDepth); + + /// Called after parsing a function declarator belonging to a function + /// declaration. + void ActOnFinishFunctionDeclarationDeclarator(Declarator &D); + void ActOnComment(SourceRange Comment); //===--------------------------------------------------------------------===// @@ -1921,6 +1971,8 @@ class Sema final { NC_FunctionTemplate, /// The name was classified as an ADL-only function template name. NC_UndeclaredTemplate, + /// The name was classified as a concept name. + NC_Concept, }; class NameClassification { @@ -1985,6 +2037,12 @@ class Sema final { return Result; } + static NameClassification Concept(TemplateName Name) { + NameClassification Result(NC_Concept); + Result.Template = Name; + return Result; + } + static NameClassification UndeclaredTemplate(TemplateName Name) { NameClassification Result(NC_UndeclaredTemplate); Result.Template = Name; @@ -2010,7 +2068,8 @@ class Sema final { TemplateName getTemplateName() const { assert(Kind == NC_TypeTemplate || Kind == NC_FunctionTemplate || - Kind == NC_VarTemplate || Kind == NC_UndeclaredTemplate); + Kind == NC_VarTemplate || Kind == NC_Concept || + Kind == NC_UndeclaredTemplate); return Template; } @@ -2022,6 +2081,8 @@ class Sema final { return TNK_Function_template; case NC_VarTemplate: return TNK_Var_template; + case NC_Concept: + return TNK_Concept_template; case NC_UndeclaredTemplate: return TNK_Undeclared_template; default: @@ -4890,8 +4951,10 @@ class Sema final { LabelDecl *TheDecl); void ActOnStartStmtExpr(); - ExprResult ActOnStmtExpr(SourceLocation LPLoc, Stmt *SubStmt, - SourceLocation RPLoc); // "({..})" + ExprResult ActOnStmtExpr(Scope *S, SourceLocation LPLoc, Stmt *SubStmt, + SourceLocation RPLoc); + ExprResult BuildStmtExpr(SourceLocation LPLoc, Stmt *SubStmt, + SourceLocation RPLoc, unsigned TemplateDepth); // Handle the final expression in a statement expression. ExprResult ActOnStmtExprResult(ExprResult E); void ActOnStmtExprError(); @@ -6199,6 +6262,9 @@ class Sema final { llvm::DenseMap NormalizationCache; + llvm::ContextualFoldingSet + SatisfactionCache; + public: const NormalizedConstraint * getNormalizedAssociatedConstraints( @@ -6225,6 +6291,8 @@ class Sema final { /// \brief Check whether the given list of constraint expressions are /// satisfied (as if in a 'conjunction') given template arguments. + /// \param Template the template-like entity that triggered the constraints + /// check (either a concept or a constrained entity). /// \param ConstraintExprs a list of constraint expressions, treated as if /// they were 'AND'ed together. /// \param TemplateArgs the list of template arguments to substitute into the @@ -6236,23 +6304,10 @@ class Sema final { /// expression. /// \returns true if an error occurred and satisfaction could not be checked, /// false otherwise. - bool CheckConstraintSatisfaction(TemplateDecl *Template, - ArrayRef ConstraintExprs, - ArrayRef TemplateArgs, - SourceRange TemplateIDRange, - ConstraintSatisfaction &Satisfaction); - - bool CheckConstraintSatisfaction(ClassTemplatePartialSpecializationDecl *TD, - ArrayRef ConstraintExprs, - ArrayRef TemplateArgs, - SourceRange TemplateIDRange, - ConstraintSatisfaction &Satisfaction); - - bool CheckConstraintSatisfaction(VarTemplatePartialSpecializationDecl *TD, - ArrayRef ConstraintExprs, - ArrayRef TemplateArgs, - SourceRange TemplateIDRange, - ConstraintSatisfaction &Satisfaction); + bool CheckConstraintSatisfaction( + const NamedDecl *Template, ArrayRef ConstraintExprs, + ArrayRef TemplateArgs, + SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction); /// \brief Check whether the given non-dependent constraint expression is /// satisfied. Returns false and updates Satisfaction with the satisfaction @@ -6263,6 +6318,17 @@ class Sema final { bool CheckConstraintSatisfaction(const Expr *ConstraintExpr, ConstraintSatisfaction &Satisfaction); + /// Check whether the given function decl's trailing requires clause is + /// satisfied, if any. Returns false and updates Satisfaction with the + /// satisfaction verdict if successful, emits a diagnostic and returns true if + /// an error occured and satisfaction could not be determined. + /// + /// \returns true if an error occurred, false otherwise. + bool CheckFunctionConstraints(const FunctionDecl *FD, + ConstraintSatisfaction &Satisfaction, + SourceLocation UsageLoc = SourceLocation()); + + /// \brief Ensure that the given template arguments satisfy the constraints /// associated with the given template, emitting a diagnostic if they do not. /// @@ -6282,13 +6348,17 @@ class Sema final { /// \brief Emit diagnostics explaining why a constraint expression was deemed /// unsatisfied. + /// \param First whether this is the first time an unsatisfied constraint is + /// diagnosed for this error. void - DiagnoseUnsatisfiedConstraint(const ConstraintSatisfaction& Satisfaction); + DiagnoseUnsatisfiedConstraint(const ConstraintSatisfaction &Satisfaction, + bool First = true); /// \brief Emit diagnostics explaining why a constraint expression was deemed /// unsatisfied. void - DiagnoseUnsatisfiedConstraint(const ASTConstraintSatisfaction& Satisfaction); + DiagnoseUnsatisfiedConstraint(const ASTConstraintSatisfaction &Satisfaction, + bool First = true); /// \brief Emit diagnostics explaining why a constraint expression was deemed /// unsatisfied because it was ill-formed. @@ -6815,7 +6885,8 @@ class Sema final { QualType ObjectType, bool EnteringContext, bool &MemberOfUnknownSpecialization, SourceLocation TemplateKWLoc = SourceLocation(), - AssumedTemplateKind *ATK = nullptr); + AssumedTemplateKind *ATK = nullptr, + bool Disambiguation = false); TemplateNameKind isTemplateName(Scope *S, CXXScopeSpec &SS, @@ -6824,7 +6895,8 @@ class Sema final { ParsedType ObjectType, bool EnteringContext, TemplateTy &Template, - bool &MemberOfUnknownSpecialization); + bool &MemberOfUnknownSpecialization, + bool Disambiguation = false); /// Try to resolve an undeclared template name as a type template. /// @@ -6873,7 +6945,8 @@ class Sema final { SourceLocation EqualLoc, ParsedType DefaultArg, bool HasTypeConstraint); - bool ActOnTypeConstraint(TemplateIdAnnotation *TypeConstraint, + bool ActOnTypeConstraint(const CXXScopeSpec &SS, + TemplateIdAnnotation *TypeConstraint, TemplateTypeParmDecl *ConstrainedParameter, SourceLocation EllipsisLoc); @@ -6884,6 +6957,10 @@ class Sema final { TemplateTypeParmDecl *ConstrainedParameter, SourceLocation EllipsisLoc); + bool AttachTypeConstraint(AutoTypeLoc TL, + NonTypeTemplateParmDecl *ConstrainedParameter, + SourceLocation EllipsisLoc); + QualType CheckNonTypeTemplateParameterType(TypeSourceInfo *&TSI, SourceLocation Loc); QualType CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc); @@ -6933,7 +7010,8 @@ class Sema final { SourceLocation DeclStartLoc, SourceLocation DeclLoc, const CXXScopeSpec &SS, TemplateIdAnnotation *TemplateId, ArrayRef ParamLists, - bool IsFriend, bool &IsMemberSpecialization, bool &Invalid); + bool IsFriend, bool &IsMemberSpecialization, bool &Invalid, + bool SuppressDiagnostic = false); DeclResult CheckClassTemplate( Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, @@ -6951,7 +7029,7 @@ class Sema final { /// Get a template argument mapping the given template parameter to itself, /// e.g. for X in \c template, this would return an expression template /// argument referencing X. - TemplateArgumentLoc getIdentityTemplateArgumentLoc(Decl *Param, + TemplateArgumentLoc getIdentityTemplateArgumentLoc(NamedDecl *Param, SourceLocation Location); void translateTemplateArguments(const ASTTemplateArgsPtr &In, @@ -7028,8 +7106,8 @@ class Sema final { DeclResult ActOnClassTemplateSpecialization( Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, - SourceLocation ModulePrivateLoc, TemplateIdAnnotation &TemplateId, - const ParsedAttributesView &Attr, + SourceLocation ModulePrivateLoc, CXXScopeSpec &SS, + TemplateIdAnnotation &TemplateId, const ParsedAttributesView &Attr, MultiTemplateParamsArg TemplateParameterLists, SkipBodyInfo *SkipBody = nullptr); @@ -7261,7 +7339,17 @@ class Sema final { SourceLocation KeywordLoc, NestedNameSpecifierLoc QualifierLoc, const IdentifierInfo &II, - SourceLocation IILoc); + SourceLocation IILoc, + TypeSourceInfo **TSI, + bool DeducedTSTContext); + + QualType CheckTypenameType(ElaboratedTypeKeyword Keyword, + SourceLocation KeywordLoc, + NestedNameSpecifierLoc QualifierLoc, + const IdentifierInfo &II, + SourceLocation IILoc, + bool DeducedTSTContext = true); + TypeSourceInfo *RebuildTypeInCurrentInstantiation(TypeSourceInfo *T, SourceLocation Loc, @@ -7281,11 +7369,52 @@ class Sema final { const TemplateArgument *Args, unsigned NumArgs); - // Concepts + //===--------------------------------------------------------------------===// + // C++ Concepts + //===--------------------------------------------------------------------===// Decl *ActOnConceptDefinition( Scope *S, MultiTemplateParamsArg TemplateParameterLists, IdentifierInfo *Name, SourceLocation NameLoc, Expr *ConstraintExpr); + RequiresExprBodyDecl * + ActOnStartRequiresExpr(SourceLocation RequiresKWLoc, + ArrayRef LocalParameters, + Scope *BodyScope); + void ActOnFinishRequiresExpr(); + concepts::Requirement *ActOnSimpleRequirement(Expr *E); + concepts::Requirement *ActOnTypeRequirement( + SourceLocation TypenameKWLoc, CXXScopeSpec &SS, SourceLocation NameLoc, + IdentifierInfo *TypeName, TemplateIdAnnotation *TemplateId); + concepts::Requirement *ActOnCompoundRequirement(Expr *E, + SourceLocation NoexceptLoc); + concepts::Requirement * + ActOnCompoundRequirement( + Expr *E, SourceLocation NoexceptLoc, CXXScopeSpec &SS, + TemplateIdAnnotation *TypeConstraint, unsigned Depth); + concepts::Requirement *ActOnNestedRequirement(Expr *Constraint); + concepts::ExprRequirement * + BuildExprRequirement( + Expr *E, bool IsSatisfied, SourceLocation NoexceptLoc, + concepts::ExprRequirement::ReturnTypeRequirement ReturnTypeRequirement); + concepts::ExprRequirement * + BuildExprRequirement( + concepts::Requirement::SubstitutionDiagnostic *ExprSubstDiag, + bool IsSatisfied, SourceLocation NoexceptLoc, + concepts::ExprRequirement::ReturnTypeRequirement ReturnTypeRequirement); + concepts::TypeRequirement *BuildTypeRequirement(TypeSourceInfo *Type); + concepts::TypeRequirement * + BuildTypeRequirement( + concepts::Requirement::SubstitutionDiagnostic *SubstDiag); + concepts::NestedRequirement *BuildNestedRequirement(Expr *E); + concepts::NestedRequirement * + BuildNestedRequirement( + concepts::Requirement::SubstitutionDiagnostic *SubstDiag); + ExprResult ActOnRequiresExpr(SourceLocation RequiresKWLoc, + RequiresExprBodyDecl *Body, + ArrayRef LocalParameters, + ArrayRef Requirements, + SourceLocation ClosingBraceLoc); + //===--------------------------------------------------------------------===// // C++ Variadic Templates (C++0x [temp.variadic]) //===--------------------------------------------------------------------===// @@ -7794,10 +7923,12 @@ class Sema final { DeduceAutoResult DeduceAutoType(TypeSourceInfo *AutoType, Expr *&Initializer, QualType &Result, - Optional DependentDeductionDepth = None); + Optional DependentDeductionDepth = None, + bool IgnoreConstraints = false); DeduceAutoResult DeduceAutoType(TypeLoc AutoTypeLoc, Expr *&Initializer, QualType &Result, - Optional DependentDeductionDepth = None); + Optional DependentDeductionDepth = None, + bool IgnoreConstraints = false); void DiagnoseAutoDeductionFailure(VarDecl *VDecl, Expr *Init); bool DeduceReturnType(FunctionDecl *FD, SourceLocation Loc, bool Diagnose = true); @@ -7932,6 +8063,13 @@ class Sema final { /// template which was deferred until it was needed. ExceptionSpecInstantiation, + /// We are instantiating a requirement of a requires expression. + RequirementInstantiation, + + /// We are checking the satisfaction of a nested requirement of a requires + /// expression. + NestedRequirementConstraintsCheck, + /// We are declaring an implicit special member function. DeclaringSpecialMember, @@ -8253,6 +8391,19 @@ class Sema final { ParameterMappingSubstitution, NamedDecl *Template, SourceRange InstantiationRange); + /// \brief Note that we are substituting template arguments into a part of + /// a requirement of a requires expression. + InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + concepts::Requirement *Req, + sema::TemplateDeductionInfo &DeductionInfo, + SourceRange InstantiationRange = SourceRange()); + + /// \brief Note that we are checking the satisfaction of the constraint + /// expression inside of a nested requirement. + InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + concepts::NestedRequirement *Req, ConstraintsCheck, + SourceRange InstantiationRange = SourceRange()); + /// Note that we have finished instantiating this template. void Clear(); @@ -11805,6 +11956,13 @@ class Sema final { return DC; } + /// Determine the number of levels of enclosing template parameters. This is + /// only usable while parsing. Note that this does not include dependent + /// contexts in which no template parameters have yet been declared, such as + /// in a terse function template or generic lambda before the first 'auto' is + /// encountered. + unsigned getTemplateDepth(Scope *S) const; + /// To be used for checking whether the arguments being passed to /// function exceeds the number of parameters expected for it. static bool TooManyArguments(size_t NumParams, size_t NumArgs, diff --git a/clang/include/clang/Sema/SemaConcept.h b/clang/include/clang/Sema/SemaConcept.h index acd1e604211a1..c5f9fc45612a9 100644 --- a/clang/include/clang/Sema/SemaConcept.h +++ b/clang/include/clang/Sema/SemaConcept.h @@ -13,10 +13,17 @@ #ifndef LLVM_CLANG_SEMA_SEMACONCEPT_H #define LLVM_CLANG_SEMA_SEMACONCEPT_H +#include "clang/AST/ASTConcept.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Expr.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallVector.h" +#include +#include + namespace clang { class Sema; @@ -36,11 +43,15 @@ struct AtomicConstraint { if (ParameterMapping->size() != Other.ParameterMapping->size()) return false; - for (unsigned I = 0, S = ParameterMapping->size(); I < S; ++I) - if (!C.getCanonicalTemplateArgument((*ParameterMapping)[I].getArgument()) - .structurallyEquals(C.getCanonicalTemplateArgument( - (*Other.ParameterMapping)[I].getArgument()))) + for (unsigned I = 0, S = ParameterMapping->size(); I < S; ++I) { + llvm::FoldingSetNodeID IDA, IDB; + C.getCanonicalTemplateArgument((*ParameterMapping)[I].getArgument()) + .Profile(IDA, C); + C.getCanonicalTemplateArgument((*Other.ParameterMapping)[I].getArgument()) + .Profile(IDB, C); + if (IDA != IDB) return false; + } return true; } diff --git a/clang/include/clang/Sema/Template.h b/clang/include/clang/Sema/Template.h index 4c1cfecd4de68..47d6143bdc9aa 100644 --- a/clang/include/clang/Sema/Template.h +++ b/clang/include/clang/Sema/Template.h @@ -95,6 +95,16 @@ class VarDecl; return TemplateArgumentLists.size(); } + /// Determine how many of the \p OldDepth outermost template parameter + /// lists would be removed by substituting these arguments. + unsigned getNewDepth(unsigned OldDepth) const { + if (OldDepth < NumRetainedOuterLevels) + return OldDepth; + if (OldDepth < getNumLevels()) + return NumRetainedOuterLevels; + return OldDepth - TemplateArgumentLists.size(); + } + /// Retrieve the template argument at a given depth and index. const TemplateArgument &operator()(unsigned Depth, unsigned Index) const { assert(NumRetainedOuterLevels <= Depth && Depth < getNumLevels()); diff --git a/clang/include/clang/Sema/TemplateDeduction.h b/clang/include/clang/Sema/TemplateDeduction.h index b60939c97872d..c0af9f3260b6d 100644 --- a/clang/include/clang/Sema/TemplateDeduction.h +++ b/clang/include/clang/Sema/TemplateDeduction.h @@ -15,6 +15,7 @@ #define LLVM_CLANG_SEMA_TEMPLATEDEDUCTION_H #include "clang/Sema/Ownership.h" +#include "clang/Sema/SemaConcept.h" #include "clang/AST/ASTConcept.h" #include "clang/AST/DeclAccessPair.h" #include "clang/AST/DeclTemplate.h" @@ -66,6 +67,13 @@ class TemplateDeductionInfo { TemplateDeductionInfo(const TemplateDeductionInfo &) = delete; TemplateDeductionInfo &operator=(const TemplateDeductionInfo &) = delete; + enum ForBaseTag { ForBase }; + /// Create temporary template deduction info for speculatively deducing + /// against a base class of an argument's type. + TemplateDeductionInfo(ForBaseTag, const TemplateDeductionInfo &Info) + : Deduced(Info.Deduced), Loc(Info.Loc), DeducedDepth(Info.DeducedDepth), + ExplicitArgs(Info.ExplicitArgs) {} + /// Returns the location at which template argument is /// occurring. SourceLocation getLocation() const { diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h index 1bfcbda8c9f1e..44a12c875da7d 100644 --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -1403,6 +1403,9 @@ namespace serialization { /// An LifetimeExtendedTemporaryDecl record. DECL_LIFETIME_EXTENDED_TEMPORARY, + /// A RequiresExprBodyDecl record. + DECL_REQUIRES_EXPR_BODY, + /// An ObjCTypeParamDecl record. DECL_OBJC_TYPE_PARAM, @@ -1785,6 +1788,7 @@ namespace serialization { EXPR_MATERIALIZE_TEMPORARY, // MaterializeTemporaryExpr EXPR_CXX_FOLD, // CXXFoldExpr EXPR_CONCEPT_SPECIALIZATION,// ConceptSpecializationExpr + EXPR_REQUIRES, // RequiresExpr // CUDA EXPR_CUDA_KERNEL_CALL, // CUDAKernelCallExpr diff --git a/clang/lib/AST/ASTConcept.cpp b/clang/lib/AST/ASTConcept.cpp index fc32e768d92f8..549088ad4a8a8 100644 --- a/clang/lib/AST/ASTConcept.cpp +++ b/clang/lib/AST/ASTConcept.cpp @@ -14,6 +14,10 @@ #include "clang/AST/ASTConcept.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" +#include "clang/AST/TemplateBase.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/FoldingSet.h" using namespace clang; ASTConstraintSatisfaction::ASTConstraintSatisfaction(const ASTContext &C, @@ -53,3 +57,12 @@ ASTConstraintSatisfaction::Create(const ASTContext &C, void *Mem = C.Allocate(size, alignof(ASTConstraintSatisfaction)); return new (Mem) ASTConstraintSatisfaction(C, Satisfaction); } + +void ConstraintSatisfaction::Profile( + llvm::FoldingSetNodeID &ID, const ASTContext &C, + const NamedDecl *ConstraintOwner, ArrayRef TemplateArgs) { + ID.AddPointer(ConstraintOwner); + ID.AddInteger(TemplateArgs.size()); + for (auto &Arg : TemplateArgs) + Arg.Profile(ID, C); +} diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index a51429264dbee..1be72efe4de89 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -716,6 +716,57 @@ ASTContext::CanonicalTemplateTemplateParm::Profile(llvm::FoldingSetNodeID &ID, RequiresClause->Profile(ID, C, /*Canonical=*/true); } +static Expr * +canonicalizeImmediatelyDeclaredConstraint(const ASTContext &C, Expr *IDC, + QualType ConstrainedType) { + // This is a bit ugly - we need to form a new immediately-declared + // constraint that references the new parameter; this would ideally + // require semantic analysis (e.g. template struct S {}; - the + // converted arguments of C could be an argument pack if C is + // declared as template concept C = ...). + // We don't have semantic analysis here so we dig deep into the + // ready-made constraint expr and change the thing manually. + ConceptSpecializationExpr *CSE; + if (const auto *Fold = dyn_cast(IDC)) + CSE = cast(Fold->getLHS()); + else + CSE = cast(IDC); + ArrayRef OldConverted = CSE->getTemplateArguments(); + SmallVector NewConverted; + NewConverted.reserve(OldConverted.size()); + if (OldConverted.front().getKind() == TemplateArgument::Pack) { + // The case: + // template concept C = true; + // template T> struct S; -> constraint is C<{T, int}> + NewConverted.push_back(ConstrainedType); + for (auto &Arg : OldConverted.front().pack_elements().drop_front(1)) + NewConverted.push_back(Arg); + TemplateArgument NewPack(NewConverted); + + NewConverted.clear(); + NewConverted.push_back(NewPack); + assert(OldConverted.size() == 1 && + "Template parameter pack should be the last parameter"); + } else { + assert(OldConverted.front().getKind() == TemplateArgument::Type && + "Unexpected first argument kind for immediately-declared " + "constraint"); + NewConverted.push_back(ConstrainedType); + for (auto &Arg : OldConverted.drop_front(1)) + NewConverted.push_back(Arg); + } + Expr *NewIDC = ConceptSpecializationExpr::Create( + C, CSE->getNamedConcept(), NewConverted, nullptr, + CSE->isInstantiationDependent(), CSE->containsUnexpandedParameterPack()); + + if (auto *OrigFold = dyn_cast(IDC)) + NewIDC = new (C) CXXFoldExpr(OrigFold->getType(), SourceLocation(), NewIDC, + BinaryOperatorKind::BO_LAnd, + SourceLocation(), /*RHS=*/nullptr, + SourceLocation(), /*NumExpansions=*/None); + return NewIDC; +} + TemplateTemplateParmDecl * ASTContext::getCanonicalTemplateTemplateParmDecl( TemplateTemplateParmDecl *TTP) const { @@ -743,68 +794,23 @@ ASTContext::getCanonicalTemplateTemplateParmDecl( TTP->isExpandedParameterPack() ? llvm::Optional(TTP->getNumExpansionParameters()) : None); if (const auto *TC = TTP->getTypeConstraint()) { - // This is a bit ugly - we need to form a new immediately-declared - // constraint that references the new parameter; this would ideally - // require semantic analysis (e.g. template struct S {}; - the - // converted arguments of C could be an argument pack if C is - // declared as template concept C = ...). - // We don't have semantic analysis here so we dig deep into the - // ready-made constraint expr and change the thing manually. - Expr *IDC = TC->getImmediatelyDeclaredConstraint(); - ConceptSpecializationExpr *CSE; - if (const auto *Fold = dyn_cast(IDC)) - CSE = cast(Fold->getLHS()); - else - CSE = cast(IDC); - ArrayRef OldConverted = CSE->getTemplateArguments(); - SmallVector NewConverted; - NewConverted.reserve(OldConverted.size()); - QualType ParamAsArgument(NewTTP->getTypeForDecl(), 0); - if (OldConverted.front().getKind() == TemplateArgument::Pack) { - // The case: - // template concept C = true; - // template T> struct S; -> constraint is C<{T, int}> - NewConverted.push_back(ParamAsArgument); - for (auto &Arg : OldConverted.front().pack_elements().drop_front(1)) - NewConverted.push_back(Arg); - TemplateArgument NewPack(NewConverted); - - NewConverted.clear(); - NewConverted.push_back(NewPack); - assert(OldConverted.size() == 1 && - "Template parameter pack should be the last parameter"); - } else { - assert(OldConverted.front().getKind() == TemplateArgument::Type && - "Unexpected first argument kind for immediately-declared " - "constraint"); - NewConverted.push_back(ParamAsArgument); - for (auto &Arg : OldConverted.drop_front(1)) - NewConverted.push_back(Arg); - } - Expr *NewIDC = ConceptSpecializationExpr::Create(*this, - NestedNameSpecifierLoc(), /*TemplateKWLoc=*/SourceLocation(), - CSE->getConceptNameInfo(), /*FoundDecl=*/CSE->getNamedConcept(), - CSE->getNamedConcept(), - // Actually canonicalizing a TemplateArgumentLoc is difficult so we - // simply omit the ArgsAsWritten - /*ArgsAsWritten=*/nullptr, NewConverted, nullptr); - - if (auto *OrigFold = dyn_cast(IDC)) - NewIDC = new (*this) CXXFoldExpr(OrigFold->getType(), - SourceLocation(), NewIDC, - BinaryOperatorKind::BO_LAnd, - SourceLocation(), /*RHS=*/nullptr, - SourceLocation(), - /*NumExpansions=*/None); - + Expr *NewIDC = canonicalizeImmediatelyDeclaredConstraint( + *this, TC->getImmediatelyDeclaredConstraint(), + ParamAsArgument); + TemplateArgumentListInfo CanonArgsAsWritten; + if (auto *Args = TC->getTemplateArgsAsWritten()) + for (const auto &ArgLoc : Args->arguments()) + CanonArgsAsWritten.addArgument( + TemplateArgumentLoc(ArgLoc.getArgument(), + TemplateArgumentLocInfo())); NewTTP->setTypeConstraint( NestedNameSpecifierLoc(), DeclarationNameInfo(TC->getNamedConcept()->getDeclName(), SourceLocation()), /*FoundDecl=*/nullptr, // Actually canonicalizing a TemplateArgumentLoc is difficult so we // simply omit the ArgsAsWritten - CSE->getNamedConcept(), /*ArgsAsWritten=*/nullptr, NewIDC); + TC->getNamedConcept(), /*ArgsAsWritten=*/nullptr, NewIDC); } CanonParams.push_back(NewTTP); } else if (const auto *NTTP = dyn_cast(*P)) { @@ -839,6 +845,13 @@ ASTContext::getCanonicalTemplateTemplateParmDecl( NTTP->isParameterPack(), TInfo); } + if (AutoType *AT = T->getContainedAutoType()) { + if (AT->isConstrained()) { + Param->setPlaceholderTypeConstraint( + canonicalizeImmediatelyDeclaredConstraint( + *this, NTTP->getPlaceholderTypeConstraint(), T)); + } + } CanonParams.push_back(Param); } else @@ -943,7 +956,7 @@ ASTContext::ASTContext(LangOptions &LOpts, SourceManager &SM, Builtin::Context &builtins) : ConstantArrayTypes(this_()), FunctionProtoTypes(this_()), TemplateSpecializationTypes(this_()), - DependentTemplateSpecializationTypes(this_()), + DependentTemplateSpecializationTypes(this_()), AutoTypes(this_()), SubstTemplateTemplateParmPacks(this_()), CanonTemplateTemplateParms(this_()), SourceMgr(SM), LangOpts(LOpts), SanitizerBL(new SanitizerBlacklist(LangOpts.SanitizerBlacklistFiles, SM)), @@ -5124,21 +5137,29 @@ QualType ASTContext::getUnaryTransformType(QualType BaseType, /// getAutoType - Return the uniqued reference to the 'auto' type which has been /// deduced to the given type, or to the canonical undeduced 'auto' type, or the /// canonical deduced-but-dependent 'auto' type. -QualType ASTContext::getAutoType(QualType DeducedType, AutoTypeKeyword Keyword, - bool IsDependent, bool IsPack) const { +QualType +ASTContext::getAutoType(QualType DeducedType, AutoTypeKeyword Keyword, + bool IsDependent, bool IsPack, + ConceptDecl *TypeConstraintConcept, + ArrayRef TypeConstraintArgs) const { assert((!IsPack || IsDependent) && "only use IsPack for a dependent pack"); - if (DeducedType.isNull() && Keyword == AutoTypeKeyword::Auto && !IsDependent) + if (DeducedType.isNull() && Keyword == AutoTypeKeyword::Auto && + !TypeConstraintConcept && !IsDependent) return getAutoDeductType(); // Look in the folding set for an existing type. void *InsertPos = nullptr; llvm::FoldingSetNodeID ID; - AutoType::Profile(ID, DeducedType, Keyword, IsDependent, IsPack); + AutoType::Profile(ID, *this, DeducedType, Keyword, IsDependent, + TypeConstraintConcept, TypeConstraintArgs); if (AutoType *AT = AutoTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(AT, 0); - auto *AT = new (*this, TypeAlignment) - AutoType(DeducedType, Keyword, IsDependent, IsPack); + void *Mem = Allocate(sizeof(AutoType) + + sizeof(TemplateArgument) * TypeConstraintArgs.size(), + TypeAlignment); + auto *AT = new (Mem) AutoType(DeducedType, Keyword, IsDependent, IsPack, + TypeConstraintConcept, TypeConstraintArgs); Types.push_back(AT); if (InsertPos) AutoTypes.InsertNode(AT, InsertPos); @@ -5200,7 +5221,8 @@ QualType ASTContext::getAutoDeductType() const { if (AutoDeductTy.isNull()) AutoDeductTy = QualType( new (*this, TypeAlignment) AutoType(QualType(), AutoTypeKeyword::Auto, - /*dependent*/false, /*pack*/false), + /*dependent*/false, /*pack*/false, + /*concept*/nullptr, /*args*/{}), 0); return AutoDeductTy; } diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 22fb67478c969..ab4e961dcd4cb 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -1366,9 +1366,21 @@ ExpectedType ASTNodeImporter::VisitAutoType(const AutoType *T) { if (!ToDeducedTypeOrErr) return ToDeducedTypeOrErr.takeError(); - return Importer.getToContext().getAutoType(*ToDeducedTypeOrErr, - T->getKeyword(), - /*IsDependent*/false); + ExpectedDecl ToTypeConstraintConcept = import(T->getTypeConstraintConcept()); + if (!ToTypeConstraintConcept) + return ToTypeConstraintConcept.takeError(); + + SmallVector ToTemplateArgs; + ArrayRef FromTemplateArgs = T->getTypeConstraintArguments(); + if (Error Err = ImportTemplateArguments(FromTemplateArgs.data(), + FromTemplateArgs.size(), + ToTemplateArgs)) + return std::move(Err); + + return Importer.getToContext().getAutoType( + *ToDeducedTypeOrErr, T->getKeyword(), /*IsDependent*/false, + /*IsPack=*/false, cast_or_null(*ToTypeConstraintConcept), + ToTemplateArgs); } ExpectedType ASTNodeImporter::VisitInjectedClassNameType( @@ -6712,8 +6724,9 @@ ExpectedStmt ASTNodeImporter::VisitStmtExpr(StmtExpr *E) { SourceLocation ToLParenLoc, ToRParenLoc; std::tie(ToSubStmt, ToType, ToLParenLoc, ToRParenLoc) = *Imp; - return new (Importer.getToContext()) StmtExpr( - ToSubStmt, ToType, ToLParenLoc, ToRParenLoc); + return new (Importer.getToContext()) + StmtExpr(ToSubStmt, ToType, ToLParenLoc, ToRParenLoc, + E->getTemplateDepth()); } ExpectedStmt ASTNodeImporter::VisitUnaryOperator(UnaryOperator *E) { diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp index db48405055cda..91a2f3a8391bb 100644 --- a/clang/lib/AST/ASTStructuralEquivalence.cpp +++ b/clang/lib/AST/ASTStructuralEquivalence.cpp @@ -729,11 +729,31 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, return false; break; - case Type::Auto: - if (!IsStructurallyEquivalent(Context, cast(T1)->getDeducedType(), - cast(T2)->getDeducedType())) + case Type::Auto: { + auto *Auto1 = cast(T1); + auto *Auto2 = cast(T2); + if (!IsStructurallyEquivalent(Context, Auto1->getDeducedType(), + Auto2->getDeducedType())) return false; + if (Auto1->isConstrained() != Auto2->isConstrained()) + return false; + if (Auto1->isConstrained()) { + if (Auto1->getTypeConstraintConcept() != + Auto2->getTypeConstraintConcept()) + return false; + ArrayRef Auto1Args = + Auto1->getTypeConstraintArguments(); + ArrayRef Auto2Args = + Auto2->getTypeConstraintArguments(); + if (Auto1Args.size() != Auto2Args.size()) + return false; + for (unsigned I = 0, N = Auto1Args.size(); I != N; ++I) { + if (!IsStructurallyEquivalent(Context, Auto1Args[I], Auto2Args[I])) + return false; + } + } break; + } case Type::DeducedTemplateSpecialization: { const auto *DT1 = cast(T1); diff --git a/clang/lib/AST/CMakeLists.txt b/clang/lib/AST/CMakeLists.txt index bd9b0934591c5..e79c245d2f8c4 100644 --- a/clang/lib/AST/CMakeLists.txt +++ b/clang/lib/AST/CMakeLists.txt @@ -46,6 +46,7 @@ add_clang_library(clangAST DeclTemplate.cpp Expr.cpp ExprClassification.cpp + ExprConcepts.cpp ExprConstant.cpp ExprCXX.cpp ExprObjC.cpp diff --git a/clang/lib/AST/CXXInheritance.cpp b/clang/lib/AST/CXXInheritance.cpp index a3a3794b2edd4..0377bd324cb65 100644 --- a/clang/lib/AST/CXXInheritance.cpp +++ b/clang/lib/AST/CXXInheritance.cpp @@ -758,6 +758,8 @@ CXXRecordDecl::getFinalOverriders(CXXFinalOverriderMap &FinalOverriders) const { return false; }; + // FIXME: IsHidden reads from Overriding from the middle of a remove_if + // over the same sequence! Is this guaranteed to work? Overriding.erase( std::remove_if(Overriding.begin(), Overriding.end(), IsHidden), Overriding.end()); diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index 6ee767ccecf7d..cb4d61cac2c71 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -804,6 +804,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case OMPCapturedExpr: case Empty: case LifetimeExtendedTemporary: + case RequiresExprBody: // Never looked up by name. return 0; } @@ -1177,6 +1178,7 @@ DeclContext *DeclContext::getPrimaryContext() { case Decl::Captured: case Decl::OMPDeclareReduction: case Decl::OMPDeclareMapper: + case Decl::RequiresExprBody: // There is only one DeclContext for these entities. return this; diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index 2ead1e70ea0d6..227fe80ccab4a 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -1968,6 +1968,16 @@ CXXDeductionGuideDecl *CXXDeductionGuideDecl::CreateDeserialized(ASTContext &C, QualType(), nullptr, SourceLocation()); } +RequiresExprBodyDecl *RequiresExprBodyDecl::Create( + ASTContext &C, DeclContext *DC, SourceLocation StartLoc) { + return new (C, DC) RequiresExprBodyDecl(C, DC, StartLoc); +} + +RequiresExprBodyDecl *RequiresExprBodyDecl::CreateDeserialized(ASTContext &C, + unsigned ID) { + return new (C, ID) RequiresExprBodyDecl(C, nullptr, SourceLocation()); +} + void CXXMethodDecl::anchor() {} bool CXXMethodDecl::isStatic() const { @@ -2028,17 +2038,36 @@ CXXMethodDecl::getCorrespondingMethodInClass(const CXXRecordDecl *RD, if (auto *MD = getCorrespondingMethodDeclaredInClass(RD, MayBeBase)) return MD; + llvm::SmallVector FinalOverriders; + auto AddFinalOverrider = [&](CXXMethodDecl *D) { + // If this function is overridden by a candidate final overrider, it is not + // a final overrider. + for (CXXMethodDecl *OtherD : FinalOverriders) { + if (declaresSameEntity(D, OtherD) || recursivelyOverrides(OtherD, D)) + return; + } + + // Other candidate final overriders might be overridden by this function. + FinalOverriders.erase( + std::remove_if(FinalOverriders.begin(), FinalOverriders.end(), + [&](CXXMethodDecl *OtherD) { + return recursivelyOverrides(D, OtherD); + }), + FinalOverriders.end()); + + FinalOverriders.push_back(D); + }; + for (const auto &I : RD->bases()) { const RecordType *RT = I.getType()->getAs(); if (!RT) continue; const auto *Base = cast(RT->getDecl()); - CXXMethodDecl *T = this->getCorrespondingMethodInClass(Base); - if (T) - return T; + if (CXXMethodDecl *D = this->getCorrespondingMethodInClass(Base)) + AddFinalOverrider(D); } - return nullptr; + return FinalOverriders.size() == 1 ? FinalOverriders.front() : nullptr; } CXXMethodDecl *CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD, @@ -2095,6 +2124,11 @@ CXXMethodDecl *CXXMethodDecl::getDevirtualizedMethod(const Expr *Base, CXXMethodDecl *DevirtualizedMethod = getCorrespondingMethodInClass(BestDynamicDecl); + // If there final overrider in the dynamic type is ambiguous, we can't + // devirtualize this call. + if (!DevirtualizedMethod) + return nullptr; + // If that method is pure virtual, we can't devirtualize. If this code is // reached, the result would be UB, not a direct call to the derived class // function, and we can't assume the derived class function is defined. diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp index 95a2e26e0df84..b5e4ec2d7f43c 100755 --- a/clang/lib/AST/DeclTemplate.cpp +++ b/clang/lib/AST/DeclTemplate.cpp @@ -164,10 +164,15 @@ static void AdoptTemplateParameterList(TemplateParameterList *Params, void TemplateParameterList:: getAssociatedConstraints(llvm::SmallVectorImpl &AC) const { if (HasConstrainedParameters) - for (const NamedDecl *Param : *this) - if (const auto *TTP = dyn_cast(Param)) + for (const NamedDecl *Param : *this) { + if (const auto *TTP = dyn_cast(Param)) { if (const auto *TC = TTP->getTypeConstraint()) AC.push_back(TC->getImmediatelyDeclaredConstraint()); + } else if (const auto *NTTP = dyn_cast(Param)) { + if (const Expr *E = NTTP->getPlaceholderTypeConstraint()) + AC.push_back(E); + } + } if (HasRequiresClause) AC.push_back(getRequiresClause()); } @@ -483,7 +488,10 @@ static void ProfileTemplateParameterList(ASTContext &C, if (const auto *TTP = dyn_cast(D)) { ID.AddInteger(1); ID.AddBoolean(TTP->isParameterPack()); - // TODO: Concepts: profile type-constraints. + ID.AddBoolean(TTP->hasTypeConstraint()); + if (const TypeConstraint *TC = TTP->getTypeConstraint()) + TC->getImmediatelyDeclaredConstraint()->Profile(ID, C, + /*Canonical=*/true); continue; } const auto *TTP = cast(D); @@ -684,8 +692,14 @@ NonTypeTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC, unsigned D, unsigned P, IdentifierInfo *Id, QualType T, bool ParameterPack, TypeSourceInfo *TInfo) { - return new (C, DC) NonTypeTemplateParmDecl(DC, StartLoc, IdLoc, D, P, Id, - T, ParameterPack, TInfo); + AutoType *AT = + C.getLangOpts().CPlusPlus2a ? T->getContainedAutoType() : nullptr; + return new (C, DC, + additionalSizeToAlloc, + Expr *>(0, + AT && AT->isConstrained() ? 1 : 0)) + NonTypeTemplateParmDecl(DC, StartLoc, IdLoc, D, P, Id, T, ParameterPack, + TInfo); } NonTypeTemplateParmDecl *NonTypeTemplateParmDecl::Create( @@ -693,26 +707,34 @@ NonTypeTemplateParmDecl *NonTypeTemplateParmDecl::Create( SourceLocation IdLoc, unsigned D, unsigned P, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, ArrayRef ExpandedTypes, ArrayRef ExpandedTInfos) { + AutoType *AT = TInfo->getType()->getContainedAutoType(); return new (C, DC, - additionalSizeToAlloc>( - ExpandedTypes.size())) + additionalSizeToAlloc, + Expr *>( + ExpandedTypes.size(), AT && AT->isConstrained() ? 1 : 0)) NonTypeTemplateParmDecl(DC, StartLoc, IdLoc, D, P, Id, T, TInfo, ExpandedTypes, ExpandedTInfos); } NonTypeTemplateParmDecl * -NonTypeTemplateParmDecl::CreateDeserialized(ASTContext &C, unsigned ID) { - return new (C, ID) NonTypeTemplateParmDecl(nullptr, SourceLocation(), - SourceLocation(), 0, 0, nullptr, - QualType(), false, nullptr); +NonTypeTemplateParmDecl::CreateDeserialized(ASTContext &C, unsigned ID, + bool HasTypeConstraint) { + return new (C, ID, additionalSizeToAlloc, + Expr *>(0, + HasTypeConstraint ? 1 : 0)) + NonTypeTemplateParmDecl(nullptr, SourceLocation(), SourceLocation(), + 0, 0, nullptr, QualType(), false, nullptr); } NonTypeTemplateParmDecl * NonTypeTemplateParmDecl::CreateDeserialized(ASTContext &C, unsigned ID, - unsigned NumExpandedTypes) { + unsigned NumExpandedTypes, + bool HasTypeConstraint) { auto *NTTP = - new (C, ID, additionalSizeToAlloc>( - NumExpandedTypes)) + new (C, ID, additionalSizeToAlloc, + Expr *>( + NumExpandedTypes, HasTypeConstraint ? 1 : 0)) NonTypeTemplateParmDecl(nullptr, SourceLocation(), SourceLocation(), 0, 0, nullptr, QualType(), nullptr, None, None); diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 73ddbc62482dd..fea7d606f2616 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -1685,6 +1685,11 @@ MemberExpr *MemberExpr::Create( CXXRecordDecl *RD = dyn_cast_or_null(DC); if (RD && RD->isDependentContext() && RD->isCurrentInstantiation(DC)) E->setTypeDependent(T->isDependentType()); + + // Bitfield with value-dependent width is type-dependent. + FieldDecl *FD = dyn_cast(MemberDecl); + if (FD && FD->isBitField() && FD->getBitWidth()->isValueDependent()) + E->setTypeDependent(true); } if (HasQualOrFound) { @@ -3457,6 +3462,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx, case OpaqueValueExprClass: case SourceLocExprClass: case ConceptSpecializationExprClass: + case RequiresExprClass: // These never have a side-effect. return false; diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp index 422227d787b10..e4bd218ae2d36 100644 --- a/clang/lib/AST/ExprCXX.cpp +++ b/clang/lib/AST/ExprCXX.cpp @@ -17,6 +17,7 @@ #include "clang/AST/DeclAccessPair.h" #include "clang/AST/DeclBase.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclTemplate.h" #include "clang/AST/DeclarationName.h" #include "clang/AST/Expr.h" #include "clang/AST/LambdaCapture.h" @@ -1764,81 +1765,3 @@ CUDAKernelCallExpr *CUDAKernelCallExpr::CreateEmpty(const ASTContext &Ctx, alignof(CUDAKernelCallExpr)); return new (Mem) CUDAKernelCallExpr(NumArgs, Empty); } - -ConceptSpecializationExpr::ConceptSpecializationExpr(const ASTContext &C, - NestedNameSpecifierLoc NNS, SourceLocation TemplateKWLoc, - DeclarationNameInfo ConceptNameInfo, NamedDecl *FoundDecl, - ConceptDecl *NamedConcept, const ASTTemplateArgumentListInfo *ArgsAsWritten, - ArrayRef ConvertedArgs, - const ConstraintSatisfaction *Satisfaction) - : Expr(ConceptSpecializationExprClass, C.BoolTy, VK_RValue, OK_Ordinary, - /*TypeDependent=*/false, - // All the flags below are set in setTemplateArguments. - /*ValueDependent=*/!Satisfaction, /*InstantiationDependent=*/false, - /*ContainsUnexpandedParameterPacks=*/false), - ConceptReference(NNS, TemplateKWLoc, ConceptNameInfo, FoundDecl, - NamedConcept, ArgsAsWritten), - NumTemplateArgs(ConvertedArgs.size()), - Satisfaction(Satisfaction ? - ASTConstraintSatisfaction::Create(C, *Satisfaction) : - nullptr) { - setTemplateArguments(ConvertedArgs); -} - -ConceptSpecializationExpr::ConceptSpecializationExpr(EmptyShell Empty, - unsigned NumTemplateArgs) - : Expr(ConceptSpecializationExprClass, Empty), ConceptReference(), - NumTemplateArgs(NumTemplateArgs) { } - -void ConceptSpecializationExpr::setTemplateArguments( - ArrayRef Converted) { - assert(Converted.size() == NumTemplateArgs); - std::uninitialized_copy(Converted.begin(), Converted.end(), - getTrailingObjects()); - bool IsInstantiationDependent = false; - bool ContainsUnexpandedParameterPack = false; - for (const TemplateArgument& Arg : Converted) { - if (Arg.isInstantiationDependent()) - IsInstantiationDependent = true; - if (Arg.containsUnexpandedParameterPack()) - ContainsUnexpandedParameterPack = true; - if (ContainsUnexpandedParameterPack && IsInstantiationDependent) - break; - } - - // Currently guaranteed by the fact concepts can only be at namespace-scope. - assert(!NestedNameSpec || - (!NestedNameSpec.getNestedNameSpecifier()->isInstantiationDependent() && - !NestedNameSpec.getNestedNameSpecifier() - ->containsUnexpandedParameterPack())); - setInstantiationDependent(IsInstantiationDependent); - setContainsUnexpandedParameterPack(ContainsUnexpandedParameterPack); - assert((!isValueDependent() || isInstantiationDependent()) && - "should not be value-dependent"); -} - -ConceptSpecializationExpr * -ConceptSpecializationExpr::Create(const ASTContext &C, - NestedNameSpecifierLoc NNS, - SourceLocation TemplateKWLoc, - DeclarationNameInfo ConceptNameInfo, - NamedDecl *FoundDecl, - ConceptDecl *NamedConcept, - const ASTTemplateArgumentListInfo *ArgsAsWritten, - ArrayRef ConvertedArgs, - const ConstraintSatisfaction *Satisfaction) { - void *Buffer = C.Allocate(totalSizeToAlloc( - ConvertedArgs.size())); - return new (Buffer) ConceptSpecializationExpr(C, NNS, TemplateKWLoc, - ConceptNameInfo, FoundDecl, - NamedConcept, ArgsAsWritten, - ConvertedArgs, Satisfaction); -} - -ConceptSpecializationExpr * -ConceptSpecializationExpr::Create(ASTContext &C, EmptyShell Empty, - unsigned NumTemplateArgs) { - void *Buffer = C.Allocate(totalSizeToAlloc( - NumTemplateArgs)); - return new (Buffer) ConceptSpecializationExpr(Empty, NumTemplateArgs); -} diff --git a/clang/lib/AST/ExprClassification.cpp b/clang/lib/AST/ExprClassification.cpp index 9dbf6fe9e0f06..d201af31f521e 100644 --- a/clang/lib/AST/ExprClassification.cpp +++ b/clang/lib/AST/ExprClassification.cpp @@ -193,6 +193,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { case Expr::DesignatedInitUpdateExprClass: case Expr::SourceLocExprClass: case Expr::ConceptSpecializationExprClass: + case Expr::RequiresExprClass: return Cl::CL_PRValue; case Expr::ConstantExprClass: diff --git a/clang/lib/AST/ExprConcepts.cpp b/clang/lib/AST/ExprConcepts.cpp new file mode 100644 index 0000000000000..b5a3686dc99a5 --- /dev/null +++ b/clang/lib/AST/ExprConcepts.cpp @@ -0,0 +1,218 @@ +//===- ExprCXX.cpp - (C++) Expression AST Node Implementation -------------===// +// +// 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 implements the subclesses of Expr class declared in ExprCXX.h +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/ExprConcepts.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/ASTConcept.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclarationName.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/Expr.h" +#include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/TemplateBase.h" +#include "clang/AST/Type.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/Support/TrailingObjects.h" +#include +#include +#include + +using namespace clang; + +ConceptSpecializationExpr::ConceptSpecializationExpr(const ASTContext &C, + NestedNameSpecifierLoc NNS, SourceLocation TemplateKWLoc, + DeclarationNameInfo ConceptNameInfo, NamedDecl *FoundDecl, + ConceptDecl *NamedConcept, const ASTTemplateArgumentListInfo *ArgsAsWritten, + ArrayRef ConvertedArgs, + const ConstraintSatisfaction *Satisfaction) + : Expr(ConceptSpecializationExprClass, C.BoolTy, VK_RValue, OK_Ordinary, + /*TypeDependent=*/false, + // All the flags below are set in setTemplateArguments. + /*ValueDependent=*/!Satisfaction, /*InstantiationDependent=*/false, + /*ContainsUnexpandedParameterPacks=*/false), + ConceptReference(NNS, TemplateKWLoc, ConceptNameInfo, FoundDecl, + NamedConcept, ArgsAsWritten), + NumTemplateArgs(ConvertedArgs.size()), + Satisfaction(Satisfaction ? + ASTConstraintSatisfaction::Create(C, *Satisfaction) : + nullptr) { + setTemplateArguments(ConvertedArgs); + bool IsInstantiationDependent = false; + bool ContainsUnexpandedParameterPack = false; + for (const TemplateArgumentLoc& ArgLoc : ArgsAsWritten->arguments()) { + if (ArgLoc.getArgument().isInstantiationDependent()) + IsInstantiationDependent = true; + if (ArgLoc.getArgument().containsUnexpandedParameterPack()) + ContainsUnexpandedParameterPack = true; + if (ContainsUnexpandedParameterPack && IsInstantiationDependent) + break; + } + + // Currently guaranteed by the fact concepts can only be at namespace-scope. + assert(!NestedNameSpec || + (!NestedNameSpec.getNestedNameSpecifier()->isInstantiationDependent() && + !NestedNameSpec.getNestedNameSpecifier() + ->containsUnexpandedParameterPack())); + setInstantiationDependent(IsInstantiationDependent); + setContainsUnexpandedParameterPack(ContainsUnexpandedParameterPack); + assert((!isValueDependent() || isInstantiationDependent()) && + "should not be value-dependent"); +} + +ConceptSpecializationExpr::ConceptSpecializationExpr(EmptyShell Empty, + unsigned NumTemplateArgs) + : Expr(ConceptSpecializationExprClass, Empty), ConceptReference(), + NumTemplateArgs(NumTemplateArgs) { } + +void ConceptSpecializationExpr::setTemplateArguments( + ArrayRef Converted) { + assert(Converted.size() == NumTemplateArgs); + std::uninitialized_copy(Converted.begin(), Converted.end(), + getTrailingObjects()); +} + +ConceptSpecializationExpr * +ConceptSpecializationExpr::Create(const ASTContext &C, + NestedNameSpecifierLoc NNS, + SourceLocation TemplateKWLoc, + DeclarationNameInfo ConceptNameInfo, + NamedDecl *FoundDecl, + ConceptDecl *NamedConcept, + const ASTTemplateArgumentListInfo *ArgsAsWritten, + ArrayRef ConvertedArgs, + const ConstraintSatisfaction *Satisfaction) { + void *Buffer = C.Allocate(totalSizeToAlloc( + ConvertedArgs.size())); + return new (Buffer) ConceptSpecializationExpr(C, NNS, TemplateKWLoc, + ConceptNameInfo, FoundDecl, + NamedConcept, ArgsAsWritten, + ConvertedArgs, Satisfaction); +} + +ConceptSpecializationExpr::ConceptSpecializationExpr( + const ASTContext &C, ConceptDecl *NamedConcept, + ArrayRef ConvertedArgs, + const ConstraintSatisfaction *Satisfaction, bool Dependent, + bool ContainsUnexpandedParameterPack) + : Expr(ConceptSpecializationExprClass, C.BoolTy, VK_RValue, OK_Ordinary, + /*TypeDependent=*/false, + /*ValueDependent=*/!Satisfaction, Dependent, + ContainsUnexpandedParameterPack), + ConceptReference(NestedNameSpecifierLoc(), SourceLocation(), + DeclarationNameInfo(), NamedConcept, + NamedConcept, nullptr), + NumTemplateArgs(ConvertedArgs.size()), + Satisfaction(Satisfaction ? + ASTConstraintSatisfaction::Create(C, *Satisfaction) : + nullptr) { + setTemplateArguments(ConvertedArgs); +} + +ConceptSpecializationExpr * +ConceptSpecializationExpr::Create(const ASTContext &C, + ConceptDecl *NamedConcept, + ArrayRef ConvertedArgs, + const ConstraintSatisfaction *Satisfaction, + bool Dependent, + bool ContainsUnexpandedParameterPack) { + void *Buffer = C.Allocate(totalSizeToAlloc( + ConvertedArgs.size())); + return new (Buffer) ConceptSpecializationExpr( + C, NamedConcept, ConvertedArgs, Satisfaction, Dependent, + ContainsUnexpandedParameterPack); +} + +ConceptSpecializationExpr * +ConceptSpecializationExpr::Create(ASTContext &C, EmptyShell Empty, + unsigned NumTemplateArgs) { + void *Buffer = C.Allocate(totalSizeToAlloc( + NumTemplateArgs)); + return new (Buffer) ConceptSpecializationExpr(Empty, NumTemplateArgs); +} + +const TypeConstraint * +concepts::ExprRequirement::ReturnTypeRequirement::getTypeConstraint() const { + assert(isTypeConstraint()); + auto TPL = + TypeConstraintInfo.getPointer().get(); + return cast(TPL->getParam(0)) + ->getTypeConstraint(); +} + +RequiresExpr::RequiresExpr(ASTContext &C, SourceLocation RequiresKWLoc, + RequiresExprBodyDecl *Body, + ArrayRef LocalParameters, + ArrayRef Requirements, + SourceLocation RBraceLoc) + : Expr(RequiresExprClass, C.BoolTy, VK_RValue, OK_Ordinary, + /*TD=*/false, /*VD=*/false, /*ID=*/false, + /*ContainsUnexpandedParameterPack=*/false), + NumLocalParameters(LocalParameters.size()), + NumRequirements(Requirements.size()), Body(Body), RBraceLoc(RBraceLoc) { + RequiresExprBits.IsSatisfied = false; + RequiresExprBits.RequiresKWLoc = RequiresKWLoc; + bool Dependent = false; + bool ContainsUnexpandedParameterPack = false; + for (ParmVarDecl *P : LocalParameters) { + Dependent |= P->getType()->isInstantiationDependentType(); + ContainsUnexpandedParameterPack |= + P->getType()->containsUnexpandedParameterPack(); + } + RequiresExprBits.IsSatisfied = true; + for (concepts::Requirement *R : Requirements) { + Dependent |= R->isDependent(); + ContainsUnexpandedParameterPack |= R->containsUnexpandedParameterPack(); + if (!Dependent) { + RequiresExprBits.IsSatisfied = R->isSatisfied(); + if (!RequiresExprBits.IsSatisfied) + break; + } + } + std::copy(LocalParameters.begin(), LocalParameters.end(), + getTrailingObjects()); + std::copy(Requirements.begin(), Requirements.end(), + getTrailingObjects()); + RequiresExprBits.IsSatisfied |= Dependent; + setValueDependent(Dependent); + setInstantiationDependent(Dependent); + setContainsUnexpandedParameterPack(ContainsUnexpandedParameterPack); +} + +RequiresExpr::RequiresExpr(ASTContext &C, EmptyShell Empty, + unsigned NumLocalParameters, + unsigned NumRequirements) + : Expr(RequiresExprClass, Empty), NumLocalParameters(NumLocalParameters), + NumRequirements(NumRequirements) { } + +RequiresExpr * +RequiresExpr::Create(ASTContext &C, SourceLocation RequiresKWLoc, + RequiresExprBodyDecl *Body, + ArrayRef LocalParameters, + ArrayRef Requirements, + SourceLocation RBraceLoc) { + void *Mem = + C.Allocate(totalSizeToAlloc( + LocalParameters.size(), Requirements.size()), + alignof(RequiresExpr)); + return new (Mem) RequiresExpr(C, RequiresKWLoc, Body, LocalParameters, + Requirements, RBraceLoc); +} + +RequiresExpr * +RequiresExpr::Create(ASTContext &C, EmptyShell Empty, + unsigned NumLocalParameters, unsigned NumRequirements) { + void *Mem = + C.Allocate(totalSizeToAlloc( + NumLocalParameters, NumRequirements), + alignof(RequiresExpr)); + return new (Mem) RequiresExpr(C, Empty, NumLocalParameters, NumRequirements); +} diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index c4b27b5d1daa2..c79973507323d 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -9912,6 +9912,7 @@ class IntExprEvaluator bool VisitSizeOfPackExpr(const SizeOfPackExpr *E); bool VisitSourceLocExpr(const SourceLocExpr *E); bool VisitConceptSpecializationExpr(const ConceptSpecializationExpr *E); + bool VisitRequiresExpr(const RequiresExpr *E); // FIXME: Missing: array subscript of vector, member of vector }; @@ -12524,6 +12525,9 @@ bool IntExprEvaluator::VisitConceptSpecializationExpr( return Success(E->isSatisfied(), E); } +bool IntExprEvaluator::VisitRequiresExpr(const RequiresExpr *E) { + return Success(E->isSatisfied(), E); +} bool FixedPointExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) { switch (E->getOpcode()) { @@ -14182,6 +14186,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) { case Expr::CXXScalarValueInitExprClass: case Expr::TypeTraitExprClass: case Expr::ConceptSpecializationExprClass: + case Expr::RequiresExprClass: case Expr::ArrayTypeTraitExprClass: case Expr::ExpressionTraitExprClass: case Expr::CXXNoexceptExprClass: diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 0d567edac5216..5d485e000750b 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -22,6 +22,7 @@ #include "clang/AST/DeclOpenMP.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" +#include "clang/AST/ExprConcepts.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" #include "clang/AST/TypeLoc.h" @@ -3668,6 +3669,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) { case Expr::ConvertVectorExprClass: case Expr::StmtExprClass: case Expr::TypeTraitExprClass: + case Expr::RequiresExprClass: case Expr::ArrayTypeTraitExprClass: case Expr::ExpressionTraitExprClass: case Expr::VAArgExprClass: diff --git a/clang/lib/AST/ODRHash.cpp b/clang/lib/AST/ODRHash.cpp index 27fdca1c4b9cf..1f9ff9e407dc2 100644 --- a/clang/lib/AST/ODRHash.cpp +++ b/clang/lib/AST/ODRHash.cpp @@ -857,6 +857,13 @@ class ODRTypeVisitor : public TypeVisitor { void VisitAutoType(const AutoType *T) { ID.AddInteger((unsigned)T->getKeyword()); + ID.AddInteger(T->isConstrained()); + if (T->isConstrained()) { + AddDecl(T->getTypeConstraintConcept()); + ID.AddInteger(T->getNumArgs()); + for (const auto &TA : T->getTypeConstraintArguments()) + Hash.AddTemplateArgument(TA); + } VisitDeducedType(T); } diff --git a/clang/lib/AST/Stmt.cpp b/clang/lib/AST/Stmt.cpp index b6e4d8aff21e9..7409ae7ddc9e7 100644 --- a/clang/lib/AST/Stmt.cpp +++ b/clang/lib/AST/Stmt.cpp @@ -16,6 +16,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclGroup.h" #include "clang/AST/Expr.h" +#include "clang/AST/ExprConcepts.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" #include "clang/AST/ExprOpenMP.h" diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index c14bb886bb11a..45fd8ceae8d36 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -2269,6 +2269,60 @@ void StmtPrinter::VisitConceptSpecializationExpr(ConceptSpecializationExpr *E) { Policy); } +void StmtPrinter::VisitRequiresExpr(RequiresExpr *E) { + OS << "requires "; + auto LocalParameters = E->getLocalParameters(); + if (!LocalParameters.empty()) { + OS << "("; + for (ParmVarDecl *LocalParam : LocalParameters) { + PrintRawDecl(LocalParam); + if (LocalParam != LocalParameters.back()) + OS << ", "; + } + + OS << ") "; + } + OS << "{ "; + auto Requirements = E->getRequirements(); + for (concepts::Requirement *Req : Requirements) { + if (auto *TypeReq = dyn_cast(Req)) { + if (TypeReq->isSubstitutionFailure()) + OS << "<>"; + else + TypeReq->getType()->getType().print(OS, Policy); + } else if (auto *ExprReq = dyn_cast(Req)) { + if (ExprReq->isCompound()) + OS << "{ "; + if (ExprReq->isExprSubstitutionFailure()) + OS << "<>"; + else + PrintExpr(ExprReq->getExpr()); + if (ExprReq->isCompound()) { + OS << " }"; + if (ExprReq->getNoexceptLoc().isValid()) + OS << " noexcept"; + const auto &RetReq = ExprReq->getReturnTypeRequirement(); + if (!RetReq.isEmpty()) { + OS << " -> "; + if (RetReq.isSubstitutionFailure()) + OS << "<>"; + else if (RetReq.isTypeConstraint()) + RetReq.getTypeConstraint()->print(OS, Policy); + } + } + } else { + auto *NestedReq = cast(Req); + OS << "requires "; + if (NestedReq->isSubstitutionFailure()) + OS << "<>"; + else + PrintExpr(NestedReq->getConstraintExpr()); + } + OS << "; "; + } + OS << "}"; +} + // C++ Coroutines TS void StmtPrinter::VisitCoroutineBodyStmt(CoroutineBodyStmt *S) { diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index 2aa5106e90fae..60dec50d53da4 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -1335,9 +1335,52 @@ void StmtProfiler::VisitAtomicExpr(const AtomicExpr *S) { void StmtProfiler::VisitConceptSpecializationExpr( const ConceptSpecializationExpr *S) { VisitExpr(S); - VisitDecl(S->getFoundDecl()); - VisitTemplateArguments(S->getTemplateArgsAsWritten()->getTemplateArgs(), - S->getTemplateArgsAsWritten()->NumTemplateArgs); + VisitDecl(S->getNamedConcept()); + for (const TemplateArgument &Arg : S->getTemplateArguments()) + VisitTemplateArgument(Arg); +} + +void StmtProfiler::VisitRequiresExpr(const RequiresExpr *S) { + VisitExpr(S); + ID.AddInteger(S->getLocalParameters().size()); + for (ParmVarDecl *LocalParam : S->getLocalParameters()) + VisitDecl(LocalParam); + ID.AddInteger(S->getRequirements().size()); + for (concepts::Requirement *Req : S->getRequirements()) { + if (auto *TypeReq = dyn_cast(Req)) { + ID.AddInteger(concepts::Requirement::RK_Type); + ID.AddBoolean(TypeReq->isSubstitutionFailure()); + if (!TypeReq->isSubstitutionFailure()) + VisitType(TypeReq->getType()->getType()); + } else if (auto *ExprReq = dyn_cast(Req)) { + ID.AddInteger(concepts::Requirement::RK_Compound); + ID.AddBoolean(ExprReq->isExprSubstitutionFailure()); + if (!ExprReq->isExprSubstitutionFailure()) + Visit(ExprReq->getExpr()); + // C++2a [expr.prim.req.compound]p1 Example: + // [...] The compound-requirement in C1 requires that x++ is a valid + // expression. It is equivalent to the simple-requirement x++; [...] + // We therefore do not profile isSimple() here. + ID.AddBoolean(ExprReq->getNoexceptLoc().isValid()); + const concepts::ExprRequirement::ReturnTypeRequirement &RetReq = + ExprReq->getReturnTypeRequirement(); + if (RetReq.isEmpty()) { + ID.AddInteger(0); + } else if (RetReq.isTypeConstraint()) { + ID.AddInteger(1); + Visit(RetReq.getTypeConstraint()->getImmediatelyDeclaredConstraint()); + } else { + assert(RetReq.isSubstitutionFailure()); + ID.AddInteger(2); + } + } else { + ID.AddInteger(concepts::Requirement::RK_Nested); + auto *NestedReq = cast(Req); + ID.AddBoolean(NestedReq->isSubstitutionFailure()); + if (!NestedReq->isSubstitutionFailure()) + Visit(NestedReq->getConstraintExpr()); + } + } } static Stmt::StmtClass DecodeOperatorCall(const CXXOperatorCallExpr *S, @@ -1492,8 +1535,8 @@ static Stmt::StmtClass DecodeOperatorCall(const CXXOperatorCallExpr *S, return Stmt::BinaryOperatorClass; case OO_Spaceship: - // FIXME: Update this once we support <=> expressions. - llvm_unreachable("<=> expressions not supported yet"); + BinaryOp = BO_Cmp; + return Stmt::BinaryOperatorClass; case OO_AmpAmp: BinaryOp = BO_LAnd; diff --git a/clang/lib/AST/TemplateBase.cpp b/clang/lib/AST/TemplateBase.cpp index db16c2a06b64f..6f0ebf232e77c 100644 --- a/clang/lib/AST/TemplateBase.cpp +++ b/clang/lib/AST/TemplateBase.cpp @@ -561,7 +561,7 @@ const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB, } const ASTTemplateArgumentListInfo * -ASTTemplateArgumentListInfo::Create(ASTContext &C, +ASTTemplateArgumentListInfo::Create(const ASTContext &C, const TemplateArgumentListInfo &List) { std::size_t size = totalSizeToAlloc(List.size()); void *Mem = C.Allocate(size, alignof(ASTTemplateArgumentListInfo)); diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp index 965ad17fcfa5b..c9b571862c199 100644 --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -1201,6 +1201,11 @@ void TextNodeDumper::VisitAutoType(const AutoType *T) { OS << " decltype(auto)"; if (!T->isDeduced()) OS << " undeduced"; + if (T->isConstrained()) { + dumpDeclRef(T->getTypeConstraintConcept()); + for (const auto &Arg : T->getTypeConstraintArguments()) + VisitTemplateArgument(Arg); + } } void TextNodeDumper::VisitTemplateSpecializationType( diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index c5ad711d872e0..5099494da5fd6 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -1114,7 +1114,9 @@ struct SimpleTransformVisitor : public TypeVisitor { return QualType(T, 0); return Ctx.getAutoType(deducedType, T->getKeyword(), - T->isDependentType()); + T->isDependentType(), /*IsPack=*/false, + T->getTypeConstraintConcept(), + T->getTypeConstraintArguments()); } // FIXME: Non-trivial to implement, but important for C++ @@ -4158,3 +4160,35 @@ void clang::FixedPointValueToString(SmallVectorImpl &Str, /*HasUnsignedPadding=*/false); APFixedPoint(Val, FXSema).toString(Str); } + +AutoType::AutoType(QualType DeducedAsType, AutoTypeKeyword Keyword, + bool IsDeducedAsDependent, bool IsDeducedAsPack, + ConceptDecl *TypeConstraintConcept, + ArrayRef TypeConstraintArgs) + : DeducedType(Auto, DeducedAsType, IsDeducedAsDependent, + IsDeducedAsDependent, IsDeducedAsPack) { + AutoTypeBits.Keyword = (unsigned)Keyword; + AutoTypeBits.NumArgs = TypeConstraintArgs.size(); + this->TypeConstraintConcept = TypeConstraintConcept; + if (TypeConstraintConcept) { + TemplateArgument *ArgBuffer = getArgBuffer(); + for (const TemplateArgument &Arg : TypeConstraintArgs) { + if (Arg.containsUnexpandedParameterPack()) + setContainsUnexpandedParameterPack(); + + new (ArgBuffer++) TemplateArgument(Arg); + } + } +} + +void AutoType::Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, + QualType Deduced, AutoTypeKeyword Keyword, + bool IsDependent, ConceptDecl *CD, + ArrayRef Arguments) { + ID.AddPointer(Deduced.getAsOpaquePtr()); + ID.AddInteger((unsigned)Keyword); + ID.AddBoolean(IsDependent); + ID.AddPointer(CD); + for (const TemplateArgument &Arg : Arguments) + Arg.Profile(ID, Context); +} diff --git a/clang/lib/AST/TypeLoc.cpp b/clang/lib/AST/TypeLoc.cpp index 6e67ca8e0af72..665a86f2c1432 100644 --- a/clang/lib/AST/TypeLoc.cpp +++ b/clang/lib/AST/TypeLoc.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "clang/AST/TypeLoc.h" +#include "clang/AST/DeclTemplate.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Attr.h" #include "clang/AST/Expr.h" @@ -589,3 +590,97 @@ void TemplateSpecializationTypeLoc::initializeArgLocs(ASTContext &Context, } } } + +DeclarationNameInfo AutoTypeLoc::getConceptNameInfo() const { + return DeclarationNameInfo(getNamedConcept()->getDeclName(), + getLocalData()->ConceptNameLoc); +} + +void AutoTypeLoc::initializeLocal(ASTContext &Context, SourceLocation Loc) { + setNestedNameSpecifierLoc(NestedNameSpecifierLoc()); + setTemplateKWLoc(Loc); + setConceptNameLoc(Loc); + setFoundDecl(nullptr); + setRAngleLoc(Loc); + setLAngleLoc(Loc); + TemplateSpecializationTypeLoc::initializeArgLocs(Context, getNumArgs(), + getTypePtr()->getArgs(), + getArgInfos(), Loc); + setNameLoc(Loc); +} + + +namespace { + + class GetContainedAutoTypeLocVisitor : + public TypeLocVisitor { + public: + using TypeLocVisitor::Visit; + + TypeLoc VisitAutoTypeLoc(AutoTypeLoc TL) { + return TL; + } + + // Only these types can contain the desired 'auto' type. + + TypeLoc VisitElaboratedTypeLoc(ElaboratedTypeLoc T) { + return Visit(T.getNamedTypeLoc()); + } + + TypeLoc VisitQualifiedTypeLoc(QualifiedTypeLoc T) { + return Visit(T.getUnqualifiedLoc()); + } + + TypeLoc VisitPointerTypeLoc(PointerTypeLoc T) { + return Visit(T.getPointeeLoc()); + } + + TypeLoc VisitBlockPointerTypeLoc(BlockPointerTypeLoc T) { + return Visit(T.getPointeeLoc()); + } + + TypeLoc VisitReferenceTypeLoc(ReferenceTypeLoc T) { + return Visit(T.getPointeeLoc()); + } + + TypeLoc VisitMemberPointerTypeLoc(MemberPointerTypeLoc T) { + return Visit(T.getPointeeLoc()); + } + + TypeLoc VisitArrayTypeLoc(ArrayTypeLoc T) { + return Visit(T.getElementLoc()); + } + + TypeLoc VisitFunctionTypeLoc(FunctionTypeLoc T) { + return Visit(T.getReturnLoc()); + } + + TypeLoc VisitParenTypeLoc(ParenTypeLoc T) { + return Visit(T.getInnerLoc()); + } + + TypeLoc VisitAttributedTypeLoc(AttributedTypeLoc T) { + return Visit(T.getModifiedLoc()); + } + + TypeLoc VisitMacroQualifiedTypeLoc(MacroQualifiedTypeLoc T) { + return Visit(T.getInnerLoc()); + } + + TypeLoc VisitAdjustedTypeLoc(AdjustedTypeLoc T) { + return Visit(T.getOriginalLoc()); + } + + TypeLoc VisitPackExpansionTypeLoc(PackExpansionTypeLoc T) { + return Visit(T.getPatternLoc()); + } + }; + +} // namespace + +AutoTypeLoc TypeLoc::getContainedAutoTypeLoc() const { + TypeLoc Res = GetContainedAutoTypeLocVisitor().Visit(*this); + if (Res.isNull()) + return AutoTypeLoc(); + return Res.getAs(); +} diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp index c2f4baec989ee..4a7e765a2bd82 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -1046,6 +1046,13 @@ void TypePrinter::printAutoBefore(const AutoType *T, raw_ostream &OS) { if (!T->getDeducedType().isNull()) { printBefore(T->getDeducedType(), OS); } else { + if (T->isConstrained()) { + OS << T->getTypeConstraintConcept()->getName(); + auto Args = T->getTypeConstraintArguments(); + if (!Args.empty()) + printTemplateArgumentList(OS, Args, Policy); + OS << ' '; + } switch (T->getKeyword()) { case AutoTypeKeyword::Auto: OS << "auto"; break; case AutoTypeKeyword::DecltypeAuto: OS << "decltype(auto)"; break; @@ -1234,20 +1241,18 @@ void TypePrinter::printEnumAfter(const EnumType *T, raw_ostream &OS) {} void TypePrinter::printTemplateTypeParmBefore(const TemplateTypeParmType *T, raw_ostream &OS) { - if (IdentifierInfo *Id = T->getIdentifier()) - OS << Id->getName(); - else { - bool IsLambdaAutoParam = false; - if (auto D = T->getDecl()) { - if (auto M = dyn_cast_or_null(D->getDeclContext())) - IsLambdaAutoParam = D->isImplicit() && M->getParent()->isLambda(); + TemplateTypeParmDecl *D = T->getDecl(); + if (D && D->isImplicit()) { + if (auto *TC = D->getTypeConstraint()) { + TC->print(OS, Policy); + OS << ' '; } + OS << "auto"; + } else if (IdentifierInfo *Id = T->getIdentifier()) + OS << Id->getName(); + else + OS << "type-parameter-" << T->getDepth() << '-' << T->getIndex(); - if (IsLambdaAutoParam) - OS << "auto"; - else - OS << "type-parameter-" << T->getDepth() << '-' << T->getIndex(); - } spaceBeforePlaceHolder(OS); } diff --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp index 199a6d839e2eb..ae127d7758469 100644 --- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp +++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp @@ -523,7 +523,13 @@ bool HasNameMatcher::matchesNodeFullFast(const NamedDecl &Node) const { if (Ctx->isFunctionOrMethod()) return Patterns.foundMatch(/*AllowFullyQualified=*/false); - for (; Ctx && isa(Ctx); Ctx = Ctx->getParent()) { + for (; Ctx; Ctx = Ctx->getParent()) { + // Linkage Spec can just be ignored + // FIXME: Any other DeclContext kinds that can be safely disregarded + if (isa(Ctx)) + continue; + if (!isa(Ctx)) + break; if (Patterns.foundMatch(/*AllowFullyQualified=*/false)) return true; diff --git a/clang/lib/Basic/Cuda.cpp b/clang/lib/Basic/Cuda.cpp index f2b6c8cd3ee92..e06d120c58bfc 100644 --- a/clang/lib/Basic/Cuda.cpp +++ b/clang/lib/Basic/Cuda.cpp @@ -2,6 +2,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/Twine.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/VersionTuple.h" @@ -31,8 +32,8 @@ const char *CudaVersionToString(CudaVersion V) { llvm_unreachable("invalid enum"); } -CudaVersion CudaStringToVersion(llvm::StringRef S) { - return llvm::StringSwitch(S) +CudaVersion CudaStringToVersion(const llvm::Twine &S) { + return llvm::StringSwitch(S.str()) .Case("7.0", CudaVersion::CUDA_70) .Case("7.5", CudaVersion::CUDA_75) .Case("8.0", CudaVersion::CUDA_80) @@ -40,7 +41,8 @@ CudaVersion CudaStringToVersion(llvm::StringRef S) { .Case("9.1", CudaVersion::CUDA_91) .Case("9.2", CudaVersion::CUDA_92) .Case("10.0", CudaVersion::CUDA_100) - .Case("10.1", CudaVersion::CUDA_101); + .Case("10.1", CudaVersion::CUDA_101) + .Default(CudaVersion::UNKNOWN); } const char *CudaArchToString(CudaArch A) { diff --git a/clang/lib/Basic/IdentifierTable.cpp b/clang/lib/Basic/IdentifierTable.cpp index 4aebea19924f7..ee25bd883caf6 100644 --- a/clang/lib/Basic/IdentifierTable.cpp +++ b/clang/lib/Basic/IdentifierTable.cpp @@ -142,7 +142,7 @@ static KeywordStatus getKeywordStatus(const LangOptions &LangOpts, // We treat bridge casts as objective-C keywords so we can warn on them // in non-arc mode. if (LangOpts.ObjC && (Flags & KEYOBJC)) return KS_Enabled; - if (LangOpts.ConceptsTS && (Flags & KEYCONCEPTS)) return KS_Enabled; + if (LangOpts.CPlusPlus2a && (Flags & KEYCONCEPTS)) return KS_Enabled; if (LangOpts.Coroutines && (Flags & KEYCOROUTINES)) return KS_Enabled; if (LangOpts.ModulesTS && (Flags & KEYMODULES)) return KS_Enabled; if (LangOpts.CPlusPlus && (Flags & KEYALLCXX)) return KS_Future; diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 09fd3087b494a..2d20f92fbb3d2 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -3222,6 +3222,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, Builder.CreateZExt(EmitSignBit(*this, EmitScalarExpr(E->getArg(0))), ConvertType(E->getType()))); } + case Builtin::BI__warn_memset_zero_len: + return RValue::getIgnored(); case Builtin::BI__annotation: { // Re-encode each wide string to UTF8 and make an MDString. SmallVector Strings; diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index 5aac7a8d54c77..60f1dba7c768a 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -111,6 +111,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) { case Decl::Empty: case Decl::Concept: case Decl::LifetimeExtendedTemporary: + case Decl::RequiresExprBody: // None of these decls require codegen support. return; diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index 3f23fe11e4f58..de5c3a03fb68d 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -680,6 +680,10 @@ class ScalarExprEmitter return Builder.getInt1(E->isSatisfied()); } + Value *VisitRequiresExpr(const RequiresExpr *E) { + return Builder.getInt1(E->isSatisfied()); + } + Value *VisitArrayTypeTraitExpr(const ArrayTypeTraitExpr *E) { return llvm::ConstantInt::get(Builder.getInt32Ty(), E->getValue()); } diff --git a/clang/lib/CodeGen/CodeGenAction.cpp b/clang/lib/CodeGen/CodeGenAction.cpp index 7065e78f19a20..20ebaf3578d64 100644 --- a/clang/lib/CodeGen/CodeGenAction.cpp +++ b/clang/lib/CodeGen/CodeGenAction.cpp @@ -1146,6 +1146,9 @@ void CodeGenAction::ExecuteAction() { CI.getTargetOpts(), CI.getLangOpts(), CI.getFrontendOpts().ShowTimers, std::move(LinkModules), *VMContext, nullptr); + // PR44896: Force DiscardValueNames as false. DiscardValueNames cannot be + // true here because the valued names are needed for reading textual IR. + Ctx.setDiscardValueNames(false); Ctx.setDiagnosticHandler( std::make_unique(CodeGenOpts, &Result)); diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index 2bf94f697e01c..648e6d9c214a8 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -820,13 +820,18 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, llvm::itostr(CGM.getCodeGenOpts().XRayInstructionThreshold)); } + unsigned Count, Offset; if (const auto *Attr = D->getAttr()) { - // Attr->getStart is currently ignored. - Fn->addFnAttr("patchable-function-entry", - std::to_string(Attr->getCount())); - } else if (unsigned Count = CGM.getCodeGenOpts().PatchableFunctionEntryCount) { - Fn->addFnAttr("patchable-function-entry", - std::to_string(Count)); + Count = Attr->getCount(); + Offset = Attr->getOffset(); + } else { + Count = CGM.getCodeGenOpts().PatchableFunctionEntryCount; + Offset = CGM.getCodeGenOpts().PatchableFunctionEntryOffset; + } + if (Count && Offset <= Count) { + Fn->addFnAttr("patchable-function-entry", std::to_string(Count - Offset)); + if (Offset) + Fn->addFnAttr("patchable-function-prefix", std::to_string(Offset)); } } diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 57beda26677cb..f8866ac4f7f64 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -537,6 +537,13 @@ void CodeGenModule::Release() { getModule().addModuleFlag(llvm::Module::Error, "min_enum_size", EnumWidth); } + if (Arch == llvm::Triple::riscv32 || Arch == llvm::Triple::riscv64) { + StringRef ABIStr = Target.getABI(); + llvm::LLVMContext &Ctx = TheModule.getContext(); + getModule().addModuleFlag(llvm::Module::Error, "target-abi", + llvm::MDString::get(Ctx, ABIStr)); + } + if (CodeGenOpts.SanitizeCfiCrossDso) { // Indicate that we want cross-DSO control flow integrity checks. getModule().addModuleFlag(llvm::Module::Override, "Cross-DSO CFI", 1); diff --git a/clang/lib/Driver/Compilation.cpp b/clang/lib/Driver/Compilation.cpp index ba188f5c4083c..52477576b2eb1 100644 --- a/clang/lib/Driver/Compilation.cpp +++ b/clang/lib/Driver/Compilation.cpp @@ -172,7 +172,7 @@ int Compilation::ExecuteCommand(const Command &C, } if (getDriver().CCPrintOptions) - *OS << "[Logging clang options]"; + *OS << "[Logging clang options]\n"; C.Print(*OS, "\n", /*Quote=*/getDriver().CCPrintOptions); } @@ -258,14 +258,23 @@ void Compilation::initCompilationForDiagnostics() { // Remove any user specified output. Claim any unclaimed arguments, so as // to avoid emitting warnings about unused args. - OptSpecifier OutputOpts[] = { options::OPT_o, options::OPT_MD, - options::OPT_MMD }; + OptSpecifier OutputOpts[] = { + options::OPT_o, options::OPT_MD, options::OPT_MMD, options::OPT_M, + options::OPT_MM, options::OPT_MF, options::OPT_MG, options::OPT_MJ, + options::OPT_MQ, options::OPT_MT, options::OPT_MV}; for (unsigned i = 0, e = llvm::array_lengthof(OutputOpts); i != e; ++i) { if (TranslatedArgs->hasArg(OutputOpts[i])) TranslatedArgs->eraseArg(OutputOpts[i]); } TranslatedArgs->ClaimAllArgs(); + // Force re-creation of the toolchain Args, otherwise our modifications just + // above will have no effect. + for (auto Arg : TCArgs) + if (Arg.second != TranslatedArgs) + delete Arg.second; + TCArgs.clear(); + // Redirect stdout/stderr to /dev/null. Redirects = {None, {""}, {""}}; diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index e718b8366df0e..fb8335a3695dd 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -1035,6 +1035,10 @@ Compilation *Driver::BuildCompilation(ArrayRef ArgList) { // -no-canonical-prefixes is used very early in main. Args.ClaimAllArgs(options::OPT_no_canonical_prefixes); + // f(no-)integated-cc1 is also used very early in main. + Args.ClaimAllArgs(options::OPT_fintegrated_cc1); + Args.ClaimAllArgs(options::OPT_fno_integrated_cc1); + // Ignore -pipe. Args.ClaimAllArgs(options::OPT_pipe); @@ -3753,6 +3757,11 @@ void Driver::BuildJobs(Compilation &C) const { /*TargetDeviceOffloadKind*/ Action::OFK_None); } + // If we have more than one job, then disable integrated-cc1 for now. + if (C.getJobs().size() > 1) + for (auto &J : C.getJobs()) + J.InProcess = false; + // If the user passed -Qunused-arguments or there were errors, don't warn // about any unused arguments. if (Diags.hasErrorOccurred() || diff --git a/clang/lib/Driver/Job.cpp b/clang/lib/Driver/Job.cpp index d57c3a1cdbb89..6d1e7e61ba1df 100644 --- a/clang/lib/Driver/Job.cpp +++ b/clang/lib/Driver/Job.cpp @@ -371,14 +371,29 @@ int Command::Execute(ArrayRef> Redirects, /*memoryLimit*/ 0, ErrMsg, ExecutionFailed); } +CC1Command::CC1Command(const Action &Source, const Tool &Creator, + const char *Executable, + const llvm::opt::ArgStringList &Arguments, + ArrayRef Inputs) + : Command(Source, Creator, Executable, Arguments, Inputs) { + InProcess = true; +} + void CC1Command::Print(raw_ostream &OS, const char *Terminator, bool Quote, CrashReportInfo *CrashInfo) const { - OS << " (in-process)"; + if (InProcess) + OS << " (in-process)\n"; Command::Print(OS, Terminator, Quote, CrashInfo); } -int CC1Command::Execute(ArrayRef> /*Redirects*/, +int CC1Command::Execute(ArrayRef> Redirects, std::string *ErrMsg, bool *ExecutionFailed) const { + // FIXME: Currently, if there're more than one job, we disable + // -fintegrate-cc1. If we're no longer a integrated-cc1 job, fallback to + // out-of-process execution. See discussion in https://reviews.llvm.org/D74447 + if (!InProcess) + return Command::Execute(Redirects, ErrMsg, ExecutionFailed); + PrintFileNames(); SmallVector Argv; diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp index 3ebbd30195b31..cab97b1a601a3 100644 --- a/clang/lib/Driver/ToolChain.cpp +++ b/clang/lib/Driver/ToolChain.cpp @@ -68,8 +68,7 @@ static ToolChain::RTTIMode CalculateRTTIMode(const ArgList &Args, } // -frtti is default, except for the PS4 CPU. - return (Triple.isPS4CPU() || Triple.isNVPTX()) ? ToolChain::RM_Disabled - : ToolChain::RM_Enabled; + return (Triple.isPS4CPU()) ? ToolChain::RM_Disabled : ToolChain::RM_Enabled; } ToolChain::ToolChain(const Driver &D, const llvm::Triple &T, diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 9b3055413e9e6..fa025be14e438 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -4266,8 +4266,16 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Discard value names in assert builds unless otherwise specified. if (Args.hasFlag(options::OPT_fdiscard_value_names, - options::OPT_fno_discard_value_names, !IsAssertBuild)) + options::OPT_fno_discard_value_names, !IsAssertBuild)) { + if (Args.hasArg(options::OPT_fdiscard_value_names) && + (std::any_of(Inputs.begin(), Inputs.end(), + [](const clang::driver::InputInfo &II) { + return types::isLLVMIR(II.getType()); + }))) { + D.Diag(diag::warn_ignoring_fdiscard_for_bitcode); + } CmdArgs.push_back("-discard-value-names"); + } // Set the main file name, so that debug info works even with // -save-temps. @@ -4679,6 +4687,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, : "-"); } + // Give the gen diagnostics more chances to succeed, by avoiding intentional + // crashes. + if (D.CCGenDiagnostics) + CmdArgs.push_back("-disable-pragma-debug-crash"); + bool UseSeparateSections = isUseSeparateSections(Triple); if (Args.hasFlag(options::OPT_ffunction_sections, @@ -5077,20 +5090,23 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Arg *A = Args.getLastArg(options::OPT_fpatchable_function_entry_EQ)) { StringRef S0 = A->getValue(), S = S0; - unsigned Size, Start = 0; + unsigned Size, Offset = 0; if (!Triple.isAArch64() && Triple.getArch() != llvm::Triple::x86 && Triple.getArch() != llvm::Triple::x86_64) D.Diag(diag::err_drv_unsupported_opt_for_target) << A->getAsString(Args) << TripleStr; else if (S.consumeInteger(10, Size) || (!S.empty() && (!S.consume_front(",") || - S.consumeInteger(10, Start) || !S.empty()))) + S.consumeInteger(10, Offset) || !S.empty()))) D.Diag(diag::err_drv_invalid_argument_to_option) << S0 << A->getOption().getName(); - else if (Start) + else if (Size < Offset) D.Diag(diag::err_drv_unsupported_fpatchable_function_entry_argument); - else + else { CmdArgs.push_back(Args.MakeArgString(A->getSpelling() + Twine(Size))); + CmdArgs.push_back(Args.MakeArgString( + "-fpatchable-function-entry-offset=" + Twine(Offset))); + } } if (TC.SupportsProfiling()) { @@ -6045,7 +6061,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Output.getType() == types::TY_Object && Args.hasFlag(options::OPT__SLASH_showFilenames, options::OPT__SLASH_showFilenames_, false)) { - C.getJobs().getJobs().back()->setPrintInputFilenames(true); + C.getJobs().getJobs().back()->PrintInputFilenames = true; } if (Arg *A = Args.getLastArg(options::OPT_pg)) diff --git a/clang/lib/Driver/ToolChains/Cuda.cpp b/clang/lib/Driver/ToolChains/Cuda.cpp index 02871d2ce411f..50d22a2a8ea74 100644 --- a/clang/lib/Driver/ToolChains/Cuda.cpp +++ b/clang/lib/Driver/ToolChains/Cuda.cpp @@ -32,37 +32,28 @@ using namespace llvm::opt; // Parses the contents of version.txt in an CUDA installation. It should // contain one line of the from e.g. "CUDA Version 7.5.2". -static CudaVersion ParseCudaVersionFile(llvm::StringRef V) { +void CudaInstallationDetector::ParseCudaVersionFile(llvm::StringRef V) { + Version = CudaVersion::UNKNOWN; if (!V.startswith("CUDA Version ")) - return CudaVersion::UNKNOWN; + return; V = V.substr(strlen("CUDA Version ")); - int Major = -1, Minor = -1; - auto First = V.split('.'); - auto Second = First.second.split('.'); - if (First.first.getAsInteger(10, Major) || - Second.first.getAsInteger(10, Minor)) - return CudaVersion::UNKNOWN; - - if (Major == 7 && Minor == 0) { - // This doesn't appear to ever happen -- version.txt doesn't exist in the - // CUDA 7 installs I've seen. But no harm in checking. - return CudaVersion::CUDA_70; - } - if (Major == 7 && Minor == 5) - return CudaVersion::CUDA_75; - if (Major == 8 && Minor == 0) - return CudaVersion::CUDA_80; - if (Major == 9 && Minor == 0) - return CudaVersion::CUDA_90; - if (Major == 9 && Minor == 1) - return CudaVersion::CUDA_91; - if (Major == 9 && Minor == 2) - return CudaVersion::CUDA_92; - if (Major == 10 && Minor == 0) - return CudaVersion::CUDA_100; - if (Major == 10 && Minor == 1) - return CudaVersion::CUDA_101; - return CudaVersion::UNKNOWN; + SmallVector VersionParts; + V.split(VersionParts, '.'); + if (VersionParts.size() < 2) + return; + DetectedVersion = join_items(".", VersionParts[0], VersionParts[1]); + Version = CudaStringToVersion(DetectedVersion); + if (Version != CudaVersion::UNKNOWN) + return; + + Version = CudaVersion::LATEST; + DetectedVersionIsNotSupported = true; +} + +void CudaInstallationDetector::WarnIfUnsupportedVersion() { + if (DetectedVersionIsNotSupported) + D.Diag(diag::warn_drv_unknown_cuda_version) + << DetectedVersion << CudaVersionToString(Version); } CudaInstallationDetector::CudaInstallationDetector( @@ -160,7 +151,7 @@ CudaInstallationDetector::CudaInstallationDetector( // version.txt isn't present. Version = CudaVersion::CUDA_70; } else { - Version = ParseCudaVersionFile((*VersionFile)->getBuffer()); + ParseCudaVersionFile((*VersionFile)->getBuffer()); } if (Version >= CudaVersion::CUDA_90) { @@ -578,8 +569,10 @@ CudaToolChain::CudaToolChain(const Driver &D, const llvm::Triple &Triple, const Action::OffloadKind OK) : ToolChain(D, Triple, Args), HostTC(HostTC), CudaInstallation(D, HostTC.getTriple(), Args), OK(OK) { - if (CudaInstallation.isValid()) + if (CudaInstallation.isValid()) { + CudaInstallation.WarnIfUnsupportedVersion(); getProgramPaths().push_back(CudaInstallation.getBinPath()); + } // Lookup binaries into the driver directory, this is used to // discover the clang-offload-bundler executable. getProgramPaths().push_back(getDriver().Dir); diff --git a/clang/lib/Driver/ToolChains/Cuda.h b/clang/lib/Driver/ToolChains/Cuda.h index 4ee8b6f1fea99..d1e066f93dfb5 100644 --- a/clang/lib/Driver/ToolChains/Cuda.h +++ b/clang/lib/Driver/ToolChains/Cuda.h @@ -30,6 +30,8 @@ class CudaInstallationDetector { const Driver &D; bool IsValid = false; CudaVersion Version = CudaVersion::UNKNOWN; + std::string DetectedVersion; + bool DetectedVersionIsNotSupported = false; std::string InstallPath; std::string BinPath; std::string LibPath; @@ -75,6 +77,10 @@ class CudaInstallationDetector { std::string getLibDeviceFile(StringRef Gpu) const { return LibDeviceMap.lookup(Gpu); } + void WarnIfUnsupportedVersion(); + +private: + void ParseCudaVersionFile(llvm::StringRef V); }; namespace tools { diff --git a/clang/lib/Driver/ToolChains/Darwin.cpp b/clang/lib/Driver/ToolChains/Darwin.cpp index 344a14fe1ea7c..220bc8f983512 100644 --- a/clang/lib/Driver/ToolChains/Darwin.cpp +++ b/clang/lib/Driver/ToolChains/Darwin.cpp @@ -335,7 +335,7 @@ void darwin::Linker::AddLinkArgs(Compilation &C, const ArgList &Args, Args.AddAllArgs(CmdArgs, options::OPT_init); // Add the deployment target. - if (!Version[0] || Version[0] >= 520) + if (Version[0] >= 520) MachOTC.addPlatformVersionArgs(Args, CmdArgs); else MachOTC.addMinVersionArgs(Args, CmdArgs); diff --git a/clang/lib/Driver/ToolChains/FreeBSD.cpp b/clang/lib/Driver/ToolChains/FreeBSD.cpp index c5c6f530f48c0..6fb4ddd7f5019 100644 --- a/clang/lib/Driver/ToolChains/FreeBSD.cpp +++ b/clang/lib/Driver/ToolChains/FreeBSD.cpp @@ -99,7 +99,8 @@ void freebsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, case llvm::Triple::sparcel: case llvm::Triple::sparcv9: { std::string CPU = getCPUName(Args, getToolChain().getTriple()); - CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple())); + CmdArgs.push_back( + sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple())); AddAssemblerKPIC(getToolChain(), Args, CmdArgs); break; } @@ -388,6 +389,12 @@ unsigned FreeBSD::GetDefaultDwarfVersion() const { return 4; } +void FreeBSD::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { + addSystemInclude(DriverArgs, CC1Args, + getDriver().SysRoot + "/usr/include/c++/v1"); +} + void FreeBSD::addLibStdCxxIncludePaths( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const { diff --git a/clang/lib/Driver/ToolChains/FreeBSD.h b/clang/lib/Driver/ToolChains/FreeBSD.h index 84bdbfd9a3125..7e13f48b7167a 100644 --- a/clang/lib/Driver/ToolChains/FreeBSD.h +++ b/clang/lib/Driver/ToolChains/FreeBSD.h @@ -59,16 +59,18 @@ class LLVM_LIBRARY_VISIBILITY FreeBSD : public Generic_ELF { bool IsObjCNonFragileABIDefault() const override { return true; } CXXStdlibType GetDefaultCXXStdlibType() const override; - void addLibStdCxxIncludePaths( - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; + void addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + void + addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const override; void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; - llvm::ExceptionHandling GetExceptionModel( - const llvm::opt::ArgList &Args) const override; + llvm::ExceptionHandling + GetExceptionModel(const llvm::opt::ArgList &Args) const override; bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override; bool isPIEDefault() const override; SanitizerMask getSupportedSanitizers() const override; diff --git a/clang/lib/Driver/ToolChains/HIP.cpp b/clang/lib/Driver/ToolChains/HIP.cpp index f89e648948aba..da7004cf283f2 100644 --- a/clang/lib/Driver/ToolChains/HIP.cpp +++ b/clang/lib/Driver/ToolChains/HIP.cpp @@ -105,9 +105,8 @@ const char *AMDGCN::Linker::constructLLVMLinkCommand( CmdArgs.push_back("-o"); auto OutputFileName = getOutputFileName(C, OutputFilePrefix, "-linked", "bc"); CmdArgs.push_back(OutputFileName); - SmallString<128> ExecPath(C.getDriver().Dir); - llvm::sys::path::append(ExecPath, "llvm-link"); - const char *Exec = Args.MakeArgString(ExecPath); + const char *Exec = + Args.MakeArgString(getToolChain().GetProgramPath("llvm-link")); C.addCommand(std::make_unique(JA, *this, Exec, CmdArgs, Inputs)); return OutputFileName; } @@ -133,9 +132,8 @@ const char *AMDGCN::Linker::constructOptCommand( auto OutputFileName = getOutputFileName(C, OutputFilePrefix, "-optimized", "bc"); OptArgs.push_back(OutputFileName); - SmallString<128> OptPath(C.getDriver().Dir); - llvm::sys::path::append(OptPath, "opt"); - const char *OptExec = Args.MakeArgString(OptPath); + const char *OptExec = + Args.MakeArgString(getToolChain().GetProgramPath("opt")); C.addCommand(std::make_unique(JA, *this, OptExec, OptArgs, Inputs)); return OutputFileName; } @@ -180,9 +178,7 @@ const char *AMDGCN::Linker::constructLlcCommand( auto LlcOutputFile = getOutputFileName(C, OutputFilePrefix, "", OutputIsAsm ? "s" : "o"); LlcArgs.push_back(LlcOutputFile); - SmallString<128> LlcPath(C.getDriver().Dir); - llvm::sys::path::append(LlcPath, "llc"); - const char *Llc = Args.MakeArgString(LlcPath); + const char *Llc = Args.MakeArgString(getToolChain().GetProgramPath("llc")); C.addCommand(std::make_unique(JA, *this, Llc, LlcArgs, Inputs)); return LlcOutputFile; } @@ -196,9 +192,7 @@ void AMDGCN::Linker::constructLldCommand(Compilation &C, const JobAction &JA, // The output from ld.lld is an HSA code object file. ArgStringList LldArgs{ "-flavor", "gnu", "-shared", "-o", Output.getFilename(), InputFileName}; - SmallString<128> LldPath(C.getDriver().Dir); - llvm::sys::path::append(LldPath, "lld"); - const char *Lld = Args.MakeArgString(LldPath); + const char *Lld = Args.MakeArgString(getToolChain().GetProgramPath("lld")); C.addCommand(std::make_unique(JA, *this, Lld, LldArgs, Inputs)); } @@ -230,9 +224,8 @@ void AMDGCN::constructHIPFatbinCommand(Compilation &C, const JobAction &JA, Args.MakeArgString(std::string("-outputs=").append(OutputFileName)); BundlerArgs.push_back(BundlerOutputArg); - SmallString<128> BundlerPath(C.getDriver().Dir); - llvm::sys::path::append(BundlerPath, "clang-offload-bundler"); - const char *Bundler = Args.MakeArgString(BundlerPath); + const char *Bundler = Args.MakeArgString( + T.getToolChain().GetProgramPath("clang-offload-bundler")); C.addCommand(std::make_unique(JA, T, Bundler, BundlerArgs, Inputs)); } diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index d5d394e61926a..70bcd7048c559 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -2596,7 +2596,7 @@ bool TokenAnnotator::spaceRequiredBeforeParens(const FormatToken &Right) const { /// otherwise. static bool isKeywordWithCondition(const FormatToken &Tok) { return Tok.isOneOf(tok::kw_if, tok::kw_for, tok::kw_while, tok::kw_switch, - tok::kw_constexpr); + tok::kw_constexpr, tok::kw_catch); } bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, @@ -2707,10 +2707,17 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, return false; if (Right.isOneOf(tok::star, tok::amp, tok::ampamp) && (Left.is(tok::identifier) || Left.isSimpleTypeSpecifier()) && - Left.Previous && Left.Previous->is(tok::kw_operator)) - // Space between the type and the * - // operator void*(), operator char*(), operator Foo*() dependant - // on PointerAlignment style. + // Space between the type and the * in: + // operator void*() + // operator char*() + // operator /*comment*/ const char*() + // operator volatile /*comment*/ char*() + // operator Foo*() + // dependent on PointerAlignment style. + Left.Previous && + (Left.Previous->endsSequence(tok::kw_operator) || + Left.Previous->endsSequence(tok::kw_const, tok::kw_operator) || + Left.Previous->endsSequence(tok::kw_volatile, tok::kw_operator))) return (Style.PointerAlignment != FormatStyle::PAS_Left); const auto SpaceRequiredForArrayInitializerLSquare = [](const FormatToken &LSquareTok, const FormatStyle &Style) { diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index e1e59565083b7..e98a407ac42f9 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -1103,6 +1103,8 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.PatchableFunctionEntryCount = getLastArgIntValue(Args, OPT_fpatchable_function_entry_EQ, 0, Diags); + Opts.PatchableFunctionEntryOffset = getLastArgIntValue( + Args, OPT_fpatchable_function_entry_offset_EQ, 0, Diags); Opts.InstrumentForProfiling = Args.hasArg(OPT_pg); Opts.CallFEntry = Args.hasArg(OPT_mfentry); Opts.MNopMCount = Args.hasArg(OPT_mnop_mcount); @@ -2852,7 +2854,10 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, << A->getValue(); Opts.NewAlignOverride = 0; } - Opts.ConceptsTS = Args.hasArg(OPT_fconcepts_ts); + Opts.ConceptSatisfactionCaching = + !Args.hasArg(OPT_fno_concept_satisfaction_caching); + if (Args.hasArg(OPT_fconcepts_ts)) + Diags.Report(diag::warn_fe_concepts_ts_flag); Opts.HeinousExtensions = Args.hasArg(OPT_fheinous_gnu_extensions); Opts.AccessControl = !Args.hasArg(OPT_fno_access_control); Opts.ElideConstructors = !Args.hasArg(OPT_fno_elide_constructors); @@ -3435,6 +3440,7 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, Opts.LexEditorPlaceholders = false; Opts.SetUpStaticAnalyzer = Args.hasArg(OPT_setup_static_analyzer); + Opts.DisablePragmaDebugCrash = Args.hasArg(OPT_disable_pragma_debug_crash); } static void ParsePreprocessorOutputArgs(PreprocessorOutputOptions &Opts, diff --git a/clang/lib/Frontend/FrontendActions.cpp b/clang/lib/Frontend/FrontendActions.cpp index 8574d0a7e8132..935c64a0fa13f 100644 --- a/clang/lib/Frontend/FrontendActions.cpp +++ b/clang/lib/Frontend/FrontendActions.cpp @@ -429,6 +429,10 @@ class DefaultTemplateInstCallback : public TemplateInstantiationCallback { return "ConstraintNormalization"; case CodeSynthesisContext::ParameterMappingSubstitution: return "ParameterMappingSubstitution"; + case CodeSynthesisContext::RequirementInstantiation: + return "RequirementInstantiation"; + case CodeSynthesisContext::NestedRequirementConstraintsCheck: + return "NestedRequirementConstraintsCheck"; } return ""; } diff --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp index 2c7e3a56c0436..c273cb96d9b91 100644 --- a/clang/lib/Frontend/InitPreprocessor.cpp +++ b/clang/lib/Frontend/InitPreprocessor.cpp @@ -344,13 +344,27 @@ static void InitializeStandardPredefinedMacros(const TargetInfo &TI, const LangOptions &LangOpts, const FrontendOptions &FEOpts, MacroBuilder &Builder) { + // C++ [cpp.predefined]p1: + // The following macro names shall be defined by the implementation: + + // -- __STDC__ + // [C++] Whether __STDC__ is predefined and if so, what its value is, + // are implementation-defined. + // (Removed in C++20.) if (!LangOpts.MSVCCompat && !LangOpts.TraditionalCPP) Builder.defineMacro("__STDC__"); + // -- __STDC_HOSTED__ + // The integer literal 1 if the implementation is a hosted + // implementation or the integer literal 0 if it is not. if (LangOpts.Freestanding) Builder.defineMacro("__STDC_HOSTED__", "0"); else Builder.defineMacro("__STDC_HOSTED__"); + // -- __STDC_VERSION__ + // [C++] Whether __STDC_VERSION__ is predefined and if so, what its + // value is, are implementation-defined. + // (Removed in C++20.) if (!LangOpts.CPlusPlus) { if (LangOpts.C17) Builder.defineMacro("__STDC_VERSION__", "201710L"); @@ -361,33 +375,29 @@ static void InitializeStandardPredefinedMacros(const TargetInfo &TI, else if (!LangOpts.GNUMode && LangOpts.Digraphs) Builder.defineMacro("__STDC_VERSION__", "199409L"); } else { - // FIXME: Use correct value for C++20. + // -- __cplusplus + // [C++20] The integer literal 202002L. if (LangOpts.CPlusPlus2a) - Builder.defineMacro("__cplusplus", "201707L"); - // C++17 [cpp.predefined]p1: - // The name __cplusplus is defined to the value 201703L when compiling a - // C++ translation unit. + Builder.defineMacro("__cplusplus", "202002L"); + // [C++17] The integer literal 201703L. else if (LangOpts.CPlusPlus17) Builder.defineMacro("__cplusplus", "201703L"); - // C++1y [cpp.predefined]p1: - // The name __cplusplus is defined to the value 201402L when compiling a - // C++ translation unit. + // [C++14] The name __cplusplus is defined to the value 201402L when + // compiling a C++ translation unit. else if (LangOpts.CPlusPlus14) Builder.defineMacro("__cplusplus", "201402L"); - // C++11 [cpp.predefined]p1: - // The name __cplusplus is defined to the value 201103L when compiling a - // C++ translation unit. + // [C++11] The name __cplusplus is defined to the value 201103L when + // compiling a C++ translation unit. else if (LangOpts.CPlusPlus11) Builder.defineMacro("__cplusplus", "201103L"); - // C++03 [cpp.predefined]p1: - // The name __cplusplus is defined to the value 199711L when compiling a - // C++ translation unit. + // [C++03] The name __cplusplus is defined to the value 199711L when + // compiling a C++ translation unit. else Builder.defineMacro("__cplusplus", "199711L"); - // C++1z [cpp.predefined]p1: - // An integer literal of type std::size_t whose value is the alignment - // guaranteed by a call to operator new(std::size_t) + // -- __STDCPP_DEFAULT_NEW_ALIGNMENT__ + // [C++17] An integer literal of type std::size_t whose value is the + // alignment guaranteed by a call to operator new(std::size_t) // // We provide this in all language modes, since it seems generally useful. Builder.defineMacro("__STDCPP_DEFAULT_NEW_ALIGNMENT__", @@ -548,7 +558,7 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts, // C++20 features. if (LangOpts.CPlusPlus2a) { //Builder.defineMacro("__cpp_aggregate_paren_init", "201902L"); - //Builder.defineMacro("__cpp_concepts", "201907L"); + Builder.defineMacro("__cpp_concepts", "201907L"); Builder.defineMacro("__cpp_conditional_explicit", "201806L"); //Builder.defineMacro("__cpp_consteval", "201811L"); Builder.defineMacro("__cpp_constexpr_dynamic_alloc", "201907L"); @@ -564,8 +574,6 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts, Builder.defineMacro("__cpp_impl_destroying_delete", "201806L"); // TS features. - if (LangOpts.ConceptsTS) - Builder.defineMacro("__cpp_experimental_concepts", "1L"); if (LangOpts.Coroutines) Builder.defineMacro("__cpp_coroutines", "201703L"); } diff --git a/clang/lib/Headers/__clang_cuda_intrinsics.h b/clang/lib/Headers/__clang_cuda_intrinsics.h index b67461a146fc6..c7bff6a9d8fe6 100644 --- a/clang/lib/Headers/__clang_cuda_intrinsics.h +++ b/clang/lib/Headers/__clang_cuda_intrinsics.h @@ -45,7 +45,7 @@ _Static_assert(sizeof(__val) == sizeof(__Bits)); \ _Static_assert(sizeof(__Bits) == 2 * sizeof(int)); \ __Bits __tmp; \ - memcpy(&__val, &__tmp, sizeof(__val)); \ + memcpy(&__tmp, &__val, sizeof(__val)); \ __tmp.__a = ::__FnName(__tmp.__a, __offset, __width); \ __tmp.__b = ::__FnName(__tmp.__b, __offset, __width); \ long long __ret; \ @@ -129,7 +129,7 @@ __MAKE_SHUFFLES(__shfl_xor, __nvvm_shfl_bfly_i32, __nvvm_shfl_bfly_f32, 0x1f, _Static_assert(sizeof(__val) == sizeof(__Bits)); \ _Static_assert(sizeof(__Bits) == 2 * sizeof(int)); \ __Bits __tmp; \ - memcpy(&__val, &__tmp, sizeof(__val)); \ + memcpy(&__tmp, &__val, sizeof(__val)); \ __tmp.__a = ::__FnName(__mask, __tmp.__a, __offset, __width); \ __tmp.__b = ::__FnName(__mask, __tmp.__b, __offset, __width); \ long long __ret; \ diff --git a/clang/lib/Headers/__clang_cuda_runtime_wrapper.h b/clang/lib/Headers/__clang_cuda_runtime_wrapper.h index 3e362dd967db6..e91de3c81dbdc 100644 --- a/clang/lib/Headers/__clang_cuda_runtime_wrapper.h +++ b/clang/lib/Headers/__clang_cuda_runtime_wrapper.h @@ -48,7 +48,7 @@ #include "cuda.h" #if !defined(CUDA_VERSION) #error "cuda.h did not define CUDA_VERSION" -#elif CUDA_VERSION < 7000 || CUDA_VERSION > 10010 +#elif CUDA_VERSION < 7000 #error "Unsupported CUDA version!" #endif diff --git a/clang/lib/Headers/ppc_wrappers/emmintrin.h b/clang/lib/Headers/ppc_wrappers/emmintrin.h index 293276cc9be05..4dcb8485e2e9b 100644 --- a/clang/lib/Headers/ppc_wrappers/emmintrin.h +++ b/clang/lib/Headers/ppc_wrappers/emmintrin.h @@ -1749,7 +1749,7 @@ _mm_sll_epi64 (__m128i __A, __m128i __B) lshift = vec_splat ((__v2du) __B, 0); shmask = vec_cmplt (lshift, shmax); result = vec_sl ((__v2du) __A, lshift); - result = vec_sel ((__v2du) shmask, result, shmask); + result = (__v2du)vec_sel ((__v2df) shmask, (__v2df)result, shmask); return (__m128i) result; } @@ -1843,7 +1843,7 @@ _mm_srl_epi64 (__m128i __A, __m128i __B) rshift = vec_splat ((__v2du) __B, 0); shmask = vec_cmplt (rshift, shmax); result = vec_sr ((__v2du) __A, rshift); - result = vec_sel ((__v2du) shmask, result, shmask); + result = (__v2du)vec_sel ((__v2df) shmask, (__v2df)result, shmask); return (__m128i) result; } diff --git a/clang/lib/Headers/xmmintrin.h b/clang/lib/Headers/xmmintrin.h index 0e61eab44aeb1..9b8de63f04d5b 100644 --- a/clang/lib/Headers/xmmintrin.h +++ b/clang/lib/Headers/xmmintrin.h @@ -2181,7 +2181,7 @@ void _mm_sfence(void); /// 3: Bits [63:48] are copied to the destination. /// \returns A 16-bit integer containing the extracted 16 bits of packed data. #define _mm_extract_pi16(a, n) \ - (int)__builtin_ia32_vec_ext_v4hi((__m64)a, (int)n) + (int)__builtin_ia32_vec_ext_v4hi((__v4hi)a, (int)n) /// Copies data from the 64-bit vector of [4 x i16] to the destination, /// and inserts the lower 16-bits of an integer operand at the 16-bit offset @@ -2212,7 +2212,7 @@ void _mm_sfence(void); /// \returns A 64-bit integer vector containing the copied packed data from the /// operands. #define _mm_insert_pi16(a, d, n) \ - (__m64)__builtin_ia32_vec_set_v4hi((__m64)a, (int)d, (int)n) + (__m64)__builtin_ia32_vec_set_v4hi((__v4hi)a, (int)d, (int)n) /// Compares each of the corresponding packed 16-bit integer values of /// the 64-bit integer vectors, and writes the greater value to the diff --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp index 648bda2705780..981111d037448 100644 --- a/clang/lib/Lex/Lexer.cpp +++ b/clang/lib/Lex/Lexer.cpp @@ -2552,8 +2552,8 @@ bool Lexer::SkipBlockComment(Token &Result, const char *CurPtr, '/', '/', '/', '/', '/', '/', '/', '/', '/', '/', '/', '/', '/', '/', '/', '/' }; - while (CurPtr+16 <= BufferEnd && - !vec_any_eq(*(const vector unsigned char*)CurPtr, Slashes)) + while (CurPtr + 16 <= BufferEnd && + !vec_any_eq(*(const __vector unsigned char *)CurPtr, Slashes)) CurPtr += 16; #else // Scan for '/' quickly. Many block comments are very large. diff --git a/clang/lib/Lex/Pragma.cpp b/clang/lib/Lex/Pragma.cpp index e4636265a72bb..57a95815488eb 100644 --- a/clang/lib/Lex/Pragma.cpp +++ b/clang/lib/Lex/Pragma.cpp @@ -30,6 +30,7 @@ #include "clang/Lex/PPCallbacks.h" #include "clang/Lex/Preprocessor.h" #include "clang/Lex/PreprocessorLexer.h" +#include "clang/Lex/PreprocessorOptions.h" #include "clang/Lex/Token.h" #include "clang/Lex/TokenLexer.h" #include "llvm/ADT/ArrayRef.h" @@ -39,9 +40,9 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/StringRef.h" -#include "llvm/Support/CrashRecoveryContext.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Timer.h" #include #include #include @@ -1035,15 +1036,21 @@ struct PragmaDebugHandler : public PragmaHandler { IdentifierInfo *II = Tok.getIdentifierInfo(); if (II->isStr("assert")) { - llvm_unreachable("This is an assertion!"); + if (!PP.getPreprocessorOpts().DisablePragmaDebugCrash) + llvm_unreachable("This is an assertion!"); } else if (II->isStr("crash")) { - LLVM_BUILTIN_TRAP; + llvm::Timer T("crash", "pragma crash"); + llvm::TimeRegion R(&T); + if (!PP.getPreprocessorOpts().DisablePragmaDebugCrash) + LLVM_BUILTIN_TRAP; } else if (II->isStr("parser_crash")) { - Token Crasher; - Crasher.startToken(); - Crasher.setKind(tok::annot_pragma_parser_crash); - Crasher.setAnnotationRange(SourceRange(Tok.getLocation())); - PP.EnterToken(Crasher, /*IsReinject*/false); + if (!PP.getPreprocessorOpts().DisablePragmaDebugCrash) { + Token Crasher; + Crasher.startToken(); + Crasher.setKind(tok::annot_pragma_parser_crash); + Crasher.setAnnotationRange(SourceRange(Tok.getLocation())); + PP.EnterToken(Crasher, /*IsReinject*/ false); + } } else if (II->isStr("dump")) { Token Identifier; PP.LexUnexpandedToken(Identifier); @@ -1075,9 +1082,11 @@ struct PragmaDebugHandler : public PragmaHandler { << II->getName(); } } else if (II->isStr("llvm_fatal_error")) { - llvm::report_fatal_error("#pragma clang __debug llvm_fatal_error"); + if (!PP.getPreprocessorOpts().DisablePragmaDebugCrash) + llvm::report_fatal_error("#pragma clang __debug llvm_fatal_error"); } else if (II->isStr("llvm_unreachable")) { - llvm_unreachable("#pragma clang __debug llvm_unreachable"); + if (!PP.getPreprocessorOpts().DisablePragmaDebugCrash) + llvm_unreachable("#pragma clang __debug llvm_unreachable"); } else if (II->isStr("macro")) { Token MacroName; PP.LexUnexpandedToken(MacroName); @@ -1104,11 +1113,8 @@ struct PragmaDebugHandler : public PragmaHandler { } M->dump(); } else if (II->isStr("overflow_stack")) { - DebugOverflowStack(); - } else if (II->isStr("handle_crash")) { - llvm::CrashRecoveryContext *CRC =llvm::CrashRecoveryContext::GetCurrent(); - if (CRC) - CRC->HandleCrash(); + if (!PP.getPreprocessorOpts().DisablePragmaDebugCrash) + DebugOverflowStack(); } else if (II->isStr("captured")) { HandleCaptured(PP); } else { diff --git a/clang/lib/Parse/ParseCXXInlineMethods.cpp b/clang/lib/Parse/ParseCXXInlineMethods.cpp index f8b5fec438007..a75965784168c 100644 --- a/clang/lib/Parse/ParseCXXInlineMethods.cpp +++ b/clang/lib/Parse/ParseCXXInlineMethods.cpp @@ -133,7 +133,9 @@ NamedDecl *Parser::ParseCXXInlineMethodDef( LexedMethod* LM = new LexedMethod(this, FnD); getCurrentClass().LateParsedDeclarations.push_back(LM); - LM->TemplateScope = getCurScope()->isTemplateParamScope(); + LM->TemplateScope = getCurScope()->isTemplateParamScope() || + (FnD && isa(FnD) && + cast(FnD)->isAbbreviated()); CachedTokens &Toks = LM->Toks; tok::TokenKind kind = Tok.getKind(); diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 69a3ed9cbad77..6353e14bc41a9 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -2962,6 +2962,7 @@ Parser::DiagnoseMissingSemiAfterTagDefinition(DeclSpec &DS, AccessSpecifier AS, case Sema::NC_ContextIndependentExpr: case Sema::NC_VarTemplate: case Sema::NC_FunctionTemplate: + case Sema::NC_Concept: // Might be a redeclaration of a prior entity. break; } @@ -3177,7 +3178,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, DSContext == DeclSpecContext::DSC_class) && TemplateId->Name && Actions.isCurrentClassName(*TemplateId->Name, getCurScope(), &SS) && - isConstructorDeclarator(/*Unqualified*/ false)) { + isConstructorDeclarator(/*Unqualified=*/false)) { // The user meant this to be an out-of-line constructor // definition, but template arguments are not allowed // there. Just allow this as a constructor; we'll @@ -3189,7 +3190,19 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, ConsumeAnnotationToken(); // The C++ scope. assert(Tok.is(tok::annot_template_id) && "ParseOptionalCXXScopeSpecifier not working"); - AnnotateTemplateIdTokenAsType(); + AnnotateTemplateIdTokenAsType(SS); + continue; + } + + if (Next.is(tok::annot_template_id) && + static_cast(Next.getAnnotationValue()) + ->Kind == TNK_Concept_template && + GetLookAheadToken(2).isOneOf(tok::kw_auto, tok::kw_decltype)) { + DS.getTypeSpecScope() = SS; + // This is a qualified placeholder-specifier, e.g., ::C auto ... + // Consume the scope annotation and continue to consume the template-id + // as a placeholder-specifier. + ConsumeAnnotationToken(); continue; } @@ -3235,6 +3248,13 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // C++ doesn't have implicit int. Diagnose it as a typo w.r.t. to the // typename. if (!TypeRep) { + if (TryAnnotateTypeConstraint()) + goto DoneWithDeclSpec; + if (isTypeConstraintAnnotation()) + continue; + if (NextToken().is(tok::annot_template_id)) + // Might have been annotated by TryAnnotateTypeConstraint. + continue; // Eat the scope spec so the identifier is current. ConsumeAnnotationToken(); ParsedAttributesWithRange Attrs(AttrFactory); @@ -3384,6 +3404,13 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // If this is not a typedef name, don't parse it as part of the declspec, // it must be an implicit int or an error. if (!TypeRep) { + if (TryAnnotateTypeConstraint()) + goto DoneWithDeclSpec; + if (isTypeConstraintAnnotation()) + continue; + if (Tok.is(tok::annot_template_id)) + // Might have been annotated by TryAnnotateTypeConstraint. + continue; ParsedAttributesWithRange Attrs(AttrFactory); if (ParseImplicitInt(DS, nullptr, TemplateInfo, AS, DSContext, Attrs)) { if (!Attrs.empty()) { @@ -3433,9 +3460,51 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, continue; } - // type-name + // type-name or placeholder-specifier case tok::annot_template_id: { TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); + if (TemplateId->Kind == TNK_Concept_template) { + if (NextToken().is(tok::identifier)) { + Diag(Loc, diag::err_placeholder_expected_auto_or_decltype_auto) + << FixItHint::CreateInsertion(NextToken().getLocation(), "auto"); + // Attempt to continue as if 'auto' was placed here. + isInvalid = DS.SetTypeSpecType(TST_auto, Loc, PrevSpec, DiagID, + TemplateId, Policy); + break; + } + if (!NextToken().isOneOf(tok::kw_auto, tok::kw_decltype)) + goto DoneWithDeclSpec; + ConsumeAnnotationToken(); + SourceLocation AutoLoc = Tok.getLocation(); + if (TryConsumeToken(tok::kw_decltype)) { + BalancedDelimiterTracker Tracker(*this, tok::l_paren); + if (Tracker.consumeOpen()) { + // Something like `void foo(Iterator decltype i)` + Diag(Tok, diag::err_expected) << tok::l_paren; + } else { + if (!TryConsumeToken(tok::kw_auto)) { + // Something like `void foo(Iterator decltype(int) i)` + Tracker.skipToEnd(); + Diag(Tok, diag::err_placeholder_expected_auto_or_decltype_auto) + << FixItHint::CreateReplacement(SourceRange(AutoLoc, + Tok.getLocation()), + "auto"); + } else { + Tracker.consumeClose(); + } + } + ConsumedEnd = Tok.getLocation(); + // Even if something went wrong above, continue as if we've seen + // `decltype(auto)`. + isInvalid = DS.SetTypeSpecType(TST_decltype_auto, Loc, PrevSpec, + DiagID, TemplateId, Policy); + } else { + isInvalid = DS.SetTypeSpecType(TST_auto, Loc, PrevSpec, DiagID, + TemplateId, Policy); + } + break; + } + if (TemplateId->Kind != TNK_Type_template && TemplateId->Kind != TNK_Undeclared_template) { // This template-id does not refer to a type name, so we're @@ -3448,12 +3517,13 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // constructor declaration. if (getLangOpts().CPlusPlus && DSContext == DeclSpecContext::DSC_class && Actions.isCurrentClassName(*TemplateId->Name, getCurScope()) && - isConstructorDeclarator(TemplateId->SS.isEmpty())) + isConstructorDeclarator(/*Unqualified=*/true)) goto DoneWithDeclSpec; // Turn the template-id annotation token into a type annotation // token, then try again to parse it as a type-specifier. - AnnotateTemplateIdTokenAsType(); + CXXScopeSpec SS; + AnnotateTemplateIdTokenAsType(SS); continue; } @@ -3617,7 +3687,11 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, ConsumedEnd = ExplicitLoc; ConsumeToken(); // kw_explicit if (Tok.is(tok::l_paren)) { - if (getLangOpts().CPlusPlus2a) { + if (getLangOpts().CPlusPlus2a || isExplicitBool() == TPResult::True) { + Diag(Tok.getLocation(), getLangOpts().CPlusPlus2a + ? diag::warn_cxx17_compat_explicit_bool + : diag::ext_explicit_bool); + ExprResult ExplicitExpr(static_cast(nullptr)); BalancedDelimiterTracker Tracker(*this, tok::l_paren); Tracker.consumeOpen(); @@ -3630,8 +3704,9 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, Actions.ActOnExplicitBoolSpecifier(ExplicitExpr.get()); } else Tracker.skipToEnd(); - } else + } else { Diag(Tok.getLocation(), diag::warn_cxx2a_compat_explicit_bool); + } } isInvalid = DS.setFunctionSpecExplicit(ExplicitLoc, PrevSpec, DiagID, ExplicitSpec, CloseParenLoc); @@ -4991,6 +5066,8 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { // recurse to handle whatever we get. if (TryAnnotateTypeOrScopeToken()) return true; + if (TryAnnotateTypeConstraint()) + return true; if (Tok.is(tok::identifier)) return false; @@ -5123,11 +5200,14 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { // placeholder-type-specifier case tok::annot_template_id: { - TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); - return TemplateId->Kind == TNK_Concept_template && + return isTypeConstraintAnnotation() && (NextToken().is(tok::kw_auto) || NextToken().is(tok::kw_decltype)); } - + case tok::annot_cxxscope: + if (NextToken().is(tok::identifier) && TryAnnotateTypeConstraint()) + return true; + return isTypeConstraintAnnotation() && + GetLookAheadToken(2).isOneOf(tok::kw_auto, tok::kw_decltype); case tok::kw___declspec: case tok::kw___cdecl: case tok::kw___stdcall: @@ -6021,11 +6101,12 @@ void Parser::ParseDirectDeclarator(Declarator &D) { while (1) { if (Tok.is(tok::l_paren)) { + bool IsFunctionDeclaration = D.isFunctionDeclaratorAFunctionDeclaration(); // Enter function-declaration scope, limiting any declarators to the // function prototype scope, including parameter declarators. ParseScope PrototypeScope(this, Scope::FunctionPrototypeScope|Scope::DeclScope| - (D.isFunctionDeclaratorAFunctionDeclaration() + (IsFunctionDeclaration ? Scope::FunctionDeclarationScope : 0)); // The paren may be part of a C++ direct initializer, eg. "int x(1);". @@ -6044,7 +6125,12 @@ void Parser::ParseDirectDeclarator(Declarator &D) { ParsedAttributes attrs(AttrFactory); BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); + if (IsFunctionDeclaration) + Actions.ActOnStartFunctionDeclarationDeclarator(D, + TemplateParameterDepth); ParseFunctionDeclarator(D, attrs, T, IsAmbiguous); + if (IsFunctionDeclaration) + Actions.ActOnFinishFunctionDeclarationDeclarator(D); PrototypeScope.Exit(); } else if (Tok.is(tok::l_square)) { ParseBracketDeclarator(D); @@ -6360,7 +6446,7 @@ void Parser::ParseFunctionDeclarator(Declarator &D, ProhibitAttributes(FnAttrs); } else { if (Tok.isNot(tok::r_paren)) - ParseParameterDeclarationClause(D, FirstArgAttrs, ParamInfo, + ParseParameterDeclarationClause(D.getContext(), FirstArgAttrs, ParamInfo, EllipsisLoc); else if (RequiresArg) Diag(Tok, diag::err_argument_required_after_attribute); @@ -6578,9 +6664,9 @@ void Parser::ParseFunctionDeclaratorIdentifierList( /// after the opening parenthesis. This function will not parse a K&R-style /// identifier list. /// -/// D is the declarator being parsed. If FirstArgAttrs is non-null, then the -/// caller parsed those arguments immediately after the open paren - they should -/// be considered to be part of the first parameter. +/// DeclContext is the context of the declarator being parsed. If FirstArgAttrs +/// is non-null, then the caller parsed those attributes immediately after the +/// open paren - they should be considered to be part of the first parameter. /// /// After returning, ParamInfo will hold the parsed parameters. EllipsisLoc will /// be the location of the ellipsis, if any was parsed. @@ -6606,7 +6692,7 @@ void Parser::ParseFunctionDeclaratorIdentifierList( /// [C++11] attribute-specifier-seq parameter-declaration /// void Parser::ParseParameterDeclarationClause( - Declarator &D, + DeclaratorContext DeclaratorCtx, ParsedAttributes &FirstArgAttrs, SmallVectorImpl &ParamInfo, SourceLocation &EllipsisLoc) { @@ -6655,9 +6741,11 @@ void Parser::ParseParameterDeclarationClause( // "LambdaExprParameterContext", because we must accept either // 'declarator' or 'abstract-declarator' here. Declarator ParmDeclarator( - DS, D.getContext() == DeclaratorContext::LambdaExprContext - ? DeclaratorContext::LambdaExprParameterContext - : DeclaratorContext::PrototypeContext); + DS, DeclaratorCtx == DeclaratorContext::RequiresExprContext + ? DeclaratorContext::RequiresExprContext + : DeclaratorCtx == DeclaratorContext::LambdaExprContext + ? DeclaratorContext::LambdaExprParameterContext + : DeclaratorContext::PrototypeContext); ParseDeclarator(ParmDeclarator); // Parse GNU attributes, if present. @@ -6711,7 +6799,7 @@ void Parser::ParseParameterDeclarationClause( SourceLocation EqualLoc = Tok.getLocation(); // Parse the default argument - if (D.getContext() == DeclaratorContext::MemberContext) { + if (DeclaratorCtx == DeclaratorContext::MemberContext) { // If we're inside a class definition, cache the tokens // corresponding to the default argument. We'll actually parse // them when we see the end of the class definition. diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 081d4d8b12092..09e5c7996fcd5 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -1142,7 +1142,7 @@ TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc, if (TemplateId->Kind == TNK_Type_template || TemplateId->Kind == TNK_Dependent_template_name || TemplateId->Kind == TNK_Undeclared_template) { - AnnotateTemplateIdTokenAsType(/*IsClassName*/true); + AnnotateTemplateIdTokenAsType(SS, /*IsClassName*/true); assert(Tok.is(tok::annot_typename) && "template-id -> type failed"); ParsedType Type = getTypeAnnotation(Tok); @@ -1193,7 +1193,7 @@ TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc, TemplateName)) return true; if (TNK == TNK_Type_template || TNK == TNK_Dependent_template_name) - AnnotateTemplateIdTokenAsType(/*IsClassName*/true); + AnnotateTemplateIdTokenAsType(SS, /*IsClassName*/true); // If we didn't end up with a typename token, there's nothing more we // can do. @@ -1826,7 +1826,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, TemplateInfo.Kind == ParsedTemplateInfo::NonTemplate)) { ProhibitAttributes(attrs); TypeResult = Actions.ActOnTagTemplateIdType(TUK, TagType, StartLoc, - TemplateId->SS, + SS, TemplateId->TemplateKWLoc, TemplateId->Template, TemplateId->TemplateNameLoc, @@ -1876,7 +1876,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // Build the class template specialization. TagOrTempResult = Actions.ActOnClassTemplateSpecialization( getCurScope(), TagType, TUK, StartLoc, DS.getModulePrivateSpecLoc(), - *TemplateId, attrs, + SS, *TemplateId, attrs, MultiTemplateParamsArg(TemplateParams ? &(*TemplateParams)[0] : nullptr, TemplateParams ? TemplateParams->size() : 0), @@ -2642,6 +2642,8 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, } ParsingDeclarator DeclaratorInfo(*this, DS, DeclaratorContext::MemberContext); + if (TemplateInfo.TemplateParams) + DeclaratorInfo.setTemplateParameterLists(TemplateParams); VirtSpecifiers VS; // Hold late-parsed attributes so we can attach a Decl to them later. @@ -2714,7 +2716,7 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // C++11 [dcl.attr.grammar] p4: If an attribute-specifier-seq appertains // to a friend declaration, that declaration shall be a definition. if (DeclaratorInfo.isFunctionDeclarator() && - DefinitionKind != FDK_Definition && DS.isFriendSpecified()) { + DefinitionKind == FDK_Declaration && DS.isFriendSpecified()) { // Diagnose attributes that appear before decl specifier: // [[]] friend int foo(); ProhibitAttributes(FnAttrs); @@ -3520,7 +3522,7 @@ MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) { if (TemplateId && (TemplateId->Kind == TNK_Type_template || TemplateId->Kind == TNK_Dependent_template_name || TemplateId->Kind == TNK_Undeclared_template)) { - AnnotateTemplateIdTokenAsType(/*IsClassName*/true); + AnnotateTemplateIdTokenAsType(SS, /*IsClassName*/true); assert(Tok.is(tok::annot_typename) && "template-id -> type failed"); TemplateTypeTy = getTypeAnnotation(Tok); ConsumeAnnotationToken(); diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index 1442df046bb93..ad9627a2425c2 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -234,7 +234,7 @@ ExprResult Parser::ParseCaseExpression(SourceLocation CaseLoc) { /// \endverbatim ExprResult Parser::ParseConstraintExpression() { EnterExpressionEvaluationContext ConstantEvaluated( - Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated); + Actions, Sema::ExpressionEvaluationContext::Unevaluated); ExprResult LHS(ParseCastExpression(AnyCastExpr)); ExprResult Res(ParseRHSOfBinaryExpression(LHS, prec::LogicalOr)); if (Res.isUsable() && !Actions.CheckConstraintExpression(Res.get())) { @@ -256,7 +256,7 @@ ExprResult Parser::ParseConstraintExpression() { ExprResult Parser::ParseConstraintLogicalAndExpression(bool IsTrailingRequiresClause) { EnterExpressionEvaluationContext ConstantEvaluated( - Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated); + Actions, Sema::ExpressionEvaluationContext::Unevaluated); bool NotPrimaryExpression = false; auto ParsePrimary = [&] () { ExprResult E = ParseCastExpression(PrimaryExprOnly, @@ -756,6 +756,7 @@ class CastExpressionIdValidator final : public CorrectionCandidateCallback { /// [C++11] user-defined-literal /// '(' expression ')' /// [C11] generic-selection +/// [C++2a] requires-expression /// '__func__' [C99 6.4.2.2] /// [GNU] '__FUNCTION__' /// [MS] '__FUNCDNAME__' @@ -1530,7 +1531,7 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind, CXXScopeSpec SS; ParseOptionalCXXScopeSpecifier(SS, nullptr, /*EnteringContext=*/false); - AnnotateTemplateIdTokenAsType(); + AnnotateTemplateIdTokenAsType(SS); return ParseCastExpression(ParseKind, isAddressOfOperand, NotCastExpr, isTypeCast, isVectorLiteral, NotPrimaryExpression); @@ -1548,7 +1549,8 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind, // We have a template-id that we know refers to a type, // translate it into a type and continue parsing as a cast // expression. - AnnotateTemplateIdTokenAsType(); + CXXScopeSpec SS; + AnnotateTemplateIdTokenAsType(SS); return ParseCastExpression(ParseKind, isAddressOfOperand, NotCastExpr, isTypeCast, isVectorLiteral, NotPrimaryExpression); @@ -1600,6 +1602,9 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind, *NotPrimaryExpression = true; return ParseCXXDeleteExpression(false, Tok.getLocation()); + case tok::kw_requires: // [C++2a] requires-expression + return ParseRequiresExpression(); + case tok::kw_noexcept: { // [C++0x] 'noexcept' '(' expression ')' if (NotPrimaryExpression) *NotPrimaryExpression = true; @@ -2650,7 +2655,8 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, // If the substmt parsed correctly, build the AST node. if (!Stmt.isInvalid()) { - Result = Actions.ActOnStmtExpr(OpenLoc, Stmt.get(), Tok.getLocation()); + Result = Actions.ActOnStmtExpr(getCurScope(), OpenLoc, Stmt.get(), + Tok.getLocation()); } else { Actions.ActOnStmtExprError(); } diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index e685d5ea8a9cc..17f81ec96c1f2 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -11,7 +11,9 @@ //===----------------------------------------------------------------------===// #include "clang/Parse/Parser.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" #include "clang/AST/DeclTemplate.h" +#include "clang/AST/ExprCXX.h" #include "clang/Basic/PrettyStackTrace.h" #include "clang/Lex/LiteralSupport.h" #include "clang/Parse/ParseDiagnostic.h" @@ -165,13 +167,6 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, return false; } - if (Tok.is(tok::annot_template_id)) { - // If the current token is an annotated template id, it may already have - // a scope specifier. Restore it. - TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); - SS = TemplateId->SS; - } - // Has to happen before any "return false"s in this function. bool CheckForDestructor = false; if (MayBePseudoDestructor && *MayBePseudoDestructor) { @@ -1306,9 +1301,9 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( Actions.RecordParsingTemplateParameterDepth( CurTemplateDepthTracker.getOriginalDepth()); - ParseParameterDeclarationClause(D, Attr, ParamInfo, EllipsisLoc); - - // For a generic lambda, each 'auto' within the parameter declaration + ParseParameterDeclarationClause(D.getContext(), Attr, ParamInfo, + EllipsisLoc); + // For a generic lambda, each 'auto' within the parameter declaration // clause creates a template type parameter, so increment the depth. // If we've parsed any explicit template parameters, then the depth will // have already been incremented. So we make sure that at most a single @@ -2405,7 +2400,7 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, : Id.OperatorFunctionId.Operator; TemplateIdAnnotation *TemplateId = TemplateIdAnnotation::Create( - SS, TemplateKWLoc, Id.StartLocation, TemplateII, OpKind, Template, TNK, + TemplateKWLoc, Id.StartLocation, TemplateII, OpKind, Template, TNK, LAngleLoc, RAngleLoc, TemplateArgs, TemplateIds); Id.setTemplateId(TemplateId); @@ -3262,6 +3257,311 @@ Parser::ParseCXXDeleteExpression(bool UseGlobal, SourceLocation Start) { return Actions.ActOnCXXDelete(Start, UseGlobal, ArrayDelete, Operand.get()); } +/// ParseRequiresExpression - Parse a C++2a requires-expression. +/// C++2a [expr.prim.req]p1 +/// A requires-expression provides a concise way to express requirements on +/// template arguments. A requirement is one that can be checked by name +/// lookup (6.4) or by checking properties of types and expressions. +/// +/// requires-expression: +/// 'requires' requirement-parameter-list[opt] requirement-body +/// +/// requirement-parameter-list: +/// '(' parameter-declaration-clause[opt] ')' +/// +/// requirement-body: +/// '{' requirement-seq '}' +/// +/// requirement-seq: +/// requirement +/// requirement-seq requirement +/// +/// requirement: +/// simple-requirement +/// type-requirement +/// compound-requirement +/// nested-requirement +ExprResult Parser::ParseRequiresExpression() { + assert(Tok.is(tok::kw_requires) && "Expected 'requires' keyword"); + SourceLocation RequiresKWLoc = ConsumeToken(); // Consume 'requires' + + llvm::SmallVector LocalParameterDecls; + if (Tok.is(tok::l_paren)) { + // requirement parameter list is present. + ParseScope LocalParametersScope(this, Scope::FunctionPrototypeScope | + Scope::DeclScope); + BalancedDelimiterTracker Parens(*this, tok::l_paren); + Parens.consumeOpen(); + if (!Tok.is(tok::r_paren)) { + ParsedAttributes FirstArgAttrs(getAttrFactory()); + SourceLocation EllipsisLoc; + llvm::SmallVector LocalParameters; + DiagnosticErrorTrap Trap(Diags); + ParseParameterDeclarationClause(DeclaratorContext::RequiresExprContext, + FirstArgAttrs, LocalParameters, + EllipsisLoc); + if (EllipsisLoc.isValid()) + Diag(EllipsisLoc, diag::err_requires_expr_parameter_list_ellipsis); + for (auto &ParamInfo : LocalParameters) + LocalParameterDecls.push_back(cast(ParamInfo.Param)); + if (Trap.hasErrorOccurred()) + SkipUntil(tok::r_paren, StopBeforeMatch); + } + Parens.consumeClose(); + } + + BalancedDelimiterTracker Braces(*this, tok::l_brace); + if (Braces.expectAndConsume()) + return ExprError(); + + // Start of requirement list + llvm::SmallVector Requirements; + + // C++2a [expr.prim.req]p2 + // Expressions appearing within a requirement-body are unevaluated operands. + EnterExpressionEvaluationContext Ctx( + Actions, Sema::ExpressionEvaluationContext::Unevaluated); + + ParseScope BodyScope(this, Scope::DeclScope); + RequiresExprBodyDecl *Body = Actions.ActOnStartRequiresExpr( + RequiresKWLoc, LocalParameterDecls, getCurScope()); + + if (Tok.is(tok::r_brace)) { + // Grammar does not allow an empty body. + // requirement-body: + // { requirement-seq } + // requirement-seq: + // requirement + // requirement-seq requirement + Diag(Tok, diag::err_empty_requires_expr); + // Continue anyway and produce a requires expr with no requirements. + } else { + while (!Tok.is(tok::r_brace)) { + switch (Tok.getKind()) { + case tok::l_brace: { + // Compound requirement + // C++ [expr.prim.req.compound] + // compound-requirement: + // '{' expression '}' 'noexcept'[opt] + // return-type-requirement[opt] ';' + // return-type-requirement: + // trailing-return-type + // '->' cv-qualifier-seq[opt] constrained-parameter + // cv-qualifier-seq[opt] abstract-declarator[opt] + BalancedDelimiterTracker ExprBraces(*this, tok::l_brace); + ExprBraces.consumeOpen(); + ExprResult Expression = + Actions.CorrectDelayedTyposInExpr(ParseExpression()); + if (!Expression.isUsable()) { + ExprBraces.skipToEnd(); + SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch); + break; + } + if (ExprBraces.consumeClose()) + ExprBraces.skipToEnd(); + + concepts::Requirement *Req = nullptr; + SourceLocation NoexceptLoc; + TryConsumeToken(tok::kw_noexcept, NoexceptLoc); + if (Tok.is(tok::semi)) { + Req = Actions.ActOnCompoundRequirement(Expression.get(), NoexceptLoc); + if (Req) + Requirements.push_back(Req); + break; + } + if (!TryConsumeToken(tok::arrow)) + // User probably forgot the arrow, remind them and try to continue. + Diag(Tok, diag::err_requires_expr_missing_arrow) + << FixItHint::CreateInsertion(Tok.getLocation(), "->"); + // Try to parse a 'type-constraint' + if (TryAnnotateTypeConstraint()) { + SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch); + break; + } + if (!isTypeConstraintAnnotation()) { + Diag(Tok, diag::err_requires_expr_expected_type_constraint); + SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch); + break; + } + CXXScopeSpec SS; + if (Tok.is(tok::annot_cxxscope)) { + Actions.RestoreNestedNameSpecifierAnnotation(Tok.getAnnotationValue(), + Tok.getAnnotationRange(), + SS); + ConsumeAnnotationToken(); + } + + Req = Actions.ActOnCompoundRequirement( + Expression.get(), NoexceptLoc, SS, takeTemplateIdAnnotation(Tok), + TemplateParameterDepth); + ConsumeAnnotationToken(); + if (Req) + Requirements.push_back(Req); + break; + } + default: { + bool PossibleRequiresExprInSimpleRequirement = false; + if (Tok.is(tok::kw_requires)) { + auto IsNestedRequirement = [&] { + RevertingTentativeParsingAction TPA(*this); + ConsumeToken(); // 'requires' + if (Tok.is(tok::l_brace)) + // This is a requires expression + // requires (T t) { + // requires { t++; }; + // ... ^ + // } + return false; + if (Tok.is(tok::l_paren)) { + // This might be the parameter list of a requires expression + ConsumeParen(); + auto Res = TryParseParameterDeclarationClause(); + if (Res != TPResult::False) { + // Skip to the closing parenthesis + // FIXME: Don't traverse these tokens twice (here and in + // TryParseParameterDeclarationClause). + unsigned Depth = 1; + while (Depth != 0) { + if (Tok.is(tok::l_paren)) + Depth++; + else if (Tok.is(tok::r_paren)) + Depth--; + ConsumeAnyToken(); + } + // requires (T t) { + // requires () ? + // ... ^ + // - OR - + // requires (int x) ? + // ... ^ + // } + if (Tok.is(tok::l_brace)) + // requires (...) { + // ^ - a requires expression as a + // simple-requirement. + return false; + } + } + return true; + }; + if (IsNestedRequirement()) { + ConsumeToken(); + // Nested requirement + // C++ [expr.prim.req.nested] + // nested-requirement: + // 'requires' constraint-expression ';' + ExprResult ConstraintExpr = + Actions.CorrectDelayedTyposInExpr(ParseConstraintExpression()); + if (ConstraintExpr.isInvalid() || !ConstraintExpr.isUsable()) { + SkipUntil(tok::semi, tok::r_brace, + SkipUntilFlags::StopBeforeMatch); + break; + } + if (auto *Req = + Actions.ActOnNestedRequirement(ConstraintExpr.get())) + Requirements.push_back(Req); + else { + SkipUntil(tok::semi, tok::r_brace, + SkipUntilFlags::StopBeforeMatch); + break; + } + break; + } else + PossibleRequiresExprInSimpleRequirement = true; + } else if (Tok.is(tok::kw_typename)) { + // This might be 'typename T::value_type;' (a type requirement) or + // 'typename T::value_type{};' (a simple requirement). + TentativeParsingAction TPA(*this); + + // We need to consume the typename to allow 'requires { typename a; }' + SourceLocation TypenameKWLoc = ConsumeToken(); + if (TryAnnotateCXXScopeToken()) { + TPA.Commit(); + SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch); + break; + } + CXXScopeSpec SS; + if (Tok.is(tok::annot_cxxscope)) { + Actions.RestoreNestedNameSpecifierAnnotation( + Tok.getAnnotationValue(), Tok.getAnnotationRange(), SS); + ConsumeAnnotationToken(); + } + + if (Tok.isOneOf(tok::identifier, tok::annot_template_id) && + !NextToken().isOneOf(tok::l_brace, tok::l_paren)) { + TPA.Commit(); + SourceLocation NameLoc = Tok.getLocation(); + IdentifierInfo *II = nullptr; + TemplateIdAnnotation *TemplateId = nullptr; + if (Tok.is(tok::identifier)) { + II = Tok.getIdentifierInfo(); + ConsumeToken(); + } else { + TemplateId = takeTemplateIdAnnotation(Tok); + ConsumeAnnotationToken(); + } + + if (auto *Req = Actions.ActOnTypeRequirement(TypenameKWLoc, SS, + NameLoc, II, + TemplateId)) { + Requirements.push_back(Req); + } + break; + } + TPA.Revert(); + } + // Simple requirement + // C++ [expr.prim.req.simple] + // simple-requirement: + // expression ';' + SourceLocation StartLoc = Tok.getLocation(); + ExprResult Expression = + Actions.CorrectDelayedTyposInExpr(ParseExpression()); + if (!Expression.isUsable()) { + SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch); + break; + } + if (!Expression.isInvalid() && PossibleRequiresExprInSimpleRequirement) + Diag(StartLoc, diag::warn_requires_expr_in_simple_requirement) + << FixItHint::CreateInsertion(StartLoc, "requires"); + if (auto *Req = Actions.ActOnSimpleRequirement(Expression.get())) + Requirements.push_back(Req); + else { + SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch); + break; + } + // User may have tried to put some compound requirement stuff here + if (Tok.is(tok::kw_noexcept)) { + Diag(Tok, diag::err_requires_expr_simple_requirement_noexcept) + << FixItHint::CreateInsertion(StartLoc, "{") + << FixItHint::CreateInsertion(Tok.getLocation(), "}"); + SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch); + break; + } + break; + } + } + if (ExpectAndConsumeSemi(diag::err_expected_semi_requirement)) { + SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch); + TryConsumeToken(tok::semi); + break; + } + } + if (Requirements.empty()) { + // Don't emit an empty requires expr here to avoid confusing the user with + // other diagnostics quoting an empty requires expression they never + // wrote. + Braces.consumeClose(); + Actions.ActOnFinishRequiresExpr(); + return ExprError(); + } + } + Braces.consumeClose(); + Actions.ActOnFinishRequiresExpr(); + return Actions.ActOnRequiresExpr(RequiresKWLoc, Body, LocalParameterDecls, + Requirements, Braces.getCloseLocation()); +} + static TypeTrait TypeTraitFromTokKind(tok::TokenKind kind) { switch (kind) { default: llvm_unreachable("Not a known type trait"); diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp index 1b9301b6591dc..609640576e9e0 100644 --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -240,6 +240,8 @@ Decl *Parser::ParseSingleDeclarationAfterTemplate( // Parse the declarator. ParsingDeclarator DeclaratorInfo(*this, DS, (DeclaratorContext)Context); + if (TemplateInfo.TemplateParams) + DeclaratorInfo.setTemplateParameterLists(*TemplateInfo.TemplateParams); ParseDeclarator(DeclaratorInfo); // Error parsing the declarator? if (!DeclaratorInfo.hasName()) { @@ -499,10 +501,7 @@ Parser::ParseTemplateParameterList(const unsigned Depth, /// Determine whether the parser is at the start of a template /// type parameter. -/// \param ScopeError will receive true if there was an error parsing a -/// scope specifier at the current location. -bool Parser::isStartOfTemplateTypeParameter(bool &ScopeError) { - ScopeError = false; +Parser::TPResult Parser::isStartOfTemplateTypeParameter() { if (Tok.is(tok::kw_class)) { // "class" may be the start of an elaborated-type-specifier or a // type-parameter. Per C++ [temp.param]p3, we prefer the type-parameter. @@ -512,7 +511,7 @@ bool Parser::isStartOfTemplateTypeParameter(bool &ScopeError) { case tok::greater: case tok::greatergreater: case tok::ellipsis: - return true; + return TPResult::True; case tok::identifier: // This may be either a type-parameter or an elaborated-type-specifier. @@ -520,7 +519,7 @@ bool Parser::isStartOfTemplateTypeParameter(bool &ScopeError) { break; default: - return false; + return TPResult::False; } switch (GetLookAheadToken(2).getKind()) { @@ -528,51 +527,28 @@ bool Parser::isStartOfTemplateTypeParameter(bool &ScopeError) { case tok::comma: case tok::greater: case tok::greatergreater: - return true; + return TPResult::True; default: - return false; + return TPResult::False; } } - bool WasScopeAnnotation = Tok.is(tok::annot_cxxscope); - CXXScopeSpec SS; - ScopeError = - ParseOptionalCXXScopeSpecifier(SS, ParsedType(), - /*EnteringContext=*/false, - /*MayBePseudoDestructor=*/nullptr, - // If this is not a type-constraint, then - // this scope-spec is part of the typename - // of a non-type template parameter - /*IsTypename=*/true, /*LastII=*/nullptr, - // We won't find concepts in - // non-namespaces anyway, so might as well - // parse this correctly for possible type - // names. - /*OnlyNamespace=*/false); - if (ScopeError) - return false; - if (TryAnnotateTypeConstraint(SS)) - return false; - bool IsTypeConstraint = isTypeConstraintAnnotation(); - if (!IsTypeConstraint && SS.isNotEmpty()) { - // This isn't a type-constraint but we've already parsed this scope - // specifier - annotate it. - AnnotateScopeToken(SS, /*isNewAnnotation=*/!WasScopeAnnotation); - return false; - } + if (TryAnnotateTypeConstraint()) + return TPResult::Error; - if (IsTypeConstraint && + if (isTypeConstraintAnnotation() && // Next token might be 'auto' or 'decltype', indicating that this // type-constraint is in fact part of a placeholder-type-specifier of a // non-type template parameter. - !NextToken().isOneOf(tok::kw_auto, tok::kw_decltype)) - return true; + !GetLookAheadToken(Tok.is(tok::annot_cxxscope) ? 2 : 1) + .isOneOf(tok::kw_auto, tok::kw_decltype)) + return TPResult::True; // 'typedef' is a reasonably-common typo/thinko for 'typename', and is // ill-formed otherwise. if (Tok.isNot(tok::kw_typename) && Tok.isNot(tok::kw_typedef)) - return false; + return TPResult::False; // C++ [temp.param]p2: // There is no semantic difference between class and typename in a @@ -592,17 +568,17 @@ bool Parser::isStartOfTemplateTypeParameter(bool &ScopeError) { case tok::greater: case tok::greatergreater: case tok::ellipsis: - return true; + return TPResult::True; case tok::kw_typename: case tok::kw_typedef: case tok::kw_class: // These indicate that a comma was missed after a type parameter, not that // we have found a non-type parameter. - return true; + return TPResult::True; default: - return false; + return TPResult::False; } } @@ -627,13 +603,9 @@ bool Parser::isStartOfTemplateTypeParameter(bool &ScopeError) { /// typename /// NamedDecl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) { - // We could be facing a type-constraint, which (could) start a type parameter. - // Annotate it now (we might end up not using it if we determine this - // type-constraint is in fact part of a placeholder-type-specifier of a - // non-type template parameter. - bool ScopeError; - if (isStartOfTemplateTypeParameter(ScopeError)) { + switch (isStartOfTemplateTypeParameter()) { + case TPResult::True: // Is there just a typo in the input code? ('typedef' instead of // 'typename') if (Tok.is(tok::kw_typedef)) { @@ -649,8 +621,10 @@ NamedDecl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) { } return ParseTypeParameter(Depth, Position); - } - if (ScopeError) { + case TPResult::False: + break; + + case TPResult::Error: { // We return an invalid parameter as opposed to null to avoid having bogus // diagnostics about an empty template parameter list. // FIXME: Fix ParseTemplateParameterList to better handle nullptr results @@ -670,6 +644,11 @@ NamedDecl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) { StopAtSemi | StopBeforeMatch); return ErrorParam; } + + case TPResult::Ambiguous: + llvm_unreachable("template param classification can't be ambiguous"); + } + if (Tok.is(tok::kw_template)) return ParseTemplateTemplateParameter(Depth, Position); @@ -682,15 +661,15 @@ NamedDecl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) { /// Check whether the current token is a template-id annotation denoting a /// type-constraint. bool Parser::isTypeConstraintAnnotation() { - if (Tok.isNot(tok::annot_template_id)) + const Token &T = Tok.is(tok::annot_cxxscope) ? NextToken() : Tok; + if (T.isNot(tok::annot_template_id)) return false; const auto *ExistingAnnot = - static_cast(Tok.getAnnotationValue()); + static_cast(T.getAnnotationValue()); return ExistingAnnot->Kind == TNK_Concept_template; } -/// Try parsing a type-constraint construct at the current location, after the -/// optional scope specifier. +/// Try parsing a type-constraint at the current location. /// /// type-constraint: /// nested-name-specifier[opt] concept-name @@ -698,35 +677,62 @@ bool Parser::isTypeConstraintAnnotation() { /// '<' template-argument-list[opt] '>'[opt] /// /// \returns true if an error occurred, and false otherwise. -bool Parser::TryAnnotateTypeConstraint(CXXScopeSpec &SS) { - if (!getLangOpts().ConceptsTS || Tok.isNot(tok::identifier)) +bool Parser::TryAnnotateTypeConstraint() { + if (!getLangOpts().CPlusPlus2a) return false; + CXXScopeSpec SS; + bool WasScopeAnnotation = Tok.is(tok::annot_cxxscope); + if (ParseOptionalCXXScopeSpecifier( + SS, ParsedType(), + /*EnteringContext=*/false, + /*MayBePseudoDestructor=*/nullptr, + // If this is not a type-constraint, then + // this scope-spec is part of the typename + // of a non-type template parameter + /*IsTypename=*/true, /*LastII=*/nullptr, + // We won't find concepts in + // non-namespaces anyway, so might as well + // parse this correctly for possible type + // names. + /*OnlyNamespace=*/false)) + return true; - UnqualifiedId PossibleConceptName; - PossibleConceptName.setIdentifier(Tok.getIdentifierInfo(), - Tok.getLocation()); - - TemplateTy PossibleConcept; - bool MemberOfUnknownSpecialization = false; - auto TNK = Actions.isTemplateName(getCurScope(), SS, - /*hasTemplateKeyword=*/false, - PossibleConceptName, - /*ObjectType=*/ParsedType(), - /*EnteringContext=*/false, - PossibleConcept, - MemberOfUnknownSpecialization); - assert(!MemberOfUnknownSpecialization - && "Member when we only allowed namespace scope qualifiers??"); - if (!PossibleConcept || TNK != TNK_Concept_template) - return false; + if (Tok.is(tok::identifier)) { + UnqualifiedId PossibleConceptName; + PossibleConceptName.setIdentifier(Tok.getIdentifierInfo(), + Tok.getLocation()); + + TemplateTy PossibleConcept; + bool MemberOfUnknownSpecialization = false; + auto TNK = Actions.isTemplateName(getCurScope(), SS, + /*hasTemplateKeyword=*/false, + PossibleConceptName, + /*ObjectType=*/ParsedType(), + /*EnteringContext=*/false, + PossibleConcept, + MemberOfUnknownSpecialization, + /*Disambiguation=*/true); + if (MemberOfUnknownSpecialization || !PossibleConcept || + TNK != TNK_Concept_template) { + if (SS.isNotEmpty()) + AnnotateScopeToken(SS, !WasScopeAnnotation); + return false; + } - // At this point we're sure we're dealing with a constrained parameter. It - // may or may not have a template parameter list following the concept name. - return AnnotateTemplateIdToken(PossibleConcept, TNK, SS, - /*TemplateKWLoc=*/SourceLocation(), - PossibleConceptName, - /*AllowTypeAnnotation=*/false, - /*TypeConstraint=*/true); + // At this point we're sure we're dealing with a constrained parameter. It + // may or may not have a template parameter list following the concept + // name. + if (AnnotateTemplateIdToken(PossibleConcept, TNK, SS, + /*TemplateKWLoc=*/SourceLocation(), + PossibleConceptName, + /*AllowTypeAnnotation=*/false, + /*TypeConstraint=*/true)) + return true; + } + + if (SS.isNotEmpty()) + AnnotateScopeToken(SS, !WasScopeAnnotation); + return false; } /// ParseTypeParameter - Parse a template type parameter (C++ [temp.param]). @@ -739,13 +745,17 @@ bool Parser::TryAnnotateTypeConstraint(CXXScopeSpec &SS) { /// 'typename' ...[opt][C++0x] identifier[opt] /// 'typename' identifier[opt] '=' type-id NamedDecl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) { - assert(Tok.isOneOf(tok::kw_class, tok::kw_typename, tok::annot_template_id) && + assert((Tok.isOneOf(tok::kw_class, tok::kw_typename) || + isTypeConstraintAnnotation()) && "A type-parameter starts with 'class', 'typename' or a " "type-constraint"); + CXXScopeSpec TypeConstraintSS; TemplateIdAnnotation *TypeConstraint = nullptr; bool TypenameKeyword = false; SourceLocation KeyLoc; + ParseOptionalCXXScopeSpecifier(TypeConstraintSS, nullptr, + /*EnteringContext*/ false); if (Tok.is(tok::annot_template_id)) { // Consume the 'type-constraint'. TypeConstraint = @@ -754,6 +764,9 @@ NamedDecl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) { "stray non-concept template-id annotation"); KeyLoc = ConsumeAnnotationToken(); } else { + assert(TypeConstraintSS.isEmpty() && + "expected type constraint after scope specifier"); + // Consume the 'class' or 'typename' keyword. TypenameKeyword = Tok.is(tok::kw_typename); KeyLoc = ConsumeToken(); @@ -795,7 +808,8 @@ NamedDecl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) { ParsedType DefaultArg; if (TryConsumeToken(tok::equal, EqualLoc)) DefaultArg = ParseTypeName(/*Range=*/nullptr, - DeclaratorContext::TemplateTypeArgContext).get(); + DeclaratorContext::TemplateTypeArgContext) + .get(); NamedDecl *NewDecl = Actions.ActOnTypeParameter(getCurScope(), TypenameKeyword, EllipsisLoc, @@ -804,10 +818,11 @@ NamedDecl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) { DefaultArg, TypeConstraint != nullptr); - if (TypeConstraint) - Actions.ActOnTypeConstraint(TypeConstraint, + if (TypeConstraint) { + Actions.ActOnTypeConstraint(TypeConstraintSS, TypeConstraint, cast(NewDecl), EllipsisLoc); + } return NewDecl; } @@ -1331,8 +1346,8 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, : TemplateName.OperatorFunctionId.Operator; TemplateIdAnnotation *TemplateId = TemplateIdAnnotation::Create( - SS, TemplateKWLoc, TemplateNameLoc, TemplateII, OpKind, Template, TNK, - LAngleLoc, RAngleLoc, TemplateArgs, TemplateIds); + TemplateKWLoc, TemplateNameLoc, TemplateII, OpKind, Template, TNK, + LAngleLoc, RAngleLoc, TemplateArgs, TemplateIds); Tok.setAnnotationValue(TemplateId); if (TemplateKWLoc.isValid()) @@ -1357,11 +1372,14 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, /// a type annotation token will still be created, but will have a /// NULL type pointer to signify an error. /// +/// \param SS The scope specifier appearing before the template-id, if any. +/// /// \param IsClassName Is this template-id appearing in a context where we /// know it names a class, such as in an elaborated-type-specifier or /// base-specifier? ('typename' and 'template' are unneeded and disallowed /// in those contexts.) -void Parser::AnnotateTemplateIdTokenAsType(bool IsClassName) { +void Parser::AnnotateTemplateIdTokenAsType(CXXScopeSpec &SS, + bool IsClassName) { assert(Tok.is(tok::annot_template_id) && "Requires template-id tokens"); TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); @@ -1375,7 +1393,7 @@ void Parser::AnnotateTemplateIdTokenAsType(bool IsClassName) { TypeResult Type = Actions.ActOnTemplateIdType(getCurScope(), - TemplateId->SS, + SS, TemplateId->TemplateKWLoc, TemplateId->Template, TemplateId->Name, @@ -1388,8 +1406,8 @@ void Parser::AnnotateTemplateIdTokenAsType(bool IsClassName) { // Create the new "type" annotation token. Tok.setKind(tok::annot_typename); setTypeAnnotation(Tok, Type.isInvalid() ? nullptr : Type.get()); - if (TemplateId->SS.isNotEmpty()) // it was a C++ qualified type name. - Tok.setLocation(TemplateId->SS.getBeginLoc()); + if (SS.isNotEmpty()) // it was a C++ qualified type name. + Tok.setLocation(SS.getBeginLoc()); // End location stays the same // Replace the template-id annotation token, and possible the scope-specifier diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp index 4d69fb4693fb8..ad0a15b0c8a6d 100644 --- a/clang/lib/Parse/ParseTentative.cpp +++ b/clang/lib/Parse/ParseTentative.cpp @@ -202,9 +202,7 @@ Parser::TPResult Parser::TryConsumeDeclarationSpecifier() { } } - if (Tok.isOneOf(tok::identifier, tok::coloncolon, tok::kw_decltype, - tok::annot_template_id) && - TryAnnotateCXXScopeToken()) + if (TryAnnotateOptionalCXXScopeToken()) return TPResult::Error; if (Tok.is(tok::annot_cxxscope)) ConsumeAnnotationToken(); @@ -785,9 +783,8 @@ Parser::isCXX11AttributeSpecifier(bool Disambiguate, Parser::TPResult Parser::TryParsePtrOperatorSeq() { while (true) { - if (Tok.isOneOf(tok::coloncolon, tok::identifier)) - if (TryAnnotateCXXScopeToken(true)) - return TPResult::Error; + if (TryAnnotateOptionalCXXScopeToken(true)) + return TPResult::Error; if (Tok.isOneOf(tok::star, tok::amp, tok::caret, tok::ampamp) || (Tok.is(tok::annot_cxxscope) && NextToken().is(tok::star))) { @@ -1316,6 +1313,18 @@ class TentativeParseCCC final : public CorrectionCandidateCallback { Parser::TPResult Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, bool *InvalidAsDeclSpec) { + auto IsPlaceholderSpecifier = [&] (TemplateIdAnnotation *TemplateId, + int Lookahead) { + // We have a placeholder-constraint (we check for 'auto' or 'decltype' to + // distinguish 'C;' from 'C auto c = 1;') + return TemplateId->Kind == TNK_Concept_template && + GetLookAheadToken(Lookahead + 1).isOneOf(tok::kw_auto, tok::kw_decltype, + // If we have an identifier here, the user probably forgot the + // 'auto' in the placeholder constraint, e.g. 'C x = 2;' + // This will be diagnosed nicely later, so disambiguate as a + // declaration. + tok::identifier); + }; switch (Tok.getKind()) { case tok::identifier: { // Check for need to substitute AltiVec __vector keyword @@ -1519,10 +1528,12 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, *InvalidAsDeclSpec = NextToken().is(tok::l_paren); return TPResult::Ambiguous; } + if (IsPlaceholderSpecifier(TemplateId, /*Lookahead=*/0)) + return TPResult::True; if (TemplateId->Kind != TNK_Type_template) return TPResult::False; CXXScopeSpec SS; - AnnotateTemplateIdTokenAsType(); + AnnotateTemplateIdTokenAsType(SS); assert(Tok.is(tok::annot_typename)); goto case_typename; } @@ -1532,6 +1543,13 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, if (TryAnnotateTypeOrScopeToken()) return TPResult::Error; if (!Tok.is(tok::annot_typename)) { + if (Tok.is(tok::annot_cxxscope) && + NextToken().is(tok::annot_template_id)) { + TemplateIdAnnotation *TemplateId = + takeTemplateIdAnnotation(NextToken()); + if (IsPlaceholderSpecifier(TemplateId, /*Lookahead=*/1)) + return TPResult::True; + } // If the next token is an identifier or a type qualifier, then this // can't possibly be a valid expression either. if (Tok.is(tok::annot_cxxscope) && NextToken().is(tok::identifier)) { @@ -2137,3 +2155,58 @@ Parser::TPResult Parser::isTemplateArgumentList(unsigned TokensToSkip) { return TPResult::Ambiguous; return TPResult::False; } + +/// Determine whether we might be looking at the '(' of a C++20 explicit(bool) +/// in an earlier language mode. +Parser::TPResult Parser::isExplicitBool() { + assert(Tok.is(tok::l_paren) && "expected to be looking at a '(' token"); + + RevertingTentativeParsingAction PA(*this); + ConsumeParen(); + + // We can only have 'explicit' on a constructor, conversion function, or + // deduction guide. The declarator of a deduction guide cannot be + // parenthesized, so we know this isn't a deduction guide. So the only + // thing we need to check for is some number of parens followed by either + // the current class name or 'operator'. + while (Tok.is(tok::l_paren)) + ConsumeParen(); + + if (TryAnnotateOptionalCXXScopeToken()) + return TPResult::Error; + + // Class-scope constructor and conversion function names can't really be + // qualified, but we get better diagnostics if we assume they can be. + CXXScopeSpec SS; + if (Tok.is(tok::annot_cxxscope)) { + Actions.RestoreNestedNameSpecifierAnnotation(Tok.getAnnotationValue(), + Tok.getAnnotationRange(), + SS); + ConsumeAnnotationToken(); + } + + // 'explicit(operator' might be explicit(bool) or the declaration of a + // conversion function, but it's probably a conversion function. + if (Tok.is(tok::kw_operator)) + return TPResult::Ambiguous; + + // If this can't be a constructor name, it can only be explicit(bool). + if (Tok.isNot(tok::identifier) && Tok.isNot(tok::annot_template_id)) + return TPResult::True; + if (!Actions.isCurrentClassName(Tok.is(tok::identifier) + ? *Tok.getIdentifierInfo() + : *takeTemplateIdAnnotation(Tok)->Name, + getCurScope(), &SS)) + return TPResult::True; + // Formally, we must have a right-paren after the constructor name to match + // the grammar for a constructor. But clang permits a parenthesized + // constructor declarator, so also allow a constructor declarator to follow + // with no ')' token after the constructor name. + if (!NextToken().is(tok::r_paren) && + !isConstructorDeclarator(/*Unqualified=*/SS.isEmpty(), + /*DeductionGuide=*/false)) + return TPResult::True; + + // Might be explicit(bool) or a parenthesized constructor name. + return TPResult::Ambiguous; +} diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index 4249de361b89e..0b778bd242776 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -1136,6 +1136,7 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, // Poison SEH identifiers so they are flagged as illegal in function bodies. PoisonSEHIdentifiersRAIIObject PoisonSEHIdentifiers(*this, true); const DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo(); + TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth); // If this is C90 and the declspecs were completely missing, fudge in an // implicit int. We do this here because this is the only place where @@ -1262,6 +1263,15 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, // safe because we're always the sole owner. D.getMutableDeclSpec().abort(); + // With abbreviated function templates - we need to explicitly add depth to + // account for the implicit template parameter list induced by the template. + if (auto *Template = dyn_cast_or_null(Res)) + if (Template->isAbbreviated() && + Template->getTemplateParameters()->getParam(0)->isImplicit()) + // First template parameter is implicit - meaning no explicit template + // parameter list was specified. + CurTemplateDepthTracker.addDepth(1); + if (TryConsumeToken(tok::equal)) { assert(getLangOpts().CPlusPlus && "Only C++ function definitions have '='"); @@ -1732,6 +1742,20 @@ Parser::TryAnnotateName(CorrectionCandidateCallback *CCC) { return ANK_Error; return ANK_Success; } + case Sema::NC_Concept: { + UnqualifiedId Id; + Id.setIdentifier(Name, NameLoc); + if (Next.is(tok::less)) + // We have a concept name followed by '<'. Consume the identifier token so + // we reach the '<' and annotate it. + ConsumeToken(); + if (AnnotateTemplateIdToken( + TemplateTy::make(Classification.getTemplateName()), + Classification.getTemplateNameKind(), SS, SourceLocation(), Id, + /*AllowTypeAnnotation=*/false, /*TypeConstraint=*/true)) + return ANK_Error; + return ANK_Success; + } } // Unable to classify the name, but maybe we can annotate a scope specifier. @@ -1810,7 +1834,7 @@ bool Parser::TryAnnotateTypeOrScopeToken() { /*EnteringContext=*/false, nullptr, /*IsTypename*/ true)) return true; - if (!SS.isSet()) { + if (SS.isEmpty()) { if (Tok.is(tok::identifier) || Tok.is(tok::annot_template_id) || Tok.is(tok::annot_decltype)) { // Attempt to recover by skipping the invalid 'typename' @@ -1983,7 +2007,7 @@ bool Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec(CXXScopeSpec &SS, // template-id annotation in a context where we weren't allowed // to produce a type annotation token. Update the template-id // annotation token to a type annotation token now. - AnnotateTemplateIdTokenAsType(); + AnnotateTemplateIdTokenAsType(SS); return false; } } @@ -2005,10 +2029,7 @@ bool Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec(CXXScopeSpec &SS, bool Parser::TryAnnotateCXXScopeToken(bool EnteringContext) { assert(getLangOpts().CPlusPlus && "Call sites of this function should be guarded by checking for C++"); - assert((Tok.is(tok::identifier) || Tok.is(tok::coloncolon) || - (Tok.is(tok::annot_template_id) && NextToken().is(tok::coloncolon)) || - Tok.is(tok::kw_decltype) || Tok.is(tok::kw___super)) && - "Cannot be a type or scope token!"); + assert(MightBeCXXScopeToken() && "Cannot be a type or scope token!"); CXXScopeSpec SS; if (ParseOptionalCXXScopeSpecifier(SS, nullptr, EnteringContext)) diff --git a/clang/lib/Sema/DeclSpec.cpp b/clang/lib/Sema/DeclSpec.cpp index 639231c87232a..94d87974624e1 100644 --- a/clang/lib/Sema/DeclSpec.cpp +++ b/clang/lib/Sema/DeclSpec.cpp @@ -784,6 +784,15 @@ bool DeclSpec::SetTypeSpecType(TST T, SourceLocation TagKwLoc, return false; } +bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID, TemplateIdAnnotation *Rep, + const PrintingPolicy &Policy) { + assert(T == TST_auto || T == TST_decltype_auto); + ConstrainedAuto = true; + TemplateIdRep = Rep; + return SetTypeSpecType(T, Loc, PrevSpec, DiagID, Policy); +} + bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID, diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 2cd158a8b43c1..9cfce5a63b1df 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -52,6 +52,21 @@ SourceLocation Sema::getLocForEndOfToken(SourceLocation Loc, unsigned Offset) { ModuleLoader &Sema::getModuleLoader() const { return PP.getModuleLoader(); } +IdentifierInfo * +Sema::InventAbbreviatedTemplateParameterTypeName(IdentifierInfo *ParamName, + unsigned int Index) { + std::string InventedName; + llvm::raw_string_ostream OS(InventedName); + + if (!ParamName) + OS << "auto:" << Index + 1; + else + OS << ParamName->getName() << ":auto"; + + OS.flush(); + return &Context.Idents.get(OS.str()); +} + PrintingPolicy Sema::getPrintingPolicy(const ASTContext &Context, const Preprocessor &PP) { PrintingPolicy Policy = Context.getPrintingPolicy(); @@ -153,10 +168,10 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, TUKind(TUKind), NumSFINAEErrors(0), FullyCheckedComparisonCategories( static_cast(ComparisonCategoryType::Last) + 1), - AccessCheckingSFINAE(false), InNonInstantiationSFINAEContext(false), - NonInstantiationEntries(0), ArgumentPackSubstitutionIndex(-1), - CurrentInstantiationScope(nullptr), DisableTypoCorrection(false), - TyposCorrected(0), AnalysisWarnings(*this), + SatisfactionCache(Context), AccessCheckingSFINAE(false), + InNonInstantiationSFINAEContext(false), NonInstantiationEntries(0), + ArgumentPackSubstitutionIndex(-1), CurrentInstantiationScope(nullptr), + DisableTypoCorrection(false), TyposCorrected(0), AnalysisWarnings(*this), ThreadSafetyDeclCache(nullptr), VarDataSharingAttributesStack(nullptr), CurScope(nullptr), Ident_super(nullptr), Ident___float128(nullptr) { TUScope = nullptr; @@ -379,6 +394,14 @@ Sema::~Sema() { if (isMultiplexExternalSource) delete ExternalSource; + // Delete cached satisfactions. + std::vector Satisfactions; + Satisfactions.reserve(Satisfactions.size()); + for (auto &Node : SatisfactionCache) + Satisfactions.push_back(&Node); + for (auto *Node : Satisfactions) + delete Node; + threadSafety::threadSafetyCleanup(ThreadSafetyDeclCache); // Destroys data sharing attributes stack for OpenMP @@ -1261,7 +1284,8 @@ DeclContext *Sema::getFunctionLevelDeclContext() { DeclContext *DC = CurContext; while (true) { - if (isa(DC) || isa(DC) || isa(DC)) { + if (isa(DC) || isa(DC) || isa(DC) || + isa(DC)) { DC = DC->getParent(); } else if (isa(DC) && cast(DC)->getOverloadedOperator() == OO_Call && diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp index a905ebc673056..7a8cbca1e3f16 100644 --- a/clang/lib/Sema/SemaCast.cpp +++ b/clang/lib/Sema/SemaCast.cpp @@ -2311,6 +2311,24 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, return SuccessResult; } + // Diagnose address space conversion in nested pointers. + QualType DestPtee = DestType->getPointeeType().isNull() + ? DestType->getPointeeType() + : DestType->getPointeeType()->getPointeeType(); + QualType SrcPtee = SrcType->getPointeeType().isNull() + ? SrcType->getPointeeType() + : SrcType->getPointeeType()->getPointeeType(); + while (!DestPtee.isNull() && !SrcPtee.isNull()) { + if (DestPtee.getAddressSpace() != SrcPtee.getAddressSpace()) { + Self.Diag(OpRange.getBegin(), + diag::warn_bad_cxx_cast_nested_pointer_addr_space) + << CStyle << SrcType << DestType << SrcExpr.get()->getSourceRange(); + break; + } + DestPtee = DestPtee->getPointeeType(); + SrcPtee = SrcPtee->getPointeeType(); + } + // C++ 5.2.10p7: A pointer to an object can be explicitly converted to // a pointer to an object of different type. // Void pointers are not specified, but supported by every compiler out there. diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp index 018ac2d7dc9d1..290e4cbff4fd6 100755 --- a/clang/lib/Sema/SemaConcept.cpp +++ b/clang/lib/Sema/SemaConcept.cpp @@ -17,7 +17,10 @@ #include "clang/Sema/SemaDiagnostic.h" #include "clang/Sema/TemplateDeduction.h" #include "clang/Sema/Template.h" -#include "clang/AST/ExprCXX.h" +#include "clang/Sema/Overload.h" +#include "clang/Sema/Initialization.h" +#include "clang/Sema/SemaInternal.h" +#include "clang/AST/ExprConcepts.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/Basic/OperatorPrecedence.h" #include "llvm/ADT/DenseMap.h" @@ -164,9 +167,8 @@ calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr, return false; } -template static bool calculateConstraintSatisfaction( - Sema &S, TemplateDeclT *Template, ArrayRef TemplateArgs, + Sema &S, const NamedDecl *Template, ArrayRef TemplateArgs, SourceLocation TemplateNameLoc, MultiLevelTemplateArgumentList &MLTAL, const Expr *ConstraintExpr, ConstraintSatisfaction &Satisfaction) { return calculateConstraintSatisfaction( @@ -179,8 +181,9 @@ static bool calculateConstraintSatisfaction( { TemplateDeductionInfo Info(TemplateNameLoc); Sema::InstantiatingTemplate Inst(S, AtomicExpr->getBeginLoc(), - Sema::InstantiatingTemplate::ConstraintSubstitution{}, Template, - Info, AtomicExpr->getSourceRange()); + Sema::InstantiatingTemplate::ConstraintSubstitution{}, + const_cast(Template), Info, + AtomicExpr->getSourceRange()); if (Inst.isInvalid()) return ExprError(); // We do not want error diagnostics escaping here. @@ -227,8 +230,7 @@ static bool calculateConstraintSatisfaction( }); } -template -static bool CheckConstraintSatisfaction(Sema &S, TemplateDeclT *Template, +static bool CheckConstraintSatisfaction(Sema &S, const NamedDecl *Template, ArrayRef ConstraintExprs, ArrayRef TemplateArgs, SourceRange TemplateIDRange, @@ -246,8 +248,8 @@ static bool CheckConstraintSatisfaction(Sema &S, TemplateDeclT *Template, } Sema::InstantiatingTemplate Inst(S, TemplateIDRange.getBegin(), - Sema::InstantiatingTemplate::ConstraintsCheck{}, Template, TemplateArgs, - TemplateIDRange); + Sema::InstantiatingTemplate::ConstraintsCheck{}, + const_cast(Template), TemplateArgs, TemplateIDRange); if (Inst.isInvalid()) return true; @@ -269,36 +271,45 @@ static bool CheckConstraintSatisfaction(Sema &S, TemplateDeclT *Template, return false; } -bool Sema::CheckConstraintSatisfaction(TemplateDecl *Template, - ArrayRef ConstraintExprs, - ArrayRef TemplateArgs, - SourceRange TemplateIDRange, - ConstraintSatisfaction &Satisfaction) { - return ::CheckConstraintSatisfaction(*this, Template, ConstraintExprs, - TemplateArgs, TemplateIDRange, - Satisfaction); -} +bool Sema::CheckConstraintSatisfaction( + const NamedDecl *Template, ArrayRef ConstraintExprs, + ArrayRef TemplateArgs, SourceRange TemplateIDRange, + ConstraintSatisfaction &OutSatisfaction) { + if (ConstraintExprs.empty()) { + OutSatisfaction.IsSatisfied = true; + return false; + } -bool -Sema::CheckConstraintSatisfaction(ClassTemplatePartialSpecializationDecl* Part, - ArrayRef ConstraintExprs, - ArrayRef TemplateArgs, - SourceRange TemplateIDRange, - ConstraintSatisfaction &Satisfaction) { - return ::CheckConstraintSatisfaction(*this, Part, ConstraintExprs, - TemplateArgs, TemplateIDRange, - Satisfaction); -} + llvm::FoldingSetNodeID ID; + void *InsertPos; + ConstraintSatisfaction *Satisfaction = nullptr; + bool ShouldCache = LangOpts.ConceptSatisfactionCaching && Template; + if (ShouldCache) { + ConstraintSatisfaction::Profile(ID, Context, Template, TemplateArgs); + Satisfaction = SatisfactionCache.FindNodeOrInsertPos(ID, InsertPos); + if (Satisfaction) { + OutSatisfaction = *Satisfaction; + return false; + } + Satisfaction = new ConstraintSatisfaction(Template, TemplateArgs); + } else { + Satisfaction = &OutSatisfaction; + } + if (::CheckConstraintSatisfaction(*this, Template, ConstraintExprs, + TemplateArgs, TemplateIDRange, + *Satisfaction)) { + if (ShouldCache) + delete Satisfaction; + return true; + } -bool -Sema::CheckConstraintSatisfaction(VarTemplatePartialSpecializationDecl* Partial, - ArrayRef ConstraintExprs, - ArrayRef TemplateArgs, - SourceRange TemplateIDRange, - ConstraintSatisfaction &Satisfaction) { - return ::CheckConstraintSatisfaction(*this, Partial, ConstraintExprs, - TemplateArgs, TemplateIDRange, - Satisfaction); + if (ShouldCache) { + // We cannot use InsertNode here because CheckConstraintSatisfaction might + // have invalidated it. + SatisfactionCache.InsertNode(Satisfaction); + OutSatisfaction = *Satisfaction; + } + return false; } bool Sema::CheckConstraintSatisfaction(const Expr *ConstraintExpr, @@ -310,6 +321,30 @@ bool Sema::CheckConstraintSatisfaction(const Expr *ConstraintExpr, }); } +bool Sema::CheckFunctionConstraints(const FunctionDecl *FD, + ConstraintSatisfaction &Satisfaction, + SourceLocation UsageLoc) { + const Expr *RC = FD->getTrailingRequiresClause(); + if (RC->isInstantiationDependent()) { + Satisfaction.IsSatisfied = true; + return false; + } + Qualifiers ThisQuals; + CXXRecordDecl *Record = nullptr; + if (auto *Method = dyn_cast(FD)) { + ThisQuals = Method->getMethodQualifiers(); + Record = const_cast(Method->getParent()); + } + CXXThisScopeRAII ThisScope(*this, Record, ThisQuals, Record != nullptr); + // We substitute with empty arguments in order to rebuild the atomic + // constraint in a constant-evaluated context. + // FIXME: Should this be a dedicated TreeTransform? + return CheckConstraintSatisfaction( + FD, {RC}, /*TemplateArgs=*/{}, + SourceRange(UsageLoc.isValid() ? UsageLoc : FD->getLocation()), + Satisfaction); +} + bool Sema::EnsureTemplateArgumentListConstraints( TemplateDecl *TD, ArrayRef TemplateArgs, SourceRange TemplateIDRange) { @@ -336,6 +371,118 @@ bool Sema::EnsureTemplateArgumentListConstraints( return false; } +static void diagnoseUnsatisfiedRequirement(Sema &S, + concepts::ExprRequirement *Req, + bool First) { + assert(!Req->isSatisfied() + && "Diagnose() can only be used on an unsatisfied requirement"); + switch (Req->getSatisfactionStatus()) { + case concepts::ExprRequirement::SS_Dependent: + llvm_unreachable("Diagnosing a dependent requirement"); + break; + case concepts::ExprRequirement::SS_ExprSubstitutionFailure: { + auto *SubstDiag = Req->getExprSubstitutionDiagnostic(); + if (!SubstDiag->DiagMessage.empty()) + S.Diag(SubstDiag->DiagLoc, + diag::note_expr_requirement_expr_substitution_error) + << (int)First << SubstDiag->SubstitutedEntity + << SubstDiag->DiagMessage; + else + S.Diag(SubstDiag->DiagLoc, + diag::note_expr_requirement_expr_unknown_substitution_error) + << (int)First << SubstDiag->SubstitutedEntity; + break; + } + case concepts::ExprRequirement::SS_NoexceptNotMet: + S.Diag(Req->getNoexceptLoc(), + diag::note_expr_requirement_noexcept_not_met) + << (int)First << Req->getExpr(); + break; + case concepts::ExprRequirement::SS_TypeRequirementSubstitutionFailure: { + auto *SubstDiag = + Req->getReturnTypeRequirement().getSubstitutionDiagnostic(); + if (!SubstDiag->DiagMessage.empty()) + S.Diag(SubstDiag->DiagLoc, + diag::note_expr_requirement_type_requirement_substitution_error) + << (int)First << SubstDiag->SubstitutedEntity + << SubstDiag->DiagMessage; + else + S.Diag(SubstDiag->DiagLoc, + diag::note_expr_requirement_type_requirement_unknown_substitution_error) + << (int)First << SubstDiag->SubstitutedEntity; + break; + } + case concepts::ExprRequirement::SS_ConstraintsNotSatisfied: { + ConceptSpecializationExpr *ConstraintExpr = + Req->getReturnTypeRequirementSubstitutedConstraintExpr(); + if (ConstraintExpr->getTemplateArgsAsWritten()->NumTemplateArgs == 1) + // A simple case - expr type is the type being constrained and the concept + // was not provided arguments. + S.Diag(ConstraintExpr->getBeginLoc(), + diag::note_expr_requirement_constraints_not_satisfied_simple) + << (int)First << S.BuildDecltypeType(Req->getExpr(), + Req->getExpr()->getBeginLoc()) + << ConstraintExpr->getNamedConcept(); + else + S.Diag(ConstraintExpr->getBeginLoc(), + diag::note_expr_requirement_constraints_not_satisfied) + << (int)First << ConstraintExpr; + S.DiagnoseUnsatisfiedConstraint(ConstraintExpr->getSatisfaction()); + break; + } + case concepts::ExprRequirement::SS_Satisfied: + llvm_unreachable("We checked this above"); + } +} + +static void diagnoseUnsatisfiedRequirement(Sema &S, + concepts::TypeRequirement *Req, + bool First) { + assert(!Req->isSatisfied() + && "Diagnose() can only be used on an unsatisfied requirement"); + switch (Req->getSatisfactionStatus()) { + case concepts::TypeRequirement::SS_Dependent: + llvm_unreachable("Diagnosing a dependent requirement"); + return; + case concepts::TypeRequirement::SS_SubstitutionFailure: { + auto *SubstDiag = Req->getSubstitutionDiagnostic(); + if (!SubstDiag->DiagMessage.empty()) + S.Diag(SubstDiag->DiagLoc, + diag::note_type_requirement_substitution_error) << (int)First + << SubstDiag->SubstitutedEntity << SubstDiag->DiagMessage; + else + S.Diag(SubstDiag->DiagLoc, + diag::note_type_requirement_unknown_substitution_error) + << (int)First << SubstDiag->SubstitutedEntity; + return; + } + default: + llvm_unreachable("Unknown satisfaction status"); + return; + } +} + +static void diagnoseUnsatisfiedRequirement(Sema &S, + concepts::NestedRequirement *Req, + bool First) { + if (Req->isSubstitutionFailure()) { + concepts::Requirement::SubstitutionDiagnostic *SubstDiag = + Req->getSubstitutionDiagnostic(); + if (!SubstDiag->DiagMessage.empty()) + S.Diag(SubstDiag->DiagLoc, + diag::note_nested_requirement_substitution_error) + << (int)First << SubstDiag->SubstitutedEntity + << SubstDiag->DiagMessage; + else + S.Diag(SubstDiag->DiagLoc, + diag::note_nested_requirement_unknown_substitution_error) + << (int)First << SubstDiag->SubstitutedEntity; + return; + } + S.DiagnoseUnsatisfiedConstraint(Req->getConstraintSatisfaction(), First); +} + + static void diagnoseWellFormedUnsatisfiedConstraintExpr(Sema &S, Expr *SubstExpr, bool First = true) { @@ -412,6 +559,19 @@ static void diagnoseWellFormedUnsatisfiedConstraintExpr(Sema &S, } S.DiagnoseUnsatisfiedConstraint(CSE->getSatisfaction()); return; + } else if (auto *RE = dyn_cast(SubstExpr)) { + for (concepts::Requirement *Req : RE->getRequirements()) + if (!Req->isDependent() && !Req->isSatisfied()) { + if (auto *E = dyn_cast(Req)) + diagnoseUnsatisfiedRequirement(S, E, First); + else if (auto *T = dyn_cast(Req)) + diagnoseUnsatisfiedRequirement(S, T, First); + else + diagnoseUnsatisfiedRequirement( + S, cast(Req), First); + break; + } + return; } S.Diag(SubstExpr->getSourceRange().getBegin(), @@ -434,11 +594,11 @@ static void diagnoseUnsatisfiedConstraintExpr( Record.template get(), First); } -void Sema::DiagnoseUnsatisfiedConstraint( - const ConstraintSatisfaction& Satisfaction) { +void +Sema::DiagnoseUnsatisfiedConstraint(const ConstraintSatisfaction& Satisfaction, + bool First) { assert(!Satisfaction.IsSatisfied && "Attempted to diagnose a satisfied constraint"); - bool First = true; for (auto &Pair : Satisfaction.Details) { diagnoseUnsatisfiedConstraintExpr(*this, Pair.first, Pair.second, First); First = false; @@ -446,10 +606,10 @@ void Sema::DiagnoseUnsatisfiedConstraint( } void Sema::DiagnoseUnsatisfiedConstraint( - const ASTConstraintSatisfaction &Satisfaction) { + const ASTConstraintSatisfaction &Satisfaction, + bool First) { assert(!Satisfaction.IsSatisfied && "Attempted to diagnose a satisfied constraint"); - bool First = true; for (auto &Pair : Satisfaction) { diagnoseUnsatisfiedConstraintExpr(*this, Pair.first, Pair.second, First); First = false; @@ -523,6 +683,10 @@ static bool substituteParameterMappings(Sema &S, NormalizedConstraint &N, ArgsAsWritten->arguments().back().getSourceRange().getEnd())); if (S.SubstTemplateArguments(*Atomic.ParameterMapping, MLTAL, SubstArgs)) return true; + Atomic.ParameterMapping.emplace( + MutableArrayRef( + new (S.Context) TemplateArgumentLoc[SubstArgs.size()], + SubstArgs.size())); std::copy(SubstArgs.arguments().begin(), SubstArgs.arguments().end(), N.getAtomicConstraint()->ParameterMapping->begin()); return false; @@ -826,3 +990,67 @@ bool Sema::MaybeEmitAmbiguousAtomicConstraintsDiagnostic(NamedDecl *D1, << AmbiguousAtomic2->getSourceRange(); return true; } + +concepts::ExprRequirement::ExprRequirement( + Expr *E, bool IsSimple, SourceLocation NoexceptLoc, + ReturnTypeRequirement Req, SatisfactionStatus Status, + ConceptSpecializationExpr *SubstitutedConstraintExpr) : + Requirement(IsSimple ? RK_Simple : RK_Compound, Status == SS_Dependent, + Status == SS_Dependent && + (E->containsUnexpandedParameterPack() || + Req.containsUnexpandedParameterPack()), + Status == SS_Satisfied), Value(E), NoexceptLoc(NoexceptLoc), + TypeReq(Req), SubstitutedConstraintExpr(SubstitutedConstraintExpr), + Status(Status) { + assert((!IsSimple || (Req.isEmpty() && NoexceptLoc.isInvalid())) && + "Simple requirement must not have a return type requirement or a " + "noexcept specification"); + assert((Status > SS_TypeRequirementSubstitutionFailure && Req.isTypeConstraint()) == + (SubstitutedConstraintExpr != nullptr)); +} + +concepts::ExprRequirement::ExprRequirement( + SubstitutionDiagnostic *ExprSubstDiag, bool IsSimple, + SourceLocation NoexceptLoc, ReturnTypeRequirement Req) : + Requirement(IsSimple ? RK_Simple : RK_Compound, Req.isDependent(), + Req.containsUnexpandedParameterPack(), /*IsSatisfied=*/false), + Value(ExprSubstDiag), NoexceptLoc(NoexceptLoc), TypeReq(Req), + Status(SS_ExprSubstitutionFailure) { + assert((!IsSimple || (Req.isEmpty() && NoexceptLoc.isInvalid())) && + "Simple requirement must not have a return type requirement or a " + "noexcept specification"); +} + +concepts::ExprRequirement::ReturnTypeRequirement:: +ReturnTypeRequirement(TemplateParameterList *TPL) : + TypeConstraintInfo(TPL, 0) { + assert(TPL->size() == 1); + const TypeConstraint *TC = + cast(TPL->getParam(0))->getTypeConstraint(); + assert(TC && + "TPL must have a template type parameter with a type constraint"); + auto *Constraint = + cast_or_null( + TC->getImmediatelyDeclaredConstraint()); + bool Dependent = false; + if (Constraint->getTemplateArgsAsWritten()) { + for (auto &ArgLoc : + Constraint->getTemplateArgsAsWritten()->arguments().drop_front(1)) { + if (ArgLoc.getArgument().isDependent()) { + Dependent = true; + break; + } + } + } + TypeConstraintInfo.setInt(Dependent ? 1 : 0); +} + +concepts::TypeRequirement::TypeRequirement(TypeSourceInfo *T) : + Requirement(RK_Type, T->getType()->isDependentType(), + T->getType()->containsUnexpandedParameterPack(), + // We reach this ctor with either dependent types (in which + // IsSatisfied doesn't matter) or with non-dependent type in + // which the existence of the type indicates satisfaction. + /*IsSatisfied=*/true + ), Value(T), + Status(T->getType()->isDependentType() ? SS_Dependent : SS_Satisfied) {} diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 507e4a6cd4365..64146f4a912f6 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -10,6 +10,7 @@ // //===----------------------------------------------------------------------===// +#include "TreeTransform.h" #include "TypeLocBuilder.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" @@ -1153,6 +1154,10 @@ Sema::NameClassification Sema::ClassifyName(Scope *S, CXXScopeSpec &SS, return ParsedType::make(T); } + if (isa(FirstDecl)) + return NameClassification::Concept( + TemplateName(cast(FirstDecl))); + // We can have a type template here if we're classifying a template argument. if (isa(FirstDecl) && !isa(FirstDecl) && !isa(FirstDecl)) @@ -6468,6 +6473,8 @@ static bool shouldConsiderLinkage(const VarDecl *VD) { return true; if (DC->isRecord()) return false; + if (isa(DC)) + return false; llvm_unreachable("Unexpected context"); } @@ -8654,11 +8661,21 @@ static Scope *getTagInjectionScope(Scope *S, const LangOptions &LangOpts) { NamedDecl* Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, TypeSourceInfo *TInfo, LookupResult &Previous, - MultiTemplateParamsArg TemplateParamLists, + MultiTemplateParamsArg TemplateParamListsRef, bool &AddToScope) { QualType R = TInfo->getType(); assert(R->isFunctionType()); + SmallVector TemplateParamLists; + for (TemplateParameterList *TPL : TemplateParamListsRef) + TemplateParamLists.push_back(TPL); + if (TemplateParameterList *Invented = D.getInventedTemplateParameterList()) { + if (!TemplateParamLists.empty() && + Invented->getDepth() == TemplateParamLists.back()->getDepth()) + TemplateParamLists.back() = Invented; + else + TemplateParamLists.push_back(Invented); + } // TODO: consider using NameInfo for diagnostic. DeclarationNameInfo NameInfo = GetNameForDeclarator(D); @@ -8738,15 +8755,16 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // Match up the template parameter lists with the scope specifier, then // determine whether we have a template or a template specialization. bool Invalid = false; - if (TemplateParameterList *TemplateParams = - MatchTemplateParametersToScopeSpecifier( - D.getDeclSpec().getBeginLoc(), D.getIdentifierLoc(), - D.getCXXScopeSpec(), - D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId - ? D.getName().TemplateId - : nullptr, - TemplateParamLists, isFriend, isMemberSpecialization, - Invalid)) { + TemplateParameterList *TemplateParams = + MatchTemplateParametersToScopeSpecifier( + D.getDeclSpec().getBeginLoc(), D.getIdentifierLoc(), + D.getCXXScopeSpec(), + D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId + ? D.getName().TemplateId + : nullptr, + TemplateParamLists, isFriend, isMemberSpecialization, + Invalid); + if (TemplateParams) { if (TemplateParams->size() > 0) { // This is a function template @@ -8779,7 +8797,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // For source fidelity, store the other template param lists. if (TemplateParamLists.size() > 1) { NewFD->setTemplateParameterListsInfo(Context, - TemplateParamLists.drop_back(1)); + ArrayRef(TemplateParamLists) + .drop_back(1)); } } else { // This is a function template specialization. @@ -12507,6 +12526,7 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { var->getDeclContext()->getRedeclContext()->isFileContext() && var->isExternallyVisible() && var->hasLinkage() && !var->isInline() && !var->getDescribedVarTemplate() && + !isa(var) && !isTemplateInstantiation(var->getTemplateSpecializationKind()) && !getDiagnostics().isIgnored(diag::warn_missing_variable_declarations, var->getLocation())) { diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 5c51b0f9b8cb7..849bc09063b37 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -4924,9 +4924,9 @@ static void handlePatchableFunctionEntryAttr(Sema &S, Decl *D, Expr *Arg = AL.getArgAsExpr(1); if (!checkUInt32Argument(S, AL, Arg, Offset, 1, true)) return; - if (Offset) { + if (Count < Offset) { S.Diag(getAttrLoc(AL), diag::err_attribute_argument_out_of_range) - << &AL << 0 << 0 << Arg->getBeginLoc(); + << &AL << 0 << Count << Arg->getBeginLoc(); return; } } diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 9916d3be77e10..831e55046e808 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -7373,7 +7373,14 @@ class DefaultedComparisonAnalyzer /// resolution [...] CandidateSet.exclude(FD); - S.LookupOverloadedBinOp(CandidateSet, OO, Fns, Args); + if (Args[0]->getType()->isOverloadableType()) + S.LookupOverloadedBinOp(CandidateSet, OO, Fns, Args); + else { + // FIXME: We determine whether this is a valid expression by checking to + // see if there's a viable builtin operator candidate for it. That isn't + // really what the rules ask us to do, but should give the right results. + S.AddBuiltinOperatorCandidates(OO, FD->getLocation(), Args, CandidateSet); + } Result R; @@ -7438,6 +7445,31 @@ class DefaultedComparisonAnalyzer if (OO == OO_Spaceship && FD->getReturnType()->isUndeducedAutoType()) { if (auto *BestFD = Best->Function) { + // If any callee has an undeduced return type, deduce it now. + // FIXME: It's not clear how a failure here should be handled. For + // now, we produce an eager diagnostic, because that is forward + // compatible with most (all?) other reasonable options. + if (BestFD->getReturnType()->isUndeducedType() && + S.DeduceReturnType(BestFD, FD->getLocation(), + /*Diagnose=*/false)) { + // Don't produce a duplicate error when asked to explain why the + // comparison is deleted: we diagnosed that when initially checking + // the defaulted operator. + if (Diagnose == NoDiagnostics) { + S.Diag( + FD->getLocation(), + diag::err_defaulted_comparison_cannot_deduce_undeduced_auto) + << Subobj.Kind << Subobj.Decl; + S.Diag( + Subobj.Loc, + diag::note_defaulted_comparison_cannot_deduce_undeduced_auto) + << Subobj.Kind << Subobj.Decl; + S.Diag(BestFD->getLocation(), + diag::note_defaulted_comparison_cannot_deduce_callee) + << Subobj.Kind << Subobj.Decl; + } + return Result::deleted(); + } if (auto *Info = S.Context.CompCategories.lookupInfoForType( BestFD->getCallResultType())) { R.Category = Info->Kind; @@ -7826,10 +7858,14 @@ class DefaultedComparisonSynthesizer return StmtError(); OverloadedOperatorKind OO = FD->getOverloadedOperator(); - ExprResult Op = S.CreateOverloadedBinOp( - Loc, BinaryOperator::getOverloadedOpcode(OO), Fns, - Obj.first.get(), Obj.second.get(), /*PerformADL=*/true, - /*AllowRewrittenCandidates=*/true, FD); + BinaryOperatorKind Opc = BinaryOperator::getOverloadedOpcode(OO); + ExprResult Op; + if (Type->isOverloadableType()) + Op = S.CreateOverloadedBinOp(Loc, Opc, Fns, Obj.first.get(), + Obj.second.get(), /*PerformADL=*/true, + /*AllowRewrittenCandidates=*/true, FD); + else + Op = S.CreateBuiltinBinOp(Loc, Opc, Obj.first.get(), Obj.second.get()); if (Op.isInvalid()) return StmtError(); @@ -7869,8 +7905,12 @@ class DefaultedComparisonSynthesizer llvm::APInt ZeroVal(S.Context.getIntWidth(S.Context.IntTy), 0); Expr *Zero = IntegerLiteral::Create(S.Context, ZeroVal, S.Context.IntTy, Loc); - ExprResult Comp = S.CreateOverloadedBinOp(Loc, BO_NE, Fns, VDRef.get(), - Zero, true, true, FD); + ExprResult Comp; + if (VDRef.get()->getType()->isOverloadableType()) + Comp = S.CreateOverloadedBinOp(Loc, BO_NE, Fns, VDRef.get(), Zero, true, + true, FD); + else + Comp = S.CreateBuiltinBinOp(Loc, BO_NE, VDRef.get(), Zero); if (Comp.isInvalid()) return StmtError(); Sema::ConditionResult Cond = S.ActOnCondition( @@ -17386,3 +17426,50 @@ MSPropertyDecl *Sema::HandleMSProperty(Scope *S, RecordDecl *Record, return NewPD; } + +void Sema::ActOnStartFunctionDeclarationDeclarator( + Declarator &Declarator, unsigned TemplateParameterDepth) { + auto &Info = InventedParameterInfos.emplace_back(); + TemplateParameterList *ExplicitParams = nullptr; + ArrayRef ExplicitLists = + Declarator.getTemplateParameterLists(); + if (!ExplicitLists.empty()) { + bool IsMemberSpecialization, IsInvalid; + ExplicitParams = MatchTemplateParametersToScopeSpecifier( + Declarator.getBeginLoc(), Declarator.getIdentifierLoc(), + Declarator.getCXXScopeSpec(), /*TemplateId=*/nullptr, + ExplicitLists, /*IsFriend=*/false, IsMemberSpecialization, IsInvalid, + /*SuppressDiagnostic=*/true); + } + if (ExplicitParams) { + Info.AutoTemplateParameterDepth = ExplicitParams->getDepth(); + for (NamedDecl *Param : *ExplicitParams) + Info.TemplateParams.push_back(Param); + Info.NumExplicitTemplateParams = ExplicitParams->size(); + } else { + Info.AutoTemplateParameterDepth = TemplateParameterDepth; + Info.NumExplicitTemplateParams = 0; + } +} + +void Sema::ActOnFinishFunctionDeclarationDeclarator(Declarator &Declarator) { + auto &FSI = InventedParameterInfos.back(); + if (FSI.TemplateParams.size() > FSI.NumExplicitTemplateParams) { + if (FSI.NumExplicitTemplateParams != 0) { + TemplateParameterList *ExplicitParams = + Declarator.getTemplateParameterLists().back(); + Declarator.setInventedTemplateParameterList( + TemplateParameterList::Create( + Context, ExplicitParams->getTemplateLoc(), + ExplicitParams->getLAngleLoc(), FSI.TemplateParams, + ExplicitParams->getRAngleLoc(), + ExplicitParams->getRequiresClause())); + } else { + Declarator.setInventedTemplateParameterList( + TemplateParameterList::Create( + Context, SourceLocation(), SourceLocation(), FSI.TemplateParams, + SourceLocation(), /*RequiresClause=*/nullptr)); + } + } + InventedParameterInfos.pop_back(); +} diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp index 5aedbe7644e4b..193eaa3e01f93 100644 --- a/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/clang/lib/Sema/SemaExceptionSpec.cpp @@ -1386,6 +1386,7 @@ CanThrowResult Sema::canThrow(const Stmt *S) { case Expr::StringLiteralClass: case Expr::SourceLocExprClass: case Expr::ConceptSpecializationExprClass: + case Expr::RequiresExprClass: // These expressions can never throw. return CT_Cannot; diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 5f4071924d3f1..04a7038d67548 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -245,8 +245,8 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef Locs, return true; } - // See if this is a deleted function. if (FunctionDecl *FD = dyn_cast(D)) { + // See if this is a deleted function. if (FD->isDeleted()) { auto *Ctor = dyn_cast(FD); if (Ctor && Ctor->isInheritingConstructor()) @@ -259,6 +259,29 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef Locs, return true; } + // [expr.prim.id]p4 + // A program that refers explicitly or implicitly to a function with a + // trailing requires-clause whose constraint-expression is not satisfied, + // other than to declare it, is ill-formed. [...] + // + // See if this is a function with constraints that need to be satisfied. + // Check this before deducing the return type, as it might instantiate the + // definition. + if (FD->getTrailingRequiresClause()) { + ConstraintSatisfaction Satisfaction; + if (CheckFunctionConstraints(FD, Satisfaction, Loc)) + // A diagnostic will have already been generated (non-constant + // constraint expression, for example) + return true; + if (!Satisfaction.IsSatisfied) { + Diag(Loc, + diag::err_reference_to_function_with_unsatisfied_constraints) + << D; + DiagnoseUnsatisfiedConstraint(Satisfaction); + return true; + } + } + // If the function has a deduced return type, and we can't deduce it, // then we can't use it either. if (getLangOpts().CPlusPlus14 && FD->getReturnType()->isUndeducedType() && @@ -326,28 +349,15 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef Locs, diagnoseUseOfInternalDeclInInlineFunction(*this, D, Loc); - // [expr.prim.id]p4 - // A program that refers explicitly or implicitly to a function with a - // trailing requires-clause whose constraint-expression is not satisfied, - // other than to declare it, is ill-formed. [...] - // - // See if this is a function with constraints that need to be satisfied. - if (FunctionDecl *FD = dyn_cast(D)) { - if (Expr *RC = FD->getTrailingRequiresClause()) { - ConstraintSatisfaction Satisfaction; - bool Failed = CheckConstraintSatisfaction(RC, Satisfaction); - if (Failed) - // A diagnostic will have already been generated (non-constant - // constraint expression, for example) - return true; - if (!Satisfaction.IsSatisfied) { - Diag(Loc, - diag::err_reference_to_function_with_unsatisfied_constraints) - << D; - DiagnoseUnsatisfiedConstraint(Satisfaction); - return true; - } - } + if (isa(D) && isa(D->getDeclContext()) && + !isUnevaluatedContext()) { + // C++ [expr.prim.req.nested] p3 + // A local parameter shall only appear as an unevaluated operand + // (Clause 8) within the constraint-expression. + Diag(Loc, diag::err_requires_expr_parameter_referenced_in_evaluated_context) + << D; + Diag(D->getLocation(), diag::note_entity_declared_at) << D; + return true; } return false; @@ -1904,7 +1914,7 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, bool RefersToCapturedVariable = isa(D) && NeedToCaptureVariable(cast(D), NameInfo.getLoc()); - + DeclRefExpr *E = DeclRefExpr::Create( Context, NNS, TemplateKWLoc, D, RefersToCapturedVariable, NameInfo, Ty, VK, FoundD, TemplateArgs, getNonOdrUseReasonInCurrentContext(D)); @@ -13898,9 +13908,13 @@ void Sema::ActOnStmtExprError() { PopExpressionEvaluationContext(); } -ExprResult -Sema::ActOnStmtExpr(SourceLocation LPLoc, Stmt *SubStmt, - SourceLocation RPLoc) { // "({..})" +ExprResult Sema::ActOnStmtExpr(Scope *S, SourceLocation LPLoc, Stmt *SubStmt, + SourceLocation RPLoc) { + return BuildStmtExpr(LPLoc, SubStmt, RPLoc, getTemplateDepth(S)); +} + +ExprResult Sema::BuildStmtExpr(SourceLocation LPLoc, Stmt *SubStmt, + SourceLocation RPLoc, unsigned TemplateDepth) { assert(SubStmt && isa(SubStmt) && "Invalid action invocation!"); CompoundStmt *Compound = cast(SubStmt); @@ -13931,7 +13945,8 @@ Sema::ActOnStmtExpr(SourceLocation LPLoc, Stmt *SubStmt, // FIXME: Check that expression type is complete/non-abstract; statement // expressions are not lvalues. - Expr *ResStmtExpr = new (Context) StmtExpr(Compound, Ty, LPLoc, RPLoc); + Expr *ResStmtExpr = + new (Context) StmtExpr(Compound, Ty, LPLoc, RPLoc, TemplateDepth); if (StmtExprMayBindToTemp) return MaybeBindToTemporary(ResStmtExpr); return ResStmtExpr; diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index a73e6906fceb9..e97171b6334ea 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -11,6 +11,7 @@ /// //===----------------------------------------------------------------------===// +#include "clang/Sema/Template.h" #include "clang/Sema/SemaInternal.h" #include "TreeTransform.h" #include "TypeLocBuilder.h" @@ -6799,8 +6800,9 @@ Stmt *Sema::MaybeCreateStmtWithCleanups(Stmt *SubStmt) { // a new AsmStmtWithTemporaries. CompoundStmt *CompStmt = CompoundStmt::Create( Context, SubStmt, SourceLocation(), SourceLocation()); - Expr *E = new (Context) StmtExpr(CompStmt, Context.VoidTy, SourceLocation(), - SourceLocation()); + Expr *E = new (Context) + StmtExpr(CompStmt, Context.VoidTy, SourceLocation(), SourceLocation(), + /*FIXME TemplateDepth=*/0); return MaybeCreateExprWithCleanups(E); } @@ -7317,7 +7319,7 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base, ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(), TemplateId->NumArgs); TypeResult T = ActOnTemplateIdType(S, - TemplateId->SS, + SS, TemplateId->TemplateKWLoc, TemplateId->Template, TemplateId->Name, @@ -7370,7 +7372,7 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base, ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(), TemplateId->NumArgs); TypeResult T = ActOnTemplateIdType(S, - TemplateId->SS, + SS, TemplateId->TemplateKWLoc, TemplateId->Template, TemplateId->Name, @@ -8331,3 +8333,216 @@ Sema::CheckMicrosoftIfExistsSymbol(Scope *S, SourceLocation KeywordLoc, return CheckMicrosoftIfExistsSymbol(S, SS, TargetNameInfo); } + +concepts::Requirement *Sema::ActOnSimpleRequirement(Expr *E) { + return BuildExprRequirement(E, /*IsSimple=*/true, + /*NoexceptLoc=*/SourceLocation(), + /*ReturnTypeRequirement=*/{}); +} + +concepts::Requirement * +Sema::ActOnTypeRequirement(SourceLocation TypenameKWLoc, CXXScopeSpec &SS, + SourceLocation NameLoc, IdentifierInfo *TypeName, + TemplateIdAnnotation *TemplateId) { + assert(((!TypeName && TemplateId) || (TypeName && !TemplateId)) && + "Exactly one of TypeName and TemplateId must be specified."); + TypeSourceInfo *TSI = nullptr; + if (TypeName) { + QualType T = CheckTypenameType(ETK_Typename, TypenameKWLoc, + SS.getWithLocInContext(Context), *TypeName, + NameLoc, &TSI, /*DeducedTypeContext=*/false); + if (T.isNull()) + return nullptr; + } else { + ASTTemplateArgsPtr ArgsPtr(TemplateId->getTemplateArgs(), + TemplateId->NumArgs); + TypeResult T = ActOnTypenameType(CurScope, TypenameKWLoc, SS, + TemplateId->TemplateKWLoc, + TemplateId->Template, TemplateId->Name, + TemplateId->TemplateNameLoc, + TemplateId->LAngleLoc, ArgsPtr, + TemplateId->RAngleLoc); + if (T.isInvalid()) + return nullptr; + if (GetTypeFromParser(T.get(), &TSI).isNull()) + return nullptr; + } + return BuildTypeRequirement(TSI); +} + +concepts::Requirement * +Sema::ActOnCompoundRequirement(Expr *E, SourceLocation NoexceptLoc) { + return BuildExprRequirement(E, /*IsSimple=*/false, NoexceptLoc, + /*ReturnTypeRequirement=*/{}); +} + +concepts::Requirement * +Sema::ActOnCompoundRequirement( + Expr *E, SourceLocation NoexceptLoc, CXXScopeSpec &SS, + TemplateIdAnnotation *TypeConstraint, unsigned Depth) { + // C++2a [expr.prim.req.compound] p1.3.3 + // [..] the expression is deduced against an invented function template + // F [...] F is a void function template with a single type template + // parameter T declared with the constrained-parameter. Form a new + // cv-qualifier-seq cv by taking the union of const and volatile specifiers + // around the constrained-parameter. F has a single parameter whose + // type-specifier is cv T followed by the abstract-declarator. [...] + // + // The cv part is done in the calling function - we get the concept with + // arguments and the abstract declarator with the correct CV qualification and + // have to synthesize T and the single parameter of F. + auto &II = Context.Idents.get("expr-type"); + auto *TParam = TemplateTypeParmDecl::Create(Context, CurContext, + SourceLocation(), + SourceLocation(), Depth, + /*Index=*/0, &II, + /*Typename=*/true, + /*ParameterPack=*/false, + /*HasTypeConstraint=*/true); + + if (ActOnTypeConstraint(SS, TypeConstraint, TParam, + /*EllpsisLoc=*/SourceLocation())) + // Just produce a requirement with no type requirements. + return BuildExprRequirement(E, /*IsSimple=*/false, NoexceptLoc, {}); + + auto *TPL = TemplateParameterList::Create(Context, SourceLocation(), + SourceLocation(), + ArrayRef(TParam), + SourceLocation(), + /*RequiresClause=*/nullptr); + return BuildExprRequirement( + E, /*IsSimple=*/false, NoexceptLoc, + concepts::ExprRequirement::ReturnTypeRequirement(TPL)); +} + +concepts::ExprRequirement * +Sema::BuildExprRequirement( + Expr *E, bool IsSimple, SourceLocation NoexceptLoc, + concepts::ExprRequirement::ReturnTypeRequirement ReturnTypeRequirement) { + auto Status = concepts::ExprRequirement::SS_Satisfied; + ConceptSpecializationExpr *SubstitutedConstraintExpr = nullptr; + if (E->isInstantiationDependent() || ReturnTypeRequirement.isDependent()) + Status = concepts::ExprRequirement::SS_Dependent; + else if (NoexceptLoc.isValid() && canThrow(E) == CanThrowResult::CT_Can) + Status = concepts::ExprRequirement::SS_NoexceptNotMet; + else if (ReturnTypeRequirement.isSubstitutionFailure()) + Status = concepts::ExprRequirement::SS_TypeRequirementSubstitutionFailure; + else if (ReturnTypeRequirement.isTypeConstraint()) { + // C++2a [expr.prim.req]p1.3.3 + // The immediately-declared constraint ([temp]) of decltype((E)) shall + // be satisfied. + TemplateParameterList *TPL = + ReturnTypeRequirement.getTypeConstraintTemplateParameterList(); + QualType MatchedType = + BuildDecltypeType(E, E->getBeginLoc()).getCanonicalType(); + llvm::SmallVector Args; + Args.push_back(TemplateArgument(MatchedType)); + TemplateArgumentList TAL(TemplateArgumentList::OnStack, Args); + MultiLevelTemplateArgumentList MLTAL(TAL); + for (unsigned I = 0; I < TPL->getDepth(); ++I) + MLTAL.addOuterRetainedLevel(); + Expr *IDC = + cast(TPL->getParam(0))->getTypeConstraint() + ->getImmediatelyDeclaredConstraint(); + ExprResult Constraint = SubstExpr(IDC, MLTAL); + assert(!Constraint.isInvalid() && + "Substitution cannot fail as it is simply putting a type template " + "argument into a concept specialization expression's parameter."); + + SubstitutedConstraintExpr = + cast(Constraint.get()); + if (!SubstitutedConstraintExpr->isSatisfied()) + Status = concepts::ExprRequirement::SS_ConstraintsNotSatisfied; + } + return new (Context) concepts::ExprRequirement(E, IsSimple, NoexceptLoc, + ReturnTypeRequirement, Status, + SubstitutedConstraintExpr); +} + +concepts::ExprRequirement * +Sema::BuildExprRequirement( + concepts::Requirement::SubstitutionDiagnostic *ExprSubstitutionDiagnostic, + bool IsSimple, SourceLocation NoexceptLoc, + concepts::ExprRequirement::ReturnTypeRequirement ReturnTypeRequirement) { + return new (Context) concepts::ExprRequirement(ExprSubstitutionDiagnostic, + IsSimple, NoexceptLoc, + ReturnTypeRequirement); +} + +concepts::TypeRequirement * +Sema::BuildTypeRequirement(TypeSourceInfo *Type) { + return new (Context) concepts::TypeRequirement(Type); +} + +concepts::TypeRequirement * +Sema::BuildTypeRequirement( + concepts::Requirement::SubstitutionDiagnostic *SubstDiag) { + return new (Context) concepts::TypeRequirement(SubstDiag); +} + +concepts::Requirement *Sema::ActOnNestedRequirement(Expr *Constraint) { + return BuildNestedRequirement(Constraint); +} + +concepts::NestedRequirement * +Sema::BuildNestedRequirement(Expr *Constraint) { + ConstraintSatisfaction Satisfaction; + if (!Constraint->isInstantiationDependent() && + CheckConstraintSatisfaction(nullptr, {Constraint}, /*TemplateArgs=*/{}, + Constraint->getSourceRange(), Satisfaction)) + return nullptr; + return new (Context) concepts::NestedRequirement(Context, Constraint, + Satisfaction); +} + +concepts::NestedRequirement * +Sema::BuildNestedRequirement( + concepts::Requirement::SubstitutionDiagnostic *SubstDiag) { + return new (Context) concepts::NestedRequirement(SubstDiag); +} + +RequiresExprBodyDecl * +Sema::ActOnStartRequiresExpr(SourceLocation RequiresKWLoc, + ArrayRef LocalParameters, + Scope *BodyScope) { + assert(BodyScope); + + RequiresExprBodyDecl *Body = RequiresExprBodyDecl::Create(Context, CurContext, + RequiresKWLoc); + + PushDeclContext(BodyScope, Body); + + for (ParmVarDecl *Param : LocalParameters) { + if (Param->hasDefaultArg()) + // C++2a [expr.prim.req] p4 + // [...] A local parameter of a requires-expression shall not have a + // default argument. [...] + Diag(Param->getDefaultArgRange().getBegin(), + diag::err_requires_expr_local_parameter_default_argument); + // Ignore default argument and move on + + Param->setDeclContext(Body); + // If this has an identifier, add it to the scope stack. + if (Param->getIdentifier()) { + CheckShadow(BodyScope, Param); + PushOnScopeChains(Param, BodyScope); + } + } + return Body; +} + +void Sema::ActOnFinishRequiresExpr() { + assert(CurContext && "DeclContext imbalance!"); + CurContext = CurContext->getLexicalParent(); + assert(CurContext && "Popped translation unit!"); +} + +ExprResult +Sema::ActOnRequiresExpr(SourceLocation RequiresKWLoc, + RequiresExprBodyDecl *Body, + ArrayRef LocalParameters, + ArrayRef Requirements, + SourceLocation ClosingBraceLoc) { + return RequiresExpr::Create(Context, RequiresKWLoc, Body, LocalParameters, + Requirements, ClosingBraceLoc); +} diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp index c2d14a44f53d4..ae89b146c409b 100644 --- a/clang/lib/Sema/SemaLambda.cpp +++ b/clang/lib/Sema/SemaLambda.cpp @@ -791,7 +791,8 @@ QualType Sema::buildLambdaInitCaptureInitialization( // deduce against. QualType DeductType = Context.getAutoDeductType(); TypeLocBuilder TLB; - TLB.pushTypeSpec(DeductType).setNameLoc(Loc); + AutoTypeLoc TL = TLB.push(DeductType); + TL.setNameLoc(Loc); if (ByRef) { DeductType = BuildReferenceType(DeductType, true, Loc, Id); assert(!DeductType.isNull() && "can't build reference to auto"); diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index 0ed51de0cc131..8d96404a5c27d 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -1575,7 +1575,9 @@ llvm::DenseSet &Sema::getLookupModules() { unsigned N = CodeSynthesisContexts.size(); for (unsigned I = CodeSynthesisContextLookupModules.size(); I != N; ++I) { - Module *M = getDefiningModule(*this, CodeSynthesisContexts[I].Entity); + Module *M = CodeSynthesisContexts[I].Entity ? + getDefiningModule(*this, CodeSynthesisContexts[I].Entity) : + nullptr; if (M && !LookupModulesCache.insert(M).second) M = nullptr; CodeSynthesisContextLookupModules.push_back(M); diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 0fd932fac9709..db1884acd3497 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -3176,7 +3176,7 @@ static bool isNonTrivialObjCLifetimeConversion(Qualifiers FromQuals, /// FromType and \p ToType is permissible, given knowledge about whether every /// outer layer is const-qualified. static bool isQualificationConversionStep(QualType FromType, QualType ToType, - bool CStyle, + bool CStyle, bool IsTopLevel, bool &PreviousToQualsIncludeConst, bool &ObjCLifetimeConversion) { Qualifiers FromQuals = FromType.getQualifiers(); @@ -3213,11 +3213,15 @@ static bool isQualificationConversionStep(QualType FromType, QualType ToType, if (!CStyle && !ToQuals.compatiblyIncludes(FromQuals)) return false; - // For a C-style cast, just require the address spaces to overlap. - // FIXME: Does "superset" also imply the representation of a pointer is the - // same? We're assuming that it does here and in compatiblyIncludes. - if (CStyle && !ToQuals.isAddressSpaceSupersetOf(FromQuals) && - !FromQuals.isAddressSpaceSupersetOf(ToQuals)) + // If address spaces mismatch: + // - in top level it is only valid to convert to addr space that is a + // superset in all cases apart from C-style casts where we allow + // conversions between overlapping address spaces. + // - in non-top levels it is not a valid conversion. + if (ToQuals.getAddressSpace() != FromQuals.getAddressSpace() && + (!IsTopLevel || + !(ToQuals.isAddressSpaceSupersetOf(FromQuals) || + (CStyle && FromQuals.isAddressSpaceSupersetOf(ToQuals))))) return false; // -- if the cv 1,j and cv 2,j are different, then const is in @@ -3258,9 +3262,9 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType, bool PreviousToQualsIncludeConst = true; bool UnwrappedAnyPointer = false; while (Context.UnwrapSimilarTypes(FromType, ToType)) { - if (!isQualificationConversionStep(FromType, ToType, CStyle, - PreviousToQualsIncludeConst, - ObjCLifetimeConversion)) + if (!isQualificationConversionStep( + FromType, ToType, CStyle, !UnwrappedAnyPointer, + PreviousToQualsIncludeConst, ObjCLifetimeConversion)) return false; UnwrappedAnyPointer = true; } @@ -4499,7 +4503,7 @@ Sema::CompareReferenceRelationship(SourceLocation Loc, // If we find a qualifier mismatch, the types are not reference-compatible, // but are still be reference-related if they're similar. bool ObjCLifetimeConversion = false; - if (!isQualificationConversionStep(T2, T1, /*CStyle=*/false, + if (!isQualificationConversionStep(T2, T1, /*CStyle=*/false, TopLevel, PreviousToQualsIncludeConst, ObjCLifetimeConversion)) return (ConvertedReferent || Context.hasSimilarType(T1, T2)) @@ -6291,9 +6295,9 @@ void Sema::AddOverloadCandidate( return; } - if (Expr *RequiresClause = Function->getTrailingRequiresClause()) { + if (Function->getTrailingRequiresClause()) { ConstraintSatisfaction Satisfaction; - if (CheckConstraintSatisfaction(RequiresClause, Satisfaction) || + if (CheckFunctionConstraints(Function, Satisfaction) || !Satisfaction.IsSatisfied) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_constraints_not_satisfied; @@ -6808,9 +6812,9 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, return; } - if (Expr *RequiresClause = Method->getTrailingRequiresClause()) { + if (Method->getTrailingRequiresClause()) { ConstraintSatisfaction Satisfaction; - if (CheckConstraintSatisfaction(RequiresClause, Satisfaction) || + if (CheckFunctionConstraints(Method, Satisfaction) || !Satisfaction.IsSatisfied) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_constraints_not_satisfied; @@ -7204,10 +7208,9 @@ void Sema::AddConversionCandidate( return; } - Expr *RequiresClause = Conversion->getTrailingRequiresClause(); - if (RequiresClause) { + if (Conversion->getTrailingRequiresClause()) { ConstraintSatisfaction Satisfaction; - if (CheckConstraintSatisfaction(RequiresClause, Satisfaction) || + if (CheckFunctionConstraints(Conversion, Satisfaction) || !Satisfaction.IsSatisfied) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_constraints_not_satisfied; @@ -9270,17 +9273,31 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name, if (ExplicitTemplateArgs) continue; - AddOverloadCandidate(FD, FoundDecl, Args, CandidateSet, - /*SuppressUserConversions=*/false, PartialOverloading, - /*AllowExplicit*/ true, - /*AllowExplicitConversions*/ false, - ADLCallKind::UsesADL); + AddOverloadCandidate( + FD, FoundDecl, Args, CandidateSet, /*SuppressUserConversions=*/false, + PartialOverloading, /*AllowExplicit=*/true, + /*AllowExplicitConversions=*/false, ADLCallKind::UsesADL); + if (CandidateSet.getRewriteInfo().shouldAddReversed(Context, FD)) { + AddOverloadCandidate( + FD, FoundDecl, {Args[1], Args[0]}, CandidateSet, + /*SuppressUserConversions=*/false, PartialOverloading, + /*AllowExplicit=*/true, /*AllowExplicitConversions=*/false, + ADLCallKind::UsesADL, None, OverloadCandidateParamOrder::Reversed); + } } else { + auto *FTD = cast(*I); AddTemplateOverloadCandidate( - cast(*I), FoundDecl, ExplicitTemplateArgs, Args, - CandidateSet, + FTD, FoundDecl, ExplicitTemplateArgs, Args, CandidateSet, /*SuppressUserConversions=*/false, PartialOverloading, - /*AllowExplicit*/true, ADLCallKind::UsesADL); + /*AllowExplicit=*/true, ADLCallKind::UsesADL); + if (CandidateSet.getRewriteInfo().shouldAddReversed( + Context, FTD->getTemplatedDecl())) { + AddTemplateOverloadCandidate( + FTD, FoundDecl, ExplicitTemplateArgs, {Args[1], Args[0]}, + CandidateSet, /*SuppressUserConversions=*/false, PartialOverloading, + /*AllowExplicit=*/true, ADLCallKind::UsesADL, + OverloadCandidateParamOrder::Reversed); + } } } } @@ -9566,17 +9583,15 @@ bool clang::isBetterOverloadCandidate( if (RC1 && RC2) { bool AtLeastAsConstrained1, AtLeastAsConstrained2; if (S.IsAtLeastAsConstrained(Cand1.Function, {RC1}, Cand2.Function, - {RC2}, AtLeastAsConstrained1)) - return false; - if (!AtLeastAsConstrained1) - return false; - if (S.IsAtLeastAsConstrained(Cand2.Function, {RC2}, Cand1.Function, + {RC2}, AtLeastAsConstrained1) || + S.IsAtLeastAsConstrained(Cand2.Function, {RC2}, Cand1.Function, {RC1}, AtLeastAsConstrained2)) return false; - if (!AtLeastAsConstrained2) - return true; - } else if (RC1 || RC2) + if (AtLeastAsConstrained1 != AtLeastAsConstrained2) + return AtLeastAsConstrained1; + } else if (RC1 || RC2) { return RC1 != nullptr; + } } } @@ -9947,9 +9962,9 @@ static bool checkAddressOfFunctionIsAvailable(Sema &S, const FunctionDecl *FD, return false; } - if (const Expr *RC = FD->getTrailingRequiresClause()) { + if (FD->getTrailingRequiresClause()) { ConstraintSatisfaction Satisfaction; - if (S.CheckConstraintSatisfaction(RC, Satisfaction)) + if (S.CheckFunctionConstraints(FD, Satisfaction, Loc)) return false; if (!Satisfaction.IsSatisfied) { if (Complain) { @@ -10974,8 +10989,7 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand, << (unsigned)FnKindPair.first << (unsigned)ocs_non_template << FnDesc /* Ignored */; ConstraintSatisfaction Satisfaction; - if (S.CheckConstraintSatisfaction(Fn->getTrailingRequiresClause(), - Satisfaction)) + if (S.CheckFunctionConstraints(Fn, Satisfaction)) break; S.DiagnoseUnsatisfiedConstraint(Satisfaction); } diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index d6c3af9e84c80..ff64810062801 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -2838,6 +2838,9 @@ static void DiagnoseForRangeConstVariableCopies(Sema &SemaRef, /// Suggest "const foo &x" to prevent the copy. static void DiagnoseForRangeVariableCopies(Sema &SemaRef, const CXXForRangeStmt *ForStmt) { + if (SemaRef.inTemplateInstantiation()) + return; + if (SemaRef.Diags.isIgnored(diag::warn_for_range_const_reference_copy, ForStmt->getBeginLoc()) && SemaRef.Diags.isIgnored(diag::warn_for_range_variable_always_copy, @@ -2860,6 +2863,9 @@ static void DiagnoseForRangeVariableCopies(Sema &SemaRef, if (!InitExpr) return; + if (InitExpr->getExprLoc().isMacroID()) + return; + if (VariableType->isReferenceType()) { DiagnoseForRangeReferenceVariableCopies(SemaRef, VD, ForStmt->getRangeInit()->getType()); diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 1184446796eba..c38c724ed9b06 100755 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -46,6 +46,48 @@ clang::getTemplateParamsRange(TemplateParameterList const * const *Ps, return SourceRange(Ps[0]->getTemplateLoc(), Ps[N-1]->getRAngleLoc()); } +unsigned Sema::getTemplateDepth(Scope *S) const { + unsigned Depth = 0; + + // Each template parameter scope represents one level of template parameter + // depth. + for (Scope *TempParamScope = S->getTemplateParamParent(); + TempParamScope && !Depth; + TempParamScope = TempParamScope->getParent()->getTemplateParamParent()) { + ++Depth; + } + + // Note that there are template parameters with the given depth. + auto ParamsAtDepth = [&](unsigned D) { Depth = std::max(Depth, D + 1); }; + + // Look for parameters of an enclosing generic lambda. We don't create a + // template parameter scope for these. + for (FunctionScopeInfo *FSI : getFunctionScopes()) { + if (auto *LSI = dyn_cast(FSI)) { + if (!LSI->TemplateParams.empty()) { + ParamsAtDepth(LSI->AutoTemplateParameterDepth); + break; + } + if (LSI->GLTemplateParameterList) { + ParamsAtDepth(LSI->GLTemplateParameterList->getDepth()); + break; + } + } + } + + // Look for parameters of an enclosing terse function template. We don't + // create a template parameter scope for these either. + for (const InventedTemplateParameterInfo &Info : + getInventedParameterInfos()) { + if (!Info.TemplateParams.empty()) { + ParamsAtDepth(Info.AutoTemplateParameterDepth); + break; + } + } + + return Depth; +} + /// \brief Determine whether the declaration found is acceptable as the name /// of a template and, if so, return that template declaration. Otherwise, /// returns null. @@ -132,7 +174,8 @@ TemplateNameKind Sema::isTemplateName(Scope *S, ParsedType ObjectTypePtr, bool EnteringContext, TemplateTy &TemplateResult, - bool &MemberOfUnknownSpecialization) { + bool &MemberOfUnknownSpecialization, + bool Disambiguation) { assert(getLangOpts().CPlusPlus && "No template names in C!"); DeclarationName TName; @@ -162,7 +205,7 @@ TemplateNameKind Sema::isTemplateName(Scope *S, LookupResult R(*this, TName, Name.getBeginLoc(), LookupOrdinaryName); if (LookupTemplateName(R, S, SS, ObjectType, EnteringContext, MemberOfUnknownSpecialization, SourceLocation(), - &AssumedTemplate)) + &AssumedTemplate, Disambiguation)) return TNK_Non_template; if (AssumedTemplate != AssumedTemplateKind::None) { @@ -329,7 +372,8 @@ bool Sema::LookupTemplateName(LookupResult &Found, bool EnteringContext, bool &MemberOfUnknownSpecialization, SourceLocation TemplateKWLoc, - AssumedTemplateKind *ATK) { + AssumedTemplateKind *ATK, + bool Disambiguation) { if (ATK) *ATK = AssumedTemplateKind::None; @@ -452,8 +496,9 @@ bool Sema::LookupTemplateName(LookupResult &Found, } } - if (Found.empty() && !IsDependent) { - // If we did not find any names, attempt to correct any typos. + if (Found.empty() && !IsDependent && !Disambiguation) { + // If we did not find any names, and this is not a disambiguation, attempt + // to correct any typos. DeclarationName Name = Found.getLookupName(); Found.clear(); // Simple filter callback that, for keywords, only accepts the C++ *_cast @@ -1050,7 +1095,8 @@ makeTemplateArgumentListInfo(Sema &S, TemplateIdAnnotation &TemplateId) { return TemplateArgs; } -bool Sema::ActOnTypeConstraint(TemplateIdAnnotation *TypeConstr, +bool Sema::ActOnTypeConstraint(const CXXScopeSpec &SS, + TemplateIdAnnotation *TypeConstr, TemplateTypeParmDecl *ConstrainedParameter, SourceLocation EllipsisLoc) { ConceptDecl *CD = @@ -1080,14 +1126,57 @@ bool Sema::ActOnTypeConstraint(TemplateIdAnnotation *TypeConstr, makeTemplateArgumentListInfo(*this, *TypeConstr); } return AttachTypeConstraint( - TypeConstr->SS.isSet() ? TypeConstr->SS.getWithLocInContext(Context) : - NestedNameSpecifierLoc(), + SS.isSet() ? SS.getWithLocInContext(Context) : NestedNameSpecifierLoc(), DeclarationNameInfo(DeclarationName(TypeConstr->Name), TypeConstr->TemplateNameLoc), CD, TypeConstr->LAngleLoc.isValid() ? &TemplateArgs : nullptr, ConstrainedParameter, EllipsisLoc); } +template +static ExprResult formImmediatelyDeclaredConstraint( + Sema &S, NestedNameSpecifierLoc NS, DeclarationNameInfo NameInfo, + ConceptDecl *NamedConcept, SourceLocation LAngleLoc, + SourceLocation RAngleLoc, QualType ConstrainedType, + SourceLocation ParamNameLoc, ArgumentLocAppender Appender, + SourceLocation EllipsisLoc) { + + TemplateArgumentListInfo ConstraintArgs; + ConstraintArgs.addArgument( + S.getTrivialTemplateArgumentLoc(TemplateArgument(ConstrainedType), + /*NTTPType=*/QualType(), ParamNameLoc)); + + ConstraintArgs.setRAngleLoc(RAngleLoc); + ConstraintArgs.setLAngleLoc(LAngleLoc); + Appender(ConstraintArgs); + + // C++2a [temp.param]p4: + // [...] This constraint-expression E is called the immediately-declared + // constraint of T. [...] + CXXScopeSpec SS; + SS.Adopt(NS); + ExprResult ImmediatelyDeclaredConstraint = S.CheckConceptTemplateId( + SS, /*TemplateKWLoc=*/SourceLocation(), NameInfo, + /*FoundDecl=*/NamedConcept, NamedConcept, &ConstraintArgs); + if (ImmediatelyDeclaredConstraint.isInvalid() || !EllipsisLoc.isValid()) + return ImmediatelyDeclaredConstraint; + + // C++2a [temp.param]p4: + // [...] If T is not a pack, then E is E', otherwise E is (E' && ...). + // + // We have the following case: + // + // template concept C1 = true; + // template struct s1; + // + // The constraint: (C1 && ...) + return S.BuildCXXFoldExpr(/*LParenLoc=*/SourceLocation(), + ImmediatelyDeclaredConstraint.get(), BO_LAnd, + EllipsisLoc, /*RHS=*/nullptr, + /*RParenLoc=*/SourceLocation(), + /*NumExpansions=*/None); +} + /// Attach a type-constraint to a template parameter. /// \returns true if an error occured. This can happen if the /// immediately-declared constraint could not be formed (e.g. incorrect number @@ -1106,51 +1195,21 @@ bool Sema::AttachTypeConstraint(NestedNameSpecifierLoc NS, *TemplateArgs) : nullptr; QualType ParamAsArgument(ConstrainedParameter->getTypeForDecl(), 0); - TemplateArgumentListInfo ConstraintArgs; - ConstraintArgs.addArgument( - TemplateArgumentLoc( - TemplateArgument(ParamAsArgument), - TemplateArgumentLocInfo( - Context.getTrivialTypeSourceInfo(ParamAsArgument, - ConstrainedParameter->getLocation())))); - if (TemplateArgs) { - ConstraintArgs.setRAngleLoc(TemplateArgs->getRAngleLoc()); - ConstraintArgs.setLAngleLoc(TemplateArgs->getLAngleLoc()); - for (const TemplateArgumentLoc &ArgLoc : TemplateArgs->arguments()) - ConstraintArgs.addArgument(ArgLoc); - } - // C++2a [temp.param]p4: - // [...] This constraint-expression E is called the immediately-declared - // constraint of T. [...] - CXXScopeSpec SS; - SS.Adopt(NS); - ExprResult ImmediatelyDeclaredConstraint = CheckConceptTemplateId(SS, - /*TemplateKWLoc=*/SourceLocation(), NameInfo, /*FoundDecl=*/NamedConcept, - NamedConcept, &ConstraintArgs); + ExprResult ImmediatelyDeclaredConstraint = + formImmediatelyDeclaredConstraint( + *this, NS, NameInfo, NamedConcept, + TemplateArgs ? TemplateArgs->getLAngleLoc() : SourceLocation(), + TemplateArgs ? TemplateArgs->getRAngleLoc() : SourceLocation(), + ParamAsArgument, ConstrainedParameter->getLocation(), + [&] (TemplateArgumentListInfo &ConstraintArgs) { + if (TemplateArgs) + for (const auto &ArgLoc : TemplateArgs->arguments()) + ConstraintArgs.addArgument(ArgLoc); + }, EllipsisLoc); if (ImmediatelyDeclaredConstraint.isInvalid()) return true; - if (ConstrainedParameter->isParameterPack()) { - // C++2a [temp.param]p4: - // [...] If T is not a pack, then E is E', otherwise E is (E' && ...). - // - // We have the following case: - // - // template concept C1 = true; - // template struct s1; - // - // The constraint: (C1 && ...) - ImmediatelyDeclaredConstraint = - BuildCXXFoldExpr(/*LParenLoc=*/SourceLocation(), - ImmediatelyDeclaredConstraint.get(), BO_LAnd, - EllipsisLoc, /*RHS=*/nullptr, - /*RParenLoc=*/SourceLocation(), - /*NumExpansions=*/None).get(); - if (ImmediatelyDeclaredConstraint.isInvalid()) - return true; - } - ConstrainedParameter->setTypeConstraint(NS, NameInfo, /*FoundDecl=*/NamedConcept, NamedConcept, ArgsAsWritten, @@ -1158,6 +1217,38 @@ bool Sema::AttachTypeConstraint(NestedNameSpecifierLoc NS, return false; } +bool Sema::AttachTypeConstraint(AutoTypeLoc TL, NonTypeTemplateParmDecl *NTTP, + SourceLocation EllipsisLoc) { + if (NTTP->getType() != TL.getType() || + TL.getAutoKeyword() != AutoTypeKeyword::Auto) { + Diag(NTTP->getTypeSourceInfo()->getTypeLoc().getBeginLoc(), + diag::err_unsupported_placeholder_constraint) + << NTTP->getTypeSourceInfo()->getTypeLoc().getSourceRange(); + return true; + } + // FIXME: Concepts: This should be the type of the placeholder, but this is + // unclear in the wording right now. + DeclRefExpr *Ref = BuildDeclRefExpr(NTTP, NTTP->getType(), VK_RValue, + NTTP->getLocation()); + if (!Ref) + return true; + ExprResult ImmediatelyDeclaredConstraint = + formImmediatelyDeclaredConstraint( + *this, TL.getNestedNameSpecifierLoc(), TL.getConceptNameInfo(), + TL.getNamedConcept(), TL.getLAngleLoc(), TL.getRAngleLoc(), + BuildDecltypeType(Ref, NTTP->getLocation()), NTTP->getLocation(), + [&] (TemplateArgumentListInfo &ConstraintArgs) { + for (unsigned I = 0, C = TL.getNumArgs(); I != C; ++I) + ConstraintArgs.addArgument(TL.getArgLoc(I)); + }, EllipsisLoc); + if (ImmediatelyDeclaredConstraint.isInvalid() || + !ImmediatelyDeclaredConstraint.isUsable()) + return true; + + NTTP->setPlaceholderTypeConstraint(ImmediatelyDeclaredConstraint.get()); + return false; +} + /// Check that the type of a non-type template parameter is /// well-formed. /// @@ -1319,6 +1410,11 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, TInfo); Param->setAccess(AS_public); + if (AutoTypeLoc TL = TInfo->getTypeLoc().getContainedAutoTypeLoc()) + if (TL.isConstrained()) + if (AttachTypeConstraint(TL, Param, D.getEllipsisLoc())) + Invalid = true; + if (Invalid) Param->setInvalidDecl(); @@ -1996,12 +2092,14 @@ struct ConvertConstructorToDeductionGuideTransform { if (const auto *TC = TTP->getTypeConstraint()) { TemplateArgumentListInfo TransformedArgs; const auto *ArgsAsWritten = TC->getTemplateArgsAsWritten(); - if (SemaRef.Subst(ArgsAsWritten->getTemplateArgs(), + if (!ArgsAsWritten || + SemaRef.Subst(ArgsAsWritten->getTemplateArgs(), ArgsAsWritten->NumTemplateArgs, TransformedArgs, Args)) SemaRef.AttachTypeConstraint( TC->getNestedNameSpecifierLoc(), TC->getConceptNameInfo(), - TC->getNamedConcept(), &TransformedArgs, NewTTP, + TC->getNamedConcept(), ArgsAsWritten ? &TransformedArgs : nullptr, + NewTTP, NewTTP->isParameterPack() ? cast(TC->getImmediatelyDeclaredConstraint()) ->getEllipsisLoc() @@ -2120,9 +2218,15 @@ struct ConvertConstructorToDeductionGuideTransform { // constructor. ExprResult NewDefArg; if (OldParam->hasDefaultArg()) { - NewDefArg = SemaRef.SubstExpr(OldParam->getDefaultArg(), Args); - if (NewDefArg.isInvalid()) - return nullptr; + // We don't care what the value is (we won't use it); just create a + // placeholder to indicate there is a default argument. + QualType ParamTy = NewDI->getType(); + NewDefArg = new (SemaRef.Context) + OpaqueValueExpr(OldParam->getDefaultArg()->getBeginLoc(), + ParamTy.getNonLValueExprType(SemaRef.Context), + ParamTy->isLValueReferenceType() ? VK_LValue : + ParamTy->isRValueReferenceType() ? VK_XValue : + VK_RValue); } ParmVarDecl *NewParam = ParmVarDecl::Create(SemaRef.Context, DC, @@ -2762,7 +2866,7 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( SourceLocation DeclStartLoc, SourceLocation DeclLoc, const CXXScopeSpec &SS, TemplateIdAnnotation *TemplateId, ArrayRef ParamLists, bool IsFriend, - bool &IsMemberSpecialization, bool &Invalid) { + bool &IsMemberSpecialization, bool &Invalid, bool SuppressDiagnostic) { IsMemberSpecialization = false; Invalid = false; @@ -2870,8 +2974,9 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( auto CheckExplicitSpecialization = [&](SourceRange Range, bool Recovery) { if (SawNonEmptyTemplateParameterList) { - Diag(DeclLoc, diag::err_specialize_member_of_template) - << !Recovery << Range; + if (!SuppressDiagnostic) + Diag(DeclLoc, diag::err_specialize_member_of_template) + << !Recovery << Range; Invalid = true; IsMemberSpecialization = false; return true; @@ -2892,9 +2997,10 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( else ExpectedTemplateLoc = DeclStartLoc; - Diag(DeclLoc, diag::err_template_spec_needs_header) - << Range - << FixItHint::CreateInsertion(ExpectedTemplateLoc, "template<> "); + if (!SuppressDiagnostic) + Diag(DeclLoc, diag::err_template_spec_needs_header) + << Range + << FixItHint::CreateInsertion(ExpectedTemplateLoc, "template<> "); return false; }; @@ -2984,12 +3090,13 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( if (ParamIdx < ParamLists.size()) { if (ParamLists[ParamIdx]->size() > 0) { // The header has template parameters when it shouldn't. Complain. - Diag(ParamLists[ParamIdx]->getTemplateLoc(), - diag::err_template_param_list_matches_nontemplate) - << T - << SourceRange(ParamLists[ParamIdx]->getLAngleLoc(), - ParamLists[ParamIdx]->getRAngleLoc()) - << getRangeOfTypeInNestedNameSpecifier(Context, T, SS); + if (!SuppressDiagnostic) + Diag(ParamLists[ParamIdx]->getTemplateLoc(), + diag::err_template_param_list_matches_nontemplate) + << T + << SourceRange(ParamLists[ParamIdx]->getLAngleLoc(), + ParamLists[ParamIdx]->getRAngleLoc()) + << getRangeOfTypeInNestedNameSpecifier(Context, T, SS); Invalid = true; return nullptr; } @@ -3025,7 +3132,7 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( if (ExpectedTemplateParams && !TemplateParameterListsAreEqual(ParamLists[ParamIdx], ExpectedTemplateParams, - true, TPL_TemplateMatch)) + !SuppressDiagnostic, TPL_TemplateMatch)) Invalid = true; if (!Invalid && @@ -3037,9 +3144,10 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( continue; } - Diag(DeclLoc, diag::err_template_spec_needs_template_parameters) - << T - << getRangeOfTypeInNestedNameSpecifier(Context, T, SS); + if (!SuppressDiagnostic) + Diag(DeclLoc, diag::err_template_spec_needs_template_parameters) + << T + << getRangeOfTypeInNestedNameSpecifier(Context, T, SS); Invalid = true; continue; } @@ -3075,16 +3183,18 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( AllExplicitSpecHeaders = false; } - Diag(ParamLists[ParamIdx]->getTemplateLoc(), - AllExplicitSpecHeaders ? diag::warn_template_spec_extra_headers - : diag::err_template_spec_extra_headers) - << SourceRange(ParamLists[ParamIdx]->getTemplateLoc(), - ParamLists[ParamLists.size() - 2]->getRAngleLoc()); + if (!SuppressDiagnostic) + Diag(ParamLists[ParamIdx]->getTemplateLoc(), + AllExplicitSpecHeaders ? diag::warn_template_spec_extra_headers + : diag::err_template_spec_extra_headers) + << SourceRange(ParamLists[ParamIdx]->getTemplateLoc(), + ParamLists[ParamLists.size() - 2]->getRAngleLoc()); // If there was a specialization somewhere, such that 'template<>' is // not required, and there were any 'template<>' headers, note where the // specialization occurred. - if (ExplicitSpecLoc.isValid() && HasAnyExplicitSpecHeader) + if (ExplicitSpecLoc.isValid() && HasAnyExplicitSpecHeader && + !SuppressDiagnostic) Diag(ExplicitSpecLoc, diag::note_explicit_template_spec_does_not_need_header) << NestedTypes.back(); @@ -4044,7 +4154,7 @@ DeclResult Sema::ActOnVarTemplateSpecialization( if (isSameAsPrimaryTemplate(VarTemplate->getTemplateParameters(), Converted) && - (!Context.getLangOpts().ConceptsTS || + (!Context.getLangOpts().CPlusPlus2a || !TemplateParams->hasAssociatedConstraints())) { // C++ [temp.class.spec]p9b3: // @@ -6530,7 +6640,12 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, DeductionArg = PE->getPattern(); if (DeduceAutoType( Context.getTrivialTypeSourceInfo(ParamType, Param->getLocation()), - DeductionArg, ParamType, Depth) == DAR_Failed) { + DeductionArg, ParamType, Depth, + // We do not check constraints right now because the + // immediately-declared constraint of the auto type is also an + // associated constraint, and will be checked along with the other + // associated constraints after checking the template argument list. + /*IgnoreConstraints=*/true) == DAR_Failed) { Diag(Arg->getExprLoc(), diag::err_non_type_template_parm_type_deduction_failure) << Param->getDeclName() << Param->getType() << Arg->getType() @@ -7102,6 +7217,11 @@ bool Sema::CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param, // [temp.constr.order]. SmallVector ParamsAC, TemplateAC; Params->getAssociatedConstraints(ParamsAC); + // C++2a[temp.arg.template]p3 + // [...] In this comparison, if P is unconstrained, the constraints on A + // are not considered. + if (ParamsAC.empty()) + return false; Template->getAssociatedConstraints(TemplateAC); bool IsParamAtLeastAsConstrained; if (IsAtLeastAsConstrained(Param, ParamsAC, Template, TemplateAC, @@ -7872,13 +7992,11 @@ bool Sema::CheckTemplatePartialSpecializationArgs( DeclResult Sema::ActOnClassTemplateSpecialization( Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, - SourceLocation ModulePrivateLoc, TemplateIdAnnotation &TemplateId, - const ParsedAttributesView &Attr, + SourceLocation ModulePrivateLoc, CXXScopeSpec &SS, + TemplateIdAnnotation &TemplateId, const ParsedAttributesView &Attr, MultiTemplateParamsArg TemplateParameterLists, SkipBodyInfo *SkipBody) { assert(TUK != TUK_Reference && "References are not specializations"); - CXXScopeSpec &SS = TemplateId.SS; - // NOTE: KWLoc is the location of the tag keyword. This will instead // store the location of the outermost template keyword in the declaration. SourceLocation TemplateKWLoc = TemplateParameterLists.size() > 0 @@ -8048,7 +8166,7 @@ DeclResult Sema::ActOnClassTemplateSpecialization( if (Context.hasSameType(CanonType, ClassTemplate->getInjectedClassNameSpecialization()) && - (!Context.getLangOpts().ConceptsTS || + (!Context.getLangOpts().CPlusPlus2a || !TemplateParams->hasAssociatedConstraints())) { // C++ [temp.class.spec]p9b3: // @@ -10012,24 +10130,12 @@ Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc, << FixItHint::CreateRemoval(TypenameLoc); NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context); + TypeSourceInfo *TSI = nullptr; QualType T = CheckTypenameType(TypenameLoc.isValid()? ETK_Typename : ETK_None, - TypenameLoc, QualifierLoc, II, IdLoc); + TypenameLoc, QualifierLoc, II, IdLoc, &TSI, + /*DeducedTSTContext=*/true); if (T.isNull()) return true; - - TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(T); - if (isa(T)) { - DependentNameTypeLoc TL = TSI->getTypeLoc().castAs(); - TL.setElaboratedKeywordLoc(TypenameLoc); - TL.setQualifierLoc(QualifierLoc); - TL.setNameLoc(IdLoc); - } else { - ElaboratedTypeLoc TL = TSI->getTypeLoc().castAs(); - TL.setElaboratedKeywordLoc(TypenameLoc); - TL.setQualifierLoc(QualifierLoc); - TL.getNamedTypeLoc().castAs().setNameLoc(IdLoc); - } - return CreateParsedType(T, TSI); } @@ -10166,6 +10272,35 @@ static bool isEnableIf(NestedNameSpecifierLoc NNS, const IdentifierInfo &II, return true; } +QualType +Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, + SourceLocation KeywordLoc, + NestedNameSpecifierLoc QualifierLoc, + const IdentifierInfo &II, + SourceLocation IILoc, + TypeSourceInfo **TSI, + bool DeducedTSTContext) { + QualType T = CheckTypenameType(Keyword, KeywordLoc, QualifierLoc, II, IILoc, + DeducedTSTContext); + if (T.isNull()) + return QualType(); + + *TSI = Context.CreateTypeSourceInfo(T); + if (isa(T)) { + DependentNameTypeLoc TL = + (*TSI)->getTypeLoc().castAs(); + TL.setElaboratedKeywordLoc(KeywordLoc); + TL.setQualifierLoc(QualifierLoc); + TL.setNameLoc(IILoc); + } else { + ElaboratedTypeLoc TL = (*TSI)->getTypeLoc().castAs(); + TL.setElaboratedKeywordLoc(KeywordLoc); + TL.setQualifierLoc(QualifierLoc); + TL.getNamedTypeLoc().castAs().setNameLoc(IILoc); + } + return T; +} + /// Build the type that describes a C++ typename specifier, /// e.g., "typename T::type". QualType @@ -10173,32 +10308,38 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, SourceLocation KeywordLoc, NestedNameSpecifierLoc QualifierLoc, const IdentifierInfo &II, - SourceLocation IILoc) { + SourceLocation IILoc, bool DeducedTSTContext) { CXXScopeSpec SS; SS.Adopt(QualifierLoc); - DeclContext *Ctx = computeDeclContext(SS); - if (!Ctx) { - // If the nested-name-specifier is dependent and couldn't be - // resolved to a type, build a typename type. - assert(QualifierLoc.getNestedNameSpecifier()->isDependent()); - return Context.getDependentNameType(Keyword, - QualifierLoc.getNestedNameSpecifier(), - &II); + DeclContext *Ctx = nullptr; + if (QualifierLoc) { + Ctx = computeDeclContext(SS); + if (!Ctx) { + // If the nested-name-specifier is dependent and couldn't be + // resolved to a type, build a typename type. + assert(QualifierLoc.getNestedNameSpecifier()->isDependent()); + return Context.getDependentNameType(Keyword, + QualifierLoc.getNestedNameSpecifier(), + &II); + } + + // If the nested-name-specifier refers to the current instantiation, + // the "typename" keyword itself is superfluous. In C++03, the + // program is actually ill-formed. However, DR 382 (in C++0x CD1) + // allows such extraneous "typename" keywords, and we retroactively + // apply this DR to C++03 code with only a warning. In any case we continue. + + if (RequireCompleteDeclContext(SS, Ctx)) + return QualType(); } - // If the nested-name-specifier refers to the current instantiation, - // the "typename" keyword itself is superfluous. In C++03, the - // program is actually ill-formed. However, DR 382 (in C++0x CD1) - // allows such extraneous "typename" keywords, and we retroactively - // apply this DR to C++03 code with only a warning. In any case we continue. - - if (RequireCompleteDeclContext(SS, Ctx)) - return QualType(); - DeclarationName Name(&II); LookupResult Result(*this, Name, IILoc, LookupOrdinaryName); - LookupQualifiedName(Result, Ctx, SS); + if (Ctx) + LookupQualifiedName(Result, Ctx, SS); + else + LookupName(Result, CurScope); unsigned DiagID = 0; Decl *Referenced = nullptr; switch (Result.getResultKind()) { @@ -10207,7 +10348,7 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, // a more specific diagnostic. SourceRange CondRange; Expr *Cond = nullptr; - if (isEnableIf(QualifierLoc, II, CondRange, Cond)) { + if (Ctx && isEnableIf(QualifierLoc, II, CondRange, Cond)) { // If we have a condition, narrow it down to the specific failed // condition. if (Cond) { @@ -10223,12 +10364,14 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, return QualType(); } - Diag(CondRange.getBegin(), diag::err_typename_nested_not_found_enable_if) + Diag(CondRange.getBegin(), + diag::err_typename_nested_not_found_enable_if) << Ctx << CondRange; return QualType(); } - DiagID = diag::err_typename_nested_not_found; + DiagID = Ctx ? diag::err_typename_nested_not_found + : diag::err_unknown_typename; break; } @@ -10294,6 +10437,19 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, // is a placeholder for a deduced class type [...]. if (getLangOpts().CPlusPlus17) { if (auto *TD = getAsTypeTemplateDecl(Result.getFoundDecl())) { + if (!DeducedTSTContext) { + QualType T(QualifierLoc + ? QualifierLoc.getNestedNameSpecifier()->getAsType() + : nullptr, 0); + if (!T.isNull()) + Diag(IILoc, diag::err_dependent_deduced_tst) + << (int)getTemplateNameKindForDiagnostics(TemplateName(TD)) << T; + else + Diag(IILoc, diag::err_deduced_tst) + << (int)getTemplateNameKindForDiagnostics(TemplateName(TD)); + Diag(TD->getLocation(), diag::note_template_decl_here); + return QualType(); + } return Context.getElaboratedType( Keyword, QualifierLoc.getNestedNameSpecifier(), Context.getDeducedTemplateSpecializationType(TemplateName(TD), @@ -10301,12 +10457,14 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, } } - DiagID = diag::err_typename_nested_not_type; + DiagID = Ctx ? diag::err_typename_nested_not_type + : diag::err_typename_not_type; Referenced = Result.getFoundDecl(); break; case LookupResult::FoundOverloaded: - DiagID = diag::err_typename_nested_not_type; + DiagID = Ctx ? diag::err_typename_nested_not_type + : diag::err_typename_not_type; Referenced = *Result.begin(); break; @@ -10318,9 +10476,14 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, // type. Emit an appropriate diagnostic and return an error. SourceRange FullRange(KeywordLoc.isValid() ? KeywordLoc : SS.getBeginLoc(), IILoc); - Diag(IILoc, DiagID) << FullRange << Name << Ctx; + if (Ctx) + Diag(IILoc, DiagID) << FullRange << Name << Ctx; + else + Diag(IILoc, DiagID) << FullRange << Name; if (Referenced) - Diag(Referenced->getLocation(), diag::note_typename_refers_here) + Diag(Referenced->getLocation(), + Ctx ? diag::note_typename_member_refers_here + : diag::note_typename_refers_here) << Name; return QualType(); } diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index 1b9f1b2144d1a..1e321d6379104 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -724,38 +724,48 @@ class PackDeductionScope { // Compute the set of template parameter indices that correspond to // parameter packs expanded by the pack expansion. llvm::SmallBitVector SawIndices(TemplateParams->size()); + llvm::SmallVector ExtraDeductions; auto AddPack = [&](unsigned Index) { if (SawIndices[Index]) return; SawIndices[Index] = true; addPack(Index); + + // Deducing a parameter pack that is a pack expansion also constrains the + // packs appearing in that parameter to have the same deduced arity. Also, + // in C++17 onwards, deducing a non-type template parameter deduces its + // type, so we need to collect the pending deduced values for those packs. + if (auto *NTTP = dyn_cast( + TemplateParams->getParam(Index))) { + if (auto *Expansion = dyn_cast(NTTP->getType())) + ExtraDeductions.push_back(Expansion->getPattern()); + } + // FIXME: Also collect the unexpanded packs in any type and template + // parameter packs that are pack expansions. }; - // First look for unexpanded packs in the pattern. - SmallVector Unexpanded; - S.collectUnexpandedParameterPacks(Pattern, Unexpanded); - for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) { - unsigned Depth, Index; - std::tie(Depth, Index) = getDepthAndIndex(Unexpanded[I]); - if (Depth == Info.getDeducedDepth()) - AddPack(Index); - } + auto Collect = [&](TemplateArgument Pattern) { + SmallVector Unexpanded; + S.collectUnexpandedParameterPacks(Pattern, Unexpanded); + for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) { + unsigned Depth, Index; + std::tie(Depth, Index) = getDepthAndIndex(Unexpanded[I]); + if (Depth == Info.getDeducedDepth()) + AddPack(Index); + } + }; + + // Look for unexpanded packs in the pattern. + Collect(Pattern); assert(!Packs.empty() && "Pack expansion without unexpanded packs?"); unsigned NumNamedPacks = Packs.size(); - // We can also have deduced template parameters that do not actually - // appear in the pattern, but can be deduced by it (the type of a non-type - // template parameter pack, in particular). These won't have prevented us - // from partially expanding the pack. - llvm::SmallBitVector Used(TemplateParams->size()); - MarkUsedTemplateParameters(S.Context, Pattern, /*OnlyDeduced*/true, - Info.getDeducedDepth(), Used); - for (int Index = Used.find_first(); Index != -1; - Index = Used.find_next(Index)) - if (TemplateParams->getParam(Index)->isParameterPack()) - AddPack(Index); + // Also look for unexpanded packs that are indirectly deduced by deducing + // the sizes of the packs in this pattern. + while (!ExtraDeductions.empty()) + Collect(ExtraDeductions.pop_back_val()); return NumNamedPacks; } @@ -1808,7 +1818,7 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, // If this is a base class, try to perform template argument // deduction from it. if (NextT != RecordT) { - TemplateDeductionInfo BaseInfo(Info.getLocation()); + TemplateDeductionInfo BaseInfo(TemplateDeductionInfo::ForBase, Info); Sema::TemplateDeductionResult BaseResult = DeduceTemplateArguments(S, TemplateParams, SpecParam, QualType(NextT, 0), BaseInfo, Deduced); @@ -2478,7 +2488,7 @@ Sema::getTrivialTemplateArgumentLoc(const TemplateArgument &Arg, case TemplateArgument::Template: case TemplateArgument::TemplateExpansion: { NestedNameSpecifierLocBuilder Builder; - TemplateName Template = Arg.getAsTemplate(); + TemplateName Template = Arg.getAsTemplateOrTemplatePattern(); if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) Builder.MakeTrivial(Context, DTN->getQualifier(), Loc); else if (QualifiedTemplateName *QTN = @@ -2504,27 +2514,10 @@ Sema::getTrivialTemplateArgumentLoc(const TemplateArgument &Arg, } TemplateArgumentLoc -Sema::getIdentityTemplateArgumentLoc(Decl *TemplateParm, +Sema::getIdentityTemplateArgumentLoc(NamedDecl *TemplateParm, SourceLocation Location) { - if (auto *TTP = dyn_cast(TemplateParm)) - return getTrivialTemplateArgumentLoc( - TemplateArgument( - Context.getTemplateTypeParmType(TTP->getDepth(), TTP->getIndex(), - TTP->isParameterPack(), TTP)), - QualType(), Location.isValid() ? Location : TTP->getLocation()); - else if (auto *TTP = dyn_cast(TemplateParm)) - return getTrivialTemplateArgumentLoc(TemplateArgument(TemplateName(TTP)), - QualType(), - Location.isValid() ? Location : - TTP->getLocation()); - auto *NTTP = cast(TemplateParm); - CXXScopeSpec SS; - DeclarationNameInfo Info(NTTP->getDeclName(), - Location.isValid() ? Location : NTTP->getLocation()); - Expr *E = BuildDeclarationNameExpr(SS, Info, NTTP).get(); - return getTrivialTemplateArgumentLoc(TemplateArgument(E), NTTP->getType(), - Location.isValid() ? Location : - NTTP->getLocation()); + return getTrivialTemplateArgumentLoc( + Context.getInjectedTemplateArg(TemplateParm), QualType(), Location); } /// Convert the given deduced template argument and add it to the set of @@ -3446,13 +3439,16 @@ Sema::TemplateDeductionResult Sema::FinishTemplateArgumentDeduction( // ([temp.constr.decl]), those constraints are checked for satisfaction // ([temp.constr.constr]). If the constraints are not satisfied, type // deduction fails. - if (CheckInstantiatedFunctionTemplateConstraints(Info.getLocation(), - Specialization, Builder, Info.AssociatedConstraintsSatisfaction)) - return TDK_MiscellaneousDeductionFailure; + if (!PartialOverloading || + (Builder.size() == FunctionTemplate->getTemplateParameters()->size())) { + if (CheckInstantiatedFunctionTemplateConstraints(Info.getLocation(), + Specialization, Builder, Info.AssociatedConstraintsSatisfaction)) + return TDK_MiscellaneousDeductionFailure; - if (!Info.AssociatedConstraintsSatisfaction.IsSatisfied) { - Info.reset(TemplateArgumentList::CreateCopy(Context, Builder)); - return TDK_ConstraintsNotSatisfied; + if (!Info.AssociatedConstraintsSatisfaction.IsSatisfied) { + Info.reset(TemplateArgumentList::CreateCopy(Context, Builder)); + return TDK_ConstraintsNotSatisfied; + } } if (OriginalCallArgs) { @@ -4404,9 +4400,10 @@ namespace { QualType Result = SemaRef.Context.getAutoType( Replacement, TL.getTypePtr()->getKeyword(), Replacement.isNull(), - ReplacementIsPack); + ReplacementIsPack, TL.getTypePtr()->getTypeConstraintConcept(), + TL.getTypePtr()->getTypeConstraintArguments()); auto NewTL = TLB.push(Result); - NewTL.setNameLoc(TL.getNameLoc()); + NewTL.copy(TL); return Result; } @@ -4441,9 +4438,10 @@ namespace { Sema::DeduceAutoResult Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init, QualType &Result, - Optional DependentDeductionDepth) { + Optional DependentDeductionDepth, + bool IgnoreConstraints) { return DeduceAutoType(Type->getTypeLoc(), Init, Result, - DependentDeductionDepth); + DependentDeductionDepth, IgnoreConstraints); } /// Attempt to produce an informative diagostic explaining why auto deduction @@ -4471,6 +4469,49 @@ static bool diagnoseAutoDeductionFailure(Sema &S, } } +static Sema::DeduceAutoResult +CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type, + AutoTypeLoc TypeLoc, QualType Deduced) { + ConstraintSatisfaction Satisfaction; + ConceptDecl *Concept = Type.getTypeConstraintConcept(); + TemplateArgumentListInfo TemplateArgs(TypeLoc.getLAngleLoc(), + TypeLoc.getRAngleLoc()); + TemplateArgs.addArgument( + TemplateArgumentLoc(TemplateArgument(Deduced), + S.Context.getTrivialTypeSourceInfo( + Deduced, TypeLoc.getNameLoc()))); + for (unsigned I = 0, C = TypeLoc.getNumArgs(); I != C; ++I) + TemplateArgs.addArgument(TypeLoc.getArgLoc(I)); + + llvm::SmallVector Converted; + if (S.CheckTemplateArgumentList(Concept, SourceLocation(), TemplateArgs, + /*PartialTemplateArgs=*/false, Converted)) + return Sema::DAR_FailedAlreadyDiagnosed; + if (S.CheckConstraintSatisfaction(Concept, {Concept->getConstraintExpr()}, + Converted, TypeLoc.getLocalSourceRange(), + Satisfaction)) + return Sema::DAR_FailedAlreadyDiagnosed; + if (!Satisfaction.IsSatisfied) { + std::string Buf; + llvm::raw_string_ostream OS(Buf); + OS << "'" << Concept->getName(); + if (TypeLoc.hasExplicitTemplateArgs()) { + OS << "<"; + for (const auto &Arg : Type.getTypeConstraintArguments()) + Arg.print(S.getPrintingPolicy(), OS); + OS << ">"; + } + OS << "'"; + OS.flush(); + S.Diag(TypeLoc.getConceptNameLoc(), + diag::err_placeholder_constraints_not_satisfied) + << Deduced << Buf << TypeLoc.getLocalSourceRange(); + S.DiagnoseUnsatisfiedConstraint(Satisfaction); + return Sema::DAR_FailedAlreadyDiagnosed; + } + return Sema::DAR_Succeeded; +} + /// Deduce the type for an auto type-specifier (C++11 [dcl.spec.auto]p6) /// /// Note that this is done even if the initializer is dependent. (This is @@ -4485,9 +4526,12 @@ static bool diagnoseAutoDeductionFailure(Sema &S, /// dependent cases. This is necessary for template partial ordering with /// 'auto' template parameters. The value specified is the template /// parameter depth at which we should perform 'auto' deduction. +/// \param IgnoreConstraints Set if we should not fail if the deduced type does +/// not satisfy the type-constraint in the auto type. Sema::DeduceAutoResult Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result, - Optional DependentDeductionDepth) { + Optional DependentDeductionDepth, + bool IgnoreConstraints) { if (Init->getType()->isNonOverloadPlaceholderType()) { ExprResult NonPlaceholder = CheckPlaceholderExpr(Init); if (NonPlaceholder.isInvalid()) @@ -4528,6 +4572,14 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result, return DAR_FailedAlreadyDiagnosed; // FIXME: Support a non-canonical deduced type for 'auto'. Deduced = Context.getCanonicalType(Deduced); + if (AT->isConstrained() && !IgnoreConstraints) { + auto ConstraintsResult = + CheckDeducedPlaceholderConstraints(*this, *AT, + Type.getContainedAutoTypeLoc(), + Deduced); + if (ConstraintsResult != DAR_Succeeded) + return ConstraintsResult; + } Result = SubstituteDeducedTypeTransform(*this, Deduced).Apply(Type); if (Result.isNull()) return DAR_FailedAlreadyDiagnosed; @@ -4635,6 +4687,17 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result, return DAR_FailedAlreadyDiagnosed; } + if (const auto *AT = Type.getType()->getAs()) { + if (AT->isConstrained() && !IgnoreConstraints) { + auto ConstraintsResult = + CheckDeducedPlaceholderConstraints(*this, *AT, + Type.getContainedAutoTypeLoc(), + DeducedType); + if (ConstraintsResult != DAR_Succeeded) + return ConstraintsResult; + } + } + Result = SubstituteDeducedTypeTransform(*this, DeducedType).Apply(Type); if (Result.isNull()) return DAR_FailedAlreadyDiagnosed; diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index af41e231134d0..b5d2ab1f31f27 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -18,6 +18,7 @@ #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/PrettyDeclStackTrace.h" +#include "clang/AST/TypeVisitor.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/Stack.h" #include "clang/Sema/DeclSpec.h" @@ -26,6 +27,7 @@ #include "clang/Sema/Template.h" #include "clang/Sema/TemplateDeduction.h" #include "clang/Sema/TemplateInstCallback.h" +#include "clang/Sema/SemaConcept.h" #include "llvm/Support/TimeProfiler.h" using namespace clang; @@ -199,8 +201,10 @@ bool Sema::CodeSynthesisContext::isInstantiationRecord() const { case DeducedTemplateArgumentSubstitution: case PriorTemplateArgumentSubstitution: case ConstraintsCheck: + case NestedRequirementConstraintsCheck: return true; + case RequirementInstantiation: case DefaultTemplateArgumentChecking: case DeclaringSpecialMember: case DeclaringImplicitEqualityComparison: @@ -247,7 +251,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate( Inst.InstantiationRange = InstantiationRange; SemaRef.pushCodeSynthesisContext(Inst); - AlreadyInstantiating = + AlreadyInstantiating = !Inst.Entity ? false : !SemaRef.InstantiatingSpecializations .insert(std::make_pair(Inst.Entity->getCanonicalDecl(), Inst.Kind)) .second; @@ -364,6 +368,26 @@ Sema::InstantiatingTemplate::InstantiatingTemplate( PointOfInstantiation, InstantiationRange, Param, Template, TemplateArgs) {} +Sema::InstantiatingTemplate::InstantiatingTemplate( + Sema &SemaRef, SourceLocation PointOfInstantiation, + concepts::Requirement *Req, sema::TemplateDeductionInfo &DeductionInfo, + SourceRange InstantiationRange) + : InstantiatingTemplate( + SemaRef, CodeSynthesisContext::RequirementInstantiation, + PointOfInstantiation, InstantiationRange, /*Entity=*/nullptr, + /*Template=*/nullptr, /*TemplateArgs=*/None, &DeductionInfo) {} + + +Sema::InstantiatingTemplate::InstantiatingTemplate( + Sema &SemaRef, SourceLocation PointOfInstantiation, + concepts::NestedRequirement *Req, ConstraintsCheck, + SourceRange InstantiationRange) + : InstantiatingTemplate( + SemaRef, CodeSynthesisContext::NestedRequirementConstraintsCheck, + PointOfInstantiation, InstantiationRange, /*Entity=*/nullptr, + /*Template=*/nullptr, /*TemplateArgs=*/None) {} + + Sema::InstantiatingTemplate::InstantiatingTemplate( Sema &SemaRef, SourceLocation PointOfInstantiation, ConstraintsCheck, NamedDecl *Template, @@ -446,8 +470,9 @@ void Sema::InstantiatingTemplate::Clear() { if (!Invalid) { if (!AlreadyInstantiating) { auto &Active = SemaRef.CodeSynthesisContexts.back(); - SemaRef.InstantiatingSpecializations.erase( - std::make_pair(Active.Entity, Active.Kind)); + if (Active.Entity) + SemaRef.InstantiatingSpecializations.erase( + std::make_pair(Active.Entity, Active.Kind)); } atTemplateEnd(SemaRef.TemplateInstCallbacks, SemaRef, @@ -684,6 +709,18 @@ void Sema::PrintInstantiationStack() { << Active->InstantiationRange; break; + case CodeSynthesisContext::RequirementInstantiation: + Diags.Report(Active->PointOfInstantiation, + diag::note_template_requirement_instantiation_here) + << Active->InstantiationRange; + break; + + case CodeSynthesisContext::NestedRequirementConstraintsCheck: + Diags.Report(Active->PointOfInstantiation, + diag::note_nested_requirement_here) + << Active->InstantiationRange; + break; + case CodeSynthesisContext::DeclaringSpecialMember: Diags.Report(Active->PointOfInstantiation, diag::note_in_declaration_of_implicit_special_member) @@ -727,21 +764,30 @@ void Sema::PrintInstantiationStack() { case CodeSynthesisContext::ConstraintsCheck: { unsigned DiagID = 0; + if (!Active->Entity) { + Diags.Report(Active->PointOfInstantiation, + diag::note_nested_requirement_here) + << Active->InstantiationRange; + break; + } if (isa(Active->Entity)) DiagID = diag::note_concept_specialization_here; else if (isa(Active->Entity)) DiagID = diag::note_checking_constraints_for_template_id_here; else if (isa(Active->Entity)) DiagID = diag::note_checking_constraints_for_var_spec_id_here; - else { - assert(isa(Active->Entity)); + else if (isa(Active->Entity)) DiagID = diag::note_checking_constraints_for_class_spec_id_here; + else { + assert(isa(Active->Entity)); + DiagID = diag::note_checking_constraints_for_function_here; } SmallVector TemplateArgsStr; llvm::raw_svector_ostream OS(TemplateArgsStr); cast(Active->Entity)->printName(OS); - printTemplateArgumentList(OS, Active->template_arguments(), - getPrintingPolicy()); + if (!isa(Active->Entity)) + printTemplateArgumentList(OS, Active->template_arguments(), + getPrintingPolicy()); Diags.Report(Active->PointOfInstantiation, DiagID) << OS.str() << Active->InstantiationRange; break; @@ -788,6 +834,7 @@ Optional Sema::isSFINAEContext() const { case CodeSynthesisContext::ConstraintsCheck: case CodeSynthesisContext::ParameterMappingSubstitution: case CodeSynthesisContext::ConstraintNormalization: + case CodeSynthesisContext::NestedRequirementConstraintsCheck: // This is a template instantiation, so there is no SFINAE. return None; @@ -802,9 +849,10 @@ Optional Sema::isSFINAEContext() const { case CodeSynthesisContext::ExplicitTemplateArgumentSubstitution: case CodeSynthesisContext::DeducedTemplateArgumentSubstitution: case CodeSynthesisContext::ConstraintSubstitution: - // We're either substituting explicitly-specified template arguments - // or deduced template arguments or a constraint expression, so SFINAE - // applies. + case CodeSynthesisContext::RequirementInstantiation: + // We're either substituting explicitly-specified template arguments, + // deduced template arguments, a constraint expression or a requirement + // in a requires expression, so SFINAE applies. assert(Active->DeductionInfo && "Missing deduction info pointer"); return Active->DeductionInfo; @@ -874,6 +922,10 @@ namespace { this->Entity = Entity; } + unsigned TransformTemplateDepth(unsigned Depth) { + return TemplateArgs.getNewDepth(Depth); + } + bool TryExpandParameterPacks(SourceLocation EllipsisLoc, SourceRange PatternRange, ArrayRef Unexpanded, @@ -1010,6 +1062,8 @@ namespace { NonTypeTemplateParmDecl *D); ExprResult TransformSubstNonTypeTemplateParmPackExpr( SubstNonTypeTemplateParmPackExpr *E); + ExprResult TransformSubstNonTypeTemplateParmExpr( + SubstNonTypeTemplateParmExpr *E); /// Rebuild a DeclRefExpr for a VarDecl reference. ExprResult RebuildVarDeclRefExpr(VarDecl *PD, SourceLocation Loc); @@ -1056,6 +1110,41 @@ namespace { return TreeTransform::TransformLambdaExpr(E); } + ExprResult TransformRequiresExpr(RequiresExpr *E) { + LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true); + return TreeTransform::TransformRequiresExpr(E); + } + + bool TransformRequiresExprRequirements( + ArrayRef Reqs, + SmallVectorImpl &Transformed) { + bool SatisfactionDetermined = false; + for (concepts::Requirement *Req : Reqs) { + concepts::Requirement *TransReq = nullptr; + if (!SatisfactionDetermined) { + if (auto *TypeReq = dyn_cast(Req)) + TransReq = TransformTypeRequirement(TypeReq); + else if (auto *ExprReq = dyn_cast(Req)) + TransReq = TransformExprRequirement(ExprReq); + else + TransReq = TransformNestedRequirement( + cast(Req)); + if (!TransReq) + return true; + if (!TransReq->isDependent() && !TransReq->isSatisfied()) + // [expr.prim.req]p6 + // [...] The substitution and semantic constraint checking + // proceeds in lexical order and stops when a condition that + // determines the result of the requires-expression is + // encountered. [..] + SatisfactionDetermined = true; + } else + TransReq = Req; + Transformed.push_back(TransReq); + } + return false; + } + TemplateParameterList *TransformTemplateParameterList( TemplateParameterList *OrigTPL) { if (!OrigTPL || !OrigTPL->size()) return OrigTPL; @@ -1065,6 +1154,14 @@ namespace { /* DeclContext *Owner */ Owner, TemplateArgs); return DeclInstantiator.SubstTemplateParams(OrigTPL); } + + concepts::TypeRequirement * + TransformTypeRequirement(concepts::TypeRequirement *Req); + concepts::ExprRequirement * + TransformExprRequirement(concepts::ExprRequirement *Req); + concepts::NestedRequirement * + TransformNestedRequirement(concepts::NestedRequirement *Req); + private: ExprResult transformNonTypeTemplateParmRef(NonTypeTemplateParmDecl *parm, SourceLocation loc, @@ -1445,6 +1542,44 @@ TemplateInstantiator::TransformSubstNonTypeTemplateParmPackExpr( Arg); } +ExprResult +TemplateInstantiator::TransformSubstNonTypeTemplateParmExpr( + SubstNonTypeTemplateParmExpr *E) { + ExprResult SubstReplacement = TransformExpr(E->getReplacement()); + if (SubstReplacement.isInvalid()) + return true; + QualType SubstType = TransformType(E->getType()); + if (SubstType.isNull()) + return true; + // The type may have been previously dependent and not now, which means we + // might have to implicit cast the argument to the new type, for example: + // template + // concept C = sizeof(U) == 4; + // void foo() requires C<2, 'a'> { } + // When normalizing foo(), we first form the normalized constraints of C: + // AtomicExpr(sizeof(U) == 4, + // U=SubstNonTypeTemplateParmExpr(Param=U, + // Expr=DeclRef(U), + // Type=decltype(T))) + // Then we substitute T = 2, U = 'a' into the parameter mapping, and need to + // produce: + // AtomicExpr(sizeof(U) == 4, + // U=SubstNonTypeTemplateParmExpr(Param=U, + // Expr=ImpCast( + // decltype(2), + // SubstNTTPE(Param=U, Expr='a', + // Type=char)), + // Type=decltype(2))) + // The call to CheckTemplateArgument here produces the ImpCast. + TemplateArgument Converted; + if (SemaRef.CheckTemplateArgument(E->getParameter(), SubstType, + SubstReplacement.get(), + Converted).isInvalid()) + return true; + return transformNonTypeTemplateParmRef(E->getParameter(), + E->getExprLoc(), Converted); +} + ExprResult TemplateInstantiator::RebuildVarDeclRefExpr(VarDecl *PD, SourceLocation Loc) { DeclarationNameInfo NameInfo(PD->getDeclName(), Loc); @@ -1669,6 +1804,163 @@ TemplateInstantiator::TransformSubstTemplateTypeParmPackType( return Result; } +template +static concepts::Requirement::SubstitutionDiagnostic * +createSubstDiag(Sema &S, TemplateDeductionInfo &Info, EntityPrinter Printer) { + SmallString<128> Message; + SourceLocation ErrorLoc; + if (Info.hasSFINAEDiagnostic()) { + PartialDiagnosticAt PDA(SourceLocation(), + PartialDiagnostic::NullDiagnostic{}); + Info.takeSFINAEDiagnostic(PDA); + PDA.second.EmitToString(S.getDiagnostics(), Message); + ErrorLoc = PDA.first; + } else { + ErrorLoc = Info.getLocation(); + } + char *MessageBuf = new (S.Context) char[Message.size()]; + std::copy(Message.begin(), Message.end(), MessageBuf); + SmallString<128> Entity; + llvm::raw_svector_ostream OS(Entity); + Printer(OS); + char *EntityBuf = new (S.Context) char[Entity.size()]; + std::copy(Entity.begin(), Entity.end(), EntityBuf); + return new (S.Context) concepts::Requirement::SubstitutionDiagnostic{ + StringRef(EntityBuf, Entity.size()), ErrorLoc, + StringRef(MessageBuf, Message.size())}; +} + +concepts::TypeRequirement * +TemplateInstantiator::TransformTypeRequirement(concepts::TypeRequirement *Req) { + if (!Req->isDependent() && !AlwaysRebuild()) + return Req; + if (Req->isSubstitutionFailure()) { + if (AlwaysRebuild()) + return RebuildTypeRequirement( + Req->getSubstitutionDiagnostic()); + return Req; + } + + Sema::SFINAETrap Trap(SemaRef); + TemplateDeductionInfo Info(Req->getType()->getTypeLoc().getBeginLoc()); + Sema::InstantiatingTemplate TypeInst(SemaRef, + Req->getType()->getTypeLoc().getBeginLoc(), Req, Info, + Req->getType()->getTypeLoc().getSourceRange()); + if (TypeInst.isInvalid()) + return nullptr; + TypeSourceInfo *TransType = TransformType(Req->getType()); + if (!TransType || Trap.hasErrorOccurred()) + return RebuildTypeRequirement(createSubstDiag(SemaRef, Info, + [&] (llvm::raw_ostream& OS) { + Req->getType()->getType().print(OS, SemaRef.getPrintingPolicy()); + })); + return RebuildTypeRequirement(TransType); +} + +concepts::ExprRequirement * +TemplateInstantiator::TransformExprRequirement(concepts::ExprRequirement *Req) { + if (!Req->isDependent() && !AlwaysRebuild()) + return Req; + + Sema::SFINAETrap Trap(SemaRef); + TemplateDeductionInfo Info(Req->getExpr()->getBeginLoc()); + + llvm::PointerUnion + TransExpr; + if (Req->isExprSubstitutionFailure()) + TransExpr = Req->getExprSubstitutionDiagnostic(); + else { + Sema::InstantiatingTemplate ExprInst(SemaRef, Req->getExpr()->getBeginLoc(), + Req, Info, + Req->getExpr()->getSourceRange()); + if (ExprInst.isInvalid()) + return nullptr; + ExprResult TransExprRes = TransformExpr(Req->getExpr()); + if (TransExprRes.isInvalid() || Trap.hasErrorOccurred()) + TransExpr = createSubstDiag(SemaRef, Info, + [&] (llvm::raw_ostream& OS) { + Req->getExpr()->printPretty(OS, nullptr, + SemaRef.getPrintingPolicy()); + }); + else + TransExpr = TransExprRes.get(); + } + + llvm::Optional TransRetReq; + const auto &RetReq = Req->getReturnTypeRequirement(); + if (RetReq.isEmpty()) + TransRetReq.emplace(); + else if (RetReq.isSubstitutionFailure()) + TransRetReq.emplace(RetReq.getSubstitutionDiagnostic()); + else if (RetReq.isTypeConstraint()) { + TemplateParameterList *OrigTPL = + RetReq.getTypeConstraintTemplateParameterList(); + Sema::InstantiatingTemplate TPLInst(SemaRef, OrigTPL->getTemplateLoc(), + Req, Info, OrigTPL->getSourceRange()); + if (TPLInst.isInvalid()) + return nullptr; + TemplateParameterList *TPL = + TransformTemplateParameterList(OrigTPL); + if (!TPL) + TransRetReq.emplace(createSubstDiag(SemaRef, Info, + [&] (llvm::raw_ostream& OS) { + RetReq.getTypeConstraint()->getImmediatelyDeclaredConstraint() + ->printPretty(OS, nullptr, SemaRef.getPrintingPolicy()); + })); + else { + TPLInst.Clear(); + TransRetReq.emplace(TPL); + } + } + assert(TransRetReq.hasValue() && + "All code paths leading here must set TransRetReq"); + if (Expr *E = TransExpr.dyn_cast()) + return RebuildExprRequirement(E, Req->isSimple(), Req->getNoexceptLoc(), + std::move(*TransRetReq)); + return RebuildExprRequirement( + TransExpr.get(), + Req->isSimple(), Req->getNoexceptLoc(), std::move(*TransRetReq)); +} + +concepts::NestedRequirement * +TemplateInstantiator::TransformNestedRequirement( + concepts::NestedRequirement *Req) { + if (!Req->isDependent() && !AlwaysRebuild()) + return Req; + if (Req->isSubstitutionFailure()) { + if (AlwaysRebuild()) + return RebuildNestedRequirement( + Req->getSubstitutionDiagnostic()); + return Req; + } + Sema::InstantiatingTemplate ReqInst(SemaRef, + Req->getConstraintExpr()->getBeginLoc(), Req, + Sema::InstantiatingTemplate::ConstraintsCheck{}, + Req->getConstraintExpr()->getSourceRange()); + + ExprResult TransConstraint; + TemplateDeductionInfo Info(Req->getConstraintExpr()->getBeginLoc()); + { + EnterExpressionEvaluationContext ContextRAII( + SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated); + Sema::SFINAETrap Trap(SemaRef); + Sema::InstantiatingTemplate ConstrInst(SemaRef, + Req->getConstraintExpr()->getBeginLoc(), Req, Info, + Req->getConstraintExpr()->getSourceRange()); + if (ConstrInst.isInvalid()) + return nullptr; + TransConstraint = TransformExpr(Req->getConstraintExpr()); + if (TransConstraint.isInvalid() || Trap.hasErrorOccurred()) + return RebuildNestedRequirement(createSubstDiag(SemaRef, Info, + [&] (llvm::raw_ostream& OS) { + Req->getConstraintExpr()->printPretty(OS, nullptr, + SemaRef.getPrintingPolicy()); + })); + } + return RebuildNestedRequirement(TransConstraint.get()); +} + + /// Perform substitution on the type T with a given set of template /// arguments. /// @@ -1858,6 +2150,94 @@ void Sema::SubstExceptionSpec(FunctionDecl *New, const FunctionProtoType *Proto, UpdateExceptionSpec(New, ESI); } +namespace { + + struct GetContainedInventedTypeParmVisitor : + public TypeVisitor { + using TypeVisitor::Visit; + + TemplateTypeParmDecl *Visit(QualType T) { + if (T.isNull()) + return nullptr; + return Visit(T.getTypePtr()); + } + // The deduced type itself. + TemplateTypeParmDecl *VisitTemplateTypeParmType( + const TemplateTypeParmType *T) { + if (!T->getDecl() || !T->getDecl()->isImplicit()) + return nullptr; + return T->getDecl(); + } + + // Only these types can contain 'auto' types, and subsequently be replaced + // by references to invented parameters. + + TemplateTypeParmDecl *VisitElaboratedType(const ElaboratedType *T) { + return Visit(T->getNamedType()); + } + + TemplateTypeParmDecl *VisitPointerType(const PointerType *T) { + return Visit(T->getPointeeType()); + } + + TemplateTypeParmDecl *VisitBlockPointerType(const BlockPointerType *T) { + return Visit(T->getPointeeType()); + } + + TemplateTypeParmDecl *VisitReferenceType(const ReferenceType *T) { + return Visit(T->getPointeeTypeAsWritten()); + } + + TemplateTypeParmDecl *VisitMemberPointerType(const MemberPointerType *T) { + return Visit(T->getPointeeType()); + } + + TemplateTypeParmDecl *VisitArrayType(const ArrayType *T) { + return Visit(T->getElementType()); + } + + TemplateTypeParmDecl *VisitDependentSizedExtVectorType( + const DependentSizedExtVectorType *T) { + return Visit(T->getElementType()); + } + + TemplateTypeParmDecl *VisitVectorType(const VectorType *T) { + return Visit(T->getElementType()); + } + + TemplateTypeParmDecl *VisitFunctionProtoType(const FunctionProtoType *T) { + return VisitFunctionType(T); + } + + TemplateTypeParmDecl *VisitFunctionType(const FunctionType *T) { + return Visit(T->getReturnType()); + } + + TemplateTypeParmDecl *VisitParenType(const ParenType *T) { + return Visit(T->getInnerType()); + } + + TemplateTypeParmDecl *VisitAttributedType(const AttributedType *T) { + return Visit(T->getModifiedType()); + } + + TemplateTypeParmDecl *VisitMacroQualifiedType(const MacroQualifiedType *T) { + return Visit(T->getUnderlyingType()); + } + + TemplateTypeParmDecl *VisitAdjustedType(const AdjustedType *T) { + return Visit(T->getOriginalType()); + } + + TemplateTypeParmDecl *VisitPackExpansionType(const PackExpansionType *T) { + return Visit(T->getPattern()); + } + }; + +} // namespace + ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm, const MultiLevelTemplateArgumentList &TemplateArgs, int indexAdjustment, @@ -1905,6 +2285,46 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm, return nullptr; } + // In abbreviated templates, TemplateTypeParmDecls with possible + // TypeConstraints are created when the parameter list is originally parsed. + // The TypeConstraints can therefore reference other functions parameters in + // the abbreviated function template, which is why we must instantiate them + // here, when the instantiated versions of those referenced parameters are in + // scope. + if (TemplateTypeParmDecl *TTP = + GetContainedInventedTypeParmVisitor().Visit(OldDI->getType())) { + if (const TypeConstraint *TC = TTP->getTypeConstraint()) { + auto *Inst = cast_or_null( + FindInstantiatedDecl(TTP->getLocation(), TTP, TemplateArgs)); + // We will first get here when instantiating the abbreviated function + // template's described function, but we might also get here later. + // Make sure we do not instantiate the TypeConstraint more than once. + if (Inst && !Inst->getTypeConstraint()) { + // TODO: Concepts: do not instantiate the constraint (delayed constraint + // substitution) + const ASTTemplateArgumentListInfo *TemplArgInfo + = TC->getTemplateArgsAsWritten(); + TemplateArgumentListInfo InstArgs; + + if (TemplArgInfo) { + InstArgs.setLAngleLoc(TemplArgInfo->LAngleLoc); + InstArgs.setRAngleLoc(TemplArgInfo->RAngleLoc); + if (Subst(TemplArgInfo->getTemplateArgs(), + TemplArgInfo->NumTemplateArgs, InstArgs, TemplateArgs)) + return nullptr; + } + if (AttachTypeConstraint( + TC->getNestedNameSpecifierLoc(), TC->getConceptNameInfo(), + TC->getNamedConcept(), &InstArgs, Inst, + TTP->isParameterPack() + ? cast(TC->getImmediatelyDeclaredConstraint()) + ->getEllipsisLoc() + : SourceLocation())) + return nullptr; + } + } + } + ParmVarDecl *NewParm = CheckParameter(Context.getTranslationUnitDecl(), OldParm->getInnerLocStart(), OldParm->getLocation(), diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 64500d0a26d54..37dace3bee7f6 100755 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1837,6 +1837,23 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl( return nullptr; QualType T = adjustFunctionTypeForInstantiation(SemaRef.Context, D, TInfo); + if (TemplateParams && TemplateParams->size()) { + auto *LastParam = + dyn_cast(TemplateParams->asArray().back()); + if (LastParam && LastParam->isImplicit() && + LastParam->hasTypeConstraint()) { + // In abbreviated templates, the type-constraints of invented template + // type parameters are instantiated with the function type, invalidating + // the TemplateParameterList which relied on the template type parameter + // not having a type constraint. Recreate the TemplateParameterList with + // the updated parameter list. + TemplateParams = TemplateParameterList::Create( + SemaRef.Context, TemplateParams->getTemplateLoc(), + TemplateParams->getLAngleLoc(), TemplateParams->asArray(), + TemplateParams->getRAngleLoc(), TemplateParams->getRequiresClause()); + } + } + NestedNameSpecifierLoc QualifierLoc = D->getQualifierLoc(); if (QualifierLoc) { QualifierLoc = SemaRef.SubstNestedNameSpecifierLoc(QualifierLoc, @@ -1848,6 +1865,8 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl( // FIXME: Concepts: Do not substitute into constraint expressions Expr *TrailingRequiresClause = D->getTrailingRequiresClause(); if (TrailingRequiresClause) { + EnterExpressionEvaluationContext ConstantEvaluated( + SemaRef, Sema::ExpressionEvaluationContext::Unevaluated); ExprResult SubstRC = SemaRef.SubstExpr(TrailingRequiresClause, TemplateArgs); if (SubstRC.isInvalid()) @@ -2175,6 +2194,23 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl( return nullptr; QualType T = adjustFunctionTypeForInstantiation(SemaRef.Context, D, TInfo); + if (TemplateParams && TemplateParams->size()) { + auto *LastParam = + dyn_cast(TemplateParams->asArray().back()); + if (LastParam && LastParam->isImplicit() && + LastParam->hasTypeConstraint()) { + // In abbreviated templates, the type-constraints of invented template + // type parameters are instantiated with the function type, invalidating + // the TemplateParameterList which relied on the template type parameter + // not having a type constraint. Recreate the TemplateParameterList with + // the updated parameter list. + TemplateParams = TemplateParameterList::Create( + SemaRef.Context, TemplateParams->getTemplateLoc(), + TemplateParams->getLAngleLoc(), TemplateParams->asArray(), + TemplateParams->getRAngleLoc(), TemplateParams->getRequiresClause()); + } + } + NestedNameSpecifierLoc QualifierLoc = D->getQualifierLoc(); if (QualifierLoc) { QualifierLoc = SemaRef.SubstNestedNameSpecifierLoc(QualifierLoc, @@ -2186,6 +2222,11 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl( // FIXME: Concepts: Do not substitute into constraint expressions Expr *TrailingRequiresClause = D->getTrailingRequiresClause(); if (TrailingRequiresClause) { + EnterExpressionEvaluationContext ConstantEvaluated( + SemaRef, Sema::ExpressionEvaluationContext::Unevaluated); + auto *ThisContext = dyn_cast_or_null(Owner); + Sema::CXXThisScopeRAII ThisScope(SemaRef, ThisContext, + D->getMethodQualifiers(), ThisContext); ExprResult SubstRC = SemaRef.SubstExpr(TrailingRequiresClause, TemplateArgs); if (SubstRC.isInvalid()) @@ -2518,28 +2559,34 @@ Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl( Inst->setAccess(AS_public); Inst->setImplicit(D->isImplicit()); if (auto *TC = D->getTypeConstraint()) { - // TODO: Concepts: do not instantiate the constraint (delayed constraint - // substitution) - const ASTTemplateArgumentListInfo *TemplArgInfo - = TC->getTemplateArgsAsWritten(); - TemplateArgumentListInfo InstArgs; - - if (TemplArgInfo) { - InstArgs.setLAngleLoc(TemplArgInfo->LAngleLoc); - InstArgs.setRAngleLoc(TemplArgInfo->RAngleLoc); - if (SemaRef.Subst(TemplArgInfo->getTemplateArgs(), - TemplArgInfo->NumTemplateArgs, - InstArgs, TemplateArgs)) + if (!D->isImplicit()) { + // Invented template parameter type constraints will be instantiated with + // the corresponding auto-typed parameter as it might reference other + // parameters. + + // TODO: Concepts: do not instantiate the constraint (delayed constraint + // substitution) + const ASTTemplateArgumentListInfo *TemplArgInfo + = TC->getTemplateArgsAsWritten(); + TemplateArgumentListInfo InstArgs; + + if (TemplArgInfo) { + InstArgs.setLAngleLoc(TemplArgInfo->LAngleLoc); + InstArgs.setRAngleLoc(TemplArgInfo->RAngleLoc); + if (SemaRef.Subst(TemplArgInfo->getTemplateArgs(), + TemplArgInfo->NumTemplateArgs, + InstArgs, TemplateArgs)) + return nullptr; + } + if (SemaRef.AttachTypeConstraint( + TC->getNestedNameSpecifierLoc(), TC->getConceptNameInfo(), + TC->getNamedConcept(), &InstArgs, Inst, + D->isParameterPack() + ? cast(TC->getImmediatelyDeclaredConstraint()) + ->getEllipsisLoc() + : SourceLocation())) return nullptr; } - if (SemaRef.AttachTypeConstraint( - TC->getNestedNameSpecifierLoc(), TC->getConceptNameInfo(), - TC->getNamedConcept(), &InstArgs, Inst, - D->isParameterPack() - ? cast(TC->getImmediatelyDeclaredConstraint()) - ->getEllipsisLoc() - : SourceLocation())) - return nullptr; } if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) { TypeSourceInfo *InstantiatedDefaultArg = @@ -2685,6 +2732,16 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl( D->getDepth() - TemplateArgs.getNumSubstitutedLevels(), D->getPosition(), D->getIdentifier(), T, D->isParameterPack(), DI); + if (AutoTypeLoc AutoLoc = DI->getTypeLoc().getContainedAutoTypeLoc()) + if (AutoLoc.isConstrained()) + if (SemaRef.AttachTypeConstraint( + AutoLoc, Param, + IsExpandedParameterPack + ? DI->getTypeLoc().getAs() + .getEllipsisLoc() + : SourceLocation())) + Invalid = true; + Param->setAccess(AS_public); Param->setImplicit(D->isImplicit()); if (Invalid) @@ -3600,6 +3657,12 @@ Decl *TemplateDeclInstantiator::VisitConceptDecl(ConceptDecl *D) { llvm_unreachable("Concept definitions cannot reside inside a template"); } +Decl * +TemplateDeclInstantiator::VisitRequiresExprBodyDecl(RequiresExprBodyDecl *D) { + return RequiresExprBodyDecl::Create(SemaRef.Context, D->getDeclContext(), + D->getBeginLoc()); +} + Decl *TemplateDeclInstantiator::VisitDecl(Decl *D) { llvm_unreachable("Unexpected decl"); } @@ -3713,6 +3776,8 @@ TemplateDeclInstantiator::SubstTemplateParams(TemplateParameterList *L) { // checking satisfaction. Expr *InstRequiresClause = nullptr; if (Expr *E = L->getRequiresClause()) { + EnterExpressionEvaluationContext ConstantEvaluated( + SemaRef, Sema::ExpressionEvaluationContext::Unevaluated); ExprResult Res = SemaRef.SubstExpr(E, TemplateArgs); if (Res.isInvalid() || !Res.isUsable()) { return nullptr; @@ -4224,24 +4289,29 @@ bool Sema::CheckInstantiatedFunctionTemplateConstraints( Sema::ContextRAII savedContext(*this, Decl); LocalInstantiationScope Scope(*this); - MultiLevelTemplateArgumentList MLTAL = - getTemplateInstantiationArgs(Decl, nullptr, /*RelativeToPrimary*/true); - // If this is not an explicit specialization - we need to get the instantiated // version of the template arguments and add them to scope for the // substitution. if (Decl->isTemplateInstantiation()) { InstantiatingTemplate Inst(*this, Decl->getPointOfInstantiation(), InstantiatingTemplate::ConstraintsCheck{}, Decl->getPrimaryTemplate(), - MLTAL.getInnermost(), SourceRange()); + TemplateArgs, SourceRange()); if (Inst.isInvalid()) return true; - if (addInstantiatedParametersToScope(*this, Decl, - Decl->getTemplateInstantiationPattern(), - Scope, MLTAL)) + MultiLevelTemplateArgumentList MLTAL( + *Decl->getTemplateSpecializationArgs()); + if (addInstantiatedParametersToScope( + *this, Decl, Decl->getPrimaryTemplate()->getTemplatedDecl(), + Scope, MLTAL)) return true; } - + Qualifiers ThisQuals; + CXXRecordDecl *Record = nullptr; + if (auto *Method = dyn_cast(Decl)) { + ThisQuals = Method->getMethodQualifiers(); + Record = Method->getParent(); + } + CXXThisScopeRAII ThisScope(*this, Record, ThisQuals, Record != nullptr); return CheckConstraintSatisfaction(Template, TemplateAC, TemplateArgs, PointOfInstantiation, Satisfaction); } diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 3884fdae8fe72..93ddd047e09be 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "TypeLocBuilder.h" +#include "TreeTransform.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTMutationListener.h" @@ -27,6 +28,7 @@ #include "clang/Sema/DeclSpec.h" #include "clang/Sema/DelayedDiagnostic.h" #include "clang/Sema/Lookup.h" +#include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/SemaInternal.h" #include "clang/Sema/Template.h" @@ -1251,6 +1253,26 @@ getImageAccess(const ParsedAttributesView &Attrs) { return OpenCLAccessAttr::Keyword_read_only; } +static QualType ConvertConstrainedAutoDeclSpecToType(Sema &S, DeclSpec &DS, + AutoTypeKeyword AutoKW) { + assert(DS.isConstrainedAuto()); + TemplateIdAnnotation *TemplateId = DS.getRepAsTemplateId(); + TemplateArgumentListInfo TemplateArgsInfo; + TemplateArgsInfo.setLAngleLoc(TemplateId->LAngleLoc); + TemplateArgsInfo.setRAngleLoc(TemplateId->RAngleLoc); + ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(), + TemplateId->NumArgs); + S.translateTemplateArguments(TemplateArgsPtr, TemplateArgsInfo); + llvm::SmallVector TemplateArgs; + for (auto &ArgLoc : TemplateArgsInfo.arguments()) + TemplateArgs.push_back(ArgLoc.getArgument()); + return S.Context.getAutoType(QualType(), AutoTypeKeyword::Auto, false, + /*IsPack=*/false, + cast(TemplateId->Template.get() + .getAsTemplateDecl()), + TemplateArgs); +} + /// Convert the specified declspec to the appropriate type /// object. /// \param state Specifies the declarator containing the declaration specifier @@ -1595,6 +1617,11 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { break; case DeclSpec::TST_auto: + if (DS.isConstrainedAuto()) { + Result = ConvertConstrainedAutoDeclSpecToType(S, DS, + AutoTypeKeyword::Auto); + break; + } Result = Context.getAutoType(QualType(), AutoTypeKeyword::Auto, false); break; @@ -1603,6 +1630,12 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { break; case DeclSpec::TST_decltype_auto: + if (DS.isConstrainedAuto()) { + Result = + ConvertConstrainedAutoDeclSpecToType(S, DS, + AutoTypeKeyword::DecltypeAuto); + break; + } Result = Context.getAutoType(QualType(), AutoTypeKeyword::DecltypeAuto, /*IsDependent*/ false); break; @@ -2921,6 +2954,87 @@ static void diagnoseRedundantReturnTypeQualifiers(Sema &S, QualType RetTy, D.getDeclSpec().getUnalignedSpecLoc()); } +static void CopyTypeConstraintFromAutoType(Sema &SemaRef, const AutoType *Auto, + AutoTypeLoc AutoLoc, + TemplateTypeParmDecl *TP, + SourceLocation EllipsisLoc) { + + TemplateArgumentListInfo TAL(AutoLoc.getLAngleLoc(), AutoLoc.getRAngleLoc()); + for (unsigned Idx = 0; Idx < AutoLoc.getNumArgs(); ++Idx) + TAL.addArgument(AutoLoc.getArgLoc(Idx)); + + SemaRef.AttachTypeConstraint( + AutoLoc.getNestedNameSpecifierLoc(), AutoLoc.getConceptNameInfo(), + AutoLoc.getNamedConcept(), + AutoLoc.hasExplicitTemplateArgs() ? &TAL : nullptr, TP, EllipsisLoc); +} + +static QualType InventTemplateParameter( + TypeProcessingState &state, QualType T, TypeSourceInfo *TSI, AutoType *Auto, + InventedTemplateParameterInfo &Info) { + Sema &S = state.getSema(); + Declarator &D = state.getDeclarator(); + + const unsigned TemplateParameterDepth = Info.AutoTemplateParameterDepth; + const unsigned AutoParameterPosition = Info.TemplateParams.size(); + const bool IsParameterPack = D.hasEllipsis(); + + // If auto is mentioned in a lambda parameter or abbreviated function + // template context, convert it to a template parameter type. + + // Create the TemplateTypeParmDecl here to retrieve the corresponding + // template parameter type. Template parameters are temporarily added + // to the TU until the associated TemplateDecl is created. + TemplateTypeParmDecl *InventedTemplateParam = + TemplateTypeParmDecl::Create( + S.Context, S.Context.getTranslationUnitDecl(), + /*KeyLoc=*/D.getDeclSpec().getTypeSpecTypeLoc(), + /*NameLoc=*/D.getIdentifierLoc(), + TemplateParameterDepth, AutoParameterPosition, + S.InventAbbreviatedTemplateParameterTypeName( + D.getIdentifier(), AutoParameterPosition), false, + IsParameterPack, /*HasTypeConstraint=*/Auto->isConstrained()); + InventedTemplateParam->setImplicit(); + Info.TemplateParams.push_back(InventedTemplateParam); + // Attach type constraints + if (Auto->isConstrained()) { + if (TSI) { + CopyTypeConstraintFromAutoType( + S, Auto, TSI->getTypeLoc().getContainedAutoTypeLoc(), + InventedTemplateParam, D.getEllipsisLoc()); + } else { + TemplateIdAnnotation *TemplateId = D.getDeclSpec().getRepAsTemplateId(); + TemplateArgumentListInfo TemplateArgsInfo; + if (TemplateId->LAngleLoc.isValid()) { + ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(), + TemplateId->NumArgs); + S.translateTemplateArguments(TemplateArgsPtr, TemplateArgsInfo); + } + S.AttachTypeConstraint( + D.getDeclSpec().getTypeSpecScope().getWithLocInContext(S.Context), + DeclarationNameInfo(DeclarationName(TemplateId->Name), + TemplateId->TemplateNameLoc), + cast(TemplateId->Template.get().getAsTemplateDecl()), + TemplateId->LAngleLoc.isValid() ? &TemplateArgsInfo : nullptr, + InventedTemplateParam, D.getEllipsisLoc()); + } + } + + // If TSI is nullptr, this is a constrained declspec auto and the type + // constraint will be attached later in TypeSpecLocFiller + + // Replace the 'auto' in the function parameter with this invented + // template type parameter. + // FIXME: Retain some type sugar to indicate that this was written + // as 'auto'? + return state.ReplaceAutoType( + T, QualType(InventedTemplateParam->getTypeForDecl(), 0)); +} + +static TypeSourceInfo * +GetTypeSourceInfoForDeclarator(TypeProcessingState &State, + QualType T, TypeSourceInfo *ReturnTypeInfo); + static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, TypeSourceInfo *&ReturnTypeInfo) { Sema &SemaRef = state.getSema(); @@ -2991,43 +3105,43 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, break; case DeclaratorContext::ObjCParameterContext: case DeclaratorContext::ObjCResultContext: - case DeclaratorContext::PrototypeContext: Error = 0; break; - case DeclaratorContext::LambdaExprParameterContext: - // In C++14, generic lambdas allow 'auto' in their parameters. - if (!SemaRef.getLangOpts().CPlusPlus14 || - !Auto || Auto->getKeyword() != AutoTypeKeyword::Auto) - Error = 16; - else { - // If auto is mentioned in a lambda parameter context, convert it to a - // template parameter type. - sema::LambdaScopeInfo *LSI = SemaRef.getCurLambda(); - assert(LSI && "No LambdaScopeInfo on the stack!"); - const unsigned TemplateParameterDepth = LSI->AutoTemplateParameterDepth; - const unsigned AutoParameterPosition = LSI->TemplateParams.size(); - const bool IsParameterPack = D.hasEllipsis(); - - // Create the TemplateTypeParmDecl here to retrieve the corresponding - // template parameter type. Template parameters are temporarily added - // to the TU until the associated TemplateDecl is created. - TemplateTypeParmDecl *CorrespondingTemplateParam = - TemplateTypeParmDecl::Create( - SemaRef.Context, SemaRef.Context.getTranslationUnitDecl(), - /*KeyLoc*/ SourceLocation(), /*NameLoc*/ D.getBeginLoc(), - TemplateParameterDepth, AutoParameterPosition, - /*Identifier*/ nullptr, false, IsParameterPack, - /*HasTypeConstraint=*/false); - CorrespondingTemplateParam->setImplicit(); - LSI->TemplateParams.push_back(CorrespondingTemplateParam); - // Replace the 'auto' in the function parameter with this invented - // template type parameter. - // FIXME: Retain some type sugar to indicate that this was written - // as 'auto'. - T = state.ReplaceAutoType( - T, QualType(CorrespondingTemplateParam->getTypeForDecl(), 0)); + case DeclaratorContext::RequiresExprContext: + Error = 22; + break; + case DeclaratorContext::PrototypeContext: + case DeclaratorContext::LambdaExprParameterContext: { + InventedTemplateParameterInfo *Info = nullptr; + if (D.getContext() == DeclaratorContext::PrototypeContext) { + // With concepts we allow 'auto' in function parameters. + if (!SemaRef.getLangOpts().CPlusPlus2a || !Auto || + Auto->getKeyword() != AutoTypeKeyword::Auto) { + Error = 0; + break; + } else if (!SemaRef.getCurScope()->isFunctionDeclarationScope()) { + Error = 21; + break; + } else if (D.hasTrailingReturnType()) { + // This might be OK, but we'll need to convert the trailing return + // type later. + break; + } + + Info = &SemaRef.InventedParameterInfos.back(); + } else { + // In C++14, generic lambdas allow 'auto' in their parameters. + if (!SemaRef.getLangOpts().CPlusPlus14 || !Auto || + Auto->getKeyword() != AutoTypeKeyword::Auto) { + Error = 16; + break; + } + Info = SemaRef.getCurLambda(); + assert(Info && "No LambdaScopeInfo on the stack!"); } + T = InventTemplateParameter(state, T, nullptr, Auto, *Info); break; + } case DeclaratorContext::MemberContext: { if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static || D.isFunctionDeclarator()) @@ -3221,6 +3335,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, case DeclaratorContext::ObjCParameterContext: case DeclaratorContext::ObjCResultContext: case DeclaratorContext::KNRTypeListContext: + case DeclaratorContext::RequiresExprContext: // C++ [dcl.fct]p6: // Types shall not be defined in return or parameter types. DiagID = diag::err_type_defined_in_param_type; @@ -4028,10 +4143,6 @@ static bool DiagnoseMultipleAddrSpaceAttributes(Sema &S, LangAS ASOld, return false; } -static TypeSourceInfo * -GetTypeSourceInfoForDeclarator(TypeProcessingState &State, - QualType T, TypeSourceInfo *ReturnTypeInfo); - static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, QualType declSpecType, TypeSourceInfo *TInfo) { @@ -4279,6 +4390,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, case DeclaratorContext::TemplateTypeArgContext: case DeclaratorContext::TypeNameContext: case DeclaratorContext::FunctionalCastContext: + case DeclaratorContext::RequiresExprContext: // Don't infer in these contexts. break; } @@ -4606,7 +4718,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, } else if (D.getContext() != DeclaratorContext::LambdaExprContext && (T.hasQualifiers() || !isa(T) || cast(T)->getKeyword() != - AutoTypeKeyword::Auto)) { + AutoTypeKeyword::Auto || + cast(T)->isConstrained())) { S.Diag(D.getDeclSpec().getTypeSpecTypeLoc(), diag::err_trailing_return_without_auto) << T << D.getDeclSpec().getSourceRange(); @@ -4617,7 +4730,12 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // An error occurred parsing the trailing return type. T = Context.IntTy; D.setInvalidType(true); - } + } else if (S.getLangOpts().CPlusPlus2a) + // Handle cases like: `auto f() -> auto` or `auto f() -> C auto`. + if (AutoType *Auto = T->getContainedAutoType()) + if (S.getCurScope()->isFunctionDeclarationScope()) + T = InventTemplateParameter(state, T, TInfo, Auto, + S.InventedParameterInfos.back()); } else { // This function type is not the type of the entity being declared, // so checking the 'auto' is not the responsibility of this chunk. @@ -5227,6 +5345,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, switch (D.getContext()) { case DeclaratorContext::PrototypeContext: case DeclaratorContext::LambdaExprParameterContext: + case DeclaratorContext::RequiresExprContext: // C++0x [dcl.fct]p13: // [...] When it is part of a parameter-declaration-clause, the // parameter pack is a function parameter pack (14.5.3). The type T @@ -5236,7 +5355,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // // We represent function parameter packs as function parameters whose // type is a pack expansion. - if (!T->containsUnexpandedParameterPack()) { + if (!T->containsUnexpandedParameterPack() && + (!LangOpts.CPlusPlus2a || !T->getContainedAutoType())) { S.Diag(D.getEllipsisLoc(), diag::err_function_parameter_pack_without_parameter_packs) << T << D.getSourceRange(); @@ -5444,14 +5564,15 @@ static void fillAttributedTypeLoc(AttributedTypeLoc TL, namespace { class TypeSpecLocFiller : public TypeLocVisitor { + Sema &SemaRef; ASTContext &Context; TypeProcessingState &State; const DeclSpec &DS; public: - TypeSpecLocFiller(ASTContext &Context, TypeProcessingState &State, + TypeSpecLocFiller(Sema &S, ASTContext &Context, TypeProcessingState &State, const DeclSpec &DS) - : Context(Context), State(State), DS(DS) {} + : SemaRef(S), Context(Context), State(State), DS(DS) {} void VisitAttributedTypeLoc(AttributedTypeLoc TL) { Visit(TL.getModifiedLoc()); @@ -5579,6 +5700,34 @@ namespace { TL.copy( TInfo->getTypeLoc().castAs()); } + void VisitAutoTypeLoc(AutoTypeLoc TL) { + assert(DS.getTypeSpecType() == TST_auto || + DS.getTypeSpecType() == TST_decltype_auto || + DS.getTypeSpecType() == TST_auto_type || + DS.getTypeSpecType() == TST_unspecified); + TL.setNameLoc(DS.getTypeSpecTypeLoc()); + if (!DS.isConstrainedAuto()) + return; + TemplateIdAnnotation *TemplateId = DS.getRepAsTemplateId(); + if (DS.getTypeSpecScope().isNotEmpty()) + TL.setNestedNameSpecifierLoc( + DS.getTypeSpecScope().getWithLocInContext(Context)); + else + TL.setNestedNameSpecifierLoc(NestedNameSpecifierLoc()); + TL.setTemplateKWLoc(TemplateId->TemplateKWLoc); + TL.setConceptNameLoc(TemplateId->TemplateNameLoc); + TL.setFoundDecl(nullptr); + TL.setLAngleLoc(TemplateId->LAngleLoc); + TL.setRAngleLoc(TemplateId->RAngleLoc); + if (TemplateId->NumArgs == 0) + return; + TemplateArgumentListInfo TemplateArgsInfo; + ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(), + TemplateId->NumArgs); + SemaRef.translateTemplateArguments(TemplateArgsPtr, TemplateArgsInfo); + for (unsigned I = 0; I < TemplateId->NumArgs; ++I) + TL.setArgLocInfo(I, TemplateArgsInfo.arguments()[I].getLocInfo()); + } void VisitTagTypeLoc(TagTypeLoc TL) { TL.setNameLoc(DS.getTypeSpecTypeNameLoc()); } @@ -5848,7 +5997,7 @@ GetTypeSourceInfoForDeclarator(TypeProcessingState &State, assert(TL.getFullDataSize() == CurrTL.getFullDataSize()); memcpy(CurrTL.getOpaqueData(), TL.getOpaqueData(), TL.getFullDataSize()); } else { - TypeSpecLocFiller(S.Context, State, D.getDeclSpec()).Visit(CurrTL); + TypeSpecLocFiller(S, S.Context, State, D.getDeclSpec()).Visit(CurrTL); } return TInfo; diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 3b827fbc950b7..0305954a278e9 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -19,6 +19,7 @@ #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" +#include "clang/AST/ExprConcepts.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" #include "clang/AST/ExprOpenMP.h" @@ -211,6 +212,14 @@ class TreeTransform { return T.isNull(); } + /// Transform a template parameter depth level. + /// + /// During a transformation that transforms template parameters, this maps + /// an old template parameter depth to a new depth. + unsigned TransformTemplateDepth(unsigned Depth) { + return Depth; + } + /// Determine whether the given call argument should be dropped, e.g., /// because it is a default argument. /// @@ -509,6 +518,15 @@ class TreeTransform { DeclarationNameInfo TransformDeclarationNameInfo(const DeclarationNameInfo &NameInfo); + bool TransformRequiresExprRequirements(ArrayRef Reqs, + llvm::SmallVectorImpl &Transformed); + concepts::TypeRequirement * + TransformTypeRequirement(concepts::TypeRequirement *Req); + concepts::ExprRequirement * + TransformExprRequirement(concepts::ExprRequirement *Req); + concepts::NestedRequirement * + TransformNestedRequirement(concepts::NestedRequirement *Req); + /// Transform the given template name. /// /// \param SS The nested-name-specifier that qualifies the template @@ -941,12 +959,16 @@ class TreeTransform { /// Build a new C++11 auto type. /// /// By default, builds a new AutoType with the given deduced type. - QualType RebuildAutoType(QualType Deduced, AutoTypeKeyword Keyword) { + QualType RebuildAutoType(QualType Deduced, AutoTypeKeyword Keyword, + ConceptDecl *TypeConstraintConcept, + ArrayRef TypeConstraintArgs) { // Note, IsDependent is always false here: we implicitly convert an 'auto' // which has been deduced to a dependent type into an undeduced 'auto', so // that we'll retry deduction after the transformation. return SemaRef.Context.getAutoType(Deduced, Keyword, - /*IsDependent*/ false); + /*IsDependent*/ false, /*IsPack=*/false, + TypeConstraintConcept, + TypeConstraintArgs); } /// By default, builds a new DeducedTemplateSpecializationType with the given @@ -1056,23 +1078,8 @@ class TreeTransform { } if (Keyword == ETK_None || Keyword == ETK_Typename) { - QualType T = SemaRef.CheckTypenameType(Keyword, KeywordLoc, QualifierLoc, - *Id, IdLoc); - // If a dependent name resolves to a deduced template specialization type, - // check that we're in one of the syntactic contexts permitting it. - if (!DeducedTSTContext) { - if (auto *Deduced = dyn_cast_or_null( - T.isNull() ? nullptr : T->getContainedDeducedType())) { - SemaRef.Diag(IdLoc, diag::err_dependent_deduced_tst) - << (int)SemaRef.getTemplateNameKindForDiagnostics( - Deduced->getTemplateName()) - << QualType(QualifierLoc.getNestedNameSpecifier()->getAsType(), 0); - if (auto *TD = Deduced->getTemplateName().getAsTemplateDecl()) - SemaRef.Diag(TD->getLocation(), diag::note_template_decl_here); - return QualType(); - } - } - return T; + return SemaRef.CheckTypenameType(Keyword, KeywordLoc, QualifierLoc, + *Id, IdLoc, DeducedTSTContext); } TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForKeyword(Keyword); @@ -2527,10 +2534,10 @@ class TreeTransform { /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. - ExprResult RebuildStmtExpr(SourceLocation LParenLoc, - Stmt *SubStmt, - SourceLocation RParenLoc) { - return getSema().ActOnStmtExpr(LParenLoc, SubStmt, RParenLoc); + ExprResult RebuildStmtExpr(SourceLocation LParenLoc, Stmt *SubStmt, + SourceLocation RParenLoc, unsigned TemplateDepth) { + return getSema().BuildStmtExpr(LParenLoc, SubStmt, RParenLoc, + TemplateDepth); } /// Build a new __builtin_choose_expr expression. @@ -3078,7 +3085,56 @@ class TreeTransform { return Result; } - /// \brief Build a new Objective-C boxed expression. + /// \brief Build a new requires expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + ExprResult RebuildRequiresExpr(SourceLocation RequiresKWLoc, + RequiresExprBodyDecl *Body, + ArrayRef LocalParameters, + ArrayRef Requirements, + SourceLocation ClosingBraceLoc) { + return RequiresExpr::Create(SemaRef.Context, RequiresKWLoc, Body, + LocalParameters, Requirements, ClosingBraceLoc); + } + + concepts::TypeRequirement * + RebuildTypeRequirement( + concepts::Requirement::SubstitutionDiagnostic *SubstDiag) { + return SemaRef.BuildTypeRequirement(SubstDiag); + } + + concepts::TypeRequirement *RebuildTypeRequirement(TypeSourceInfo *T) { + return SemaRef.BuildTypeRequirement(T); + } + + concepts::ExprRequirement * + RebuildExprRequirement( + concepts::Requirement::SubstitutionDiagnostic *SubstDiag, bool IsSimple, + SourceLocation NoexceptLoc, + concepts::ExprRequirement::ReturnTypeRequirement Ret) { + return SemaRef.BuildExprRequirement(SubstDiag, IsSimple, NoexceptLoc, + std::move(Ret)); + } + + concepts::ExprRequirement * + RebuildExprRequirement(Expr *E, bool IsSimple, SourceLocation NoexceptLoc, + concepts::ExprRequirement::ReturnTypeRequirement Ret) { + return SemaRef.BuildExprRequirement(E, IsSimple, NoexceptLoc, + std::move(Ret)); + } + + concepts::NestedRequirement * + RebuildNestedRequirement( + concepts::Requirement::SubstitutionDiagnostic *SubstDiag) { + return SemaRef.BuildNestedRequirement(SubstDiag); + } + + concepts::NestedRequirement *RebuildNestedRequirement(Expr *Constraint) { + return SemaRef.BuildNestedRequirement(Constraint); + } + + /// \brief Build a new Objective-C boxed expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. @@ -4456,7 +4512,10 @@ QualType TreeTransform::RebuildQualifiedType(QualType T, Deduced = SemaRef.Context.getQualifiedType(Deduced.getUnqualifiedType(), Qs); T = SemaRef.Context.getAutoType(Deduced, AutoTy->getKeyword(), - AutoTy->isDependentType()); + AutoTy->isDependentType(), + /*isPack=*/false, + AutoTy->getTypeConstraintConcept(), + AutoTy->getTypeConstraintArguments()); } else { // Otherwise, complain about the addition of a qualifier to an // already-qualified type. @@ -5189,21 +5248,29 @@ bool TreeTransform::TransformFunctionTypeParams( PackExpansionTypeLoc ExpansionTL = TL.castAs(); TypeLoc Pattern = ExpansionTL.getPatternLoc(); SemaRef.collectUnexpandedParameterPacks(Pattern, Unexpanded); - assert(Unexpanded.size() > 0 && "Could not find parameter packs!"); // Determine whether we should expand the parameter packs. bool ShouldExpand = false; bool RetainExpansion = false; - Optional OrigNumExpansions = - ExpansionTL.getTypePtr()->getNumExpansions(); - NumExpansions = OrigNumExpansions; - if (getDerived().TryExpandParameterPacks(ExpansionTL.getEllipsisLoc(), - Pattern.getSourceRange(), - Unexpanded, - ShouldExpand, - RetainExpansion, - NumExpansions)) { - return true; + Optional OrigNumExpansions; + if (Unexpanded.size() > 0) { + OrigNumExpansions = ExpansionTL.getTypePtr()->getNumExpansions(); + NumExpansions = OrigNumExpansions; + if (getDerived().TryExpandParameterPacks(ExpansionTL.getEllipsisLoc(), + Pattern.getSourceRange(), + Unexpanded, + ShouldExpand, + RetainExpansion, + NumExpansions)) { + return true; + } + } else { +#ifndef NDEBUG + const AutoType *AT = + Pattern.getType().getTypePtr()->getContainedAutoType(); + assert((AT && (!AT->isDeduced() || AT->getDeducedType().isNull())) && + "Could not find parameter packs or undeduced auto type!"); +#endif } if (ShouldExpand) { @@ -5263,6 +5330,9 @@ bool TreeTransform::TransformFunctionTypeParams( indexAdjustment, NumExpansions, /*ExpectParameterPack=*/true); + assert(NewParm->isParameterPack() && + "Parameter pack no longer a parameter pack after " + "transformation."); } else { NewParm = getDerived().TransformFunctionTypeParam( OldParm, indexAdjustment, None, /*ExpectParameterPack=*/ false); @@ -5767,32 +5837,6 @@ QualType TreeTransform::TransformUnaryTransformType( return Result; } -template -QualType TreeTransform::TransformAutoType(TypeLocBuilder &TLB, - AutoTypeLoc TL) { - const AutoType *T = TL.getTypePtr(); - QualType OldDeduced = T->getDeducedType(); - QualType NewDeduced; - if (!OldDeduced.isNull()) { - NewDeduced = getDerived().TransformType(OldDeduced); - if (NewDeduced.isNull()) - return QualType(); - } - - QualType Result = TL.getType(); - if (getDerived().AlwaysRebuild() || NewDeduced != OldDeduced || - T->isDependentType()) { - Result = getDerived().RebuildAutoType(NewDeduced, T->getKeyword()); - if (Result.isNull()) - return QualType(); - } - - AutoTypeLoc NewTL = TLB.push(Result); - NewTL.setNameLoc(TL.getNameLoc()); - - return Result; -} - template QualType TreeTransform::TransformDeducedTemplateSpecializationType( TypeLocBuilder &TLB, DeducedTemplateSpecializationTypeLoc TL) { @@ -6054,6 +6098,71 @@ QualType TreeTransform::TransformPipeType(TypeLocBuilder &TLB, } }; +template +QualType TreeTransform::TransformAutoType(TypeLocBuilder &TLB, + AutoTypeLoc TL) { + const AutoType *T = TL.getTypePtr(); + QualType OldDeduced = T->getDeducedType(); + QualType NewDeduced; + if (!OldDeduced.isNull()) { + NewDeduced = getDerived().TransformType(OldDeduced); + if (NewDeduced.isNull()) + return QualType(); + } + + ConceptDecl *NewCD = nullptr; + TemplateArgumentListInfo NewTemplateArgs; + NestedNameSpecifierLoc NewNestedNameSpec; + if (TL.getTypePtr()->isConstrained()) { + NewCD = cast_or_null( + getDerived().TransformDecl( + TL.getConceptNameLoc(), + TL.getTypePtr()->getTypeConstraintConcept())); + + NewTemplateArgs.setLAngleLoc(TL.getLAngleLoc()); + NewTemplateArgs.setRAngleLoc(TL.getRAngleLoc()); + typedef TemplateArgumentLocContainerIterator ArgIterator; + if (getDerived().TransformTemplateArguments(ArgIterator(TL, 0), + ArgIterator(TL, + TL.getNumArgs()), + NewTemplateArgs)) + return QualType(); + + if (TL.getNestedNameSpecifierLoc()) { + NewNestedNameSpec + = getDerived().TransformNestedNameSpecifierLoc( + TL.getNestedNameSpecifierLoc()); + if (!NewNestedNameSpec) + return QualType(); + } + } + + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || NewDeduced != OldDeduced || + T->isDependentType()) { + llvm::SmallVector NewArgList; + NewArgList.reserve(NewArgList.size()); + for (const auto &ArgLoc : NewTemplateArgs.arguments()) + NewArgList.push_back(ArgLoc.getArgument()); + Result = getDerived().RebuildAutoType(NewDeduced, T->getKeyword(), NewCD, + NewArgList); + if (Result.isNull()) + return QualType(); + } + + AutoTypeLoc NewTL = TLB.push(Result); + NewTL.setNameLoc(TL.getNameLoc()); + NewTL.setNestedNameSpecifierLoc(NewNestedNameSpec); + NewTL.setTemplateKWLoc(TL.getTemplateKWLoc()); + NewTL.setConceptNameLoc(TL.getConceptNameLoc()); + NewTL.setFoundDecl(TL.getFoundDecl()); + NewTL.setLAngleLoc(TL.getLAngleLoc()); + NewTL.setRAngleLoc(TL.getRAngleLoc()); + for (unsigned I = 0; I < TL.getNumArgs(); ++I) + NewTL.setArgLocInfo(I, NewTemplateArgs.arguments()[I].getLocInfo()); + + return Result; +} template QualType TreeTransform::TransformTemplateSpecializationType( @@ -10245,16 +10354,18 @@ TreeTransform::TransformStmtExpr(StmtExpr *E) { return ExprError(); } - if (!getDerived().AlwaysRebuild() && + unsigned OldDepth = E->getTemplateDepth(); + unsigned NewDepth = getDerived().TransformTemplateDepth(OldDepth); + + if (!getDerived().AlwaysRebuild() && OldDepth == NewDepth && SubStmt.get() == E->getSubStmt()) { // Calling this an 'error' is unintuitive, but it does the right thing. SemaRef.ActOnStmtExprError(); return SemaRef.MaybeBindToTemporary(E); } - return getDerived().RebuildStmtExpr(E->getLParenLoc(), - SubStmt.get(), - E->getRParenLoc()); + return getDerived().RebuildStmtExpr(E->getLParenLoc(), SubStmt.get(), + E->getRParenLoc(), NewDepth); } template @@ -11179,6 +11290,146 @@ TreeTransform::TransformConceptSpecializationExpr( &TransArgs); } +template +ExprResult +TreeTransform::TransformRequiresExpr(RequiresExpr *E) { + SmallVector TransParams; + SmallVector TransParamTypes; + Sema::ExtParameterInfoBuilder ExtParamInfos; + + // C++2a [expr.prim.req]p2 + // Expressions appearing within a requirement-body are unevaluated operands. + EnterExpressionEvaluationContext Ctx( + SemaRef, Sema::ExpressionEvaluationContext::Unevaluated); + + RequiresExprBodyDecl *Body = RequiresExprBodyDecl::Create( + getSema().Context, getSema().CurContext, + E->getBody()->getBeginLoc()); + + Sema::ContextRAII SavedContext(getSema(), Body, /*NewThisContext*/false); + + if (getDerived().TransformFunctionTypeParams(E->getRequiresKWLoc(), + E->getLocalParameters(), + /*ParamTypes=*/nullptr, + /*ParamInfos=*/nullptr, + TransParamTypes, &TransParams, + ExtParamInfos)) + return ExprError(); + + for (ParmVarDecl *Param : TransParams) + Param->setDeclContext(Body); + + SmallVector TransReqs; + if (getDerived().TransformRequiresExprRequirements(E->getRequirements(), + TransReqs)) + return ExprError(); + + for (concepts::Requirement *Req : TransReqs) { + if (auto *ER = dyn_cast(Req)) { + if (ER->getReturnTypeRequirement().isTypeConstraint()) { + ER->getReturnTypeRequirement() + .getTypeConstraintTemplateParameterList()->getParam(0) + ->setDeclContext(Body); + } + } + } + + return getDerived().RebuildRequiresExpr(E->getRequiresKWLoc(), Body, + TransParams, TransReqs, + E->getRBraceLoc()); +} + +template +bool TreeTransform::TransformRequiresExprRequirements( + ArrayRef Reqs, + SmallVectorImpl &Transformed) { + for (concepts::Requirement *Req : Reqs) { + concepts::Requirement *TransReq = nullptr; + if (auto *TypeReq = dyn_cast(Req)) + TransReq = getDerived().TransformTypeRequirement(TypeReq); + else if (auto *ExprReq = dyn_cast(Req)) + TransReq = getDerived().TransformExprRequirement(ExprReq); + else + TransReq = getDerived().TransformNestedRequirement( + cast(Req)); + if (!TransReq) + return true; + Transformed.push_back(TransReq); + } + return false; +} + +template +concepts::TypeRequirement * +TreeTransform::TransformTypeRequirement( + concepts::TypeRequirement *Req) { + if (Req->isSubstitutionFailure()) { + if (getDerived().AlwaysRebuild()) + return getDerived().RebuildTypeRequirement( + Req->getSubstitutionDiagnostic()); + return Req; + } + TypeSourceInfo *TransType = getDerived().TransformType(Req->getType()); + if (!TransType) + return nullptr; + return getDerived().RebuildTypeRequirement(TransType); +} + +template +concepts::ExprRequirement * +TreeTransform::TransformExprRequirement(concepts::ExprRequirement *Req) { + llvm::PointerUnion TransExpr; + if (Req->isExprSubstitutionFailure()) + TransExpr = Req->getExprSubstitutionDiagnostic(); + else { + ExprResult TransExprRes = getDerived().TransformExpr(Req->getExpr()); + if (TransExprRes.isInvalid()) + return nullptr; + TransExpr = TransExprRes.get(); + } + + llvm::Optional TransRetReq; + const auto &RetReq = Req->getReturnTypeRequirement(); + if (RetReq.isEmpty()) + TransRetReq.emplace(); + else if (RetReq.isSubstitutionFailure()) + TransRetReq.emplace(RetReq.getSubstitutionDiagnostic()); + else if (RetReq.isTypeConstraint()) { + TemplateParameterList *OrigTPL = + RetReq.getTypeConstraintTemplateParameterList(); + TemplateParameterList *TPL = + getDerived().TransformTemplateParameterList(OrigTPL); + if (!TPL) + return nullptr; + TransRetReq.emplace(TPL); + } + assert(TransRetReq.hasValue() && + "All code paths leading here must set TransRetReq"); + if (Expr *E = TransExpr.dyn_cast()) + return getDerived().RebuildExprRequirement(E, Req->isSimple(), + Req->getNoexceptLoc(), + std::move(*TransRetReq)); + return getDerived().RebuildExprRequirement( + TransExpr.get(), + Req->isSimple(), Req->getNoexceptLoc(), std::move(*TransRetReq)); +} + +template +concepts::NestedRequirement * +TreeTransform::TransformNestedRequirement( + concepts::NestedRequirement *Req) { + if (Req->isSubstitutionFailure()) { + if (getDerived().AlwaysRebuild()) + return getDerived().RebuildNestedRequirement( + Req->getSubstitutionDiagnostic()); + return Req; + } + ExprResult TransConstraint = + getDerived().TransformExpr(Req->getConstraintExpr()); + if (TransConstraint.isInvalid()) + return nullptr; + return getDerived().RebuildNestedRequirement(TransConstraint.get()); +} template ExprResult @@ -11560,6 +11811,8 @@ TreeTransform::TransformLambdaExpr(LambdaExpr *E) { NewTrailingRequiresClause = getDerived().TransformExpr(TRC); // Create the local class that will describe the lambda. + // FIXME: KnownDependent below is wrong when substituting inside a templated + // context that isn't a DeclContext (such as a variable template). CXXRecordDecl *OldClass = E->getLambdaClass(); CXXRecordDecl *Class = getSema().createLambdaClosureType(E->getIntroducerRange(), diff --git a/clang/lib/Serialization/ASTCommon.cpp b/clang/lib/Serialization/ASTCommon.cpp index cdb5b17022c2f..f93f1f77405d3 100644 --- a/clang/lib/Serialization/ASTCommon.cpp +++ b/clang/lib/Serialization/ASTCommon.cpp @@ -402,6 +402,7 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) { case Decl::Binding: case Decl::Concept: case Decl::LifetimeExtendedTemporary: + case Decl::RequiresExprBody: return false; // These indirectly derive from Redeclarable but are not actually diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 19e7ebe03a1fd..652b772f37cc2 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -3224,8 +3224,7 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { case MODULAR_CODEGEN_DECLS: // FIXME: Skip reading this record if our ASTConsumer doesn't care about // them (ie: if we're not codegenerating this module). - if (F.Kind == MK_MainFile || - getContext().getLangOpts().BuildingPCHWithObjectFile) + if (F.Kind == MK_MainFile) for (unsigned I = 0, N = Record.size(); I != N; ++I) EagerlyDeserializedDecls.push_back(getGlobalDeclID(F, Record[I])); break; @@ -6576,6 +6575,17 @@ void TypeLocReader::VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) { void TypeLocReader::VisitAutoTypeLoc(AutoTypeLoc TL) { TL.setNameLoc(readSourceLocation()); + if (Reader.readBool()) { + TL.setNestedNameSpecifierLoc(ReadNestedNameSpecifierLoc()); + TL.setTemplateKWLoc(readSourceLocation()); + TL.setConceptNameLoc(readSourceLocation()); + TL.setFoundDecl(Reader.readDeclAs()); + TL.setLAngleLoc(readSourceLocation()); + TL.setRAngleLoc(readSourceLocation()); + for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) + TL.setArgLocInfo(i, Reader.readTemplateArgumentLocInfo( + TL.getTypePtr()->getArg(i).getKind())); + } } void TypeLocReader::VisitDeducedTemplateSpecializationTypeLoc( diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index 96a7d5ae0a31c..e3eea3c6f8606 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -375,6 +375,7 @@ namespace clang { void VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D); DeclID VisitTemplateDecl(TemplateDecl *D); void VisitConceptDecl(ConceptDecl *D); + void VisitRequiresExprBodyDecl(RequiresExprBodyDecl *D); RedeclarableResult VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D); void VisitClassTemplateDecl(ClassTemplateDecl *D); void VisitBuiltinTemplateDecl(BuiltinTemplateDecl *D); @@ -501,12 +502,8 @@ uint64_t ASTDeclReader::GetCurrentCursorOffset() { } void ASTDeclReader::ReadFunctionDefinition(FunctionDecl *FD) { - if (Record.readInt()) { + if (Record.readInt()) Reader.DefinitionSource[FD] = Loc.F->Kind == ModuleKind::MK_MainFile; - if (Reader.getContext().getLangOpts().BuildingPCHWithObjectFile && - Reader.DeclIsFromPCHWithObjectFile(FD)) - Reader.DefinitionSource[FD] = true; - } if (auto *CD = dyn_cast(FD)) { CD->setNumCtorInitializers(Record.readInt()); if (CD->getNumCtorInitializers()) @@ -554,7 +551,7 @@ void ASTDeclReader::Visit(Decl *D) { void ASTDeclReader::VisitDecl(Decl *D) { if (D->isTemplateParameter() || D->isTemplateParameterPack() || - isa(D)) { + isa(D) || isa(D)) { // We don't want to deserialize the DeclContext of a template // parameter or of a parameter of a function template immediately. These // entities might be used in the formulation of its DeclContext (for @@ -1421,12 +1418,8 @@ ASTDeclReader::RedeclarableResult ASTDeclReader::VisitVarDeclImpl(VarDecl *VD) { Reader.getContext().setBlockVarCopyInit(VD, CopyExpr, Record.readInt()); } - if (VD->getStorageDuration() == SD_Static && Record.readInt()) { + if (VD->getStorageDuration() == SD_Static && Record.readInt()) Reader.DefinitionSource[VD] = Loc.F->Kind == ModuleKind::MK_MainFile; - if (Reader.getContext().getLangOpts().BuildingPCHWithObjectFile && - Reader.DeclIsFromPCHWithObjectFile(VD)) - Reader.DefinitionSource[VD] = true; - } enum VarKind { VarNotTemplate = 0, VarTemplate, StaticDataMemberSpecialization @@ -1685,12 +1678,8 @@ void ASTDeclReader::ReadCXXDefinitionData( Data.ODRHash = Record.readInt(); Data.HasODRHash = true; - if (Record.readInt()) { + if (Record.readInt()) Reader.DefinitionSource[D] = Loc.F->Kind == ModuleKind::MK_MainFile; - if (Reader.getContext().getLangOpts().BuildingPCHWithObjectFile && - Reader.DeclIsFromPCHWithObjectFile(D)) - Reader.DefinitionSource[D] = true; - } Data.NumBases = Record.readInt(); if (Data.NumBases) @@ -2037,6 +2026,9 @@ void ASTDeclReader::VisitConceptDecl(ConceptDecl *D) { mergeMergeable(D); } +void ASTDeclReader::VisitRequiresExprBodyDecl(RequiresExprBodyDecl *D) { +} + ASTDeclReader::RedeclarableResult ASTDeclReader::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) { RedeclarableResult Redecl = VisitRedeclarable(D); @@ -2313,12 +2305,12 @@ void ASTDeclReader::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) { D->setDeclaredWithTypename(Record.readInt()); - if (Record.readInt()) { + if (Record.readBool()) { NestedNameSpecifierLoc NNS = Record.readNestedNameSpecifierLoc(); DeclarationNameInfo DN = Record.readDeclarationNameInfo(); - ConceptDecl *NamedConcept = cast(Record.readDecl()); + ConceptDecl *NamedConcept = Record.readDeclAs(); const ASTTemplateArgumentListInfo *ArgsAsWritten = nullptr; - if (Record.readInt()) + if (Record.readBool()) ArgsAsWritten = Record.readASTTemplateArgumentListInfo(); Expr *ImmediatelyDeclaredConstraint = Record.readExpr(); D->setTypeConstraint(NNS, DN, /*FoundDecl=*/nullptr, NamedConcept, @@ -2336,6 +2328,8 @@ void ASTDeclReader::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) { // TemplateParmPosition. D->setDepth(Record.readInt()); D->setPosition(Record.readInt()); + if (D->hasPlaceholderTypeConstraint()) + D->setPlaceholderTypeConstraint(Record.readExpr()); if (D->isExpandedParameterPack()) { auto TypesAndInfos = D->getTrailingObjects>(); @@ -2873,7 +2867,8 @@ uint64_t ASTReader::getGlobalBitOffset(ModuleFile &M, uint32_t LocalOffset) { return LocalOffset + M.GlobalBitOffset; } -static bool isSameTemplateParameterList(const TemplateParameterList *X, +static bool isSameTemplateParameterList(const ASTContext &C, + const TemplateParameterList *X, const TemplateParameterList *Y); /// Determine whether two template parameters are similar enough @@ -2885,7 +2880,32 @@ static bool isSameTemplateParameter(const NamedDecl *X, if (const auto *TX = dyn_cast(X)) { const auto *TY = cast(Y); - return TX->isParameterPack() == TY->isParameterPack(); + if (TX->isParameterPack() != TY->isParameterPack()) + return false; + if (TX->hasTypeConstraint() != TY->hasTypeConstraint()) + return false; + if (TX->hasTypeConstraint()) { + const TypeConstraint *TXTC = TX->getTypeConstraint(); + const TypeConstraint *TYTC = TY->getTypeConstraint(); + if (TXTC->getNamedConcept() != TYTC->getNamedConcept()) + return false; + if (TXTC->hasExplicitTemplateArgs() != TYTC->hasExplicitTemplateArgs()) + return false; + if (TXTC->hasExplicitTemplateArgs()) { + const auto *TXTCArgs = TXTC->getTemplateArgsAsWritten(); + const auto *TYTCArgs = TYTC->getTemplateArgsAsWritten(); + if (TXTCArgs->NumTemplateArgs != TYTCArgs->NumTemplateArgs) + return false; + llvm::FoldingSetNodeID XID, YID; + for (const auto &ArgLoc : TXTCArgs->arguments()) + ArgLoc.getArgument().Profile(XID, X->getASTContext()); + for (const auto &ArgLoc : TYTCArgs->arguments()) + ArgLoc.getArgument().Profile(YID, Y->getASTContext()); + if (XID != YID) + return false; + } + } + return true; } if (const auto *TX = dyn_cast(X)) { @@ -2897,7 +2917,8 @@ static bool isSameTemplateParameter(const NamedDecl *X, const auto *TX = cast(X); const auto *TY = cast(Y); return TX->isParameterPack() == TY->isParameterPack() && - isSameTemplateParameterList(TX->getTemplateParameters(), + isSameTemplateParameterList(TX->getASTContext(), + TX->getTemplateParameters(), TY->getTemplateParameters()); } @@ -2950,7 +2971,8 @@ static bool isSameQualifier(const NestedNameSpecifier *X, /// Determine whether two template parameter lists are similar enough /// that they may be used in declarations of the same template. -static bool isSameTemplateParameterList(const TemplateParameterList *X, +static bool isSameTemplateParameterList(const ASTContext &C, + const TemplateParameterList *X, const TemplateParameterList *Y) { if (X->size() != Y->size()) return false; @@ -2959,6 +2981,18 @@ static bool 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 false; + if (XRC) { + llvm::FoldingSetNodeID XRCID, YRCID; + XRC->Profile(XRCID, C, /*Canonical=*/true); + YRC->Profile(YRCID, C, /*Canonical=*/true); + if (XRCID != YRCID) + return false; + } + return true; } @@ -2995,7 +3029,7 @@ static bool hasSameOverloadableAttrs(const FunctionDecl *A, return true; } -/// Determine whether the two declarations refer to the same entity. +/// Determine whether the two declarations refer to the same entity.pr static bool isSameEntity(NamedDecl *X, NamedDecl *Y) { assert(X->getDeclName() == Y->getDeclName() && "Declaration name mismatch!"); @@ -3070,6 +3104,19 @@ static bool isSameEntity(NamedDecl *X, NamedDecl *Y) { } ASTContext &C = FuncX->getASTContext(); + + const Expr *XRC = FuncX->getTrailingRequiresClause(); + const Expr *YRC = FuncY->getTrailingRequiresClause(); + if (!XRC != !YRC) + return false; + if (XRC) { + llvm::FoldingSetNodeID XRCID, YRCID; + XRC->Profile(XRCID, C, /*Canonical=*/true); + YRC->Profile(YRCID, C, /*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. // The TSI of redeclarations might not match (due to calling conventions @@ -3093,6 +3140,7 @@ static bool isSameEntity(NamedDecl *X, NamedDecl *Y) { return true; return false; } + return FuncX->getLinkageInternal() == FuncY->getLinkageInternal() && hasSameOverloadableAttrs(FuncX, FuncY); } @@ -3132,7 +3180,8 @@ static bool isSameEntity(NamedDecl *X, NamedDecl *Y) { const auto *TemplateY = cast(Y); return isSameEntity(TemplateX->getTemplatedDecl(), TemplateY->getTemplatedDecl()) && - isSameTemplateParameterList(TemplateX->getTemplateParameters(), + isSameTemplateParameterList(TemplateX->getASTContext(), + TemplateX->getTemplateParameters(), TemplateY->getTemplateParameters()); } @@ -3819,13 +3868,19 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) { HasTypeConstraint); break; } - case DECL_NON_TYPE_TEMPLATE_PARM: - D = NonTypeTemplateParmDecl::CreateDeserialized(Context, ID); + case DECL_NON_TYPE_TEMPLATE_PARM: { + bool HasTypeConstraint = Record.readInt(); + D = NonTypeTemplateParmDecl::CreateDeserialized(Context, ID, + HasTypeConstraint); break; - case DECL_EXPANDED_NON_TYPE_TEMPLATE_PARM_PACK: + } + case DECL_EXPANDED_NON_TYPE_TEMPLATE_PARM_PACK: { + bool HasTypeConstraint = Record.readInt(); D = NonTypeTemplateParmDecl::CreateDeserialized(Context, ID, - Record.readInt()); + Record.readInt(), + HasTypeConstraint); break; + } case DECL_TEMPLATE_TEMPLATE_PARM: D = TemplateTemplateParmDecl::CreateDeserialized(Context, ID); break; @@ -3839,6 +3894,9 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) { case DECL_CONCEPT: D = ConceptDecl::CreateDeserialized(Context, ID); break; + case DECL_REQUIRES_EXPR_BODY: + D = RequiresExprBodyDecl::CreateDeserialized(Context, ID); + break; case DECL_STATIC_ASSERT: D = StaticAssertDecl::CreateDeserialized(Context, ID); break; diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index f558c26b5f1e8..c38b3ad184674 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -724,27 +724,15 @@ void ASTStmtReader::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E) { E->setRParenLoc(readSourceLocation()); } -void ASTStmtReader::VisitConceptSpecializationExpr( - ConceptSpecializationExpr *E) { - VisitExpr(E); - unsigned NumTemplateArgs = Record.readInt(); - E->NestedNameSpec = Record.readNestedNameSpecifierLoc(); - E->TemplateKWLoc = Record.readSourceLocation(); - E->ConceptName = Record.readDeclarationNameInfo(); - E->NamedConcept = readDeclAs(); - E->ArgsAsWritten = Record.readASTTemplateArgumentListInfo(); - llvm::SmallVector Args; - for (unsigned I = 0; I < NumTemplateArgs; ++I) - Args.push_back(Record.readTemplateArgument()); - E->setTemplateArguments(Args); +static ConstraintSatisfaction +readConstraintSatisfaction(ASTRecordReader &Record) { ConstraintSatisfaction Satisfaction; Satisfaction.IsSatisfied = Record.readInt(); if (!Satisfaction.IsSatisfied) { unsigned NumDetailRecords = Record.readInt(); for (unsigned i = 0; i != NumDetailRecords; ++i) { Expr *ConstraintExpr = Record.readExpr(); - bool IsDiagnostic = Record.readInt(); - if (IsDiagnostic) { + if (bool IsDiagnostic = Record.readInt()) { SourceLocation DiagLocation = Record.readSourceLocation(); std::string DiagMessage = Record.readString(); Satisfaction.Details.emplace_back( @@ -755,8 +743,138 @@ void ASTStmtReader::VisitConceptSpecializationExpr( Satisfaction.Details.emplace_back(ConstraintExpr, Record.readExpr()); } } - E->Satisfaction = ASTConstraintSatisfaction::Create(Record.getContext(), - Satisfaction); + return Satisfaction; +} + +void ASTStmtReader::VisitConceptSpecializationExpr( + ConceptSpecializationExpr *E) { + VisitExpr(E); + unsigned NumTemplateArgs = Record.readInt(); + E->NestedNameSpec = Record.readNestedNameSpecifierLoc(); + E->TemplateKWLoc = Record.readSourceLocation(); + E->ConceptName = Record.readDeclarationNameInfo(); + E->NamedConcept = readDeclAs(); + E->FoundDecl = Record.readDeclAs(); + E->ArgsAsWritten = Record.readASTTemplateArgumentListInfo(); + llvm::SmallVector Args; + for (unsigned I = 0; I < NumTemplateArgs; ++I) + Args.push_back(Record.readTemplateArgument()); + E->setTemplateArguments(Args); + E->Satisfaction = E->isValueDependent() ? nullptr : + ASTConstraintSatisfaction::Create(Record.getContext(), + readConstraintSatisfaction(Record)); +} + +static concepts::Requirement::SubstitutionDiagnostic * +readSubstitutionDiagnostic(ASTRecordReader &Record) { + std::string SubstitutedEntity = Record.readString(); + SourceLocation DiagLoc = Record.readSourceLocation(); + std::string DiagMessage = Record.readString(); + return new (Record.getContext()) + concepts::Requirement::SubstitutionDiagnostic{SubstitutedEntity, DiagLoc, + DiagMessage}; +} + +void ASTStmtReader::VisitRequiresExpr(RequiresExpr *E) { + VisitExpr(E); + unsigned NumLocalParameters = Record.readInt(); + unsigned NumRequirements = Record.readInt(); + E->RequiresExprBits.RequiresKWLoc = Record.readSourceLocation(); + E->RequiresExprBits.IsSatisfied = Record.readInt(); + E->Body = Record.readDeclAs(); + llvm::SmallVector LocalParameters; + for (unsigned i = 0; i < NumLocalParameters; ++i) + LocalParameters.push_back(cast(Record.readDecl())); + std::copy(LocalParameters.begin(), LocalParameters.end(), + E->getTrailingObjects()); + llvm::SmallVector Requirements; + for (unsigned i = 0; i < NumRequirements; ++i) { + auto RK = + static_cast(Record.readInt()); + concepts::Requirement *R = nullptr; + switch (RK) { + case concepts::Requirement::RK_Type: { + auto Status = + static_cast( + Record.readInt()); + if (Status == concepts::TypeRequirement::SS_SubstitutionFailure) + R = new (Record.getContext()) + concepts::TypeRequirement(readSubstitutionDiagnostic(Record)); + else + R = new (Record.getContext()) + concepts::TypeRequirement(Record.readTypeSourceInfo()); + } break; + case concepts::Requirement::RK_Simple: + case concepts::Requirement::RK_Compound: { + auto Status = + static_cast( + Record.readInt()); + llvm::PointerUnion E; + if (Status == concepts::ExprRequirement::SS_ExprSubstitutionFailure) { + E = readSubstitutionDiagnostic(Record); + } else + E = Record.readExpr(); + + llvm::Optional Req; + ConceptSpecializationExpr *SubstitutedConstraintExpr = nullptr; + SourceLocation NoexceptLoc; + if (RK == concepts::Requirement::RK_Simple) { + Req.emplace(); + } else { + NoexceptLoc = Record.readSourceLocation(); + switch (auto returnTypeRequirementKind = Record.readInt()) { + case 0: + // No return type requirement. + Req.emplace(); + break; + case 1: { + // type-constraint + TemplateParameterList *TPL = Record.readTemplateParameterList(); + if (Status >= + concepts::ExprRequirement::SS_ConstraintsNotSatisfied) + SubstitutedConstraintExpr = + cast(Record.readExpr()); + Req.emplace(TPL); + } break; + case 2: + // Substitution failure + Req.emplace(readSubstitutionDiagnostic(Record)); + break; + } + } + if (Expr *Ex = E.dyn_cast()) + R = new (Record.getContext()) concepts::ExprRequirement( + Ex, RK == concepts::Requirement::RK_Simple, NoexceptLoc, + std::move(*Req), Status, SubstitutedConstraintExpr); + else + R = new (Record.getContext()) concepts::ExprRequirement( + E.get(), + RK == concepts::Requirement::RK_Simple, NoexceptLoc, + std::move(*Req)); + } break; + case concepts::Requirement::RK_Nested: { + if (bool IsSubstitutionDiagnostic = Record.readInt()) { + R = new (Record.getContext()) concepts::NestedRequirement( + readSubstitutionDiagnostic(Record)); + break; + } + Expr *E = Record.readExpr(); + if (E->isInstantiationDependent()) + R = new (Record.getContext()) concepts::NestedRequirement(E); + else + R = new (Record.getContext()) + concepts::NestedRequirement(Record.getContext(), E, + readConstraintSatisfaction(Record)); + } break; + } + if (!R) + continue; + Requirements.push_back(R); + } + std::copy(Requirements.begin(), Requirements.end(), + E->getTrailingObjects()); + E->RBraceLoc = Record.readSourceLocation(); } void ASTStmtReader::VisitArraySubscriptExpr(ArraySubscriptExpr *E) { @@ -1073,6 +1191,7 @@ void ASTStmtReader::VisitStmtExpr(StmtExpr *E) { E->setLParenLoc(readSourceLocation()); E->setRParenLoc(readSourceLocation()); E->setSubStmt(cast_or_null(Record.readSubStmt())); + E->StmtExprBits.TemplateDepth = Record.readInt(); } void ASTStmtReader::VisitChooseExpr(ChooseExpr *E) { @@ -3566,11 +3685,18 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { S = new (Context) DependentCoawaitExpr(Empty); break; - case EXPR_CONCEPT_SPECIALIZATION: + case EXPR_CONCEPT_SPECIALIZATION: { unsigned numTemplateArgs = Record[ASTStmtReader::NumExprFields]; S = ConceptSpecializationExpr::Create(Context, Empty, numTemplateArgs); break; - + } + + case EXPR_REQUIRES: + unsigned numLocalParameters = Record[ASTStmtReader::NumExprFields]; + unsigned numRequirement = Record[ASTStmtReader::NumExprFields + 1]; + S = RequiresExpr::Create(Context, Empty, numLocalParameters, + numRequirement); + break; } // We hit a STMT_STOP, so we're done with this expression. diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index 6eba48a1abe97..7626827b441a7 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -349,6 +349,18 @@ void TypeLocWriter::VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) { void TypeLocWriter::VisitAutoTypeLoc(AutoTypeLoc TL) { Record.AddSourceLocation(TL.getNameLoc()); + Record.push_back(TL.isConstrained()); + if (TL.isConstrained()) { + Record.AddNestedNameSpecifierLoc(TL.getNestedNameSpecifierLoc()); + Record.AddSourceLocation(TL.getTemplateKWLoc()); + Record.AddSourceLocation(TL.getConceptNameLoc()); + Record.AddDeclRef(TL.getFoundDecl()); + Record.AddSourceLocation(TL.getLAngleLoc()); + Record.AddSourceLocation(TL.getRAngleLoc()); + for (unsigned I = 0; I < TL.getNumArgs(); ++I) + Record.AddTemplateArgumentLocInfo(TL.getTypePtr()->getArg(I).getKind(), + TL.getArgLocInfo(I)); + } } void TypeLocWriter::VisitDeducedTemplateSpecializationTypeLoc( @@ -885,6 +897,7 @@ void ASTWriter::WriteBlockInfoBlock() { RECORD(DECL_NON_TYPE_TEMPLATE_PARM); RECORD(DECL_TEMPLATE_TEMPLATE_PARM); RECORD(DECL_CONCEPT); + RECORD(DECL_REQUIRES_EXPR_BODY); RECORD(DECL_TYPE_ALIAS_TEMPLATE); RECORD(DECL_STATIC_ASSERT); RECORD(DECL_CXX_BASE_SPECIFIERS); @@ -5583,8 +5596,8 @@ void ASTRecordWriter::AddCXXDefinitionData(const CXXRecordDecl *D) { // getODRHash will compute the ODRHash if it has not been previously computed. Record->push_back(D->getODRHash()); - bool ModulesDebugInfo = - Writer->Context->getLangOpts().ModulesDebugInfo && !D->isDependentType(); + bool ModulesDebugInfo = Writer->Context->getLangOpts().ModulesDebugInfo && + Writer->WritingModule && !D->isDependentType(); Record->push_back(ModulesDebugInfo); if (ModulesDebugInfo) Writer->ModularCodegenDecls.push_back(Writer->GetDeclRef(D)); diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index b2a8c118d4011..92d566fc78547 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -104,6 +104,7 @@ namespace clang { void VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D); void VisitTemplateDecl(TemplateDecl *D); void VisitConceptDecl(ConceptDecl *D); + void VisitRequiresExprBodyDecl(RequiresExprBodyDecl *D); void VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D); void VisitClassTemplateDecl(ClassTemplateDecl *D); void VisitVarTemplateDecl(VarTemplateDecl *D); @@ -1010,16 +1011,15 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) { if (D->getStorageDuration() == SD_Static) { bool ModulesCodegen = false; - if (!D->getDescribedVarTemplate() && !D->getMemberSpecializationInfo() && + if (Writer.WritingModule && + !D->getDescribedVarTemplate() && !D->getMemberSpecializationInfo() && !isa(D)) { // When building a C++ Modules TS module interface unit, a strong // definition in the module interface is provided by the compilation of // that module interface unit, not by its users. (Inline variables are // still emitted in module users.) ModulesCodegen = - (((Writer.WritingModule && - Writer.WritingModule->Kind == Module::ModuleInterfaceUnit) || - Writer.Context->getLangOpts().BuildingPCHWithObjectFile) && + (Writer.WritingModule->Kind == Module::ModuleInterfaceUnit && Writer.Context->GetGVALinkageForVariable(D) == GVA_StrongExternal); } Record.push_back(ModulesCodegen); @@ -1481,6 +1481,10 @@ void ASTDeclWriter::VisitConceptDecl(ConceptDecl *D) { Code = serialization::DECL_CONCEPT; } +void ASTDeclWriter::VisitRequiresExprBodyDecl(RequiresExprBodyDecl *D) { + Code = serialization::DECL_REQUIRES_EXPR_BODY; +} + void ASTDeclWriter::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) { VisitRedeclarable(D); @@ -1670,6 +1674,8 @@ void ASTDeclWriter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) { // For an expanded parameter pack, record the number of expansion types here // so that it's easier for deserialization to allocate the right amount of // memory. + Expr *TypeConstraint = D->getPlaceholderTypeConstraint(); + Record.push_back(!!TypeConstraint); if (D->isExpandedParameterPack()) Record.push_back(D->getNumExpansionTypes()); @@ -1677,6 +1683,8 @@ void ASTDeclWriter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) { // TemplateParmPosition. Record.push_back(D->getDepth()); Record.push_back(D->getPosition()); + if (TypeConstraint) + Record.AddStmt(TypeConstraint); if (D->isExpandedParameterPack()) { for (unsigned I = 0, N = D->getNumExpansionTypes(); I != N; ++I) { @@ -2440,11 +2448,9 @@ void ASTRecordWriter::AddFunctionDefinition(const FunctionDecl *FD) { assert(FD->doesThisDeclarationHaveABody()); bool ModulesCodegen = false; - if (!FD->isDependentContext()) { + if (Writer->WritingModule && !FD->isDependentContext()) { Optional Linkage; - if ((Writer->WritingModule && - Writer->WritingModule->Kind == Module::ModuleInterfaceUnit) || - Writer->Context->getLangOpts().BuildingPCHWithObjectFile) { + if (Writer->WritingModule->Kind == Module::ModuleInterfaceUnit) { // When building a C++ Modules TS module interface unit, a strong // definition in the module interface is provided by the compilation of // that module interface unit, not by its users. (Inline functions are diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp index 9231f3b2b9ba2..8519a4df019d7 100644 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "clang/Serialization/ASTRecordWriter.h" +#include "clang/Sema/DeclSpec.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" @@ -388,19 +389,9 @@ void ASTStmtWriter::VisitDependentCoawaitExpr(DependentCoawaitExpr *E) { Code = serialization::EXPR_DEPENDENT_COAWAIT; } -void ASTStmtWriter::VisitConceptSpecializationExpr( - ConceptSpecializationExpr *E) { - VisitExpr(E); - ArrayRef TemplateArgs = E->getTemplateArguments(); - Record.push_back(TemplateArgs.size()); - Record.AddNestedNameSpecifierLoc(E->getNestedNameSpecifierLoc()); - Record.AddSourceLocation(E->getTemplateKWLoc()); - Record.AddDeclarationNameInfo(E->getConceptNameInfo()); - Record.AddDeclRef(E->getNamedConcept()); - Record.AddASTTemplateArgumentListInfo(E->getTemplateArgsAsWritten()); - for (const TemplateArgument &Arg : TemplateArgs) - Record.AddTemplateArgument(Arg); - const ASTConstraintSatisfaction &Satisfaction = E->getSatisfaction(); +static void +addConstraintSatisfaction(ASTRecordWriter &Record, + const ASTConstraintSatisfaction &Satisfaction) { Record.push_back(Satisfaction.IsSatisfied); if (!Satisfaction.IsSatisfied) { Record.push_back(Satisfaction.NumRecords); @@ -418,10 +409,99 @@ void ASTStmtWriter::VisitConceptSpecializationExpr( } } } +} + +static void +addSubstitutionDiagnostic( + ASTRecordWriter &Record, + const concepts::Requirement::SubstitutionDiagnostic *D) { + Record.AddString(D->SubstitutedEntity); + Record.AddSourceLocation(D->DiagLoc); + Record.AddString(D->DiagMessage); +} + +void ASTStmtWriter::VisitConceptSpecializationExpr( + ConceptSpecializationExpr *E) { + VisitExpr(E); + ArrayRef TemplateArgs = E->getTemplateArguments(); + Record.push_back(TemplateArgs.size()); + Record.AddNestedNameSpecifierLoc(E->getNestedNameSpecifierLoc()); + Record.AddSourceLocation(E->getTemplateKWLoc()); + Record.AddDeclarationNameInfo(E->getConceptNameInfo()); + Record.AddDeclRef(E->getNamedConcept()); + Record.AddDeclRef(E->getFoundDecl()); + Record.AddASTTemplateArgumentListInfo(E->getTemplateArgsAsWritten()); + for (const TemplateArgument &Arg : TemplateArgs) + Record.AddTemplateArgument(Arg); + if (!E->isValueDependent()) + addConstraintSatisfaction(Record, E->getSatisfaction()); Code = serialization::EXPR_CONCEPT_SPECIALIZATION; } +void ASTStmtWriter::VisitRequiresExpr(RequiresExpr *E) { + VisitExpr(E); + Record.push_back(E->getLocalParameters().size()); + Record.push_back(E->getRequirements().size()); + Record.AddSourceLocation(E->RequiresExprBits.RequiresKWLoc); + Record.push_back(E->RequiresExprBits.IsSatisfied); + Record.AddDeclRef(E->getBody()); + for (ParmVarDecl *P : E->getLocalParameters()) + Record.AddDeclRef(P); + for (concepts::Requirement *R : E->getRequirements()) { + if (auto *TypeReq = dyn_cast(R)) { + Record.push_back(concepts::Requirement::RK_Type); + Record.push_back(TypeReq->Status); + if (TypeReq->Status == concepts::TypeRequirement::SS_SubstitutionFailure) + addSubstitutionDiagnostic(Record, TypeReq->getSubstitutionDiagnostic()); + else + Record.AddTypeSourceInfo(TypeReq->getType()); + } else if (auto *ExprReq = dyn_cast(R)) { + Record.push_back(ExprReq->getKind()); + Record.push_back(ExprReq->Status); + if (ExprReq->isExprSubstitutionFailure()) { + addSubstitutionDiagnostic(Record, + ExprReq->Value.get()); + } else + Record.AddStmt(ExprReq->Value.get()); + if (ExprReq->getKind() == concepts::Requirement::RK_Compound) { + Record.AddSourceLocation(ExprReq->NoexceptLoc); + const auto &RetReq = ExprReq->getReturnTypeRequirement(); + if (RetReq.isSubstitutionFailure()) { + Record.push_back(2); + addSubstitutionDiagnostic(Record, RetReq.getSubstitutionDiagnostic()); + } else if (RetReq.isTypeConstraint()) { + Record.push_back(1); + Record.AddTemplateParameterList( + RetReq.getTypeConstraintTemplateParameterList()); + if (ExprReq->Status >= + concepts::ExprRequirement::SS_ConstraintsNotSatisfied) + Record.AddStmt( + ExprReq->getReturnTypeRequirementSubstitutedConstraintExpr()); + } else { + assert(RetReq.isEmpty()); + Record.push_back(0); + } + } + } else { + auto *NestedReq = cast(R); + Record.push_back(concepts::Requirement::RK_Nested); + Record.push_back(NestedReq->isSubstitutionFailure()); + if (NestedReq->isSubstitutionFailure()){ + addSubstitutionDiagnostic(Record, + NestedReq->getSubstitutionDiagnostic()); + } else { + Record.AddStmt(NestedReq->Value.get()); + if (!NestedReq->isDependent()) + addConstraintSatisfaction(Record, *NestedReq->Satisfaction); + } + } + } + Record.AddSourceLocation(E->getEndLoc()); + + Code = serialization::EXPR_REQUIRES; +} + void ASTStmtWriter::VisitCapturedStmt(CapturedStmt *S) { VisitStmt(S); @@ -989,6 +1069,7 @@ void ASTStmtWriter::VisitStmtExpr(StmtExpr *E) { Record.AddStmt(E->getSubStmt()); Record.AddSourceLocation(E->getLParenLoc()); Record.AddSourceLocation(E->getRParenLoc()); + Record.push_back(E->getTemplateDepth()); Code = serialization::EXPR_STMT; } diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index f917a4c8637b6..b542cf2c03038 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -1386,6 +1386,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::AsTypeExprClass: case Stmt::ConceptSpecializationExprClass: case Stmt::CXXRewrittenBinaryOperatorClass: + case Stmt::RequiresExprClass: // Fall through. // Cases we intentionally don't evaluate, since they don't need diff --git a/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp b/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp index a4918d7179ff5..002b6070ddcd1 100644 --- a/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp +++ b/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp @@ -607,10 +607,17 @@ window.addEventListener("keydown", function (event) { )<<<"; } +static bool shouldDisplayPopUpRange(const SourceRange &Range) { + return !(Range.getBegin().isMacroID() || Range.getEnd().isMacroID()); +} + static void HandlePopUpPieceStartTag(Rewriter &R, const std::vector &PopUpRanges) { for (const auto &Range : PopUpRanges) { + if (!shouldDisplayPopUpRange(Range)) + continue; + html::HighlightRange(R, Range.getBegin(), Range.getEnd(), "", "", /*IsTokenRange=*/true); @@ -626,6 +633,8 @@ static void HandlePopUpPieceEndTag(Rewriter &R, llvm::raw_svector_ostream Out(Buf); SourceRange Range(Piece.getLocation().asRange()); + if (!shouldDisplayPopUpRange(Range)) + return; // Write out the path indices with a right arrow and the message as a row. Out << ""; + << ")\">←"; } os << " +// CHECK-NOT: +// CHECK-SAME: +// CHECK-SAME: MACRO +// CHECK-SAME: +// CHECK-SAME: if (b) +// CHECK-SAME: +// CHECK-SAME: diff --git a/clang/test/Analysis/html_diagnostics/variable-popups-multiple.c b/clang/test/Analysis/html_diagnostics/variable-popups-multiple.c new file mode 100644 index 0000000000000..d7a05b53e4f53 --- /dev/null +++ b/clang/test/Analysis/html_diagnostics/variable-popups-multiple.c @@ -0,0 +1,29 @@ +// RUN: rm -fR %t +// RUN: mkdir %t +// RUN: %clang_analyze_cc1 -analyzer-checker=core \ +// RUN: -analyzer-output=html -o %t -verify %s +// RUN: cat %t/report-*.html | FileCheck %s + +void bar(int); + +void foo() { + int a; + for (unsigned i = 0; i < 3; ++i) + if (i) + bar(a); // expected-warning{{1st function call argument is an uninitialized value}} +} + +// CHECK: i +// CHECK-SAME:
" @@ -870,7 +879,7 @@ void HTMLDiagnostics::HandlePiece(Rewriter &R, FileID BugFileID, << (num - 1) << "\" title=\"Previous event (" << (num - 1) - << ")\">←
"; diff --git a/clang/lib/Tooling/ArgumentsAdjusters.cpp b/clang/lib/Tooling/ArgumentsAdjusters.cpp index a609e4ed2469b..ec15311d4bacb 100644 --- a/clang/lib/Tooling/ArgumentsAdjusters.cpp +++ b/clang/lib/Tooling/ArgumentsAdjusters.cpp @@ -42,6 +42,12 @@ ArgumentsAdjuster getClangSyntaxOnlyAdjuster() { if (!Arg.startswith("-fcolor-diagnostics") && !Arg.startswith("-fdiagnostics-color")) AdjustedArgs.push_back(Args[i]); + // If we strip a color option, make sure we strip any preceeding `-Xclang` + // option as well. + // FIXME: This should be added to most argument adjusters! + else if (!AdjustedArgs.empty() && AdjustedArgs.back() == "-Xclang") + AdjustedArgs.pop_back(); + if (Arg == "-fsyntax-only") HasSyntaxOnly = true; } diff --git a/clang/test/AST/ast-dump-record-definition-data-json.cpp b/clang/test/AST/ast-dump-record-definition-data-json.cpp index 2603eedcd8178..44ec2a2f7bc62 100644 --- a/clang/test/AST/ast-dump-record-definition-data-json.cpp +++ b/clang/test/AST/ast-dump-record-definition-data-json.cpp @@ -417,15 +417,24 @@ struct DoesNotAllowConstDefaultInit { // CHECK-NEXT: "id": "0x{{.*}}", // CHECK-NEXT: "kind": "TemplateTypeParmDecl", // CHECK-NEXT: "loc": { -// CHECK-NEXT: "offset": 193, -// CHECK-NEXT: "col": 29, -// CHECK-NEXT: "tokLen": 4 +// CHECK-NEXT: "offset": 197, +// CHECK-NEXT: "col": 33, +// CHECK-NEXT: "tokLen": 1 // CHECK-NEXT: }, // CHECK-NEXT: "range": { -// CHECK-NEXT: "begin": {}, -// CHECK-NEXT: "end": {} +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "offset": 193, +// CHECK-NEXT: "col": 29, +// CHECK-NEXT: "tokLen": 4 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "offset": 197, +// CHECK-NEXT: "col": 33, +// CHECK-NEXT: "tokLen": 1 +// CHECK-NEXT: } // CHECK-NEXT: }, // CHECK-NEXT: "isImplicit": true, +// CHECK-NEXT: "name": "auto:1", // CHECK-NEXT: "tagUsed": "class", // CHECK-NEXT: "depth": 0, // CHECK-NEXT: "index": 0 @@ -524,15 +533,24 @@ struct DoesNotAllowConstDefaultInit { // CHECK-NEXT: "id": "0x{{.*}}", // CHECK-NEXT: "kind": "TemplateTypeParmDecl", // CHECK-NEXT: "loc": { -// CHECK-NEXT: "offset": 193, -// CHECK-NEXT: "col": 29, -// CHECK-NEXT: "tokLen": 4 +// CHECK-NEXT: "offset": 197, +// CHECK-NEXT: "col": 33, +// CHECK-NEXT: "tokLen": 1 // CHECK-NEXT: }, // CHECK-NEXT: "range": { -// CHECK-NEXT: "begin": {}, -// CHECK-NEXT: "end": {} +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "offset": 193, +// CHECK-NEXT: "col": 29, +// CHECK-NEXT: "tokLen": 4 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "offset": 197, +// CHECK-NEXT: "col": 33, +// CHECK-NEXT: "tokLen": 1 +// CHECK-NEXT: } // CHECK-NEXT: }, // CHECK-NEXT: "isImplicit": true, +// CHECK-NEXT: "name": "auto:1", // CHECK-NEXT: "tagUsed": "class", // CHECK-NEXT: "depth": 0, // CHECK-NEXT: "index": 0 @@ -590,15 +608,24 @@ struct DoesNotAllowConstDefaultInit { // CHECK-NEXT: "id": "0x{{.*}}", // CHECK-NEXT: "kind": "TemplateTypeParmDecl", // CHECK-NEXT: "loc": { -// CHECK-NEXT: "offset": 193, -// CHECK-NEXT: "col": 29, -// CHECK-NEXT: "tokLen": 4 +// CHECK-NEXT: "offset": 197, +// CHECK-NEXT: "col": 33, +// CHECK-NEXT: "tokLen": 1 // CHECK-NEXT: }, // CHECK-NEXT: "range": { -// CHECK-NEXT: "begin": {}, -// CHECK-NEXT: "end": {} +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "offset": 193, +// CHECK-NEXT: "col": 29, +// CHECK-NEXT: "tokLen": 4 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "offset": 197, +// CHECK-NEXT: "col": 33, +// CHECK-NEXT: "tokLen": 1 +// CHECK-NEXT: } // CHECK-NEXT: }, // CHECK-NEXT: "isImplicit": true, +// CHECK-NEXT: "name": "auto:1", // CHECK-NEXT: "tagUsed": "class", // CHECK-NEXT: "depth": 0, // CHECK-NEXT: "index": 0 diff --git a/clang/test/Analysis/html_diagnostics/td-hotfix.c b/clang/test/Analysis/html_diagnostics/td-hotfix.c new file mode 100644 index 0000000000000..8595642ad0f58 --- /dev/null +++ b/clang/test/Analysis/html_diagnostics/td-hotfix.c @@ -0,0 +1,31 @@ +// RUN: rm -fR %t +// RUN: mkdir %t +// RUN: %clang_analyze_cc1 -analyzer-checker=core \ +// RUN: -analyzer-output=html -o %t -verify %s +// RUN: cat %t/report-*.html | FileCheck %s + +void bar(int); + +void foo() { + int a; + bar(a); // expected-warning{{1st function call argument is an uninitialized value}} +} + +// CHECK-LABEL:
+// CHECK-SAME: +// CHECK-SAME: +// CHECK-SAME: +// CHECK-SAME: +// CHECK-NOT: +// CHECK-SAME: +// CHECK-SAME: +// CHECK-SAME:
+// CHECK-SAME:
2
+// CHECK-SAME:
+// CHECK-SAME:
+// CHECK-SAME: +// CHECK-SAME:
+// CHECK-SAME:
+// CHECK-SAME: 1st function call argument is an uninitialized value +// CHECK-SAME:
+// CHECK-SAME:
diff --git a/clang/test/Analysis/html_diagnostics/variable-popups-macro.c b/clang/test/Analysis/html_diagnostics/variable-popups-macro.c new file mode 100644 index 0000000000000..83bda14d4f2f7 --- /dev/null +++ b/clang/test/Analysis/html_diagnostics/variable-popups-macro.c @@ -0,0 +1,28 @@ +// RUN: rm -fR %t +// RUN: mkdir %t +// RUN: %clang_analyze_cc1 -analyzer-checker=core \ +// RUN: -analyzer-output=html -o %t -verify %s +// RUN: cat %t/report-*.html | FileCheck %s + +void bar(int); + +#define MACRO if (b) + +void foo2() { + int a; + int b = 1; + MACRO + bar(a); // expected-warning{{1st function call argument is an uninitialized value}} +} + +// For now we don't emit popups inside macros due to UI limitations. +// Once we do, we should test it thoroughly. + +// CHECK-LABEL:
+// CHECK-SAME: +// CHECK-SAME: +// CHECK-SAME: +// CHECK-SAME: +// CHECK-SAME: +// CHECK-SAME: +// CHECK-SAME:
+// CHECK-SAME:
2.1
+// CHECK-SAME:
'i' is 0
+// CHECK-SAME:
4.1
+// CHECK-SAME:
'i' is 1
+// CHECK-SAME: diff --git a/clang/test/Analysis/html_diagnostics/variable-popups-simple.c b/clang/test/Analysis/html_diagnostics/variable-popups-simple.c new file mode 100644 index 0000000000000..cb2f3bf3226d5 --- /dev/null +++ b/clang/test/Analysis/html_diagnostics/variable-popups-simple.c @@ -0,0 +1,23 @@ +// RUN: rm -fR %t +// RUN: mkdir %t +// RUN: %clang_analyze_cc1 -analyzer-checker=core \ +// RUN: -analyzer-output=html -o %t -verify %s +// RUN: cat %t/report-*.html | FileCheck %s + +void bar(int); + +void foo2() { + int a; + int b = 1; + if (b) + bar(a); // expected-warning{{1st function call argument is an uninitialized value}} +} + +// CHECK: b +// CHECK-SAME: +// CHECK-SAME: +// CHECK-SAME: +// CHECK-SAME:
+// CHECK-SAME:
1.1
+// CHECK-SAME:
'b' is 1
+// CHECK-SAME:
diff --git a/clang/test/CMakeLists.txt b/clang/test/CMakeLists.txt index 2c6487e8c2608..7fdc7d0be79f3 100644 --- a/clang/test/CMakeLists.txt +++ b/clang/test/CMakeLists.txt @@ -9,6 +9,15 @@ endif () string(REPLACE ${CMAKE_CFG_INTDIR} ${LLVM_BUILD_MODE} CLANG_TOOLS_DIR ${LLVM_RUNTIME_OUTPUT_INTDIR}) +if(CLANG_BUILT_STANDALONE) + # Set HAVE_LIBZ according to recorded LLVM_ENABLE_ZLIB value. This + # value is forced to 0 if zlib was not found, so it is fine to use it + # instead of HAVE_LIBZ (not recorded). + if(LLVM_ENABLE_ZLIB) + set(HAVE_LIBZ 1) + endif() +endif() + llvm_canonicalize_cmake_booleans( CLANG_BUILD_EXAMPLES CLANG_ENABLE_ARCMT @@ -16,7 +25,7 @@ llvm_canonicalize_cmake_booleans( CLANG_SPAWN_CC1 ENABLE_BACKTRACES ENABLE_EXPERIMENTAL_NEW_PASS_MANAGER - LLVM_ENABLE_ZLIB + HAVE_LIBZ LLVM_ENABLE_PER_TARGET_RUNTIME_DIR LLVM_ENABLE_PLUGINS LLVM_ENABLE_THREADS) diff --git a/clang/test/CXX/basic/basic.lookup/basic.lookup.unqual/p3.cpp b/clang/test/CXX/basic/basic.lookup/basic.lookup.unqual/p3.cpp index 0138b88578f63..ef3b127ef82aa 100644 --- a/clang/test/CXX/basic/basic.lookup/basic.lookup.unqual/p3.cpp +++ b/clang/test/CXX/basic/basic.lookup/basic.lookup.unqual/p3.cpp @@ -1,6 +1,6 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s // RUN: %clang_cc1 -std=c++17 -fsyntax-only -verify %s -// RUN: %clang_cc1 -std=c++2a -fsyntax-only -verify %s +// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s typedef int fn; @@ -43,7 +43,7 @@ namespace std_example { int x = f(N::A()); #if __cplusplus <= 201703L - // expected-warning@-2 {{C++2a extension}} + // expected-warning@-2 {{C++20 extension}} #endif int y = g(N::A()); #if __cplusplus <= 201703L diff --git a/clang/test/CXX/class.derived/class.virtual/p6.cpp b/clang/test/CXX/class.derived/class.virtual/p6.cpp index 63a4313de5541..f0243a776b6be 100644 --- a/clang/test/CXX/class.derived/class.virtual/p6.cpp +++ b/clang/test/CXX/class.derived/class.virtual/p6.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -verify %s +// RUN: %clang_cc1 -std=c++2a -verify %s template class A { diff --git a/clang/test/CXX/class/class.compare/class.compare.default/p3.cpp b/clang/test/CXX/class/class.compare/class.compare.default/p3.cpp index 3d0ab2c5bde6f..81a48a393a068 100644 --- a/clang/test/CXX/class/class.compare/class.compare.default/p3.cpp +++ b/clang/test/CXX/class/class.compare/class.compare.default/p3.cpp @@ -190,3 +190,15 @@ bool operator<(const G&, const G&); bool operator<=(const G&, const G&); bool operator>(const G&, const G&); bool operator>=(const G&, const G&); + +namespace PR44721 { + template bool operator==(T const &, T const &) { return true; } + template bool operator!=(T const &, U const &) { return true; } + template int operator<=>(T const &, T const &) { return 0; } + + struct S { + friend bool operator==(const S &, const S &) = default; + friend bool operator<=>(const S &, const S &) = default; + int x; + }; +} diff --git a/clang/test/CXX/class/class.compare/class.compare.default/p4.cpp b/clang/test/CXX/class/class.compare/class.compare.default/p4.cpp index 3820b5b442876..8c303c63d899d 100644 --- a/clang/test/CXX/class/class.compare/class.compare.default/p4.cpp +++ b/clang/test/CXX/class/class.compare/class.compare.default/p4.cpp @@ -122,7 +122,7 @@ namespace NoInjectionIfOperatorEqualsDeclared { bool test_a = A() == A(); // expected-error {{invalid operands}} struct B { - friend void operator==(int, struct Q); // expected-note {{not viable}} + friend void operator==(int, struct Q); // expected-note 2{{not viable}} std::strong_ordering operator<=>(const B&) const = default; }; bool test_b = B() == B(); // expected-error {{invalid operands}} diff --git a/clang/test/CXX/class/class.compare/class.spaceship/p2.cpp b/clang/test/CXX/class/class.compare/class.spaceship/p2.cpp index 1290a063e7947..dae31e925ba1e 100644 --- a/clang/test/CXX/class/class.compare/class.spaceship/p2.cpp +++ b/clang/test/CXX/class/class.compare/class.spaceship/p2.cpp @@ -97,6 +97,39 @@ namespace Deduction { // Check that the above mechanism works. template void f(); // expected-note {{instantiation of}} + + std::strong_ordering x = A() <=> A(); +} + +namespace PR44723 { + // Make sure we trigger return type deduction for a callee 'operator<=>' + // before inspecting its return type. + template struct a { + friend constexpr auto operator<=>(a const &lhs, a const &rhs) { + return std::strong_ordering::equal; + } + }; + struct b { + friend constexpr auto operator<=>(b const &, b const &) = default; + a<0> m_value; + }; + std::strong_ordering cmp_b = b() <=> b(); + + struct c { + auto operator<=>(const c&) const&; // expected-note {{selected 'operator<=>' for base class 'c' declared here}} + }; + struct d : c { // expected-note {{base class 'c' declared here}} + friend auto operator<=>(const d&, const d&) = default; // #d + // expected-error@#d {{return type of defaulted 'operator<=>' cannot be deduced because three-way comparison for base class 'c' has a deduced return type and is not yet defined}} + // expected-warning@#d {{implicitly deleted}} + }; + auto c::operator<=>(const c&) const& { // #c + return std::strong_ordering::equal; + } + // expected-error@+1 {{overload resolution selected deleted operator '<=>'}} + std::strong_ordering cmp_d = d() <=> d(); + // expected-note@#c 2{{candidate}} + // expected-note@#d {{candidate function has been implicitly deleted}} } namespace BadDeducedType { @@ -118,8 +151,7 @@ namespace BadDeducedType { template concept CmpCat = true; struct D { - // FIXME: Once we support P1141R2, we should give a better diagnostic here: - // {{deduced return type for defaulted three-way comparison operator must be 'auto', not 'CmpCat auto'}} - friend CmpCat auto operator<=>(const D&, const D&) = default; // expected-error {{unknown type name 'CmpCat'}} + // expected-error@+1 {{deduced return type for defaulted three-way comparison operator must be 'auto', not 'CmpCat auto'}} + friend CmpCat auto operator<=>(const D&, const D&) = default; }; } diff --git a/clang/test/CXX/dcl.dcl/dcl.attr/dcl.attr.nodiscard/p2.cpp b/clang/test/CXX/dcl.dcl/dcl.attr/dcl.attr.nodiscard/p2.cpp index bdf829210e0fb..3d3223cda7560 100644 --- a/clang/test/CXX/dcl.dcl/dcl.attr/dcl.attr.nodiscard/p2.cpp +++ b/clang/test/CXX/dcl.dcl/dcl.attr/dcl.attr.nodiscard/p2.cpp @@ -1,6 +1,6 @@ -// RUN: %clang_cc1 -fsyntax-only -std=c++2a -verify -Wc++2a-extensions %s +// RUN: %clang_cc1 -fsyntax-only -std=c++20 -verify -Wc++20-extensions %s // RUN: %clang_cc1 -fsyntax-only -std=c++17 -verify -Wc++17-extensions %s -// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify -DEXT -Wc++17-extensions -Wc++2a-extensions %s +// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify -DEXT -Wc++17-extensions -Wc++20-extensions %s struct [[nodiscard]] S {}; S get_s(); @@ -73,7 +73,7 @@ LaterReason get_later_reason(); [[nodiscard("conflicting reason")]] int conflicting_reason(); [[nodiscard("special reason")]] int conflicting_reason(); -void cxx2a_use() { +void cxx20_use() { get_reason(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute: reason}} get_later_reason(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute: later reason}} another_reason(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute: another reason}} @@ -130,15 +130,15 @@ void usage() { // expected-warning@12 {{use of the 'nodiscard' attribute is a C++17 extension}} // expected-warning@13 {{use of the 'nodiscard' attribute is a C++17 extension}} // expected-warning@29 {{use of the 'nodiscard' attribute is a C++17 extension}} -// expected-warning@65 {{use of the 'nodiscard' attribute is a C++2a extension}} -// expected-warning@67 {{use of the 'nodiscard' attribute is a C++2a extension}} -// expected-warning@71 {{use of the 'nodiscard' attribute is a C++2a extension}} -// expected-warning@73 {{use of the 'nodiscard' attribute is a C++2a extension}} -// expected-warning@74 {{use of the 'nodiscard' attribute is a C++2a extension}} -// expected-warning@84 {{use of the 'nodiscard' attribute is a C++2a extension}} +// expected-warning@65 {{use of the 'nodiscard' attribute is a C++20 extension}} +// expected-warning@67 {{use of the 'nodiscard' attribute is a C++20 extension}} +// expected-warning@71 {{use of the 'nodiscard' attribute is a C++20 extension}} +// expected-warning@73 {{use of the 'nodiscard' attribute is a C++20 extension}} +// expected-warning@74 {{use of the 'nodiscard' attribute is a C++20 extension}} +// expected-warning@84 {{use of the 'nodiscard' attribute is a C++20 extension}} // expected-warning@86 {{use of the 'nodiscard' attribute is a C++17 extension}} -// expected-warning@87 {{use of the 'nodiscard' attribute is a C++2a extension}} +// expected-warning@87 {{use of the 'nodiscard' attribute is a C++20 extension}} // expected-warning@91 {{use of the 'nodiscard' attribute is a C++17 extension}} -// expected-warning@92 {{use of the 'nodiscard' attribute is a C++2a extension}} -// expected-warning@95 {{use of the 'nodiscard' attribute is a C++2a extension}} +// expected-warning@92 {{use of the 'nodiscard' attribute is a C++20 extension}} +// expected-warning@95 {{use of the 'nodiscard' attribute is a C++20 extension}} #endif diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp index 59c2ee7d936e3..9b0e7cc60f101 100644 --- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp +++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp @@ -1,6 +1,6 @@ -// RUN: %clang_cc1 -verify -fcxx-exceptions -triple=x86_64-linux-gnu -std=c++11 -Werror=c++1y-extensions -Werror=c++2a-extensions %s -// RUN: %clang_cc1 -verify -fcxx-exceptions -triple=x86_64-linux-gnu -std=c++1y -DCXX1Y -Werror=c++2a-extensions %s -// RUN: %clang_cc1 -verify -fcxx-exceptions -triple=x86_64-linux-gnu -std=c++2a -DCXX1Y -DCXX2A %s +// RUN: %clang_cc1 -verify -fcxx-exceptions -triple=x86_64-linux-gnu -std=c++11 -Werror=c++14-extensions -Werror=c++20-extensions %s +// RUN: %clang_cc1 -verify -fcxx-exceptions -triple=x86_64-linux-gnu -std=c++14 -DCXX14 -Werror=c++20-extensions %s +// RUN: %clang_cc1 -verify -fcxx-exceptions -triple=x86_64-linux-gnu -std=c++20 -DCXX14 -DCXX20 %s namespace N { typedef char C; @@ -54,11 +54,11 @@ struct T : SS, NonLiteral { // - its return type shall be a literal type; constexpr NonLiteral NonLiteralReturn() const { return {}; } // expected-error {{constexpr function's return type 'NonLiteral' is not a literal type}} constexpr void VoidReturn() const { return; } -#ifndef CXX1Y +#ifndef CXX14 // expected-error@-2 {{constexpr function's return type 'void' is not a literal type}} #endif constexpr ~T(); -#ifndef CXX2A +#ifndef CXX20 // expected-error@-2 {{destructor cannot be declared constexpr}} #endif typedef NonLiteral F() const; @@ -78,7 +78,7 @@ struct T : SS, NonLiteral { // don't have a literal return type. Defaulted assignment operators can't be // constexpr since they can't be const. constexpr T &operator=(const T&) = default; -#ifndef CXX1Y +#ifndef CXX14 // expected-error@-2 {{an explicitly-defaulted copy assignment operator may not have 'const', 'constexpr' or 'volatile' qualifiers}} // expected-warning@-3 {{C++14}} #else @@ -87,14 +87,14 @@ struct T : SS, NonLiteral { }; constexpr int T::OutOfLineVirtual() const { return 0; } -#ifdef CXX1Y +#ifdef CXX14 struct T2 { int n = 0; constexpr T2 &operator=(const T2&) = default; // ok }; struct T3 { constexpr T3 &operator=(const T3&) const = default; -#ifndef CXX2A +#ifndef CXX20 // expected-error@-2 {{an explicitly-defaulted copy assignment operator may not have 'const' or 'volatile' qualifiers}} #else // expected-warning@-4 {{explicitly defaulted copy assignment operator is implicitly deleted}} @@ -138,56 +138,56 @@ constexpr int AllowedStmtsCXX11() { return sizeof(K) + sizeof(C) + sizeof(K); } -// or a compound-statement that does not contain [CXX1Y] -constexpr int DisallowedStmtsCXX1Y_1(bool b) { +// or a compound-statement that does not contain [C++14] +constexpr int DisallowedStmtsCXX14_1(bool b) { // - an asm-definition if (b) asm("int3"); -#if !defined(CXX2A) - // expected-error@-2 {{use of this statement in a constexpr function is a C++2a extension}} +#if !defined(CXX20) + // expected-error@-2 {{use of this statement in a constexpr function is a C++20 extension}} #endif return 0; } -constexpr int DisallowedStmtsCXX1Y_2() { +constexpr int DisallowedStmtsCXX14_2() { // - a goto statement goto x; // expected-error {{statement not allowed in constexpr function}} x: return 0; } -constexpr int DisallowedStmtsCXX1Y_2_1() { +constexpr int DisallowedStmtsCXX14_2_1() { try { return 0; } catch (...) { merp: goto merp; // expected-error {{statement not allowed in constexpr function}} } } -constexpr int DisallowedStmtsCXX1Y_3() { +constexpr int DisallowedStmtsCXX14_3() { // - a try-block, try {} catch (...) {} -#if !defined(CXX2A) - // expected-error@-2 {{use of this statement in a constexpr function is a C++2a extension}} +#if !defined(CXX20) + // expected-error@-2 {{use of this statement in a constexpr function is a C++20 extension}} #endif return 0; } -constexpr int DisallowedStmtsCXX1Y_4() { +constexpr int DisallowedStmtsCXX14_4() { // - a definition of a variable of non-literal type NonLiteral nl; // expected-error {{variable of non-literal type 'NonLiteral' cannot be defined in a constexpr function}} return 0; } -constexpr int DisallowedStmtsCXX1Y_5() { +constexpr int DisallowedStmtsCXX14_5() { // - a definition of a variable of static storage duration static constexpr int n = 123; // expected-error {{static variable not permitted in a constexpr function}} return n; } -constexpr int DisallowedStmtsCXX1Y_6() { +constexpr int DisallowedStmtsCXX14_6() { // - a definition of a variable of thread storage duration thread_local constexpr int n = 123; // expected-error {{thread_local variable not permitted in a constexpr function}} return n; } -constexpr int DisallowedStmtsCXX1Y_7() { +constexpr int DisallowedStmtsCXX14_7() { // - a definition of a variable for which no initialization is performed int n; -#ifndef CXX2A +#ifndef CXX20 // expected-error@-2 {{uninitialized variable in a constexpr function}} #endif return 0; @@ -195,28 +195,28 @@ constexpr int DisallowedStmtsCXX1Y_7() { constexpr int ForStmt() { for (int n = 0; n < 10; ++n) -#ifndef CXX1Y +#ifndef CXX14 // expected-error@-2 {{statement not allowed in constexpr function}} #endif return 0; } constexpr int VarDecl() { int a = 0; -#ifndef CXX1Y +#ifndef CXX14 // expected-error@-2 {{variable declaration in a constexpr function is a C++14 extension}} #endif return 0; } constexpr int ConstexprVarDecl() { constexpr int a = 0; -#ifndef CXX1Y +#ifndef CXX14 // expected-error@-2 {{variable declaration in a constexpr function is a C++14 extension}} #endif return 0; } constexpr int VarWithCtorDecl() { Literal a; -#ifndef CXX1Y +#ifndef CXX14 // expected-error@-2 {{variable declaration in a constexpr function is a C++14 extension}} #endif return 0; @@ -224,7 +224,7 @@ constexpr int VarWithCtorDecl() { NonLiteral nl; constexpr NonLiteral &ExternNonLiteralVarDecl() { extern NonLiteral nl; -#ifndef CXX1Y +#ifndef CXX14 // expected-error@-2 {{variable declaration in a constexpr function is a C++14 extension}} #endif return nl; @@ -232,28 +232,28 @@ constexpr NonLiteral &ExternNonLiteralVarDecl() { static_assert(&ExternNonLiteralVarDecl() == &nl, ""); constexpr int FuncDecl() { constexpr int ForwardDecl(int); -#ifndef CXX1Y +#ifndef CXX14 // expected-error@-2 {{use of this statement in a constexpr function is a C++14 extension}} #endif return ForwardDecl(42); } constexpr int ClassDecl1() { typedef struct { } S1; -#ifndef CXX1Y +#ifndef CXX14 // expected-error@-2 {{type definition in a constexpr function is a C++14 extension}} #endif return 0; } constexpr int ClassDecl2() { using S2 = struct { }; -#ifndef CXX1Y +#ifndef CXX14 // expected-error@-2 {{type definition in a constexpr function is a C++14 extension}} #endif return 0; } constexpr int ClassDecl3() { struct S3 { }; -#ifndef CXX1Y +#ifndef CXX14 // expected-error@-2 {{type definition in a constexpr function is a C++14 extension}} #endif return 0; @@ -262,7 +262,7 @@ constexpr int NoReturn() {} // expected-error {{no return statement in constexpr constexpr int MultiReturn() { return 0; return 0; -#ifndef CXX1Y +#ifndef CXX14 // expected-error@-2 {{multiple return statements in constexpr function}} // expected-note@-4 {{return statement}} #endif @@ -310,7 +310,7 @@ namespace std_example { } constexpr int abs(int x) { if (x < 0) -#ifndef CXX1Y +#ifndef CXX14 // expected-error@-2 {{C++14}} #endif x = -x; @@ -322,7 +322,7 @@ namespace std_example { } constexpr int uninit() { int a; -#ifndef CXX2A +#ifndef CXX20 // expected-error@-2 {{uninitialized}} #endif return a; @@ -330,7 +330,7 @@ namespace std_example { constexpr int prev(int x) { return --x; } -#ifndef CXX1Y +#ifndef CXX14 // expected-error@-4 {{never produces a constant expression}} // expected-note@-4 {{subexpression}} #endif @@ -339,7 +339,7 @@ namespace std_example { while (--n > 0) r *= x; return r; } -#ifndef CXX1Y +#ifndef CXX14 // expected-error@-5 {{C++14}} // expected-error@-5 {{statement not allowed}} #endif diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp index 39088042251f0..aed2f29f67c3a 100644 --- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp +++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp @@ -1,6 +1,6 @@ -// RUN: %clang_cc1 -verify -std=c++11 -fcxx-exceptions -Werror=c++1y-extensions -Werror=c++2a-extensions %s -// RUN: %clang_cc1 -verify -std=c++1y -fcxx-exceptions -DCXX1Y -Werror=c++2a-extensions %s -// RUN: %clang_cc1 -verify -std=c++2a -fcxx-exceptions -DCXX1Y -DCXX2A %s +// RUN: %clang_cc1 -verify -std=c++11 -fcxx-exceptions -Werror=c++14-extensions -Werror=c++20-extensions %s +// RUN: %clang_cc1 -verify -std=c++14 -fcxx-exceptions -DCXX14 -Werror=c++20-extensions %s +// RUN: %clang_cc1 -verify -std=c++20 -fcxx-exceptions -DCXX14 -DCXX2A %s namespace N { typedef char C; @@ -52,10 +52,10 @@ struct U { constexpr U() try #ifndef CXX2A - // expected-error@-2 {{function try block in constexpr constructor is a C++2a extension}} + // expected-error@-2 {{function try block in constexpr constructor is a C++20 extension}} #endif : u() { -#ifndef CXX1Y +#ifndef CXX14 // expected-error@-2 {{use of this statement in a constexpr constructor is a C++14 extension}} #endif } catch (...) { @@ -92,43 +92,43 @@ struct V { constexpr V(int(&)[1]) { for (int n = 0; n < 10; ++n) /**/; -#ifndef CXX1Y +#ifndef CXX14 // expected-error@-3 {{statement not allowed in constexpr constructor}} #endif } constexpr V(int(&)[2]) { constexpr int a = 0; -#ifndef CXX1Y +#ifndef CXX14 // expected-error@-2 {{variable declaration in a constexpr constructor is a C++14 extension}} #endif } constexpr V(int(&)[3]) { constexpr int ForwardDecl(int); -#ifndef CXX1Y +#ifndef CXX14 // expected-error@-2 {{use of this statement in a constexpr constructor is a C++14 extension}} #endif } constexpr V(int(&)[4]) { typedef struct { } S1; -#ifndef CXX1Y +#ifndef CXX14 // expected-error@-2 {{type definition in a constexpr constructor is a C++14 extension}} #endif } constexpr V(int(&)[5]) { using S2 = struct { }; -#ifndef CXX1Y +#ifndef CXX14 // expected-error@-2 {{type definition in a constexpr constructor is a C++14 extension}} #endif } constexpr V(int(&)[6]) { struct S3 { }; -#ifndef CXX1Y +#ifndef CXX14 // expected-error@-2 {{type definition in a constexpr constructor is a C++14 extension}} #endif } constexpr V(int(&)[7]) { return; -#ifndef CXX1Y +#ifndef CXX14 // expected-error@-2 {{use of this statement in a constexpr constructor is a C++14 extension}} #endif } diff --git a/clang/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p1.cpp b/clang/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p1.cpp index 6e9b45903d394..9614a17241996 100644 --- a/clang/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p1.cpp +++ b/clang/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p1.cpp @@ -1,10 +1,10 @@ -// RUN: %clang_cc1 -verify=expected,pre2a %s -std=c++11 -// RUN: %clang_cc1 -verify=expected,pre2a %s -std=c++17 -// RUN: %clang_cc1 -verify=expected %s -std=c++2a +// RUN: %clang_cc1 -verify=expected,pre20 %s -std=c++11 +// RUN: %clang_cc1 -verify=expected,pre20 %s -std=c++17 +// RUN: %clang_cc1 -verify=expected %s -std=c++20 // A function that is explicitly defaulted shall struct A { - // -- be a special member function [C++2a: or a comparison operator function], + // -- be a special member function [C++20: or a comparison operator function], A(int) = default; #if __cplusplus <= 201703L // expected-error@-2 {{only special member functions may be defaulted}} @@ -14,13 +14,13 @@ struct A { A(A) = default; // expected-error {{must pass its first argument by reference}} void f(A) = default; // expected-error-re {{only special member functions{{( and comparison operators)?}} may be defaulted}} - bool operator==(const A&) const = default; // pre2a-warning {{defaulted comparison operators are a C++20 extension}} - bool operator!=(const A&) const = default; // pre2a-warning {{defaulted comparison operators are a C++20 extension}} - bool operator<(const A&) const = default; // pre2a-error {{only special member functions may be defaulted}} - bool operator>(const A&) const = default; // pre2a-error {{only special member functions may be defaulted}} - bool operator<=(const A&) const = default; // pre2a-error {{only special member functions may be defaulted}} - bool operator>=(const A&) const = default; // pre2a-error {{only special member functions may be defaulted}} - bool operator<=>(const A&) const = default; // pre2a-error 1+{{}} pre2a-warning {{'<=>' is a single token in C++2a}} + bool operator==(const A&) const = default; // pre20-warning {{defaulted comparison operators are a C++20 extension}} + bool operator!=(const A&) const = default; // pre20-warning {{defaulted comparison operators are a C++20 extension}} + bool operator<(const A&) const = default; // pre20-error {{only special member functions may be defaulted}} + bool operator>(const A&) const = default; // pre20-error {{only special member functions may be defaulted}} + bool operator<=(const A&) const = default; // pre20-error {{only special member functions may be defaulted}} + bool operator>=(const A&) const = default; // pre20-error {{only special member functions may be defaulted}} + bool operator<=>(const A&) const = default; // pre20-error 1+{{}} pre20-warning {{'<=>' is a single token in C++20}} A operator+(const A&) const = default; // expected-error-re {{only special member functions{{( and comparison operators)?}} may be defaulted}} diff --git a/clang/test/CXX/dcl/dcl.decl/p3.cpp b/clang/test/CXX/dcl/dcl.decl/p3.cpp index eec0aa2043a2e..5bfec8a22da29 100644 --- a/clang/test/CXX/dcl/dcl.decl/p3.cpp +++ b/clang/test/CXX/dcl/dcl.decl/p3.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -verify %s +// RUN: %clang_cc1 -std=c++2a -verify %s template constexpr bool is_same_v = false; diff --git a/clang/test/CXX/dcl/dcl.fct/p17.cpp b/clang/test/CXX/dcl/dcl.fct/p17.cpp new file mode 100644 index 0000000000000..10e52570d9466 --- /dev/null +++ b/clang/test/CXX/dcl/dcl.fct/p17.cpp @@ -0,0 +1,260 @@ +// RUN: %clang_cc1 -std=c++2a -verify %s +template constexpr bool is_same_v = false; +template constexpr bool is_same_v = true; + +template +struct type_list; + +namespace unconstrained { + decltype(auto) f1(auto x) { return x; } + static_assert(is_same_v); + static_assert(is_same_v); + + decltype(auto) f2(auto &x) { return x; } + // expected-note@-1{{candidate function [with x:auto = int] not viable: expects an l-value for 1st argument}} + // expected-note@-2{{candidate function [with x:auto = char] not viable: expects an l-value for 1st argument}} + static_assert(is_same_v); // expected-error{{no matching}} + static_assert(is_same_v); // expected-error{{no matching}} + + decltype(auto) f3(const auto &x) { return x; } + static_assert(is_same_v); + static_assert(is_same_v); + + decltype(auto) f4(auto (*x)(auto y)) { return x; } // expected-error{{'auto' not allowed in function prototype}} + + decltype(auto) f5(void (*x)(decltype(auto) y)) { return x; } // expected-error{{'decltype(auto)' not allowed in function prototype}} + + int return_int(); void return_void(); int foo(int); + + decltype(auto) f6(auto (*x)()) { return x; } + // expected-note@-1{{candidate template ignored: failed template argument deduction}} + static_assert(is_same_v); + static_assert(is_same_v); + using f6c1 = decltype(f6(foo)); // expected-error{{no matching}} + + decltype(auto) f7(auto (*x)() -> int) { return x; } + // expected-note@-1{{candidate function not viable: no known conversion from 'void ()' to 'auto (*)() -> int' for 1st argument}} + // expected-note@-2{{candidate function not viable: no known conversion from 'int (int)' to 'auto (*)() -> int' for 1st argument}} + static_assert(is_same_v); + using f7c1 = decltype(f7(return_void)); // expected-error{{no matching}} + using f7c2 = decltype(f7(foo)); // expected-error{{no matching}} + static_assert(is_same_v); + + decltype(auto) f8(auto... x) { return (x + ...); } + static_assert(is_same_v); + static_assert(is_same_v); + static_assert(is_same_v); + + decltype(auto) f9(auto &... x) { return (x, ...); } + // expected-note@-1{{candidate function [with x:auto = ] not viable: expects an l-value for 2nd argument}} + using f9c1 = decltype(f9(return_int, 1)); // expected-error{{no matching}} + + decltype(auto) f11(decltype(auto) x) { return x; } // expected-error{{'decltype(auto)' not allowed in function prototype}} + + template + auto f12(auto x, T y) -> type_list; + static_assert(is_same_v>); + static_assert(is_same_v(1, 'c')), type_list>); + + template + auto f13(T x, auto y) -> type_list; + static_assert(is_same_v>); + static_assert(is_same_v(1, 'c')), type_list>); + + template + auto f14(auto y) -> type_list; + static_assert(is_same_v('c')), type_list>); + static_assert(is_same_v('c')), type_list>); + + template + auto f15(auto y, U u) -> type_list; + static_assert(is_same_v('c', nullptr)), type_list>); + static_assert(is_same_v('c', nullptr)), type_list>); + + auto f16(auto x, auto y) -> type_list; + static_assert(is_same_v>); + static_assert(is_same_v('c', 1)), type_list>); + static_assert(is_same_v('c', 1)), type_list>); + + void f17(auto x, auto y) requires (sizeof(x) > 1); + // expected-note@-1{{candidate template ignored: constraints not satisfied [with x:auto = char, y:auto = int]}} + // expected-note@-2{{because 'sizeof (x) > 1' (1 > 1) evaluated to false}} + static_assert(is_same_v); + // expected-error@-1{{no matching}} + static_assert(is_same_v('c', 1)), void>); + static_assert(is_same_v('c', 1)), void>); + + void f18(auto... x) requires (sizeof...(x) == 2); + // expected-note@-1{{candidate template ignored: constraints not satisfied [with x:auto = ]}} + // expected-note@-2{{candidate template ignored: constraints not satisfied [with x:auto = ]}} + // expected-note@-3{{because 'sizeof...(x) == 2' (1 == 2) evaluated to false}} + // expected-note@-4{{because 'sizeof...(x) == 2' (3 == 2) evaluated to false}} + static_assert(is_same_v); + // expected-error@-1{{no matching}} + static_assert(is_same_v); + static_assert(is_same_v); + // expected-error@-1{{no matching}} + + template + struct S { + constexpr auto f1(auto x, T t) -> decltype(x + t); + + template + constexpr auto f2(U u, auto x, T t) -> decltype(x + u + t); + }; + + template + constexpr auto S::f1(auto x, T t) -> decltype(x + t) { return x + t; } + + template + template + constexpr auto S::f2(auto x, U u, T t) -> decltype(x + u + t) { return x + u + t; } + // expected-error@-1 {{out-of-line definition of 'f2' does not match any declaration in 'S'}} + + template + template + constexpr auto S::f2(U u, auto x, T t) -> decltype(x + u + t) { return x + u + t; } + + template<> + template<> + constexpr auto S::f2(double u, char x, int t) -> double { return 42; } + + static_assert(S{}.f1(1, 2) == 3); + static_assert(S{}.f2(1, 2, '\x00') == 3); + static_assert(S{}.f2(1, 2, '\x00') == 3.); + static_assert(S{}.f2(1, '2', '\x00') == 42); +} + +namespace constrained { + template + concept C = is_same_v; + // expected-note@-1 12{{because}} + template + concept C2 = is_same_v; + // expected-note@-1 12{{because}} + + int i; + const int ci = 1; + char c; + const char cc = 'a'; + int g(int); + char h(int); + + void f1(C auto x); + // expected-note@-1 {{candidate template ignored: constraints not satisfied [with x:auto = }} + // expected-note@-2{{because}} + static_assert(is_same_v); + static_assert(is_same_v); + // expected-error@-1{{no matching}} + void f2(C auto &x); + // expected-note@-1 2{{candidate template ignored}} expected-note@-1 2{{because}} + static_assert(is_same_v); + static_assert(is_same_v); + // expected-error@-1{{no matching}} + static_assert(is_same_v); + // expected-error@-1{{no matching}} + void f3(const C auto &x); + // expected-note@-1{{candidate template ignored}} expected-note@-1{{because}} + static_assert(is_same_v); + static_assert(is_same_v); + static_assert(is_same_v); + // expected-error@-1{{no matching}} + void f4(C auto (*x)(C auto y)); // expected-error{{'auto' not allowed}} + void f5(C auto (*x)(int y)); + // expected-note@-1{{candidate template ignored}} expected-note@-1{{because}} + static_assert(is_same_v); + static_assert(is_same_v); + // expected-error@-1{{no matching}} + void f6(C auto (*x)() -> int); // expected-error{{function with trailing return type must specify return type 'auto', not 'C auto'}} + void f7(C auto... x); + // expected-note@-1 2{{candidate template ignored}} expected-note@-1 2{{because}} + static_assert(is_same_v); + static_assert(is_same_v); + // expected-error@-1{{no matching}} + static_assert(is_same_v); + // expected-error@-1{{no matching}} + void f8(C auto &... x); + // expected-note@-1 2{{candidate template ignored}} expected-note@-1 2{{because}} + static_assert(is_same_v); + static_assert(is_same_v); + // expected-error@-1{{no matching}} + static_assert(is_same_v); + // expected-error@-1{{no matching}} + void f9(const C auto &... x); + // expected-note@-1{{candidate template ignored}} expected-note@-1{{because}} + static_assert(is_same_v); + static_assert(is_same_v); + // expected-error@-1{{no matching}} + static_assert(is_same_v); + void f10(C decltype(auto) x); + auto f11 = [] (C auto x) { }; + // expected-note@-1{{candidate template ignored}} expected-note@-1{{because}} + static_assert(is_same_v); + static_assert(is_same_v); + // expected-error@-1{{no matching}} + + void f12(C2 auto x); + // expected-note@-1{{candidate template ignored}} expected-note@-1{{because}} + static_assert(is_same_v); + // expected-error@-1{{no matching}} + static_assert(is_same_v); + void f13(C2 auto &x); + // expected-note@-1 2{{candidate template ignored}} expected-note@-1 2{{because}} + static_assert(is_same_v); + // expected-error@-1{{no matching}} + static_assert(is_same_v); + // expected-error@-1{{no matching}} + static_assert(is_same_v); + void f14(const C2 auto &x); + // expected-note@-1{{candidate template ignored}} expected-note@-1{{because}} + static_assert(is_same_v); + // expected-error@-1{{no matching}} + static_assert(is_same_v); + static_assert(is_same_v); + void f15(C2 auto (*x)(C2 auto y)); // expected-error{{'auto' not allowed}} + void f16(C2 auto (*x)(int y)); + // expected-note@-1{{candidate template ignored}} expected-note@-1{{because}} + static_assert(is_same_v); + // expected-error@-1{{no matching}} + static_assert(is_same_v); + void f17(C2 auto (*x)() -> int); // expected-error{{function with trailing return type must specify return type 'auto', not 'C2 auto'}} + void f18(C2 auto... x); + // expected-note@-1 2{{candidate template ignored}} expected-note@-1 2{{because}} + static_assert(is_same_v); + static_assert(is_same_v); + // expected-error@-1{{no matching}} + static_assert(is_same_v); + // expected-error@-1{{no matching}} + void f19(C2 auto &... x); + // expected-note@-1 2{{candidate template ignored}} expected-note@-1 2{{because}} + static_assert(is_same_v); + static_assert(is_same_v); + // expected-error@-1{{no matching}} + static_assert(is_same_v); + // expected-error@-1{{no matching}} + void f20(const C2 auto &... x); + // expected-note@-1{{candidate template ignored}} expected-note@-1{{because}} + static_assert(is_same_v); + static_assert(is_same_v); + // expected-error@-1{{no matching}} + static_assert(is_same_v); + void f21(C2 decltype(auto) x); + auto f22 = [] (C2 auto x) { }; + // expected-note@-1{{candidate template ignored}} expected-note@-1{{because}} + static_assert(is_same_v); + // expected-error@-1{{no matching}} + static_assert(is_same_v); + + struct S1 { S1(C auto); }; + // expected-note@-1{{candidate template ignored}} expected-note@-1{{because}} + // expected-note@-2 2{{candidate constructor}} + static_assert(is_same_v); + static_assert(is_same_v); + // expected-error@-1{{no matching}} + struct S2 { S2(C2 auto); }; + // expected-note@-1{{candidate template ignored}} expected-note@-1{{because}} + // expected-note@-2 2{{candidate constructor}} + static_assert(is_same_v); + // expected-error@-1{{no matching}} + static_assert(is_same_v); +} diff --git a/clang/test/CXX/dcl/dcl.spec/dcl.type/dcl.spec.auto/p6.cpp b/clang/test/CXX/dcl/dcl.spec/dcl.type/dcl.spec.auto/p6.cpp new file mode 100644 index 0000000000000..ae194670954c0 --- /dev/null +++ b/clang/test/CXX/dcl/dcl.spec/dcl.type/dcl.spec.auto/p6.cpp @@ -0,0 +1,44 @@ +// RUN: %clang_cc1 -std=c++2a -verify %s + +template +concept LargerThan = sizeof(T) > size; +// expected-note@-1 2{{because 'sizeof(char) > 1U' (1 > 1) evaluated to false}} +// expected-note@-2 {{because 'sizeof(int) > 10U' (4 > 10) evaluated to false}} +// expected-note@-3 {{because 'sizeof(int) > 4U' (4 > 4) evaluated to false}} + +template +concept Large = LargerThan; +// expected-note@-1 2{{because 'LargerThan' evaluated to false}} + +namespace X { + template + concept SmallerThan = sizeof(T) < size; + template + concept Small = SmallerThan; +} + +Large auto test1() { // expected-error{{deduced type 'char' does not satisfy 'Large'}} + Large auto i = 'a'; + // expected-error@-1{{deduced type 'char' does not satisfy 'Large'}} + Large auto j = 10; + ::Large auto k = 10; + LargerThan<1> auto l = 10; + ::LargerThan<1> auto m = 10; + LargerThan<10> auto n = 10; + // expected-error@-1{{deduced type 'int' does not satisfy 'LargerThan<10>'}} + X::Small auto o = 'x'; + X::SmallerThan<5> auto p = 1; + return 'a'; +} + +::Large auto test2() { return 10; } +LargerThan<4> auto test3() { return 10; } +// expected-error@-1{{deduced type 'int' does not satisfy 'LargerThan<4>'}} +::LargerThan<2> auto test4() { return 10; } + +Large auto test5() -> void; +// expected-error@-1{{function with trailing return type must specify return type 'auto', not 'Large auto'}} +auto test6() -> Large auto { return 1; } + +X::Small auto test7() { return 'a'; } +X::SmallerThan<5> auto test8() { return 10; } \ No newline at end of file diff --git a/clang/test/CXX/drs/dr2xx.cpp b/clang/test/CXX/drs/dr2xx.cpp index 1f625efe2b55d..eb325119b9444 100644 --- a/clang/test/CXX/drs/dr2xx.cpp +++ b/clang/test/CXX/drs/dr2xx.cpp @@ -2,7 +2,7 @@ // RUN: %clang_cc1 -std=c++11 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors // RUN: %clang_cc1 -std=c++14 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors // RUN: %clang_cc1 -std=c++17 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors -// RUN: %clang_cc1 -std=c++2a %s -verify -fexceptions -fcxx-exceptions -pedantic-errors +// RUN: %clang_cc1 -std=c++20 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors // PR13819 -- __SIZE_TYPE__ is incompatible. typedef __SIZE_TYPE__ size_t; // expected-error 0-1 {{extension}} @@ -449,8 +449,8 @@ namespace dr241 { // dr241: yes template void g(T t); // expected-note {{candidate}} } void h(A::B b) { - f<3>(b); // expected-error 0-1{{C++2a extension}} expected-error {{no matching}} - g<3>(b); // expected-error 0-1{{C++2a extension}} + f<3>(b); // expected-error 0-1{{C++20 extension}} expected-error {{no matching}} + g<3>(b); // expected-error 0-1{{C++20 extension}} A::f<3>(b); // expected-error {{no matching}} A::g<3>(b); C::f<3>(b); // expected-error {{no matching}} diff --git a/clang/test/CXX/drs/dr6xx.cpp b/clang/test/CXX/drs/dr6xx.cpp index 6ff1625458268..03842f2a1de6c 100644 --- a/clang/test/CXX/drs/dr6xx.cpp +++ b/clang/test/CXX/drs/dr6xx.cpp @@ -2,7 +2,7 @@ // RUN: %clang_cc1 -std=c++11 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors -fno-spell-checking // RUN: %clang_cc1 -std=c++14 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors -fno-spell-checking // RUN: %clang_cc1 -std=c++17 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors -fno-spell-checking -// RUN: %clang_cc1 -std=c++2a %s -verify -fexceptions -fcxx-exceptions -pedantic-errors -fno-spell-checking +// RUN: %clang_cc1 -std=c++20 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors -fno-spell-checking namespace std { struct type_info {}; @@ -506,7 +506,7 @@ namespace dr647 { // dr647: yes constexpr C(NonLiteral, int) {} // expected-error {{not a literal type}} constexpr C() try {} catch (...) {} #if __cplusplus <= 201703L - // expected-error@-2 {{function try block in constexpr constructor is a C++2a extension}} + // expected-error@-2 {{function try block in constexpr constructor is a C++20 extension}} #endif #if __cplusplus < 201402L // expected-error@-5 {{use of this statement in a constexpr constructor is a C++14 extension}} @@ -1070,7 +1070,7 @@ namespace dr687 { // dr687 (9 c++20, but the issue is still considered open) // This is valid in C++20. g(a); #if __cplusplus <= 201703L - // expected-error@-2 {{C++2a extension}} + // expected-error@-2 {{C++20 extension}} #endif // This is not. diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.id/mixed-constraints.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.id/mixed-constraints.cpp index fafb3f7b35d9f..6add2c5d10a49 100644 --- a/clang/test/CXX/expr/expr.prim/expr.prim.id/mixed-constraints.cpp +++ b/clang/test/CXX/expr/expr.prim/expr.prim.id/mixed-constraints.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -verify %s +// RUN: %clang_cc1 -std=c++2a -verify %s template requires (sizeof(T) >= 4 && sizeof(T) <= 10) // expected-note@-1{{because 'sizeof(char [20]) <= 10' (20 <= 10) evaluated to false}} diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.id/p3.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.id/p3.cpp index fb3978240af2f..30ec2a3ab70f7 100644 --- a/clang/test/CXX/expr/expr.prim/expr.prim.id/p3.cpp +++ b/clang/test/CXX/expr/expr.prim/expr.prim.id/p3.cpp @@ -183,3 +183,18 @@ concept C8 = sizeof(T) > sizeof(U); template constexpr bool B8 = C8; // expected-error@-1{{pack expansion used as argument for non-pack parameter of concept}} + + +// Make sure we correctly check for containsUnexpandedParameterPack + +template +concept C9 = true; + +template +using invoke = typename Fn::template invoke; + +template +// The converted argument here will not containsUnexpandedParameterPack, but the +// as-written one will. +requires (C9> &&...) +struct S { }; diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.id/p4.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.id/p4.cpp index f13ab279da33a..d3dde10ff2b2d 100644 --- a/clang/test/CXX/expr/expr.prim/expr.prim.id/p4.cpp +++ b/clang/test/CXX/expr/expr.prim/expr.prim.id/p4.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -verify %s +// RUN: %clang_cc1 -std=c++2a -verify %s namespace functions { @@ -26,11 +26,14 @@ namespace methods struct A { static void foo(int) requires (sizeof(T) == 1) {} // expected-note 3{{because 'sizeof(char [2]) == 1' (2 == 1) evaluated to false}} static void bar(int) requires (sizeof(T) == 2) {} // expected-note 3{{because 'sizeof(char) == 2' (1 == 2) evaluated to false}} + // Make sure the function body is not instantiated before constraints are checked. + static auto baz(int) requires (sizeof(T) == 2) { return T::foo(); } // expected-note{{because 'sizeof(char) == 2' (1 == 2) evaluated to false}} }; void baz() { A::foo(1); A::bar(1); // expected-error{{invalid reference to function 'bar': constraints not satisfied}} + A::baz(1); // expected-error{{invalid reference to function 'baz': constraints not satisfied}} A::foo(1); // expected-error{{invalid reference to function 'foo': constraints not satisfied}} A::bar(1); void (*p1)(int) = A::foo; diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/expr.prim.lambda.closure/p3.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/expr.prim.lambda.closure/p3.cpp index 942280e1059fb..9c5765b06b851 100644 --- a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/expr.prim.lambda.closure/p3.cpp +++ b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/expr.prim.lambda.closure/p3.cpp @@ -1,7 +1,7 @@ -// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -verify %s +// RUN: %clang_cc1 -std=c++2a -verify %s auto l1 = [] (auto x) requires (sizeof(decltype(x)) == 1) { return x; }; -// expected-note@-1{{candidate template ignored: constraints not satisfied [with $0 = int]}} +// expected-note@-1{{candidate template ignored: constraints not satisfied [with x:auto = int]}} // expected-note@-2{{because 'sizeof(decltype(x)) == 1' (4 == 1) evaluated to false}} auto l1t1 = l1('a'); @@ -9,8 +9,8 @@ auto l1t2 = l1(1); // expected-error@-1{{no matching function for call to object of type '(lambda at}} auto l2 = [] (auto... x) requires ((sizeof(decltype(x)) >= 2) && ...) { return (x + ...); }; -// expected-note@-1{{candidate template ignored: constraints not satisfied [with $0 = ]}} -// expected-note@-2{{candidate template ignored: constraints not satisfied [with $0 = ]}} +// expected-note@-1{{candidate template ignored: constraints not satisfied [with x:auto = ]}} +// expected-note@-2{{candidate template ignored: constraints not satisfied [with x:auto = ]}} // expected-note@-3 2{{because 'sizeof(decltype(x)) >= 2' (1 >= 2) evaluated to false}} auto l2t1 = l2('a'); diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p8.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p8.cpp index 1cc1fd974ca5d..7c95245da4ca2 100644 --- a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p8.cpp +++ b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p8.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -std=c++11 %s -verify -Wno-c++1y-extensions +// RUN: %clang_cc1 -std=c++11 %s -verify -Wno-c++14-extensions class X0 { void explicit_capture() { @@ -8,7 +8,7 @@ class X0 { (void)[this, this] () {}; // expected-error {{'this' can appear only once}} (void)[=, foo] () {}; // expected-error {{'&' must precede a capture when}} (void)[=, &foo] () {}; - (void)[=, this] () {}; // expected-warning {{C++2a extension}} + (void)[=, this] () {}; // expected-warning {{C++20 extension}} (void)[&, foo] () {}; (void)[&, &foo] () {}; // expected-error {{'&' cannot precede a capture when}} (void)[&, this] () {}; @@ -23,7 +23,7 @@ struct S2 { void S2::f(int i) { (void)[&, i]{ }; (void)[&, &i]{ }; // expected-error{{'&' cannot precede a capture when the capture default is '&'}} - (void)[=, this]{ }; // expected-warning{{C++2a extension}} + (void)[=, this]{ }; // expected-warning{{C++20 extension}} (void)[=]{ this->g(i); }; (void)[i, i]{ }; // expected-error{{'i' can appear only once in a capture list}} (void)[i(0), i(1)]{ }; // expected-error{{'i' can appear only once in a capture list}} diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.req/compound-requirement.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.req/compound-requirement.cpp new file mode 100644 index 0000000000000..19b794ba29ad0 --- /dev/null +++ b/clang/test/CXX/expr/expr.prim/expr.prim.req/compound-requirement.cpp @@ -0,0 +1,175 @@ +// RUN: %clang_cc1 -std=c++2a -x c++ %s -verify + +static_assert(requires { { 0 }; }); +static_assert(requires { { "aaaa" }; }); +static_assert(requires { { (0).da }; }); // expected-error{{member reference base type 'int' is not a structure or union}} + +void foo() {} +static_assert(requires { { foo() }; }); + +// Substitution failure in expression + +struct A {}; +struct B { + B operator+(const B &other) const { return other; } +}; +struct C { + C operator+(C &other) const { return other; } +}; + +template requires requires (T a, const T& b) { { a + b }; } // expected-note{{because 'a + b' would be invalid: invalid operands to binary expression ('A' and 'const A')}} expected-note{{because 'a + b' would be invalid: invalid operands to binary expression ('C' and 'const C')}} +struct r1 {}; + +using r1i1 = r1; +using r1i2 = r1; // expected-error{{constraints not satisfied for class template 'r1' [with T = A]}} +using r1i3 = r1; +using r1i4 = r1; // expected-error{{constraints not satisfied for class template 'r1' [with T = C]}} + +struct D { void foo() {} }; + +template requires requires (T a) { { a.foo() }; } // expected-note{{because 'a.foo()' would be invalid: no member named 'foo' in 'A'}} expected-note{{because 'a.foo()' would be invalid: member reference base type 'int' is not a structure or union}} expected-note{{because 'a.foo()' would be invalid: 'this' argument to member function 'foo' has type 'const D', but function is not marked const}} +struct r2 {}; + +using r2i1 = r2; // expected-error{{constraints not satisfied for class template 'r2' [with T = int]}} +using r2i2 = r2; // expected-error{{constraints not satisfied for class template 'r2' [with T = A]}} +using r2i3 = r2; +using r2i4 = r2; // expected-error{{constraints not satisfied for class template 'r2' [with T = const D]}} + +template requires requires { { sizeof(T) }; } // expected-note{{because 'sizeof(T)' would be invalid: invalid application of 'sizeof' to an incomplete type 'void'}} expected-note{{because 'sizeof(T)' would be invalid: invalid application of 'sizeof' to an incomplete type 'nonexistent'}} +struct r3 {}; + +using r3i1 = r3; +using r3i2 = r3; +using r3i3 = r3; +using r3i4 = r3; // expected-error{{constraints not satisfied for class template 'r3' [with T = void]}} +using r3i4 = r3; // expected-error{{constraints not satisfied for class template 'r3' [with T = nonexistent]}} + +// Non-dependent expressions + +template requires requires (T t) { { 0 }; { "a" }; { (void)'a' }; } +struct r4 {}; + +using r4i1 = r4; +using r4i2 = r4; +using r4i3 = r4; + +// Noexcept requirement +void maythrow() { } +static_assert(!requires { { maythrow() } noexcept; }); +static_assert(requires { { 1 } noexcept; }); + +struct E { void operator++(int) noexcept; }; +struct F { void operator++(int); }; + +template requires requires (T t) { { t++ } noexcept; } // expected-note{{because 't ++' may throw an exception}} +struct r5 {}; + +using r5i1 = r5; +using r5i2 = r5; +using r5i2 = r5; // expected-error{{constraints not satisfied for class template 'r5' [with T = F]}} + +template requires requires (T t) { { t.foo() } noexcept; } // expected-note{{because 't.foo()' would be invalid: no member named 'foo' in 'E'}} +struct r6 {}; + +using r6i = r6; // expected-error{{constraints not satisfied for class template 'r6' [with T = E]}} + +template +constexpr bool is_same_v = false; + +template +constexpr bool is_same_v = true; + +template +concept Same = is_same_v; + +template +concept Large = sizeof(T) >= 4; // expected-note{{because 'sizeof(short) >= 4' (2 >= 4) evaluated to false}} + +template requires requires (T t) { { t } -> Large; } // expected-note{{because 'decltype(t)' (aka 'short') does not satisfy 'Large':}} +struct r7 {}; + +using r7i1 = r7; +using r7i2 = r7; // expected-error{{constraints not satisfied for class template 'r7' [with T = short]}} + +template requires requires (T t) { { t } -> Same; } +struct r8 {}; + +using r8i1 = r8; +using r8i2 = r8; + +// Substitution failure in type constraint + +template requires requires (T t) { { t } -> Same; } // expected-note{{because 'Same' would be invalid: type 'int' cannot be used prior to '::' because it has no members}} +struct r9 {}; + +struct M { using type = M; }; + +using r9i1 = r9; +using r9i2 = r9; // expected-error{{constraints not satisfied for class template 'r9' [with T = int]}} + +// Substitution failure in both expression and return type requirement + +template requires requires (T t) { { t.foo() } -> Same; } // expected-note{{because 't.foo()' would be invalid: member reference base type 'int' is not a structure or union}} +struct r10 {}; + +using r10i = r10; // expected-error{{constraints not satisfied for class template 'r10' [with T = int]}} + +// Non-type concept in type constraint + +template +concept IsEven = (T % 2) == 0; + +template requires requires (T t) { { t } -> IsEven; } // expected-error{{concept named in type constraint is not a type concept}} +struct r11 {}; + +// C++ [expr.prim.req.compound] Example +namespace std_example { + template concept C1 = + requires(T x) { + {x++}; + }; + + template constexpr bool is_same_v = false; + template constexpr bool is_same_v = true; + + template concept same_as = is_same_v; + // expected-note@-1 {{because 'is_same_v' evaluated to false}} + + static_assert(C1); + static_assert(C1); + template struct C1_check {}; + using c1c1 = C1_check; + using c1c2 = C1_check; + + template concept C2 = + requires(T x) { + {*x} -> same_as; + // expected-note@-1{{because type constraint 'same_as' was not satisfied:}} + // expected-note@-2{{because '*x' would be invalid: indirection requires pointer operand ('int' invalid)}} + }; + + struct T1 { + using inner = int; + inner operator *() { return 0; } + }; + struct T2 { + using inner = int *; + int operator *() { return 0; } + }; + static_assert(C2); + template struct C2_check {}; // expected-note{{because 'int' does not satisfy 'C2'}} expected-note{{because 'std_example::T2' does not satisfy 'C2'}} + using c2c1 = C2_check; // expected-error{{constraints not satisfied for class template 'C2_check' [with T = int]}} + using c2c2 = C2_check; // expected-error{{constraints not satisfied for class template 'C2_check' [with T = std_example::T2]}} + + template + void g(T t) noexcept(sizeof(T) == 1) {} + + template concept C5 = + requires(T x) { + {g(x)} noexcept; // expected-note{{because 'g(x)' may throw an exception}} + }; + + static_assert(C5); + template struct C5_check {}; // expected-note{{because 'short' does not satisfy 'C5'}} + using c5 = C5_check; // expected-error{{constraints not satisfied for class template 'C5_check' [with T = short]}} +} \ No newline at end of file diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.req/equivalence.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.req/equivalence.cpp new file mode 100644 index 0000000000000..8a36d7a520a87 --- /dev/null +++ b/clang/test/CXX/expr/expr.prim/expr.prim.req/equivalence.cpp @@ -0,0 +1,125 @@ +// RUN: %clang_cc1 -std=c++2a -x c++ %s -verify + +template constexpr bool is_same_v = false; +template constexpr bool is_same_v = true; + +template struct identity { using type = T; }; +template using identity_t = T; + +// Type requirements +template requires requires { typename identity_t; } +struct r1; +template requires requires { typename identity_t; } // expected-note{{previous template declaration is here}} +struct r1; +template requires requires { typename identity_t; } // expected-error{{requires clause differs in template redeclaration}} +struct r1; +template requires requires { typename ::identity_t; } +struct r1; + +template requires requires { typename identity::type; } +struct r2; +template requires requires { typename identity::type; } +struct r2; +template requires requires { typename ::identity::type; } // expected-note 2{{previous template declaration is here}} +struct r2; +template requires requires { typename identity::typr; } // expected-error{{requires clause differs in template redeclaration}} +struct r2; +namespace ns { + template struct identity { using type = T; }; +} +template requires requires { typename ns::identity::type; } // expected-error{{requires clause differs in template redeclaration}} +struct r2; + +template requires requires { typename T::template identity::type; } +struct r3; +template requires requires { typename U::template identity::type; } // expected-note{{previous template declaration is here}} +struct r3; +template requires requires { typename T::template identitr::type; } // expected-error{{requires clause differs in template redeclaration}} +struct r3; + +template requires requires { typename T::template temp<>; } +struct r4; +template requires requires { typename U::template temp<>; } +struct r4; + +// Expr requirements +template requires requires { 0; } // expected-note{{previous template declaration is here}} +struct r5; +template requires requires { 1; } // expected-error{{requires clause differs in template redeclaration}} +struct r5; + +template +concept C1 = true; + +template requires requires { sizeof(T); } +struct r6; +template requires requires { sizeof(U); } // expected-note{{previous template declaration is here}} +struct r6; +template requires requires { sizeof(U) - 1; } // expected-error{{requires clause differs in template redeclaration}} +struct r6; +template requires requires { { sizeof(T) }; } // expected-note 2{{previous template declaration is here}} +struct r6; +template requires requires { { sizeof(T) } noexcept; } // expected-error{{requires clause differs in template redeclaration}} +struct r6; +template requires requires { { sizeof(T) } -> C1; } // expected-error{{requires clause differs in template redeclaration}} +struct r6; + +template requires requires { { sizeof(T) } -> C1; } +struct r7; +template requires requires { { sizeof(U) } -> C1; } +struct r7; +template requires requires { { sizeof(T) } -> C1<>; } // expected-note {{previous template declaration is here}} +struct r7; +template requires requires { { sizeof(U) }; } // expected-error{{requires clause differs in template redeclaration}} +struct r7; + +template +concept C2 = true; + +template requires requires { { sizeof(T) } -> C2; } +struct r8; +template requires requires { { sizeof(U) } -> C2; } // expected-note{{previous template declaration is here}} +struct r8; +template requires requires { { sizeof(T) } -> C2; } // expected-error{{requires clause differs in template redeclaration}} +struct r8; + +// Nested requirements +template requires requires { requires sizeof(T) == 0; } +struct r9; +template requires requires { requires sizeof(U) == 0; } // expected-note{{previous template declaration is here}} +struct r9; +template requires requires { requires sizeof(T) == 1; } // expected-error{{requires clause differs in template redeclaration}} +struct r9; + +// Parameter list +template requires requires { requires true; } +struct r10; +template requires requires() { requires true; } // expected-note{{previous template declaration is here}} +struct r10; +template requires requires(T i) { requires true; } // expected-error{{requires clause differs in template redeclaration}} +struct r10; + +template requires requires(T i, T *j) { requires true; } // expected-note 2{{previous template declaration is here}} +struct r11; +template requires requires(T i) { requires true; } // expected-error{{requires clause differs in template redeclaration}} +struct r11; +template requires requires(T i, T *j, T &k) { requires true; } // expected-error{{requires clause differs in template redeclaration}} +struct r11; + +// Parameter names +template requires requires(int i) { requires sizeof(i) == 1; } +struct r12; +template requires requires(int j) { requires sizeof(j) == 1; } // expected-note 2{{previous template declaration is here}} +struct r12; +template requires requires(int k) { requires sizeof(k) == 2; } // expected-error{{requires clause differs in template redeclaration}} +struct r12; +template requires requires(const int k) { requires sizeof(k) == 1; } // expected-error{{requires clause differs in template redeclaration}} +struct r12; + +// Order of requirements +template requires requires { requires true; 0; } +struct r13; +template requires requires { requires true; 0; } // expected-note{{previous template declaration is here}} +struct r13; +template requires requires { 0; requires true; } // expected-error{{requires clause differs in template redeclaration}} +struct r13; diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.req/nested-requirement.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.req/nested-requirement.cpp new file mode 100644 index 0000000000000..b45b57f6b9242 --- /dev/null +++ b/clang/test/CXX/expr/expr.prim/expr.prim.req/nested-requirement.cpp @@ -0,0 +1,47 @@ +// RUN: %clang_cc1 -std=c++2a -x c++ %s -verify + +static_assert(requires { requires true; }); + +template requires requires { requires false; } // expected-note{{because 'false' evaluated to false}} +struct r1 {}; + +using r1i = r1; // expected-error{{constraints not satisfied for class template 'r1' [with T = int]}} + +template requires requires { requires sizeof(T) == 0; } // expected-note{{because 'sizeof(int) == 0' (4 == 0) evaluated to false}} +struct r2 {}; + +using r2i = r2; // expected-error{{constraints not satisfied for class template 'r2' [with T = int]}} + +template requires requires (T t) { requires sizeof(t) == 0; } // expected-note{{because 'sizeof (t) == 0' (4 == 0) evaluated to false}} +struct r3 {}; + +using r3i = r3; // expected-error{{constraints not satisfied for class template 'r3' [with T = int]}} + +template +struct X { + template requires requires (U u) { requires sizeof(u) == sizeof(T); } // expected-note{{because 'sizeof (u) == sizeof(T)' would be invalid: invalid application of 'sizeof' to an incomplete type 'void'}} + struct r4 {}; +}; + +using r4i = X::r4; // expected-error{{constraints not satisfied for class template 'r4' [with U = int]}} + +// C++ [expr.prim.req.nested] Examples +namespace std_example { + template concept C1 = sizeof(U) == 1; // expected-note{{because 'sizeof(int) == 1' (4 == 1) evaluated to false}} + template concept D = + requires (T t) { + requires C1; // expected-note{{because 'decltype(+t)' (aka 'int') does not satisfy 'C1'}} + }; + + struct T1 { char operator+() { return 'a'; } }; + static_assert(D); + template struct D_check {}; // expected-note{{because 'short' does not satisfy 'D'}} + using dc1 = D_check; // expected-error{{constraints not satisfied for class template 'D_check' [with T = short]}} + + template + concept C2 = requires (T a) { + requires sizeof(a) == 4; // OK + requires a == 0; // expected-note{{because 'a == 0' would be invalid: constraint variable 'a' cannot be used in an evaluated context}} + }; + static_assert(C2); // expected-note{{because 'int' does not satisfy 'C2'}} expected-error{{static_assert failed}} +} \ No newline at end of file diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.req/p3.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.req/p3.cpp new file mode 100644 index 0000000000000..d2c8cd4fc2195 --- /dev/null +++ b/clang/test/CXX/expr/expr.prim/expr.prim.req/p3.cpp @@ -0,0 +1,37 @@ +// RUN: %clang_cc1 -std=c++2a -x c++ %s -verify + +// Examples from standard + +template +concept convertible_to = requires(T t) { U(t); }; + +template +concept R = requires (T i) { + typename T::type; + {*i} -> convertible_to; +}; + +template requires R struct S {}; + +struct T { + using type = int; + type i; + const type &operator*() { return i; } +}; + +using si = S; + +template +requires requires (T x) { x + x; } // expected-note{{because 'x + x' would be invalid: invalid operands to binary expression ('T' and 'T')}} +T add(T a, T b) { return a + b; } // expected-note{{candidate template ignored: constraints not satisfied [with T = T]}} + +int x = add(1, 2); +int y = add(T{}, T{}); // expected-error{{no matching function for call to 'add'}} + +template +concept C = requires (T x) { x + x; }; // expected-note{{because 'x + x' would be invalid: invalid operands to binary expression ('T' and 'T')}} +template requires C // expected-note{{because 'T' does not satisfy 'C'}} +T add2(T a, T b) { return a + b; } // expected-note{{candidate template ignored: constraints not satisfied [with T = T]}} + +int z = add2(1, 2); +int w = add2(T{}, T{}); // expected-error{{no matching function for call to 'add2'}} \ No newline at end of file diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.req/requires-expr.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.req/requires-expr.cpp new file mode 100644 index 0000000000000..90a38292d15d3 --- /dev/null +++ b/clang/test/CXX/expr/expr.prim/expr.prim.req/requires-expr.cpp @@ -0,0 +1,68 @@ +// RUN: %clang_cc1 -std=c++2a -x c++ %s -verify + +using A = int; + +template +constexpr bool is_same_v = false; + +template +constexpr bool is_same_v = true; + +template +concept same_as = is_same_v; + +static_assert(requires { requires true; 0; typename A; + { 0 } -> same_as; }); +static_assert(is_same_v); + +// Check that requires expr is an unevaluated context. +struct Y { + int i; + static constexpr bool r = requires { i; }; +}; + +template requires requires (T t) { + requires false; // expected-note{{because 'false' evaluated to false}} + requires false; + requires requires { + requires false; + }; +} +struct r1 { }; + +using r1i = r1; +// expected-error@-1 {{constraints not satisfied for class template 'r1' [with T = int]}} + +template requires requires (T t) { + requires requires { + requires false; // expected-note{{because 'false' evaluated to false}} + }; +} +struct r2 { }; + +using r2i = r2; +// expected-error@-1 {{constraints not satisfied for class template 'r2' [with T = int]}} + +template requires requires (T t) { + requires requires { + requires true; + }; + requires true; + requires requires { + requires false; // expected-note{{because 'false' evaluated to false}} + }; +} +struct r3 { }; + +using r3i = r3; +// expected-error@-1 {{constraints not satisfied for class template 'r3' [with T = int]}} + +template +struct S { static const int s = T::value; }; + +template requires requires { T::value; S::s; } +// expected-note@-1 {{because 'T::value' would be invalid: type 'int' cannot be used prior to '::' because it has no members}} +struct r4 { }; + +using r4i = r4; +// expected-error@-1 {{constraints not satisfied for class template 'r4' [with T = int]}} \ No newline at end of file diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp new file mode 100644 index 0000000000000..39e882b8fa5f9 --- /dev/null +++ b/clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp @@ -0,0 +1,106 @@ +// RUN: %clang_cc1 %s -I%S -std=c++2a -verify + +namespace std { struct type_info; } + +static_assert(requires { 0; }); +static_assert(requires { "aaaa"; }); +static_assert(requires { (0).da; }); // expected-error{{member reference base type 'int' is not a structure or union}} + +struct A {}; +struct B { + B operator+(const B &other) const { return other; } +}; +struct C { + C operator+(C &other) const { return other; } +}; + +template requires requires (T a, const T& b) { a + b; } +// expected-note@-1{{because 'a + b' would be invalid: invalid operands to binary expression ('A' and 'const A')}} +// expected-note@-2{{because 'a + b' would be invalid: invalid operands to binary expression ('C' and 'const C')}} +struct r1 {}; + +using r1i1 = r1; +using r1i2 = r1; // expected-error{{constraints not satisfied for class template 'r1' [with T = A]}} +using r1i3 = r1; +using r1i4 = r1; // expected-error{{constraints not satisfied for class template 'r1' [with T = C]}} + +struct D { void foo() {} }; + +template requires requires (T a) { a.foo(); } +// expected-note@-1{{because 'a.foo()' would be invalid: no member named 'foo' in 'A'}} +// expected-note@-2{{because 'a.foo()' would be invalid: member reference base type 'int' is not a structure or union}} +// expected-note@-3{{because 'a.foo()' would be invalid: 'this' argument to member function 'foo' has type 'const D', but function is not marked const}} +struct r2 {}; + +using r2i1 = r2; // expected-error{{constraints not satisfied for class template 'r2' [with T = int]}} +using r2i2 = r2; // expected-error{{constraints not satisfied for class template 'r2' [with T = A]}} +using r2i3 = r2; +using r2i4 = r2; // expected-error{{constraints not satisfied for class template 'r2' [with T = const D]}} + +template requires requires { sizeof(T); } +// expected-note@-1{{because 'sizeof(T)' would be invalid: invalid application of 'sizeof' to an incomplete type 'void'}} +// expected-note@-2{{because 'sizeof(T)' would be invalid: invalid application of 'sizeof' to an incomplete type 'nonexistent'}} +struct r3 {}; + +using r3i1 = r3; +using r3i2 = r3; +using r3i3 = r3; +using r3i4 = r3; // expected-error{{constraints not satisfied for class template 'r3' [with T = void]}} +using r3i4 = r3; // expected-error{{constraints not satisfied for class template 'r3' [with T = nonexistent]}} + +template requires requires (T t) { 0; "a"; (void)'a'; } +struct r4 {}; + +using r4i1 = r4; +using r4i2 = r4; +using r4i3 = r4; + +template void f(T) = delete; +template requires (sizeof(T) == 1) void f(T) { } + +template requires requires(T t) { f(t); } +// expected-note@-1{{because 'f(t)' would be invalid: call to deleted function 'f'}} +struct r5 {}; + +using r5i1 = r5; +// expected-error@-1 {{constraints not satisfied for class template 'r5' [with T = int]}} +using r5i2 = r5; + +template +struct E { + struct non_default_constructible { non_default_constructible(T t) { } }; +}; + +template requires requires(T t) { typename E::non_default_constructible{}; } +// expected-note@-1 {{because 'typename E::non_default_constructible({})' would be invalid: no matching constructor for initialization of 'typename E::non_default_constructible'}} +struct r6 {}; + +using r6i1 = r6; +// expected-error@-1 {{constraints not satisfied for class template 'r6' [with T = int]}} + +template requires requires(T t) { typename E::non_default_constructible(); } +// expected-note@-1 {{because 'typename E::non_default_constructible()' would be invalid: no matching constructor for initialization of 'typename E::non_default_constructible'}} +struct r7 {}; + +using r7i1 = r7; +// expected-error@-1 {{constraints not satisfied for class template 'r7' [with T = int]}} + +// C++ [expr.prim.req.simple] Example +namespace std_example { + template concept C = + requires (T a, T b) { // expected-note{{because substituted constraint expression is ill-formed: argument may not have 'void' type}} + a + b; // expected-note{{because 'a + b' would be invalid: invalid operands to binary expression ('int *' and 'int *')}} + }; + + static_assert(C); + template struct C_check {}; // expected-note{{because 'void' does not satisfy 'C'}} expected-note{{because 'int *' does not satisfy 'C'}} + using c1c1 = C_check; // expected-error{{constraints not satisfied for class template 'C_check' [with T = void]}} + using c1c2 = C_check; // expected-error{{constraints not satisfied for class template 'C_check' [with T = int *]}} +} + +// typeid() of an expression becomes potentially evaluated if the expression is +// of a polymorphic type. +class X { virtual ~X(); }; +constexpr bool b = requires (X &x) { static_cast(nullptr); }; +// expected-error@-1{{constraint variable 'x' cannot be used in an evaluated context}} +// expected-note@-2{{'x' declared here}} diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.req/type-requirement.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.req/type-requirement.cpp new file mode 100644 index 0000000000000..71c87ffff8bce --- /dev/null +++ b/clang/test/CXX/expr/expr.prim/expr.prim.req/type-requirement.cpp @@ -0,0 +1,194 @@ +// RUN: %clang_cc1 -std=c++2a -x c++ %s -verify + +using A = int; + +template using identity_t = T; // expected-note 4{{template is declared here}}} + +template struct identity { using type = T; }; +// expected-note@-1 2{{template is declared here}} + +struct C {}; + +struct D { static int type; }; // expected-note{{referenced member 'type' is declared here}} + +// Basic unqualified and global-qualified lookups + +static_assert(requires { typename A; typename ::A; }); +static_assert(requires { typename identity_t; typename ::identity_t; }); +static_assert(!requires { typename identity_t; }); // expected-error{{too many template arguments for alias template 'identity_t'}} +static_assert(!requires { typename ::identity_t; }); // expected-error{{too many template arguments for alias template 'identity_t'}} +static_assert(requires { typename identity; }); +static_assert(!requires { typename identity; }); +// expected-error@-1 {{typename specifier refers to class template; argument deduction not allowed here}} +static_assert(!requires { typename ::identity; }); +// expected-error@-1 {{typename specifier refers to class template; argument deduction not allowed here}} +static_assert(!requires { typename identity_t; }); +// expected-error@-1 {{typename specifier refers to alias template; argument deduction not allowed here}} +static_assert(!requires { typename ::identity_t; }); +// expected-error@-1 {{typename specifier refers to alias template; argument deduction not allowed here}} + +namespace ns { + using B = int; + int C = 0; + // expected-note@-1 {{referenced 'C' is declared here}} + static_assert(requires { typename A; typename B; typename ::A; }); + static_assert(!requires { typename ns::A; }); // expected-error{{no type named 'A' in namespace 'ns'}} + static_assert(!requires { typename ::B; }); // expected-error{{no type named 'B' in the global namespace}} + static_assert(requires { typename C; }); + // expected-error@-1 {{typename specifier refers to non-type 'C'}} +} + +// member type lookups + +static_assert(requires { typename identity::type; typename ::identity::type; }); +static_assert(!requires { typename identity::typr; }); // expected-error{{no type named 'typr' in 'identity'}} +static_assert(!requires { typename ::identity::typr; }); // expected-error{{no type named 'typr' in 'identity'}} + +template requires requires { typename T::type; } +// expected-note@-1 {{because 'typename T::type' would be invalid: type 'int' cannot be used prior to '::' because it has no members}} +// expected-note@-2 {{because 'typename T::type' would be invalid: no type named 'type' in 'C'}} +// expected-note@-3 {{because 'typename T::type' would be invalid: typename specifier refers to non-type member 'type' in 'D'}} +// expected-note@-4 {{in instantiation of template class 'invalid' requested here}} +// expected-note@-5 {{in instantiation of requirement here}} +// expected-note@-6 {{while substituting template arguments into constraint expression here}} +// expected-note@-7 {{because 'typename T::type' would be invalid}} +struct r1 {}; + +using r1i1 = r1>; +using r1i2 = r1; // expected-error{{constraints not satisfied for class template 'r1' [with T = int]}} +using r1i3 = r1; // expected-error{{constraints not satisfied for class template 'r1' [with T = C]}} +using r1i4 = r1; // expected-error{{constraints not satisfied for class template 'r1' [with T = D]}} + +template struct invalid { typename T::type x; }; +// expected-error@-1 {{typename specifier refers to non-type member 'type' in 'D'}} +using r1i5 = r1>; +// expected-error@-1 {{constraints not satisfied for class template 'r1' [with T = invalid]}} +// expected-note@-2 {{while checking constraint satisfaction for template 'r1 >' required here}} + +// mismatching template arguments + +template requires requires { typename identity; } // expected-note{{because 'typename identity' would be invalid: too many template arguments for class template 'identity'}} +struct r2 {}; + +using r2i1 = r2; +using r2i2 = r2; +using r2i3 = r2; // expected-error{{constraints not satisfied for class template 'r2' [with Ts = ]}} + +namespace ns2 { + template struct identity {}; + + template requires requires { typename identity; } // expected-note 2{{because 'typename identity' would be invalid: too few template arguments for class template 'identity'}} + struct r4 {}; + + using r4i1 = r4; // expected-error{{constraints not satisfied for class template 'r4' [with Ts = ]}} +} + +using r4i2 = ns2::r4; // expected-error{{constraints not satisfied for class template 'r4' [with Ts = ]}} + +using E = int; +template requires requires { typename E; } // expected-error{{expected ';' at end of requirement}} +struct r5v1 {}; +template requires requires { typename ::E; } // expected-error{{expected ';' at end of requirement}} +struct r5v2 {}; + +template requires (sizeof(T) == 1) +struct chars_only {}; + +template requires requires { typename chars_only; } // expected-note{{because 'typename chars_only' would be invalid: constraints not satisfied for class template 'chars_only' [with T = int]}} +struct r6 {}; + +using r6i = r6; // expected-error{{constraints not satisfied for class template 'r6' [with T = int]}} + +template int F = 0; // expected-note 2{{variable template 'F' declared here}} + +static_assert(!requires { typename F; }); +// expected-error@-1{{template name refers to non-type template 'F'}} +static_assert(!requires { typename ::F; }); +// expected-error@-1{{template name refers to non-type template '::F'}} + +struct G { template static T temp; }; + +template requires requires { typename T::template temp; } +// expected-note@-1{{because 'typename T::temp' would be invalid: type 'int' cannot be used prior to '::' because it has no members}} +// expected-note@-2{{because 'typename T::temp' would be invalid: no member named 'temp' in 'D'}} +// expected-note@-3{{because 'typename T::temp' would be invalid: template name refers to non-type template 'G::template temp'}} +struct r7 {}; + +using r7i1 = r7; // expected-error{{constraints not satisfied for class template 'r7' [with T = int]}} +using r7i2 = r7; // expected-error{{constraints not satisfied for class template 'r7' [with T = D]}} +using r7i3 = r7; // expected-error{{constraints not satisfied for class template 'r7' [with T = G]}} + +template struct H; + +template requires requires { typename H; } +struct r8 {}; + +using r8i = r8; + +template struct I { struct incomplete; }; // expected-note{{member is declared here}} + +static_assert(!requires { I::incomplete::inner; }); // expected-error{{implicit instantiation of undefined member 'I::incomplete'}} + +template requires requires { typename I::incomplete::inner; } // expected-note{{because 'typename I::incomplete::inner' would be invalid: implicit instantiation of undefined member 'I::incomplete'}} +struct r9 {}; + +using r9i = r9; // expected-error{{constraints not satisfied for class template 'r9' [with T = int]}} + +namespace ns3 { + struct X { }; // expected-note 2{{candidate found by name lookup is 'ns3::X'}} +} + +struct X { using inner = int; }; // expected-note 2{{candidate found by name lookup is 'X'}} + +using namespace ns3; +static_assert(requires { typename X; }); // expected-error{{reference to 'X' is ambiguous}} +static_assert(requires { typename X::inner; }); // expected-error{{reference to 'X' is ambiguous}} +// expected-error@-1{{unknown type name 'inner'}} + +// naming a type template specialization in a type requirement does not require +// it to be complete and should not care about partial specializations. + +template +struct Z; + +template requires (sizeof(T) >= 1) +struct Z {}; // expected-note{{partial specialization matches [with T = int]}} + +template requires (sizeof(T) <= 4) +struct Z {}; // expected-note{{partial specialization matches [with T = int]}} + +Z x; // expected-error{{ambiguous partial specializations of 'Z'}} + +static_assert(requires { typename Z; }); + +// C++ [expr.prim.req.type] Example +namespace std_example { + template struct S; + // expected-note@-1 {{because 'typename S' would be invalid: no type named 'type' in 'std_example::has_inner}} + template using Ref = T&; // expected-note{{because 'typename Ref' would be invalid: cannot form a reference to 'void'}} + template concept C1 = + requires { + typename T::inner; + // expected-note@-1 {{because 'typename T::inner' would be invalid: type 'int' cannot be used prior to '::' because it has no members}} + // expected-note@-2 {{because 'typename T::inner' would be invalid: no type named 'inner' in 'std_example::has_type'}} + }; + template concept C2 = requires { typename S; }; + template concept C3 = requires { typename Ref; }; + + struct has_inner { using inner = int;}; + struct has_type { using type = int; }; + struct has_inner_and_type { using inner = int; using type = int; }; + + static_assert(C1 && C2 && C3); + template struct C1_check {}; + // expected-note@-1 {{because 'int' does not satisfy 'C1'}} + // expected-note@-2 {{because 'std_example::has_type' does not satisfy 'C1'}} + template struct C2_check {}; + // expected-note@-1 {{because 'std_example::has_inner' does not satisfy 'C2'}} + template struct C3_check {}; + // expected-note@-1 {{because 'void' does not satisfy 'C3'}} + using c1 = C1_check; // expected-error{{constraints not satisfied for class template 'C1_check' [with T = int]}} + using c2 = C1_check; // expected-error{{constraints not satisfied for class template 'C1_check' [with T = std_example::has_type]}} + using c3 = C2_check; // expected-error{{constraints not satisfied for class template 'C2_check' [with T = std_example::has_inner]}} + using c4 = C3_check; // expected-error{{constraints not satisfied for class template 'C3_check' [with T = void]}} +} \ No newline at end of file diff --git a/clang/test/CXX/over/over.match/over.match.best/p1-2a.cpp b/clang/test/CXX/over/over.match/over.match.best/p1-2a.cpp index 36c68071448c7..dff06308a98ed 100644 --- a/clang/test/CXX/over/over.match/over.match.best/p1-2a.cpp +++ b/clang/test/CXX/over/over.match/over.match.best/p1-2a.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -verify %s +// RUN: %clang_cc1 -std=c++2a -verify %s template constexpr static bool is_same_v = false; diff --git a/clang/test/CXX/over/over.match/over.match.best/p2.cpp b/clang/test/CXX/over/over.match/over.match.best/p2.cpp new file mode 100644 index 0000000000000..3a44436655767 --- /dev/null +++ b/clang/test/CXX/over/over.match/over.match.best/p2.cpp @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -std=c++2a -verify %s + +namespace PR44761 { + template concept X = (sizeof(T) == sizeof(T)); + + template struct A { + bool operator<(const A&) const & requires X; // #1 + int operator<=>(const A&) const & requires X && X = delete; // #2 + }; + bool k1 = A() < A(); // not ordered by constraints: prefer non-rewritten form + bool k2 = A() < A(); // prefer more-constrained 'operator<=>' + // expected-error@-1 {{deleted}} + // expected-note@#1 {{candidate}} + // expected-note@#2 {{candidate function has been explicitly deleted}} + // expected-note@#2 {{candidate function (with reversed parameter order) has been explicitly deleted}} +} diff --git a/clang/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3-2a.cpp b/clang/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3-2a.cpp index 3be8dc7749c6f..023e076d50a73 100644 --- a/clang/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3-2a.cpp +++ b/clang/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3-2a.cpp @@ -113,6 +113,18 @@ namespace bullet4 { X<3> reversed_add = x2 + x1; // expected-error {{invalid operands}} } +namespace PR44627 { + namespace ADL { + struct type {}; + bool operator==(type lhs, int rhs) { + return true; + } + } + + bool b1 = ADL::type() == 0; + bool b2 = 0 == ADL::type(); +} + // Various C++17 cases that are known to be broken by the C++20 rules. namespace problem_cases { // We can have an ambiguity between an operator and its reversed form. This diff --git a/clang/test/CXX/over/over.match/over.match.viable/p3.cpp b/clang/test/CXX/over/over.match/over.match.viable/p3.cpp index ef752d76ec23d..c6f9922226771 100644 --- a/clang/test/CXX/over/over.match/over.match.viable/p3.cpp +++ b/clang/test/CXX/over/over.match/over.match.viable/p3.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -verify %s +// RUN: %clang_cc1 -std=c++2a -verify %s struct S2 {}; // expected-note@-1 {{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'S1' to 'const S2' for 1st argument}} diff --git a/clang/test/CXX/over/over.over/p4-2a.cpp b/clang/test/CXX/over/over.over/p4-2a.cpp index a5d7a110992cf..669620360f882 100644 --- a/clang/test/CXX/over/over.over/p4-2a.cpp +++ b/clang/test/CXX/over/over.over/p4-2a.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -verify %s +// RUN: %clang_cc1 -std=c++2a -verify %s template constexpr static bool is_same_v = false; diff --git a/clang/test/CXX/temp/temp.arg/temp.arg.template/p3-2a.cpp b/clang/test/CXX/temp/temp.arg/temp.arg.template/p3-2a.cpp index 593336163fa1b..8e69f134a3d14 100644 --- a/clang/test/CXX/temp/temp.arg/temp.arg.template/p3-2a.cpp +++ b/clang/test/CXX/temp/temp.arg/temp.arg.template/p3-2a.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -frelaxed-template-template-args -verify %s +// RUN: %clang_cc1 -std=c++2a -frelaxed-template-template-args -verify %s template concept C = T::f(); // expected-note@-1{{similar constraint}} @@ -7,9 +7,9 @@ template concept F = T::f(); // expected-note@-1{{similar constraint expressions not considered equivalent}} template class P> struct S1 { }; // expected-note 2{{'P' declared here}} -template struct X { }; // expected-note{{'X' declared here}} +template struct X { }; -template struct Y { }; // expected-note 2{{'Y' declared here}} +template struct Y { }; // expected-note{{'Y' declared here}} template struct Z { }; template struct W { }; // expected-note{{'W' declared here}} @@ -18,10 +18,10 @@ S1 s12; // expected-error{{template template argument 'Y' is more constrained S1 s13; S1 s14; // expected-error{{template template argument 'W' is more constrained than template template parameter 'P'}} -template class P> struct S2 { }; // expected-note 2{{'P' declared here}} +template class P> struct S2 { }; -S2 s21; // expected-error{{template template argument 'X' is more constrained than template template parameter 'P'}} -S2 s22; // expected-error{{template template argument 'Y' is more constrained than template template parameter 'P'}} +S2 s21; +S2 s22; S2 s23; template