84 changes: 48 additions & 36 deletions clang/include/clang/Basic/Attr.td

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions clang/include/clang/Basic/BuiltinsAArch64.def
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ TARGET_HEADER_BUILTIN(_BitScanForward64, "UcUNi*ULLi", "nh", INTRIN_H, ALL_MS_LA
TARGET_HEADER_BUILTIN(_BitScanReverse64, "UcUNi*ULLi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")

TARGET_HEADER_BUILTIN(_InterlockedAdd, "NiNiD*Ni", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedAdd64, "LLiLLiD*LLi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedAnd64, "LLiLLiD*LLi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedDecrement64, "LLiLLiD*", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedExchange64, "LLiLLiD*LLi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
Expand Down
2 changes: 0 additions & 2 deletions clang/include/clang/Basic/DiagnosticCommonKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -356,8 +356,6 @@ def warn_target_unrecognized_env : Warning<
def warn_knl_knm_isa_support_removed : Warning<
"KNL, KNM related Intel Xeon Phi CPU's specific ISA's supports will be removed in LLVM 19.">,
InGroup<DiagGroup<"knl-knm-isa-support-removed">>;
def err_target_unsupported_abi_with_fpu : Error<
"'%0' ABI is not supported with FPU">;

// Source manager
def err_cannot_open_file : Error<"cannot open file '%0': %1">, DefaultFatal;
Expand Down
3 changes: 0 additions & 3 deletions clang/include/clang/Basic/DiagnosticDriverKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -804,7 +804,4 @@ def warn_android_unversioned_fallback : Warning<

def err_drv_triple_version_invalid : Error<
"version '%0' in target triple '%1' is invalid">;

def err_drv_installapi_unsupported : Error<
"InstallAPI is not supported for '%0'">;
}
4 changes: 4 additions & 0 deletions clang/include/clang/Basic/DiagnosticFrontendKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,10 @@ def err_builtin_needs_feature : Error<"%0 needs target feature %1">;
def err_function_needs_feature : Error<
"always_inline function %1 requires target feature '%2', but would "
"be inlined into function %0 that is compiled without support for '%2'">;
def err_function_always_inline_attribute_mismatch : Error<
"always_inline function %1 and its caller %0 have mismatching %2 attributes">;
def err_function_always_inline_new_za : Error<
"always_inline function %0 has new za state">;

def warn_avx_calling_convention
: Warning<"AVX vector %select{return|argument}0 of type %1 without '%2' "
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/DiagnosticGroups.td
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,9 @@ def : DiagGroup<"c++1z-compat-mangling", [CXX17CompatMangling]>;
def NoexceptType : DiagGroup<"noexcept-type", [CXX17CompatMangling]>;

// Warnings for C code which is not compatible with previous C standards.
def CPre11Compat : DiagGroup<"pre-c11-compat">;
def CPre11CompatPedantic : DiagGroup<"pre-c11-compat-pedantic",
[CPre11Compat]>;
def CPre23Compat : DiagGroup<"pre-c23-compat">;
def CPre23CompatPedantic : DiagGroup<"pre-c23-compat-pedantic",
[CPre23Compat]>;
Expand Down
5 changes: 4 additions & 1 deletion clang/include/clang/Basic/DiagnosticLexKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,10 @@ def err_raw_delim_too_long : Error<
"raw string delimiter longer than 16 characters"
"; use PREFIX( )PREFIX to delimit raw string">;
def err_invalid_char_raw_delim : Error<
"invalid character '%0' character in raw string delimiter"
"invalid character '%0' in raw string delimiter"
"; use PREFIX( )PREFIX to delimit raw string">;
def err_invalid_newline_raw_delim : Error<
"invalid newline character in raw string delimiter"
"; use PREFIX( )PREFIX to delimit raw string">;
def err_unterminated_raw_string : Error<
"raw string missing terminating delimiter )%0\"">;
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/DiagnosticParseKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,9 @@ def ext_c99_feature : Extension<
"'%0' is a C99 extension">, InGroup<C99>;
def ext_c11_feature : Extension<
"'%0' is a C11 extension">, InGroup<C11>;
def warn_c11_compat_keyword : Warning<
"'%0' is incompatible with C standards before C11">,
InGroup<CPre11Compat>, DefaultIgnore;
def warn_c23_compat_keyword : Warning<
"'%0' is incompatible with C standards before C23">,
InGroup<CPre23Compat>, DefaultIgnore;
Expand Down
11 changes: 8 additions & 3 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -5325,7 +5325,7 @@ def err_alias_template_extra_headers : Error<
def err_template_spec_extra_headers : Error<
"extraneous template parameter list in template specialization or "
"out-of-line template definition">;
def warn_template_spec_extra_headers : Warning<
def ext_template_spec_extra_headers : ExtWarn<
"extraneous template parameter list in template specialization">;
def note_explicit_template_spec_does_not_need_header : Note<
"'template<>' header not required for explicitly-specialized class %0 "
Expand Down Expand Up @@ -8255,6 +8255,9 @@ def err_not_tag_in_scope : Error<
def ext_template_after_declarative_nns : ExtWarn<
"'template' cannot be used after a declarative nested name specifier">,
InGroup<DiagGroup<"template-in-declaration-name">>;
def ext_alias_template_in_declarative_nns : ExtWarn<
"a declarative nested name specifier cannot name an alias template">,
InGroup<DiagGroup<"alias-template-in-declaration-name">>;

def err_no_typeid_with_fno_rtti : Error<
"use of typeid requires -frtti">;
Expand Down Expand Up @@ -10361,6 +10364,8 @@ def err_x86_builtin_tile_arg_duplicate : Error<

def err_builtin_target_unsupported : Error<
"builtin is not supported on this target">;
def err_builtin_aix_os_unsupported : Error<
"this builtin is available only on AIX 7.2 and later operating systems">;
def err_builtin_longjmp_unsupported : Error<
"__builtin_longjmp is not supported for the current target">;
def err_builtin_setjmp_unsupported : Error<
Expand Down Expand Up @@ -11314,8 +11319,6 @@ def err_omp_wrong_dependency_iterator_type : Error<
def err_target_unsupported_type
: Error<"%0 requires %select{|%2 bit size}1 %3 %select{|return }4type support,"
" but target '%5' does not support it">;
def err_target_unsupported_type_for_abi
: Error<"%0 requires %1 type support, but ABI '%2' does not support it">;
def err_omp_lambda_capture_in_declare_target_not_to : Error<
"variable captured in declare target region must appear in a to clause">;
def err_omp_device_type_mismatch : Error<
Expand Down Expand Up @@ -12200,4 +12203,6 @@ def warn_acc_clause_unimplemented
def err_acc_construct_appertainment
: Error<"OpenACC construct '%0' cannot be used here; it can only "
"be used in a statement context">;
def err_acc_branch_in_out
: Error<"invalid branch %select{out of|into}0 OpenACC region">;
} // end of sema component.
8 changes: 0 additions & 8 deletions clang/include/clang/Basic/TargetInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,6 @@ class TargetInfo : public TransferrableTargetInfo,
bool HasIbm128;
bool HasLongDouble;
bool HasFPReturn;
bool HasFPTypes;
bool HasStrictFP;

unsigned char MaxAtomicPromoteWidth, MaxAtomicInlineWidth;
Expand Down Expand Up @@ -690,9 +689,6 @@ class TargetInfo : public TransferrableTargetInfo,
/// on this target.
virtual bool hasFPReturn() const { return HasFPReturn; }

/// Determine whether floating point types are supported for this target.
virtual bool hasFPTypes() const { return HasFPTypes; }

/// Determine whether constrained floating point is supported on this target.
virtual bool hasStrictFP() const { return HasStrictFP; }

Expand Down Expand Up @@ -1335,10 +1331,6 @@ class TargetInfo : public TransferrableTargetInfo,
return false;
}

/// Make changes to the supported types which depend on both the target
/// features and ABI.
virtual void setSupportedArgTypes() {}

/// Use the specified unit for FP math.
///
/// \return False on error (invalid unit name).
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Basic/TokenKinds.def
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,7 @@ TYPE_TRAIT_1(__is_trivially_copyable, IsTriviallyCopyable, KEYCXX)
TYPE_TRAIT_1(__is_union, IsUnion, KEYCXX)
TYPE_TRAIT_1(__has_unique_object_representations,
HasUniqueObjectRepresentations, KEYCXX)
TYPE_TRAIT_2(__is_layout_compatible, IsLayoutCompatible, KEYCXX)

#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) KEYWORD(__##Trait, KEYCXX)
#include "clang/Basic/TransformTypeTraits.def"
Expand Down
12 changes: 0 additions & 12 deletions clang/include/clang/Driver/Action.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ class Action {
PreprocessJobClass,
PrecompileJobClass,
ExtractAPIJobClass,
InstallAPIJobClass,
AnalyzeJobClass,
MigrateJobClass,
CompileJobClass,
Expand Down Expand Up @@ -449,17 +448,6 @@ class ExtractAPIJobAction : public JobAction {
void addHeaderInput(Action *Input) { getInputs().push_back(Input); }
};

class InstallAPIJobAction : public JobAction {
void anchor() override;

public:
InstallAPIJobAction(Action *Input, types::ID OutputType);

static bool classof(const Action *A) {
return A->getKind() == InstallAPIJobClass;
}
};

class AnalyzeJobAction : public JobAction {
void anchor() override;

Expand Down
10 changes: 10 additions & 0 deletions clang/include/clang/Driver/Driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,11 @@ class Driver {
/// from non-system headers are emitted.
HeaderIncludeFilteringKind CCPrintHeadersFiltering = HIFIL_None;

/// Name of the library that provides implementations of
/// IEEE-754 128-bit float math functions used by Fortran F128
/// runtime library. It should be linked as needed by the linker job.
std::string FlangF128MathLibrary;

/// Set CC_LOG_DIAGNOSTICS mode, which causes the frontend to log diagnostics
/// to CCLogDiagnosticsFilename or to stderr, in a stable machine readable
/// format.
Expand Down Expand Up @@ -440,6 +445,11 @@ class Driver {
bool offloadHostOnly() const { return Offload == OffloadHost; }
bool offloadDeviceOnly() const { return Offload == OffloadDevice; }

void setFlangF128MathLibrary(std::string name) {
FlangF128MathLibrary = std::move(name);
}
StringRef getFlangF128MathLibrary() const { return FlangF128MathLibrary; }

/// Compute the desired OpenMP runtime from the flags provided.
OpenMPRuntimeKind getOpenMPRuntime(const llvm::opt::ArgList &Args) const;

Expand Down
16 changes: 2 additions & 14 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -336,8 +336,6 @@ class AnalyzerOpts<string base>
: KeyPathAndMacro<"AnalyzerOpts->", base, "ANALYZER_"> {}
class MigratorOpts<string base>
: KeyPathAndMacro<"MigratorOpts.", base, "MIGRATOR_"> {}
class InstallAPIOpts<string base>
: KeyPathAndMacro<"InstallAPIOpts.", base, "INSTALLAPI_"> {}

// A boolean option which is opt-in in CC1. The positive option exists in CC1 and
// Args.hasArg(OPT_ffoo) can be used to check that the flag is enabled.
Expand Down Expand Up @@ -1143,8 +1141,7 @@ def config_user_dir_EQ : Joined<["--"], "config-user-dir=">,
def coverage : Flag<["-", "--"], "coverage">, Group<Link_Group>,
Visibility<[ClangOption, CLOption]>;
def cpp_precomp : Flag<["-"], "cpp-precomp">, Group<clang_ignored_f_Group>;
def current__version : JoinedOrSeparate<["-"], "current_version">,
Visibility<[ClangOption, CC1Option]>;
def current__version : JoinedOrSeparate<["-"], "current_version">;
def cxx_isystem : JoinedOrSeparate<["-"], "cxx-isystem">, Group<clang_i_Group>,
HelpText<"Add directory to the C++ SYSTEM include search path">,
Visibility<[ClangOption, CC1Option]>,
Expand Down Expand Up @@ -1559,9 +1556,6 @@ def static_libsan : Flag<["-"], "static-libsan">,
HelpText<"Statically link the sanitizer runtime (Not supported for ASan, TSan or UBSan on darwin)">;
def : Flag<["-"], "shared-libasan">, Alias<shared_libsan>;
def fasm : Flag<["-"], "fasm">, Group<f_Group>;
def installapi : Flag<["-"], "installapi">,
Visibility<[ClangOption, CC1Option]>, Group<Action_Group>,
HelpText<"Create a text-based stub file by scanning header files">;

defm assume_unique_vtables : BoolFOption<"assume-unique-vtables",
CodeGenOpts<"AssumeUniqueVTables">, DefaultTrue,
Expand Down Expand Up @@ -3871,10 +3865,6 @@ def funroll_loops : Flag<["-"], "funroll-loops">, Group<f_Group>,
HelpText<"Turn on loop unroller">, Visibility<[ClangOption, CC1Option]>;
def fno_unroll_loops : Flag<["-"], "fno-unroll-loops">, Group<f_Group>,
HelpText<"Turn off loop unroller">, Visibility<[ClangOption, CC1Option]>;
defm reroll_loops : BoolFOption<"reroll-loops",
CodeGenOpts<"RerollLoops">, DefaultFalse,
PosFlag<SetTrue, [], [ClangOption, CC1Option], "Turn on loop reroller">,
NegFlag<SetFalse>>;
def ffinite_loops: Flag<["-"], "ffinite-loops">, Group<f_Group>,
HelpText<"Assume all loops are finite.">, Visibility<[ClangOption, CC1Option]>;
def fno_finite_loops: Flag<["-"], "fno-finite-loops">, Group<f_Group>,
Expand Down Expand Up @@ -4324,9 +4314,7 @@ def verify_pch : Flag<["-"], "verify-pch">, Group<Action_Group>,
Visibility<[ClangOption, CC1Option]>,
HelpText<"Load and verify that a pre-compiled header file is not stale">;
def init : Separate<["-"], "init">;
def install__name : Separate<["-"], "install_name">,
Visibility<[ClangOption, CC1Option]>,
MarshallingInfoString<InstallAPIOpts<"InstallName">>;
def install__name : Separate<["-"], "install_name">;
def iprefix : JoinedOrSeparate<["-"], "iprefix">, Group<clang_i_Group>,
Visibility<[ClangOption, CC1Option]>,
HelpText<"Set the -iwithprefix/-iwithprefixbefore prefix">, MetaVarName<"<dir>">;
Expand Down
10 changes: 10 additions & 0 deletions clang/include/clang/Driver/ToolChain.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,11 @@ class ToolChain {
RM_Disabled,
};

enum ExceptionsMode {
EM_Enabled,
EM_Disabled,
};

struct BitCodeLibraryInfo {
std::string Path;
bool ShouldInternalize;
Expand All @@ -141,6 +146,8 @@ class ToolChain {

const RTTIMode CachedRTTIMode;

const ExceptionsMode CachedExceptionsMode;

/// The list of toolchain specific path prefixes to search for libraries.
path_list LibraryPaths;

Expand Down Expand Up @@ -318,6 +325,9 @@ class ToolChain {
// Returns the RTTIMode for the toolchain with the current arguments.
RTTIMode getRTTIMode() const { return CachedRTTIMode; }

// Returns the ExceptionsMode for the toolchain with the current arguments.
ExceptionsMode getExceptionsMode() const { return CachedExceptionsMode; }

/// Return any implicit target and/or mode flag for an invocation of
/// the compiler driver as `ProgName`.
///
Expand Down
1 change: 0 additions & 1 deletion clang/include/clang/Driver/Types.def
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,6 @@ TYPE("lto-bc", LTO_BC, INVALID, "o", phases
TYPE("ast", AST, INVALID, "ast", phases::Compile, phases::Backend, phases::Assemble, phases::Link)
TYPE("ifs", IFS, INVALID, "ifs", phases::IfsMerge)
TYPE("ifs-cpp", IFS_CPP, INVALID, "ifs", phases::Compile, phases::IfsMerge)
TYPE("tbd", TextAPI, INVALID, "tbd", phases::Precompile)
TYPE("pcm", ModuleFile, INVALID, "pcm", phases::Compile, phases::Backend, phases::Assemble, phases::Link)
TYPE("header-unit", HeaderUnit, INVALID, "pcm", phases::Compile, phases::Backend, phases::Assemble, phases::Link)
TYPE("plist", Plist, INVALID, "plist", phases::Compile, phases::Backend, phases::Assemble, phases::Link)
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/ExtractAPI/API.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@
#ifndef LLVM_CLANG_EXTRACTAPI_API_H
#define LLVM_CLANG_EXTRACTAPI_API_H

#include "clang/AST/Availability.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/RawCommentList.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/Specifiers.h"
#include "clang/ExtractAPI/AvailabilityInfo.h"
#include "clang/ExtractAPI/DeclarationFragments.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/StringRef.h"
Expand Down
76 changes: 0 additions & 76 deletions clang/include/clang/ExtractAPI/AvailabilityInfo.h

This file was deleted.

2 changes: 1 addition & 1 deletion clang/include/clang/ExtractAPI/ExtractAPIVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@
#ifndef LLVM_CLANG_EXTRACTAPI_EXTRACT_API_VISITOR_H
#define LLVM_CLANG_EXTRACTAPI_EXTRACT_API_VISITOR_H

#include "clang/AST/Availability.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/Basic/OperatorKinds.h"
#include "clang/Basic/Specifiers.h"
#include "clang/ExtractAPI/AvailabilityInfo.h"
#include "clang/ExtractAPI/DeclarationFragments.h"
#include "llvm/ADT/FunctionExtras.h"

Expand Down
7 changes: 0 additions & 7 deletions clang/include/clang/Frontend/CompilerInstance.h
Original file line number Diff line number Diff line change
Expand Up @@ -294,13 +294,6 @@ class CompilerInstance : public ModuleLoader {
return Invocation->getFrontendOpts();
}

InstallAPIOptions &getInstallAPIOpts() {
return Invocation->getInstallAPIOpts();
}
const InstallAPIOptions &getInstallAPIOpts() const {
return Invocation->getInstallAPIOpts();
}

HeaderSearchOptions &getHeaderSearchOpts() {
return Invocation->getHeaderSearchOpts();
}
Expand Down
9 changes: 1 addition & 8 deletions clang/include/clang/Frontend/CompilerInvocation.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,11 @@
#include "clang/Basic/LangStandard.h"
#include "clang/Frontend/DependencyOutputOptions.h"
#include "clang/Frontend/FrontendOptions.h"
#include "clang/Frontend/InstallAPIOptions.h"
#include "clang/Frontend/MigratorOptions.h"
#include "clang/Frontend/PreprocessorOutputOptions.h"
#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/ArrayRef.h"
#include <memory>
#include <string>

Expand Down Expand Up @@ -112,9 +111,6 @@ class CompilerInvocationBase {
/// Options controlling preprocessed output.
std::shared_ptr<PreprocessorOutputOptions> PreprocessorOutputOpts;

/// Options controlling InstallAPI operations and output.
std::shared_ptr<InstallAPIOptions> InstallAPIOpts;

/// Dummy tag type whose instance can be passed into the constructor to
/// prevent creation of the reference-counted option objects.
struct EmptyConstructor {};
Expand Down Expand Up @@ -149,7 +145,6 @@ class CompilerInvocationBase {
const PreprocessorOutputOptions &getPreprocessorOutputOpts() const {
return *PreprocessorOutputOpts;
}
const InstallAPIOptions &getInstallAPIOpts() const { return *InstallAPIOpts; }
/// @}

/// Command line generation.
Expand Down Expand Up @@ -242,7 +237,6 @@ class CompilerInvocation : public CompilerInvocationBase {
using CompilerInvocationBase::getFrontendOpts;
using CompilerInvocationBase::getDependencyOutputOpts;
using CompilerInvocationBase::getPreprocessorOutputOpts;
using CompilerInvocationBase::getInstallAPIOpts;
/// @}

/// Mutable getters.
Expand All @@ -264,7 +258,6 @@ class CompilerInvocation : public CompilerInvocationBase {
PreprocessorOutputOptions &getPreprocessorOutputOpts() {
return *PreprocessorOutputOpts;
}
InstallAPIOptions &getInstallAPIOpts() { return *InstallAPIOpts; }
/// @}

/// Base class internals.
Expand Down
10 changes: 0 additions & 10 deletions clang/include/clang/Frontend/FrontendActions.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,16 +130,6 @@ class GenerateModuleAction : public ASTFrontendAction {
bool shouldEraseOutputFiles() override;
};

class InstallAPIAction : public ASTFrontendAction {
protected:
std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) override;

public:
static std::unique_ptr<llvm::raw_pwrite_stream>
CreateOutputFile(CompilerInstance &CI, StringRef InFile);
};

class GenerateInterfaceStubsAction : public ASTFrontendAction {
protected:
std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
Expand Down
3 changes: 0 additions & 3 deletions clang/include/clang/Frontend/FrontendOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,6 @@ enum ActionKind {
/// Only execute frontend initialization.
InitOnly,

// Create TextAPI stub.
InstallAPI,

/// Dump information about a module file.
ModuleFileInfo,

Expand Down
28 changes: 0 additions & 28 deletions clang/include/clang/Frontend/InstallAPIOptions.h

This file was deleted.

27 changes: 1 addition & 26 deletions clang/include/clang/InstallAPI/Context.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,10 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Top level types for interacting with the generic clang driver and frontend
// for InstallAPI operations.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_INSTALLAPI_CONTEXT_H
#define LLVM_CLANG_INSTALLAPI_CONTEXT_H

#include "clang/AST/ASTConsumer.h"
#include "clang/Basic/Diagnostic.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/TextAPI/InterfaceFile.h"
#include "llvm/TextAPI/RecordVisitor.h"
#include "llvm/TextAPI/RecordsSlice.h"
Expand All @@ -35,30 +27,13 @@ struct InstallAPIContext {
/// Active target triple to parse.
llvm::Triple TargetTriple{};

/// Output stream to write TextAPI file to.
std::unique_ptr<llvm::raw_pwrite_stream> OS = nullptr;

/// DiagnosticsEngine to report errors.
llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags = nullptr;

/// File Path of output location.
StringRef OutputLoc{};
llvm::StringRef OutputLoc{};

/// What encoding to write output as.
llvm::MachO::FileType FT = llvm::MachO::FileType::TBD_V5;
};

class InstallAPIConsumer : public ASTConsumer {
public:
InstallAPIConsumer(InstallAPIContext InstallAPICtx)
: Ctx(std::move(InstallAPICtx)) {}

void HandleTranslationUnit(ASTContext &ASTContext) override;

private:
InstallAPIContext Ctx;
};

} // namespace installapi
} // namespace clang

Expand Down
42 changes: 42 additions & 0 deletions clang/include/clang/InstallAPI/FileList.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//===- InstallAPI/FileList.h ------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
/// The JSON file list parser is used to communicate input to InstallAPI.
///
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_INSTALLAPI_FILELIST_H
#define LLVM_CLANG_INSTALLAPI_FILELIST_H

#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/FileManager.h"
#include "clang/InstallAPI/HeaderFile.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/MemoryBuffer.h"

namespace clang {
namespace installapi {

class FileListReader {
public:
/// Decode JSON input and append header input into destination container.
/// Headers are loaded in the order they appear in the JSON input.
///
/// \param InputBuffer JSON input data.
/// \param Destination Container to load headers into.
static llvm::Error
loadHeaders(std::unique_ptr<llvm::MemoryBuffer> InputBuffer,
HeaderSeq &Destination);

FileListReader() = delete;
};

} // namespace installapi
} // namespace clang

#endif // LLVM_CLANG_INSTALLAPI_FILELIST_H
75 changes: 75 additions & 0 deletions clang/include/clang/InstallAPI/HeaderFile.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
//===- InstallAPI/HeaderFile.h ----------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
/// Representations of a library's headers for InstallAPI.
///
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_INSTALLAPI_HEADERFILE_H
#define LLVM_CLANG_INSTALLAPI_HEADERFILE_H

#include "clang/Basic/LangStandard.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Regex.h"
#include <optional>
#include <string>

namespace clang::installapi {
enum class HeaderType {
/// Unset or unknown type.
Unknown,
/// Represents declarations accessible to all clients.
Public,
/// Represents declarations accessible to a disclosed set of clients.
Private,
/// Represents declarations only accessible as implementation details to the
/// input library.
Project,
};

class HeaderFile {
/// Full input path to header.
std::string FullPath;
/// Access level of header.
HeaderType Type;
/// Expected way header will be included by clients.
std::string IncludeName;
/// Supported language mode for header.
std::optional<clang::Language> Language;

public:
HeaderFile() = delete;
HeaderFile(StringRef FullPath, HeaderType Type,
StringRef IncludeName = StringRef(),
std::optional<clang::Language> Language = std::nullopt)
: FullPath(FullPath), Type(Type), IncludeName(IncludeName),
Language(Language) {}

static llvm::Regex getFrameworkIncludeRule();

bool operator==(const HeaderFile &Other) const {
return std::tie(Type, FullPath, IncludeName, Language) ==
std::tie(Other.Type, Other.FullPath, Other.IncludeName,
Other.Language);
}
};

/// Assemble expected way header will be included by clients.
/// As in what maps inside the brackets of `#include <IncludeName.h>`
/// For example,
/// "/System/Library/Frameworks/Foo.framework/Headers/Foo.h" returns
/// "Foo/Foo.h"
///
/// \param FullPath Path to the header file which includes the library
/// structure.
std::optional<std::string> createIncludeHeaderName(const StringRef FullPath);
using HeaderSeq = std::vector<HeaderFile>;

} // namespace clang::installapi

#endif // LLVM_CLANG_INSTALLAPI_HEADERFILE_H
2 changes: 2 additions & 0 deletions clang/include/clang/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -1122,6 +1122,8 @@ class Parser : public CodeCompletionHandler {
void checkCompoundToken(SourceLocation FirstTokLoc,
tok::TokenKind FirstTokKind, CompoundToken Op);

void diagnoseUseOfC11Keyword(const Token &Tok);

public:
//===--------------------------------------------------------------------===//
// Scope manipulation
Expand Down
17 changes: 17 additions & 0 deletions clang/include/clang/Sema/Scope.h
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,9 @@ class Scope {
/// template scope in between), the outer scope does not increase the
/// depth of recursion.
LambdaScope = 0x8000000,
/// This is the scope of an OpenACC Compute Construct, which restricts
/// jumping into/out of it.
OpenACCComputeConstructScope = 0x10000000,
};

private:
Expand Down Expand Up @@ -469,6 +472,14 @@ class Scope {
return false;
}

/// Return true if this scope is a loop.
bool isLoopScope() const {
// 'switch' is the only loop that is not a 'break' scope as well, so we can
// just check BreakScope and not SwitchScope.
return (getFlags() & Scope::BreakScope) &&
!(getFlags() & Scope::SwitchScope);
}

/// Determines whether this scope is the OpenMP directive scope
bool isOpenMPDirectiveScope() const {
return (getFlags() & Scope::OpenMPDirectiveScope);
Expand Down Expand Up @@ -504,6 +515,12 @@ class Scope {
return getFlags() & Scope::OpenMPOrderClauseScope;
}

/// Determine whether this scope is the statement associated with an OpenACC
/// Compute construct directive.
bool isOpenACCComputeConstructScope() const {
return getFlags() & Scope::OpenACCComputeConstructScope;
}

/// Determine whether this scope is a while/do/for statement, which can have
/// continue statements embedded into it.
bool isContinueScope() const {
Expand Down
7 changes: 6 additions & 1 deletion clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include "clang/AST/NSAPI.h"
#include "clang/AST/PrettyPrinter.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtOpenACC.h"
#include "clang/AST/StmtOpenMP.h"
#include "clang/AST/TypeLoc.h"
#include "clang/AST/TypeOrdering.h"
Expand Down Expand Up @@ -1157,7 +1158,9 @@ class Sema final {
if (FD) {
FD->setWillHaveBody(true);
S.ExprEvalContexts.back().InImmediateFunctionContext =
FD->isImmediateFunction();
FD->isImmediateFunction() ||
S.ExprEvalContexts[S.ExprEvalContexts.size() - 2]
.isConstantEvaluated();
S.ExprEvalContexts.back().InImmediateEscalatingFunctionContext =
S.getLangOpts().CPlusPlus20 && FD->isImmediateEscalating();
} else
Expand Down Expand Up @@ -14077,6 +14080,8 @@ class Sema final {
bool SemaValueIsRunOfOnes(CallExpr *TheCall, unsigned ArgNum);

public:
bool IsLayoutCompatible(QualType T1, QualType T2) const;

// Used by C++ template instantiation.
ExprResult SemaBuiltinShuffleVector(CallExpr *TheCall);
ExprResult SemaConvertVectorExpr(Expr *E, TypeSourceInfo *TInfo,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,12 +110,16 @@ class SValBuilder {
/// that value is returned. Otherwise, returns NULL.
virtual const llvm::APSInt *getKnownValue(ProgramStateRef state, SVal val) = 0;

/// Tries to get the minimal possible (integer) value of a given SVal. If the
/// constraint manager cannot provide an useful answer, this returns NULL.
/// Tries to get the minimal possible (integer) value of a given SVal. This
/// always returns the value of a ConcreteInt, but may return NULL if the
/// value is symbolic and the constraint manager cannot provide a useful
/// answer.
virtual const llvm::APSInt *getMinValue(ProgramStateRef state, SVal val) = 0;

/// Tries to get the maximal possible (integer) value of a given SVal. If the
/// constraint manager cannot provide an useful answer, this returns NULL.
/// Tries to get the maximal possible (integer) value of a given SVal. This
/// always returns the value of a ConcreteInt, but may return NULL if the
/// value is symbolic and the constraint manager cannot provide a useful
/// answer.
virtual const llvm::APSInt *getMaxValue(ProgramStateRef state, SVal val) = 0;

/// Simplify symbolic expressions within a given SVal. Return an SVal
Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
#include "clang/AST/RawCommentList.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/StmtOpenACC.h"
#include "clang/AST/TemplateBase.h"
#include "clang/AST/TemplateName.h"
#include "clang/AST/Type.h"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,22 @@
#include "clang/ExtractAPI/AvailabilityInfo.h"
//===- Availability.cpp --------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file implements the Availability information for Decls.
//
//===----------------------------------------------------------------------===//

#include "clang/AST/Availability.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/STLExtras.h"

using namespace clang::extractapi;
using namespace llvm;
namespace clang {

AvailabilityInfo AvailabilityInfo::createFromDecl(const Decl *Decl) {
ASTContext &Context = Decl->getASTContext();
Expand Down Expand Up @@ -33,3 +44,5 @@ AvailabilityInfo AvailabilityInfo::createFromDecl(const Decl *Decl) {
}
return Availability;
}

} // namespace clang
1 change: 1 addition & 0 deletions clang/lib/AST/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ add_clang_library(clangAST
ASTTypeTraits.cpp
AttrDocTable.cpp
AttrImpl.cpp
Availability.cpp
Comment.cpp
CommentBriefParser.cpp
CommentCommandTraits.cpp
Expand Down
11 changes: 10 additions & 1 deletion clang/lib/AST/Interp/ByteCodeEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,15 @@
using namespace clang;
using namespace clang::interp;

/// Unevaluated builtins don't get their arguments put on the stack
/// automatically. They instead operate on the AST of their Call
/// Expression.
/// Similar information is available via ASTContext::BuiltinInfo,
/// but that is not correct for our use cases.
static bool isUnevaluatedBuiltin(unsigned BuiltinID) {
return BuiltinID == Builtin::BI__builtin_classify_type;
}

Function *ByteCodeEmitter::compileFunc(const FunctionDecl *FuncDecl) {
bool IsLambdaStaticInvoker = false;
if (const auto *MD = dyn_cast<CXXMethodDecl>(FuncDecl);
Expand Down Expand Up @@ -122,7 +131,7 @@ Function *ByteCodeEmitter::compileFunc(const FunctionDecl *FuncDecl) {
if (!Func) {
bool IsUnevaluatedBuiltin = false;
if (unsigned BI = FuncDecl->getBuiltinID())
IsUnevaluatedBuiltin = Ctx.getASTContext().BuiltinInfo.isUnevaluated(BI);
IsUnevaluatedBuiltin = isUnevaluatedBuiltin(BI);

Func =
P.createFunction(FuncDecl, ParamOffset, std::move(ParamTypes),
Expand Down
475 changes: 206 additions & 269 deletions clang/lib/AST/Interp/ByteCodeExprGen.cpp

Large diffs are not rendered by default.

31 changes: 6 additions & 25 deletions clang/lib/AST/Interp/ByteCodeExprGen.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
bool VisitCXXUuidofExpr(const CXXUuidofExpr *E);
bool VisitRequiresExpr(const RequiresExpr *E);
bool VisitConceptSpecializationExpr(const ConceptSpecializationExpr *E);
bool VisitCXXRewrittenBinaryOperator(const CXXRewrittenBinaryOperator *E);

protected:
bool visitExpr(const Expr *E) override;
Expand Down Expand Up @@ -235,29 +236,6 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
bool visitZeroInitializer(PrimType T, QualType QT, const Expr *E);
bool visitZeroRecordInitializer(const Record *R, const Expr *E);

enum class DerefKind {
/// Value is read and pushed to stack.
Read,
/// Direct method generates a value which is written. Returns pointer.
Write,
/// Direct method receives the value, pushes mutated value. Returns pointer.
ReadWrite,
};

/// Method to directly load a value. If the value can be fetched directly,
/// the direct handler is called. Otherwise, a pointer is left on the stack
/// and the indirect handler is expected to operate on that.
bool dereference(const Expr *LV, DerefKind AK,
llvm::function_ref<bool(PrimType)> Direct,
llvm::function_ref<bool(PrimType)> Indirect);
bool dereferenceParam(const Expr *LV, PrimType T, const ParmVarDecl *PD,
DerefKind AK,
llvm::function_ref<bool(PrimType)> Direct,
llvm::function_ref<bool(PrimType)> Indirect);
bool dereferenceVar(const Expr *LV, PrimType T, const VarDecl *PD,
DerefKind AK, llvm::function_ref<bool(PrimType)> Direct,
llvm::function_ref<bool(PrimType)> Indirect);

/// Emits an APSInt constant.
bool emitConst(const llvm::APSInt &Value, PrimType Ty, const Expr *E);
bool emitConst(const llvm::APSInt &Value, const Expr *E);
Expand Down Expand Up @@ -288,8 +266,10 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
}

bool emitComplexReal(const Expr *SubExpr);
bool emitComplexBoolCast(const Expr *E);

bool emitRecordDestruction(const Descriptor *Desc);
bool emitRecordDestruction(const Record *R);
bool emitDestruction(const Descriptor *Desc);
unsigned collectBaseOffset(const RecordType *BaseType,
const RecordType *DerivedType);

Expand Down Expand Up @@ -401,7 +381,8 @@ template <class Emitter> class LocalScope : public VariableScope<Emitter> {
for (Scope::Local &Local : this->Ctx->Descriptors[*Idx]) {
if (!Local.Desc->isPrimitive() && !Local.Desc->isPrimitiveArray()) {
this->Ctx->emitGetPtrLocal(Local.Offset, SourceInfo{});
this->Ctx->emitRecordDestruction(Local.Desc);
this->Ctx->emitDestruction(Local.Desc);
this->Ctx->emitPopPtr(SourceInfo{});
removeIfStoredOpaqueValue(Local);
}
}
Expand Down
25 changes: 5 additions & 20 deletions clang/lib/AST/Interp/Context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,10 @@ bool Context::evaluateAsInitializer(State &Parent, const VarDecl *VD,
assert(Stk.empty());
ByteCodeExprGen<EvalEmitter> C(*this, *P, Parent, Stk, Result);

auto Res = C.interpretDecl(VD);
bool CheckGlobalInitialized =
shouldBeGloballyIndexed(VD) &&
(VD->getType()->isRecordType() || VD->getType()->isArrayType());
auto Res = C.interpretDecl(VD, CheckGlobalInitialized);
if (Res.isInvalid()) {
Stk.clear();
return false;
Expand All @@ -101,25 +104,7 @@ bool Context::evaluateAsInitializer(State &Parent, const VarDecl *VD,
Stk.clear();
#endif

// Ensure global variables are fully initialized.
if (shouldBeGloballyIndexed(VD) &&
(VD->getType()->isRecordType() || VD->getType()->isArrayType() ||
VD->getType()->isAnyComplexType())) {
assert(Res.isLValue());

if (!VD->getType()->isAnyComplexType() &&
!Res.checkFullyInitialized(C.getState()))
return false;

// lvalue-to-rvalue conversion. We do this manually here so we can
// examine the result above before converting and returning it.
std::optional<APValue> RValueResult = Res.toRValue();
if (!RValueResult)
return false;
Result = *RValueResult;

} else
Result = Res.toAPValue();
Result = Res.toAPValue();
return true;
}

Expand Down
4 changes: 2 additions & 2 deletions clang/lib/AST/Interp/Descriptor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ static void moveArrayDesc(Block *B, const std::byte *Src, std::byte *Dst,
static void ctorRecord(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable,
bool IsActive, const Descriptor *D) {
const bool IsUnion = D->ElemRecord->isUnion();
auto CtorSub = [=](unsigned SubOff, Descriptor *F, bool IsBase) {
auto CtorSub = [=](unsigned SubOff, const Descriptor *F, bool IsBase) {
auto *Desc = reinterpret_cast<InlineDescriptor *>(Ptr + SubOff) - 1;
Desc->Offset = SubOff;
Desc->Desc = F;
Expand All @@ -161,7 +161,7 @@ static void ctorRecord(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable,
}

static void dtorRecord(Block *B, std::byte *Ptr, const Descriptor *D) {
auto DtorSub = [=](unsigned SubOff, Descriptor *F) {
auto DtorSub = [=](unsigned SubOff, const Descriptor *F) {
if (auto Fn = F->DtorFn)
Fn(B, Ptr + SubOff, F);
};
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/AST/Interp/Descriptor.h
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,10 @@ struct Descriptor final {
return dyn_cast_if_present<ValueDecl>(asDecl());
}

const VarDecl *asVarDecl() const {
return dyn_cast_if_present<VarDecl>(asDecl());
}

const FieldDecl *asFieldDecl() const {
return dyn_cast_if_present<FieldDecl>(asDecl());
}
Expand Down
20 changes: 17 additions & 3 deletions clang/lib/AST/Interp/EvalEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,12 @@ EvaluationResult EvalEmitter::interpretExpr(const Expr *E,
return std::move(this->EvalResult);
}

EvaluationResult EvalEmitter::interpretDecl(const VarDecl *VD) {
EvaluationResult EvalEmitter::interpretDecl(const VarDecl *VD,
bool CheckFullyInitialized) {
this->CheckFullyInitialized = CheckFullyInitialized;
this->ConvertResultToRValue =
VD->getAnyInitializer() &&
(VD->getAnyInitializer()->getType()->isAnyComplexType());
EvalResult.setSource(VD);

if (!this->visitDecl(VD) && EvalResult.empty())
Expand Down Expand Up @@ -131,7 +136,17 @@ template <> bool EvalEmitter::emitRet<PT_Ptr>(const SourceInfo &Info) {
return false;
}
} else {
EvalResult.setPointer(Ptr);
if (CheckFullyInitialized) {
if (!EvalResult.checkFullyInitialized(S, Ptr))
return false;

std::optional<APValue> RValueResult = Ptr.toRValue(Ctx);
if (!RValueResult)
return false;
EvalResult.setValue(*RValueResult);
} else {
EvalResult.setValue(Ptr.toAPValue());
}
}

return true;
Expand All @@ -140,7 +155,6 @@ template <> bool EvalEmitter::emitRet<PT_FnPtr>(const SourceInfo &Info) {
if (!isActive())
return true;
// Function pointers cannot be converted to rvalues.
assert(!ConvertResultToRValue);
EvalResult.setFunctionPointer(S.Stk.pop<FunctionPointer>());
return true;
}
Expand Down
5 changes: 4 additions & 1 deletion clang/lib/AST/Interp/EvalEmitter.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class EvalEmitter : public SourceMapper {

EvaluationResult interpretExpr(const Expr *E,
bool ConvertResultToRValue = false);
EvaluationResult interpretDecl(const VarDecl *VD);
EvaluationResult interpretDecl(const VarDecl *VD, bool CheckFullyInitialized);

InterpState &getState() { return S; }

Expand Down Expand Up @@ -89,6 +89,9 @@ class EvalEmitter : public SourceMapper {
EvaluationResult EvalResult;
/// Whether the result should be converted to an RValue.
bool ConvertResultToRValue = false;
/// Whether we should check if the result has been fully
/// initialized.
bool CheckFullyInitialized = false;

/// Temporaries which require storage.
llvm::DenseMap<unsigned, std::unique_ptr<char[]>> Locals;
Expand Down
6 changes: 3 additions & 3 deletions clang/lib/AST/Interp/EvaluationResult.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,9 +132,10 @@ static bool CheckFieldsInitialized(InterpState &S, SourceLocation Loc,
return Result;
}

bool EvaluationResult::checkFullyInitialized(InterpState &S) const {
bool EvaluationResult::checkFullyInitialized(InterpState &S,
const Pointer &Ptr) const {
assert(Source);
assert(isLValue());
assert(empty());

// Our Source must be a VarDecl.
const Decl *SourceDecl = Source.dyn_cast<const Decl *>();
Expand All @@ -143,7 +144,6 @@ bool EvaluationResult::checkFullyInitialized(InterpState &S) const {
assert(VD->getType()->isRecordType() || VD->getType()->isArrayType());
SourceLocation InitLoc = VD->getAnyInitializer()->getExprLoc();

const Pointer &Ptr = *std::get_if<Pointer>(&Value);
assert(!Ptr.isZero());

if (const Record *R = Ptr.getRecord())
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/Interp/EvaluationResult.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ class EvaluationResult final {
/// LValue and we can't read from it.
std::optional<APValue> toRValue() const;

bool checkFullyInitialized(InterpState &S) const;
bool checkFullyInitialized(InterpState &S, const Pointer &Ptr) const;

/// Dump to stderr.
void dump() const;
Expand Down
19 changes: 8 additions & 11 deletions clang/lib/AST/Interp/Interp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -357,9 +357,17 @@ bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {

bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
AccessKinds AK) {
assert(Ptr.isLive());

if (Ptr.isInitialized())
return true;

if (const auto *VD = Ptr.getDeclDesc()->asVarDecl();
VD && VD->hasGlobalStorage()) {
const SourceInfo &Loc = S.Current->getSource(OpPC);
S.FFDiag(Loc, diag::note_constexpr_var_init_non_constant, 1) << VD;
S.Note(VD->getLocation(), diag::note_declared_at);
}
if (!S.checkingPotentialConstantExpression()) {
S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_access_uninit)
<< AK << /*uninitialized=*/true << S.Current->getRange(OpPC);
Expand Down Expand Up @@ -533,17 +541,6 @@ bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD) {
return false;
}

bool CheckPotentialReinterpretCast(InterpState &S, CodePtr OpPC,
const Pointer &Ptr) {
if (!S.inConstantContext())
return true;

const SourceInfo &E = S.Current->getSource(OpPC);
S.CCEDiag(E, diag::note_constexpr_invalid_cast)
<< 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);
return false;
}

bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result,
APFloat::opStatus Status) {
const SourceInfo &E = S.Current->getSource(OpPC);
Expand Down
40 changes: 28 additions & 12 deletions clang/lib/AST/Interp/Interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,10 +113,6 @@ bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This);
/// Checks if a method is pure virtual.
bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD);

/// Checks if reinterpret casts are legal in the current context.
bool CheckPotentialReinterpretCast(InterpState &S, CodePtr OpPC,
const Pointer &Ptr);

/// Sets the given integral value to the pointer, which is of
/// a std::{weak,partial,strong}_ordering type.
bool SetThreeWayComparisonField(InterpState &S, CodePtr OpPC,
Expand All @@ -139,7 +135,7 @@ bool CheckShift(InterpState &S, CodePtr OpPC, const LT &LHS, const RT &RHS,
const APSInt Val = RHS.toAPSInt();
QualType Ty = E->getType();
S.CCEDiag(E, diag::note_constexpr_large_shift) << Val << Ty << Bits;
return false;
return true; // We will do the shift anyway but fix up the shift amount.
}

if (LHS.isSigned() && !S.getLangOpts().CPlusPlus20) {
Expand Down Expand Up @@ -1583,6 +1579,11 @@ inline bool SubPtr(InterpState &S, CodePtr OpPC) {
return false;
}

if (LHS.isZero() && RHS.isZero()) {
S.Stk.push<T>();
return true;
}

T A = T::from(LHS.getIndex());
T B = T::from(RHS.getIndex());
return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, A.bitWidth(), A, B);
Expand Down Expand Up @@ -1722,8 +1723,9 @@ template <PrimType Name, class T = typename PrimConv<Name>::T>
bool CastPointerIntegral(InterpState &S, CodePtr OpPC) {
const Pointer &Ptr = S.Stk.pop<Pointer>();

if (!CheckPotentialReinterpretCast(S, OpPC, Ptr))
return false;
const SourceInfo &E = S.Current->getSource(OpPC);
S.CCEDiag(E, diag::note_constexpr_invalid_cast)
<< 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);

S.Stk.push<T>(T::from(Ptr.getIntegerRepresentation()));
return true;
Expand Down Expand Up @@ -1796,11 +1798,17 @@ inline bool Shr(InterpState &S, CodePtr OpPC) {
if (!CheckShift(S, OpPC, LHS, RHS, Bits))
return false;

// Limit the shift amount to Bits - 1. If this happened,
// it has already been diagnosed by CheckShift() above,
// but we still need to handle it.
typename LT::AsUnsigned R;
LT::AsUnsigned::shiftRight(LT::AsUnsigned::from(LHS),
LT::AsUnsigned::from(RHS), Bits, &R);
if (RHS > RT::from(Bits - 1, RHS.bitWidth()))
LT::AsUnsigned::shiftRight(LT::AsUnsigned::from(LHS),
LT::AsUnsigned::from(Bits - 1), Bits, &R);
else
LT::AsUnsigned::shiftRight(LT::AsUnsigned::from(LHS),
LT::AsUnsigned::from(RHS, Bits), Bits, &R);
S.Stk.push<LT>(LT::from(R));

return true;
}

Expand All @@ -1815,9 +1823,17 @@ inline bool Shl(InterpState &S, CodePtr OpPC) {
if (!CheckShift(S, OpPC, LHS, RHS, Bits))
return false;

// Limit the shift amount to Bits - 1. If this happened,
// it has already been diagnosed by CheckShift() above,
// but we still need to handle it.
typename LT::AsUnsigned R;
LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
LT::AsUnsigned::from(RHS, Bits), Bits, &R);
if (RHS > RT::from(Bits - 1, RHS.bitWidth()))
LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
LT::AsUnsigned::from(Bits - 1), Bits, &R);
else
LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
LT::AsUnsigned::from(RHS, Bits), Bits, &R);

S.Stk.push<LT>(LT::from(R));
return true;
}
Expand Down
303 changes: 301 additions & 2 deletions clang/lib/AST/Interp/InterpBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ static APSInt peekToAPSInt(InterpStack &Stk, PrimType T, size_t Offset = 0) {
APSInt R;
INT_TYPE_SWITCH(T, {
T Val = Stk.peek<T>(Offset);
R = APSInt(
APInt(Val.bitWidth(), static_cast<uint64_t>(Val), T::isSigned()));
R = APSInt(APInt(Val.bitWidth(), static_cast<uint64_t>(Val), T::isSigned()),
!T::isSigned());
});

return R;
Expand Down Expand Up @@ -155,6 +155,11 @@ static void pushSizeT(InterpState &S, uint64_t Val) {
}
}

static void assignInteger(Pointer &Dest, PrimType ValueT, const APSInt &Value) {
INT_TYPE_SWITCH_NO_BOOL(
ValueT, { Dest.deref<T>() = T::from(static_cast<T>(Value)); });
}

static bool retPrimValue(InterpState &S, CodePtr OpPC, APValue &Result,
std::optional<PrimType> &T) {
if (!T)
Expand Down Expand Up @@ -658,6 +663,230 @@ static bool interp__builtin_eh_return_data_regno(InterpState &S, CodePtr OpPC,
return true;
}

static bool interp__builtin_launder(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame,
const Function *Func,
const CallExpr *Call) {
const Pointer &Arg = S.Stk.peek<Pointer>();
S.Stk.push<Pointer>(Arg);
return true;
}

// Two integral values followed by a pointer (lhs, rhs, resultOut)
static bool interp__builtin_overflowop(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame,
const Function *Func,
const CallExpr *Call) {
Pointer &ResultPtr = S.Stk.peek<Pointer>();
if (ResultPtr.isDummy())
return false;

unsigned BuiltinOp = Func->getBuiltinID();
PrimType RHST = *S.getContext().classify(Call->getArg(1)->getType());
PrimType LHST = *S.getContext().classify(Call->getArg(0)->getType());
APSInt RHS = peekToAPSInt(S.Stk, RHST,
align(primSize(PT_Ptr)) + align(primSize(RHST)));
APSInt LHS = peekToAPSInt(S.Stk, LHST,
align(primSize(PT_Ptr)) + align(primSize(RHST)) +
align(primSize(LHST)));
QualType ResultType = Call->getArg(2)->getType()->getPointeeType();
PrimType ResultT = *S.getContext().classify(ResultType);
bool Overflow;

APSInt Result;
if (BuiltinOp == Builtin::BI__builtin_add_overflow ||
BuiltinOp == Builtin::BI__builtin_sub_overflow ||
BuiltinOp == Builtin::BI__builtin_mul_overflow) {
bool IsSigned = LHS.isSigned() || RHS.isSigned() ||
ResultType->isSignedIntegerOrEnumerationType();
bool AllSigned = LHS.isSigned() && RHS.isSigned() &&
ResultType->isSignedIntegerOrEnumerationType();
uint64_t LHSSize = LHS.getBitWidth();
uint64_t RHSSize = RHS.getBitWidth();
uint64_t ResultSize = S.getCtx().getTypeSize(ResultType);
uint64_t MaxBits = std::max(std::max(LHSSize, RHSSize), ResultSize);

// Add an additional bit if the signedness isn't uniformly agreed to. We
// could do this ONLY if there is a signed and an unsigned that both have
// MaxBits, but the code to check that is pretty nasty. The issue will be
// caught in the shrink-to-result later anyway.
if (IsSigned && !AllSigned)
++MaxBits;

LHS = APSInt(LHS.extOrTrunc(MaxBits), !IsSigned);
RHS = APSInt(RHS.extOrTrunc(MaxBits), !IsSigned);
Result = APSInt(MaxBits, !IsSigned);
}

// Find largest int.
switch (BuiltinOp) {
default:
llvm_unreachable("Invalid value for BuiltinOp");
case Builtin::BI__builtin_add_overflow:
case Builtin::BI__builtin_sadd_overflow:
case Builtin::BI__builtin_saddl_overflow:
case Builtin::BI__builtin_saddll_overflow:
case Builtin::BI__builtin_uadd_overflow:
case Builtin::BI__builtin_uaddl_overflow:
case Builtin::BI__builtin_uaddll_overflow:
Result = LHS.isSigned() ? LHS.sadd_ov(RHS, Overflow)
: LHS.uadd_ov(RHS, Overflow);
break;
case Builtin::BI__builtin_sub_overflow:
case Builtin::BI__builtin_ssub_overflow:
case Builtin::BI__builtin_ssubl_overflow:
case Builtin::BI__builtin_ssubll_overflow:
case Builtin::BI__builtin_usub_overflow:
case Builtin::BI__builtin_usubl_overflow:
case Builtin::BI__builtin_usubll_overflow:
Result = LHS.isSigned() ? LHS.ssub_ov(RHS, Overflow)
: LHS.usub_ov(RHS, Overflow);
break;
case Builtin::BI__builtin_mul_overflow:
case Builtin::BI__builtin_smul_overflow:
case Builtin::BI__builtin_smull_overflow:
case Builtin::BI__builtin_smulll_overflow:
case Builtin::BI__builtin_umul_overflow:
case Builtin::BI__builtin_umull_overflow:
case Builtin::BI__builtin_umulll_overflow:
Result = LHS.isSigned() ? LHS.smul_ov(RHS, Overflow)
: LHS.umul_ov(RHS, Overflow);
break;
}

// In the case where multiple sizes are allowed, truncate and see if
// the values are the same.
if (BuiltinOp == Builtin::BI__builtin_add_overflow ||
BuiltinOp == Builtin::BI__builtin_sub_overflow ||
BuiltinOp == Builtin::BI__builtin_mul_overflow) {
// APSInt doesn't have a TruncOrSelf, so we use extOrTrunc instead,
// since it will give us the behavior of a TruncOrSelf in the case where
// its parameter <= its size. We previously set Result to be at least the
// type-size of the result, so getTypeSize(ResultType) <= Resu
APSInt Temp = Result.extOrTrunc(S.getCtx().getTypeSize(ResultType));
Temp.setIsSigned(ResultType->isSignedIntegerOrEnumerationType());

if (!APSInt::isSameValue(Temp, Result))
Overflow = true;
Result = Temp;
}

// Write Result to ResultPtr and put Overflow on the stacl.
assignInteger(ResultPtr, ResultT, Result);
ResultPtr.initialize();
assert(Func->getDecl()->getReturnType()->isBooleanType());
S.Stk.push<Boolean>(Overflow);
return true;
}

/// Three integral values followed by a pointer (lhs, rhs, carry, carryOut).
static bool interp__builtin_carryop(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame,
const Function *Func,
const CallExpr *Call) {
unsigned BuiltinOp = Func->getBuiltinID();
PrimType LHST = *S.getContext().classify(Call->getArg(0)->getType());
PrimType RHST = *S.getContext().classify(Call->getArg(1)->getType());
PrimType CarryT = *S.getContext().classify(Call->getArg(2)->getType());
APSInt RHS = peekToAPSInt(S.Stk, RHST,
align(primSize(PT_Ptr)) + align(primSize(CarryT)) +
align(primSize(RHST)));
APSInt LHS =
peekToAPSInt(S.Stk, LHST,
align(primSize(PT_Ptr)) + align(primSize(RHST)) +
align(primSize(CarryT)) + align(primSize(LHST)));
APSInt CarryIn = peekToAPSInt(
S.Stk, LHST, align(primSize(PT_Ptr)) + align(primSize(CarryT)));
APSInt CarryOut;

APSInt Result;
// Copy the number of bits and sign.
Result = LHS;
CarryOut = LHS;

bool FirstOverflowed = false;
bool SecondOverflowed = false;
switch (BuiltinOp) {
default:
llvm_unreachable("Invalid value for BuiltinOp");
case Builtin::BI__builtin_addcb:
case Builtin::BI__builtin_addcs:
case Builtin::BI__builtin_addc:
case Builtin::BI__builtin_addcl:
case Builtin::BI__builtin_addcll:
Result =
LHS.uadd_ov(RHS, FirstOverflowed).uadd_ov(CarryIn, SecondOverflowed);
break;
case Builtin::BI__builtin_subcb:
case Builtin::BI__builtin_subcs:
case Builtin::BI__builtin_subc:
case Builtin::BI__builtin_subcl:
case Builtin::BI__builtin_subcll:
Result =
LHS.usub_ov(RHS, FirstOverflowed).usub_ov(CarryIn, SecondOverflowed);
break;
}
// It is possible for both overflows to happen but CGBuiltin uses an OR so
// this is consistent.
CarryOut = (uint64_t)(FirstOverflowed | SecondOverflowed);

Pointer &CarryOutPtr = S.Stk.peek<Pointer>();
QualType CarryOutType = Call->getArg(3)->getType()->getPointeeType();
PrimType CarryOutT = *S.getContext().classify(CarryOutType);
assignInteger(CarryOutPtr, CarryOutT, CarryOut);
CarryOutPtr.initialize();

assert(Call->getType() == Call->getArg(0)->getType());
pushAPSInt(S, Result);
return true;
}

static bool interp__builtin_clz(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame, const Function *Func,
const CallExpr *Call) {
unsigned BuiltinOp = Func->getBuiltinID();
PrimType ValT = *S.getContext().classify(Call->getArg(0));
const APSInt &Val = peekToAPSInt(S.Stk, ValT);

// When the argument is 0, the result of GCC builtins is undefined, whereas
// for Microsoft intrinsics, the result is the bit-width of the argument.
bool ZeroIsUndefined = BuiltinOp != Builtin::BI__lzcnt16 &&
BuiltinOp != Builtin::BI__lzcnt &&
BuiltinOp != Builtin::BI__lzcnt64;

if (ZeroIsUndefined && Val == 0)
return false;

pushInt(S, Val.countl_zero());
return true;
}

static bool interp__builtin_ctz(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame, const Function *Func,
const CallExpr *Call) {
PrimType ValT = *S.getContext().classify(Call->getArg(0));
const APSInt &Val = peekToAPSInt(S.Stk, ValT);

if (Val == 0)
return false;

pushInt(S, Val.countr_zero());
return true;
}

static bool interp__builtin_bswap(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame,
const Function *Func, const CallExpr *Call) {
PrimType ReturnT = *S.getContext().classify(Call->getType());
PrimType ValT = *S.getContext().classify(Call->getArg(0));
const APSInt &Val = peekToAPSInt(S.Stk, ValT);
assert(Val.getActiveBits() <= 64);

INT_TYPE_SWITCH(ReturnT,
{ S.Stk.push<T>(T::from(Val.byteSwap().getZExtValue())); });
return true;
}

bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
const CallExpr *Call) {
InterpFrame *Frame = S.Current;
Expand Down Expand Up @@ -887,6 +1116,76 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
return false;
break;

case Builtin::BI__builtin_launder:
if (!interp__builtin_launder(S, OpPC, Frame, F, Call))
return false;
break;

case Builtin::BI__builtin_add_overflow:
case Builtin::BI__builtin_sub_overflow:
case Builtin::BI__builtin_mul_overflow:
case Builtin::BI__builtin_sadd_overflow:
case Builtin::BI__builtin_uadd_overflow:
case Builtin::BI__builtin_uaddl_overflow:
case Builtin::BI__builtin_uaddll_overflow:
case Builtin::BI__builtin_usub_overflow:
case Builtin::BI__builtin_usubl_overflow:
case Builtin::BI__builtin_usubll_overflow:
case Builtin::BI__builtin_umul_overflow:
case Builtin::BI__builtin_umull_overflow:
case Builtin::BI__builtin_umulll_overflow:
case Builtin::BI__builtin_saddl_overflow:
case Builtin::BI__builtin_saddll_overflow:
case Builtin::BI__builtin_ssub_overflow:
case Builtin::BI__builtin_ssubl_overflow:
case Builtin::BI__builtin_ssubll_overflow:
case Builtin::BI__builtin_smul_overflow:
case Builtin::BI__builtin_smull_overflow:
case Builtin::BI__builtin_smulll_overflow:
if (!interp__builtin_overflowop(S, OpPC, Frame, F, Call))
return false;
break;

case Builtin::BI__builtin_addcb:
case Builtin::BI__builtin_addcs:
case Builtin::BI__builtin_addc:
case Builtin::BI__builtin_addcl:
case Builtin::BI__builtin_addcll:
case Builtin::BI__builtin_subcb:
case Builtin::BI__builtin_subcs:
case Builtin::BI__builtin_subc:
case Builtin::BI__builtin_subcl:
case Builtin::BI__builtin_subcll:
if (!interp__builtin_carryop(S, OpPC, Frame, F, Call))
return false;
break;

case Builtin::BI__builtin_clz:
case Builtin::BI__builtin_clzl:
case Builtin::BI__builtin_clzll:
case Builtin::BI__builtin_clzs:
case Builtin::BI__lzcnt16: // Microsoft variants of count leading-zeroes
case Builtin::BI__lzcnt:
case Builtin::BI__lzcnt64:
if (!interp__builtin_clz(S, OpPC, Frame, F, Call))
return false;
break;

case Builtin::BI__builtin_ctz:
case Builtin::BI__builtin_ctzl:
case Builtin::BI__builtin_ctzll:
case Builtin::BI__builtin_ctzs:
if (!interp__builtin_ctz(S, OpPC, Frame, F, Call))
return false;
break;

case Builtin::BI__builtin_bswap16:
case Builtin::BI__builtin_bswap32:
case Builtin::BI__builtin_bswap64:
if (!interp__builtin_bswap(S, OpPC, Frame, F, Call))
return false;
break;

default:
return false;
}
Expand Down
8 changes: 4 additions & 4 deletions clang/lib/AST/Interp/Opcodes.td
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def FnPtr : Type;
// Types transferred to the interpreter.
//===----------------------------------------------------------------------===//

class ArgType { string Name = ?; }
class ArgType { string Name = ?; bit AsRef = false; }
def ArgSint8 : ArgType { let Name = "int8_t"; }
def ArgUint8 : ArgType { let Name = "uint8_t"; }
def ArgSint16 : ArgType { let Name = "int16_t"; }
Expand All @@ -44,9 +44,9 @@ def ArgSint32 : ArgType { let Name = "int32_t"; }
def ArgUint32 : ArgType { let Name = "uint32_t"; }
def ArgSint64 : ArgType { let Name = "int64_t"; }
def ArgUint64 : ArgType { let Name = "uint64_t"; }
def ArgFloat : ArgType { let Name = "Floating"; }
def ArgIntAP : ArgType { let Name = "IntegralAP<false>"; }
def ArgIntAPS : ArgType { let Name = "IntegralAP<true>"; }
def ArgIntAP : ArgType { let Name = "IntegralAP<false>"; let AsRef = true; }
def ArgIntAPS : ArgType { let Name = "IntegralAP<true>"; let AsRef = true; }
def ArgFloat : ArgType { let Name = "Floating"; let AsRef = true; }
def ArgBool : ArgType { let Name = "bool"; }

def ArgFunction : ArgType { let Name = "const Function *"; }
Expand Down
18 changes: 18 additions & 0 deletions clang/lib/AST/Interp/PrimType.h
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,24 @@ static inline bool aligned(const void *P) {
} \
} while (0)

#define INT_TYPE_SWITCH_NO_BOOL(Expr, B) \
do { \
switch (Expr) { \
TYPE_SWITCH_CASE(PT_Sint8, B) \
TYPE_SWITCH_CASE(PT_Uint8, B) \
TYPE_SWITCH_CASE(PT_Sint16, B) \
TYPE_SWITCH_CASE(PT_Uint16, B) \
TYPE_SWITCH_CASE(PT_Sint32, B) \
TYPE_SWITCH_CASE(PT_Uint32, B) \
TYPE_SWITCH_CASE(PT_Sint64, B) \
TYPE_SWITCH_CASE(PT_Uint64, B) \
TYPE_SWITCH_CASE(PT_IntAP, B) \
TYPE_SWITCH_CASE(PT_IntAPS, B) \
default: \
llvm_unreachable("Not an integer value"); \
} \
} while (0)

#define COMPOSITE_TYPE_SWITCH(Expr, B, D) \
do { \
switch (Expr) { \
Expand Down
46 changes: 29 additions & 17 deletions clang/lib/AST/Interp/Program.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,9 @@ Record *Program::getOrCreateRecord(const RecordDecl *RD) {
if (!RD)
return nullptr;

if (!RD->isCompleteDefinition())
return nullptr;

// Deduplicate records.
if (auto It = Records.find(RD); It != Records.end())
return It->second;
Expand All @@ -247,7 +250,8 @@ Record *Program::getOrCreateRecord(const RecordDecl *RD) {
unsigned VirtSize = 0;

// Helper to get a base descriptor.
auto GetBaseDesc = [this](const RecordDecl *BD, Record *BR) -> Descriptor * {
auto GetBaseDesc = [this](const RecordDecl *BD,
const Record *BR) -> const Descriptor * {
if (!BR)
return nullptr;
return allocateDescriptor(BD, BR, std::nullopt, /*isConst=*/false,
Expand All @@ -258,31 +262,39 @@ Record *Program::getOrCreateRecord(const RecordDecl *RD) {
// Reserve space for base classes.
Record::BaseList Bases;
Record::VirtualBaseList VirtBases;
if (auto *CD = dyn_cast<CXXRecordDecl>(RD)) {
if (const auto *CD = dyn_cast<CXXRecordDecl>(RD)) {

for (const CXXBaseSpecifier &Spec : CD->bases()) {
if (Spec.isVirtual())
continue;

const RecordDecl *BD = Spec.getType()->castAs<RecordType>()->getDecl();
Record *BR = getOrCreateRecord(BD);
if (Descriptor *Desc = GetBaseDesc(BD, BR)) {
BaseSize += align(sizeof(InlineDescriptor));
Bases.push_back({BD, BaseSize, Desc, BR});
BaseSize += align(BR->getSize());
continue;
// In error cases, the base might not be a RecordType.
if (const auto *RT = Spec.getType()->getAs<RecordType>()) {
const RecordDecl *BD = RT->getDecl();
const Record *BR = getOrCreateRecord(BD);

if (const Descriptor *Desc = GetBaseDesc(BD, BR)) {
BaseSize += align(sizeof(InlineDescriptor));
Bases.push_back({BD, BaseSize, Desc, BR});
BaseSize += align(BR->getSize());
continue;
}
}
return nullptr;
}

for (const CXXBaseSpecifier &Spec : CD->vbases()) {
const RecordDecl *BD = Spec.getType()->castAs<RecordType>()->getDecl();
Record *BR = getOrCreateRecord(BD);

if (Descriptor *Desc = GetBaseDesc(BD, BR)) {
VirtSize += align(sizeof(InlineDescriptor));
VirtBases.push_back({BD, VirtSize, Desc, BR});
VirtSize += align(BR->getSize());
continue;
if (const auto *RT = Spec.getType()->getAs<RecordType>()) {
const RecordDecl *BD = RT->getDecl();
const Record *BR = getOrCreateRecord(BD);

if (const Descriptor *Desc = GetBaseDesc(BD, BR)) {
VirtSize += align(sizeof(InlineDescriptor));
VirtBases.push_back({BD, VirtSize, Desc, BR});
VirtSize += align(BR->getSize());
continue;
}
}
return nullptr;
}
Expand All @@ -298,7 +310,7 @@ Record *Program::getOrCreateRecord(const RecordDecl *RD) {
QualType FT = FD->getType();
const bool IsConst = FT.isConstQualified();
const bool IsMutable = FD->isMutable();
Descriptor *Desc;
const Descriptor *Desc;
if (std::optional<PrimType> T = Ctx.classify(FT)) {
Desc = createDescriptor(FD, *T, std::nullopt, IsConst,
/*isTemporary=*/false, IsMutable);
Expand Down
11 changes: 5 additions & 6 deletions clang/lib/AST/Interp/Record.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,16 @@ class Record final {
struct Field {
const FieldDecl *Decl;
unsigned Offset;
Descriptor *Desc;
const Descriptor *Desc;
bool isBitField() const { return Decl->isBitField(); }
};

/// Describes a base class.
struct Base {
const RecordDecl *Decl;
unsigned Offset;
Descriptor *Desc;
Record *R;
const Descriptor *Desc;
const Record *R;
};

/// Mapping from identifiers to field descriptors.
Expand Down Expand Up @@ -80,7 +80,6 @@ class Record final {

unsigned getNumFields() const { return Fields.size(); }
const Field *getField(unsigned I) const { return &Fields[I]; }
Field *getField(unsigned I) { return &Fields[I]; }

using const_base_iter = BaseList::const_iterator;
llvm::iterator_range<const_base_iter> bases() const {
Expand Down Expand Up @@ -120,9 +119,9 @@ class Record final {
VirtualBaseList VirtualBases;

/// Mapping from declarations to bases.
llvm::DenseMap<const RecordDecl *, Base *> BaseMap;
llvm::DenseMap<const RecordDecl *, const Base *> BaseMap;
/// Mapping from field identifiers to descriptors.
llvm::DenseMap<const FieldDecl *, Field *> FieldMap;
llvm::DenseMap<const FieldDecl *, const Field *> FieldMap;
/// Mapping from declarations to virtual bases.
llvm::DenseMap<const RecordDecl *, Base *> VirtualBaseMap;
/// Size of the structure.
Expand Down
7 changes: 4 additions & 3 deletions clang/lib/AST/StmtOpenACC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,11 @@ OpenACCComputeConstruct::CreateEmpty(const ASTContext &C, EmptyShell) {

OpenACCComputeConstruct *
OpenACCComputeConstruct::Create(const ASTContext &C, OpenACCDirectiveKind K,
SourceLocation BeginLoc,
SourceLocation EndLoc) {
SourceLocation BeginLoc, SourceLocation EndLoc,
Stmt *StructuredBlock) {
void *Mem = C.Allocate(sizeof(OpenACCComputeConstruct),
alignof(OpenACCComputeConstruct));
auto *Inst = new (Mem) OpenACCComputeConstruct(K, BeginLoc, EndLoc);
auto *Inst =
new (Mem) OpenACCComputeConstruct(K, BeginLoc, EndLoc, StructuredBlock);
return Inst;
}
31 changes: 29 additions & 2 deletions clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,35 @@ buildStmtToBasicBlockMap(const CFG &Cfg) {

StmtToBlock[Stmt->getStmt()] = Block;
}
if (const Stmt *TerminatorStmt = Block->getTerminatorStmt())
StmtToBlock[TerminatorStmt] = Block;
}
// Some terminator conditions don't appear as a `CFGElement` anywhere else -
// for example, this is true if the terminator condition is a `&&` or `||`
// operator.
// We associate these conditions with the block the terminator appears in,
// but only if the condition has not already appeared as a regular
// `CFGElement`. (The `insert()` below does nothing if the key already exists
// in the map.)
for (const CFGBlock *Block : Cfg) {
if (Block != nullptr)
if (const Stmt *TerminatorCond = Block->getTerminatorCondition())
StmtToBlock.insert({TerminatorCond, Block});
}
// Terminator statements typically don't appear as a `CFGElement` anywhere
// else, so we want to associate them with the block that they terminate.
// However, there are some important special cases:
// - The conditional operator is a type of terminator, but it also appears
// as a regular `CFGElement`, and we want to associate it with the block
// in which it appears as a `CFGElement`.
// - The `&&` and `||` operators are types of terminators, but like the
// conditional operator, they can appear as a regular `CFGElement` or
// as a terminator condition (see above).
// We process terminators last to make sure that we only associate them with
// the block they terminate if they haven't previously occurred as a regular
// `CFGElement` or as a terminator condition.
for (const CFGBlock *Block : Cfg) {
if (Block != nullptr)
if (const Stmt *TerminatorStmt = Block->getTerminatorStmt())
StmtToBlock.insert({TerminatorStmt, Block});
}
return StmtToBlock;
}
Expand Down
18 changes: 14 additions & 4 deletions clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -361,8 +361,8 @@ getFieldsGlobalsAndFuncs(const Stmt &S, FieldSet &Fields,
if (const auto *FD = dyn_cast<FieldDecl>(VD))
Fields.insert(FD);
} else if (auto *InitList = dyn_cast<InitListExpr>(&S)) {
if (RecordDecl *RD = InitList->getType()->getAsRecordDecl())
for (const auto *FD : getFieldsForInitListExpr(RD))
if (InitList->getType()->isRecordType())
for (const auto *FD : getFieldsForInitListExpr(InitList))
Fields.insert(FD);
}
}
Expand Down Expand Up @@ -1104,12 +1104,22 @@ RecordStorageLocation *getBaseObjectLocation(const MemberExpr &ME,
return Env.get<RecordStorageLocation>(*Base);
}

std::vector<FieldDecl *> getFieldsForInitListExpr(const RecordDecl *RD) {
std::vector<const FieldDecl *>
getFieldsForInitListExpr(const InitListExpr *InitList) {
const RecordDecl *RD = InitList->getType()->getAsRecordDecl();
assert(RD != nullptr);

std::vector<const FieldDecl *> Fields;

if (InitList->getType()->isUnionType()) {
Fields.push_back(InitList->getInitializedFieldInUnion());
return Fields;
}

// Unnamed bitfields are only used for padding and do not appear in
// `InitListExpr`'s inits. However, those fields do appear in `RecordDecl`'s
// field list, and we thus need to remove them before mapping inits to
// fields to avoid mapping inits to the wrongs fields.
std::vector<FieldDecl *> Fields;
llvm::copy_if(
RD->fields(), std::back_inserter(Fields),
[](const FieldDecl *Field) { return !Field->isUnnamedBitfield(); });
Expand Down
24 changes: 14 additions & 10 deletions clang/lib/Analysis/FlowSensitive/Transfer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -663,13 +663,7 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
void VisitInitListExpr(const InitListExpr *S) {
QualType Type = S->getType();

if (Type->isUnionType()) {
if (auto *Val = Env.createValue(Type))
Env.setValue(*S, *Val);
return;
}

if (!Type->isStructureOrClassType()) {
if (!Type->isRecordType()) {
// Until array initialization is implemented, we don't need to care about
// cases where `getNumInits() > 1`.
if (S->getNumInits() == 1)
Expand All @@ -687,10 +681,9 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
llvm::DenseMap<const ValueDecl *, StorageLocation *> FieldLocs;

// This only contains the direct fields for the given type.
std::vector<FieldDecl *> FieldsForInit =
getFieldsForInitListExpr(Type->getAsRecordDecl());
std::vector<const FieldDecl *> FieldsForInit = getFieldsForInitListExpr(S);

// `S->inits()` contains all the initializer epressions, including the
// `S->inits()` contains all the initializer expressions, including the
// ones for direct base classes.
auto Inits = S->inits();
size_t InitIdx = 0;
Expand Down Expand Up @@ -730,6 +723,17 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
FieldLocs.insert({Field, &Loc});
}

// In the case of a union, we don't in general have initializers for all
// of the fields. Create storage locations for the remaining fields (but
// don't associate them with values).
if (Type->isUnionType()) {
for (const FieldDecl *Field :
Env.getDataflowAnalysisContext().getModeledFields(Type)) {
if (auto [it, inserted] = FieldLocs.insert({Field, nullptr}); inserted)
it->second = &Env.createStorageLocation(Field->getType());
}
}

// Check that we satisfy the invariant that a `RecordStorageLoation`
// contains exactly the set of modeled fields for that type.
// `ModeledFields` includes fields from all the bases, but only the
Expand Down
76 changes: 31 additions & 45 deletions clang/lib/Analysis/UnsafeBufferUsage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ isInUnspecifiedPointerContext(internal::Matcher<Stmt> InnerMatcher) {
// clang-format off
auto CallArgMatcher = callExpr(
forEachArgumentWithParamType(
InnerMatcher,
InnerMatcher,
isAnyPointer() /* array also decays to pointer type*/),
unless(callee(
functionDecl(hasAttr(attr::UnsafeBufferUsage)))));
Expand Down Expand Up @@ -1677,15 +1677,6 @@ std::string getUserFillPlaceHolder(StringRef HintTextToUser = "placeholder") {
return s;
}

// Return the text representation of the given `APInt Val`:
static std::string getAPIntText(APInt Val) {
SmallVector<char> Txt;
Val.toString(Txt, 10, true);
// APInt::toString does not add '\0' to the end of the string for us:
Txt.push_back('\0');
return Txt.data();
}

// Return the source location of the last character of the AST `Node`.
template <typename NodeTy>
static std::optional<SourceLocation>
Expand Down Expand Up @@ -2152,15 +2143,18 @@ UPCPreIncrementGadget::getFixits(const FixitStrategy &S) const {
// In many cases, this function cannot figure out the actual extent `S`. It
// then will use a place holder to replace `S` to ask users to fill `S` in. The
// initializer shall be used to initialize a variable of type `std::span<T>`.
// In some cases (e. g. constant size array) the initializer should remain
// unchanged and the function returns empty list. In case the function can't
// provide the right fixit it will return nullopt.
//
// FIXME: Support multi-level pointers
//
// Parameters:
// `Init` a pointer to the initializer expression
// `Ctx` a reference to the ASTContext
static FixItList
static std::optional<FixItList>
FixVarInitializerWithSpan(const Expr *Init, ASTContext &Ctx,
const StringRef UserFillPlaceHolder) {
const StringRef UserFillPlaceHolder) {
const SourceManager &SM = Ctx.getSourceManager();
const LangOptions &LangOpts = Ctx.getLangOpts();

Expand All @@ -2176,11 +2170,11 @@ FixVarInitializerWithSpan(const Expr *Init, ASTContext &Ctx,
std::optional<SourceLocation> InitLocation =
getEndCharLoc(Init, SM, LangOpts);
if (!InitLocation)
return {};
return std::nullopt;

SourceRange SR(Init->getBeginLoc(), *InitLocation);

return {FixItHint::CreateRemoval(SR)};
return FixItList{FixItHint::CreateRemoval(SR)};
}

FixItList FixIts{};
Expand All @@ -2199,19 +2193,18 @@ FixVarInitializerWithSpan(const Expr *Init, ASTContext &Ctx,
if (!Ext->HasSideEffects(Ctx)) {
std::optional<StringRef> ExtentString = getExprText(Ext, SM, LangOpts);
if (!ExtentString)
return {};
return std::nullopt;
ExtentText = *ExtentString;
}
} else if (!CxxNew->isArray())
// Although the initializer is not allocating a buffer, the pointer
// variable could still be used in buffer access operations.
ExtentText = One;
} else if (const auto *CArrTy = Ctx.getAsConstantArrayType(
Init->IgnoreImpCasts()->getType())) {
// In cases `Init` is of an array type after stripping off implicit casts,
// the extent is the array size. Note that if the array size is not a
// constant, we cannot use it as the extent.
ExtentText = getAPIntText(CArrTy->getSize());
} else if (Ctx.getAsConstantArrayType(Init->IgnoreImpCasts()->getType())) {
// std::span has a single parameter constructor for initialization with
// constant size array. The size is auto-deduced as the constructor is a
// function template. The correct fixit is empty - no changes should happen.
return FixItList{};
} else {
// In cases `Init` is of the form `&Var` after stripping of implicit
// casts, where `&` is the built-in operator, the extent is 1.
Expand All @@ -2227,7 +2220,7 @@ FixVarInitializerWithSpan(const Expr *Init, ASTContext &Ctx,
std::optional<SourceLocation> LocPassInit = getPastLoc(Init, SM, LangOpts);

if (!LocPassInit)
return {};
return std::nullopt;

StrBuffer.append(", ");
StrBuffer.append(ExtentText);
Expand Down Expand Up @@ -2301,37 +2294,30 @@ static FixItList fixLocalVarDeclWithSpan(const VarDecl *D, ASTContext &Ctx,
std::stringstream SS;

SS << *SpanTyText;
// Append qualifiers to the type of `D`, if any:
if (D->getType().hasQualifiers())
SS << " " << D->getType().getQualifiers().getAsString();

// The end of the range of the original source that will be replaced
// by `std::span<T> ident`:
SourceLocation EndLocForReplacement = D->getEndLoc();
std::optional<StringRef> IdentText =
getVarDeclIdentifierText(D, Ctx.getSourceManager(), Ctx.getLangOpts());

if (!IdentText) {
DEBUG_NOTE_DECL_FAIL(D, " : failed to locate the identifier");
return {};
}
// Fix the initializer if it exists:
if (const Expr *Init = D->getInit()) {
FixItList InitFixIts =
std::optional<FixItList> InitFixIts =
FixVarInitializerWithSpan(Init, Ctx, UserFillPlaceHolder);
if (InitFixIts.empty())
if (!InitFixIts)
return {};
FixIts.insert(FixIts.end(), std::make_move_iterator(InitFixIts.begin()),
std::make_move_iterator(InitFixIts.end()));
// If the declaration has the form `T *ident = init`, we want to replace
// `T *ident = ` with `std::span<T> ident`:
EndLocForReplacement = Init->getBeginLoc().getLocWithOffset(-1);
}
SS << " " << IdentText->str();
FixIts.insert(FixIts.end(), std::make_move_iterator(InitFixIts->begin()),
std::make_move_iterator(InitFixIts->end()));
}
// For declaration of the form `T * ident = init;`, we want to replace
// `T * ` with `std::span<T>`.
// We ignore CV-qualifiers so for `T * const ident;` we also want to replace
// just `T *` with `std::span<T>`.
const SourceLocation EndLocForReplacement = D->getTypeSpecEndLoc();
if (!EndLocForReplacement.isValid()) {
DEBUG_NOTE_DECL_FAIL(D, " : failed to locate the end of the declaration");
return {};
}
// The only exception is that for `T *ident` we'll add a single space between
// "std::span<T>" and "ident".
// FIXME: The condition is false for identifiers expended from macros.
if (EndLocForReplacement.getLocWithOffset(1) == getVarDeclIdentifierLoc(D))
SS << " ";

FixIts.push_back(FixItHint::CreateReplacement(
SourceRange(D->getBeginLoc(), EndLocForReplacement), SS.str()));
return FixIts;
Expand Down
1 change: 0 additions & 1 deletion clang/lib/Basic/TargetInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@ TargetInfo::TargetInfo(const llvm::Triple &T) : Triple(T) {
HasFullBFloat16 = false;
HasLongDouble = true;
HasFPReturn = true;
HasFPTypes = true;
HasStrictFP = false;
PointerWidth = PointerAlign = 32;
BoolWidth = BoolAlign = 8;
Expand Down
1 change: 0 additions & 1 deletion clang/lib/Basic/Targets.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -830,7 +830,6 @@ TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags,
Target->setSupportedOpenCLOpts();
Target->setCommandLineOpenCLOpts();
Target->setMaxAtomicWidth();
Target->setSupportedArgTypes();

if (!Opts->DarwinTargetVariantTriple.empty())
Target->DarwinTargetVariantTriple =
Expand Down
49 changes: 11 additions & 38 deletions clang/lib/Basic/Targets/AArch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
//===----------------------------------------------------------------------===//

#include "AArch64.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/TargetBuiltins.h"
#include "clang/Basic/TargetInfo.h"
Expand Down Expand Up @@ -200,32 +199,13 @@ AArch64TargetInfo::AArch64TargetInfo(const llvm::Triple &Triple,
StringRef AArch64TargetInfo::getABI() const { return ABI; }

bool AArch64TargetInfo::setABI(const std::string &Name) {
if (Name != "aapcs" && Name != "aapcs-soft" && Name != "darwinpcs")
if (Name != "aapcs" && Name != "darwinpcs")
return false;

ABI = Name;
return true;
}

void AArch64TargetInfo::setSupportedArgTypes() {
if (!(FPU & FPUMode) && ABI != "aapcs-soft") {
// When a hard-float ABI is used on a target without an FPU, all
// floating-point argument and return types are rejected because they must
// be passed in FP registers.
HasFPTypes = false;
}
}

bool AArch64TargetInfo::validateTarget(DiagnosticsEngine &Diags) const {
if (hasFeature("fp") && ABI == "aapcs-soft") {
// aapcs-soft is not allowed for targets with an FPU, to avoid there being
// two incomatible ABIs.
Diags.Report(diag::err_target_unsupported_abi_with_fpu) << ABI;
return false;
}
return true;
}

bool AArch64TargetInfo::validateBranchProtection(StringRef Spec, StringRef,
BranchProtectionInfo &BPI,
StringRef &Err) const {
Expand Down Expand Up @@ -387,20 +367,8 @@ void AArch64TargetInfo::getTargetDefines(const LangOptions &Opts,

// ACLE predefines. Many can only have one possible value on v8 AArch64.
Builder.defineMacro("__ARM_ACLE", "200");

// __ARM_ARCH is defined as an integer value indicating the current ARM ISA.
// For ISAs up to and including v8, __ARM_ARCH is equal to the major version
// number. For ISAs from v8.1 onwards, __ARM_ARCH is scaled up to include the
// minor version number, e.g. for ARM architecture ARMvX.Y:
// __ARM_ARCH = X * 100 + Y.
if (ArchInfo->Version.getMajor() == 8 && ArchInfo->Version.getMinor() == 0)
Builder.defineMacro("__ARM_ARCH",
std::to_string(ArchInfo->Version.getMajor()));
else
Builder.defineMacro("__ARM_ARCH",
std::to_string(ArchInfo->Version.getMajor() * 100 +
ArchInfo->Version.getMinor().value()));

Builder.defineMacro("__ARM_ARCH",
std::to_string(ArchInfo->Version.getMajor()));
Builder.defineMacro("__ARM_ARCH_PROFILE",
std::string("'") + (char)ArchInfo->Profile + "'");

Expand Down Expand Up @@ -699,15 +667,20 @@ StringRef AArch64TargetInfo::getFeatureDependencies(StringRef Name) const {
}

bool AArch64TargetInfo::validateCpuSupports(StringRef FeatureStr) const {
return llvm::AArch64::parseArchExtension(FeatureStr).has_value();
// CPU features might be separated by '+', extract them and check
llvm::SmallVector<StringRef, 8> Features;
FeatureStr.split(Features, "+");
for (auto &Feature : Features)
if (!llvm::AArch64::parseArchExtension(Feature.trim()).has_value())
return false;
return true;
}

bool AArch64TargetInfo::hasFeature(StringRef Feature) const {
return llvm::StringSwitch<bool>(Feature)
.Cases("aarch64", "arm64", "arm", true)
.Case("fmv", HasFMV)
.Case("fp", FPU & FPUMode)
.Cases("neon", "simd", FPU & NeonMode)
.Cases("neon", "fp", "simd", FPU & NeonMode)
.Case("jscvt", HasJSCVT)
.Case("fcma", HasFCMA)
.Case("rng", HasRandGen)
Expand Down
5 changes: 1 addition & 4 deletions clang/lib/Basic/Targets/AArch64.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,6 @@ class LLVM_LIBRARY_VISIBILITY AArch64TargetInfo : public TargetInfo {

StringRef getABI() const override;
bool setABI(const std::string &Name) override;
void setSupportedArgTypes() override;

bool validateBranchProtection(StringRef Spec, StringRef Arch,
BranchProtectionInfo &BPI,
Expand Down Expand Up @@ -166,7 +165,7 @@ class LLVM_LIBRARY_VISIBILITY AArch64TargetInfo : public TargetInfo {
DiagnosticsEngine &Diags) override;
ParsedTargetAttr parseTargetAttr(StringRef Str) const override;
bool supportsTargetAttributeTune() const override { return true; }

bool supportsCpuSupports() const override { return true; }
bool checkArithmeticFenceSupported() const override { return true; }

bool hasBFloat16Type() const override;
Expand Down Expand Up @@ -200,8 +199,6 @@ class LLVM_LIBRARY_VISIBILITY AArch64TargetInfo : public TargetInfo {
bool hasInt128Type() const override;

bool hasBitIntType() const override { return true; }

bool validateTarget(DiagnosticsEngine &Diags) const override;
};

class LLVM_LIBRARY_VISIBILITY AArch64leTargetInfo : public AArch64TargetInfo {
Expand Down
14 changes: 3 additions & 11 deletions clang/lib/Basic/Targets/ARM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,6 @@ void ARMTargetInfo::setArchInfo(llvm::ARM::ArchKind Kind) {
SubArch = llvm::ARM::getSubArch(ArchKind);
ArchProfile = llvm::ARM::parseArchProfile(SubArch);
ArchVersion = llvm::ARM::parseArchVersion(SubArch);
ArchMinorVersion = llvm::ARM::parseArchMinorVersion(SubArch);

// cache CPU related strings
CPUAttr = getCPUAttr();
Expand Down Expand Up @@ -737,16 +736,9 @@ void ARMTargetInfo::getTargetDefines(const LangOptions &Opts,
if (!CPUAttr.empty())
Builder.defineMacro("__ARM_ARCH_" + CPUAttr + "__");

// __ARM_ARCH is defined as an integer value indicating the current ARM ISA.
// For ISAs up to and including v8, __ARM_ARCH is equal to the major version
// number. For ISAs from v8.1 onwards, __ARM_ARCH is scaled up to include the
// minor version number, e.g. for ARM architecture ARMvX.Y:
// __ARM_ARCH = X * 100 + Y.
if (ArchVersion >= 9 || ArchMinorVersion != 0)
Builder.defineMacro("__ARM_ARCH",
Twine(ArchVersion * 100 + ArchMinorVersion));
else
Builder.defineMacro("__ARM_ARCH", Twine(ArchVersion));
// ACLE 6.4.1 ARM/Thumb instruction set architecture
// __ARM_ARCH is defined as an integer value indicating the current ARM ISA
Builder.defineMacro("__ARM_ARCH", Twine(ArchVersion));

if (ArchVersion >= 8) {
// ACLE 6.5.7 Crypto Extension
Expand Down
1 change: 0 additions & 1 deletion clang/lib/Basic/Targets/ARM.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ class LLVM_LIBRARY_VISIBILITY ARMTargetInfo : public TargetInfo {
llvm::ARM::ArchKind ArchKind = llvm::ARM::ArchKind::ARMV4T;
llvm::ARM::ProfileKind ArchProfile;
unsigned ArchVersion;
unsigned ArchMinorVersion;

LLVM_PREFERRED_TYPE(FPUMode)
unsigned FPU : 5;
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Basic/Targets/NVPTX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ NVPTXTargetInfo::NVPTXTargetInfo(const llvm::Triple &Triple,
NoAsmVariants = true;
GPU = CudaArch::UNUSED;

// PTX supports f16 as a fundamental type.
HasLegalHalfType = true;
HasFloat16 = true;

if (TargetPointerWidth == 32)
resetDataLayout("e-p:32:32-i64:64-i128:128-v16:16-v32:32-n16:32:64");
else if (Opts.NVPTXUseShortPointers)
Expand Down
10 changes: 10 additions & 0 deletions clang/lib/Basic/Targets/PPC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -904,6 +904,16 @@ bool PPCTargetInfo::validateCpuSupports(StringRef FeatureStr) const {
}

bool PPCTargetInfo::validateCpuIs(StringRef CPUName) const {
llvm::Triple Triple = getTriple();
if (Triple.isOSAIX()) {
#define PPC_AIX_CPU(NAME, SUPPORT, INDEX, OP, VALUE) .Case(NAME, true)
return llvm::StringSwitch<bool>(CPUName)
#include "llvm/TargetParser/PPCTargetParser.def"
.Default(false);
}

assert(Triple.isOSLinux() &&
"__builtin_cpu_is() is only supported for AIX and Linux.");
#define PPC_LNX_CPU(NAME, NUM) .Case(NAME, true)
return llvm::StringSwitch<bool>(CPUName)
#include "llvm/TargetParser/PPCTargetParser.def"
Expand Down
10 changes: 9 additions & 1 deletion clang/lib/Basic/Targets/PPC.h
Original file line number Diff line number Diff line change
Expand Up @@ -362,8 +362,16 @@ class LLVM_LIBRARY_VISIBILITY PPCTargetInfo : public TargetInfo {

// We support __builtin_cpu_supports/__builtin_cpu_is on targets that
// have Glibc since it is Glibc that provides the HWCAP[2] in the auxv.
static constexpr int MINIMUM_AIX_OS_MAJOR = 7;
static constexpr int MINIMUM_AIX_OS_MINOR = 2;
bool supportsCpuSupports() const override { return getTriple().isOSGlibc(); }
bool supportsCpuIs() const override { return getTriple().isOSGlibc(); }
bool supportsCpuIs() const override {
llvm::Triple Triple = getTriple();
// AIX 7.2 is the minimum requirement to support __builtin_cpu_is().
return Triple.isOSGlibc() ||
(Triple.isOSAIX() &&
!Triple.isOSVersionLT(MINIMUM_AIX_OS_MAJOR, MINIMUM_AIX_OS_MINOR));
}
bool validateCpuSupports(StringRef Feature) const override;
bool validateCpuIs(StringRef Name) const override;
};
Expand Down
66 changes: 65 additions & 1 deletion clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10638,6 +10638,9 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
BuiltinID <= clang::AArch64::LastSMEBuiltin)
return EmitAArch64SMEBuiltinExpr(BuiltinID, E);

if (BuiltinID == Builtin::BI__builtin_cpu_supports)
return EmitAArch64CpuSupports(E);

unsigned HintID = static_cast<unsigned>(-1);
switch (BuiltinID) {
default: break;
Expand Down Expand Up @@ -12043,7 +12046,8 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
"vgetq_lane");
}

case clang::AArch64::BI_InterlockedAdd: {
case clang::AArch64::BI_InterlockedAdd:
case clang::AArch64::BI_InterlockedAdd64: {
Address DestAddr = CheckAtomicAlignment(*this, E);
Value *Val = EmitScalarExpr(E->getArg(1));
AtomicRMWInst *RMWI =
Expand Down Expand Up @@ -14024,6 +14028,19 @@ Value *CodeGenFunction::EmitX86CpuInit() {
return Builder.CreateCall(Func);
}

Value *CodeGenFunction::EmitAArch64CpuSupports(const CallExpr *E) {
const Expr *ArgExpr = E->getArg(0)->IgnoreParenCasts();
StringRef ArgStr = cast<StringLiteral>(ArgExpr)->getString();
llvm::SmallVector<StringRef, 8> Features;
ArgStr.split(Features, "+");
for (auto &Feature : Features) {
Feature = Feature.trim();
if (Feature != "default")
Features.push_back(Feature);
}
return EmitAArch64CpuSupports(Features);
}

llvm::Value *
CodeGenFunction::EmitAArch64CpuSupports(ArrayRef<StringRef> FeaturesStrs) {
uint64_t FeaturesMask = llvm::AArch64::getCpuSupportsMask(FeaturesStrs);
Expand Down Expand Up @@ -16541,12 +16558,59 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID,

Intrinsic::ID ID = Intrinsic::not_intrinsic;

#include "llvm/TargetParser/PPCTargetParser.def"
auto GenAIXPPCBuiltinCpuExpr = [&](unsigned SupportMethod, unsigned FieldIdx,
unsigned CompOp,
unsigned OpValue) -> Value * {
if (SupportMethod == AIX_BUILTIN_PPC_FALSE)
return llvm::ConstantInt::getFalse(ConvertType(E->getType()));

if (SupportMethod == AIX_BUILTIN_PPC_TRUE)
return llvm::ConstantInt::getTrue(ConvertType(E->getType()));

assert(SupportMethod <= USE_SYS_CONF && "Invalid value for SupportMethod.");
assert((CompOp == COMP_EQ) && "Only equal comparisons are supported.");

llvm::Type *STy = llvm::StructType::get(PPC_SYSTEMCONFIG_TYPE);
llvm::Constant *SysConf =
CGM.CreateRuntimeVariable(STy, "_system_configuration");

// Grab the appropriate field from _system_configuration.
llvm::Value *Idxs[] = {ConstantInt::get(Int32Ty, 0),
ConstantInt::get(Int32Ty, FieldIdx)};

llvm::Value *FieldValue = Builder.CreateGEP(STy, SysConf, Idxs);
FieldValue = Builder.CreateAlignedLoad(Int32Ty, FieldValue,
CharUnits::fromQuantity(4));
assert(FieldValue->getType()->isIntegerTy(32) &&
"Only 32-bit integers are supported in GenAIXPPCBuiltinCpuExpr().");
return Builder.CreateICmp(ICmpInst::ICMP_EQ, FieldValue,
ConstantInt::get(Int32Ty, OpValue));
};

switch (BuiltinID) {
default: return nullptr;

case Builtin::BI__builtin_cpu_is: {
const Expr *CPUExpr = E->getArg(0)->IgnoreParenCasts();
StringRef CPUStr = cast<clang::StringLiteral>(CPUExpr)->getString();
llvm::Triple Triple = getTarget().getTriple();

if (Triple.isOSAIX()) {
unsigned IsCpuSupport, FieldIdx, CompareOp, CpuIdValue;
typedef std::tuple<unsigned, unsigned, unsigned, unsigned> CPUType;
std::tie(IsCpuSupport, FieldIdx, CompareOp, CpuIdValue) =
static_cast<CPUType>(StringSwitch<CPUType>(CPUStr)
#define PPC_AIX_CPU(NAME, SUPPORT_MAGIC, INDEX, COMPARE_OP, VALUE) \
.Case(NAME, {SUPPORT_MAGIC, INDEX, COMPARE_OP, VALUE})
#include "llvm/TargetParser/PPCTargetParser.def"
);
return GenAIXPPCBuiltinCpuExpr(IsCpuSupport, FieldIdx, CompareOp,
CpuIdValue);
}

assert(Triple.isOSLinux() &&
"__builtin_cpu_is() is only supported for AIX and Linux.");
unsigned NumCPUID = StringSwitch<unsigned>(CPUStr)
#define PPC_LNX_CPU(Name, NumericID) .Case(Name, NumericID)
#include "llvm/TargetParser/PPCTargetParser.def"
Expand Down
22 changes: 11 additions & 11 deletions clang/lib/CodeGen/CGCUDANV.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -760,10 +760,10 @@ llvm::Function *CGNVCUDARuntime::makeModuleCtorFunction() {
// to contain the fat binary but will be populated somewhere else,
// e.g. by lld through link script.
FatBinStr = new llvm::GlobalVariable(
CGM.getModule(), CGM.Int8Ty,
/*isConstant=*/true, llvm::GlobalValue::ExternalLinkage, nullptr,
"__hip_fatbin", nullptr,
llvm::GlobalVariable::NotThreadLocal);
CGM.getModule(), CGM.Int8Ty,
/*isConstant=*/true, llvm::GlobalValue::ExternalLinkage, nullptr,
"__hip_fatbin_" + CGM.getContext().getCUIDHash(), nullptr,
llvm::GlobalVariable::NotThreadLocal);
cast<llvm::GlobalVariable>(FatBinStr)->setSection(FatbinConstantName);
}

Expand Down Expand Up @@ -816,8 +816,8 @@ llvm::Function *CGNVCUDARuntime::makeModuleCtorFunction() {
// thread safety of the loaded program. Therefore we can assume sequential
// execution of constructor functions here.
if (IsHIP) {
auto Linkage = CudaGpuBinary ? llvm::GlobalValue::InternalLinkage :
llvm::GlobalValue::LinkOnceAnyLinkage;
auto Linkage = CudaGpuBinary ? llvm::GlobalValue::InternalLinkage
: llvm::GlobalValue::ExternalLinkage;
llvm::BasicBlock *IfBlock =
llvm::BasicBlock::Create(Context, "if", ModuleCtorFunc);
llvm::BasicBlock *ExitBlock =
Expand All @@ -826,11 +826,11 @@ llvm::Function *CGNVCUDARuntime::makeModuleCtorFunction() {
// of HIP ABI.
GpuBinaryHandle = new llvm::GlobalVariable(
TheModule, PtrTy, /*isConstant=*/false, Linkage,
/*Initializer=*/llvm::ConstantPointerNull::get(PtrTy),
"__hip_gpubin_handle");
if (Linkage == llvm::GlobalValue::LinkOnceAnyLinkage)
GpuBinaryHandle->setComdat(
CGM.getModule().getOrInsertComdat(GpuBinaryHandle->getName()));
/*Initializer=*/
CudaGpuBinary ? llvm::ConstantPointerNull::get(PtrTy) : nullptr,
CudaGpuBinary
? "__hip_gpubin_handle"
: "__hip_gpubin_handle_" + CGM.getContext().getCUIDHash());
GpuBinaryHandle->setAlignment(CGM.getPointerAlign().getAsAlign());
// Prevent the weak symbol in different shared libraries being merged.
if (Linkage != llvm::GlobalValue::InternalLinkage)
Expand Down
22 changes: 12 additions & 10 deletions clang/lib/CodeGen/CGExprScalar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -723,7 +723,9 @@ class ScalarExprEmitter
if (Ops.Ty->isSignedIntegerOrEnumerationType()) {
switch (CGF.getLangOpts().getSignedOverflowBehavior()) {
case LangOptions::SOB_Defined:
return Builder.CreateMul(Ops.LHS, Ops.RHS, "mul");
if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow))
return Builder.CreateMul(Ops.LHS, Ops.RHS, "mul");
[[fallthrough]];
case LangOptions::SOB_Undefined:
if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow))
return Builder.CreateNSWMul(Ops.LHS, Ops.RHS, "mul");
Expand Down Expand Up @@ -2425,8 +2427,6 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
case CK_IntegralToFloating: {
if (E->getType()->isVectorType() && DestTy->isVectorType()) {
// TODO: Support constrained FP intrinsics.
assert(!Builder.getIsFPConstrained() &&
"FP Constrained vector casts not supported yet.");
QualType SrcElTy = E->getType()->castAs<VectorType>()->getElementType();
if (SrcElTy->isSignedIntegerOrEnumerationType())
return Builder.CreateSIToFP(Visit(E), ConvertType(DestTy), "conv");
Expand All @@ -2439,8 +2439,6 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
case CK_FloatingToIntegral: {
if (E->getType()->isVectorType() && DestTy->isVectorType()) {
// TODO: Support constrained FP intrinsics.
assert(!Builder.getIsFPConstrained() &&
"FP Constrained vector casts not supported yet.");
QualType DstElTy = DestTy->castAs<VectorType>()->getElementType();
if (DstElTy->isSignedIntegerOrEnumerationType())
return Builder.CreateFPToSI(Visit(E), ConvertType(DestTy), "conv");
Expand All @@ -2453,8 +2451,6 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
case CK_FloatingCast: {
if (E->getType()->isVectorType() && DestTy->isVectorType()) {
// TODO: Support constrained FP intrinsics.
assert(!Builder.getIsFPConstrained() &&
"FP Constrained vector casts not supported yet.");
QualType SrcElTy = E->getType()->castAs<VectorType>()->getElementType();
QualType DstElTy = DestTy->castAs<VectorType>()->getElementType();
if (DstElTy->castAs<BuiltinType>()->getKind() <
Expand Down Expand Up @@ -2574,7 +2570,9 @@ llvm::Value *ScalarExprEmitter::EmitIncDecConsiderOverflowBehavior(
StringRef Name = IsInc ? "inc" : "dec";
switch (CGF.getLangOpts().getSignedOverflowBehavior()) {
case LangOptions::SOB_Defined:
return Builder.CreateAdd(InVal, Amount, Name);
if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow))
return Builder.CreateAdd(InVal, Amount, Name);
[[fallthrough]];
case LangOptions::SOB_Undefined:
if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow))
return Builder.CreateNSWAdd(InVal, Amount, Name);
Expand Down Expand Up @@ -3919,7 +3917,9 @@ Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &op) {
if (op.Ty->isSignedIntegerOrEnumerationType()) {
switch (CGF.getLangOpts().getSignedOverflowBehavior()) {
case LangOptions::SOB_Defined:
return Builder.CreateAdd(op.LHS, op.RHS, "add");
if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow))
return Builder.CreateAdd(op.LHS, op.RHS, "add");
[[fallthrough]];
case LangOptions::SOB_Undefined:
if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow))
return Builder.CreateNSWAdd(op.LHS, op.RHS, "add");
Expand Down Expand Up @@ -4073,7 +4073,9 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &op) {
if (op.Ty->isSignedIntegerOrEnumerationType()) {
switch (CGF.getLangOpts().getSignedOverflowBehavior()) {
case LangOptions::SOB_Defined:
return Builder.CreateSub(op.LHS, op.RHS, "sub");
if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow))
return Builder.CreateSub(op.LHS, op.RHS, "sub");
[[fallthrough]];
case LangOptions::SOB_Undefined:
if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow))
return Builder.CreateNSWSub(op.LHS, op.RHS, "sub");
Expand Down
Loading